diff --git a/modules/bibsched/bin/bibsched.in b/modules/bibsched/bin/bibsched.in index 2f6b3f95c..f031c1136 100644 --- a/modules/bibsched/bin/bibsched.in +++ b/modules/bibsched/bin/bibsched.in @@ -1,795 +1,798 @@ #!@PYTHON@ ## -*- mode: python; coding: utf-8; -*- ## ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006 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. """BibSched - task management, scheduling and executing system for CDS Invenio """ __version__ = "$Id$" ### -- local configuration section starts here --- cfg_valid_processes = ["bibindex","bibupload","bibreformat","webcoll","bibtaskex","bibrank","oaiharvest","oaiarchive"] # which tasks are reconized as valid? ### -- local configuration section ends here --- ## import interesting modules: try: import os import imp import string import sys import time import sre import getopt import curses import curses.panel from curses.wrapper import wrapper import signal except ImportError, e: print "Error: %s" % e import sys sys.exit(1) try: from invenio.config import * from invenio.dbquery import run_sql except ImportError, e: print "Error: %s" % e import sys sys.exit(1) 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.""" try: 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 except: return None def get_my_pid(process,args=''): - COMMAND = "ps -C %s o '%%p%%a' | grep '%s %s' | grep -v 'grep' | sed -n 1p" % (process,process,args) + if sys.platform in ['freebsd6']: + COMMAND = "ps -o pid,args | grep '%s %s' | grep -v 'grep' | sed -n 1p" % (process, args) + else: + COMMAND = "ps -C %s o '%%p%%a' | grep '%s %s' | grep -v 'grep' | sed -n 1p" % (process, process, args) answer = string.strip(os.popen(COMMAND).read()) if answer=='': answer = 0 else: answer = answer[:string.find(answer,' ')] return int(answer) def get_output_channelnames(task_id): "Construct and return filename for stdout and stderr for the task 'task_id'." filenamebase = "%s/bibsched_task_%d" % (logdir, task_id) return [filenamebase + ".log", filenamebase + ".err"] class Manager: def __init__(self): self.helper_modules = cfg_valid_processes self.running = 1 self.footer_move_mode = "[KeyUp/KeyDown Move] [M Select mode] [Q Quit]" self.footer_auto_mode = "[A Manual mode] [1/2 Display Type] [Q Quit]" self.footer_select_mode = "[KeyUp/KeyDown/PgUp/PgDown Select] [L View Log] [1/2 Display Type] [M Move mode] [A Auto mode] [Q Quit]" self.footer_waiting_item = "[R Run] [D Delete]" self.footer_running_item = "[S Sleep] [T Stop] [K Kill]" self.footer_stopped_item = "[I Initialise] [D Delete]" self.footer_sleeping_item = "[W Wake Up]" self.item_status = "" self.selected_line = 2 self.rows = [] self.panel = None self.display = 2 self.first_visible_line = 0 self.move_mode = 0 self.auto_mode = 0 self.currentrow = ["","","","","","",""] wrapper( self.start ) def handle_keys(self, chr): if chr == -1: return if self.auto_mode and (chr not in (curses.KEY_UP,curses.KEY_DOWN,curses.KEY_PPAGE,curses.KEY_NPAGE,ord("q"),ord("Q"),ord("a"),ord("A"),ord("1"),ord("2"))): self.display_in_footer("in automatic mode") self.stdscr.refresh() elif self.move_mode and (chr not in (curses.KEY_UP,curses.KEY_DOWN,ord("m"),ord("M"),ord("q"),ord("Q"))): self.display_in_footer("in move mode") self.stdscr.refresh() else: if chr == curses.KEY_UP: if self.move_mode: self.move_up() else: self.selected_line = max( self.selected_line - 1 , 2 ) self.repaint() if chr == curses.KEY_PPAGE: self.selected_line = max( self.selected_line - 10 , 2 ) self.repaint() elif chr == curses.KEY_DOWN: if self.move_mode: self.move_down() else: self.selected_line = min(self.selected_line + 1, len(self.rows) + 1 ) self.repaint() elif chr == curses.KEY_NPAGE: self.selected_line = min(self.selected_line + 10, len(self.rows) + 1 ) self.repaint() elif chr == curses.KEY_HOME: self.first_visible_line = 0 self.selected_line = 2 elif chr in (ord("a"), ord("A")): self.change_auto_mode() elif chr in (ord("l"), ord("L")): self.openlog() elif chr in (ord("w"), ord("W")): self.wakeup() elif chr in (ord("r"), ord("R")): self.run() elif chr in (ord("s"), ord("S")): self.sleep() elif chr in (ord("k"), ord("K")): self.kill() elif chr in (ord("t"), ord("T")): self.stop() elif chr in (ord("d"), ord("D")): self.delete() elif chr in (ord("i"), ord("I")): self.init() elif chr in (ord("m"), ord("M")): self.change_select_mode() elif chr == ord("1"): self.display = 1 self.first_visible_line = 0 self.selected_line = 2 self.display_in_footer("only done processes are displayed") elif chr == ord("2"): self.display = 2 self.first_visible_line = 0 self.selected_line = 2 self.display_in_footer("only not done processes are displayed") elif chr in (ord("q"), ord("Q")): if curses.panel.top_panel() == self.panel: self.panel.bottom() curses.panel.update_panels() else: self.running = 0 return def set_status(self, id, status): return run_sql("UPDATE schTASK set status=%s WHERE id=%s", (status, id)) def set_progress(self, id, progress): return run_sql("UPDATE schTASK set progress=%s WHERE id=%s", (progress, id)) def openlog(self): self.win = curses.newwin( self.height-2, self.width-2, 1, 1 ) self.panel = curses.panel.new_panel( self.win ) self.panel.top() self.win.border() self.win.addstr(1, 1, "Not implemented yet...") self.win.refresh() curses.panel.update_panels() def count_processes(self,status): out = 0 res = run_sql("SELECT COUNT(id) FROM schTASK WHERE status=%s GROUP BY status", (status,)) try: out = res[0][0] except: pass return out def wakeup(self): id = self.currentrow[0] process = self.currentrow[1] status = self.currentrow[5] if self.count_processes('RUNNING') + self.count_processes('CONTINUING') >= 1: self.display_in_footer("a process is already running!") elif status == "SLEEPING": mypid = get_my_pid(process,str(id)) if mypid!=0: os.kill(mypid, signal.SIGCONT) self.display_in_footer("process woken up") else: self.display_in_footer("process is not sleeping") self.stdscr.refresh() def run(self): id = self.currentrow[0] process = self.currentrow[1] status = self.currentrow[5] sleeptime = self.currentrow[4] if self.count_processes('RUNNING') + self.count_processes('CONTINUING') >= 1: self.display_in_footer("a process is already running!") elif status == "STOPPED" or status == "WAITING": if process in self.helper_modules: program=os.path.join( bindir, process ) fdout, fderr = get_output_channelnames(id) COMMAND = "%s %s >> %s 2>> %s &" % (program, str(id), fdout, fderr) os.system(COMMAND) Log("manually running task #%d (%s)" % (id, process)) if sleeptime: next_runtime=get_datetime(sleeptime) run_sql("INSERT INTO schTASK (proc, user, runtime, sleeptime, arguments, status) "\ " VALUES (%s,%s,%s,%s,%s,'WAITING')", (process,self.currentrow[2], next_runtime,sleeptime,self.currentrow[7])) else: self.display_in_footer("process status should be STOPPED or WAITING!") self.stdscr.refresh() def sleep(self): id = self.currentrow[0] process = self.currentrow[1] status = self.currentrow[5] if status!='RUNNING' and status!='CONTINUING': self.display_in_footer("this process is not running!") else: mypid = get_my_pid(process,str(id)) if mypid!=0: os.kill(mypid, signal.SIGUSR1) self.display_in_footer("SLEEP signal sent to process #%s" % mypid) else: self.set_status(id,'STOPPED') self.display_in_footer("cannot find process...") self.stdscr.refresh() def kill(self): id = self.currentrow[0] process = self.currentrow[1] status = self.currentrow[5] mypid = get_my_pid(process,str(id)) if mypid!=0: os.kill(mypid, signal.SIGKILL) self.set_status(id,'STOPPED') self.display_in_footer("KILL signal sent to process #%s" % mypid) else: self.set_status(id,'STOPPED') self.display_in_footer("cannot find process...") self.stdscr.refresh() def stop(self): id = self.currentrow[0] process = self.currentrow[1] status = self.currentrow[5] mypid = get_my_pid(process, str(id)) if mypid!=0: os.kill(mypid, signal.SIGINT) self.display_in_footer("INT signal sent to process #%s" % mypid) else: self.set_status(id,'STOPPED') self.display_in_footer("cannot find process...") self.stdscr.refresh() def delete(self): id = self.currentrow[0] process = self.currentrow[1] status = self.currentrow[5] if status!='RUNNING' and status!='CONTINUING' and status!='SLEEPING': self.set_status(id,"%s_DELETED" % status) self.display_in_footer("process deleted") self.selected_line = max(self.selected_line, 2) else: self.display_in_footer("cannot delete running processes") self.stdscr.refresh() def init(self): id = self.currentrow[0] process = self.currentrow[1] status = self.currentrow[5] if status!='RUNNING' and status!='CONTINUING' and status!='SLEEPING': self.set_status(id,"WAITING") self.set_progress(id,"None") self.display_in_footer("process initialised") else: self.display_in_footer("cannot initialise running processes") self.stdscr.refresh() def change_select_mode(self): if self.move_mode: self.move_mode = 0 else: status = self.currentrow[5] if status in ( "RUNNING" , "CONTINUING" , "SLEEPING" ): self.display_in_footer("cannot move running processes!") else: self.move_mode = 1 self.stdscr.refresh() def change_auto_mode(self): if self.auto_mode: program = os.path.join( bindir, "bibsched") COMMAND = "%s -q stop" % program os.system(COMMAND) self.auto_mode = 0 else: program = os.path.join( bindir, "bibsched") COMMAND = "%s -q start" % program os.system(COMMAND) self.auto_mode = 1 self.move_mode = 0 self.stdscr.refresh() def move_up(self): self.display_in_footer("not implemented yet") self.stdscr.refresh() def move_down(self): self.display_in_footer("not implemented yet") self.stdscr.refresh() def put_line(self, row): col_w = [ 5 , 11 , 21 , 21 , 7 , 11 , 25 ] maxx = self.width if self.y == self.selected_line - self.first_visible_line and self.y > 1: if self.auto_mode: attr = curses.color_pair(2) + curses.A_STANDOUT + curses.A_BOLD elif self.move_mode: attr = curses.color_pair(7) + curses.A_STANDOUT + curses.A_BOLD else: attr = curses.color_pair(8) + curses.A_STANDOUT + curses.A_BOLD self.item_status = row[5] self.currentrow = row elif self.y == 0: if self.auto_mode: attr = curses.color_pair(2) + curses.A_STANDOUT + curses.A_BOLD elif self.move_mode: attr = curses.color_pair(7) + curses.A_STANDOUT + curses.A_BOLD else: attr = curses.color_pair(8) + curses.A_STANDOUT + curses.A_BOLD elif row[5] == "DONE": attr = curses.color_pair(5) + curses.A_BOLD elif row[5] == "STOPPED": attr = curses.color_pair(6) + curses.A_BOLD elif sre.search("ERROR",row[5]): attr = curses.color_pair(4) + curses.A_BOLD elif row[5] == "WAITING": attr = curses.color_pair(3) + curses.A_BOLD elif row[5] in ("RUNNING","CONTINUING") : attr = curses.color_pair(2) + curses.A_BOLD else: attr = curses.A_BOLD myline = str(row[0]).ljust(col_w[0]) myline += str(row[1]).ljust(col_w[1]) myline += str(row[2]).ljust(col_w[2]) myline += str(row[3])[:19].ljust(col_w[3]) myline += str(row[4]).ljust(col_w[4]) myline += str(row[5]).ljust(col_w[5]) myline += str(row[6]).ljust(col_w[6]) myline = myline.ljust(maxx) self.stdscr.addnstr(self.y, 0, myline, maxx, attr) self.y = self.y+1 def display_in_footer(self, footer, i = 0, print_time_p=0): if print_time_p: footer = "%s %s" % (footer, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) maxx = self.stdscr.getmaxyx()[1] footer = footer.ljust(maxx) if self.auto_mode: colorpair = 2 elif self.move_mode: colorpair = 7 else: colorpair = 1 self.stdscr.addnstr(self.y - i, 0, footer, maxx - 1, curses.A_STANDOUT + curses.color_pair(colorpair) + curses.A_BOLD ) def repaint(self): self.y = 0 self.stdscr.clear() self.height,self.width = self.stdscr.getmaxyx() maxy = self.height - 2 maxx = self.width self.put_line( ("ID","PROC","USER","RUNTIME","SLEEP","STATUS","PROGRESS") ) self.put_line( ("---","----","----","-------------------","-----","-----","--------") ) if self.selected_line > maxy + self.first_visible_line - 1: self.first_visible_line = self.selected_line - maxy + 1 if self.selected_line < self.first_visible_line + 2: self.first_visible_line = self.selected_line - 2 for row in self.rows[self.first_visible_line:self.first_visible_line+maxy-2]: id,proc,user,runtime,sleeptime,status,progress,arguments = row self.put_line( row ) self.y = self.stdscr.getmaxyx()[0] - 1 if self.auto_mode: self.display_in_footer(self.footer_auto_mode, print_time_p=1) elif self.move_mode: self.display_in_footer(self.footer_move_mode, print_time_p=1) else: self.display_in_footer(self.footer_select_mode, print_time_p=1) footer2 = "" if sre.search("DONE",self.item_status) or self.item_status == "ERROR" or self.item_status == "STOPPED": footer2 += self.footer_stopped_item elif self.item_status == "RUNNING" or self.item_status == "CONTINUING": footer2 += self.footer_running_item elif self.item_status == "SLEEPING": footer2 += self.footer_sleeping_item elif self.item_status == "WAITING": footer2 += self.footer_waiting_item self.display_in_footer(footer2,1) self.stdscr.refresh() def start(self, stdscr): ring = 0 if curses.has_colors(): curses.start_color() curses.init_pair(8, curses.COLOR_WHITE, curses.COLOR_BLACK) curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_RED) curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK) curses.init_pair(3, curses.COLOR_MAGENTA, curses.COLOR_BLACK) curses.init_pair(4, curses.COLOR_RED, curses.COLOR_BLACK) curses.init_pair(5, curses.COLOR_BLUE, curses.COLOR_BLACK) curses.init_pair(6, curses.COLOR_CYAN, curses.COLOR_BLACK) curses.init_pair(7, curses.COLOR_YELLOW, curses.COLOR_BLACK) self.stdscr = stdscr self.base_panel = curses.panel.new_panel( self.stdscr ) self.base_panel.bottom() curses.panel.update_panels() self.height,self.width = stdscr.getmaxyx() self.stdscr.clear() if server_pid (): self.auto_mode = 1 if self.display == 1: where = "and status='DONE'" order = "DESC" else: where = "and status!='DONE'" order = "ASC" self.rows = run_sql("SELECT id,proc,user,runtime,sleeptime,status,progress,arguments FROM schTASK WHERE status NOT LIKE '%%DELETED%%' %s ORDER BY runtime %s" % (where,order)) self.repaint() ring=0 while self.running: ring += 1 chr = -1 try: chr = timed_out(self.stdscr.getch, 1) if chr == 27: # escaping sequence chr = self.stdscr.getch() if chr == 79: # arrow chr = self.stdscr.getch() if chr == 65: #arrow up chr = curses.KEY_UP elif chr == 66: #arrow down chr = curses.KEY_DOWN elif chr == 72: chr = curses.KEY_PPAGE elif chr == 70: chr = curses.KEY_NPAGE elif chr == 91: chr = self.stdscr.getch() if chr == 53: chr = self.stdscr.getch() if chr == 126: chr = curses.KEY_HOME except TimedOutExc: chr = -1 self.handle_keys(chr) if ring == 4: if self.display == 1: where = "and status='DONE'" order = "DESC" else: where = "and status!='DONE'" order = "ASC" self.rows = run_sql("SELECT id,proc,user,runtime,sleeptime,status,progress,arguments FROM schTASK WHERE status NOT LIKE '%%DELETED%%' %s ORDER BY runtime %s" % (where,order)) ring = 0 self.repaint() class BibSched: def __init__(self): self.helper_modules = cfg_valid_processes self.running = {} self.sleep_done = {} self.sleep_sent ={} self.stop_sent = {} self.suicide_sent = {} def set_status(self, id, status): return run_sql("UPDATE schTASK set status=%s WHERE id=%s", (status, id)) def can_run( self, proc ): return len( self.running.keys() ) == 0 def get_running_processes(self): row = None res = run_sql("SELECT id,proc,user,UNIX_TIMESTAMP(runtime),sleeptime,arguments,status FROM schTASK "\ " WHERE status='RUNNING' or status='CONTINUING' LIMIT 1") try: row = res[0] except: pass return row def handle_row( self, row ): id,proc,user,runtime,sleeptime,arguments,status = row if status == "SLEEP": if id in self.running.keys(): self.set_status( id, "SLEEP SENT" ) os.kill( self.running[id], signal.SIGUSR1 ) self.sleep_sent[id] = self.running[id] elif status == "SLEEPING": if id in self.sleep_sent.keys(): self.sleep_done[id] = self.sleep_sent[id] del self.sleep_sent[id] if status == "WAKEUP": if id in self.sleep_done.keys(): self.running[id] = self.sleep_done[id] del self.sleep_done[id] os.kill( self.running[id], signal.SIGCONT ) self.set_status( id, "RUNNING" ) elif status == "STOP": if id in self.running.keys(): self.set_status( id, "STOP SENT" ) os.kill( self.running[id], signal.SIGUSR2 ) self.stop_sent[id] = self.running[id] del self.running[id] elif status == "STOPPED" and id in self.stop_sent.keys(): del self.stop_sent[id] elif status == "SUICIDE": if id in self.running.keys(): self.set_status( id, "SUICIDE SENT" ) os.kill( self.running[id], signal.SIGABRT ) self.suicide_sent[id] = self.running[id] del self.running[id] elif status == "SUICIDED" and id in self.suicide_sent.keys(): del self.suicide_sent[ id ] elif sre.search("DONE",status) and id in self.running.keys(): del self.running[id] elif self.can_run(proc) and status == "WAITING" and runtime <= time.time(): if proc in self.helper_modules: program=os.path.join( bindir, proc ) fdout, fderr = get_output_channelnames(id) COMMAND = "%s %s >> %s 2>> %s" % (program, str(id), fdout, fderr) Log("task #%d (%s) started" % (id, proc)) os.system(COMMAND) Log("task #%d (%s) ended" % (id, proc)) self.running[id] = get_my_pid(proc,str(id)) if sleeptime: next_runtime=get_datetime(sleeptime) run_sql("INSERT INTO schTASK (proc, user, runtime, sleeptime, arguments, status) "\ " VALUES (%s,%s,%s,%s,%s,'WAITING')", (proc, user, next_runtime, sleeptime, arguments)) def watch_loop(self): running_process = self.get_running_processes() if running_process: proc = running_process[ 1 ] id = running_process[ 0 ] if get_my_pid(proc,str(id)): self.running[id] = get_my_pid(proc,str(id)) else: self.set_status(id,"ERROR") rows = [] while 1: for row in rows: self.handle_row( row ) time.sleep(1) rows = run_sql("SELECT id,proc,user,UNIX_TIMESTAMP(runtime),sleeptime,arguments,status FROM schTASK ORDER BY runtime ASC") class TimedOutExc(Exception): def __init__(self, value = "Timed Out"): self.value = value def __str__(self): return repr(self.value) def timed_out(f, timeout, *args, **kwargs): def handler(signum, frame): raise TimedOutExc() old = signal.signal(signal.SIGALRM, handler) signal.alarm(timeout) try: result = f(*args, **kwargs) finally: signal.signal(signal.SIGALRM, old) signal.alarm(0) return result def Log(message): log=open(logdir + "/bibsched.log","a") log.write(time.strftime("%Y-%m-%d %H:%M:%S --> ", time.localtime())) log.write(message) log.write("\n") log.close() def redirect_stdout_and_stderr(): "This function redirects stdout and stderr to bibsched.log and bibsched.err file." sys.stdout = open(logdir + "/bibsched.log", "a") sys.stderr = open(logdir + "/bibsched.err", "a") def usage(exitcode=1, msg=""): """Prints usage info.""" if msg: sys.stderr.write("Error: %s.\n" % msg) sys.stderr.write ("""\ Usage: %s [options] [start|stop|restart|monitor] The following commands are available for bibsched: - start: start bibsched in background - stop: stop a running bibsched - restart: restart a running bibsched - monitor: enter the interactive monitor Command options: -d, --daemon\t Launch BibSched in the daemon mode (deprecated, use 'start') General options: -h, --help \t\t Print this help. -V, --version \t\t Print version information. """ % sys.argv [0]) #sys.stderr.write(" -v, --verbose=LEVEL \t Verbose level (0=min, 1=default, 9=max).\n") sys.exit(exitcode) import pwd, grp prefix = '@prefix@' pidfile = os.path.join (prefix, 'var', 'run', 'bibsched.pid') def error (msg): print >> sys.stderr, "error: " + msg sys.exit (1) def server_pid (): # The pid must be stored on the filesystem try: pid = int (open (pidfile).read ()) except IOError: return None # Even if the pid is available, we check if it corresponds to an # actual process, as it might have been killed externally try: os.kill (pid, signal.SIGCONT) except OSError: return None return pid def start (verbose = True): """ Fork this process in the background and start processing requests. The process PID is stored in a pid file, so that it can be stopped later on.""" if verbose: sys.stdout.write ("starting bibsched: ") sys.stdout.flush () pid = server_pid () if pid: error ("another instance of bibsched (pid %d) is running" % pid) # start the child process using the "double fork" technique pid = os.fork () if pid > 0: sys.exit (0) os.setsid () os.chdir ('/') pid = os.fork () if pid > 0: if verbose: sys.stdout.write ('pid %d\n' % pid) Log ("daemon started (pid %d)" % pid) open (pidfile, 'w').write ('%d' % pid) return sys.stdin.close () redirect_stdout_and_stderr () sched = BibSched() sched.watch_loop () return def stop (verbose = True): pid = server_pid () if not pid: error ('bibsched seems not to be running.') try: os.kill (pid, signal.SIGKILL) except OSError: print >> sys.stderr, 'no bibsched process found' Log ("daemon stopped (pid %d)" % pid) if verbose: print "stopping bibsched: pid %d" % pid os.unlink (pidfile) return def monitor (verbose = True): redirect_stdout_and_stderr() manager = Manager () return def restart (verbose = True): stop (verbose) start (verbose) return def main(): verbose = True try: opts, args = getopt.getopt(sys.argv[1:], "hVdq", [ "help","version","daemon", "quiet"]) except getopt.GetoptError, err: Log ("Error: %s" % err) usage(1, err) for opt, arg in opts: if opt in ["-h", "--help"]: usage (0) elif opt in ["-V", "--version"]: print __version__ sys.exit(0) elif opt in ["-d", "--daemon"]: redirect_stdout_and_stderr () sched = BibSched() Log("daemon started") sched.watch_loop() elif opt in ['-q', '--quiet']: verbose = False else: usage(1) try: cmd = args [0] except IndexError: cmd = 'monitor' try: { 'start': start, 'stop': stop, 'restart': restart, 'monitor': monitor } [cmd] (verbose) except KeyError: usage (1, 'unkown command: %s' % `cmd`) return if __name__ == '__main__': main() diff --git a/modules/miscutil/sql/tabcreate.sql b/modules/miscutil/sql/tabcreate.sql index f409520f1..5348246bf 100644 --- a/modules/miscutil/sql/tabcreate.sql +++ b/modules/miscutil/sql/tabcreate.sql @@ -1,3031 +1,3040 @@ -- $Id$ -- This file is part of CDS Invenio. -- Copyright (C) 2002, 2003, 2004, 2005, 2006 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. -- 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(2) 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(2) 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(2) 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, setDefinition text NOT NULL default '', setRecList longblob, p1 text, f1 text, m1 text, p2 text, f2 text, m2 text, p3 text, f3 text, m3 text, 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(5) NOT NULL default 'h__', 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(2) 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(2) 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(2) 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 varchar(255) 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(50) NOT NULL default '', description text default '', join_policy char(2) NOT NULL default '', PRIMARY KEY (id), 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', 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), 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), 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 ( 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 '', 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 longtext, status varchar(50), progress varchar(255), PRIMARY KEY (id) ) TYPE=MyISAM; +-- External collections + +CREATE TABLE IF NOT EXISTS collection_externalcollection ( + id_collection INT, + name_external_searchengine VARCHAR(256), + type INT, + is_default BOOL +) TYPE=MyISAM; + -- webMessage tables -- end of file diff --git a/modules/miscutil/sql/tabdrop.sql b/modules/miscutil/sql/tabdrop.sql index 9e4d46ba3..8e2cb6ead 100644 --- a/modules/miscutil/sql/tabdrop.sql +++ b/modules/miscutil/sql/tabdrop.sql @@ -1,371 +1,372 @@ -- $Id$ -- This file is part of CDS Invenio. -- Copyright (C) 2002, 2003, 2004, 2005, 2006 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. DROP TABLE IF EXISTS bibrec; DROP TABLE IF EXISTS bib00x; DROP TABLE IF EXISTS bib01x; DROP TABLE IF EXISTS bib02x; DROP TABLE IF EXISTS bib03x; DROP TABLE IF EXISTS bib04x; DROP TABLE IF EXISTS bib05x; DROP TABLE IF EXISTS bib06x; DROP TABLE IF EXISTS bib07x; DROP TABLE IF EXISTS bib08x; DROP TABLE IF EXISTS bib09x; DROP TABLE IF EXISTS bib10x; DROP TABLE IF EXISTS bib11x; DROP TABLE IF EXISTS bib12x; DROP TABLE IF EXISTS bib13x; DROP TABLE IF EXISTS bib14x; DROP TABLE IF EXISTS bib15x; DROP TABLE IF EXISTS bib16x; DROP TABLE IF EXISTS bib17x; DROP TABLE IF EXISTS bib18x; DROP TABLE IF EXISTS bib19x; DROP TABLE IF EXISTS bib20x; DROP TABLE IF EXISTS bib21x; DROP TABLE IF EXISTS bib22x; DROP TABLE IF EXISTS bib23x; DROP TABLE IF EXISTS bib24x; DROP TABLE IF EXISTS bib25x; DROP TABLE IF EXISTS bib26x; DROP TABLE IF EXISTS bib27x; DROP TABLE IF EXISTS bib28x; DROP TABLE IF EXISTS bib29x; DROP TABLE IF EXISTS bib30x; DROP TABLE IF EXISTS bib31x; DROP TABLE IF EXISTS bib32x; DROP TABLE IF EXISTS bib33x; DROP TABLE IF EXISTS bib34x; DROP TABLE IF EXISTS bib35x; DROP TABLE IF EXISTS bib36x; DROP TABLE IF EXISTS bib37x; DROP TABLE IF EXISTS bib38x; DROP TABLE IF EXISTS bib39x; DROP TABLE IF EXISTS bib40x; DROP TABLE IF EXISTS bib41x; DROP TABLE IF EXISTS bib42x; DROP TABLE IF EXISTS bib43x; DROP TABLE IF EXISTS bib44x; DROP TABLE IF EXISTS bib45x; DROP TABLE IF EXISTS bib46x; DROP TABLE IF EXISTS bib47x; DROP TABLE IF EXISTS bib48x; DROP TABLE IF EXISTS bib49x; DROP TABLE IF EXISTS bib50x; DROP TABLE IF EXISTS bib51x; DROP TABLE IF EXISTS bib52x; DROP TABLE IF EXISTS bib53x; DROP TABLE IF EXISTS bib54x; DROP TABLE IF EXISTS bib55x; DROP TABLE IF EXISTS bib56x; DROP TABLE IF EXISTS bib57x; DROP TABLE IF EXISTS bib58x; DROP TABLE IF EXISTS bib59x; DROP TABLE IF EXISTS bib60x; DROP TABLE IF EXISTS bib61x; DROP TABLE IF EXISTS bib62x; DROP TABLE IF EXISTS bib63x; DROP TABLE IF EXISTS bib64x; DROP TABLE IF EXISTS bib65x; DROP TABLE IF EXISTS bib66x; DROP TABLE IF EXISTS bib67x; DROP TABLE IF EXISTS bib68x; DROP TABLE IF EXISTS bib69x; DROP TABLE IF EXISTS bib70x; DROP TABLE IF EXISTS bib71x; DROP TABLE IF EXISTS bib72x; DROP TABLE IF EXISTS bib73x; DROP TABLE IF EXISTS bib74x; DROP TABLE IF EXISTS bib75x; DROP TABLE IF EXISTS bib76x; DROP TABLE IF EXISTS bib77x; DROP TABLE IF EXISTS bib78x; DROP TABLE IF EXISTS bib79x; DROP TABLE IF EXISTS bib80x; DROP TABLE IF EXISTS bib81x; DROP TABLE IF EXISTS bib82x; DROP TABLE IF EXISTS bib83x; DROP TABLE IF EXISTS bib84x; DROP TABLE IF EXISTS bib85x; DROP TABLE IF EXISTS bib86x; DROP TABLE IF EXISTS bib87x; DROP TABLE IF EXISTS bib88x; DROP TABLE IF EXISTS bib89x; DROP TABLE IF EXISTS bib90x; DROP TABLE IF EXISTS bib91x; DROP TABLE IF EXISTS bib92x; DROP TABLE IF EXISTS bib93x; DROP TABLE IF EXISTS bib94x; DROP TABLE IF EXISTS bib95x; DROP TABLE IF EXISTS bib96x; DROP TABLE IF EXISTS bib97x; DROP TABLE IF EXISTS bib98x; DROP TABLE IF EXISTS bib99x; DROP TABLE IF EXISTS bibrec_bib00x; DROP TABLE IF EXISTS bibrec_bib01x; DROP TABLE IF EXISTS bibrec_bib02x; DROP TABLE IF EXISTS bibrec_bib03x; DROP TABLE IF EXISTS bibrec_bib04x; DROP TABLE IF EXISTS bibrec_bib05x; DROP TABLE IF EXISTS bibrec_bib06x; DROP TABLE IF EXISTS bibrec_bib07x; DROP TABLE IF EXISTS bibrec_bib08x; DROP TABLE IF EXISTS bibrec_bib09x; DROP TABLE IF EXISTS bibrec_bib10x; DROP TABLE IF EXISTS bibrec_bib11x; DROP TABLE IF EXISTS bibrec_bib12x; DROP TABLE IF EXISTS bibrec_bib13x; DROP TABLE IF EXISTS bibrec_bib14x; DROP TABLE IF EXISTS bibrec_bib15x; DROP TABLE IF EXISTS bibrec_bib16x; DROP TABLE IF EXISTS bibrec_bib17x; DROP TABLE IF EXISTS bibrec_bib18x; DROP TABLE IF EXISTS bibrec_bib19x; DROP TABLE IF EXISTS bibrec_bib20x; DROP TABLE IF EXISTS bibrec_bib21x; DROP TABLE IF EXISTS bibrec_bib22x; DROP TABLE IF EXISTS bibrec_bib23x; DROP TABLE IF EXISTS bibrec_bib24x; DROP TABLE IF EXISTS bibrec_bib25x; DROP TABLE IF EXISTS bibrec_bib26x; DROP TABLE IF EXISTS bibrec_bib27x; DROP TABLE IF EXISTS bibrec_bib28x; DROP TABLE IF EXISTS bibrec_bib29x; DROP TABLE IF EXISTS bibrec_bib30x; DROP TABLE IF EXISTS bibrec_bib31x; DROP TABLE IF EXISTS bibrec_bib32x; DROP TABLE IF EXISTS bibrec_bib33x; DROP TABLE IF EXISTS bibrec_bib34x; DROP TABLE IF EXISTS bibrec_bib35x; DROP TABLE IF EXISTS bibrec_bib36x; DROP TABLE IF EXISTS bibrec_bib37x; DROP TABLE IF EXISTS bibrec_bib38x; DROP TABLE IF EXISTS bibrec_bib39x; DROP TABLE IF EXISTS bibrec_bib40x; DROP TABLE IF EXISTS bibrec_bib41x; DROP TABLE IF EXISTS bibrec_bib42x; DROP TABLE IF EXISTS bibrec_bib43x; DROP TABLE IF EXISTS bibrec_bib44x; DROP TABLE IF EXISTS bibrec_bib45x; DROP TABLE IF EXISTS bibrec_bib46x; DROP TABLE IF EXISTS bibrec_bib47x; DROP TABLE IF EXISTS bibrec_bib48x; DROP TABLE IF EXISTS bibrec_bib49x; DROP TABLE IF EXISTS bibrec_bib50x; DROP TABLE IF EXISTS bibrec_bib51x; DROP TABLE IF EXISTS bibrec_bib52x; DROP TABLE IF EXISTS bibrec_bib53x; DROP TABLE IF EXISTS bibrec_bib54x; DROP TABLE IF EXISTS bibrec_bib55x; DROP TABLE IF EXISTS bibrec_bib56x; DROP TABLE IF EXISTS bibrec_bib57x; DROP TABLE IF EXISTS bibrec_bib58x; DROP TABLE IF EXISTS bibrec_bib59x; DROP TABLE IF EXISTS bibrec_bib60x; DROP TABLE IF EXISTS bibrec_bib61x; DROP TABLE IF EXISTS bibrec_bib62x; DROP TABLE IF EXISTS bibrec_bib63x; DROP TABLE IF EXISTS bibrec_bib64x; DROP TABLE IF EXISTS bibrec_bib65x; DROP TABLE IF EXISTS bibrec_bib66x; DROP TABLE IF EXISTS bibrec_bib67x; DROP TABLE IF EXISTS bibrec_bib68x; DROP TABLE IF EXISTS bibrec_bib69x; DROP TABLE IF EXISTS bibrec_bib70x; DROP TABLE IF EXISTS bibrec_bib71x; DROP TABLE IF EXISTS bibrec_bib72x; DROP TABLE IF EXISTS bibrec_bib73x; DROP TABLE IF EXISTS bibrec_bib74x; DROP TABLE IF EXISTS bibrec_bib75x; DROP TABLE IF EXISTS bibrec_bib76x; DROP TABLE IF EXISTS bibrec_bib77x; DROP TABLE IF EXISTS bibrec_bib78x; DROP TABLE IF EXISTS bibrec_bib79x; DROP TABLE IF EXISTS bibrec_bib80x; DROP TABLE IF EXISTS bibrec_bib81x; DROP TABLE IF EXISTS bibrec_bib82x; DROP TABLE IF EXISTS bibrec_bib83x; DROP TABLE IF EXISTS bibrec_bib84x; DROP TABLE IF EXISTS bibrec_bib85x; DROP TABLE IF EXISTS bibrec_bib86x; DROP TABLE IF EXISTS bibrec_bib87x; DROP TABLE IF EXISTS bibrec_bib88x; DROP TABLE IF EXISTS bibrec_bib89x; DROP TABLE IF EXISTS bibrec_bib90x; DROP TABLE IF EXISTS bibrec_bib91x; DROP TABLE IF EXISTS bibrec_bib92x; DROP TABLE IF EXISTS bibrec_bib93x; DROP TABLE IF EXISTS bibrec_bib94x; DROP TABLE IF EXISTS bibrec_bib95x; DROP TABLE IF EXISTS bibrec_bib96x; DROP TABLE IF EXISTS bibrec_bib97x; DROP TABLE IF EXISTS bibrec_bib98x; DROP TABLE IF EXISTS bibrec_bib99x; DROP TABLE IF EXISTS bibfmt; DROP TABLE IF EXISTS idxINDEX; DROP TABLE IF EXISTS idxINDEXNAME; DROP TABLE IF EXISTS idxINDEX_field; DROP TABLE IF EXISTS idxWORD01F; DROP TABLE IF EXISTS idxWORD02F; DROP TABLE IF EXISTS idxWORD03F; DROP TABLE IF EXISTS idxWORD04F; DROP TABLE IF EXISTS idxWORD05F; DROP TABLE IF EXISTS idxWORD06F; DROP TABLE IF EXISTS idxWORD07F; DROP TABLE IF EXISTS idxWORD08F; DROP TABLE IF EXISTS idxWORD09F; DROP TABLE IF EXISTS idxWORD10F; DROP TABLE IF EXISTS idxWORD01R; DROP TABLE IF EXISTS idxWORD02R; DROP TABLE IF EXISTS idxWORD03R; DROP TABLE IF EXISTS idxWORD04R; DROP TABLE IF EXISTS idxWORD05R; DROP TABLE IF EXISTS idxWORD06R; DROP TABLE IF EXISTS idxWORD07R; DROP TABLE IF EXISTS idxWORD08R; DROP TABLE IF EXISTS idxWORD09R; DROP TABLE IF EXISTS idxWORD10R; DROP TABLE IF EXISTS idxPHRASE01F; DROP TABLE IF EXISTS idxPHRASE02F; DROP TABLE IF EXISTS idxPHRASE03F; DROP TABLE IF EXISTS idxPHRASE04F; DROP TABLE IF EXISTS idxPHRASE05F; DROP TABLE IF EXISTS idxPHRASE06F; DROP TABLE IF EXISTS idxPHRASE07F; DROP TABLE IF EXISTS idxPHRASE08F; DROP TABLE IF EXISTS idxPHRASE09F; DROP TABLE IF EXISTS idxPHRASE10F; DROP TABLE IF EXISTS idxPHRASE01R; DROP TABLE IF EXISTS idxPHRASE02R; DROP TABLE IF EXISTS idxPHRASE03R; DROP TABLE IF EXISTS idxPHRASE04R; DROP TABLE IF EXISTS idxPHRASE05R; DROP TABLE IF EXISTS idxPHRASE06R; DROP TABLE IF EXISTS idxPHRASE07R; DROP TABLE IF EXISTS idxPHRASE08R; DROP TABLE IF EXISTS idxPHRASE09R; DROP TABLE IF EXISTS idxPHRASE10R; DROP TABLE IF EXISTS rnkMETHOD; DROP TABLE IF EXISTS rnkMETHODNAME; DROP TABLE IF EXISTS rnkMETHODDATA; DROP TABLE IF EXISTS rnkWORD01F; DROP TABLE IF EXISTS rnkWORD01R; DROP TABLE IF EXISTS rnkPAGEVIEWS; DROP TABLE IF EXISTS rnkDOWNLOADS; DROP TABLE IF EXISTS rnkCITATIONDATA; DROP TABLE IF EXISTS collection_rnkMETHOD; DROP TABLE IF EXISTS collection; DROP TABLE IF EXISTS collectionname; DROP TABLE IF EXISTS oaiARCHIVE; DROP TABLE IF EXISTS oaiHARVEST; DROP TABLE IF EXISTS collection_collection; DROP TABLE IF EXISTS collection_portalbox; DROP TABLE IF EXISTS portalbox; DROP TABLE IF EXISTS collection_example; DROP TABLE IF EXISTS example; DROP TABLE IF EXISTS collection_format; DROP TABLE IF EXISTS format; DROP TABLE IF EXISTS formatname; DROP TABLE IF EXISTS collection_field_fieldvalue; DROP TABLE IF EXISTS field; DROP TABLE IF EXISTS fieldname; DROP TABLE IF EXISTS fieldvalue; DROP TABLE IF EXISTS field_tag; DROP TABLE IF EXISTS tag; DROP TABLE IF EXISTS publreq; DROP TABLE IF EXISTS session; DROP TABLE IF EXISTS user; DROP TABLE IF EXISTS accROLE; DROP TABLE IF EXISTS user_accROLE; DROP TABLE IF EXISTS accACTION; DROP TABLE IF EXISTS accARGUMENT; DROP TABLE IF EXISTS accROLE_accACTION_accARGUMENT; DROP TABLE IF EXISTS user_query; DROP TABLE IF EXISTS query; DROP TABLE IF EXISTS user_basket; DROP TABLE IF EXISTS basket; DROP TABLE IF EXISTS basket_record; DROP TABLE IF EXISTS record; DROP TABLE IF EXISTS user_query_basket; DROP TABLE IF EXISTS cmtRECORDCOMMENT; DROP TABLE IF EXISTS fmtKNOWLEDGEBASES; DROP TABLE IF EXISTS fmtKNOWLEDGEBASEMAPPINGS; DROP TABLE IF EXISTS flxFORMATS; DROP TABLE IF EXISTS flxKBS; DROP TABLE IF EXISTS flxKBDBCOLLID2COLL; DROP TABLE IF EXISTS flxKBDBCOLLID2BIBTEX; DROP TABLE IF EXISTS flxKBEJOURNALS; DROP TABLE IF EXISTS flxLINKTYPES; DROP TABLE IF EXISTS flxLINKTYPECONDITIONS; DROP TABLE IF EXISTS flxLINKTYPECONDITIONSACTIONS; DROP TABLE IF EXISTS flxLINKTYPECONDITIONSFILEFORMATS; DROP TABLE IF EXISTS flxFILEFORMATS; DROP TABLE IF EXISTS flxLINKTYPEPARAMS; DROP TABLE IF EXISTS flxXMLMARCEXTRULES; DROP TABLE IF EXISTS flxXMLMARCEXTRULESUBFIELDS; DROP TABLE IF EXISTS flxBEHAVIORCONDITIONSACTIONS; DROP TABLE IF EXISTS flxBEHAVIORCONDITIONS; DROP TABLE IF EXISTS flxBEHAVIORS; DROP TABLE IF EXISTS flxUDFS; DROP TABLE IF EXISTS flxUDFPARAMS; DROP TABLE IF EXISTS flxUSERS; DROP TABLE IF EXISTS flxREFORMAT; DROP TABLE IF EXISTS sbmACTION; DROP TABLE IF EXISTS sbmALLFUNCDESCR; DROP TABLE IF EXISTS sbmAPPROVAL; DROP TABLE IF EXISTS sbmCOLLECTION; DROP TABLE IF EXISTS sbmCOLLECTION_sbmCOLLECTION; DROP TABLE IF EXISTS sbmCOLLECTION_sbmDOCTYPE; DROP TABLE IF EXISTS sbmCATEGORIES; DROP TABLE IF EXISTS sbmCHECKS; DROP TABLE IF EXISTS sbmCOOKIES; DROP TABLE IF EXISTS sbmDOCTYPE; DROP TABLE IF EXISTS sbmFIELD; DROP TABLE IF EXISTS sbmFIELDDESC; DROP TABLE IF EXISTS sbmFORMATEXTENSION; DROP TABLE IF EXISTS sbmFUNCTIONS; DROP TABLE IF EXISTS sbmFUNDESC; DROP TABLE IF EXISTS sbmGFILERESULT; DROP TABLE IF EXISTS sbmIMPLEMENT; DROP TABLE IF EXISTS sbmPARAMETERS; DROP TABLE IF EXISTS sbmPUBLICATION; DROP TABLE IF EXISTS sbmPUBLICATIONCOMM; DROP TABLE IF EXISTS sbmPUBLICATIONDATA; DROP TABLE IF EXISTS sbmREFEREES; DROP TABLE IF EXISTS sbmSUBMISSIONS; DROP TABLE IF EXISTS schTASK; DROP TABLE IF EXISTS bibdoc; DROP TABLE IF EXISTS bibdoc_bibdoc; DROP TABLE IF EXISTS bibrec_bibdoc; DROP TABLE IF EXISTS usergroup; DROP TABLE IF EXISTS user_usergroup; DROP TABLE IF EXISTS user_basket; DROP TABLE IF EXISTS msgMESSAGE; DROP TABLE IF EXISTS user_msgMESSAGE; DROP TABLE IF EXISTS bskBASKET; DROP TABLE IF EXISTS bskEXTREC; DROP TABLE IF EXISTS bskEXTFMT; DROP TABLE IF EXISTS bskREC; DROP TABLE IF EXISTS bskRECORDCOMMENT; DROP TABLE IF EXISTS cmtACTIONHISTORY; DROP TABLE IF EXISTS user_bskBASKET; DROP TABLE IF EXISTS usergroup_bskBASKET; +DROP TABLE IF EXISTS collection_externalcollection; -- end of file diff --git a/modules/websearch/bin/webcoll.in b/modules/websearch/bin/webcoll.in index 7a15c55c5..b1e0449fc 100644 --- a/modules/websearch/bin/webcoll.in +++ b/modules/websearch/bin/webcoll.in @@ -1,1077 +1,1090 @@ #!@PYTHON@ ## -*- mode: python; coding: utf-8; -*- ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006 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.""" __version__ = "$Id$" ## import modules: try: 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 except ImportError, e: print "Error: %s" % e sys.exit(1) try: from invenio.config import * 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_config import cfg_author_et_al_threshold, cfg_instant_browse, cfg_max_recID, cfg_narrow_search_show_grandsons from invenio.dbquery import run_sql, escape_string, Error from invenio.access_control_engine import acc_authorize_action from invenio.bibrank_record_sorter import get_bibrank_methods import invenio.template websearch_templates = invenio.template.load('websearch') except ImportError, e: print "Error: %s" % e sys.exit(1) +from invenio.websearch_external_collections import build_dictionnaries_from_db_tables + ## 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())) stream.write("%s\n" % msg) 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 def print_record(recID, format='hb', ln=cdslang): "Prints record 'recID' formatted accoding to 'format'." out = "" # HTML brief format by default 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" % zlib.decompress(res[0][0]) else: # record 'recID' does not exist in format 'format', so print some default format: # firstly, title: titles = get_field(recID, "245__a") # secondly, authors: authors = get_field(recID, "100__a") + get_field(recID, "700__a") # thirdly, date of creation: dates = get_field(recID, "260__c") # thirdly bis, report numbers: rns = get_field(recID, "037__a") + get_field(recID, "088__a") # fourthly, beginning of abstract: abstracts = get_field(recID, "520__a") # fifthly, fulltext link: urls_z = get_field(recID, "8564_z") urls_u = get_field(recID, "8564_u") out += websearch_templates.tmpl_record_body( weburl = weburl, titles = titles, authors = authors, dates = dates, rns = rns, abstracts = abstracts, urls_u = urls_u, urls_z = urls_z, ln=ln) # at the end of HTML mode, print "Detailed record" and "Mark record" functions: out += websearch_templates.tmpl_record_links( weburl = weburl, recid = recID, ln = ln ) 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 wihtout much refactoring self.update_reclist_run_already = 0 # to speed things up wihtout 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][5]))) 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 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.""" ## do this for each language: for lang, lang_fullname in language_list_long(): # 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"), + 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, time.strftime("%d %b %Y %H:%M:%S %Z", time.localtime())) 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_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_narrow_search_show_grandsons, grandsons = grandsons ) + def create_external_collections_box(self, ln=cdslang): + + (dico_collection_external_searches, dico_collection_external_seealso) = build_dictionnaries_from_db_tables() + if not dico_collection_external_searches.has_key(self.id): + return "" + + engines_list = [engine for engine in dico_collection_external_searches[self.id]] + engines_list.sort(lambda x, y: cmp(x.name, y.name)) + + return websearch_templates.tmpl_searchalso(ln, engines_list, self.id) + def create_instant_browse(self, rg=cfg_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: if self.nbrecs and self.reclist: # firstly, get last 'rg' records: recIDs = Numeric.nonzero(self.reclist._set) passIDs = [] total = len(recIDs) to_display = min(rg, total) for idx in range(total-1, total-to_display-1, -1): recid = recIDs[idx] passIDs.append({'id': recid, 'body': print_record(recid, ln=ln), 'date': get_creation_date(recid, fmt="%Y-%m-%d<br>%H:%i")}) 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}] # @todo 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." # 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." # 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: reclist = search_pattern(None,self.dbquery) 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.extend(map(lambda x: str(x[11]), run_sql("SHOW TABLE STATUS LIKE 'bibrec'"))) database_tables_timestamps.extend(map(lambda x: str(x[11]), run_sql("SHOW TABLE STATUS LIKE 'bibfmt'"))) database_tables_timestamps.extend(map(lambda x: str(x[11]), run_sql("SHOW TABLE STATUS LIKE 'idxWORD%%'"))) database_tables_timestamps.extend(map(lambda x: str(x[11]), run_sql("SHOW TABLE STATUS LIKE 'collection%%'"))) database_tables_timestamps.extend(map(lambda x: str(x[11]), run_sql("SHOW TABLE STATUS LIKE 'portalbox'"))) database_tables_timestamps.extend(map(lambda x: str(x[11]), run_sql("SHOW TABLE STATUS LIKE 'field%%'"))) database_tables_timestamps.extend(map(lambda x: str(x[11]), run_sql("SHOW TABLE STATUS LIKE 'format%%'"))) database_tables_timestamps.extend(map(lambda x: str(x[11]), run_sql("SHOW TABLE STATUS LIKE '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)) 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 or nickname=%s", (user, 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("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 == 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: 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: i = 0 for coll in colls: i += 1 if options["verbose"]: write_message("%s / web 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 ## 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("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:f", ["help", "version", "verbose=","user=","sleep=","time=","collection=","force"]) 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 __version__ 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 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/Makefile.am b/modules/websearch/lib/Makefile.am index 69612812b..1acc003fa 100644 --- a/modules/websearch/lib/Makefile.am +++ b/modules/websearch/lib/Makefile.am @@ -1,34 +1,42 @@ ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006 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 = \ websearchadminlib.py \ websearch_templates.py \ websearch_webinterface.py \ websearch_regression_tests.py \ search_engine.py \ search_engine_config.py \ search_engine_tests.py \ - websearchadmin_regression_tests.py + websearchadmin_regression_tests.py \ + websearch_external_collections.py \ + websearch_external_collections_config.py \ + websearch_external_collections_page_getter.py \ + websearch_external_collections_parser.py \ + websearch_external_collections_searcher.py \ + websearch_external_collections_templates.py \ + websearch_external_collections_tests.py \ + websearch_external_collections_utils.py EXTRA_DIST = $(pylib_DATA) CLEANFILES = *~ *.tmp *.pyc diff --git a/modules/websearch/lib/search_engine.py b/modules/websearch/lib/search_engine.py index da9d2d866..991183144 100644 --- a/modules/websearch/lib/search_engine.py +++ b/modules/websearch/lib/search_engine.py @@ -1,3476 +1,3453 @@ # -*- coding: utf-8 -*- ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006 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 Search Engine in mod_python.""" __lastupdated__ = """$Date$""" __version__ = "$Id$" ## import general modules: import cgi import copy import string import os import sre import sys import time import traceback import urllib import zlib import Numeric from xml.dom import minidom ## import CDS Invenio stuff: from invenio.config import * from invenio.search_engine_config import * 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, get_output_format_content_type, create_excel from invenio.bibformat_config import use_old_bibformat +from invenio.websearch_external_collections import print_external_results_overview, perform_external_collection_search + 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.bibrank_downloads_grapher import create_download_history_graph_and_box from invenio.dbquery import run_sql, escape_string, Error try: from mod_python import apache from invenio.webuser import getUid from invenio.webpage import 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, wash_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? ## 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")) def get_alphabetically_ordered_collection_list(level=0): """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 for long collection names): if len(c_name)>30: c_printable = c_name[:30] + "..." else: c_printable = c_name 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): """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 for long collection names): if len(c)>30: c_printable = c[:30] + "..." else: c_printable = c 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) 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 <em>any field</em>. 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 <em>within title</em> 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_fields_convert.has_key(string.lower(fi)): fi = cfg_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 <em>%s</em> 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'): # we are doing XML output: req.content_type = "text/xml" req.send_http_header() req.write("""<?xml version="1.0" encoding="UTF-8"?>\n""") if of.startswith("xm"): req.write("""<collection xmlns="http://www.loc.gov/MARC21/slim">\n""") else: req.write("""<collection>\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)) 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)) elif of.startswith('x'): req.write("""</collection>\n""") 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 += """<select name="%sd">""" % name box += """<option value="">%s""" % _("any day") for day in range(1,32): box += """<option value="%02d"%s>%02d""" % (day, is_selected(day, selected_day), day) box += """</select>""" # month box += """<select name="%sm">""" % name box += """<option value="">%s""" % _("any month") for mm, month in [(1,_("January")), (2,_("February")), (3,_("March")), (4,_("April")), \ (5,_("May")), (6,_("June")), (7,_("July")), (8,_("August")), \ (9,_("September")), (10,_("October")), (11,_("November")), (12,_("December"))]: box += """<option value="%02d"%s>%s""" % (mm, is_selected(mm, selected_month), month) box += """</select>""" # year box += """<select name="%sy">""" % name box += """<option value="">%s""" % _("any year") this_year = int(time.strftime("%Y", time.localtime())) for year in range(this_year-20, this_year+1): box += """<option value="%d"%s>%d""" % (year, is_selected(year, selected_year), year) box += """</select>""" return box -def create_google_box(cc, p, f, p1, p2, p3, ln=cdslang, - prolog_start="""<table class="googlebox"><tr><th colspan="2" class="googleboxheader">""", - prolog_end="""</th></tr><tr><td class="googleboxbody">""", - column_separator="""</td><td class="googleboxbody">""", - link_separator= """<br>""", - epilog="""</td></tr></table>"""): - "Creates the box that proposes links to other useful search engines like Google. 'p' is the search pattern." - if not p and (p1 or p2 or p3): - p = p1 + " " + p2 + " " + p3 - # check suitable p's whether we want to print it - if cfg_google_box == 0 or \ - p == "" or \ - string.find(p, "recid:")>=0 or \ - string.find(p, "sysno:")>=0 or \ - string.find(p, "sysnos:")>=0: - return "" - # remove our logical field index names: - p = sre.sub(r'\w+:', '', p) - - return websearch_templates.tmpl_google_box( - ln = ln, - cc = cc, - p = p, - f = f, - prolog_start = prolog_start, - prolog_end = prolog_end, - column_separator = column_separator, - link_separator = link_separator, - epilog = epilog, - ) - 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, + m3, sc, pl, d1y, d1m, d1d, d2y, d2m, d2d, jrec, ec, action=""): "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() else: colls_nicely_ordered = get_alphabetically_ordered_collection_list() 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, + 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." out = "" out += """<select name="%s">""" % fieldname out += """<option value="">%s""" % get_field_i18nname("any field", ln) query = "SELECT code,name FROM field ORDER BY name ASC" res = run_sql(query) for field_code, field_name in res: if field_code and field_code != "anyfield": out += """<option value="%s"%s>%s""" % (field_code, is_selected(field_code,value), get_field_i18nname(field_name, ln)) if value and str(value[0]).isdigit(): out += """<option value="%s" selected>%s MARC tag""" % (value, value) out += """</select>""" return out def get_searchwithin_fields(ln='en'): "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 = """ <select name="%s"> <option value="a"%s>%s <option value="o"%s>%s <option value="n"%s>%s </select> """ % (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 = """ <select name="%s"> <option value="a"%s>%s <option value="o"%s>%s <option value="e"%s>%s <option value="p"%s>%s <option value="r"%s>%s </select> """ % (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; """ 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): cc = cdsname # cc is not real, 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) 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_fields_convert.has_key(string.lower(f)): f = cfg_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: res = run_sql("SHOW TABLE STATUS LIKE 'collectionname'") if res and str(res[0][11])>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: res = run_sql("SHOW TABLE STATUS LIKE 'fieldname'") if res and str(res[0][11])>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: res = run_sql("SHOW TABLE STATUS LIKE 'collection'") if res and str(res[0][11])>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] != 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, """<p>No match close to <em>%s</em> found in given collections. #Please try different term.<p>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)<len(basic_search_units) and basic_search_units[idx_unit+1][0]=="|"): # stage 2-1: this basic search unit is retained, since # either the hitset is non-empty, or the approximate # pattern treatment is switched off, or the search unit # was joined by an OR operator to preceding/following # units so we do not require that it exists basic_search_units_hitsets.append(basic_search_unit_hitset) else: # stage 2-2: no hits found for this search unit, try to replace non-alphanumeric chars inside pattern: if sre.search(r'[^a-zA-Z0-9\s\:]', bsu_p): if bsu_p.startswith('"') and bsu_p.endswith('"'): # is it ACC query? bsu_pn = sre.sub(r'[^a-zA-Z0-9\s\:]+', "*", bsu_p) else: # it is WRD query bsu_pn = sre.sub(r'[^a-zA-Z0-9\s\:]+', " ", bsu_p) if verbose and of.startswith('h') and req: print_warning(req, "trying (%s,%s,%s)" % (bsu_pn,bsu_f,bsu_m)) basic_search_unit_hitset = search_pattern(req=None, p=bsu_pn, f=bsu_f, m=bsu_m, of="id", ln=ln) if basic_search_unit_hitset._nbhits > 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': "<em>"+bsu_p+"</em>", 'x_query2': "<em>"+bsu_pn+"</em>"}) 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_fields_convert.has_key(string.lower(f)): f = cfg_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(colls, ','), 'x_url_open': '<a class="nearestterms" href="%s">' % (url), 'x_nb_hits': results_in_Home._nbhits, 'x_url_close': '</a>'}) 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_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': "<em>" + (p.startswith("%") and p.endswith("%") and p[1:-1] or p) + "</em>", 'x_index': "<em>" + get_field_i18nname(f, ln) + "</em>"} else: intro = _("Search term %s did not match any record. Nearest terms in any collection are:") % \ ("<em>" + (p.startswith("%") and p.endswith("%") and p[1:-1] or p) + "</em>") 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 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 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 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] 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 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='<br>', epilogue='<br>'): "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): "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, ) 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_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_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.startswith(sort_pattern): # 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=''): """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. """ # load the right message language _ = gettext_set_language(ln) # get user id (for formatting based on priviledge) uid = getUid(req) # sanity checking: if req == None: return 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'): # we are doing XML output: for irec in range(irec_max,irec_min,-1): req.write(print_record(recIDs[irec], format, ot, ln, search_pattern=search_pattern, uid=uid)) 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) 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)) 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) 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), '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 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_record(recID, format='hb', ot='', ln=cdslang, decompress=zlib.decompress, search_pattern=None, uid=None): "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 use_old_bibformat \ and not format.lower().startswith('t') \ and not format.lower().startswith('hm') \ and not str(format[0:3]).isdigit(): #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: query = "SELECT value FROM bibfmt WHERE id_bibrec='%s' AND format='%s'" % (recID, format) res = run_sql(query) if res and not 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', so try to call BibFormat on the fly: or use default format: out += call_bibformat(recID, format, ln, search_pattern=search_pattern, uid=uid) # at the end of HTML brief mode, print the "Detailed record" functionality: if format.lower().startswith('hb'): 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 += " <record>\n" out += " <header>\n" for oai_id in get_fieldvalues(recID, cfg_oai_id_field): out += " <identifier>%s</identifier>\n" % oai_id out += " <datestamp>%s</datestamp>\n" % get_modification_date(recID) out += " </header>\n" out += " <metadata>\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 += """ <record xmlns="http://www.loc.gov/MARC21/slim">\n""" out += " <controlfield tag=\"001\">%d</controlfield>\n" % int(recID) elif format.startswith("xm"): out += """ <record>\n""" out += " <controlfield tag=\"001\">%d</controlfield>\n" % int(recID) if record_exist_p == -1: # deleted record, so display only OAI ID and 980: oai_ids = get_fieldvalues(recID, cfg_oaiidtag) if oai_ids: out += "<datafield tag=\"%s\" ind1=\"%s\" ind2=\"%s\"><subfield code=\"%s\">%s</subfield></datafield>\n" % \ (cfg_oaiidtag[0:3], cfg_oaiidtag[3:4], cfg_oaiidtag[4:5], cfg_oaiidtag[5:6], oai_ids[0]) out += "<datafield tag=\"980\" ind1=\"\" ind2=\"\"><subfield code=\"c\">DELETED</subfield></datafield>\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 += """ </datafield>\n""" out += """ <datafield tag="%s" ind1="%s" ind2="%s">\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 += """ <subfield code="%s">%s</subfield>\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 += """ </datafield>\n""" # we are at the end of printing the record: if format.startswith("xm") or format == "marcxml": out += " </record>\n" elif format == "xd" or format == "oai_dc": # XML Dublin Core format, possibly OAI -- select only some bibXXx fields: out += """ <dc xmlns="http://purl.org/dc/elements/1.1/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://purl.org/dc/elements/1.1/ http://www.openarchives.org/OAI/1.1/dc.xsd">\n""" if record_exist_p == -1: out += "" else: for f in get_fieldvalues(recID, "041__a"): out += " <language>%s</language>\n" % f for f in get_fieldvalues(recID, "100__a"): out += " <creator>%s</creator>\n" % encode_for_xml(f) for f in get_fieldvalues(recID, "700__a"): out += " <creator>%s</creator>\n" % encode_for_xml(f) for f in get_fieldvalues(recID, "245__a"): out += " <title>%s</title>\n" % encode_for_xml(f) for f in get_fieldvalues(recID, "65017a"): out += " <subject>%s</subject>\n" % encode_for_xml(f) for f in get_fieldvalues(recID, "8564_u"): out += " <identifier>%s</identifier>\n" % encode_for_xml(f) for f in get_fieldvalues(recID, "520__a"): out += " <description>%s</description>\n" % encode_for_xml(f) out += " <date>%s</date>\n" % get_creation_date(recID) out += " </dc>\n" elif str(format[0:3]).isdigit(): # user has asked to print some fields only if format == "001": out += "<!--%s-begin-->%s<!--%s-end-->\n" % (format, recID, format) else: vals = get_fieldvalues(recID, format) for val in vals: out += "<!--%s-begin-->%s<!--%s-end-->\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_oaiidtag, "980"]) else: out += get_fieldvalues_alephseq_like(recID, ot) elif format == "hm": if record_exist_p == -1: out += "<pre>" + cgi.escape(get_fieldvalues_alephseq_like(recID, ["001", cfg_oaiidtag, "980"])) + "</pre>" else: out += "<pre>" + cgi.escape(get_fieldvalues_alephseq_like(recID, ot)) + "</pre>" elif format.startswith("h") and ot: ## user directly asked for some tags to be displayed only if record_exist_p == -1: out += "<pre>" + get_fieldvalues_alephseq_like(recID, ["001", cfg_oaiidtag, "980"]) + "</pre>" else: out += "<pre>" + get_fieldvalues_alephseq_like(recID, ot) + "</pre>" 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) 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) 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) elif format.startswith("hs"): # for citation/download similarity navigation links: if record_exist_p == -1: out += _("The record has been deleted.") else: out += '<a href="%s">' % websearch_templates.build_search_url(recid=recID, ln=ln) # firstly, title: titles = get_fieldvalues(recID, "245__a") if titles: for title in titles: out += "<strong>%s</strong>" % title else: # usual title not found, try conference title: titles = get_fieldvalues(recID, "111__a") if titles: for title in titles: out += "<strong>%s</strong>" % title else: # just print record ID: out += "<strong>%s %d</strong>" % (get_field_i18nname("record ID", ln), recID) out += "</a>" # secondly, authors: authors = get_fieldvalues(recID, "100__a") + get_fieldvalues(recID, "700__a") if authors: out += " - %s" % authors[0] if len(authors) > 1: out += " <em>et al</em>" # 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_call_bibformat: out_record_in_format = call_bibformat(recID, format, ln, search_pattern=search_pattern, uid=uid) 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 += " </metadata>\n" out += " </record>\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): """ Calls BibFormat and returns formatted record. BibFormat will decide by itself if old or new BibFormat must be used. """ keywords = [] if search_pattern != 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) def log_query(hostname, query_args, uid=-1): """Log query into the query and user_query tables.""" 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 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): + 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 (cc, colls_to_display, colls_to_search) = wash_colls(cc, c, sc) # which colls to search and to display? 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) if of == "hb": of = "hd" if record_exists(recid): if recidb<=recid: # sanity check recidb=recid+1 print_records(req, range(recid,recidb), -1, -9999, of, ot, ln, search_pattern=p) 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.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, action)) + 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, action)) + 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) 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, action)) + 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) 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, action)) + 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"): - req.write(create_google_box(cc, p, f, p1, p2, p3, 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 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"): - req.write(create_google_box(cc, p, f, p1, p2, p3, 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 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)) - req.write(create_google_box(cc, p, f, p1, p2, p3, 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)) - req.write(create_google_box(cc, p, f, p1, p2, p3, 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"): - req.write(create_google_box(cc, p, f, p1, p2, p3, 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) # 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_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)) - req.write(create_google_box(cc, p, f, p1, p2, p3, 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"): - req.write(create_google_box(cc, p, f, p1, p2, p3, 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) # 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)) - req.write(create_google_box(cc, p, f, p1, p2, p3, 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"): - req.write(create_google_box(cc, p, f, p1, p2, p3, 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 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)) - req.write(create_google_box(cc, p, f, p1, p2, p3, 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"): - req.write(create_google_box(cc, p, f, p1, p2, p3, 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) 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)) + 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 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) 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)) if f == "author" and of.startswith("h"): req.write(create_similarly_named_authors_link_box(p, ln)) # log query: try: log_query(req.get_remote_host(), req.args, uid) 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) - ## 4 - write footer: + + # External searches if of.startswith("h"): - req.write(create_google_box(cc, p, f, p1, p2, p3, 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) 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 += "<h1>Search Cache</h1>" # clear cache if requested: if action == "clear": search_cache = {} collection_reclist_cache = create_collection_reclist_cache() # show collection reclist cache: out += "<h3>Collection reclist cache</h3>" res = run_sql("SHOW TABLE STATUS LIKE 'collection'") out += "- collection table last updated: %s" % str(res[0][11]) out += "<br>- reclist cache timestamp: %s" % collection_reclist_cache_timestamp out += "<br>- reclist cache contents:" out += "<blockquote>" for coll in collection_reclist_cache.keys(): if collection_reclist_cache[coll]: out += "%s (%d)<br>" % (coll, get_collection_reclist(coll)._nbhits) out += "</blockquote>" # show search cache: out += "<h3>Search Cache</h3>" out += "<blockquote>" if len(search_cache): out += """<table border="=">""" out += "<tr><td><strong>%s</strong></td><td><strong>%s</strong></td><td><strong>%s</strong></td><td><strong>%s</strong></td></tr>" % ("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 += "<tr><td>%s</td><td>%s</td><td>%s</td><td>%d</td></tr>" % (p, f, c, l) out += "</table>" else: out += "<p>Search cache is empty." out += "</blockquote>" out += """<p><a href="%s/search/cache?action=clear">clear cache</a>""" % weburl # show field i18nname cache: out += "<h3>Field I18N names cache</h3>" res = run_sql("SHOW TABLE STATUS LIKE 'fieldname'") out += "- fieldname table last updated: %s" % str(res[0][11]) out += "<br>- i18nname cache timestamp: %s" % field_i18nname_cache_timestamp out += "<br>- i18nname cache contents:" out += "<blockquote>" for field in field_i18nname_cache.keys(): for ln in field_i18nname_cache[field].keys(): out += "%s, %s = %s<br>" % (field, ln, field_i18nname_cache[field][ln]) out += "</blockquote>" # show collection i18nname cache: out += "<h3>Collection I18N names cache</h3>" res = run_sql("SHOW TABLE STATUS LIKE 'collectionname'") out += "- collectionname table last updated: %s" % str(res[0][11]) out += "<br>- i18nname cache timestamp: %s" % collection_i18nname_cache_timestamp out += "<br>- i18nname cache contents:" out += "<blockquote>" for coll in collection_i18nname_cache.keys(): for ln in collection_i18nname_cache[coll].keys(): out += "%s, %s = %s<br>" % (coll, ln, collection_i18nname_cache[coll][ln]) out += "</blockquote>" req.write("<html>") req.write(out) req.write("</html>") 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("<html>") req.write("<h1>Search Log</h1>") if date: # case A: display stats for a day yyyymmdd = string.atoi(date) req.write("<p><big><strong>Date: %d</strong></big><p>" % yyyymmdd) req.write("""<table border="1">""") req.write("<tr><td><strong>%s</strong></td><td><strong>%s</strong></td><td><strong>%s</strong></td><td><strong>%s</strong></td><td><strong>%s</strong></td><td><strong>%s</strong></td></tr>" % ("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("<tr><td align=\"right\">#%d</td><td>%s:%s:%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>" \ % (i, datetime[8:10], datetime[10:12], datetime[12:], p, f, c, nbhits)) except: pass # ignore eventual wrong log lines req.write("</table>") 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("""<table border="1">""") req.write("<tr><td><strong>%s</strong></td><td><strong>%s</strong></tr>" % ("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("""<tr><td>%s</td><td align="right"><a href="%s/search/log?date=%d">%s</a></td></tr>""" % (day, weburl,day,line)) p.close() req.write("</table>") req.write("</html>") 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_alephseq_like(11,"980__a") #print get_fieldvalues_alephseq_like(11,["001", "980"]) ## profiling: #profile("of the this") #print perform_request_search(p="ellis") diff --git a/modules/websearch/lib/websearch_external_collections.py b/modules/websearch/lib/websearch_external_collections.py new file mode 100644 index 000000000..5977835da --- /dev/null +++ b/modules/websearch/lib/websearch_external_collections.py @@ -0,0 +1,349 @@ +# -*- coding: utf-8 -*- +## $Id$ + +## This file is part of CDS Invenio. +## Copyright (C) 2002, 2003, 2004, 2005, 2006 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. + +"""External collection 'core' file. + Perform search, database access.""" + +__lastupdated__ = """$Date$""" + +__version__ = "$Id$" + +__revision__ = "0.0.1" + +from copy import copy +from sets import Set + +from invenio.config import cdslang +from invenio.dbquery import run_sql +from invenio.messages import gettext_set_language + +from invenio.websearch_external_collections_config import cfg_external_collection_timeout +from invenio.websearch_external_collections_searcher import external_collections_dictionary +from invenio.websearch_external_collections_page_getter import HTTPAsyncPageGetter, async_download +from invenio.websearch_external_collections_templates import print_results, print_timeout +from invenio.websearch_external_collections_utils import get_collection_id, get_collection_descendants, escape_dictionary, \ + warning, get_verbose_print + +import invenio.template +template = invenio.template.load('websearch_external_collections') + +dico_collection_external_searches = {} +dico_collection_seealso = {} + +def print_external_results_overview(req, current_collection, pattern_list, field, + external_collection, verbosity_level=0, lang=cdslang): + """Print the external collection overview box. Return the selected external collections and parsed query""" + from invenio.search_engine import create_basic_search_units + assert req + vprint = get_verbose_print(req, 'External collection (print_external_results_overview): ', verbosity_level) + + pattern = bind_patterns(pattern_list) + vprint(3, 'pattern = ' + pattern) + + if not pattern: + return (None, None, None, None) + + basic_search_units = create_basic_search_units(None, pattern, field) + vprint(3, 'basic_search_units = ' + str(basic_search_units)) + + (search_engines, seealso_engines) = select_external_engines(basic_search_units, current_collection, external_collection) + vprint(3, 'search_engines = ' + str(search_engines)) + vprint(3, 'seealso_engines = ' + str(seealso_engines)) + + search_engines_list = sort_engine_by_name(search_engines) + vprint(3, 'search_engines_list (sorted) : ' + str(search_engines_list)) + html = template.external_collection_overview(lang, search_engines_list) + req.write(html) + + return (search_engines, seealso_engines, pattern, basic_search_units) + +def perform_external_collection_search(req, current_collection, pattern_list, field, + external_collection, verbosity_level=0, lang=cdslang, selected_external_collections=None): + """Search external collection and print the seealso box.""" + + vprint = get_verbose_print(req, 'External collection: ', verbosity_level) + + if selected_external_collections: + (search_engines, seealso_engines, pattern, basic_search_units) = selected_external_collections + else: + (search_engines, seealso_engines, pattern, basic_search_units) = print_external_results_overview(req, + current_collection, pattern_list, field, external_collection, verbosity_level, lang) + + if not pattern: + return + + do_external_search(req, lang, vprint, basic_search_units, search_engines) + create_seealso_box(req, lang, vprint, basic_search_units, seealso_engines, pattern) + vprint(3, 'end') + +def bind_patterns(pattern_list): + """Combine a list of patterns in an unique pattern. + pattern_list[0] should be the standart search pattern, + pattern_list[1:] are advanced search patterns.""" + if pattern_list[0]: + return pattern_list[0] + + pattern = "" + for pattern_part in pattern_list[1:]: + if pattern_part: + pattern += " " + pattern_part + + return pattern.strip() + +# See also box +def create_seealso_box(req, lang, vprint, basic_search_units=None, seealso_engines=None, query=''): + "Create the box that proposes links to other useful search engines like Google." + + vprint(3, 'Create seealso box') + seealso_engines_list = sort_engine_by_name(seealso_engines) + vprint(3, 'seealso_engines_list = ' + str(seealso_engines_list)) + links = build_seealso_links(basic_search_units, seealso_engines_list, lang, query) + html = template.external_collection_seealso_box(lang, links) + req.write(html) + +def build_seealso_links(basic_search_units, seealso_engines, lang, query): + """Build the links for the see also box.""" + _ = gettext_set_language(lang) + + links = [] + for engine in seealso_engines: + url = engine.build_search_url(basic_search_units, lang) + if url: + links.append('<a href="%(url)s">%(query)s %(text_in)s %(name)s</a>' % \ + {'query': query, 'text_in': _('in'), 'name': _(engine.name), 'url': url}) + return links + +# Selection +def select_external_engines(basic_search_units, collection_name, selected_external_searches): + """Build a tuple of two sets. The first one is the list of engine to use for an external search and the + second one is for the seealso box.""" + + collection_id = get_collection_id(collection_name) + if not collection_id: + return (None, None) + + init() + + if not type(selected_external_searches) is list: + selected_external_searches = [selected_external_searches] + + seealso_engines = Set() + search_engines = Set() + + if dico_collection_seealso.has_key(collection_id): + seealso_engines = copy(dico_collection_seealso[collection_id]) + + if dico_collection_external_searches.has_key(collection_id): + seealso_engines = seealso_engines.union(dico_collection_external_searches[collection_id]) + + for ext_search_name in selected_external_searches: + if external_collections_dictionary.has_key(ext_search_name): + engine = external_collections_dictionary[ext_search_name] + if engine.parser: + search_engines.add(engine) + else: + warning('select_external_engines: %(ext_search_name)s unknow.' % locals()) + + seealso_engines = seealso_engines.difference(search_engines) + + return (search_engines, seealso_engines) + +# Search +def do_external_search(req, lang, vprint, basic_search_units, search_engines): + """Make the external search.""" + _ = gettext_set_language(lang) + vprint(3, 'beginning external search') + engines_list = [] + + for engine in search_engines: + url = engine.build_search_url(basic_search_units, lang) + if url: + engines_list.append([url, engine]) + + pagegetters_list = [HTTPAsyncPageGetter(engine[0]) for engine in engines_list] + + def finished(pagegetter, data, current_time): + """Function called, each time the download of a web page finish. + Will parse and print the results of this page.""" + print_results(req, lang, pagegetter, data, current_time) + + finished_list = async_download(pagegetters_list, finished, engines_list, cfg_external_collection_timeout) + + for (finished, engine) in zip(finished_list, engines_list): + if not finished: + url = engine[0] + name = engine[1].name + print_timeout(req, lang, engine[1], name, url) + +# Database management +def init(): + """Load db infos if it's not already done.""" + if not init.done: + external_collection_load_db_infos() + init.done = True +init.done = False + +def external_collection_load_db_infos(): + """Load and cache informations about external collections.""" + global dico_collection_external_searches, dico_collection_seealso + (dico_collection_external_searches, dico_collection_seealso) = build_dictionnaries_from_db_tables() + +def build_dictionnaries_from_db_tables(): + """Read a db table and build the dictionary making the association between a collection and a search engine.""" + global dico_collection_external_searches, dico_collection_seealso + dico_collection_external_searches = {} + dico_collection_seealso = {} + + query = "SELECT id_collection, name_external_searchengine, type FROM collection_externalcollection;" + results = run_sql(query) + if results: + for result in results: + collection_id = int(result[0]) + engine_name = result[1] + search_type = int(result[2]) + + if not external_collections_dictionary.has_key(engine_name): + warning("No search engine : " + engine_name) + continue + + engine = external_collections_dictionary[engine_name] + if search_type == 0: + continue + + if search_type == 1: + dictionary = dico_collection_external_searches + + if search_type == 2: + dictionary = dico_collection_seealso + + if not dictionary.has_key(collection_id): + dictionary[collection_id] = Set() + engine_set = dictionary[collection_id] + engine_set.add(engine) + return(dico_collection_external_searches, dico_collection_seealso) + +def external_collection_is_enabled(external_collection_search_engine, collection_id): + """Return true if this search engine is enabled for a specific collection_id.""" + return is_enable_collection_dico(external_collection_search_engine, collection_id, dico_collection_external_searches) + +def external_collection_is_seealso_enabled(external_collection_search_engine, collection_id): + """Return true if this engine is used to provide See also links for the given collection_id.""" + return is_enable_collection_dico(external_collection_search_engine, collection_id, dico_collection_seealso) + +def is_enable_collection_dico(external_collection_search_engine, collection_id, dico): + """Check if an external search engine is enabled for a collection.""" + + if not dico.has_key(collection_id): + return False + + engines_set = dico[collection_id] + for engine in engines_set: + if engine.name == external_collection_search_engine.name: + return True + return False + +def external_collection_enable(external_collection_search_engine, collection_id, recurse=False, search_type=1): + """Enable this search engine for a given collection. """ + external_collection_load_db_infos() + + if external_collection_is_enabled(external_collection_search_engine, collection_id): + return + if external_collection_is_seealso_enabled(external_collection_search_engine, collection_id): + db_update(external_collection_search_engine, collection_id, search_type) + db_insert_type(external_collection_search_engine, collection_id, search_type) + + if recurse: + for descendant_id in get_collection_descendants(collection_id): + external_collection_enable(external_collection_search_engine, descendant_id, False, search_type) + + external_collection_load_db_infos() + +def external_collection_enable_seealso(external_collection_search_engine, collection_id, recurse=False): + """Enable this search engine for See also links.""" + external_collection_enable(external_collection_search_engine, collection_id, recurse, 2) + +def external_collection_disable(external_collection_search_engine, collection_id, recurse=False): + """Disable this search engine (for search or see also).""" + external_collection_load_db_infos() + + db_delete(external_collection_search_engine, collection_id) + + if recurse: + for descendant_id in get_collection_descendants(collection_id): + external_collection_disable(external_collection_search_engine, descendant_id) + + external_collection_load_db_infos() + +def db_insert_type(external_collection_search_engine, collection_id, search_type): + """Insert a record in the db the enable the current search engine for the given collection. + type can be 1 for search or 2 for see also + """ + engine_name = external_collection_search_engine.name + sql = 'INSERT INTO collection_externalcollection (id_collection, name_external_searchengine, type, is_default) VALUES ' + \ + '(%(collection_id)d, "%(name_external_searchengine)s", %(type)d, false);' % escape_dictionary( + {'collection_id': collection_id, 'name_external_searchengine': engine_name, 'type': search_type}) + run_sql(sql) + +def db_update(external_collection_search_engine, collection_id, search_type): + """Change the type for the given collection.""" + engine_name = external_collection_search_engine.name + sql = 'UPDATE collection_externalcollection SET is_default=false, ' + \ + 'type=%(type)d WHERE id_collection=%(collection_id)d AND name_external_searchengine="%(engine_name)s";' % \ + escape_dictionary({'type': search_type, 'collection_id': collection_id, 'engine_name': engine_name}) + run_sql(sql) + +def db_delete(external_collection_search_engine, collection_id): + """Remove a row in the db, (disable an external collection).""" + engine_name = external_collection_search_engine.name + sql = 'DELETE FROM collection_externalcollection WHERE ' + \ + 'id_collection=%(collection_id)d AND name_external_searchengine="%(engine_name)s";' % \ + escape_dictionary({'collection_id': collection_id, 'engine_name': engine_name}) + run_sql(sql) + +def external_collection_is_default(external_collection_search_engine, collection_id): + """Return true if the current search engine is enabled for the given collection.""" + engine_name = external_collection_search_engine.name + sql = 'SELECT * FROM collection_externalcollection WHERE type=1 AND is_default=true AND ' + \ + 'id_collection=%(collection_id)d AND name_external_searchengine="%(engine_name)s";' % \ + escape_dictionary({'collection_id': collection_id, 'engine_name': engine_name}) + results = run_sql(sql) + return len(results) > 0 + +def external_collection_set_default_type(external_collection_search_engine, collection_id, default=True, recurse=False): + """Set default in database for an external collection (checked or not).""" + engine_name = external_collection_search_engine.name + sql_default = str(default).lower() + + sql = ('UPDATE collection_externalcollection SET is_default=%(is_default)s WHERE ' + \ + 'id_collection=%(collection_id)d AND name_external_searchengine="%(engine_name)s" AND type=1;') % \ + escape_dictionary({'is_default': sql_default, 'collection_id': collection_id, 'engine_name': engine_name}) + run_sql(sql) + + if recurse: + for descendant_id in get_collection_descendants(collection_id): + external_collection_set_default_type(external_collection_search_engine, descendant_id, default) + +# Misc functions +def sort_engine_by_name(engines_set): + """Return a list of sorted (by name) search engines.""" + engines_list = [engine for engine in engines_set] + engines_list.sort(lambda x, y: cmp(x.name, y.name)) + return engines_list + diff --git a/modules/websearch/lib/websearch_external_collections_config.py b/modules/websearch/lib/websearch_external_collections_config.py new file mode 100644 index 000000000..ad6bd0266 --- /dev/null +++ b/modules/websearch/lib/websearch_external_collections_config.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +## $Id$ + +## This file is part of CDS Invenio. +## Copyright (C) 2002, 2003, 2004, 2005, 2006 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. + +"""External collection configuration file.""" + +__lastupdated__ = """$Date$""" + +__version__ = "$Id$" + +__revision__ = "0.0.1" + +cfg_external_collection_timeout = 10 +cfg_external_collection_maxresults = 25 +cfg_external_collections = { + 'Amazon': + {'engine': 'Amazon'}, + 'CERN - CDS Indico': + {'engine': 'CDSIndico'}, + 'CERN - Intranet': + {'base_url': "http://www.iso.org", 'search_url': "http://search.cern.ch/query.html?qt="}, + 'CERN - EDMS': + {'engine': 'CERNEDMS'}, + 'CiteSeer': + {'engine': 'Citeseer'}, + 'Google': + {'engine': 'Google'}, + 'Google Books': + {'engine': 'GoogleBooks'}, + 'Google Scholar': + {'engine': 'GoogleScholar'}, + 'IEC': + {'base_url': "http://www.iec.ch", + 'search_url': "http://www.iec.ch/cgi-bin/procgi.pl/www/iecwww.p?wwwlang=E&wwwprog=sea22.p&search=text&searchfor="}, + 'IHS': + {'base_url': "http://global.ihs.com", + 'search_url': "http://global.ihs.com/search_res.cfm?&input_doc_title="}, + 'ISO': + {'base_url': "http://www.iso.org", + 'search_url': "http://www.iso.org/iso/en/StandardsQueryFormHandler.StandardsQueryFormHandler?languageCode=en" + \ + "&lastSearch=false&title=true&isoNumber=&isoPartNumber=&isoDocType=ALL&isoDocElem=ALL&ICS=&stageCode=&stages" + \ + "cope=Current&repost=1&stagedatepredefined=&stageDate=&committee=ALL&subcommittee=&scopecatalogue=CATALOGUE&" + \ + "scopeprogramme=PROGRAMME&scopewithdrawn=WITHDRAWN&scopedeleted=DELETED&sortOrder=ISO&keyword="}, + 'INSPEC': + {'engine': 'INSPEC'}, + 'KEK KISS Preprints': + {'engine': 'KissForPreprints'}, + 'KEK Library Books': + {'engine': 'KissForBooks'}, + 'KEK Library Journals': + {'engine': 'KissForJournals'}, + 'NEBIS': + {'engine': 'NEBIS'}, + 'Scirus': + {'engine': 'Scirus'}, + 'SLAC SPIRES HEP': + {'engine': 'SPIRES'}, + 'SLAC Library Books': + {'engine': 'SPIRESBooks'}, +} diff --git a/modules/websearch/lib/websearch_external_collections_page_getter.py b/modules/websearch/lib/websearch_external_collections_page_getter.py new file mode 100644 index 000000000..26fbfb2ad --- /dev/null +++ b/modules/websearch/lib/websearch_external_collections_page_getter.py @@ -0,0 +1,212 @@ +# -*- coding: utf-8 -*- +## $Id$ + +## This file is part of CDS Invenio. +## Copyright (C) 2002, 2003, 2004, 2005, 2006 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. + +"""Module to download web pages using asyncore. + +Example 1, downloading a set of webpages : + +from websearch_external_collections_page_getter import * +urls = ['http://www.google.fr', 'http://linuxfr.org'] +pagegetters = [HTTPAsyncPageGetter(url) for url in urls] +async_download(pagegetters) +for pagegetter in pagegetters: + if pagegetter.done: + print pagegetter.data + else: + print "Error downloading : " + pagegetter.uri + +Example 2, downloading a set of webpages but with callback function. + +def func(pagegetter, data, current_time): + print "OK (%f): " % current_time + pagegetter.uri + " - " + data + +from websearch_external_collections_page_getter import * +urls = ['http://www.google.fr', 'http://linuxfr.org'] +pagegetters = [HTTPAsyncPageGetter(url) for url in urls] +async_download(pagegetters, func, ['info1', 'info2'], 10) +""" + +__lastupdated__ = """$Date$""" + +__version__ = "$Id$" + +__revision__ = "0.0.1" + +import asyncore +import mimetools +import socket +import StringIO +import time +import urlparse + +def async_download(pagegetter_list, finish_function=None, datastructure_list=None, timeout=15): + """Download web pages asynchronously with timeout. + pagegetter_list : list of HTTPAsyncPageGetter objects + finish_function : function called when a web page is downloaded; + prototype def funct(pagetter, datastructure, current_time) + datastructure_list : list (same size as pagegetter_list) with information to pass as datastructure + to the finish function. + timeout : float, timeout in seconds.""" + time_start = time.time() + finished_list = [False] * len(pagegetter_list) + + nb_remaining = 0 + check_redirected(pagegetter_list) + for pagegetter in pagegetter_list: + if pagegetter and not pagegetter.done: + nb_remaining += 1 + + while (time.time() - time_start < timeout) and nb_remaining > 0: + asyncore.loop(0.01, True, None, 1) + check_redirected(pagegetter_list) + for i in range(len(pagegetter_list)): + if pagegetter_list[i] and not finished_list[i] and pagegetter_list[i].done: + nb_remaining -= 1 + if finish_function: + if datastructure_list: + datastructure = datastructure_list[i] + else: + datastructure = None + current_time = time.time() - time_start + finish_function(pagegetter_list[i], datastructure, current_time) + finished_list[i] = True + + return finished_list + +class HTTPAsyncPageGetter(asyncore.dispatcher_with_send): + """Class to download a web page using asyncore.""" + + def __init__(self, uri): + asyncore.dispatcher_with_send.__init__(self) + + self.uri = uri + self.redirected = None + self.status = None + self.header = None + self.done = False + self.data = "" + self.header_data = "" + + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.request, self.host, self.port = build_request(self.uri) + try: + self.connect((self.host, self.port)) + except: + self.done = True + + def handle_connect(self): + """Handle the connection event. By sending the request to the server.""" + self.send(self.request) + + def handle_expt(self): + """Handle an exception. Close the socket and put done at True.""" + self.close() + self.done = True + + def handle_read(self): + """Handle a read event.""" + data = self.recv(1024) + if not self.header: + self.header_data += data + (self.status, self.header, data) = decode_header(self.header_data) + if self.status != None: + if self.status[1] in ("301", "302"): + self.redirected = self.header["location"] + self.data += data + + def handle_close(self): + """Handle a close event.""" + self.done = True + self.close() + +def build_request(uri): + """Build an http request for a specific url.""" + + scheme, host, path, params, query, fragment = urlparse.urlparse(uri) + assert scheme == "http", "only supports HTTP requests (uri = " + uri + ")" + + host, port = decode_host_port(host) + path = encode_path(path, params, query) + + request = "GET %s HTTP/1.0\r\n" % (path) + \ + "User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/48 (like Gecko) Safari/48\r\n" + \ + "Accept: text/html, image/jpeg, image/png, text/*, image/*, */*\r\n" + \ + "Accept-Charset: utf-8, utf-8;q=0.5, *;q=0.5\r\n" + \ + "Host: %s\r\n" % (host) + \ + "Connection: close\r\n\r\n" + + return (request, host, port) + +def decode_host_port(host): + """Decode the host string in an (host, port) pair.""" + + try: + host, port = host.split(":", 1) + port = int(port) + except (TypeError, ValueError): + port = 80 + return (host, port) + +def encode_path(path, params, query): + """Bind the path, the params and the query in a unique http path.""" + + if not path: + path = "/" + if params: + path = path + ";" + params + if query: + path = path + "?" + query + return path + +def decode_header(data): + """Try to decode an html header. + + If the header can be decoded, will return (status, header, remaining_data) + If it cannot, (None, None, data) + """ + i = data.find("\r\n\r\n") + size = 4 + if i == -1: + i = data.find("\n\n") + size = 2 + if i == -1: + return (None, None, data) + + # parse header + header_fp = StringIO.StringIO(data[:i+size]) + # status line is "HTTP/version status message" + status = header_fp.readline() + status = status.split(" ", 2) + # followed by a rfc822-style message header + header = mimetools.Message(header_fp) + # followed by a newline, and the payload (if any) + data = data[i+size:] + + return (status, header, data) + +def check_redirected(pagegetter_list): + """Check if a redirection occured in the engines_list.""" + + for i in range(len(pagegetter_list)): + getter = pagegetter_list[i] + if getter and getter.redirected != None: + if getter.redirected.startswith('http://'): + getter = HTTPAsyncPageGetter(getter.redirected) + pagegetter_list[i] = getter diff --git a/modules/websearch/lib/websearch_external_collections_parser.py b/modules/websearch/lib/websearch_external_collections_parser.py new file mode 100644 index 000000000..390ad319f --- /dev/null +++ b/modules/websearch/lib/websearch_external_collections_parser.py @@ -0,0 +1,327 @@ +# -*- coding: utf-8 -*- +## $Id$ + +## This file is part of CDS Invenio. +## Copyright (C) 2002, 2003, 2004, 2005, 2006 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 is a collection of parsers for external search engines. + +Each parser try to extract results from a web page returned by an external search +engine. +""" + +__lastupdated__ = """$Date$""" + +__version__ = "$Id$" + +__revision__ = "0.0.1" + +import re +from invenio.websearch_external_collections_config import cfg_external_collection_maxresults + +re_href = re.compile(r'<a[^>]*href="?([^">]*)"?[^>]*>', re.IGNORECASE) +re_img = re.compile(r'<img[^>]*src="?([^">]*)"?[^>]*>', re.IGNORECASE) + +def correct_url(htmlcode, host, path): + """This function is used to correct urls in html code. + + >>> correct_url('<a href="hello.html">', 'www.google.com', 'search/') + '<a href="http://www.google.com/search/hello.html">' + """ + htmlcode = correct_url_with_regex(htmlcode, host, path, re_href) + htmlcode = correct_url_with_regex(htmlcode, host, path, re_img) + return htmlcode + +def correct_url_with_regex(htmlcode, host, path, regex): + """Correct urls in html code. The url is found using the regex given.""" + url_starts = [] + results = regex.finditer(htmlcode) + for result in results: + url = result.group(1) + if not url.startswith('http://'): + url_starts.append(result.start(1)) + url_starts.reverse() + for url_start in url_starts: + if htmlcode[url_start] == '/': + htmlcode = htmlcode[:url_start] + "http://" + host + htmlcode[url_start:] + else: + htmlcode = htmlcode[:url_start] + "http://" + host + "/" + path + htmlcode[url_start:] + return htmlcode + +class ExternalCollectionHit: + """Hold a result.""" + + def __init__(self, html=None): + self.html = html + +class ExternalCollectionResultsParser(object): + """Mother class for parsers.""" + + num_results_regex = None + + def __init__(self, host='', path=''): + self.buffer = "" + self.results = [] + self.host = host + self.path = path + self.clean() + + def clean(self): + """Clean buffer and results to be able to parse a new web page.""" + self.buffer = "" + self.results = [] + + def feed(self, data): + """Feed buffer with data that will be parse later.""" + self.buffer += data + + def parse(self): + """Parse the buffer.""" + pass + + def add_html_result(self, html): + """Add a new html code as result. The urls in the html code will be corrected.""" + + if not html: + return + + if len(self.results) >= cfg_external_collection_maxresults: + return + + html = correct_url(html, self.host, self.path) + '\n' + result = ExternalCollectionHit(html) + self.results.append(result) + + def parse_num_results(self): + """Parse the buffer with the num_results_regex to extract the number of records found. + This will be returned as a formated string.""" + if self.num_results_regex == None: + return None + list_matchs = self.num_results_regex.finditer(self.buffer) + for match in list_matchs: + return int(match.group(1).replace(',', '')) + return None + + def parse_and_get_results(self, data): + """Parse given data and return results. + """ + self.clean() + self.feed(data) + self.parse() + return self.results + +class CDSIndicoCollectionResutsParser(ExternalCollectionResultsParser): + """Parser for CDS Indico""" + + num_results_regex = re.compile(r'<strong>([0-9]+?)</strong> records found') + result_regex = re.compile(r'<tr><td valign="top" align="right" nowrap><input name="recid" type="checkbox" value="[0-9]+">\s*([0-9]+)\s*</td><td valign="top">(.*?)</td></tr>', re.MULTILINE + re.DOTALL) + + def __init__(self, host="", path=""): + super(CDSIndicoCollectionResutsParser, self).__init__(host, path) + + def parse(self): + """Parse buffer to extract records.""" + + results = self.result_regex.finditer(self.buffer) + for result in results: + num = result.group(1) + html = result.group(2) + + self.add_html_result(num + ') ' + html + '<br>') + +class KISSExternalCollectionResultsParser(ExternalCollectionResultsParser): + """Parser for Kiss.""" + + num_results_regex = re.compile(r'<pre><b> ([0-9]+?) records matched</b></pre>') + + def __init__(self, host="www-lib.kek.jp", path="cgi-bin/"): + super(KISSExternalCollectionResultsParser, self).__init__(host, path) + + def parse(self): + """Parse buffer to extract records.""" + + self.buffer = self.buffer.decode('Shift_JIS', 'ignore').encode('utf-8', 'ignore') + elements = self.buffer.split("<DL>") + if len(elements) <= 1: + return + + for element in elements[1:]: + if len(self.results) >= cfg_external_collection_maxresults: + return + end_index = element.find('</DL>') + if end_index != -1: + element = element[:end_index + 4] + self.add_html_result(element + '<br><br>') + +class KISSBooksExternalCollectionResultsParser(ExternalCollectionResultsParser): + """Parser for Kiss books.""" + line = re.compile(r'<TR>(.*?)</TR>') + title = re.compile(r'<TR>[ ]+<TD valign="top">([0-9]+)\)</TD>[ ]+<TD><A HREF="?(.*)"?>[ ]*(.*?)[ ]*</A></TD>[ ]+</TR>') + info_line = re.compile(r'[ ]*<TR>[ ]*<TD></TD>[ ]*<TD>(.*?)</TD>.*</TR>') + num_results_regex = re.compile(r'<B> (?:Books|Journals) ([0-9]+?) </B>') + + def __init__(self, host="www-lib.kek.jp", path="cgi-bin/"): + super(KISSBooksExternalCollectionResultsParser, self).__init__(host, path) + + def parse(self): + """Parse buffer to extract records.""" + + self.buffer = self.buffer.decode('Shift_JIS', 'ignore').encode('utf-8', 'ignore') + self.buffer = self.buffer.replace('\n', ' ') + + html = "" + results_to_parse = self.line.finditer(self.buffer) + for result in results_to_parse: + if len(self.results) >= cfg_external_collection_maxresults: + return + data = result.group() + + title_match = self.title.match(data) + if title_match: + self.add_html_result(html) + + num = title_match.group(1) + url = title_match.group(2) + title = title_match.group(3) + + html = num + ') <a href=http://' + self.host + url + ">" + title + "</a><br>" + else: + info_line_match = self.info_line.match(data) + if info_line_match: + info = info_line_match.group(1) + html += info + '<br>' + + self.add_html_result(html) + +class GoogleExternalCollectionResultsParser(ExternalCollectionResultsParser): + """Parser for Google""" + + num_results_regex = re.compile(r'of about <b>([0-9,]+?)</b>') + + def __init__(self, host = "www.google.com", path=""): + super(GoogleExternalCollectionResultsParser, self).__init__(host, path) + + def parse(self): + """Parse buffer to extract records.""" + elements = self.buffer.split("<p class=g>") + if len(elements) <= 1: + return + + for element in elements[1:]: + end_index = element.find('</table>') + if end_index != -1: + element = element[:end_index + 8] + self.add_html_result(element) + +class GoogleScholarExternalCollectionResultsParser(GoogleExternalCollectionResultsParser): + """Parser for Google Scholar.""" + + def __init__(self, host = "scholar.google.com", path=""): + super(GoogleScholarExternalCollectionResultsParser, self).__init__(host, path) + + def parse(self): + """Parse buffer to extract records.""" + elements = self.buffer.split("<p class=g>") + if len(elements) <= 1: + return + + for element in elements[1:-1]: + end_index = element.find('</table>') + if end_index != -1: + element = element[:end_index + 8] + self.add_html_result(element + '<br>') + +class GoogleBooksExternalCollectionResultsParser(GoogleExternalCollectionResultsParser): + """Parser for Google Books.""" + + num_results_regex = re.compile(r' with <b>([0-9]+?)</b> pages on ') + + def __init__(self, host = "books.google.com", path=""): + super(GoogleBooksExternalCollectionResultsParser, self).__init__(host, path) + + def parse(self): + """Parse buffer to extract records.""" + elements = self.buffer.split('<table><tr><td class="covertd">') + if len(elements) <= 1: + return + + for element in elements[1:-1]: + self.add_html_result(element) + +class SPIRESExternalCollectionResultsParser(ExternalCollectionResultsParser): + """Parser for SPIRES.""" + + num_results_regex = re.compile(r'Paper <b>[0-9]+</b> to <b>[0-9]+</b> of <b>([0-9]+)</b>') + + def __init__(self, host="www.slac.stanford.edu", path="spires/find/hep/"): + super(SPIRESExternalCollectionResultsParser, self).__init__(host, path) + + def parse(self): + """Parse buffer to extract records.""" + elements = self.buffer.split('<p>') + + if len(elements) <= 2: + return + + for element in elements[1:-1]: + self.add_html_result(element) + +class SCIRUSExternalCollectionResultsParser(ExternalCollectionResultsParser): + """Parser for SCIRUS.""" + + num_results_regex = re.compile(r'<b>([0-9,]+) total</b> ') + result_separator = re.compile(r'<td width="100%" valign="top" colspan="2">[ ]*(.*?)</td>[ ]*</tr>[ ]*</table>') + result_decode = re.compile('[ ]*(.*?)[ ]*<font class="filesize">.*?<br>[ ]*(.*?)[ ]*<br>[ ]*(.*?)[ ]*</td>.*?<br>[ ]*(.*)[ ]*') + + cleaning = re.compile('(<img .*?>|</td>|</tr>|<td .*?>|<tr.*?>)') + + def __init__(self, host='www.scirus.com', path='srsapp/'): + super(SCIRUSExternalCollectionResultsParser, self).__init__(host, path) + + def parse(self): + """Parse buffer to extract records.""" + data = self.buffer.replace('\n', ' ') + + for element in self.result_separator.finditer(data): + data = element.group(1) + parsed_line = self.result_decode.match(data) + if parsed_line != None: + link = parsed_line.group(1) + date = parsed_line.group(2) + comments = parsed_line.group(3) + similar = parsed_line.group(4) + html = "%(link)s - %(date)s <br> %(comments)s <br> %(similar)s <br>" % {'link' : link, + 'date' : date, 'comments' : comments, 'similar' : similar} + else: + html = self.cleaning.sub("", data) + '<br>' + self.add_html_result(html) + +class CiteSeerExternalCollectionResultsParser(ExternalCollectionResultsParser): + """Parser for CiteSeer.""" + + num_results_regex = re.compile(r'<br>(?:More than |)([0-9]+)(?: documents found.| results)') + result_separator = re.compile(r'<!--RIS-->.*?<!--RIE-->', re.DOTALL) + + def __init__(self, host='', path=''): + super(CiteSeerExternalCollectionResultsParser, self).__init__(host, path) + + def parse(self): + """Parse buffer to extract records.""" + for element in self.result_separator.finditer(self.buffer): + self.add_html_result(element.group() + '<br>') + diff --git a/modules/websearch/lib/websearch_external_collections_searcher.py b/modules/websearch/lib/websearch_external_collections_searcher.py new file mode 100644 index 000000000..6a8b16025 --- /dev/null +++ b/modules/websearch/lib/websearch_external_collections_searcher.py @@ -0,0 +1,547 @@ +# -*- coding: utf-8 -*- +## $Id$ + +## This file is part of CDS Invenio. +## Copyright (C) 2002, 2003, 2004, 2005, 2006 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 external search Engines.""" + +__lastupdated__ = """$Date$""" + +__version__ = "$Id$" + +__revision__ = "0.0.1" + +import urllib + +from invenio.config import cdslang +from invenio.websearch_external_collections_config import cfg_external_collections, cfg_external_collection_maxresults +from invenio.websearch_external_collections_parser import CDSIndicoCollectionResutsParser, \ + GoogleExternalCollectionResultsParser, \ + KISSExternalCollectionResultsParser, GoogleScholarExternalCollectionResultsParser, \ + GoogleBooksExternalCollectionResultsParser, KISSBooksExternalCollectionResultsParser, \ + SPIRESExternalCollectionResultsParser, SCIRUSExternalCollectionResultsParser, \ + CiteSeerExternalCollectionResultsParser + +def format_basic(basic): + """Format a basic query""" + if basic[3] == "w": + return basic[1] + else: + return '"' + basic[1] + '"' + +def only_field(basic_search_units, fieldname): + """Check if in the basic search units, there is only on field representated.""" + for search_unit in basic_search_units: + if search_unit[2] != fieldname: + return False + return True + +class ExternalSearchEngine(object): + """Global class for interfaces to external search engines.""" + + lang_translator = None + + def __init__(self, configuration): + self.search_url = "" + self.parser = None + self.combiner = " " + self.name = None + for (name, value) in configuration.iteritems(): + setattr(self, name, value) + + def build_units(self, basic_search_units): + """ Build the research units for basic_search_units provided""" + units = [] + for search_unit in basic_search_units: + unit = self.build_search_unit_unit(search_unit) + if unit != None: + units.append(unit) + return units + + def build_search_unit_unit(self, basic): + """Build a search string from a search unit. This is the base + version that just keep keywords with "+". """ + if basic[0] == "+": + return basic[1] + return None + + def build_search_url(self, basic_search_units, lang=cdslang): + """Build an URL for a specific set of search_units.""" + + units = self.build_units(basic_search_units) + if len(units) == 0: + return None + request = self.combine_units(units) + url_request = urllib.quote(request) + + return self.search_url + url_request + + def combine_units(self, units): + """Combine the units to make a boolean AND query.""" + return self.combiner.join(units) + + def __repr__(self): + return 'ExternalSearchEngine.' + self.name + +class SortedFieldsSearchEngine(ExternalSearchEngine): + """Class for search engines that used separate query box for fields.""" + + def __init__(self, configuration): + self.fields = [] + self.fields_content = {} + self.search_url = "" + self.converter = {} + super(SortedFieldsSearchEngine, self).__init__(configuration) + + def build_search_url(self, basic_search_units, lang=cdslang): + """Build an URL for a search.""" + self.clear_fields() + self.fill_fields(basic_search_units) + + def clear_fields(self): + """Clear fields to be able to build a new URL.""" + self.fields_content = {} + for field_name in self.fields: + self.fields_content[field_name] = [] + self.fields_content["default"] = [] + + def fill_fields(self, basic_search_units): + """Fill fields with the apropriate research terms.""" + for search_unit in basic_search_units: + self.add_search_unit(search_unit) + + def add_search_unit(self, search_unit): + """Add a search unit to fields to search.""" + + if search_unit[0] == "-": + return + + search = format_basic(search_unit) + field_name = search_unit[2] + if field_name in self.fields: + self.fields_content[field_name].append(search) + else: + self.fields_content["default"].append(search) + +# CERN + +class CDSIndicoSearchEngine(ExternalSearchEngine): + """Global class for CDS Search Engines.""" + + index_translator = {'title' : 'title', 'author': 'speaker', 'fulltext': 'fulltext'} + lang_translator = { + 'ca': 'ca', 'cs': 'cs', 'de': 'de', 'el': 'el', 'en': 'en', 'es': 'es', + 'fr': 'fr', 'it': 'it', 'ja': 'ja', 'no': 'no', 'pl': 'pl', 'pt': 'pt', + 'ru': 'ru', 'sk': 'sk', 'sv': 'sv', 'uk': 'uk', 'default' : 'en'} + + def __init__(self, configuration): + super(CDSIndicoSearchEngine, self).__init__(configuration) + self.base_url = 'http://indicosearch.cern.ch/' + self.search_url = 'http://indicosearch.cern.ch/search.py?sc=0&f=&action=Search&d1d=&d1m=&d1y=&d2d=&d2m=&d2y=&cc=Indico+Search&c=Conference+Contributions&c=Conference+Announcements&p=' + self.parser = CDSIndicoCollectionResutsParser() + + def build_search_unit_unit(self, basic): + """Build a search string from a search unit. + This will also translate index name using the index_translator + dictionary.""" + operator = basic[0] + pattern = basic[1] + index = basic[2] + search_type = basic[3] + + if self.index_translator.has_key(index): + index = self.index_translator[index] + else: + index = None + + if index: + return operator + index + ':"' + pattern + '"' + else: + if search_type == 'w': + return operator + pattern + else: + return operator + '"' + pattern + '"' + + def build_search_url(self, basic_search_units, lang=cdslang): + """Build an URL for a specific set of search_units.""" + + url = super(CDSIndicoSearchEngine, self).build_search_url(basic_search_units, lang) + if not url: + return None + + if self.lang_translator.has_key(lang): + dest_lang = self.lang_translator[lang] + else: + dest_lang = self.lang_translator['default'] + + return url + '&ln=' + dest_lang + '&rg=' + str(cfg_external_collection_maxresults) + +class CERNEDMSSearchEngine(SortedFieldsSearchEngine): + """CERN EDMS""" + + def __init__(self, configuration): + super(CERNEDMSSearchEngine, self).__init__(configuration) + self.base_url = "http://edms.cern.ch/cedar/plsql/fullsearch.doc_search" + self.search_url = "http://edms.cern.ch/cedar/plsql/fullsearch.doc_search?p_search_type=ADVANCED&" + self.search_url_simple = "http://edms.cern.ch/cedar/plsql/fullsearch.doc_search?p_search_type=BASE&p_free_text=" + self.fields = ["author", "keyword", "abstract", "title", "reportnumber"] + + def build_search_url(self, basic_search_units, lang=cdslang): + """Build an URL for CERN EDMS.""" + super(CERNEDMSSearchEngine, self).build_search_url(basic_search_units) + if len(self.fields_content["default"]) > 0: + free_text = self.bind_fields(["author", "keyword", "abstract", "title", "reportnumber", "default"]) + return self.search_url_simple + free_text + else: + authors = self.bind_fields(["author"]) + title = self.bind_fields(["title", "abstract", "keyword"]) + reportnumber = self.bind_fields(["reportnumber"]) + url_parts = [] + if authors != '': + url_parts.append('p_author=' + authors) + if title != "": + url_parts.append('p_title=' + title) + if reportnumber != "": + url_parts.append('p_document_id=' + reportnumber) + if len(url_parts) == 0: + return None + return self.search_url + "&".join(url_parts) + + def bind_fields(self, fieldname_list): + """Combine some fields together.""" + result = [] + for key in fieldname_list: + content = self.fields_content[key] + if len(content) > 0: + result.append(" ".join(content)) + return urllib.quote(" ".join(result)) + +class CERNAgendaSearchEngine(ExternalSearchEngine): + """CERN Agenda""" + + def __init__(self, configuration): + super(CERNAgendaSearchEngine, self).__init__(configuration) + self.base_url = "http://agenda.cern.ch" + self.search_url_author = "http://agenda.cern.ch/search.php?field=speaker&search=Search&keywords=" + self.search_url_title = "http://agenda.cern.ch/search.php?field=title&search=Search&keywords=" + + def build_search_url(self, basic_search_units, lang=cdslang): + """Build an url for searching on CERN Agenda. This will only work if there is only author + or title tags.""" + if only_field(basic_search_units, "author"): + self.search_url = self.search_url_author + elif only_field(basic_search_units, "title"): + self.search_url = self.search_url_title + else: + return None + return super(CERNAgendaSearchEngine, self).build_search_url(basic_search_units) + +# Google + +class GoogleSearchEngine(ExternalSearchEngine): + """Search engine class for Google """ + + def __init__(self, configuration): + super(GoogleSearchEngine, self).__init__(configuration) + self.base_url = "http://www.google.com" + self.search_url = "http://www.google.com/search?q=" + self.parser = GoogleExternalCollectionResultsParser() + + def build_search_unit_unit(self, search_unit): + """Build a part of the google query.""" + return self.build_search_unit_unit_google(search_unit, "") + + def build_search_unit_unit_google(self, search_unit, author_tag): + """Parse a unit and return it in a google query form.""" + sign = search_unit[0].replace("+", "") + if search_unit[2] == "author": + if search_unit[1].find(",") >= 0 and search_unit[3] != "p": + (lastname, firstname) = search_unit[1].split(",", 1) + return sign + author_tag + '"%s %s" OR ' % (lastname, firstname) + \ + sign + author_tag + '"%s %s"' % (firstname, lastname) + else: + return sign + author_tag + search_unit[1] + if search_unit[3] == "w": + return search_unit[0] + search_unit[1] + else: + return search_unit[0] + '"' + search_unit[1] + '"' + +class GoogleBooksSearchEngine(GoogleSearchEngine): + """Interface for searching on Google Books.""" + + def __init__(self, configuration): + super(GoogleBooksSearchEngine, self).__init__(configuration) + self.base_url = "http://books.google.com" + self.search_url = "http://books.google.com/books?q=" + self.parser = GoogleBooksExternalCollectionResultsParser() + +class GoogleScholarSearchEngine(GoogleSearchEngine): + """Interface for searching on Google Scholar.""" + + def __init__(self, configuration): + super(GoogleScholarSearchEngine, self).__init__(configuration) + self.base_url = 'http://scholar.google.com' + self.search_url = 'http://scholar.google.com/scholar?q=' + self.parser = GoogleScholarExternalCollectionResultsParser() + + def build_search_unit_unit(self, search_unit): + """Build a unit for Google Scholar. Is different from Google one's + because there is an author tag for authors.""" + return self.build_search_unit_unit_google(search_unit, "author:") + +# Kiss + +class KissSearchEngine(SortedFieldsSearchEngine): + """Search interface for KEK Information Service System. + Not to be used directly but with Kiss*SearchEngine. """ + + def __init__(self, configuration): + super(KissSearchEngine, self).__init__(configuration) + self.converter = { "author": "AU=", "year": "YR=", + "title": "TI=", "reportnumber": "RP=" } + self.fields = self.converter.keys() + self.parser = KISSExternalCollectionResultsParser() + + def build_search_url(self, basic_search_units, lang=cdslang): + """Build an URL for a search.""" + super(KissSearchEngine, self).build_search_url(basic_search_units) + url_parts = [] + for key in self.fields: + if len(self.fields_content[key]) > 0: + field_request = " and ".join(self.fields_content[key]) + url_part = self.converter[key] + urllib.quote(field_request) + url_parts.append(url_part) + if len(url_parts) == 0: + return None + return self.search_url + "&".join(url_parts) + + def add_search_unit(self, search_unit): + """Add a search unit to fields to search.""" + if search_unit[0] == "+": + search = search_unit[1] + field_name = search_unit[2] + if field_name == "author": + self.add_author(search, search_unit[3]) + elif field_name == "year" or field_name == "reportnumber": + self.fields_content[field_name].append(search) + else: + self.fields_content["title"].append("'" + search + "'") + + def add_author(self, author_name, unit_type): + """Handle an author unit. """ + if author_name.find(",") >= 0 and unit_type != "p": + (lastname, firstname) = author_name.split(",", 1) + self.fields_content["author"].append("'%s, %c'" % (lastname, firstname[0])) + else: + self.fields_content["author"].append("'" + author_name + "'") + +class KissForPreprintsSearchEngine(KissSearchEngine): + """Interface for seaching on Kiss for Preprints""" + + def __init__(self, configuration): + super(KissForPreprintsSearchEngine, self).__init__(configuration) + self.base_url = "http://www-lib.kek.jp/KISS/kiss_prepri.html" + self.search_url = "http://www-lib.kek.jp/cgi-bin/kiss_prepri?" + +class KissForBooksSearchEngine(KissSearchEngine): + """Interface for seaching on Kiss for Books""" + + def __init__(self, configuration): + super(KissForBooksSearchEngine, self).__init__(configuration) + self.base_url = "http://www-lib.kek.jp/KISS/kiss_book.html" + self.search_url = "http://www-lib.kek.jp/cgi-bin/kiss_book?DSP=1&" + self.parser = KISSBooksExternalCollectionResultsParser() + +class KissForJournalsSearchEngine(KissSearchEngine): + """Interface for seaching on Kiss for Journals.""" + + def __init__(self, configuration): + super(KissForJournalsSearchEngine, self).__init__(configuration) + self.base_url = "http://www-lib.kek.jp/KISS/kiss_book.html" + self.search_url = "http://www-lib.kek.jp/cgi-bin/kiss_book?DSP=2&" + self.parser = KISSBooksExternalCollectionResultsParser() + +# Scirus + +class ScirusSearchEngine(ExternalSearchEngine): + """Interface for the Scirus search engine.""" + + def __init__(self, configuration): + super(ScirusSearchEngine, self).__init__(configuration) + self.base_url = "http://www.scirus.com/srsapp/" + self.search_url = "http://www.scirus.com/srsapp/search?q=" + self.parser = SCIRUSExternalCollectionResultsParser() + + def build_search_unit_unit(self, search_unit): + """Build a unit for a search unit""" + sign = search_unit[0].replace("+", "") + search = self.normalize_unit(search_unit) + if search_unit[2] == "author": + return sign + "au:" + search + if search_unit[2] == "title": + return sign + "ti:" + search + if search_unit[2] == "keyword": + return sign + "keyword:" + search + if search_unit[3] == "w": + return sign + search + + def normalize_unit(self, search_unit): + """ Add double quote if needed. """ + if search_unit[3] == "a": + return '"' + search_unit[1] + '"' + else: + return search_unit[1] + +# Spires + +class SPIRESSearchEngine(ExternalSearchEngine): + """Interface for the Spires Search engine.""" + + def __init__(self, configuration): + super(SPIRESSearchEngine, self).__init__(configuration) + self.base_url = "http://www.slac.stanford.edu/spires/find/hep/" + self.search_url = "http://www.slac.stanford.edu/spires/find/hep/?rawcmd=find+" + self.combiner = " and " + self.parser = SPIRESExternalCollectionResultsParser() + + def build_search_unit_unit(self, basic): + """Build a search string from a search unit. This is the base + version that just keep keywords with "+". """ + word = format_basic(basic) + if basic[0] == "-": + sign = "not " + else: + sign = "" + if basic[2] == "author": + return sign + "a " + word + if basic[2] == "title": + return sign + "t " + word + if basic[2] == "keyword": + return sign + "k " + word + if basic[2] == "reportnumber": + return sign + "r " + word + if basic[0] == "+": + return "a " + word + " or t " + word + " or k " + word + else: + return "not a " + word + " and not t " + word + " and not k " + word + +class SPIRESBooksSearchEngine(SPIRESSearchEngine): + """SPIRES Books""" + + def __init__(self, configuration): + super(SPIRESBooksSearchEngine, self).__init__(configuration) + self.base_url = "http://www.slac.stanford.edu/spires/find/books/" + self.search_url = "http://www.slac.stanford.edu/spires/find/books/?rawcmd=find+" + self.parser = None + +class SPIRESJournalsSearchEngine(SPIRESSearchEngine): + """SPIRES Journals""" + + def __init__(self, configuration): + super(SPIRESJournalsSearchEngine, self).__init__(configuration) + self.base_url = "http://www.slac.stanford.edu/spires/find/tserials/" + self.search_url = "http://www.slac.stanford.edu/spires/find/tserials/?rawcmd=find+" + +# Misc + +class AmazonSearchEngine(ExternalSearchEngine): + """Interface for searching books on Amazon.""" + + def __init__(self, configuration): + super(AmazonSearchEngine, self).__init__(configuration) + self.base_url = "http://www.amazon.com" + self.search_url_general = "http://www.amazon.com/exec/obidos/external-search/?tag=cern&keyword=" + self.search_url_author = "http://www.amazon.com/exec/obidos/external-search/?tag=cern&field-author=" + + def build_search_url(self, basic_search_units, lang=cdslang): + """Build an URL for Amazon""" + if only_field(basic_search_units, "author"): + self.search_url = self.search_url_author + else: + self.search_url = self.search_url_general + return super(AmazonSearchEngine, self).build_search_url(basic_search_units) + +class CiteseerSearchEngine(ExternalSearchEngine): + """Interface for searching on CiteSeer.""" + + def __init__(self, configuration): + super(CiteseerSearchEngine, self).__init__(configuration) + self.base_url = "http://citeseer.ist.psu.edu" + self.search_url = "http://citeseer.ist.psu.edu/cs?q=" + self.parser = CiteSeerExternalCollectionResultsParser() + +class INSPECSearchEngine(ExternalSearchEngine): + """INSPEC""" + + def __init__(self, configuration): + super(INSPECSearchEngine, self).__init__(configuration) + self.base_url = "http://www.datastarweb.com/cern/" + self.search_url = "http://www.datastarweb.com/cern/?dblabel=inzz&query=" + self.combiner = " AND " + + @staticmethod + def build_search_unit_unit(basic): + """Build a search string from a search unit. This is the base + version that just keep keywords with "+". """ + word = format_basic(basic) + if basic[0] == "-": + return None + if basic[2] == "author": + return word + ".au." + if basic[2] == "title": + return word + ".ti." + if basic[2] == "abstract": + return word + ".ab." + if basic[2] == "year": + return word + ".yr." + return word + ".ti. OR " + word + ".ab." + +class NEBISSearchEngine(ExternalSearchEngine): + """NEBIS""" + + def __init__(self, configuration): + super(NEBISSearchEngine, self).__init__(configuration) + self.base_url = "http://opac.nebis.ch" + self.search_url_general = "http://opac.nebis.ch/F/?func=find-b&find_code=WRD&REQUEST=" + self.search_url_author = "http://opac.nebis.ch/F/?func=find-b&find_code=WAU&REQUEST=" + self.search_url_title = "http://opac.nebis.ch/F/?func=find-b&find_code=WTI&REQUEST=" + + def build_search_url(self, basic_search_units, lang=cdslang): + """Build an URL for NEBIS""" + if only_field(basic_search_units, "author"): + self.search_url = self.search_url_author + elif only_field(basic_search_units, "title"): + self.search_url = self.search_url_title + else: + self.search_url = self.search_url_general + return super(NEBISSearchEngine, self).build_search_url(basic_search_units) + +external_collections_dictionary = {} + +def build_external_collections_dictionary(): + """Build the dictionary of the external collections.""" + for (name, configuration) in cfg_external_collections.iteritems(): + engine_name = configuration.pop('engine', 'External') + 'SearchEngine' + configuration['name'] = name + if globals().has_key(engine_name): + external_collections_dictionary[name] = globals()[engine_name](configuration) + else: + print "Error : not found " + engine_name + +build_external_collections_dictionary() + diff --git a/modules/websearch/lib/websearch_external_collections_templates.py b/modules/websearch/lib/websearch_external_collections_templates.py new file mode 100644 index 000000000..779f46217 --- /dev/null +++ b/modules/websearch/lib/websearch_external_collections_templates.py @@ -0,0 +1,161 @@ +# -*- coding: utf-8 -*- +## $Id$ + +## This file is part of CDS Invenio. +## Copyright (C) 2002, 2003, 2004, 2005, 2006 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. + +"""Template for the external collections search.""" + +__lastupdated__ = """$Date$""" + +__version__ = "$Id$" + +__revision__ = "0.0.1" + +from invenio.config import cdslang +from invenio.messages import gettext_set_language + +class Template: + """Template class for the external collection search. To be loaded with template.load()""" + def __init__(self): + pass + + def external_collection_seealso_box(self, lang, links, + prolog_start='<table class="externalcollectionsbox"><tr><th colspan="2" class="externalcollectionsboxheader">', + prolog_end='</th></tr><tr><td class="externalcollectionsboxbody">', + column_separator='</td><td class="externalcollectionsboxbody">', + link_separator= '<br>', epilog='</td></tr></table>'): + """Creates the box that proposes links to other useful search engines like Google. + lang: string - The language to display in + links: list of string - List of links to display in the box + prolog_start, prolog_end, column_separator, link_separator, epilog': strings - + default HTML code for the specified position in the box""" + _ = gettext_set_language(lang) + + out = "" + if links: + out += """<a name="externalcollectionsbox"></a>""" + out += prolog_start + _("Haven't found what you were looking for? Try your search on other servers:") + prolog_end + nb_out_links_in_one_column = len(links)/2 + len(links) % 2 + out += link_separator.join(links[:nb_out_links_in_one_column]) + out += column_separator + out += link_separator.join(links[nb_out_links_in_one_column:]) + out += epilog + return out + + def external_collection_overview(self, lang=cdslang, engine_list=()): + """Prints results overview box with links to particular collections below. + lang: The language to display + engine_list: The external engines to be used""" + + if len(engine_list) <= 1: + return "" + + _ = gettext_set_language(lang) + + out = """<p><table class="externalcollectionsresultsbox"> + <thead><tr><th class="externalcollectionsresultsboxheader"><strong>%(overview_title)s</strong></th></tr></thead> + <tbody><tr><td class="externalcollectionsresultsboxbody"> """ % { + 'overview_title' : _("Results from external collections overview:") } + + for engine in engine_list: + internal_name = get_link_name(engine.name) + name = _(engine.name) + out += '''<strong><a href="#%(internal_name)s">%(name)s</a></strong><br>''' % locals() + out += "</td></tr></tbody></table>" + return out + +def print_info_line(req, html1, html2): + """Print an information line on req.""" + req.write('<table class="externalcollectionsresultsbox"><tr><td class="externalcollectionsresultsboxheader" align="left" width=50%><strong><big>') + req.write(html1) + req.write('</big></strong></td><td class="externalcollectionsresultsboxheader" align="center">') + req.write(html2) + req.write('</td></tr></table><br>') + +def print_timeout(req, lang, engine, name, url): + """Print info line for timeout.""" + _ = gettext_set_language(lang) + req.write('<a name="%s">' % get_link_name(engine.name)) + print_info_line(req, '<a href="%(url)s">%(name)s</a>' % {'url': url, 'name': name}, _('Timeout')) + req.write(_('The external search engine has not responded in time. You can check results here : <a href="%(url)s">%(name)s</a>') % locals() + '<br>') + +def get_link_name(name): + """Return a hash string for the string name.""" + return hex(abs(name.__hash__())) + +def print_results(req, lang, pagegetter, infos, current_time): + """Print results of a given search engine.""" + _ = gettext_set_language(lang) + url = infos[0] + engine = infos[1] + + results = engine.parser.parse_and_get_results(pagegetter.data) + num = format_number(engine.parser.parse_num_results()) + + html2 = _("Time : %2.3f") % current_time + if num: + num = _('%(num)s results found') % {'num': num} + else: + num = _('See results') + if num == '0': + num = _('No result found') + #if num: + # html2 += ", " + # html2 += _("Number of results : %(num_results)s") % {'num_results': num} + + internal_name = get_link_name(engine.name) + name = _(engine.name) + base_url = engine.base_url + req.write('<a name="%(internal_name)s"></a>' % locals()) + print_info_line(req, make_url(name, base_url) + ', ' + make_url(num, url) , html2) + + for result in results: + req.write(result.html + '<br>') + + if not results: + req.write(_('No results found.') + '<br>') + +def make_url(name, url): + if url: + return '<a href="' + url + '">' + name + '</a>' + else: + return name + +def format_number(num, separator=','): + """Format a number by separating thousands with a separator (by default a comma) + + >>> format_number(10) + '10' + >>> format_number(10000) + '10,000' + >>> format_number(' 000213212424249 ', '.') + '213.212.424.249' + """ + result = "" + try: + num = int(num) + except: + return None + if num == 0: + return '0' + while num > 0: + part = num % 1000 + num = num / 1000 + result = "%03d" % part + separator + result + return result.strip('0').strip(separator) + diff --git a/modules/websearch/lib/websearch_external_collections_tests.py b/modules/websearch/lib/websearch_external_collections_tests.py new file mode 100644 index 000000000..ba0c7c3df --- /dev/null +++ b/modules/websearch/lib/websearch_external_collections_tests.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- +## $Id$ + +## This file is part of CDS Invenio. +## Copyright (C) 2002, 2003, 2004, 2005, 2006 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. + +"""Testing function for the external collections search. +""" + +__lastupdated__ = """$Date$""" + +__version__ = "$Id$" + +__revision__ = "0.0.1" + +import unittest + +from invenio.websearch_external_collections_searcher import external_collections_dictionary +from invenio.websearch_external_collections_page_getter import HTTPAsyncPageGetter, async_download + +def async_download_test(): + """Test varius cases for the async_download function: + - test 2 workings pages : google, kernel.org + - test 1 unresolvable name : rjfreijoiregjreoijgoirg.fr + - test 1 bad ip : 1.2.3.4 + Return True if the test is succefull.""" + + urls = ['http://www.google.com/', 'http://rjfreijoiregjreoijgoirg.fr', 'http://1.2.3.4/', 'http://www.kernel.org'] + checks = [ ['<title>Google</title>', False], + [None, False], + [None, False], + ['<title>The Linux Kernel Archives</title>', False] ] + + def finished(pagegetter, data, current_time): + """Function called when a page is received.""" + check = data[0] + is_ok = pagegetter.status != None + + if check and is_ok: + is_ok = pagegetter.data.find(check) > 0 + + result = is_ok == (check != None) + if result: + print "Test Ok (%f): " % current_time + pagegetter.uri + else: + print "Test failed (%f): " % current_time + pagegetter.uri + + data[1] = result + + pagegetters = [HTTPAsyncPageGetter(url) for url in urls] + finished_list = async_download(pagegetters, finished, checks, 20) + + for (finished, check, pagegetter) in zip(finished_list, checks, pagegetters): + if not finished: + if check[0] == None: + print "Test Ok: " + pagegetter.uri + check[1] = True + + errors = [check for check in checks if check == False] + print errors + return len(errors) == 0 + +def download_and_parse(): + """Try to make a query that always return results on all search engines. + Check that a page is well returned and that the result can be parsed.""" + test = [['+', 'ieee', '', 'w']] + errors = [] + + external_collections = external_collections_dictionary.values() + urls = [engine.build_search_url(test)for engine in external_collections] + pagegetters = [HTTPAsyncPageGetter(url) for url in urls] + finished_list = async_download(pagegetters, None, None, 30) + print urls + print finished_list + + for (page, engine, url) in zip(pagegetters, external_collections, urls): + print engine.name + " - " + str(len(page.data)) + " - " + url + if not url: + errors.append("Unable to build url for : " + engine.name) + continue + if len(page.data) == 0: + errors.append("Zero sized page with : " + engine.name) + continue + if engine.parser: + results = engine.parser.parse_and_get_results(page.data) + num_results = engine.parser.parse_num_results() + print " parser : " + str(len(results)) + " on " + str(num_results) + if len(results) == 0: + errors.append("Unable to parse results for : " + engine.name) + continue + if not num_results: + errors.append("Unable to parse (None returned) number of results for : " + engine.name) + try: + num_results = int(num_results) + except: + errors.append("Unable to parse (not a number) number of results for : " + engine.name) + + return errors + +def build_search_urls_test(): + """Build some classical urls from basic_search_units.""" + print "Testing external_search_engines build_search_url functions." + tests = [ [['+', 'ellis', 'author', 'w'], ['+', 'unification', 'title', 'w'], + ['-', 'Ross', 'author', 'w'], ['+', 'large', '', 'w'], ['-', 'helloworld', '', 'w']], + [['+', 'ellis', 'author', 'w'], ['+', 'unification', 'title', 'w']], + [['+', 'ellis', 'author', 'w']], + [['-', 'Ross', 'author', 'w']] ] + for engine in external_collections_dictionary.values(): + print engine.name + for test in tests: + url = engine.build_search_url(test) + print " Url: " + str(url) + +def _test(): + """Make small test on the module.""" + async_download_test() + build_search_urls_test() + for error in download_and_parse(): + print error + +class TestSuite(unittest.TestCase): + """Test suite for websearch_external_collections_*""" + + def test_async_download(self): + """test of async_download function.""" + self.assertEqual(True, async_download_test()) + + def test_download_and_parse(self): + """Download page on all know search engines and check if the result is parsable.""" + self.assertEqual([], download_and_parse()) + +def create_test_suite(): + """Return test suite for the external collection tests.""" + return unittest.TestSuite((unittest.makeSuite(TestSuite, 'test'))) + +if __name__ == "__main__": + _test() + diff --git a/modules/websearch/lib/websearch_external_collections_utils.py b/modules/websearch/lib/websearch_external_collections_utils.py new file mode 100644 index 000000000..d95c92b01 --- /dev/null +++ b/modules/websearch/lib/websearch_external_collections_utils.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +## $Id$ + +## This file is part of CDS Invenio. +## Copyright (C) 2002, 2003, 2004, 2005, 2006 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. + +"""Some misc function for the external collections search. +""" + +__lastupdated__ = """$Date$""" + +__version__ = "$Id$" + +__revision__ = "0.0.1" + +from copy import copy + +from invenio.dbquery import run_sql, escape_string + +def get_verbose_print(req, prefix, cur_verbosity_level): + """Return a function used to print verbose message.""" + + def vprint(verbosity_level, message): + """Print a verbose message.""" + if cur_verbosity_level >= verbosity_level: + req.write('<br><span class="quicknote">' + prefix + message + '</span><br>') + + return vprint + +def warning(message): + """Issue a warning alert.""" + print "WARNING: %(message)s" % locals() + +def escape_dictionary(dictionary): + """Escape values of dictionary of type string with escape_string. Used for building sql query.""" + dictionary = copy(dictionary) + for key in dictionary.keys(): + if isinstance(dictionary[key], basestring): + dictionary[key] = escape_string(dictionary[key]) + return dictionary + +# Collections function +collections_id = None + +def collections_id_load(force_reload=False): + """If needed, load the database for building the dictionnary collection_name -> collection_id.""" + + global collections_id + + if not (force_reload or collections_id == None): + return + + collections_id = {} + results = run_sql("SELECT id, name FROM collection;") + for result in results: + collection_id = result[0] + name = result[1] + + collections_id[name] = collection_id + +def get_collection_id(name): + """Return the id of a collection named 'name'.""" + + collections_id_load() + + if collections_id.has_key(name): + return collections_id[name] + else: + return None + +def get_collection_descendants(id_dad): + "Returns list of all descendants of the collection having for id id_dad." + + descendants = [] + results = run_sql( "SELECT id_son FROM collection_collection WHERE id_dad=%(id_dad)d;" % + escape_dictionary({'id_dad' : id_dad})) + for result in results: + id_son = int(result[0]) + descendants.append(id_son) + descendants += get_collection_descendants(id_son) + + return descendants + diff --git a/modules/websearch/lib/websearch_templates.py b/modules/websearch/lib/websearch_templates.py index 5f52142db..187d078b8 100644 --- a/modules/websearch/lib/websearch_templates.py +++ b/modules/websearch/lib/websearch_templates.py @@ -1,2477 +1,2335 @@ # -*- coding: utf-8 -*- ## $Id$ ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006 CERN. ## ## CDS Invenio is free software; you can redistribute it and/or ## modify it under the terms of the GNU General Public License as ## published by the Free Software Foundation; either version 2 of the ## License, or (at your option) any later version. ## ## CDS Invenio is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with CDS Invenio; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. import urllib import time import cgi import gettext import string import locale import sre from invenio.config import * from invenio.dbquery import run_sql from invenio.messages import gettext_set_language from invenio.search_engine_config import * from invenio.urlutils import make_canonical_urlargd, drop_default_urlargd, a_href +from invenio.websearch_external_collections import external_collection_is_default + def get_fieldvalues(recID, tag): """Return list of field values for field TAG inside record RECID. FIXME: should be imported commonly for search_engine too.""" 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 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 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 class Template: # This dictionary maps CDS Invenio language code to locale codes (ISO 639) tmpl_localemap = { 'bg': 'bg_BG', 'ca': 'ca_ES', 'de': 'de_DE', 'el': 'el_GR', 'en': 'en_US', 'es': 'es_ES', 'pt': 'pt_BR', 'fr': 'fr_FR', 'it': 'it_IT', 'ru': 'ru_RU', 'sk': 'sk_SK', 'cs': 'cs_CZ', 'no': 'no_NO', 'sv': 'sv_SE', 'uk': 'uk_UA', 'ja': 'ja_JA', 'pl': 'pl_PL' } tmpl_default_locale = "en_US" # which locale to use by default, useful in case of failure # Type of the allowed parameters for the web interface for search results search_results_default_urlargd = { - 'cc': (str, cdsname), 'c': (list, []), + 'cc': (str, cdsname), + 'c': (list, []), 'p': (str, ""), 'f': (str, ""), 'rg': (int, 10), 'sf': (str, ""), 'so': (str, "d"), 'sp': (str, ""), 'rm': (str, ""), 'of': (str, "hb"), 'ot': (list, []), 'as': (int, 0), 'p1': (str, ""), 'f1': (str, ""), 'm1': (str, ""), 'op1':(str, ""), 'p2': (str, ""), 'f2': (str, ""), 'm2': (str, ""), 'op2':(str, ""), 'p3': (str, ""), 'f3': (str, ""), 'm3': (str, ""), 'sc': (int, 0), 'jrec': (int, 0), 'recid': (int, -1), 'recidb': (int, -1), 'sysno': (str, ""), 'id': (int, -1), 'idb': (int, -1), 'sysnb': (str, ""), 'action': (str, "search"), 'action_search': (str, ""), 'action_browse': (str, ""), 'd1y': (int, 0), 'd1m': (int, 0), 'd1d': (int, 0), 'd2y': (int, 0), 'd2m': (int, 0), 'd2d': (int, 0), 'ap': (int, 1), 'verbose': (int, 0), + 'ec': (list, []), } # ...and for search interfaces search_interface_default_urlargd = { 'as': (int, 0), 'verbose': (int, 0)} def build_search_url(self, known_parameters={}, **kargs): """ Helper for generating a canonical search url. 'known_parameters' is the list of query parameters you inherit from your current query. You can then pass keyword arguments to modify this query. build_search_url(known_parameters, of="xm") The generated URL is absolute. """ parameters = {} parameters.update(known_parameters) parameters.update(kargs) # Now, we only have the arguments which have _not_ their default value parameters = drop_default_urlargd(parameters, self.search_results_default_urlargd) # Asking for a recid? Return a /record/<recid> URL if 'recid' in parameters: target = "%s/record/%d" % (weburl, parameters['recid']) del parameters['recid'] target += make_canonical_urlargd(parameters, self.search_results_default_urlargd) return target return "%s/search%s" % (weburl, make_canonical_urlargd(parameters, self.search_results_default_urlargd)) def build_search_interface_url(self, known_parameters={}, **kargs): """ Helper for generating a canonical search interface URL.""" parameters = {} parameters.update(known_parameters) parameters.update(kargs) c = parameters['c'] del parameters['c'] # Now, we only have the arguments which have _not_ their default value if c and c != cdsname: base = weburl + '/collection/' + urllib.quote(c) else: base = weburl return base + make_canonical_urlargd(parameters, self.search_results_default_urlargd) def tmpl_record_page_header_content(self, req, recid, ln): """ Provide extra information in the header of /record pages """ _ = gettext_set_language(ln) title = get_fieldvalues(recid, "245__a") if title: title = _("Record") + '#%d: %s' %(recid, title[0]) else: title = _("Record") + ' #%d' % recid keywords = ', '.join(get_fieldvalues(recid, "6531_a")) description = ' '.join(get_fieldvalues(recid, "520__a")) description += "\n" description += '; '.join(get_fieldvalues(recid, "100__a") + get_fieldvalues(recid, "700__a")) return [cgi.escape(x, True) for x in (title, description, keywords)] def tmpl_navtrail_links(self, as, ln, dads): """ Creates the navigation bar at top of each search page (*Home > Root collection > subcollection > ...*) Parameters: - 'as' *bool* - Should we display an advanced search box? - 'ln' *string* - The language to display - 'weburl' *string* - The base URL for the site - 'separator' *string* - The separator between two consecutive collections - 'dads' *list* - A list of parent links, eachone being a dictionary of ('name', 'longname') """ out = [] for url, name in dads: out.append(a_href(name, href=self.build_search_interface_url(c=url, as=as, ln=ln), _class='navtrail')) return ' > '.join(out) def tmpl_webcoll_body(self, ln, collection, te_portalbox, searchfor, np_portalbox, narrowsearch, focuson, instantbrowse, ne_portalbox): """ Creates the body of the main search page. Parameters: - 'ln' *string* - language of the page being generated - 'collection' - collection id of the page being generated - 'te_portalbox' *string* - The HTML code for the portalbox on top of search - 'searchfor' *string* - The HTML code for the search options - 'np_portalbox' *string* - The HTML code for the portalbox on bottom of search - 'searchfor' *string* - The HTML code for the search categories (left bottom of page) - 'focuson' *string* - The HTML code for the "focuson" categories (right bottom of page) - 'ne_portalbox' *string* - The HTML code for the bottom of the page """ if not narrowsearch: narrowsearch = instantbrowse body = ''' <form name="search" action="%(weburl)s/search" method="get"> %(searchfor)s %(np_portalbox)s <table cellspacing="0" cellpadding="0" border="0"> <tr> <td valign="top">%(narrowsearch)s</td> ''' % { 'weburl' : weburl, 'searchfor' : searchfor, 'np_portalbox' : np_portalbox, 'narrowsearch' : narrowsearch } if focuson: body += """<td valign="top">""" + focuson + """</td>""" body += """</tr></table> %(ne_portalbox)s </form>""" % {'ne_portalbox' : ne_portalbox} return body def tmpl_portalbox(self, title, body): """Creates portalboxes based on the parameters Parameters: - 'title' *string* - The title of the box - 'body' *string* - The HTML code for the body of the box """ out = """<div class="portalbox"> <div class="portalboxheader">%(title)s</div> <div class="portalboxbody">%(body)s</div> </div>""" % {'title' : title, 'body' : body} return out def tmpl_searchfor_simple(self, ln, collection_id, collection_name, record_count, middle_option): """Produces simple *Search for* box for the current collection. Parameters: - 'ln' *string* - The language to display - 'header' *string* - header of search form - 'middle_option' *string* - HTML code for the options (any field, specific fields ...) """ # load the right message language _ = gettext_set_language(ln) out = ''' <!--create_searchfor_simple()--> ''' argd = drop_default_urlargd({'ln': ln, 'cc': collection_id, 'sc': 1}, self.search_results_default_urlargd) # Only add non-default hidden values for field, value in argd.items(): out += self.tmpl_input_hidden(field, value) header = _("Search %s records for:") % \ self.tmpl_nbrecs_info(record_count, "","") asearchurl = self.build_search_interface_url(c=collection_id, as=1, ln=ln) # print commentary start: out += ''' <table class="searchbox"> <thead> <tr align="left"> <th colspan="3" class="searchboxheader">%(header)s</th> </tr> </thead> <tbody> <tr valign="baseline"> <td class="searchboxbody" align="left"><input type="text" name="p" size="40" value=""></td> <td class="searchboxbody" align="left">%(middle_option)s</td> <td class="searchboxbody" align="left"> <input class="formbutton" type="submit" name="action_search" value="%(msg_search)s"> <input class="formbutton" type="submit" name="action_browse" value="%(msg_browse)s"></td> </tr> <tr valign="baseline"> <td class="searchboxbody" colspan="3" align="right"> <small> <a href="%(weburl)s/help/search/tips.%(ln)s.html">%(msg_search_tips)s</a> :: %(asearch)s </small> </td> </tr> </tbody> </table> <!--/create_searchfor_simple()--> ''' % {'ln' : ln, 'weburl' : weburl, 'asearch' : a_href(_('Advanced Search'), href=asearchurl), 'header' : header, 'middle_option' : middle_option, 'msg_search' : _('Search'), 'msg_browse' : _('Browse'), 'msg_search_tips' : _('Search Tips')} return out def tmpl_searchfor_advanced(self, ln, # current language collection_id, collection_name, record_count, middle_option_1, middle_option_2, middle_option_3, searchoptions, sortoptions, rankoptions, displayoptions, formatoptions ): """ Produces advanced *Search for* box for the current collection. Parameters: - 'ln' *string* - The language to display - 'weburl' *string* - The base URL for the site - 'ssearchurl' *string* - The URL to simple search form - 'header' *string* - header of search form - 'middle_option_1' *string* - HTML code for the first row of options (any field, specific fields ...) - 'middle_option_2' *string* - HTML code for the second row of options (any field, specific fields ...) - 'middle_option_3' *string* - HTML code for the third row of options (any field, specific fields ...) - 'searchoptions' *string* - HTML code for the search options - 'sortoptions' *string* - HTML code for the sort options - 'rankoptions' *string* - HTML code for the rank options - 'displayoptions' *string* - HTML code for the display options - 'formatoptions' *string* - HTML code for the format options """ # load the right message language _ = gettext_set_language(ln) out = ''' <!--create_searchfor_advanced()--> ''' argd = drop_default_urlargd({'ln': ln, 'as': 1, 'cc': collection_id, 'sc': 1}, self.search_results_default_urlargd) # Only add non-default hidden values for field, value in argd.items(): out += self.tmpl_input_hidden(field, value) header = _("Search %s records for") % \ self.tmpl_nbrecs_info(record_count, "","") header += ':' ssearchurl = self.build_search_interface_url(c=collection_id, as=0, ln=ln) out += ''' <table class="searchbox"> <thead> <tr> <th class="searchboxheader" colspan="3">%(header)s</th> </tr> </thead> <tbody> <tr valign="bottom"> <td class="searchboxbody" nowrap>%(matchbox_m1)s<input type="text" name="p1" size="40" value=""></td> <td class="searchboxbody">%(middle_option_1)s</td> <td class="searchboxbody">%(andornot_op1)s</td> </tr> <tr valign="bottom"> <td class="searchboxbody" nowrap>%(matchbox_m2)s<input type="text" name="p2" size="40" value=""></td> <td class="searchboxbody">%(middle_option_2)s</td> <td class="searchboxbody">%(andornot_op2)s</td> </tr> <tr valign="bottom"> <td class="searchboxbody" nowrap>%(matchbox_m3)s<input type="text" name="p3" size="40" value=""></td> <td class="searchboxbody">%(middle_option_3)s</td> <td class="searchboxbody" nowrap> <input class="formbutton" type="submit" name="action_search" value="%(msg_search)s"> <input class="formbutton" type="submit" name="action_browse" value="%(msg_browse)s"></td> </tr> <tr valign="bottom"> <td colspan="3" class="searchboxbody" align="right"> <small> <a href="%(weburl)s/help/search/tips.%(ln)s.html">%(msg_search_tips)s</a> :: %(ssearch)s </small> </td> </tr> </tbody> </table> <!-- @todo - more imports --> ''' % {'ln' : ln, 'weburl' : weburl, 'ssearch' : a_href(_("Simple Search"), href=ssearchurl), 'header' : header, 'matchbox_m1' : self.tmpl_matchtype_box('m1', ln=ln), 'middle_option_1' : middle_option_1, 'andornot_op1' : self.tmpl_andornot_box('op1', ln=ln), 'matchbox_m2' : self.tmpl_matchtype_box('m2', ln=ln), 'middle_option_2' : middle_option_2, 'andornot_op2' : self.tmpl_andornot_box('op2', ln=ln), 'matchbox_m3' : self.tmpl_matchtype_box('m3', ln=ln), 'middle_option_3' : middle_option_3, 'msg_search' : _("Search"), 'msg_browse' : _("Browse"), 'msg_search_tips' : _("Search Tips")} if (searchoptions): out += """<table class="searchbox"> <thead> <tr> <th class="searchboxheader"> %(searchheader)s </th> </tr> </thead> <tbody> <tr valign="bottom"> <td class="searchboxbody">%(searchoptions)s</td> </tr> <tbody> </table>""" % { 'searchheader' : _("Search options:"), 'searchoptions' : searchoptions } out += """<table class="searchbox"> <thead> <tr> <th class="searchboxheader"> %(added)s </th> <th class="searchboxheader"> %(until)s </th> </tr> </thead> <tbody> <tr valign="bottom"> <td class="searchboxbody">%(date_added)s</td> <td class="searchboxbody">%(date_until)s</td> </tr> </tbody> </table> <table class="searchbox"> <thead> <tr> <th class="searchboxheader"> %(msg_sort)s </th> <th class="searchboxheader"> %(msg_display)s </th> <th class="searchboxheader"> %(msg_format)s </th> </tr> </thead> <tbody> <tr valign="bottom"> <td class="searchboxbody">%(sortoptions)s %(rankoptions)s</td> <td class="searchboxbody">%(displayoptions)s</td> <td class="searchboxbody">%(formatoptions)s</td> </tr> </tbody> </table> <!--/create_searchfor_advanced()--> """ % { 'added' : _("Added since:"), 'until' : _("until:"), 'date_added' : self.tmpl_inputdate("d1", ln=ln), 'date_until' : self.tmpl_inputdate("d2", ln=ln), 'msg_sort' : _("Sort by:"), 'msg_display' : _("Display results:"), 'msg_format' : _("Output format:"), 'sortoptions' : sortoptions, 'rankoptions' : rankoptions, 'displayoptions' : displayoptions, 'formatoptions' : formatoptions } return out def tmpl_matchtype_box(self, name='m', value='', ln='en'): """Returns HTML code for the 'match type' selection box. Parameters: - 'name' *string* - The name of the produced select - 'value' *string* - The selected value (if any value is already selected) - 'ln' *string* - the language to display """ # load the right message language _ = gettext_set_language(ln) out = """ <select name="%(name)s"> <option value="a"%(sela)s>%(opta)s <option value="o"%(selo)s>%(opto)s <option value="e"%(sele)s>%(opte)s <option value="p"%(selp)s>%(optp)s <option value="r"%(selr)s>%(optr)s </select> """ % {'name' : name, 'sela' : self.tmpl_is_selected('a', value), 'opta' : _("All of the words:"), 'selo' : self.tmpl_is_selected('o', value), 'opto' : _("Any of the words:"), 'sele' : self.tmpl_is_selected('e', value), 'opte' : _("Exact phrase:"), 'selp' : self.tmpl_is_selected('p', value), 'optp' : _("Partial phrase:"), 'selr' : self.tmpl_is_selected('r', value), 'optr' : _("Regular expression:") } return out def tmpl_is_selected(self, var, fld): """ Checks if *var* and *fld* are equal, and if yes, returns ' selected'. Useful for select boxes. Parameters: - 'var' *string* - First value to compare - 'fld' *string* - Second value to compare """ if var == fld: return " selected" else: return "" def tmpl_andornot_box(self, name='op', value='', ln='en'): """ Returns HTML code for the AND/OR/NOT selection box. Parameters: - 'name' *string* - The name of the produced select - 'value' *string* - The selected value (if any value is already selected) - 'ln' *string* - the language to display """ # load the right message language _ = gettext_set_language(ln) out = """ <select name="%(name)s"> <option value="a"%(sela)s>%(opta)s <option value="o"%(selo)s>%(opto)s <option value="n"%(seln)s>%(optn)s </select> """ % {'name' : name, 'sela' : self.tmpl_is_selected('a', value), 'opta' : _("AND"), 'selo' : self.tmpl_is_selected('o', value), 'opto' : _("OR"), 'seln' : self.tmpl_is_selected('n', value), 'optn' : _("AND NOT") } return out def tmpl_inputdate(self, name, ln, sy = 0, sm = 0, sd = 0): """ Produces *From Date*, *Until Date* kind of selection box. Suitable for search options. Parameters: - 'name' *string* - The base name of the produced selects - 'ln' *string* - the language to display """ # load the right message language _ = gettext_set_language(ln) box = """ <select name="%(name)sd"> <option value=""%(sel)s>%(any)s """ % { 'name' : name, 'any' : _("any day"), 'sel' : self.tmpl_is_selected(sd, 0) } for day in range(1,32): box += """<option value="%02d"%s>%02d""" % (day, self.tmpl_is_selected(sd, day), day) box += """</select>""" # month box += """ <select name="%(name)sm"> <option value=""%(sel)s>%(any)s """ % { 'name' : name, 'any' : _("any month"), 'sel' : self.tmpl_is_selected(sm, 0) } for mm, month in [(1,_("January")), (2,_("February")), (3,_("March")), (4,_("April")), \ (5,_("May")), (6,_("June")), (7,_("July")), (8,_("August")), \ (9,_("September")), (10,_("October")), (11,_("November")), (12,_("December"))]: box += """<option value="%02d"%s>%s""" % (mm, self.tmpl_is_selected(sm, mm), month) box += """</select>""" # year box += """ <select name="%(name)sy"> <option value=""%(sel)s>%(any)s """ % { 'name' : name, 'any' : _("any year"), 'sel' : self.tmpl_is_selected(sy, 0) } this_year = int(time.strftime("%Y", time.localtime())) for year in range(this_year-20, this_year+1): box += """<option value="%d"%s>%d""" % (year, self.tmpl_is_selected(sy, year), year) box += """</select>""" return box def tmpl_narrowsearch(self, as, ln, type, father, has_grandchildren, sons, display_grandsons, grandsons): """ 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. Parameters: - 'as' *bool* - Should we display an advanced search box? - 'ln' *string* - The language to display - - 'weburl' *string* - The base URL for the site - - - 'title' *string* - The title of the produced box - - 'type' *string* - The type of the produced box (virtual collections or normal collections) - 'father' *collection* - The current collection - 'has_grandchildren' *bool* - If the current collection has grand children - 'sons' *list* - The list of the sub-collections (first level) - 'display_grandsons' *bool* - If the grand children collections should be displayed (2 level deep display) - 'grandsons' *list* - The list of sub-collections (second level) """ # load the right message language _ = gettext_set_language(ln) title = {'r': _("Narrow by collection:"), 'v': _("Focus on:")}[type] if has_grandchildren: style_prolog = "<strong>" style_epilog = "</strong>" else: style_prolog = "" style_epilog = "" out = """<table class="narrowsearchbox"> <thead> <tr> <th colspan="2" align="left" class="narrowsearchboxheader"> %(title)s </th> </tr> </thead> <tbody>""" % {'title' : title} # iterate through sons: i = 0 for son in sons: out += """<tr><td class="narrowsearchboxbody" valign="top">""" if type=='r': if son.restricted_p() and son.restricted_p() != father.restricted_p(): out += """<input type=checkbox name="c" value="%(name)s"> </td>""" % {'name' : son.name } else: out += """<input type=checkbox name="c" value="%(name)s" checked> </td>""" % {'name' : son.name } out += """<td valign="top">%(link)s%(recs)s """ % { 'link': a_href(style_prolog + son.get_name(ln) + style_epilog, href=self.build_search_interface_url(c=son.name, ln=ln, as=as)), 'recs' : self.tmpl_nbrecs_info(son.nbrecs, ln=ln)} if son.restricted_p(): out += """ <small class="warning">[%(msg)s]</small>""" % { 'msg' : _("restricted") } if display_grandsons and len(grandsons[i]): # iterate trough grandsons: out += """<br>""" for grandson in grandsons[i]: out += """ %(link)s%(nbrec)s """ % { 'link': a_href(grandson.get_name(ln), href=self.build_search_interface_url(c=grandson.name, ln=ln, as=as)), 'nbrec' : self.tmpl_nbrecs_info(grandson.nbrecs, ln=ln)} out += """</td></tr>""" i += 1 out += "</tbody></table>" return out + def tmpl_searchalso(self, ln, engines_list, collection_id): + _ = gettext_set_language(ln) + + box_name = _("Search also :") + + html = """<table cellspacing="0" cellpadding="0" border="0"> + <tr><td valign="top"><table class="narrowsearchbox"> + <thead><tr><th colspan="2" align="left" class="narrowsearchboxheader">%(box_name)s + </th></tr></thead><tbody> + """ % locals() + + for engine in engines_list: + internal_name = engine.name + name = _(internal_name) + if external_collection_is_default(engine, collection_id): + checked = ' checked' + else: + checked = '' + + html += """<tr><td class="narrowsearchboxbody" valign="top"> + <input type=checkbox name="ec" value="%(internal_name)s" %(checked)s> </td> + <td valign="top"><strong>%(name)s</strong></td></tr>""" % locals() + + html += """</tr></tbody></table></table>""" + return html + def tmpl_nbrecs_info(self, number, prolog=None, epilog=None, ln=cdslang): """ Return information on the number of records. Parameters: - 'number' *string* - The number of records - 'prolog' *string* (optional) - An HTML code to prefix the number (if **None**, will be '<small class="nbdoccoll">(') - 'epilog' *string* (optional) - An HTML code to append to the number (if **None**, will be ')</small>') """ if number is None: return '' if prolog is None: prolog = ''' <small class="nbdoccoll">(''' if epilog is None: epilog = ''')</small>''' return prolog + self.tmpl_nice_number(number, ln) + epilog def tmpl_box_restricted_content(self, ln): """ Displays a box containing a *restricted content* message Parameters: - 'ln' *string* - The language to display """ # load the right message language _ = gettext_set_language(ln) return _("The contents of this collection is restricted.") def tmpl_box_no_records(self, ln): """ Displays a box containing a *no content* message Parameters: - 'ln' *string* - The language to display """ # load the right message language _ = gettext_set_language(ln) return _("This collection does not contain any document yet.") def tmpl_instant_browse(self, as, ln, recids, more_link = None): """ Formats a list of records (given in the recids list) from the database. Parameters: - 'as' *int* - Advanced Search interface or not (0 or 1) - 'ln' *string* - The language to display - 'recids' *list* - the list of records from the database - 'more_link' *string* - the "More..." link for the record. If not given, will not be displayed """ # load the right message language _ = gettext_set_language(ln) body = '''<table class="latestadditionsbox">''' for recid in recids: body += ''' <tr> <td class="latestadditionsboxtimebody">%(date)s</td> <td class="latestadditionsboxrecordbody">%(body)s</td> </tr>''' % {'date': recid['date'], 'body': recid['body'] } body += "</table>" if more_link: body += '<div align="right"><small>' + \ a_href('[>> %s]' % _("more"), href=more_link) + \ '</small></div>' return ''' <table class="narrowsearchbox"> <thead> <tr> <th class="narrowsearchboxheader">%(header)s</th> </tr> </thead> <tbody> <tr> <td class="narrowsearchboxbody">%(body)s</td> </tr> <tbody> </table>''' % {'header' : _("Latest additions:"), 'body' : body, } def tmpl_searchwithin_select(self, ln, fieldname, selected, values): """ Produces 'search within' selection box for the current collection. Parameters: - 'ln' *string* - The language to display - 'fieldname' *string* - the name of the select box produced - 'selected' *string* - which of the values is selected - 'values' *list* - the list of values in the select """ out = '<select name="%(fieldname)s">' % {'fieldname': fieldname} if values: for pair in values: out += """<option value="%(value)s"%(selected)s>%(text)s""" % { 'value' : pair['value'], 'selected' : self.tmpl_is_selected(pair['value'], selected), 'text' : pair['text'] } out += """</select>""" return out def tmpl_select(self, fieldname, values, selected=None, css_class=''): """ Produces a generic select box Parameters: - 'css_class' *string* - optional, a css class to display this select with - 'fieldname' *list* - the name of the select box produced - 'selected' *string* - which of the values is selected - 'values' *list* - the list of values in the select """ if css_class != '': class_field = ' class="%s"' % css_class else: class_field = '' out = '<select name="%(fieldname)s"%(class)s>' % { 'fieldname' : fieldname, 'class' : class_field } for pair in values: if pair.get('selected', False) or pair['value'] == selected: flag = ' selected' else: flag = '' out += '<option value="%(value)s"%(selected)s>%(text)s' % { 'value' : pair['value'], 'selected' : flag, 'text' : pair['text'] } out += """</select>""" return out def tmpl_record_links(self, weburl, recid, ln): """ Displays the *More info* and *Find similar* links for a record Parameters: - 'ln' *string* - The language to display - 'weburl' *string* - The base URL for the site - 'recid' *string* - the id of the displayed record """ # load the right message language _ = gettext_set_language(ln) out = '''<br><span class="moreinfo">%(detailed)s - %(similar)s</span>''' % { 'detailed': a_href(_("Detailed record"), _class="moreinfo", href=self.build_search_url(recid=recid, ln=ln)), 'similar': a_href(_("Similar records"), _class="moreinfo", href=self.build_search_url(p="recid:%d" % recid, rm='wrd', ln=ln))} if cfg_experimental_features: out += '''<span class="moreinfo"> - %s </span>''' % \ a_href(_("Cited by"), _class="moreinfo", href=self.build_search_url(p='recid:%d' % recid, rm='cit', ln=ln)) return out def tmpl_record_body(self, weburl, titles, authors, dates, rns, abstracts, urls_u, urls_z, ln): """ Displays the "HTML basic" format of a record Parameters: - 'weburl' *string* - The base URL for the site - 'authors' *list* - the authors (as strings) - 'dates' *list* - the dates of publication - 'rns' *list* - the quicknotes for the record - 'abstracts' *list* - the abstracts for the record - 'urls_u' *list* - URLs to the original versions of the notice - 'urls_z' *list* - Not used """ out = "" for title in titles: out += "<strong>%(title)s</strong> " % { 'title' : cgi.escape(title) } if authors: out += " / " for author in authors[:cfg_author_et_al_threshold]: out += '%s; ' % \ a_href(cgi.escape(author), href=self.build_search_url(p=author, f='author', ln=ln)) if len(authors) > cfg_author_et_al_threshold: out += "<em>et al</em>" for date in dates: out += " %s." % cgi.escape(date) for rn in rns: out += """ <small class="quicknote">[%(rn)s]</small>""" % {'rn' : cgi.escape(rn)} for abstract in abstracts: out += "<br><small>%(abstract)s [...]</small>" % {'abstract' : cgi.escape(abstract[:1+string.find(abstract, '.')]) } for idx in range(0,len(urls_u)): out += """<br><small class="note"><a class="note" href="%(url)s">%(name)s</a></small>""" % { 'url' : urls_u[idx], 'name' : urls_u[idx] } return out def tmpl_search_in_bibwords(self, p, f, ln, nearest_box): """ Displays the *Words like current ones* links for a search Parameters: - 'p' *string* - Current search words - 'f' *string* - the fields in which the search was done - 'nearest_box' *string* - the HTML code for the "nearest_terms" box - most probably from a create_nearest_terms_box call """ # load the right message language _ = gettext_set_language(ln) out = '<p>' if f: out += _("Words nearest to %(x_word)s inside %(x_field)s in any collection are:") % {'x_word': '<em>' + p + '</em>', 'x_field': '<em>' + f + '</em>'} else: out += _("Words nearest to %(x_word)s in any collection are:") % {'x_word': '<em>' + p + '</em>'} out += '<br />' + nearest_box + '</p>' return out def tmpl_nearest_term_box(self, p, ln, f, terminfo, intro): """ Displays the *Nearest search terms* box Parameters: - 'p' *string* - Current search words - 'f' *string* - a collection description (if the search has been completed in a collection) - 'ln' *string* - The language to display - 'weburl' *string* - The base URL for the site - 'terminfo': tuple (term, hits, argd) for each near term - 'intro' *string* - the intro HTML to prefix the box with """ out = '''<table class="nearesttermsbox" cellpadding="0" cellspacing="0" border="0">''' for term, hits, argd in terminfo: if hits: hitsinfo = str(hits) else: hitsinfo = '-' term = cgi.escape(term) if term == p: # print search word for orientation: nearesttermsboxbody_class = "nearesttermsboxbodyselected" if hits > 0: term = a_href(term, href=self.build_search_url(argd), _class="nearesttermsselected") else: nearesttermsboxbody_class = "nearesttermsboxbody" term = a_href(term, href=self.build_search_url(argd), _class="nearestterms") out += '''\ <tr> <td class="%(nearesttermsboxbody_class)s" align="right">%(hits)s</td> <td class="%(nearesttermsboxbody_class)s" width="15"> </td> <td class="%(nearesttermsboxbody_class)s" align="left">%(term)s</td> </tr> ''' % {'hits': hitsinfo, 'nearesttermsboxbody_class': nearesttermsboxbody_class, 'term': term} out += "</table>" return intro + "<blockquote>" + out + "</blockquote>" def tmpl_browse_pattern(self, f, ln, browsed_phrases_in_colls, colls): """ Displays the *Nearest search terms* box Parameters: - 'f' *string* - a field name (i18nized) - 'ln' *string* - The language to display - 'weburl' *string* - The base URL for the site - 'browsed_phrases_in_colls' *array* - the phrases to display - 'colls' *array* - the list of collection parameters of the search (c's) """ # load the right message language _ = gettext_set_language(ln) out = """<table class="searchresultsbox"> <thead> <tr> <th class="searchresultsboxheader" align="left"> %(hits)s </th> <th class="searchresultsboxheader" width="15"> </th> <th class="searchresultsboxheader" align="left"> %(f)s </th> </tr> </thead> <tbody>""" % { 'hits' : _("Hits"), 'f' : f } if len(browsed_phrases_in_colls) == 1: # one hit only found: phrase, nbhits = browsed_phrases_in_colls[0][0], browsed_phrases_in_colls[0][1] query = {'c': colls, 'ln': ln, 'p': '"%s"' % phrase, 'f': f} out += """<tr> <td class="searchresultsboxbody" align="right"> %(nbhits)s </td> <td class="searchresultsboxbody" width="15"> </td> <td class="searchresultsboxbody" align="left"> %(link)s </td> </tr>""" % {'nbhits': nbhits, 'link': a_href(phrase, href=self.build_search_url(query))} elif len(browsed_phrases_in_colls) > 1: # first display what was found but the last one: for phrase, nbhits in browsed_phrases_in_colls[:-1]: query = {'c': colls, 'ln': ln, 'p': '"%s"' % phrase, 'f': f} out += """<tr> <td class="searchresultsboxbody" align="right"> %(nbhits)s </td> <td class="searchresultsboxbody" width="15"> </td> <td class="searchresultsboxbody" align="left"> %(link)s </td> </tr>""" % {'nbhits' : nbhits, 'link': a_href(phrase, href=self.build_search_url(query))} # now display last hit as "next term": phrase, nbhits = browsed_phrases_in_colls[-1] query = {'c': colls, 'ln': ln, 'p': phrase, 'f': f} out += """<tr><td colspan="2" class="normal"> </td> <td class="normal"> <img src="%(weburl)s/img/sn.gif" alt="" border="0"> %(link)s </td> </tr>""" % {'link': a_href(_("next"), href=self.build_search_url(query, action='browse')), 'weburl' : weburl} out += """</tbody> </table>""" return out def tmpl_search_box(self, ln, as, cc, cc_intl, ot, sp, action, fieldslist, f1, f2, f3, m1, m2, m3, p1, p2, p3, op1, op2, rm, p, f, coll_selects, d1y, d2y, d1m, d2m, d1d, d2d, sort_formats, - sf, so, ranks, sc, rg, formats, of, pl, jrec): + sf, so, ranks, sc, rg, formats, of, pl, jrec, ec): """ Displays the *Nearest search terms* box Parameters: - 'ln' *string* - The language to display - 'weburl' *string* - The base URL for the site - 'as' *bool* - Should we display an advanced search box? - 'cc_intl' *string* - the i18nized current collection name - 'cc' *string* - the internal current collection name - 'ot', 'sp' *string* - hidden values - 'action' *string* - the action demanded by the user - 'fieldlist' *list* - the list of all fields available in CDSWare, for use in select within boxes in advanced search - 'p, f, f1, f2, f3, m1, m2, m3, p1, p2, p3, op1, op2, op3, rm' *strings* - the search parameters - 'coll_selects' *array* - a list of lists, each containing the collections selects to display - 'd1y, d2y, d1m, d2m, d1d, d2d' *int* - the search between dates - 'sort_formats' *array* - the select information for the sorting format - 'sf' *string* - the currently selected sort format - 'so' *string* - the currently selected sort order ("a" or "d") - 'ranks' *array* - ranking methods - 'rm' *string* - selected ranking method - 'sc' *string* - split by collection or not - 'rg' *string* - selected results/page - 'formats' *array* - available output formats - 'of' *string* - the selected output format - 'pl' *string* - `limit to' search pattern """ # load the right message language _ = gettext_set_language(ln) # These are hidden fields the user does not manipulate # directly argd = drop_default_urlargd({ 'ln': ln, 'as': as, - 'cc': cc, 'ot': ot, 'sp': sp, + 'cc': cc, 'ot': ot, 'sp': sp, 'ec': ec, }, self.search_results_default_urlargd) out = ''' <h1 class="headline">%(ccname)s</h1> <form name="search" action="%(weburl)s/search" method="get"> ''' % {'ccname' : cc_intl, 'weburl' : weburl} # Only add non-default hidden values for field, value in argd.items(): out += self.tmpl_input_hidden(field, value) leadingtext = _("Search") if action == 'browse': leadingtext = _("Browse") if as == 1: # print Advanced Search form: google = '' if cfg_google_box and (p1 or p2 or p3): google = '<small> :: <a href="#googlebox">%(search_smwhere)s</a></small>' % { 'search_smwhere' : _("Try your search on...") } # define search box elements: out += ''' <table class="searchbox"> <thead> <tr> <th colspan="3" class="searchboxheader"> %(leading)s: </th> </tr> </thead> <tbody> <tr valign="top"> <td class="searchboxbody">%(matchbox1)s <input type="text" name="p1" size="%(sizepattern)d" value="%(p1)s"> </td> <td class="searchboxbody">%(searchwithin1)s</td> <td class="searchboxbody">%(andornot1)s</td> </tr> <tr valign="top"> <td class="searchboxbody">%(matchbox2)s <input type="text" name="p2" size="%(sizepattern)d" value="%(p2)s"> </td> <td class="searchboxbody">%(searchwithin2)s</td> <td class="searchboxbody">%(andornot2)s</td> </tr> <tr valign="top"> <td class="searchboxbody">%(matchbox3)s <input type="text" name="p3" size="%(sizepattern)d" value="%(p3)s"> </td> <td class="searchboxbody">%(searchwithin3)s</td> <td class="searchboxbody"> <input class="formbutton" type="submit" name="action_search" value="%(search)s"> <input class="formbutton" type="submit" name="action_browse" value="%(browse)s"> </td> </tr> <tr valign="bottom"> <td colspan="3" align="right" class="searchboxbody"> <small> <a href="%(weburl)s/help/search/tips.%(ln)s.html">%(search_tips)s</a> :: %(simple_search)s </small> %(google)s </td> </tr> </tbody> </table> ''' % { 'simple_search': a_href(_("Simple Search"), href=self.build_search_url(p=p1, f=f1, rm=rm, cc=cc, ln=ln, jrec=jrec, rg=rg)), 'leading' : leadingtext, 'sizepattern' : cfg_advancedsearch_pattern_box_width, 'matchbox1' : self.tmpl_matchtype_box('m1', m1, ln=ln), 'p1' : cgi.escape(p1,1), 'searchwithin1' : self.tmpl_searchwithin_select( ln = ln, fieldname = 'f1', selected = f1, values = self._add_mark_to_field(value = f1, fields = fieldslist, ln = ln) ), 'andornot1' : self.tmpl_andornot_box( name = 'op1', value = op1, ln = ln ), 'matchbox2' : self.tmpl_matchtype_box('m2', m2, ln=ln), 'p2' : cgi.escape(p2,1), 'searchwithin2' : self.tmpl_searchwithin_select( ln = ln, fieldname = 'f2', selected = f2, values = self._add_mark_to_field(value = f2, fields = fieldslist, ln = ln) ), 'andornot2' : self.tmpl_andornot_box( name = 'op2', value = op2, ln = ln ), 'matchbox3' : self.tmpl_matchtype_box('m3', m3, ln=ln), 'p3' : cgi.escape(p3,1), 'searchwithin3' : self.tmpl_searchwithin_select( ln = ln, fieldname = 'f3', selected = f3, values = self._add_mark_to_field(value = f3, fields = fieldslist, ln = ln) ), 'search' : _("Search"), 'browse' : _("Browse"), 'weburl' : weburl, 'ln' : ln, 'search_tips': _("Search Tips"), 'google' : google, } else: # print Simple Search form: google = '' if cfg_google_box and (p1 or p2 or p3): google = '''<small> :: <a href="#googlebox">%(search_smwhere)s</a></small>''' % { 'search_smwhere' : _("Try your search on...") } out += ''' <table class="searchbox"> <thead> <tr> <th colspan="3" class="searchboxheader"> %(leading)s: </th> </tr> </thead> <tbody> <tr valign="top"> <td class="searchboxbody"><input type="text" name="p" size="%(sizepattern)d" value="%(p)s"></td> <td class="searchboxbody">%(searchwithin)s</td> <td class="searchboxbody"> <input class="formbutton" type="submit" name="action_search" value="%(search)s"> <input class="formbutton" type="submit" name="action_browse" value="%(browse)s"> </td> </tr> <tr valign="bottom"> <td colspan="3" align="right" class="searchboxbody"> <small> <a href="%(weburl)s/help/search/tips.%(ln)s.html">%(search_tips)s</a> :: %(advanced_search)s </small> %(google)s </td> </tr> </tbody> </table> ''' % { 'advanced_search': a_href(_("Advanced Search"), href=self.build_search_url(p1=p, f1=f, rm=rm, as=1, cc=cc, jrec=jrec, ln=ln, rg=rg)), 'leading' : leadingtext, 'sizepattern' : cfg_advancedsearch_pattern_box_width, 'p' : cgi.escape(p, 1), 'searchwithin' : self.tmpl_searchwithin_select( ln = ln, fieldname = 'f', selected = f, values = self._add_mark_to_field(value=f, fields=fieldslist, ln=ln) ), 'search' : _("Search"), 'browse' : _("Browse"), 'weburl' : weburl, 'ln' : ln, 'search_tips': _("Search Tips"), 'google' : google, } ## secondly, print Collection(s) box: selects = '' for sel in coll_selects: selects += self.tmpl_select(fieldname='c', values=sel) out += """ <table class="searchbox"> <thead> <tr> <th colspan="3" class="searchboxheader"> %(leading)s %(msg_coll)s: </th> </tr> </thead> <tbody> <tr valign="bottom"> <td valign="top" class="searchboxbody"> %(colls)s </td> </tr> </tbody> </table> """ % { 'leading' : leadingtext, 'msg_coll' : _("collections"), 'colls' : selects, } ## thirdly, print search limits, if applicable: if action != _("Browse") and pl: out += """<table class="searchbox"> <thead> <tr> <th class="searchboxheader"> %(limitto)s </th> </tr> </thead> <tbody> <tr valign="bottom"> <td class="searchboxbody"> <input type="text" name="pl" size="%(sizepattern)d" value="%(pl)s"> </td> </tr> </tbody> </table>""" % { 'limitto' : _("Limit to:"), 'sizepattern' : cfg_advancedsearch_pattern_box_width, 'pl' : cgi.escape(pl, 1), } ## fourthly, print from/until date boxen, if applicable: if action == _("Browse") or (d1y==0 and d1m==0 and d1d==0 and d2y==0 and d2m==0 and d2d==0): pass # do not need it else: cell_6_a = self.tmpl_inputdate("d1", ln, d1y, d1m, d1d) cell_6_b = self.tmpl_inputdate("d2", ln, d2y, d2m, d2d) out += """<table class="searchbox"> <thead> <tr> <th class="searchboxheader"> %(added)s </th> <th class="searchboxheader"> %(until)s </th> </tr> </thead> <tbody> <tr valign="bottom"> <td class="searchboxbody">%(date1)s</td> <td class="searchboxbody">%(date2)s</td> </tr> </tbody> </table>""" % { 'added' : _("Added since:"), 'until' : _("until:"), 'date1' : self.tmpl_inputdate("d1", ln, d1y, d1m, d1d), 'date2' : self.tmpl_inputdate("d2", ln, d2y, d2m, d2d), } ## fifthly, print Display results box, including sort/rank, formats, etc: if action != _("Browse"): rgs = [] for i in [10, 25, 50, 100, 250, 500]: rgs.append({ 'value' : i, 'text' : "%d %s" % (i, _("results"))}) # sort by: out += """<table class="searchbox"> <thead> <tr> <th class="searchboxheader"> %(sort_by)s </th> <th class="searchboxheader"> %(display_res)s </th> <th class="searchboxheader"> %(out_format)s </th> </tr> </thead> <tbody> <tr valign="bottom"> <td valign="top" class="searchboxbody"> %(select_sf)s %(select_so)s %(select_rm)s </td> <td valign="top" class="searchboxbody"> %(select_rg)s %(select_sc)s </td> <td valign="top" class="searchboxbody">%(select_of)s</td> </tr> </tbody> </table>""" % { 'sort_by' : _("Sort by:"), 'display_res' : _("Display results:"), 'out_format' : _("Output format:"), 'select_sf' : self.tmpl_select(fieldname = 'sf', values = sort_formats, selected = sf, css_class = 'address'), 'select_so' : self.tmpl_select(fieldname = 'so', values = [{ 'value' : 'a', 'text' : _("asc.") }, { 'value' : 'd', 'text' : _("desc.") }], selected = so, css_class = 'address'), 'select_rm' : self.tmpl_select(fieldname = 'rm', values = ranks, selected = rm, css_class = 'address'), 'select_rg' : self.tmpl_select(fieldname = 'rg', values = rgs, selected = rg, css_class = 'address'), 'select_sc' : self.tmpl_select(fieldname = 'sc', values = [{ 'value' : 0, 'text' : _("single list") }, { 'value' : 1, 'text' : _("split by collection") }], selected = sc, css_class = 'address'), 'select_of' : self.tmpl_searchwithin_select( ln = ln, fieldname = 'of', selected = of, values = self._add_mark_to_field(value = of, fields = formats, chars = 3, ln = ln) ), } ## last but not least, print end of search box: out += """</form>""" return out def tmpl_input_hidden(self, name, value): "Produces the HTML code for a hidden field " + if isinstance(value, list): + list_input = [self.tmpl_input_hidden(name, val) for val in value] + return "\n".join(list_input) + return """<input type="hidden" name="%(name)s" value="%(value)s">""" % { 'name' : cgi.escape(str(name), 1), 'value' : cgi.escape(str(value), 1), } def _add_mark_to_field(self, value, fields, ln, chars = 1): """Adds the current value as a MARC tag in the fields array Useful for advanced search""" # load the right message language _ = gettext_set_language(ln) out = fields if value and str(value[0:chars]).isdigit(): out.append({'value' : value, 'text' : str(value) + " " + _("MARC tag") }) return out - def tmpl_google_box(self, ln, cc, p, f, prolog_start, prolog_end, column_separator, link_separator, epilog): - """Creates the box that proposes links to other useful search engines like Google. - - Parameters: - - - 'ln' *string* - The language to display in - - - 'cc' *string* - the internal current collection name - - - 'p' *string* - the search query - - - 'f' *string* - the current field - - - 'prolog_start, prolog_end, column_separator, link_separator, epilog' *strings* - default HTML code for the specified position in the box - """ - - # load the right message language - _ = gettext_set_language(ln) - - out_links = [] - p_quoted = urllib.quote(p) - # Amazon - if cfg_google_box_servers.get('Amazon', 0): - if string.find(cc, "Book") >= 0: - if f == "author": - out_links.append("""<a class="google" href="http://www.amazon.com/exec/obidos/external-search/?field-author=%s&tag=cern">%s %s Amazon</a>""" % (p_quoted, p, _('in'))) - else: - out_links.append("""<a class="google" href="http://www.amazon.com/exec/obidos/external-search/?keyword=%s&tag=cern">%s %s Amazon</a>""" % (p_quoted, p, _('in'))) - # CERN Intranet: - if cfg_google_box_servers.get('CERN Intranet', 0): - out_links.append("""<a class="google" href="http://search.cern.ch/query.html?qt=%s">%s %s CERN Intranet</a>""" % (urllib.quote(string.replace(p, ' ', ' +')), p, _('in'))) - # CERN Agenda: - if cfg_google_box_servers.get('CERN Agenda', 0): - if f == "author": - out_links.append("""<a class="google" href="http://agenda.cern.ch/search.php?field=speaker&keywords=%s&search=Search">%s %s CERN Agenda</a>""" % (p_quoted, p, _('in'))) - elif f == "title": - out_links.append("""<a class="google" href="http://agenda.cern.ch/search.php?field=title&keywords=%s&search=Search">%s %s CERN Agenda</a>""" % (p_quoted, p, _('in'))) - # CERN EDMS: - if cfg_google_box_servers.get('CERN Agenda', 0): - # FIXME: reusing CERN Agenda config variable until we can enter CERN EDMS into config.wml - if f == "author": - out_links.append("""<a class="google" href="https://edms.cern.ch/cedar/plsql/fullsearch.doc_search?p_search_type=ADVANCED&p_author=%s">%s %s CERN EDMS</a>""" % (p_quoted, p, _("in"))) - elif f == "title" or f == "abstract" or f == "keyword": - out_links.append("""<a class="google" href="https://edms.cern.ch/cedar/plsql/fullsearch.doc_search?p_search_type=ADVANCED&p_title=%s">%s %s CERN EDMS</a>""" % (p_quoted, p, _("in"))) - elif f == "reportnumber": - out_links.append("""<a class="google" href="https://edms.cern.ch/cedar/plsql/fullsearch.doc_search?p_search_type=ADVANCED&p_document_id=%s">%s %s CERN EDMS</a>""" % (p_quoted, p, _("in"))) - else: - out_links.append("""<a class="google" href="https://edms.cern.ch/cedar/plsql/fullsearch.doc_search?p_search_type=BASE&p_free_text=%s">%s %s CERN EDMS</a>""" % (p_quoted, p, _("in"))) - # CiteSeer: - if cfg_google_box_servers.get('CiteSeer', 0): - out_links.append("""<a class="google" href="http://citeseer.ist.psu.edu/cs?q=%s">%s %s CiteSeer</a>""" % (p_quoted, p, _('in'))) - # Google Print: - if cfg_google_box_servers.get('Google Scholar', 0): - # FIXME: reusing Google Scholar config variable until we can enter Google Print into config.wml - if string.find(cc, "Book") >= 0: - out_links.append("""<a class="google" href="http://print.google.com/print?q=%s">%s %s Google Print</a>""" % (p_quoted, p, _("in"))) - # Google Scholar: - if cfg_google_box_servers.get('Google Scholar', 0): - if f == "author": - out_links.append("""<a class="google" href="http://scholar.google.com/scholar?q=author%%3A%s">%s %s Google Scholar</a>""" % (p_quoted, p, _('in'))) - else: - out_links.append("""<a class="google" href="http://scholar.google.com/scholar?q=%s">%s %s Google Scholar</a>""" % (p_quoted, p, _('in'))) - # Google Web: - if cfg_google_box_servers.get('Google Web', 0): - if f == "author": - p_google = p - if string.find(p, ",") >= 0 and (not p.startswith('"')) and (not p.endswith('"')): - p_lastname, p_firstnames = string.split(p, ",", 1) - p_google = '"%s %s" OR "%s %s"' % (p_lastname, p_firstnames, p_firstnames, p_lastname) - out_links.append("""<a class="google" href="http://google.com/search?q=%s">%s %s Google Web</a>""" % (urllib.quote(p_google), p_google, _('in'))) - else: - out_links.append("""<a class="google" href="http://google.com/search?q=%s">%s %s Google Web</a>""" % (p_quoted, p, _('in'))) - # IEC - if cfg_google_box_servers.get('IEC', 0): - if string.find(cc, "Standard") >= 0: - out_links.append("""<a class="google" href="http://www.iec.ch/cgi-bin/procgi.pl/www/iecwww.p?wwwlang=E&wwwprog=sea22.p&search=text&searchfor=%s">%s %s IEC</a>""" % (p_quoted, p, _('in'))) - # IHS - if cfg_google_box_servers.get('IHS', 0): - if string.find(cc, "Standard") >= 0: - out_links.append("""<a class="google" href="http://global.ihs.com/search_res.cfm?&input_doc_title=%s">%s %s IHS</a>""" % (p_quoted, p, _('in'))) - # INSPEC - if cfg_google_box_servers.get('INSPEC', 0): - if f == "author": - p_inspec = sre.sub(r'(, )| ', '-', p) - p_inspec = sre.sub(r'(-\w)\w+$', '\\1', p_inspec) - out_links.append("""<a class="google" href="http://www.datastarweb.com/cern/?dblabel=inzz&query=%s.au.">%s %s INSPEC</a>""" % (urllib.quote(p_inspec), p_inspec, _('in'))) - elif f == "title": - out_links.append("""<a class="google" href="http://www.datastarweb.com/cern/?dblabel=inzz&query=%s.ti.">%s %s INSPEC</a>""" % (p_quoted, p, _('in'))) - elif f == "abstract": - out_links.append("""<a class="google" href="http://www.datastarweb.com/cern/?dblabel=inzz&query=%s.ab.">%s %s INSPEC</a>""" % (p_quoted, p, _('in'))) - elif f == "year": - out_links.append("""<a class="google" href="http://www.datastarweb.com/cern/?dblabel=inzz&query=%s.yr.">%s %s INSPEC</a>""" % (p_quoted, p, _('in'))) - # ISO - if cfg_google_box_servers.get('ISO', 0): - if string.find(cc, "Standard") >= 0: - out_links.append("""<a class="google" href="http://www.iso.org/iso/en/StandardsQueryFormHandler.StandardsQueryFormHandler?languageCode=en&keyword=%s&lastSearch=false&title=true&isoNumber=&isoPartNumber=&isoDocType=ALL&isoDocElem=ALL&ICS=&stageCode=&stagescope=Current&repost=1&stagedatepredefined=&stageDate=&committee=ALL&subcommittee=&scopecatalogue=CATALOGUE&scopeprogramme=PROGRAMME&scopewithdrawn=WITHDRAWN&scopedeleted=DELETED&sortOrder=ISO">%s %s ISO</a>""" % (p_quoted, p, _('in'))) - # KEK - if cfg_google_box_servers.get('KEK', 0): - kek_search_title = "KEK KISS Preprints" - kek_search_baseurl = "http://www-lib.kek.jp/cgi-bin/kiss_prepri?" - if string.find(cc, "Book") >= 0: - kek_search_title = "KEK Library Books" - kek_search_baseurl = "http://www-lib.kek.jp/cgi-bin/kiss_book?DSP=1&" - elif string.find(cc, "Periodical") >= 0: - kek_search_title = "KEK Library Journals" - kek_search_baseurl = "http://www-lib.kek.jp/cgi-bin/kiss_book?DSP=2&" - if f == "author": - out_links.append("""<a class="google" href="%sAU=%s">%s %s %s</a>""" % \ - (kek_search_baseurl, p_quoted, p, _('in'), kek_search_title)) - elif f == "title": - out_links.append("""<a class="google" href="%sTI=%s">%s %s %s</a>""" % \ - (kek_search_baseurl, p_quoted, p, _('in'), kek_search_title)) - elif f == "reportnumber": - out_links.append("""<a class="google" href="%sRP=%s">%s %s %s</a>""" % \ - (kek_search_baseurl, p_quoted, p, _('in'), kek_search_title)) - # NEBIS - if cfg_google_box_servers.get('NEBIS', 0): - if string.find(cc, "Book") >= 0: - if f == "author": - out_links.append("""<a class="google" href="http://opac.nebis.ch/F/?func=find-b&REQUEST=%s&find_code=WAU">%s %s NEBIS</a>""" % (p_quoted, p, _('in'))) - elif f == "title": - out_links.append("""<a class="google" href="http://opac.nebis.ch/F/?func=find-b&REQUEST=%s&find_code=WTI">%s %s NEBIS</a>""" % (p_quoted, p, _('in'))) - else: - out_links.append("""<a class="google" href="http://opac.nebis.ch/F/?func=find-b&REQUEST=%s&find_code=WRD">%s %s NEBIS</a>""" % (p_quoted, p, _('in'))) - # Scirus: - if cfg_google_box_servers.get('Google Scholar', 0): - # FIXME: reusing Google Scholar config variable until we can enter Scirus into config.wml - if f == "author": - out_links.append("""<a class="google" href="http://www.scirus.com/srsapp/search?q=author%%3A%s">%s %s Scirus</a>""" % (p_quoted, p, _("in"))) - elif f == "title": - out_links.append("""<a class="google" href="http://www.scirus.com/srsapp/search?q=title%%3A%s">%s %s Scirus</a>""" % (p_quoted, p, _("in"))) - elif f == "keyword": - out_links.append("""<a class="google" href="http://www.scirus.com/srsapp/search?q=keywords%%3A%s">%s %s Scirus</a>""" % (p_quoted, p, _("in"))) - else: - out_links.append("""<a class="google" href="http://www.scirus.com/srsapp/search?q=%s">%s %s Scirus</a>""" % (p_quoted, p, _("in"))) - # SPIRES - if cfg_google_box_servers.get('SPIRES', 0): - spires_search_title = "SLAC SPIRES HEP" - spires_search_baseurl = "http://www.slac.stanford.edu/spires/find/hep/" - if string.find(cc, "Book") >= 0: - spires_search_title = "SLAC Library Books" - spires_search_baseurl = "http://www.slac.stanford.edu/spires/find/books/" - elif string.find(cc, "Periodical") >= 0: - spires_search_title = "SLAC Library Journals" - spires_search_baseurl = "http://www.slac.stanford.edu/spires/find/tserials/" - if f == "author": - out_links.append("""<a class="google" href="%swww?AUTHOR=%s">%s %s %s</a>""" % \ - (spires_search_baseurl, p_quoted, p, _('in'), spires_search_title)) - elif f == "title": - out_links.append("""<a class="google" href="%swww?TITLE=%s">%s %s %s</a>""" % \ - (spires_search_baseurl, p_quoted, p, _('in'), spires_search_title)) - elif f == "reportnumber": - out_links.append("""<a class="google" href="%swww?REPORT-NUM=%s">%s %s %s</a>""" % \ - (spires_search_baseurl, p_quoted, p, _('in'), spires_search_title)) - elif f == "keyword": - out_links.append("""<a class="google" href="%swww?k=%s">%s %s %s</a>""" % \ - (spires_search_baseurl, p_quoted, p, _('in'), spires_search_title)) - else: # invent a poor man's any field search since SPIRES doesn't support one - out_links.append("""<a class="google" href="%swww?rawcmd=find+t+%s+or+a+%s+or+k+%s+or+s+%s+or+r+%s">%s %s %s</a>""" % \ - (spires_search_baseurl, p_quoted, p_quoted, p_quoted, p_quoted, p_quoted, p, _('in'), spires_search_title)) - # okay, so print the box now: - out = "" - if out_links: - out += """<a name="googlebox"></a>""" - out += prolog_start + _("Haven't found what you were looking for? Try your search on other servers:") + prolog_end - nb_out_links_in_one_column = len(out_links)/2 - out += string.join(out_links[:nb_out_links_in_one_column], link_separator) - out += column_separator - out += string.join(out_links[nb_out_links_in_one_column:], link_separator) - out += epilog - return out - def tmpl_search_pagestart(self, ln) : "page start for search page. Will display after the page header" return """<div class="pagebody"><div class="pagebodystripemiddle">""" def tmpl_search_pageend(self, ln) : "page end for search page. Will display just before the page footer" return """</div></div>""" def tmpl_print_warning(self, msg, type, prologue, epilogue): """Prints warning message and flushes output. Parameters: - 'msg' *string* - The message string - 'type' *string* - the warning type - 'prologue' *string* - HTML code to display before the warning - 'epilogue' *string* - HTML code to display after the warning """ out = '\n%s<span class="quicknote">' % (prologue) if type: out += '%s: ' % type out += '%s</span>%s' % (msg, epilogue) return out def tmpl_print_search_info(self, ln, weburl, middle_only, collection, collection_name, collection_id, as, sf, so, rm, rg, nb_found, of, ot, p, f, f1, f2, f3, m1, m2, m3, op1, op2, p1, p2, p3, d1y, d1m, d1d, d2y, d2m, d2d, all_fieldcodes, cpu_time, pl_in_url, jrec, sc, sp): """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. Parameters: - 'ln' *string* - The language to display - 'weburl' *string* - The base URL for the site - 'middle_only' *bool* - Only display parts of the interface - 'collection' *string* - the collection name - 'collection_name' *string* - the i18nized current collection name - 'as' *bool* - if we display the advanced search interface - 'sf' *string* - the currently selected sort format - 'so' *string* - the currently selected sort order ("a" or "d") - 'rm' *string* - selected ranking method - 'rg' *int* - selected results/page - 'nb_found' *int* - number of results found - 'of' *string* - the selected output format - 'ot' *string* - hidden values - 'p' *string* - Current search words - 'f' *string* - the fields in which the search was done - 'f1, f2, f3, m1, m2, m3, p1, p2, p3, op1, op2' *strings* - the search parameters - 'jrec' *int* - number of first record on this page - 'd1y, d2y, d1m, d2m, d1d, d2d' *int* - the search between dates - 'all_fieldcodes' *array* - all the available fields - 'cpu_time' *float* - the time of the query in seconds """ # load the right message language _ = gettext_set_language(ln) out = "" # left table cells: print collection name if not middle_only: out += ''' %(collection_name)s <form action="%(weburl)s/search" method="get"> <table class="searchresultsbox"><tr><td class="searchresultsboxheader" align="left"> <strong><big>%(collection_link)s</big></strong></td> ''' % { 'collection_name': a_href('', name=collection), 'weburl' : weburl, 'collection_link': a_href(collection_name, href=self.build_search_interface_url(c=collection, as=as, ln=ln)), } else: out += """ <form action="%(weburl)s/search" method="get"><div align="center"> """ % { 'weburl' : weburl } # middle table cell: print beg/next/prev/end arrows: if not middle_only: out += """<td class="searchresultsboxheader" align="center"> %(recs_found)s """ % { 'recs_found' : _("%s records found") % ('<strong>' + self.tmpl_nice_number(nb_found, ln) + '</strong>') } else: out += "<small>" if nb_found > rg: out += "" + collection_name + " : " + _("%s records found") % ('<strong>' + self.tmpl_nice_number(nb_found, ln) + '</strong>') + " " if nb_found > rg: # navig.arrows are needed, since we have many hits query = {'p': p, 'f': f, 'cc': collection, 'sf': sf, 'so': so, 'sp': sp, 'rm': rm, 'of': of, 'ot': ot, 'as': as, 'ln': ln, 'p1': p1, 'p2': p2, 'p3': p3, 'f1': f1, 'f2': f2, 'f3': f3, 'm1': m1, 'm2': m2, 'm3': m3, 'op1': op1, 'op2': op2, 'sc': 0, 'd1y': d1y, 'd1m': d1m, 'd1d': d1d, 'd2y': d2y, 'd2m': d2m, 'd2d': d2d, } # @todo here def img(gif, txt): return '<img src="%(weburl)s/img/%(gif)s.gif" alt="%(txt)s" border="0">' % { 'txt': txt, 'gif': gif, 'weburl': weburl} if jrec-rg > 1: out += a_href(img('sb', _("begin")), _class='img', href=self.build_search_url(query, jrec=1, rg=rg)) if jrec > 1: out += a_href(img('sp', _("previous")), _class='img', href=self.build_search_url(query, jrec=max(jrec-rg, 1), rg=rg)) if jrec+rg-1 < nb_found: out += "%d - %d" % (jrec, jrec+rg-1) else: out += "%d - %d" % (jrec, nb_found) if nb_found >= jrec+rg: out += a_href(img('sn', _("next")), _class='img', href=self.build_search_url(query, jrec=jrec+rg, rg=rg)) if nb_found >= jrec+rg+rg: out += a_href(img('se', _("end")), _class='img', href=self.build_search_url(query, jrec=nb_found-rg+1, rg=rg)) # still in the navigation part cc = collection sc = 0 for var in ['p', 'cc', 'f', 'sf', 'so', 'of', 'rg', 'as', 'ln', 'p1', 'p2', 'p3', 'f1', 'f2', 'f3', 'm1', 'm2', 'm3', 'op1', 'op2', 'sc', 'd1y', 'd1m', 'd1d', 'd2y', 'd2m', 'd2d']: out += self.tmpl_input_hidden(name = var, value = vars()[var]) for var in ['ot', 'sp', 'rm']: if vars()[var]: out += self.tmpl_input_hidden(name = var, value = vars()[var]) if pl_in_url: fieldargs = cgi.parse_qs(pl_in_url) for fieldcode in all_fieldcodes: # get_fieldcodes(): if fieldargs.has_key(fieldcode): for val in fieldargs[fieldcode]: out += self.tmpl_input_hidden(name = fieldcode, value = val) out += """ %(jump)s <input type="text" name="jrec" size="4" value="%(jrec)d">""" % { 'jump' : _("jump to record:"), 'jrec' : jrec, } if not middle_only: out += "</td>" else: out += "</small>" # right table cell: cpu time info if not middle_only: if cpu_time > -1: out += """<td class="searchresultsboxheader" align="right"><small>%(time)s</small> </td>""" % { 'time' : _("Search took %s seconds.") % ('%.2f' % cpu_time), } out += "</tr></table>" else: out += "</div>" out += "</form>" return out def tmpl_nice_number(self, number, ln=cdslang): "Returns nicely printed number NUM in language LN using the locale." if number is None: return None # Temporarily switch the numeric locale to the requeted one, and format the number # In case the system has no locale definition, use the vanilla form ol = locale.getlocale(locale.LC_NUMERIC) try: locale.setlocale(locale.LC_NUMERIC, self.tmpl_localemap.get(ln, self.tmpl_default_locale)) except locale.Error: return str(number) number = locale.format('%d', number, True) locale.setlocale(locale.LC_NUMERIC, ol) return number def tmpl_records_format_htmlbrief(self, ln, weburl, rows, relevances_prologue, relevances_epilogue): """Returns the htmlbrief format of the records Parameters: - 'ln' *string* - The language to display - 'weburl' *string* - The base URL for the site - 'rows' *array* - Parts of the interface to display, in the format: - 'rows[number]' *int* - The order number - 'rows[recid]' *int* - The recID - 'rows[relevance]' *string* - The relevance of the record - 'rows[record]' *string* - The formatted record - 'relevances_prologue' *string* - HTML code to prepend the relevance indicator - 'relevances_epilogue' *string* - HTML code to append to the relevance indicator (used mostly for formatting) """ # load the right message language _ = gettext_set_language(ln) out = """ <form action="%(weburl)s/yourbaskets/add" method="post"> <table> """ % { 'weburl' : weburl, } for row in rows: out += """ <tr><td valign="top" align="right" nowrap><input name="recid" type="checkbox" value="%(recid)s"> %(number)s. """ % row if row['relevance']: out += """<br><div class="rankscoreinfo"><a title="rank score">%(prologue)s%(relevance)s%(epilogue)s</a></div>""" % { 'prologue' : relevances_prologue, 'epilogue' : relevances_epilogue, 'relevance' : row['relevance'] } out += """</td><td valign="top">%s</td></tr>""" % row['record'] out += """</table> <br><input class="formbutton" type="submit" name="action" value="%(basket)s"> </form>""" % { 'basket' : _("ADD TO BASKET") } return out def tmpl_records_format_other(self, ln, weburl, rows, format, url_argd): """Returns other formats of the records Parameters: - 'ln' *string* - The language to display - 'weburl' *string* - The base URL for the site - 'rows' *array* - Parts of the interface to display, in the format: - 'rows[record]' *string* - The formatted record - 'rows[number]' *int* - The order number - 'rows[recid]' *int* - The recID - 'rows[relevance]' *string* - The relevance of the record - 'format' *string* - The current format - 'url_argd' *string* - Parameters of the search query """ # load the right message language _ = gettext_set_language(ln) out = """ <p><div align="right"><small>%(format)s """ % { 'format' : _("Format:") } result = [] for abbrev, name in (('hd', 'HTML'), ('hx', 'BibTeX'), ('xd', 'DC'), ('hm', 'MARC'), ('xm', 'MARCXML')): if format == abbrev: result.append(name) else: result.append(a_href(name, href=self.build_search_url(url_argd, of=abbrev))) out += " | ".join(result) out += "</small></div>" for row in rows: out += row ['record'] if format.startswith("hd"): # do not print further information but for HTML detailed formats if row ['creationdate']: out += '''<div class="recordlastmodifiedbox">%(dates)s</div> <p><span class="moreinfo">%(similar)s</span> <form action="%(weburl)s/yourbaskets/add" method="post"> <input name="recid" type="hidden" value="%(recid)s"> <input name="ln" type="hidden" value="%(ln)s"> <br> <input class="formbutton" type="submit" name="action" value="%(basket)s"> </form> ''' % { 'dates': _("Record created %(x_date_creation)s, last modified %(x_date_modification)s") % {'x_date_creation': row['creationdate'], 'x_date_modification': row['modifydate']}, 'weburl': weburl, 'recid': row['recid'], 'ln': ln, 'similar': a_href(_("Similar records"), _class="moreinfo", href=self.build_search_url(p='recid:%d' % row['recid'], rm='wrd', ln=ln)), 'basket' : _("ADD TO BASKET") } out += '<table>' if row.has_key ('citinglist'): cs = row ['citinglist'] similar = self.tmpl_print_record_list_for_similarity_boxen( _("Cited by: %s records") % len (cs), cs, ln) out += ''' <tr><td> %(similar)s %(more)s <br><br> </td></tr>''' % { 'more': a_href(_("more"), href=self.build_search_url(p='recid:%d' % row['recid'], rm='cit', ln=ln)), 'similar': similar} if row.has_key ('cociting'): cs = row ['cociting'] similar = self.tmpl_print_record_list_for_similarity_boxen ( _("Co-cited with: %s records") % len (cs), cs, ln) out += ''' <tr><td> %(similar)s %(more)s <br> </td></tr>''' % { 'more': a_href(_("more"), href=self.build_search_url(p='cocitedwith:%d' % row['recid'], ln=ln)), 'similar': similar} if row.has_key ('citationhistory'): out += '<tr><td>%s</td></tr>' % row ['citationhistory'] if row.has_key ('downloadsimilarity'): cs = row ['downloadsimilarity'] similar = self.tmpl_print_record_list_for_similarity_boxen ( _("People who downloaded this document also downloaded:"), cs, ln) out += ''' <tr><td>%(graph)s</td></tr> <tr><td>%(similar)s</td></tr >''' % { 'weburl': weburl, 'recid': row ['recid'], 'ln': ln, 'similar': similar, 'more': _("more"), 'graph': row ['downloadhistory'] } out += '</table>' if row.has_key ('viewsimilarity'): out += '<p> ' out += self.tmpl_print_record_list_for_similarity_boxen ( _("People who viewed this page also viewed:"), row ['viewsimilarity'], ln) if row.has_key ('reviews'): out += '<p> ' out += row['reviews'] if row.has_key ('comments'): out += row['comments'] out += "<p> " return out def tmpl_print_results_overview(self, ln, weburl, results_final_nb_total, cpu_time, results_final_nb, colls): """Prints results overview box with links to particular collections below. Parameters: - 'ln' *string* - The language to display - 'weburl' *string* - The base URL for the site - 'results_final_nb_total' *int* - The total number of hits for the query - 'colls' *array* - The collections with hits, in the format: - 'coll[code]' *string* - The code of the collection (canonical name) - 'coll[name]' *string* - The display name of the collection - 'results_final_nb' *array* - The number of hits, indexed by the collection codes: - 'cpu_time' *string* - The time the query took - 'url_args' *string* - The rest of the search query """ if len(colls) == 1: # if one collection only, print nothing: return "" # load the right message language _ = gettext_set_language(ln) # first find total number of hits: out = """<p><table class="searchresultsbox"> <thead><tr><th class="searchresultsboxheader">%(founds)s</th></tr></thead> <tbody><tr><td class="searchresultsboxbody"> """ % { 'founds' : _("%(x_fmt_open)sResults overview:%(x_fmt_close)s Found %(x_nb_records)s records in %(x_nb_seconds)s seconds.") %\ {'x_fmt_open': '<strong>', 'x_fmt_close': '</strong>', 'x_nb_records': '<strong>' + self.tmpl_nice_number(results_final_nb_total, ln) + '</strong>', 'x_nb_seconds': '%.2f' % cpu_time} } # then print hits per collection: for coll in colls: if results_final_nb.has_key(coll['code']) and results_final_nb[coll['code']] > 0: out += '''<strong><a href="#%(coll)s">%(coll_name)s</a></strong>, <a href="#%(coll)s">%(number)s</a><br>''' % { 'coll' : urllib.quote(coll['code']), 'coll_name' : coll['name'], 'number' : _("%s records found") % ('<strong>' + self.tmpl_nice_number(results_final_nb[coll['code']], ln) + '</strong>') } out += "</td></tr></tbody></table>" return out def tmpl_search_no_boolean_hits(self, ln, nearestterms): """No hits found, proposes alternative boolean queries Parameters: - 'ln' *string* - The language to display - 'weburl' *string* - The base URL for the site - 'nearestterms' *array* - Parts of the interface to display, in the format: - 'nearestterms[nbhits]' *int* - The resulting number of hits - 'nearestterms[url_args]' *string* - The search parameters - 'nearestterms[p]' *string* - The search terms """ # load the right message language _ = gettext_set_language(ln) out = _("Boolean query returned no hits. Please combine your search terms differently.") out += '''<blockquote><table class="nearesttermsbox" cellpadding="0" cellspacing="0" border="0">''' for term, hits, argd in nearestterms: out += '''\ <tr> <td class="nearesttermsboxbody" align="right">%(hits)s</td> <td class="nearesttermsboxbody" width="15"> </td> <td class="nearesttermsboxbody" align="left"> %(link)s </td> </tr>''' % {'hits' : hits, 'link': a_href(cgi.escape(term), _class="nearestterms", href=self.build_search_url(argd))} out += """</table></blockquote>""" return out def tmpl_similar_author_names(self, authors, ln): """No hits found, proposes alternative boolean queries Parameters: - 'authors': a list of (name, hits) tuples - 'ln' *string* - The language to display """ # load the right message language _ = gettext_set_language(ln) out = '''<a name="googlebox"></a> <table class="googlebox"><tr><th colspan="2" class="googleboxheader">%(similar)s</th></tr>''' % { 'similar' : _("See also: similar author names") } for author, hits in authors: out += '''\ <tr> <td class="googleboxbody">%(nb)d</td> <td class="googleboxbody">%(link)s</td> </tr>''' % {'link': a_href(cgi.escape(author), _class="google", href=self.build_search_url(p=author, f='author', ln=ln)), 'nb' : hits} out += """</table>""" return out def tmpl_print_record_detailed(self, recID, ln, weburl): """Displays a detailed on-the-fly record Parameters: - 'ln' *string* - The language to display - 'weburl' *string* - The base URL for the site - 'recID' *int* - The record id """ # okay, need to construct a simple "Detailed record" format of our own: out = "<p> " # secondly, title: titles = get_fieldvalues(recID, "245__a") for title in titles: out += "<p><p><center><big><strong>%s</strong></big></center>" % title # thirdly, authors: authors = get_fieldvalues(recID, "100__a") + get_fieldvalues(recID, "700__a") if authors: out += "<p><p><center>" for author in authors: out += '%s; ' % a_href(cgi.escape(author), href=self.build_search_url(ln=ln, p=author, f='author')) out += "</center>" # fourthly, date of creation: dates = get_fieldvalues(recID, "260__c") for date in dates: out += "<p><center><small>%s</small></center>" % date # fifthly, abstract: abstracts = get_fieldvalues(recID, "520__a") for abstract in abstracts: out += """<p style="margin-left: 15%%; width: 70%%"> <small><strong>Abstract:</strong> %s</small></p>""" % abstract # fifthly bis, keywords: keywords = get_fieldvalues(recID, "6531_a") if len(keywords): out += """<p style="margin-left: 15%%; width: 70%%"> <small><strong>Keyword(s):</strong>""" for keyword in keywords: out += '%s; ' % a_href(cgi.escape(keyword), href=self.build_search_url(ln=ln, p=keyword, f='keyword')) out += '</small>' # fifthly bis bis, published in: prs_p = get_fieldvalues(recID, "909C4p") prs_v = get_fieldvalues(recID, "909C4v") prs_y = get_fieldvalues(recID, "909C4y") prs_n = get_fieldvalues(recID, "909C4n") prs_c = get_fieldvalues(recID, "909C4c") for idx in range(0,len(prs_p)): out += """<p style="margin-left: 15%%; width: 70%%"> <small><strong>Publ. in:</strong> %s""" % prs_p[idx] if prs_v and prs_v[idx]: out += """<strong>%s</strong>""" % prs_v[idx] if prs_y and prs_y[idx]: out += """(%s)""" % prs_y[idx] if prs_n and prs_n[idx]: out += """, no.%s""" % prs_n[idx] if prs_c and prs_c[idx]: out += """, p.%s""" % prs_c[idx] out += """.</small>""" # sixthly, fulltext link: urls_z = get_fieldvalues(recID, "8564_z") urls_u = get_fieldvalues(recID, "8564_u") for idx in range(0,len(urls_u)): link_text = "URL" try: if urls_z[idx]: link_text = urls_z[idx] except IndexError: pass out += """<p style="margin-left: 15%%; width: 70%%"> <small><strong>%s:</strong> <a href="%s">%s</a></small>""" % (link_text, urls_u[idx], urls_u[idx]) # print some white space at the end: out += "<p><p>" return out def tmpl_print_record_list_for_similarity_boxen(self, title, recID_score_list, ln=cdslang): """Print list of records in the "hs" (HTML Similarity) format for similarity boxes. RECID_SCORE_LIST is a list of (recID1, score1), (recID2, score2), etc. """ from invenio.search_engine import print_record, record_public_p recID_score_list_to_be_printed = [] # firstly find 5 first public records to print: nb_records_to_be_printed = 0 nb_records_seen = 0 while nb_records_to_be_printed < 5 and nb_records_seen < len(recID_score_list) and nb_records_seen < 50: # looking through first 50 records only, picking first 5 public ones (recID, score) = recID_score_list[nb_records_seen] nb_records_seen += 1 if record_public_p(recID): nb_records_to_be_printed += 1 recID_score_list_to_be_printed.append([recID,score]) # secondly print them: out = ''' <table><tr><td> <table><tr><td class="blocknote">%(title)s</td></tr></table> </td> <tr><td><table> ''' % { 'title': title } for recid, score in recID_score_list_to_be_printed: out += ''' <tr><td><font class="rankscoreinfo"><a>(%(score)s) </a></font><small> %(info)s</small></td></tr>''' % { 'score': score, 'info' : print_record(recid, format="hs", ln=ln), } out += """</table></small></td></tr></table> """ return out def tmpl_print_record_brief(self, ln, recID, weburl): """Displays a brief record on-the-fly Parameters: - 'ln' *string* - The language to display - 'weburl' *string* - The base URL for the site - 'recID' *int* - The record id """ out = "" # record 'recID' does not exist in format 'format', so print some default format: # firstly, title: titles = get_fieldvalues(recID, "245__a") # secondly, authors: authors = get_fieldvalues(recID, "100__a") + get_fieldvalues(recID, "700__a") # thirdly, date of creation: dates = get_fieldvalues(recID, "260__c") # thirdly bis, report numbers: rns = get_fieldvalues(recID, "037__a") rns = get_fieldvalues(recID, "088__a") # fourthly, beginning of abstract: abstracts = get_fieldvalues(recID, "520__a") # fifthly, fulltext link: urls_z = get_fieldvalues(recID, "8564_z") urls_u = get_fieldvalues(recID, "8564_u") return self.tmpl_record_body( weburl = weburl, titles = titles, authors = authors, dates = dates, rns = rns, abstracts = abstracts, urls_u = urls_u, urls_z = urls_z, ln=ln) def tmpl_print_record_brief_links(self, ln, recID, weburl): """Displays links for brief record on-the-fly Parameters: - 'ln' *string* - The language to display - 'weburl' *string* - The base URL for the site - 'recID' *int* - The record id """ # load the right message language _ = gettext_set_language(ln) out = "" if cfg_use_aleph_sysnos: alephsysnos = get_fieldvalues(recID, "970__a") if len(alephsysnos)>0: alephsysno = alephsysnos[0] out += '<br><span class="moreinfo">%s</span>' % \ a_href(_("Detailed record"), _class="moreinfo", href=self.build_search_url(sysno=alephsysno, ln=ln)) else: out += '<br><span class="moreinfo">%s</span>' % \ a_href(_("Detailed record"), _class="moreinfo", href=self.build_search_url(recid=recID, ln=ln)) else: out += '<br><span class="moreinfo">%s</span>' % \ a_href(_("Detailed record"), _class="moreinfo", href=self.build_search_url(recid=recID, ln=ln)) out += '<span class="moreinfo"> - %s</span>' % \ a_href(_("Similar records"), _class="moreinfo", href=self.build_search_url(p="recid:%d" % recID, rm="wrd", ln=ln)) if cfg_experimental_features: out += '<span class="moreinfo"> - %s</span>' % \ a_href(_("Cited by"), _class="moreinfo", href=self.build_search_url(p="recid:%d" % recID, rm="cit", ln=ln)) return out diff --git a/modules/websearch/lib/websearchadminlib.py b/modules/websearch/lib/websearchadminlib.py index 261379b3e..d3a2b1a19 100644 --- a/modules/websearch/lib/websearchadminlib.py +++ b/modules/websearch/lib/websearchadminlib.py @@ -1,3173 +1,3217 @@ ## $Id$ ## Administrator interface for WebSearch ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006 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 WebSearch Administrator Interface.""" import cgi import re import Numeric import os import urllib import random import marshal import time from zlib import compress,decompress from mod_python import apache from invenio.bibrankadminlib import write_outcome,modify_translations,get_def_name,get_i8n_name,get_name,get_rnk_nametypes,get_languages,check_user,is_adminuser,adderrorbox,addadminbox,tupletotable,tupletotable_onlyselected,addcheckboxes,createhiddenform,serialize_via_numeric_array_dumps,serialize_via_numeric_array_compr,serialize_via_numeric_array_escape,serialize_via_numeric_array,deserialize_via_numeric_array,serialize_via_marshal,deserialize_via_marshal from invenio.dbquery import run_sql, escape_string from invenio.config import * from invenio.webpage import page, pageheaderonly, pagefooteronly from invenio.webuser import getUid, get_email +from invenio.websearch_external_collections import external_collections_dictionary, external_collection_load_db_infos, external_collection_set_default_type, external_collection_is_default, external_collection_disable, external_collection_enable_seealso, external_collection_enable, external_collection_is_enabled, external_collection_is_seealso_enabled, sort_engine_by_name + __version__ = "$Id$" def getnavtrail(previous = ''): """Get the navtrail""" navtrail = """<a class=navtrail href="%s/admin/">Admin Area</a> > <a class=navtrail href="%s/admin/websearch/">WebSearch Admin</a> """ % (weburl, weburl) navtrail = navtrail + previous return navtrail def perform_modifytranslations(colID, ln, sel_type='', trans=[], confirm=-1, callback='yes'): """Modify the translations of a collection sel_type - the nametype to modify trans - the translations in the same order as the languages from get_languages()""" output = '' subtitle = '' cdslangs = get_languages() if confirm in ["2", 2] and colID: finresult = modify_translations(colID, cdslangs, sel_type, trans, "collection") col_dict = dict(get_def_name('', "collection")) if colID and col_dict.has_key(int(colID)): colID = int(colID) subtitle = """<a name="3">3. Modify translations for collection '%s'</a>   <small>[<a href="%s/admin/websearch/guide.html#3.3">?</a>]</small>""" % (col_dict[colID], weburl) if type(trans) is str: trans = [trans] if sel_type == '': sel_type = get_col_nametypes()[0][0] header = ['Language', 'Translation'] actions = [] types = get_col_nametypes() if len(types) > 1: text = """ <span class="adminlabel">Name type</span> <select name="sel_type" class="admin_w200"> """ for (key, value) in types: text += """<option value="%s" %s>%s""" % (key, key == sel_type and 'selected="selected"' or '', value) trans_names = get_name(colID, ln, key, "collection") if trans_names and trans_names[0][0]: text += ": %s" % trans_names[0][0] text += "</option>" text += """</select>""" output += createhiddenform(action="modifytranslations#3", text=text, button="Select", colID=colID, ln=ln, confirm=0) if confirm in [-1, "-1", 0, "0"]: trans = [] for (key, value) in cdslangs: try: trans_names = get_name(colID, key, sel_type, "collection") 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 '<small>(def)</small>' or ''))]) actions[-1].append('<input type="text" name="trans" size="30" value="%s"/>' % trans[nr]) text = tupletotable(header=header, tuple=actions) output += createhiddenform(action="modifytranslations#3", text=text, button="Modify", colID=colID, sel_type=sel_type, ln=ln, confirm=2) if sel_type and len(trans) and confirm in ["2", 2]: output += write_outcome(finresult) try: body = [output, extra] except NameError: body = [output] if callback: return perform_editcollection(colID, ln, "perform_modifytranslations", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_modifyrankmethods(colID, ln, func='', rnkID='', confirm=0, callback='yes'): """Modify which rank methods is visible to the collection func - remove or add rank method rnkID - the id of the rank method.""" output = "" subtitle = "" col_dict = dict(get_def_name('', "collection")) rnk_dict = dict(get_def_name('', "rnkMETHOD")) if colID and col_dict.has_key(int(colID)): colID = int(colID) if func in ["0", 0] and confirm in ["1", 1]: finresult = attach_rnk_col(colID, rnkID) elif func in ["1", 1] and confirm in ["1", 1]: finresult = detach_rnk_col(colID, rnkID) subtitle = """<a name="9">9. Modify rank options for collection '%s'</a>   <small>[<a title="See guide" href="%s/admin/websearch/guide.html#3.9">?</a>]</small>""" % (col_dict[colID], weburl) output = """ <dl> <dt>The rank methods enabled for the collection '%s' is:</dt> """ % col_dict[colID] rnkmethods = get_col_rnk(colID, ln) output += """<dd>""" if not rnkmethods: output += """No rank methods""" else: for id, name in rnkmethods: output += """%s, """ % name output += """</dd> </dl> """ rnk_list = get_def_name('', "rnkMETHOD") rnk_dict_in_col = dict(get_col_rnk(colID, ln)) rnk_list = filter(lambda x: not rnk_dict_in_col.has_key(x[0]), rnk_list) if rnk_list: text = """ <span class="adminlabel">Enable:</span> <select name="rnkID" class="admin_w200"> <option value="-1">- select rank method -</option> """ for (id, name) in rnk_list: text += """<option value="%s" %s>%s</option>""" % (id, (func in ["0", 0] and confirm in ["0", 0] and int(rnkID) == int(id)) and 'selected="selected"' or '' , name) text += """</select>""" output += createhiddenform(action="modifyrankmethods#9", text=text, button="Enable", colID=colID, ln=ln, func=0, confirm=1) if confirm in ["1", 1] and func in ["0", 0] and int(rnkID) != -1: output += write_outcome(finresult) elif confirm not in ["0", 0] and func in ["0", 0]: output += """<b><span class="info">Please select a rank method.</span></b>""" coll_list = get_col_rnk(colID, ln) if coll_list: text = """ <span class="adminlabel">Disable:</span> <select name="rnkID" class="admin_w200"> <option value="-1">- select rank method-</option> """ for (id, name) in coll_list: text += """<option value="%s" %s>%s</option>""" % (id, (func in ["1", 1] and confirm in ["0", 0] and int(rnkID) == int(id)) and 'selected="selected"' or '' , name) text += """</select>""" output += createhiddenform(action="modifyrankmethods#9", text=text, button="Disable", colID=colID, ln=ln, func=1, confirm=1) if confirm in ["1", 1] and func in ["1", 1] and int(rnkID) != -1: output += write_outcome(finresult) elif confirm not in ["0", 0] and func in ["1", 1]: output += """<b><span class="info">Please select a rank method.</span></b>""" try: body = [output, extra] except NameError: body = [output] if callback: return perform_editcollection(colID, ln, "perform_modifyrankmethods", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_addcollectiontotree(colID, ln, add_dad='', add_son='', rtype='', mtype='', callback='yes', confirm=-1): """Form to add a collection to the tree. add_dad - the dad to add the collection to add_son - the collection to add rtype - add it as a regular or virtual mtype - add it to the regular or virtual tree.""" output = "" output2 = "" subtitle = """Attach collection to tree   <small>[<a title="See guide" href="%s/admin/websearch/guide.html#2.2">?</a>]</small>""" % (weburl) col_dict = dict(get_def_name('', "collection")) if confirm not in [-1, "-1"] and not (add_son and add_dad and rtype): output2 += """<b><span class="info">All fields must be filled.</span></b><br><br> """ elif add_son and add_dad and rtype: add_son = int(add_son) add_dad = int(add_dad) if confirm not in [-1, "-1"]: if add_son == add_dad: output2 += """<b><span class="info">Cannot add a collection as a pointer to itself.</span></b><br><br> """ elif check_col(add_dad, add_son): res = add_col_dad_son(add_dad, add_son, rtype) output2 += write_outcome(res) if res[0] == 1: output2 += """<b><span class="info"><br> The collection will appear on your website after the next webcoll run. You can either run it manually or wait until bibsched does it for you.</span></b><br><br> """ else: output2 += """<b><span class="info">Cannot add the collection '%s' as a %s subcollection of '%s' since it will either create a loop, or the association already exists.</span></b><br><br> """ % (col_dict[add_son], (rtype=="r" and 'regular' or 'virtual'), col_dict[add_dad]) add_son = '' add_dad = '' rtype = '' tree = get_col_tree(colID) col_list = col_dict.items() col_list.sort(compare_on_val) output = show_coll_not_in_tree(colID, ln, col_dict) text = """ <span class="adminlabel">Attach which</span> <select name="add_son" class="admin_w200"> <option value="">- select collection -</option> """ for (id, name) in col_list: if id != colID: text += """<option value="%s" %s>%s</option>""" % (id, str(id)==str(add_son) and 'selected="selected"' or '', name) text += """ </select><br> <span class="adminlabel">Attach to</span> <select name="add_dad" class="admin_w200"> <option value="">- select parent collection -</option> """ for (id, name) in col_list: text += """<option value="%s" %s>%s</option> """ % (id, str(id)==add_dad and 'selected="selected"' or '', name) text += """</select><br> """ text += """ <span class="adminlabel">Relationship</span> <select name="rtype" class="admin_w200"> <option value="">- select relationship -</option> <option value="r" %s>Regular (Narrow by...)</option> <option value="v" %s>Virtual (Focus on...)</option> </select> """ % ((rtype=="r" and 'selected="selected"' or ''), (rtype=="v" and 'selected="selected"' or '')) output += createhiddenform(action="%s/admin/websearch/websearchadmin.py/addcollectiontotree" % weburl, text=text, button="Add", colID=colID, ln=ln, confirm=1) output += output2 #output += perform_showtree(colID, ln) try: body = [output, extra] except NameError: body = [output] if callback: return perform_index(colID, ln, mtype="perform_addcollectiontotree", content=addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_addcollection(colID, ln, colNAME='', dbquery='', rest='', callback="yes", confirm=-1): """form to add a new collection. colNAME - the name of the new collection dbquery - the dbquery of the new collection rest - the group allowed to access the new collection""" output = "" subtitle = """Create new collection <small>[<a title="See guide" href="%s/admin/websearch/guide.html#2.1">?</a>]</small>""" % (weburl) text = """ <span class="adminlabel">Default name</span> <input class="admin_w200" type="text" name="colNAME" value="%s" /><br> """ % colNAME output = createhiddenform(action="%s/admin/websearch/websearchadmin.py/addcollection" % weburl, text=text, colID=colID, ln=ln, button="Add collection", confirm=1) if colNAME and confirm in ["1", 1]: res = add_col(colNAME, '', '') output += write_outcome(res) if res[0] == 1: output += perform_addcollectiontotree(colID=colID, ln=ln, add_son=res[1], callback='') elif confirm not in ["-1", -1]: output += """<b><span class="info">Please give the collection a name.</span></b>""" try: body = [output, extra] except NameError: body = [output] if callback: return perform_index(colID, ln=ln, mtype="perform_addcollection", content=addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_modifydbquery(colID, ln, dbquery='', callback='yes', confirm=-1): """form to modify the dbquery of the collection. dbquery - the dbquery of the collection.""" subtitle = '' output = "" col_dict = dict(get_def_name('', "collection")) if colID and col_dict.has_key(int(colID)): colID = int(colID) subtitle = """<a name="1">1. Modify collection query for collection '%s'</a>   <small>[<a title="See guide" href="%s/admin/websearch/guide.html#3.1">?</a>]</small>""" % (col_dict[colID], weburl) if confirm == -1: res = run_sql("SELECT dbquery FROM collection WHERE id=%s" % colID) dbquery = res[0][0] if not dbquery: dbquery = '' reg_sons = len(get_col_tree(colID, 'r')) vir_sons = len(get_col_tree(colID, 'v')) if reg_sons > 1: if dbquery: output += "Warning: This collection got subcollections, and should because of this not have a collection query, for further explanation, check the WebSearch Guide<br>" elif reg_sons <= 1: if not dbquery: output += "Warning: This collection does not have any subcollections, and should because of this have a collection query, for further explanation, check the WebSearch Guide<br>" text = """ <span class="adminlabel">Query</span> <input class="admin_w200" type="text" name="dbquery" value="%s" /><br> """ % dbquery output += createhiddenform(action="modifydbquery", text=text, button="Modify", colID=colID, ln=ln, confirm=1) if confirm in ["1", 1]: res = modify_dbquery(colID, dbquery) if res: if dbquery == "": text = """<b><span class="info">Query removed for this collection.</span></b>""" else: text = """<b><span class="info">Query set for this collection.</span></b>""" else: text = """<b><span class="info">Sorry, could not change query.</span></b>""" output += text try: body = [output, extra] except NameError: body = [output] if callback: return perform_editcollection(colID, ln, "perform_modifydbquery", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_modifyrestricted(colID, ln, rest='', callback='yes', confirm=-1): """modify which apache group is allowed to access the collection. rest - the groupname""" subtitle = '' output = "" col_dict = dict(get_def_name('', "collection")) if colID and col_dict.has_key(int(colID)): colID = int(colID) subtitle = """<a name="2">2. Modify access restrictions for collection '%s'</a>   <small>[<a title="See guide" href="%s/admin/websearch/guide.html#3.2">?</a>]</small>""" % (col_dict[colID], weburl) if confirm == -1: res = run_sql("SELECT restricted FROM collection WHERE id=%s" % colID) rest = res[0][0] if not rest: rest = '' text = """ <span class="adminlabel">Restricted to:</span> <input class="admin_w200" type="text" name="rest" value="%s" /><br> """ % rest output += createhiddenform(action="modifyrestricted", text=text, button="Modify", colID=colID, ln=ln, confirm=1) if confirm in ["1", 1]: res = modify_restricted(colID, rest) if res: if rest == "": text = """<b><span class="info">Removed restriction for this collection.</span></b>""" else: text = """<b><span class="info">Restriction set for this collection.</span></b>""" else: text = """<b><span class="info">Sorry, could not change the access restrictions.</span></b>""" output += text try: body = [output, extra] except NameError: body = [output] if callback: return perform_editcollection(colID, ln, "perform_modifyrestricted", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_modifycollectiontree(colID, ln, move_up='', move_down='', move_from='', move_to='', delete='', rtype='', callback='yes', confirm=0): """to modify the collection tree: move a collection up and down, delete a collection, or change the father of the collection. colID - the main collection of the tree, the root move_up - move this collection up (is not the collection id, but the place in the tree) move_up - move this collection down (is not the collection id, but the place in the tree) move_from - move this collection from the current positon (is not the collection id, but the place in the tree) move_to - move the move_from collection and set this as it's father. (is not the collection id, but the place in the tree) delete - delete this collection from the tree (is not the collection id, but the place in the tree) rtype - the type of the collection in the tree, regular or virtual""" colID = int(colID) tree = get_col_tree(colID, rtype) col_dict = dict(get_def_name('', "collection")) subtitle = """Modify collection tree: %s <small>[<a title="See guide" href="%s/admin/websearch/guide.html#2.3">?</a>] <a href="%s/admin/websearch/websearchadmin.py/showtree?colID=%s&ln=%s">Printer friendly version</a></small>""" % (col_dict[colID], weburl, weburl, colID, ln) fin_output = "" output = "" try: if move_up: move_up = int(move_up) switch = find_last(tree, move_up) if switch and switch_col_treescore(tree[move_up], tree[switch]): output += """<b><span class="info">Moved the %s collection '%s' up and '%s' down.</span></b><br><br> """ % ((rtype=="r" and 'regular' or 'virtual'), col_dict[tree[move_up][0]], col_dict[tree[switch][0]]) else: output += """<b><span class="info">Could not move the %s collection '%s' up and '%s' down.</span></b><br><br> """ % ((rtype=="r" and 'regular' or 'virtual'), col_dict[tree[move_up][0]], col_dict[tree[switch][0]]) elif move_down: move_down = int(move_down) switch = find_next(tree, move_down) if switch and switch_col_treescore(tree[move_down], tree[switch]): output += """<b><span class="info">Moved the %s collection '%s' down and '%s' up.</span></b><br><br> """ % ((rtype=="r" and 'regular' or 'virtual'), col_dict[tree[move_down][0]], col_dict[tree[switch][0]]) else: output += """<b><span class="info">Could not move the %s collection '%s' up and '%s' down.</span></b><br><br> """ % ((rtype=="r" and 'regular' or 'virtual'), col_dict[tree[move_up][0]],col_dict[tree[switch][0]]) elif delete: delete = int(delete) if confirm in [0, "0"]: if col_dict[tree[delete][0]] != col_dict[tree[delete][3]]: text = """<b>Do you want to remove the %s collection '%s' and its subcollections in the %s collection '%s'.</b> """ % ((tree[delete][4]=="r" and 'regular' or 'virtual'), col_dict[tree[delete][0]], (rtype=="r" and 'regular' or 'virtual'), col_dict[tree[delete][3]]) else: text = """<b>Do you want to remove all subcollections of the %s collection '%s'.</b> """ % ((rtype=="r" and 'regular' or 'virtual'), col_dict[tree[delete][3]]) output += createhiddenform(action="%s/admin/websearch/websearchadmin.py/modifycollectiontree#tree" % weburl, text=text, button="Confirm", colID=colID, delete=delete, rtype=rtype, ln=ln, confirm=1) output += createhiddenform(action="%s/admin/websearch/websearchadmin.py/index?mtype=perform_modifycollectiontree#tree" % weburl, text="<b>To cancel</b>", button="Cancel", colID=colID, ln=ln) else: if remove_col_subcol(tree[delete][0], tree[delete][3], rtype): if col_dict[tree[delete][0]] != col_dict[tree[delete][3]]: output += """<b><span class="info">Removed the %s collection '%s' and its subcollections in subdirectory '%s'.</span></b><br><br> """ % ((tree[delete][4]=="r" and 'regular' or 'virtual'), col_dict[tree[delete][0]], col_dict[tree[delete][3]]) else: output += """<b><span class="info">Removed the subcollections of the %s collection '%s'.</span></b><br><br> """ % ((rtype=="r" and 'regular' or 'virtual'), col_dict[tree[delete][3]]) else: output += """<b><span class="info">Could not remove the collection from the tree.</span></b><br><br> """ delete = '' elif move_from and not move_to: move_from_rtype = move_from[0] move_from_id = int(move_from[1:len(move_from)]) text = """<b>Select collection to place the %s collection '%s' under.</b><br><br> """ % ((move_from_rtype=="r" and 'regular' or 'virtual'), col_dict[tree[move_from_id][0]]) output += createhiddenform(action="%s/admin/websearch/websearchadmin.py/index?mtype=perform_modifycollectiontree#tree" % weburl, text=text, button="Cancel", colID=colID, ln=ln) elif move_from and move_to: move_from_rtype = move_from[0] move_from_id = int(move_from[1:len(move_from)]) move_to_rtype = move_to[0] move_to_id = int(move_to[1:len(move_to)]) tree_from = get_col_tree(colID, move_from_rtype) tree_to = get_col_tree(colID, move_to_rtype) if confirm in [0, '0']: if move_from_id == move_to_id and move_from_rtype==move_to_rtype: output += """<b><span class="info">Cannot move to itself.</span></b><br><br> """ elif tree_from[move_from_id][3] == tree_to[move_to_id][0] and move_from_rtype==move_to_rtype: output += """<b><span class="info">The collection is already there.</span></b><br><br> """ elif check_col(tree_to[move_to_id][0], tree_from[move_from_id][0]) or (tree_to[move_to_id][0] == 1 and tree_from[move_from_id][3] == tree_to[move_to_id][0] and move_from_rtype != move_to_rtype): text = """<b>Move %s collection '%s' to the %s collection '%s'.</b> """ % ((tree_from[move_from_id][4]=="r" and 'regular' or 'virtual'), col_dict[tree_from[move_from_id][0]], (tree_to[move_to_id][4]=="r" and 'regular' or 'virtual'), col_dict[tree_to[move_to_id][0]]) output += createhiddenform(action="%s/admin/websearch/websearchadmin.py/modifycollectiontree#tree" % weburl, text=text, button="Confirm", colID=colID, move_from=move_from, move_to=move_to, ln=ln, rtype=rtype, confirm=1) output += createhiddenform(action="%s/admin/websearch/websearchadmin.py/index?mtype=perform_modifycollectiontree#tree" % weburl, text="""<b>To cancel</b>""", button="Cancel", colID=colID, ln=ln) else: output += """<b><span class="info">Cannot move the collection '%s' and set it as a subcollection of '%s' since it will create a loop.</span></b><br><br> """ % (col_dict[tree_from[move_from_id][0]], col_dict[tree_to[move_to_id][0]]) else: if (move_to_id != 0 and move_col_tree(tree_from[move_from_id], tree_to[move_to_id])) or (move_to_id == 0 and move_col_tree(tree_from[move_from_id], tree_to[move_to_id], move_to_rtype)): output += """<b><span class="info">Moved %s collection '%s' to the %s collection '%s'.</span></b><br><br> """ % ((move_from_rtype=="r" and 'regular' or 'virtual'), col_dict[tree_from[move_from_id][0]], (move_to_rtype=="r" and 'regular' or 'virtual'), col_dict[tree_to[move_to_id][0]]) else: output += """<b><span class="info">Could not move %s collection '%s' to the %s collection '%s'.</span></b><br><br> """ % ((move_from_rtype=="r" and 'regular' or 'virtual'), col_dict[tree_from[move_from_id][0]], (move_to_rtype=="r" and 'regular' or 'virtual'), col_dict[tree_to[move_to_id][0]]) move_from = '' move_to = '' else: output += """ """ except StandardError, e: return """<b><span class="info">An error occured.</span></b> """ output += """<table border ="0" width="100%"> <tr><td width="50%"> <b>Narrow by collection:</b> </td><td width="50%"> <b>Focus on...:</b> </td></tr><tr><td valign="top"> """ tree = get_col_tree(colID, 'r') output += create_colltree(tree, col_dict, colID, ln, move_from, move_to, 'r', "yes") output += """</td><td valign="top"> """ tree = get_col_tree(colID, 'v') output += create_colltree(tree, col_dict, colID, ln, move_from, move_to, 'v', "yes") output += """</td> </tr> </table> """ try: body = [output, extra] except NameError: body = [output] if callback: return perform_index(colID, ln, mtype="perform_modifycollectiontree", content=addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_showtree(colID, ln): """create collection tree/hiarchy""" col_dict = dict(get_def_name('', "collection")) subtitle = "Collection tree: %s" % col_dict[int(colID)] output = """<table border ="0" width="100%"> <tr><td width="50%"> <b>Narrow by collection:</b> </td><td width="50%"> <b>Focus on...:</b> </td></tr><tr><td valign="top"> """ tree = get_col_tree(colID, 'r') output += create_colltree(tree, col_dict, colID, ln, '', '', 'r', '') output += """</td><td valign="top"> """ tree = get_col_tree(colID, 'v') output += create_colltree(tree, col_dict, colID, ln, '', '', 'v', '') output += """</td> </tr> </table> """ try: body = [output, extra] except NameError: body = [output] return addadminbox(subtitle, body) def perform_addportalbox(colID, ln, title='', body='', callback='yes', confirm=-1): """form to add a new portalbox title - the title of the portalbox body - the body of the portalbox""" col_dict = dict(get_def_name('', "collection")) colID = int(colID) subtitle = """<a name="5.1"></a>Create new portalbox""" text = """ <span class="adminlabel">Title</span> <textarea cols="50" rows="1" class="admin_wvar" type="text" name="title">%s</textarea><br> <span class="adminlabel">Body</span> <textarea cols="50" rows="10" class="admin_wvar" type="text" name="body">%s</textarea><br> """ % (cgi.escape(title), cgi.escape(body)) output = createhiddenform(action="addportalbox#5.1", text=text, button="Add", colID=colID, ln=ln, confirm=1) if body and confirm in [1, "1"]: title = cgi.escape(title) body = cgi.escape(body) res = add_pbx(title, body) output += write_outcome(res) if res[1] == 1: output += """<b><span class="info"><a href="addexistingportalbox?colID=%s&ln=%s&pbxID=%s#5">Add portalbox to collection</a></span></b>""" % (colID, ln, res[1]) elif confirm not in [-1, "-1"]: output += """<b><span class="info">Body field must be filled.</span></b> """ try: body = [output, extra] except NameError: body = [output] return perform_showportalboxes(colID, ln, content=addadminbox(subtitle, body)) def perform_addexistingportalbox(colID, ln, pbxID=-1, score=0, position='', sel_ln='', callback='yes', confirm=-1): """form to add an existing portalbox to a collection. colID - the collection to add the portalbox to pbxID - the portalbox to add score - the importance of the portalbox. position - the position of the portalbox on the page sel_ln - the language of the portalbox""" subtitle = """<a name="5.2"></a>Add existing portalbox to collection""" output = "" colID = int(colID) res = get_pbx() pos = get_pbx_pos() lang = dict(get_languages()) col_dict = dict(get_def_name('', "collection")) pbx_dict = dict(map(lambda x: (x[0], x[1]), res)) col_pbx = get_col_pbx(colID) col_pbx = dict(map(lambda x: (x[0], x[5]), col_pbx)) if len(res) > 0: text = """ <span class="adminlabel">Portalbox</span> <select name="pbxID" class="admin_w200"> <option value="-1">- Select portalbox -</option> """ for (id, t_title, t_body) in res: if not col_pbx.has_key(id): text += """<option value="%s" %s>%s - %s...</option> """ % (id, id == int(pbxID) and 'selected="selected"' or '', t_title, cgi.escape(t_body[0:25 - len(t_title)])) text += """</select><br> <span class="adminlabel">Language</span> <select name="sel_ln" class="admin_w200"> <option value="">- Select language -</option> """ listlang = lang.items() listlang.sort() for (key, name) in listlang: text += """<option value="%s" %s>%s</option> """ % (key, key == sel_ln and 'selected="selected"' or '', name) text += """</select><br> <span class="adminlabel">Position</span> <select name="position" class="admin_w200"> <option value="">- Select position -</option> """ listpos = pos.items() listpos.sort() for (key, name) in listpos: text += """<option value="%s" %s>%s</option>""" % (key, key==position and 'selected="selected"' or '', name) text += "</select>" output += createhiddenform(action="addexistingportalbox#5.2", text=text, button="Add", colID=colID, ln=ln, confirm=1) else: output = """No existing portalboxes to add, please create a new one. """ if pbxID > -1 and position and sel_ln and confirm in [1, "1"]: pbxID = int(pbxID) res = add_col_pbx(colID, pbxID, sel_ln, position, '') output += write_outcome(res) elif pbxID > -1 and confirm not in [-1, "-1"]: output += """<b><span class="info">All fields must be filled.</span></b> """ try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) return perform_showportalboxes(colID, ln, content=output) def perform_deleteportalbox(colID, ln, pbxID=-1, callback='yes', confirm=-1): """form to delete a portalbox which is not in use. colID - the current collection. pbxID - the id of the portalbox""" subtitle = """<a name="5.3"></a>Delete an unused portalbox""" output = "" colID = int(colID) if pbxID not in [-1," -1"] and confirm in [1, "1"]: ares = get_pbx() pbx_dict = dict(map(lambda x: (x[0], x[1]), ares)) if pbx_dict.has_key(int(pbxID)): pname = pbx_dict[int(pbxID)] ares = delete_pbx(int(pbxID)) else: return """<b><span class="info">This portalbox does not exist</span></b>""" res = get_pbx() col_dict = dict(get_def_name('', "collection")) pbx_dict = dict(map(lambda x: (x[0], x[1]), res)) col_pbx = get_col_pbx() col_pbx = dict(map(lambda x: (x[0], x[5]), col_pbx)) if len(res) > 0: text = """ <span class="adminlabel">Portalbox</span> <select name="pbxID" class="admin_w200"> """ text += """<option value="-1">- Select portalbox -""" for (id, t_title, t_body) in res: if not col_pbx.has_key(id): text += """<option value="%s" %s>%s - %s...""" % (id, id == int(pbxID) and 'selected="selected"' or '', t_title, cgi.escape(t_body[0:10])) text += "</option>" text += """</select><br>""" output += createhiddenform(action="deleteportalbox#5.3", text=text, button="Delete", colID=colID, ln=ln, confirm=1) if pbxID not in [-1,"-1"]: pbxID = int(pbxID) if confirm in [1, "1"]: output += write_outcome(ares) elif confirm not in [-1, "-1"]: output += """<b><span class="info">Choose a portalbox to delete.</span></b> """ try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) return perform_showportalboxes(colID, ln, content=output) def perform_modifyportalbox(colID, ln, pbxID=-1, score='', position='', sel_ln='', title='', body='', callback='yes', confirm=-1): """form to modify a portalbox in a collection, or change the portalbox itself. colID - the id of the collection. pbxID - the portalbox to change score - the score of the portalbox connected to colID which should be changed. position - the position of the portalbox in collection colID to change.""" subtitle = "" output = "" colID = int(colID) res = get_pbx() pos = get_pbx_pos() lang = dict(get_languages()) col_dict = dict(get_def_name('', "collection")) pbx_dict = dict(map(lambda x: (x[0], x[1]), res)) col_pbx = get_col_pbx(colID) col_pbx = dict(map(lambda x: (x[0], x[5]), col_pbx)) if pbxID not in [-1, "-1"]: pbxID = int(pbxID) subtitle = """<a name="5.4"></a>Modify portalbox '%s' for this collection""" % pbx_dict[pbxID] col_pbx = get_col_pbx(colID) if not (score and position) and not (body and title): for (id_pbx, id_collection, tln, score, position, title, body) in col_pbx: if id_pbx == pbxID: break output += """Collection (presentation) specific values (Changes implies only to this collection.)<br>""" text = """ <span class="adminlabel">Position</span> <select name="position" class="admin_w200"> """ listpos = pos.items() listpos.sort() for (key, name) in listpos: text += """<option value="%s" %s>%s""" % (key, key==position and 'selected="selected"' or '', name) text += "</option>" text += """</select><br>""" output += createhiddenform(action="modifyportalbox#5.4", text=text, button="Modify", colID=colID, pbxID=pbxID, score=score, title=title, body=cgi.escape(body, 1), sel_ln=sel_ln, ln=ln, confirm=3) if pbxID > -1 and score and position and confirm in [3, "3"]: pbxID = int(pbxID) res = modify_pbx(colID, pbxID, sel_ln, score, position, '', '') res2 = get_pbx() pbx_dict = dict(map(lambda x: (x[0], x[1]), res2)) output += write_outcome(res) output += """<br>Portalbox (content) specific values (any changes appears everywhere the portalbox is used.)""" text = """ <span class="adminlabel">Title</span> <textarea cols="50" rows="1" class="admin_wvar" type="text" name="title">%s</textarea><br> """ % cgi.escape(title) text += """ <span class="adminlabel">Body</span> <textarea cols="50" rows="10" class="admin_wvar" type="text" name="body">%s</textarea><br> """ % cgi.escape(body) output += createhiddenform(action="modifyportalbox#5.4", text=text, button="Modify", colID=colID, pbxID=pbxID, sel_ln=sel_ln, score=score, position=position, ln=ln, confirm=4) if pbxID > -1 and confirm in [4, "4"]: pbxID = int(pbxID) res = modify_pbx(colID, pbxID, sel_ln, '', '', title, body) output += write_outcome(res) else: output = """No portalbox to modify.""" try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) return perform_showportalboxes(colID, ln, content=output) def perform_switchpbxscore(colID, id_1, id_2, sel_ln, ln): """Switch the score of id_1 and id_2 in collection_portalbox. colID - the current collection id_1/id_2 - the id's to change the score for. sel_ln - the language of the portalbox""" res = get_pbx() pbx_dict = dict(map(lambda x: (x[0], x[1]), res)) res = switch_pbx_score(colID, id_1, id_2, sel_ln) output += write_outcome(res) return perform_showportalboxes(colID, ln, content=output) def perform_showportalboxes(colID, ln, callback='yes', content='', confirm=-1): """show the portalboxes of this collection. colID - the portalboxes to show the collection for.""" colID = int(colID) col_dict = dict(get_def_name('', "collection")) subtitle = """<a name="5">5. Modify portalboxes for collection '%s'</a>   <small>[<a title="See guide" href="%s/admin/websearch/guide.html#3.5">?</a>]</small>""" % (col_dict[colID], weburl) output = "" pos = get_pbx_pos() output = """<dl> <dt>Portalbox actions (not related to this collection) <dd><a href="addportalbox?colID=%s&ln=%s#5.1">Create new portalbox</a></dd> <dd><a href="deleteportalbox?colID=%s&ln=%s#5.3">Delete an unused portalbox</a></dd> <dt>Collection specific actions <dd><a href="addexistingportalbox?colID=%s&ln=%s#5.2">Add existing portalbox to collection</a></dd> </dl> """ % (colID, ln, colID, ln, colID, ln) header = ['Position', 'Language', '', 'Title', 'Actions'] actions = [] cdslang = get_languages() lang = dict(cdslang) pos_list = pos.items() pos_list.sort() if len(get_col_pbx(colID)) > 0: for (key, value) in cdslang: for (pos_key, pos_value) in pos_list: res = get_col_pbx(colID, key, pos_key) i = 0 for (pbxID, colID_pbx, tln, score, position, title, body) in res: move = """<table cellspacing="1" cellpadding="0" border="0"><tr><td>""" if i != 0: move += """<a href="%s/admin/websearch/websearchadmin.py/switchpbxscore?colID=%s&ln=%s&id_1=%s&id_2=%s&sel_ln=%s&rand=%s#5"><img border="0" src="%s/img/smallup.gif" title="Move portalbox up"></a>""" % (weburl, colID, ln, pbxID, res[i - 1][0], tln, random.randint(0, 1000), weburl) else: move += " " move += "</td><td>" i += 1 if i != len(res): move += """<a href="%s/admin/websearch/websearchadmin.py/switchpbxscore?colID=%s&ln=%s&id_1=%s&id_2=%s&sel_ln=%s&rand=%s#5"><img border="0" src="%s/img/smalldown.gif" title="Move portalbox down"></a>""" % (weburl, colID, ln, pbxID, res[i][0], tln, random.randint(0, 1000), weburl) move += """</td></tr></table>""" actions.append(["%s" % (i==1 and pos[position] or ''), "%s" % (i==1 and lang[tln] or ''), move, "%s" % title]) for col in [(('Modify', 'modifyportalbox'), ('Remove', 'removeportalbox'),)]: actions[-1].append('<a href="%s/admin/websearch/websearchadmin.py/%s?colID=%s&ln=%s&pbxID=%s&sel_ln=%s#5.4">%s</a>' % (weburl, col[0][1], colID, ln, pbxID, tln, col[0][0])) for (str, function) in col[1:]: actions[-1][-1] += ' / <a href="%s/admin/websearch/websearchadmin.py/%s?colID=%s&ln=%s&pbxID=%s&sel_ln=%s#5.5">%s</a>' % (weburl, function, colID, ln, pbxID, tln, str) output += tupletotable(header=header, tuple=actions) else: output += """No portalboxes exists for this collection""" output += content try: body = [output, extra] except NameError: body = [output] if callback: return perform_editcollection(colID, ln, "perform_showportalboxes", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_removeportalbox(colID, ln, pbxID='', sel_ln='', callback='yes', confirm=0): """form to remove a portalbox from a collection. colID - the current collection, remove the portalbox from this collection. sel_ln - remove the portalbox with this language pbxID - remove the portalbox with this id""" subtitle = """<a name="5.5"></a>Remove portalbox""" output = "" col_dict = dict(get_def_name('', "collection")) res = get_pbx() pbx_dict = dict(map(lambda x: (x[0], x[1]), res)) if colID and pbxID and sel_ln: colID = int(colID) pbxID = int(pbxID) if confirm in ["0", 0]: text = """Do you want to remove the portalbox '%s' from the collection '%s'.""" % (pbx_dict[pbxID], col_dict[colID]) output += createhiddenform(action="removeportalbox#5.5", text=text, button="Confirm", colID=colID, pbxID=pbxID, sel_ln=sel_ln, confirm=1) elif confirm in ["1", 1]: res = remove_pbx(colID, pbxID, sel_ln) output += write_outcome(res) try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) return perform_showportalboxes(colID, ln, content=output) def perform_switchfmtscore(colID, type, id_1, id_2, ln): """Switch the score of id_1 and id_2 in the table type. colID - the current collection id_1/id_2 - the id's to change the score for. type - like "format" """ fmt_dict = dict(get_def_name('', "format")) res = switch_score(colID, id_1, id_2, type) output = write_outcome(res) return perform_showoutputformats(colID, ln, content=output) def perform_switchfldscore(colID, id_1, id_2, fmeth, ln): """Switch the score of id_1 and id_2 in collection_field_fieldvalue. colID - the current collection id_1/id_2 - the id's to change the score for.""" fld_dict = dict(get_def_name('', "field")) res = switch_fld_score(colID, id_1, id_2) output = write_outcome(res) if fmeth == "soo": return perform_showsortoptions(colID, ln, content=output) elif fmeth == "sew": return perform_showsearchfields(colID, ln, content=output) elif fmeth == "seo": return perform_showsearchoptions(colID, ln, content=output) def perform_switchfldvaluescore(colID, id_1, id_fldvalue_1, id_fldvalue_2, ln): """Switch the score of id_1 and id_2 in collection_field_fieldvalue. colID - the current collection id_1/id_2 - the id's to change the score for.""" name_1 = run_sql("SELECT name from fieldvalue where id=%s" % id_fldvalue_1)[0][0] name_2 = run_sql("SELECT name from fieldvalue where id=%s" % id_fldvalue_2)[0][0] res = switch_fld_value_score(colID, id_1, id_fldvalue_1, id_fldvalue_2) output = write_outcome(res) return perform_modifyfield(colID, fldID=id_1, ln=ln, content=output) def perform_addnewfieldvalue(colID, fldID, ln, name='', value='', callback="yes", confirm=-1): """form to add a new fieldvalue. name - the name of the new fieldvalue value - the value of the new fieldvalue """ output = "" subtitle = """<a name="7.4"></a>Add new value""" text = """ <span class="adminlabel">Display name</span> <input class="admin_w200" type="text" name="name" value="%s" /><br> <span class="adminlabel">Search value</span> <input class="admin_w200" type="text" name="value" value="%s" /><br> """ % (name, value) output = createhiddenform(action="%s/admin/websearch/websearchadmin.py/addnewfieldvalue" % weburl, text=text, colID=colID, fldID=fldID, ln=ln, button="Add", confirm=1) if name and value and confirm in ["1", 1]: res = add_fldv(name, value) output += write_outcome(res) if res[0] == 1: res = add_col_fld(colID, fldID, 'seo', res[1]) if res[0] == 0: output += "<br>" + write_outcome(res) elif confirm not in ["-1", -1]: output += """<b><span class="info">Please fill in name and value.</span></b> """ try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) return perform_modifyfield(colID, fldID=fldID, ln=ln, content=output) def perform_modifyfieldvalue(colID, fldID, fldvID, ln, name='', value='', callback="yes", confirm=-1): """form to modify a fieldvalue. name - the name of the fieldvalue value - the value of the fieldvalue """ if confirm in [-1, "-1"]: res = get_fld_value(fldvID) (id, name, value) = res[0] output = "" subtitle = """<a name="7.4"></a>Modify existing value""" output = """<dl> <dt><b><span class="info">Warning: Modifications done below will also inflict on all places the modified data is used.</span></b></dt> </dl>""" text = """ <span class="adminlabel">Display name</span> <input class="admin_w200" type="text" name="name" value="%s" /><br> <span class="adminlabel">Search value</span> <input class="admin_w200" type="text" name="value" value="%s" /><br> """ % (name, value) output += createhiddenform(action="%s/admin/websearch/websearchadmin.py/modifyfieldvalue" % weburl, text=text, colID=colID, fldID=fldID, fldvID=fldvID, ln=ln, button="Update", confirm=1) output += createhiddenform(action="%s/admin/websearch/websearchadmin.py/modifyfieldvalue" % weburl, text="Delete value and all associations", colID=colID, fldID=fldID, fldvID=fldvID, ln=ln, button="Delete", confirm=2) if name and value and confirm in ["1", 1]: res = update_fldv(fldvID, name, value) output += write_outcome(res) #if res: # output += """<b><span class="info">Operation successfully completed.</span></b>""" #else: # output += """<b><span class="info">Operation failed.</span></b>""" elif confirm in ["2", 2]: res = delete_fldv(fldvID) output += write_outcome(res) elif confirm not in ["-1", -1]: output += """<b><span class="info">Please fill in name and value.</span></b>""" try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) return perform_modifyfield(colID, fldID=fldID, ln=ln, content=output) def perform_removefield(colID, ln, fldID='', fldvID='', fmeth='', callback='yes', confirm=0): """form to remove a field from a collection. colID - the current collection, remove the field from this collection. sel_ln - remove the field with this language fldID - remove the field with this id""" if fmeth == "soo": field = "sort option" elif fmeth == "sew": field = "search field" elif fmeth == "seo": field = "search option" else: field = "field" subtitle = """<a name="6.4"><a name="7.4"><a name="8.4"></a>Remove %s""" % field output = "" col_dict = dict(get_def_name('', "collection")) fld_dict = dict(get_def_name('', "field")) res = get_fld_value() fldv_dict = dict(map(lambda x: (x[0], x[1]), res)) if colID and fldID: colID = int(colID) fldID = int(fldID) if fldvID and fldvID != "None": fldvID = int(fldvID) if confirm in ["0", 0]: text = """Do you want to remove the %s '%s' %s from the collection '%s'.""" % (field, fld_dict[fldID], (fldvID not in["", "None"] and "with value '%s'" % fldv_dict[fldvID] or ''), col_dict[colID]) output += createhiddenform(action="removefield#6.5", text=text, button="Confirm", colID=colID, fldID=fldID, fldvID=fldvID, fmeth=fmeth, confirm=1) elif confirm in ["1", 1]: res = remove_fld(colID, fldID, fldvID) output += write_outcome(res) try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) if fmeth == "soo": return perform_showsortoptions(colID, ln, content=output) elif fmeth == "sew": return perform_showsearchfields(colID, ln, content=output) elif fmeth == "seo": return perform_showsearchoptions(colID, ln, content=output) def perform_removefieldvalue(colID, ln, fldID='', fldvID='', fmeth='', callback='yes', confirm=0): """form to remove a field from a collection. colID - the current collection, remove the field from this collection. sel_ln - remove the field with this language fldID - remove the field with this id""" subtitle = """<a name="7.4"></a>Remove value""" output = "" col_dict = dict(get_def_name('', "collection")) fld_dict = dict(get_def_name('', "field")) res = get_fld_value() fldv_dict = dict(map(lambda x: (x[0], x[1]), res)) if colID and fldID: colID = int(colID) fldID = int(fldID) if fldvID and fldvID != "None": fldvID = int(fldvID) if confirm in ["0", 0]: text = """Do you want to remove the value '%s' from the search option '%s'.""" % (fldv_dict[fldvID], fld_dict[fldID]) output += createhiddenform(action="removefieldvalue#7.4", text=text, button="Confirm", colID=colID, fldID=fldID, fldvID=fldvID, fmeth=fmeth, confirm=1) elif confirm in ["1", 1]: res = remove_fld(colID, fldID, fldvID) output += write_outcome(res) try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) return perform_modifyfield(colID, fldID=fldID, ln=ln, content=output) def perform_rearrangefieldvalue(colID, fldID, ln, callback='yes', confirm=-1): """rearrang the fieldvalues alphabetically colID - the collection fldID - the field to rearrange the fieldvalue for """ subtitle = "Order values alphabetically" output = "" col_fldv = get_col_fld(colID, 'seo', fldID) col_fldv = dict(map(lambda x: (x[1], x[0]), col_fldv)) fldv_names = get_fld_value() fldv_names = map(lambda x: (x[0], x[1]), fldv_names) if not col_fldv.has_key(None): vscore = len(col_fldv) for (fldvID, name) in fldv_names: if col_fldv.has_key(fldvID): run_sql("UPDATE collection_field_fieldvalue SET score_fieldvalue=%s WHERE id_collection=%s and id_field=%s and id_fieldvalue=%s" % (vscore, colID, fldID, fldvID)) vscore -= 1 output += write_outcome((1, "")) else: output += write_outcome((0, (0, "No values to order"))) try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) return perform_modifyfield(colID, fldID, ln, content=output) def perform_rearrangefield(colID, ln, fmeth, callback='yes', confirm=-1): """rearrang the fields alphabetically colID - the collection """ subtitle = "Order fields alphabetically" output = "" col_fld = dict(map(lambda x: (x[0], x[1]), get_col_fld(colID, fmeth))) fld_names = get_def_name('', "field") if len(col_fld) > 0: score = len(col_fld) for (fldID, name) in fld_names: if col_fld.has_key(fldID): run_sql("UPDATE collection_field_fieldvalue SET score=%s WHERE id_collection=%s and id_field=%s" % (score, colID, fldID)) score -= 1 output += write_outcome((1, "")) else: output += write_outcome((0, (0, "No fields to order"))) try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) if fmeth == "soo": return perform_showsortoptions(colID, ln, content=output) elif fmeth == "sew": return perform_showsearchfields(colID, ln, content=output) elif fmeth == "seo": return perform_showsearchoptions(colID, ln, content=output) def perform_addexistingfieldvalue(colID, fldID, fldvID=-1, ln=cdslang, callback='yes', confirm=-1): """form to add an existing fieldvalue to a field. colID - the collection fldID - the field to add the fieldvalue to fldvID - the fieldvalue to add""" subtitle = """</a><a name="7.4"></a>Add existing value to search option""" output = "" if fldvID not in [-1, "-1"] and confirm in [1, "1"]: fldvID = int(fldvID) ares = add_col_fld(colID, fldID, 'seo', fldvID) colID = int(colID) fldID = int(fldID) lang = dict(get_languages()) res = get_def_name('', "field") col_dict = dict(get_def_name('', "collection")) fld_dict = dict(res) col_fld = dict(map(lambda x: (x[0], x[1]), get_col_fld(colID, 'seo'))) fld_value = get_fld_value() fldv_dict = dict(map(lambda x: (x[0], x[1]), fld_value)) text = """ <span class="adminlabel">Value</span> <select name="fldvID" class="admin_w200"> <option value="-1">- Select value -</option> """ res = run_sql("SELECT id,name,value FROM fieldvalue ORDER BY name") for (id, name, value) in res: text += """<option value="%s" %s>%s - %s</option> """ % (id, id == int(fldvID) and 'selected="selected"' or '', name, value) text += """</select><br>""" output += createhiddenform(action="addexistingfieldvalue#7.4", text=text, button="Add", colID=colID, fldID=fldID, ln=ln, confirm=1) if fldvID not in [-1, "-1"] and confirm in [1, "1"]: output += write_outcome(ares) elif confirm in [1, "1"]: output += """<b><span class="info">Select a value to add and try again.</span></b>""" try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) return perform_modifyfield(colID, fldID, ln, content=output) def perform_addexistingfield(colID, ln, fldID=-1, fldvID=-1, fmeth='', callback='yes', confirm=-1): """form to add an existing field to a collection. colID - the collection to add the field to fldID - the field to add sel_ln - the language of the field""" subtitle = """<a name="6.2"></a><a name="7.2"></a><a name="8.2"></a>Add existing field to collection""" output = "" if fldID not in [-1, "-1"] and confirm in [1, "1"]: fldID = int(fldID) ares = add_col_fld(colID, fldID, fmeth, fldvID) colID = int(colID) lang = dict(get_languages()) res = get_def_name('', "field") col_dict = dict(get_def_name('', "collection")) fld_dict = dict(res) col_fld = dict(map(lambda x: (x[0], x[1]), get_col_fld(colID, fmeth))) fld_value = get_fld_value() fldv_dict = dict(map(lambda x: (x[0], x[1]), fld_value)) if fldvID: fldvID = int(fldvID) text = """ <span class="adminlabel">Field</span> <select name="fldID" class="admin_w200"> <option value="-1">- Select field -</option> """ for (id, var) in res: if fmeth == 'seo' or (fmeth != 'seo' and not col_fld.has_key(id)): text += """<option value="%s" %s>%s</option> """ % (id, '', fld_dict[id]) text += """</select><br>""" output += createhiddenform(action="addexistingfield#6.2", text=text, button="Add", colID=colID, fmeth=fmeth, ln=ln, confirm=1) if fldID not in [-1, "-1"] and confirm in [1, "1"]: output += write_outcome(ares) elif fldID in [-1, "-1"] and confirm not in [-1, "-1"]: output += """<b><span class="info">Select a field.</span></b> """ try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) if fmeth == "soo": return perform_showsortoptions(colID, ln, content=output) elif fmeth == "sew": return perform_showsearchfields(colID, ln, content=output) elif fmeth == "seo": return perform_showsearchoptions(colID, ln, content=output) def perform_showsortoptions(colID, ln, callback='yes', content='', confirm=-1): """show the sort fields of this collection..""" colID = int(colID) col_dict = dict(get_def_name('', "collection")) fld_dict = dict(get_def_name('', "field")) fld_type = get_sort_nametypes() subtitle = """<a name="8">8. Modify sort options for collection '%s'</a>   <small>[<a title="See guide" href="%s/admin/websearch/guide.html#3.8">?</a>]</small>""" % (col_dict[colID], weburl) output = """<dl> <dt>Field actions (not related to this collection)</dt> <dd>Go to the BibIndex interface to modify the available sort options</dd> <dt>Collection specific actions <dd><a href="addexistingfield?colID=%s&ln=%s&fmeth=soo#8.2">Add sort option to collection</a></dd> <dd><a href="rearrangefield?colID=%s&ln=%s&fmeth=soo#8.2">Order sort options alphabetically</a></dd> </dl> """ % (colID, ln, colID, ln) header = ['', 'Sort option', 'Actions'] actions = [] cdslang = get_languages() lang = dict(cdslang) fld_type_list = fld_type.items() if len(get_col_fld(colID, 'soo')) > 0: res = get_col_fld(colID, 'soo') i = 0 for (fldID, fldvID, stype, score, score_fieldvalue) in res: move = """<table cellspacing="1" cellpadding="0" border="0"><tr><td>""" if i != 0: move += """<a href="%s/admin/websearch/websearchadmin.py/switchfldscore?colID=%s&ln=%s&id_1=%s&id_2=%s&fmeth=soo&rand=%s#8"><img border="0" src="%s/img/smallup.gif" title="Move up"></a>""" % (weburl, colID, ln, fldID, res[i - 1][0], random.randint(0, 1000), weburl) else: move += " " move += "</td><td>" i += 1 if i != len(res): move += """<a href="%s/admin/websearch/websearchadmin.py/switchfldscore?colID=%s&ln=%s&id_1=%s&id_2=%s&fmeth=soo&rand=%s#8"><img border="0" src="%s/img/smalldown.gif" title="Move down"></a>""" % (weburl, colID, ln, fldID, res[i][0], random.randint(0, 1000), weburl) move += """</td></tr></table>""" actions.append([move, fld_dict[int(fldID)]]) for col in [(('Remove sort option', 'removefield'),)]: actions[-1].append('<a href="%s/admin/websearch/websearchadmin.py/%s?colID=%s&ln=%s&fldID=%s&fmeth=soo#8.4">%s</a>' % (weburl, col[0][1], colID, ln, fldID, col[0][0])) for (str, function) in col[1:]: actions[-1][-1] += ' / <a href="%s/admin/websearch/websearchadmin.py/%s?colID=%s&ln=%s&fldID=%s&fmeth=soo#8.5">%s</a>' % (weburl, function, colID, ln, fldID, str) output += tupletotable(header=header, tuple=actions) else: output += """No sort options exists for this collection""" output += content try: body = [output, extra] except NameError: body = [output] if callback: return perform_editcollection(colID, ln, "perform_showsortoptions", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_showsearchfields(colID, ln, callback='yes', content='', confirm=-1): """show the search fields of this collection..""" colID = int(colID) col_dict = dict(get_def_name('', "collection")) fld_dict = dict(get_def_name('', "field")) fld_type = get_sort_nametypes() subtitle = """<a name="6">6. Modify search fields for collection '%s'</a>   <small>[<a title="See guide" href="%s/admin/websearch/guide.html#3.6">?</a>]</small>""" % (col_dict[colID], weburl) output = """<dl> <dt>Field actions (not related to this collection)</dt> <dd>Go to the BibIndex interface to modify the available search fields</dd> <dt>Collection specific actions <dd><a href="addexistingfield?colID=%s&ln=%s&fmeth=sew#6.2">Add search field to collection</a></dd> <dd><a href="rearrangefield?colID=%s&ln=%s&fmeth=sew#6.2">Order search fields alphabetically</a></dd> </dl> """ % (colID, ln, colID, ln) header = ['', 'Search field', 'Actions'] actions = [] cdslang = get_languages() lang = dict(cdslang) fld_type_list = fld_type.items() if len(get_col_fld(colID, 'sew')) > 0: res = get_col_fld(colID, 'sew') i = 0 for (fldID, fldvID, stype, score, score_fieldvalue) in res: move = """<table cellspacing="1" cellpadding="0" border="0"><tr><td>""" if i != 0: move += """<a href="%s/admin/websearch/websearchadmin.py/switchfldscore?colID=%s&ln=%s&id_1=%s&id_2=%s&fmeth=sew&rand=%s#6"><img border="0" src="%s/img/smallup.gif" title="Move up"></a>""" % (weburl, colID, ln, fldID, res[i - 1][0], random.randint(0, 1000), weburl) else: move += " " move += "</td><td>" i += 1 if i != len(res): move += '<a href="%s/admin/websearch/websearchadmin.py/switchfldscore?colID=%s&ln=%s&id_1=%s&id_2=%s&fmeth=sew&rand=%s#6"><img border="0" src="%s/img/smalldown.gif" title="Move down"></a>' % (weburl, colID, ln, fldID, res[i][0], random.randint(0, 1000), weburl) move += """</td></tr></table>""" actions.append([move, fld_dict[int(fldID)]]) for col in [(('Remove search field', 'removefield'),)]: actions[-1].append('<a href="%s/admin/websearch/websearchadmin.py/%s?colID=%s&ln=%s&fldID=%s&fmeth=sew#6.4">%s</a>' % (weburl, col[0][1], colID, ln, fldID, col[0][0])) for (str, function) in col[1:]: actions[-1][-1] += ' / <a href="%s/admin/websearch/websearchadmin.py/%s?colID=%s&ln=%s&fldID=%s#6.5">%s</a>' % (weburl, function, colID, ln, fldID, str) output += tupletotable(header=header, tuple=actions) else: output += """No search fields exists for this collection""" output += content try: body = [output, extra] except NameError: body = [output] if callback: return perform_editcollection(colID, ln, "perform_showsearchfields", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_showsearchoptions(colID, ln, callback='yes', content='', confirm=-1): """show the sort and search options of this collection..""" colID = int(colID) col_dict = dict(get_def_name('', "collection")) fld_dict = dict(get_def_name('', "field")) fld_type = get_sort_nametypes() subtitle = """<a name="7">7. Modify search options for collection '%s'</a>   <small>[<a title="See guide" href="%s/admin/websearch/guide.html#3.7">?</a>]</small>""" % (col_dict[colID], weburl) output = """<dl> <dt>Field actions (not related to this collection)</dt> <dd>Go to the BibIndex interface to modify the available search options</dd> <dt>Collection specific actions <dd><a href="addexistingfield?colID=%s&ln=%s&fmeth=seo#7.2">Add search option to collection</a></dd> <dd><a href="rearrangefield?colID=%s&ln=%s&fmeth=seo#7.2">Order search options alphabetically</a></dd> </dl> """ % (colID, ln, colID, ln) header = ['', 'Search option', 'Actions'] actions = [] cdslang = get_languages() lang = dict(cdslang) fld_type_list = fld_type.items() fld_distinct = run_sql("SELECT distinct(id_field) FROM collection_field_fieldvalue WHERE type='seo' AND id_collection=%s ORDER by score desc" % colID) if len(fld_distinct) > 0: i = 0 for (id) in fld_distinct: fldID = id[0] col_fld = get_col_fld(colID, 'seo', fldID) move = "" if i != 0: move += """<a href="%s/admin/websearch/websearchadmin.py/switchfldscore?colID=%s&ln=%s&id_1=%s&id_2=%s&fmeth=seo&rand=%s#7"><img border="0" src="%s/img/smallup.gif" title="Move up"></a>""" % (weburl, colID, ln, fldID, fld_distinct[i - 1][0], random.randint(0, 1000), weburl) else: move += " " i += 1 if i != len(fld_distinct): move += '<a href="%s/admin/websearch/websearchadmin.py/switchfldscore?colID=%s&ln=%s&id_1=%s&id_2=%s&fmeth=seo&rand=%s#7"><img border="0" src="%s/img/smalldown.gif" title="Move down"></a>' % (weburl, colID, ln, fldID, fld_distinct[i][0], random.randint(0, 1000), weburl) actions.append([move, "%s" % fld_dict[fldID]]) for col in [(('Modify values', 'modifyfield'), ('Remove search option', 'removefield'),)]: actions[-1].append('<a href="%s/admin/websearch/websearchadmin.py/%s?colID=%s&ln=%s&fldID=%s#7.3">%s</a>' % (weburl, col[0][1], colID, ln, fldID, col[0][0])) for (str, function) in col[1:]: actions[-1][-1] += ' / <a href="%s/admin/websearch/websearchadmin.py/%s?colID=%s&ln=%s&fldID=%s&fmeth=seo#7.3">%s</a>' % (weburl, function, colID, ln, fldID, str) output += tupletotable(header=header, tuple=actions) else: output += """No search options exists for this collection""" output += content try: body = [output, extra] except NameError: body = [output] if callback: return perform_editcollection(colID, ln, "perform_showsearchoptions", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_modifyfield(colID, fldID, fldvID='', ln=cdslang, content='',callback='yes', confirm=0): """Modify the fieldvalues for a field""" colID = int(colID) col_dict = dict(get_def_name('', "collection")) fld_dict = dict(get_def_name('', "field")) fld_type = get_sort_nametypes() fldID = int(fldID) subtitle = """<a name="7.3">Modify values for field '%s'</a>""" % (fld_dict[fldID]) output = """<dl> <dt>Value specific actions <dd><a href="addexistingfieldvalue?colID=%s&ln=%s&fldID=%s#7.4">Add existing value to search option</a></dd> <dd><a href="addnewfieldvalue?colID=%s&ln=%s&fldID=%s#7.4">Add new value to search option</a></dd> <dd><a href="rearrangefieldvalue?colID=%s&ln=%s&fldID=%s#7.4">Order values alphabetically</a></dd> </dl> """ % (colID, ln, fldID, colID, ln, fldID, colID, ln, fldID) header = ['', 'Value name', 'Actions'] actions = [] cdslang = get_languages() lang = dict(cdslang) fld_type_list = fld_type.items() col_fld = list(get_col_fld(colID, 'seo', fldID)) if len(col_fld) == 1 and col_fld[0][1] == None: output += """<b><span class="info">No values added for this search option yet</span></b>""" else: j = 0 for (fldID, fldvID, stype, score, score_fieldvalue) in col_fld: fieldvalue = get_fld_value(fldvID) move = "" if j != 0: move += """<a href="%s/admin/websearch/websearchadmin.py/switchfldvaluescore?colID=%s&ln=%s&id_1=%s&id_fldvalue_1=%s&id_fldvalue_2=%s&rand=%s#7.3"><img border="0" src="%s/img/smallup.gif" title="Move up"></a>""" % (weburl, colID, ln, fldID, fldvID, col_fld[j - 1][1], random.randint(0, 1000), weburl) else: move += " " j += 1 if j != len(col_fld): move += """<a href="%s/admin/websearch/websearchadmin.py/switchfldvaluescore?colID=%s&ln=%s&id_1=%s&id_fldvalue_1=%s&id_fldvalue_2=%s&rand=%s#7.3"><img border="0" src="%s/img/smalldown.gif" title="Move down"></a>""" % (weburl, colID, ln, fldID, fldvID, col_fld[j][1], random.randint(0, 1000), weburl) if fieldvalue[0][1] != fieldvalue[0][2] and fldvID != None: actions.append([move, "%s - %s" % (fieldvalue[0][1],fieldvalue[0][2])]) elif fldvID != None: actions.append([move, "%s" % fieldvalue[0][1]]) move = '' for col in [(('Modify value', 'modifyfieldvalue'), ('Remove value', 'removefieldvalue'),)]: actions[-1].append('<a href="%s/admin/websearch/websearchadmin.py/%s?colID=%s&ln=%s&fldID=%s&fldvID=%s&fmeth=seo#7.4">%s</a>' % (weburl, col[0][1], colID, ln, fldID, fldvID, col[0][0])) for (str, function) in col[1:]: actions[-1][-1] += ' / <a href="%s/admin/websearch/websearchadmin.py/%s?colID=%s&ln=%s&fldID=%s&fldvID=%s#7.4">%s</a>' % (weburl, function, colID, ln, fldID, fldvID, str) output += tupletotable(header=header, tuple=actions) output += content try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) if len(col_fld) == 0: output = content return perform_showsearchoptions(colID, ln, content=output) def perform_showoutputformats(colID, ln, callback='yes', content='', confirm=-1): """shows the outputformats of the current collection colID - the collection id.""" colID = int(colID) col_dict = dict(get_def_name('', "collection")) subtitle = """<a name="10">10. Modify output formats for collection '%s'</a>   <small>[<a title="See guide" href="%s/admin/websearch/guide.html#3.10">?</a>]</small>""" % (col_dict[colID], weburl) output = """ <dl> <dt>Output format actions (not specific to the chosen collection) <dd>Go to the BibFormat interface to modify</dd> <dt>Collection specific actions <dd><a href="addexistingoutputformat?colID=%s&ln=%s#10.2">Add existing output format to collection</a></dd> </dl> """ % (colID, ln) header = ['', 'Code', 'Output format', 'Actions'] actions = [] col_fmt = get_col_fmt(colID) fmt_dict = dict(get_def_name('', "format")) i = 0 if len(col_fmt) > 0: for (id_format, colID_fld, code, score) in col_fmt: move = """<table cellspacing="1" cellpadding="0" border="0"><tr><td>""" if i != 0: move += """<a href="%s/admin/websearch/websearchadmin.py/switchfmtscore?colID=%s&ln=%s&type=format&id_1=%s&id_2=%s&rand=%s#10"><img border="0" src="%s/img/smallup.gif" title="Move format up"></a>""" % (weburl, colID, ln, id_format, col_fmt[i - 1][0], random.randint(0, 1000), weburl) else: move += " " move += "</td><td>" i += 1 if i != len(col_fmt): move += '<a href="%s/admin/websearch/websearchadmin.py/switchfmtscore?colID=%s&ln=%s&type=format&id_1=%s&id_2=%s&rand=%s#10"><img border="0" src="%s/img/smalldown.gif" title="Move format down"></a>' % (weburl, colID, ln, id_format, col_fmt[i][0], random.randint(0, 1000), weburl) move += """</td></tr></table>""" actions.append([move, code, fmt_dict[int(id_format)]]) for col in [(('Remove', 'removeoutputformat'),)]: actions[-1].append('<a href="%s/admin/websearch/websearchadmin.py/%s?colID=%s&ln=%s&fmtID=%s#10">%s</a>' % (weburl, col[0][1], colID, ln, id_format, col[0][0])) for (str, function) in col[1:]: actions[-1][-1] += ' / <a href="%s/admin/websearch/websearchadmin.py/%s?colID=%s&ln=%s&fmtID=%s#10">%s</a>' % (weburl, function, colID, ln, id_format, str) output += tupletotable(header=header, tuple=actions) else: output += """No output formats exists for this collection""" output += content try: body = [output, extra] except NameError: body = [output] if callback: return perform_editcollection(colID, ln, "perform_showoutputformats", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) +def perform_manage_external_collections(colID, ln, callback='yes', content='', confirm=-1): + """Show the interface to configure external collections to the user.""" + + colID = int(colID) + external_collection_load_db_infos() + + subtitle = """<a name="11">11. Configuration of external collections.</a>""" + output = "" + + table_header = ['External collection name', 'Type', 'Actions', 'Checked by default'] + table_content = [] + external_collections = sort_engine_by_name(external_collections_dictionary.values()) + for collection in external_collections: + collection_name = collection.name + + type = '[Disabled]' + checked = '' + actions = '<a href="update_external_collections?colID=%(colID)d&collection_name=%(collection_name)s&action=enable_seealso">See also</a>' % locals() + actions += ' <a href="update_external_collections?colID=%(colID)d&collection_name=%(collection_name)s&action=enable_seealso;recurse=1">(R)</a>' % locals() + if collection.parser: + actions += ' | <a href="update_external_collections?colID=%(colID)d&collection_name=%(collection_name)s&action=enable">Enable</a>' % locals() + actions += ' <a href="update_external_collections?colID=%(colID)d&collection_name=%(collection_name)s&action=enable;recurse=1">(R)</a>' % locals() + if external_collection_is_enabled(collection, colID): + type = '[Enabled]' + actions = '<a href="update_external_collections?colID=%(colID)d&collection_name=%(collection_name)s&action=disable">Disable</a>' % locals() + actions += ' <a href="update_external_collections?colID=%(colID)d&collection_name=%(collection_name)s&action=disable;recurse=1">(R)</a>' % locals() + if external_collection_is_default(collection, colID): + checked = '<a href="update_external_collections?colID=%(colID)d&collection_name=%(collection_name)s&action=check_disable">Disable</a>' % locals() + checked += ' <a href="update_external_collections?colID=%(colID)d&collection_name=%(collection_name)s&action=check_disable;recurse=1">(R)</a>' % locals() + else: + checked = '<a href="update_external_collections?colID=%(colID)d&collection_name=%(collection_name)s&action=check_enable">Enable</a>' % locals() + checked += ' <a href="update_external_collections?colID=%(colID)d&collection_name=%(collection_name)s&action=check_enable;recurse=1">(R)</a>' % locals() + if external_collection_is_seealso_enabled(collection, colID): + type = '{SeeAlso}' + actions = '<a href="update_external_collections?colID=%(colID)d&collection_name=%(collection_name)s&action=disable">Disable</a>' % locals() + actions += ' <a href="update_external_collections?colID=%(colID)d&collection_name=%(collection_name)s&action=disable;recurse=1">(R)</a>' % locals() + + table_content.append([collection_name, type, actions, checked]) + + output += tupletotable(header=table_header, tuple=table_content) + + body = [output] + + return addadminbox(subtitle, body) + +def perform_update_external_collections(colID, ln, action, collection_name, recurse): + colID = int(colID) + recurse = (recurse == 1) + + if not external_collections_dictionary.has_key(collection_name): + return 'Unknow external collection : %(collection_name)s' % locals() + + collection = external_collections_dictionary[collection_name] + + if action == "enable": + external_collection_enable(collection, colID, recurse) + + if action == "enable_seealso": + external_collection_enable_seealso(collection, colID, recurse) + + if action == "disable": + external_collection_disable(collection, colID, recurse) + + if action == "check_enable": + external_collection_set_default_type(collection, colID, True, recurse) + + if action == "check_disable": + external_collection_set_default_type(collection, colID, False, recurse) + + return perform_manage_external_collections(colID, ln) + def perform_addexistingoutputformat(colID, ln, fmtID=-1, callback='yes', confirm=-1): """form to add an existing output format to a collection. colID - the collection the format should be added to fmtID - the format to add.""" subtitle = """<a name="10.2"></a>Add existing output format to collection""" output = "" if fmtID not in [-1, "-1"] and confirm in [1, "1"]: ares = add_col_fmt(colID, fmtID) colID = int(colID) res = get_def_name('', "format") fmt_dict = dict(res) col_dict = dict(get_def_name('', "collection")) col_fmt = get_col_fmt(colID) col_fmt = dict(map(lambda x: (x[0], x[2]), col_fmt)) if len(res) > 0: text = """ <span class="adminlabel">Output format</span> <select name="fmtID" class="admin_w200"> <option value="-1">- Select output format -</option> """ for (id, name) in res: if not col_fmt.has_key(id): text += """<option value="%s" %s>%s</option> """ % (id, id == int(fmtID) and 'selected="selected"' or '', name) text += """</select><br> """ output += createhiddenform(action="addexistingoutputformat#10.2", text=text, button="Add", colID=colID, ln=ln, confirm=1) else: output = """No existing output formats to add, please create a new one.""" if fmtID not in [-1, "-1"] and confirm in [1, "1"]: output += write_outcome(ares) elif fmtID in [-1, "-1"] and confirm not in [-1, "-1"]: output += """<b><span class="info">Please select output format.</span></b>""" try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) return perform_showoutputformats(colID, ln, content=output) def perform_deleteoutputformat(colID, ln, fmtID=-1, callback='yes', confirm=-1): """form to delete an output format not in use. colID - the collection id of the current collection. fmtID - the format id to delete.""" subtitle = """<a name="10.3"></a>Delete an unused output format""" output = """ <dl> <dd>Deleting an output format will also delete the translations associated.</dd> </dl> """ colID = int(colID) if fmtID not in [-1," -1"] and confirm in [1, "1"]: fmt_dict = dict(get_def_name('', "format")) old_colNAME = fmt_dict[int(fmtID)] ares = delete_fmt(int(fmtID)) res = get_def_name('', "format") fmt_dict = dict(res) col_dict = dict(get_def_name('', "collection")) col_fmt = get_col_fmt() col_fmt = dict(map(lambda x: (x[0], x[2]), col_fmt)) if len(res) > 0: text = """ <span class="adminlabel">Output format</span> <select name="fmtID" class="admin_w200"> """ text += """<option value="-1">- Select output format -""" for (id, name) in res: if not col_fmt.has_key(id): text += """<option value="%s" %s>%s""" % (id, id == int(fmtID) and 'selected="selected"' or '', name) text += "</option>" text += """</select><br>""" output += createhiddenform(action="deleteoutputformat#10.3", text=text, button="Delete", colID=colID, ln=ln, confirm=0) if fmtID not in [-1,"-1"]: fmtID = int(fmtID) if confirm in [0, "0"]: text = """<b>Do you want to delete the output format '%s'.</b> """ % fmt_dict[fmtID] output += createhiddenform(action="deleteoutputformat#10.3", text=text, button="Confirm", colID=colID, fmtID=fmtID, ln=ln, confirm=1) elif confirm in [1, "1"]: output += write_outcome(ares) elif confirm not in [-1, "-1"]: output += """<b><span class="info">Choose a output format to delete.</span></b> """ try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) return perform_showoutputformats(colID, ln, content=output) def perform_removeoutputformat(colID, ln, fmtID='', callback='yes', confirm=0): """form to remove an output format from a collection. colID - the collection id of the current collection. fmtID - the format id. """ subtitle = """<a name="10.5"></a>Remove output format""" output = "" col_dict = dict(get_def_name('', "collection")) fmt_dict = dict(get_def_name('', "format")) if colID and fmtID: colID = int(colID) fmtID = int(fmtID) if confirm in ["0", 0]: text = """Do you want to remove the output format '%s' from the collection '%s'.""" % (fmt_dict[fmtID], col_dict[colID]) output += createhiddenform(action="removeoutputformat#10.5", text=text, button="Confirm", colID=colID, fmtID=fmtID, confirm=1) elif confirm in ["1", 1]: res = remove_fmt(colID, fmtID) output += write_outcome(res) try: body = [output, extra] except NameError: body = [output] output = "<br>" + addadminbox(subtitle, body) return perform_showoutputformats(colID, ln, content=output) def perform_index(colID=1, ln=cdslang, mtype='', content='', confirm=0): """The index method, calling methods to show the collection tree, create new collections and add collections to tree. """ subtitle = "Overview" colID = int(colID) col_dict = dict(get_def_name('', "collection")) output = "" fin_output = "" if not col_dict.has_key(1): res = add_col(cdsname, '', '') if res: fin_output += """<b><span class="info">Created root collection.</span></b><br>""" else: return "Cannot create root collection, please check database." if cdsname != run_sql("SELECT name from collection WHERE id=1")[0][0]: res = run_sql("update collection set name='%s' where id=1" % cdsname) if res: fin_output += """<b><span class="info">The name of the root collection has been modified to be the same as the CDS Invenio installation name given prior to installing CDS Invenio.</span><b><br>""" else: return "Error renaming root collection." fin_output += """ <table> <tr> <td>0. <small><a href="%s/admin/websearch/websearchadmin.py?colID=%s&ln=%s&mtype=perform_showall">Show all</a></small></td> <td>1. <small><a href="%s/admin/websearch/websearchadmin.py?colID=%s&ln=%s&mtype=perform_addcollection">Create new collection</a></small></td> <td>2. <small><a href="%s/admin/websearch/websearchadmin.py?colID=%s&ln=%s&mtype=perform_addcollectiontotree">Attach collection to tree</a></small></td> <td>3. <small><a href="%s/admin/websearch/websearchadmin.py?colID=%s&ln=%s&mtype=perform_modifycollectiontree">Modify collection tree</a></small></td> <td>4. <small><a href="%s/admin/websearch/websearchadmin.py?colID=%s&ln=%s&mtype=perform_checkwebcollstatus">Webcoll Status</a></small></td> </tr><tr> <td>5. <small><a href="%s/admin/websearch/websearchadmin.py?colID=%s&ln=%s&mtype=perform_checkcollectionstatus">Collections Status</a></small></td> </tr> </table> """ % (weburl, colID, ln, weburl, colID, ln, weburl, colID, ln, weburl, colID, ln, weburl, colID, ln, weburl, colID, ln) if mtype == "": fin_output += """<br><br><b><span class="info">For managing the collections, select an item from the menu.</span><b><br>""" if mtype == "perform_addcollection" and content: fin_output += content elif mtype == "perform_addcollection" or mtype == "perform_showall": fin_output += perform_addcollection(colID=colID, ln=ln, callback='') fin_output += "<br>" if mtype == "perform_addcollectiontotree" and content: fin_output += content elif mtype == "perform_addcollectiontotree" or mtype == "perform_showall": fin_output += perform_addcollectiontotree(colID=colID, ln=ln, callback='') fin_output += "<br>" if mtype == "perform_modifycollectiontree" and content: fin_output += content elif mtype == "perform_modifycollectiontree" or mtype == "perform_showall": fin_output += perform_modifycollectiontree(colID=colID, ln=ln, callback='') fin_output += "<br>" if mtype == "perform_checkwebcollstatus" and content: fin_output += content elif mtype == "perform_checkwebcollstatus" or mtype == "perform_showall": fin_output += perform_checkwebcollstatus(colID, ln, callback='') if mtype == "perform_checkcollectionstatus" and content: fin_output += content elif mtype == "perform_checkcollectionstatus" or mtype == "perform_showall": fin_output += perform_checkcollectionstatus(colID, ln, callback='') try: body = [fin_output, extra] except NameError: body = [fin_output] return addadminbox('<b>Menu</b>', body) def show_coll_not_in_tree(colID, ln, col_dict): """Returns collections not in tree""" tree = get_col_tree(colID) in_tree = {} output = "These collections are not in the tree, and should be added:<br>" for (id, up, down, dad, reltype) in tree: in_tree[id] = 1 in_tree[dad] = 1 res = run_sql("SELECT id from collection") if len(res) != len(in_tree): for id in res: if not in_tree.has_key(id[0]): output += """<a href="%s/admin/websearch/websearchadmin.py/editcollection?colID=%s&ln=%s" title="Edit collection">%s</a> , """ % (weburl, id[0], ln, col_dict[id[0]]) output += "<br><br>" else: output = "" return output def create_colltree(tree, col_dict, colID, ln, move_from='', move_to='', rtype='', edit=''): """Creates the presentation of the collection tree, with the buttons for modifying it. tree - the tree to present, from get_tree() col_dict - the name of the collections in a dictionary colID - the collection id to start with move_from - if a collection to be moved has been chosen move_to - the collection which should be set as father of move_from rtype - the type of the tree, regular or virtual edit - if the method should output the edit buttons.""" if move_from: move_from_rtype = move_from[0] move_from_id = int(move_from[1:len(move_from)]) tree_from = get_col_tree(colID, move_from_rtype) tree_to = get_col_tree(colID, rtype) tables = 0 tstack = [] i = 0 text = """ <table border ="0" cellspacing="0" cellpadding="0">""" for i in range(0, len(tree)): id_son = tree[i][0] up = tree[i][1] down = tree[i][2] dad = tree[i][3] reltype = tree[i][4] tmove_from = "" j = i while j > 0: j = j - 1 try: if tstack[j][1] == dad: table = tstack[j][2] for k in range(0, tables - table): tables = tables - 1 text += """</table></td></tr> """ break except StandardError, e: pass text += """<tr><td> """ if i > 0 and tree[i][1] == 0: tables = tables + 1 text += """</td><td></td><td></td><td></td><td><table border="0" cellspacing="0" cellpadding="0"><tr><td> """ if i == 0: tstack.append((id_son, dad, 1)) else: tstack.append((id_son, dad, tables)) if up == 1 and edit: text += """<a href="%s/admin/websearch/websearchadmin.py/modifycollectiontree?colID=%s&ln=%s&move_up=%s&rtype=%s#%s"><img border="0" src="%s/img/smallup.gif" title="Move collection up"></a>""" % (weburl, colID, ln, i, rtype, tree[i][0], weburl) else: text += """ """ text += "</td><td>" if down == 1 and edit: text += """<a href="%s/admin/websearch/websearchadmin.py/modifycollectiontree?colID=%s&ln=%s&move_down=%s&rtype=%s#%s"><img border="0" src="%s/img/smalldown.gif" title="Move collection down"></a>""" % (weburl, colID, ln, i, rtype, tree[i][0], weburl) else: text += """ """ text += "</td><td>" if edit: if move_from and move_to: tmove_from = move_from move_from = '' if not (move_from == "" and i == 0) and not (move_from != "" and int(move_from[1:len(move_from)]) == i and rtype == move_from[0]): check = "true" if move_from: #if tree_from[move_from_id][0] == tree_to[i][0] or not check_col(tree_to[i][0], tree_from[move_from_id][0]): # check = '' #elif not check_col(tree_to[i][0], tree_from[move_from_id][0]): # check = '' #if not check and (tree_to[i][0] == 1 and tree_from[move_from_id][3] == tree_to[i][0] and move_from_rtype != rtype): # check = "true" if check: text += """<a href="%s/admin/websearch/websearchadmin.py/modifycollectiontree?colID=%s&ln=%s&move_from=%s&move_to=%s%s&rtype=%s#tree"><img border="0" src="%s/img/move_to.gif" title="Move '%s' to '%s'"></a> """ % (weburl, colID, ln, move_from, rtype, i, rtype, weburl, col_dict[tree_from[int(move_from[1:len(move_from)])][0]], col_dict[tree_to[i][0]]) else: try: text += """<a href="%s/admin/websearch/websearchadmin.py/modifycollectiontree?colID=%s&ln=%s&move_from=%s%s&rtype=%s#%s"><img border="0" src="%s/img/move_from.gif" title="Move '%s' from this location."></a>""" % (weburl, colID, ln, rtype, i, rtype, tree[i][0], weburl, col_dict[tree[i][0]]) except KeyError: pass else: text += """<img border="0" src="%s/img/white_field.gif"> """ % weburl else: text += """<img border="0" src="%s/img/white_field.gif"> """ % weburl text += """ </td> <td>""" if edit: try: text += """<a href="%s/admin/websearch/websearchadmin.py/modifycollectiontree?colID=%s&ln=%s&delete=%s&rtype=%s#%s"><img border="0" src="%s/img/iconcross.gif" title="Remove colletion from tree"></a>""" % (weburl, colID, ln, i, rtype, tree[i][0], weburl) except KeyError: pass elif i != 0: text += """<img border="0" src="%s/img/white_field.gif"> """ % weburl text += """</td><td> """ if tmove_from: move_from = tmove_from try: text += """<a name="%s"></a>%s<a href="%s/admin/websearch/websearchadmin.py/editcollection?colID=%s&ln=%s" title="Edit collection">%s</a>%s%s%s""" % (tree[i][0], (reltype=="v" and '<i>' or ''), weburl, tree[i][0], ln, col_dict[id_son], (move_to=="%s%s" %(rtype,i) and ' <img border="0" src="%s/img/move_to.gif">' % weburl or ''), (move_from=="%s%s" % (rtype,i) and ' <img border="0" src="%s/img/move_from.gif">' % weburl or ''), (reltype=="v" and '</i>' or '')) except KeyError: pass text += """</td></tr> """ while tables > 0: text += """</table></td></tr> """ tables = tables - 1 text += """</table> """ return text def perform_deletecollection(colID, ln, confirm=-1, callback='yes'): """form to delete a collection colID - id of collection """ subtitle ='' output = """ <span class="warning"> <strong> <dl> <dt>WARNING:</dt> <dd>When deleting a collection, you also deletes all data related to the collection like translations, relations to other collections and information about which rank methods to use. <br>For more information, please go to the <a title="See guide" href="%s/admin/websearch/guide.html">WebSearch guide</a> and read the section regarding deleting a collection.</dd> </dl> </strong> </span> """ % weburl col_dict = dict(get_def_name('', "collection")) if colID !=1 and colID and col_dict.has_key(int(colID)): colID = int(colID) subtitle = """<a name="4">4. Delete collection '%s'</a>   <small>[<a title="See guide" href="%s/admin/websearch/guide.html#3.4">?</a>]</small>""" % (col_dict[colID], weburl) res = run_sql("SELECT * from collection_collection WHERE id_dad=%s" % colID) res2 = run_sql("SELECT * from collection_collection WHERE id_son=%s" % colID) if not res and not res2: if confirm in ["-1", -1]: text = """Do you want to delete this collection.""" output += createhiddenform(action="deletecollection#4", text=text, colID=colID, button="Delete", confirm=0) elif confirm in ["0", 0]: text = """Are you sure you want to delete this collection.""" output += createhiddenform(action="deletecollection#4", text=text, colID=colID, button="Confirm", confirm=1) elif confirm in ["1", 1]: result = delete_col(colID) if not result: raise StandardException else: output = """<b><span class="info">Can not delete a collection that is a part of the collection tree, remove collection from the tree and try again.</span></b>""" else: subtitle = """4. Delete collection""" output = """<b><span class="info">Not possible to delete the root collection</span></b>""" try: body = [output, extra] except NameError: body = [output] if callback: return perform_editcollection(colID, ln, "perform_deletecollection", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_editcollection(colID=1, ln=cdslang, mtype='', content=''): """interface to modify a collection. 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. colID - id of the collection mtype - the method that called this method. content - the output from that method.""" colID = int(colID) col_dict = dict(get_def_name('', "collection")) if not col_dict.has_key(colID): return """<b><span class="info">Collection deleted.</span></b> """ fin_output = """ <table> <tr> <td><b>Menu</b></td> </tr> <tr> <td>0. <small><a href="editcollection?colID=%s&ln=%s">Show all</a></small></td> <td>1. <small><a href="editcollection?colID=%s&ln=%s&mtype=perform_modifydbquery">Modify collection query</a></small></td> <td>2. <small><a href="editcollection?colID=%s&ln=%s&mtype=perform_modifyrestricted">Modify access restrictions</a></small></td> <td>3. <small><a href="editcollection?colID=%s&ln=%s&mtype=perform_modifytranslations">Modify translations</a></small></td> <td>4. <small><a href="editcollection?colID=%s&ln=%s&mtype=perform_deletecollection">Delete collection</a></small></td> </tr><tr> <td>5. <small><a href="editcollection?colID=%s&ln=%s&mtype=perform_showportalboxes">Modify portalboxes</a></small></td> <td>6. <small><a href="editcollection?colID=%s&ln=%s&mtype=perform_showsearchfields#6">Modify search fields</a></small></td> <td>7. <small><a href="editcollection?colID=%s&ln=%s&mtype=perform_showsearchoptions#7">Modify search options</a></small></td> <td>8. <small><a href="editcollection?colID=%s&ln=%s&mtype=perform_showsortoptions#8">Modify sort options</a></small></td> <td>9. <small><a href="editcollection?colID=%s&ln=%s&mtype=perform_modifyrankmethods#9">Modify rank options</a></small></td> </tr><tr> <td>10.<small><a href="editcollection?colID=%s&ln=%s&mtype=perform_showoutputformats#10">Modify output formats</a></small></td> + <td>11.<small><a href="editcollection?colID=%s&ln=%s&mtype=perform_manage_external_collections#11">Configuration of external search engines</a></small></td> </tr> </table> - """ % (colID, ln, colID, ln, colID, ln, colID, ln, colID, ln, colID, ln, colID, ln, colID, ln, colID, ln, colID, ln, colID, ln) + """ % (colID, ln, colID, ln, colID, ln, colID, ln, colID, ln, colID, ln, colID, ln, colID, ln, colID, ln, colID, ln, colID, ln, colID, ln) if mtype == "perform_modifydbquery" and content: fin_output += content elif mtype == "perform_modifydbquery" or not mtype: fin_output += perform_modifydbquery(colID, ln, callback='') if mtype == "perform_modifyrestricted" and content: fin_output += content elif mtype == "perform_modifyrestricted" or not mtype: fin_output += perform_modifyrestricted(colID, ln, callback='') if mtype == "perform_modifytranslations" and content: fin_output += content elif mtype == "perform_modifytranslations" or not mtype: fin_output += perform_modifytranslations(colID, ln, callback='') if mtype == "perform_deletecollection" and content: fin_output += content elif mtype == "perform_deletecollection" or not mtype: fin_output += perform_deletecollection(colID, ln, callback='') if mtype == "perform_showportalboxes" and content: fin_output += content elif mtype == "perform_showportalboxes" or not mtype: fin_output += perform_showportalboxes(colID, ln, callback='') if mtype == "perform_showsearchfields" and content: fin_output += content elif mtype == "perform_showsearchfields" or not mtype: fin_output += perform_showsearchfields(colID, ln, callback='') if mtype == "perform_showsearchoptions" and content: fin_output += content elif mtype == "perform_showsearchoptions" or not mtype: fin_output += perform_showsearchoptions(colID, ln, callback='') if mtype == "perform_showsortoptions" and content: fin_output += content elif mtype == "perform_showsortoptions" or not mtype: fin_output += perform_showsortoptions(colID, ln, callback='') if mtype == "perform_modifyrankmethods" and content: fin_output += content elif mtype == "perform_modifyrankmethods" or not mtype: fin_output += perform_modifyrankmethods(colID, ln, callback='') if mtype == "perform_showoutputformats" and content: fin_output += content elif mtype == "perform_showoutputformats" or not mtype: fin_output += perform_showoutputformats(colID, ln, callback='') - + + if mtype == "perform_manage_external_collections" and content: + fin_output += content + elif mtype == "perform_manage_external_collections" or not mtype: + fin_output += perform_manage_external_collections(colID, ln, callback='') + return addadminbox("Overview of edit options for collection '%s'" % col_dict[colID], [fin_output]) def perform_checkwebcollstatus(colID, ln, confirm=0, callback='yes'): """Check status of the collection tables with respect to the webcoll cache.""" subtitle = """<a name="11"></a>Webcoll Status   [<a href="%s/admin/websearch/guide.html#4">?</a>]""" % weburl output = "" colID = int(colID) col_dict = dict(get_def_name('', "collection")) output += """<br><b>Last updates:</b><br>""" collection_table_update_time = "" collection_web_update_time = "" res = run_sql("SHOW TABLE STATUS LIKE 'collection'") if res: collection_table_update_time = re.sub(r'\.00$', '', str(res[0][11])) output += "Collection table last updated: %s<br>" % collection_table_update_time try: file = open("%s/collections/1/last-updated-ln=en.html" % cachedir) collection_web_update_time = string.strip(file.readline()) collection_web_update_time = re.sub(r'[A-Z ]+$', '', collection_web_update_time) output += "Collection webpage last updated: %s<br>" % collection_web_update_time file.close() except StandardError, e: pass # reformat collection_web_update_time to the format suitable for comparisons try: collection_web_update_time = time.strftime("%Y-%m-%d %H:%M:%S", time.strptime(collection_web_update_time, "%d %b %Y %H:%M:%S")) except ValueError, e: pass if collection_table_update_time > collection_web_update_time: output += """<br><b><span class="info">Warning: The collections has been modified since last time Webcoll was executed, to process the changes, Webcoll must be executed.</span></b><br>""" header = ['ID', 'Name', 'Time', 'Status', 'Progress'] actions = [] output += """<br><b>Last BibSched tasks:</b><br>""" res = run_sql("select id, proc, host, user, runtime, sleeptime, arguments, status, progress from schTASK where proc='webcoll' and runtime< now() ORDER by runtime") if len(res) > 0: (id, proc, host, user, runtime, sleeptime, arguments, status, progress) = res[len(res) - 1] webcoll__update_time = runtime actions.append([id, proc, runtime, (status !="" and status or ''), (progress !="" and progress or '')]) else: actions.append(['', 'webcoll', '', '', 'Not executed yet']) res = run_sql("select id, proc, host, user, runtime, sleeptime, arguments, status, progress from schTASK where proc='bibindex' and runtime< now() ORDER by runtime") if len(res) > 0: (id, proc, host, user, runtime, sleeptime, arguments, status, progress) = res[len(res) - 1] actions.append([id, proc, runtime, (status !="" and status or ''), (progress !="" and progress or '')]) else: actions.append(['', 'bibindex', '', '', 'Not executed yet']) output += tupletotable(header=header, tuple=actions) output += """<br><b>Next scheduled BibSched run:</b><br>""" actions = [] res = run_sql("select id, proc, host, user, runtime, sleeptime, arguments, status, progress from schTASK where proc='webcoll' and runtime > now() ORDER by runtime") webcoll_future = "" if len(res) > 0: (id, proc, host, user, runtime, sleeptime, arguments, status, progress) = res[0] webcoll__update_time = runtime actions.append([id, proc, runtime, (status !="" and status or ''), (progress !="" and progress or '')]) webcoll_future = "yes" else: actions.append(['', 'webcoll', '', '', 'Not scheduled']) res = run_sql("select id, proc, host, user, runtime, sleeptime, arguments, status, progress from schTASK where proc='bibindex' and runtime > now() ORDER by runtime") bibindex_future = "" if len(res) > 0: (id, proc, host, user, runtime, sleeptime, arguments, status, progress) = res[0] actions.append([id, proc, runtime, (status !="" and status or ''), (progress !="" and progress or '')]) bibindex_future = "yes" else: actions.append(['', 'bibindex', '', '', 'Not scheduled']) output += tupletotable(header=header, tuple=actions) if webcoll_future == "": output += """<br><b><span class="info">Warning: Webcoll is not scheduled for a future run by bibsched, any updates to the collection will not be processed.</span></b><br>""" if bibindex_future == "": output += """<br><b><span class="info">Warning: Bibindex is not scheduled for a future run by bibsched, any updates to the records will not be processed.</span></b><br>""" try: body = [output, extra] except NameError: body = [output] if callback: return perform_index(colID, ln, "perform_checkwebcollstatus", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) def perform_checkcollectionstatus(colID, ln, confirm=0, callback='yes'): """Check the configuration of the collections.""" subtitle = """<a name="11"></a>Collections Status   [<a href="%s/admin/websearch/guide.html#5">?</a>]""" % weburl output = "" colID = int(colID) col_dict = dict(get_def_name('', "collection")) collections = run_sql("SELECT id, name, dbquery, restricted FROM collection ORDER BY id") header = ['ID', 'Name', 'Query', 'Subcollections', 'Restricted', 'I18N','Status'] rnk_list = get_def_name('', "rnkMETHOD") actions = [] for (id, name, dbquery, restricted) in collections: reg_sons = len(get_col_tree(id, 'r')) vir_sons = len(get_col_tree(id, 'v')) status = "" langs = run_sql("SELECT ln from collectionname where id_collection=%s" % id) i8n = "" if len(langs) > 0: for lang in langs: i8n += "%s, " % lang else: i8n = """<b><span class="info">None</span></b>""" if (reg_sons > 1 and dbquery) or dbquery=="": status = """<b><span class="warning">1:Query</span></b>""" elif dbquery is None and reg_sons == 1: status = """<b><span class="warning">2:Query</span></b>""" elif dbquery == "" and reg_sons == 1: status = """<b><span class="warning">3:Query</span></b>""" if (reg_sons > 1 or vir_sons > 1): subs = """<b><span class="info">Yes</span></b>""" else: subs = """<b><span class="info">No</span></b>""" if dbquery is None: dbquery = """<b><span class="info">No</span></b>""" if restricted == "": restricted = "" if status: status += """<b><span class="warning">,4:Restricted</span></b>""" else: status += """<b><span class="warning">4:Restricted</span></b>""" elif restricted is None: restricted = """<b><span class="info">No</span></b>""" if status == "": status = """<b><span class="info">OK</span></b>""" actions.append([id, """<a href="%s/admin/websearch/websearchadmin.py/editcollection?colID=%s&ln=%s">%s</a>""" % (weburl, id, ln, name), dbquery, subs, restricted, i8n, status]) output += tupletotable(header=header, tuple=actions) try: body = [output, extra] except NameError: body = [output] return addadminbox(subtitle, body) if callback: return perform_index(colID, ln, "perform_checkcollectionstatus", addadminbox(subtitle, body)) else: return addadminbox(subtitle, body) -def perform_removeoutputformat(colID, ln, fmtID='', callback='yes', confirm=0): - """form to remove an output format from a collection. - colID - the collection id of the current collection. - fmtID - the format id. - """ - - subtitle = """<a name="10.5"></a>Remove output format""" - output = "" - - col_dict = dict(get_def_name('', "collection")) - fmt_dict = dict(get_def_name('', "format")) - - if colID and fmtID: - colID = int(colID) - fmtID = int(fmtID) - - if confirm in ["0", 0]: - text = """Do you want to remove the output format '%s' from the collection '%s'.""" % (fmt_dict[fmtID], col_dict[colID]) - output += createhiddenform(action="removeoutputformat#10.5", - text=text, - button="Confirm", - colID=colID, - fmtID=fmtID, - confirm=1) - elif confirm in ["1", 1]: - res = remove_fmt(colID, fmtID) - output += write_outcome(res) - try: - body = [output, extra] - except NameError: - body = [output] - - output = "<br>" + addadminbox(subtitle, body) - return perform_showoutputformats(colID, ln, content=output) - def get_col_tree(colID, rtype=''): """Returns a presentation of the tree as a list. TODO: Add loop detection colID - startpoint for the tree rtype - get regular or virtual part of the tree""" try: colID = int(colID) stack = [colID] ssize = 0 tree = [(colID, 0, 0, colID, 'r')] while len(stack) > 0: ccolID = stack.pop() if ccolID == colID and rtype: res = run_sql("SELECT id_son, score, type FROM collection_collection WHERE id_dad=%s AND type='%s' ORDER BY score ASC,id_son" % (ccolID,rtype)) else: res = run_sql("SELECT id_son, score, type FROM collection_collection WHERE id_dad=%s ORDER BY score ASC,id_son" % ccolID) ssize += 1 ntree = [] for i in range(0,len(res)): id_son = res[i][0] score = res[i][1] rtype = res[i][2] stack.append(id_son) if i == (len(res) - 1): up = 0 else: up = 1 if i == 0: down = 0 else: down = 1 ntree.insert(0, (id_son, up, down, ccolID, rtype)) tree = tree[0:ssize] + ntree + tree[ssize:len(tree)] return tree except StandardError, e: return () def add_col_dad_son(add_dad, add_son, rtype): """Add a son to a collection (dad) add_dad - add to this collection id add_son - add this collection id rtype - either regular or virtual""" try: res = run_sql("SELECT score FROM collection_collection WHERE id_dad=%s ORDER BY score ASC" % add_dad) highscore = 0 for score in res: if int(score[0]) > highscore: highscore = int(score[0]) highscore += 1 res = run_sql("INSERT INTO collection_collection(id_dad,id_son,score,type) values(%s,%s,%s,'%s')" % (add_dad, add_son, highscore, rtype)) return (1, highscore) except StandardError, e: return (0, e) def compare_on_val(first, second): """Compare the two values""" return cmp(first[1], second[1]) def get_col_fld(colID=-1, type = '', id_field=''): """Returns either all portalboxes associated with a collection, or based on either colID or language or both. colID - collection id ln - language id""" sql = "SELECT id_field,id_fieldvalue,type,score,score_fieldvalue FROM collection_field_fieldvalue, field WHERE id_field=field.id" try: if colID > -1: sql += " AND id_collection=%s" % colID if id_field: sql += " AND id_field=%s" % id_field if type: sql += " AND type='%s'" % type sql += " ORDER BY type, score desc, score_fieldvalue desc" res = run_sql(sql) return res except StandardError, e: return "" def get_col_pbx(colID=-1, ln='', position = ''): """Returns either all portalboxes associated with a collection, or based on either colID or language or both. colID - collection id ln - language id""" sql = "SELECT id_portalbox, id_collection, ln, score, position, title, body FROM collection_portalbox, portalbox WHERE id_portalbox = portalbox.id" try: if colID > -1: sql += " AND id_collection=%s" % colID if ln: sql += " AND ln='%s'" % ln if position: sql += " AND position='%s'" % position sql += " ORDER BY position, ln, score desc" res = run_sql(sql) return res except StandardError, e: return "" def get_col_fmt(colID=-1): """Returns all formats currently associated with a collection, or for one specific collection colID - the id of the collection""" try: if colID not in [-1, "-1"]: res = run_sql("SELECT id_format, id_collection, code, score FROM collection_format, format WHERE id_format = format.id AND id_collection=%s ORDER BY score desc" % colID) else: res = run_sql("SELECT id_format, id_collection, code, score FROM collection_format, format WHERE id_format = format.id ORDER BY score desc") return res except StandardError, e: return "" def get_col_rnk(colID, ln): """ Returns a list of the rank methods the given collection is attached to colID - id from collection""" try: res1 = dict(run_sql("SELECT id_rnkMETHOD, '' FROM collection_rnkMETHOD WHERE id_collection=%s" % colID)) res2 = get_def_name('', "rnkMETHOD") result = filter(lambda x: res1.has_key(x[0]), res2) return result except StandardError, e: return () def get_pbx(): """Returns all portalboxes""" try: res = run_sql("SELECT id, title, body FROM portalbox ORDER by title,body") return res except StandardError, e: return "" def get_fld_value(fldvID = ''): """Returns fieldvalue""" try: sql = "SELECT id, name, value FROM fieldvalue" if fldvID: sql += " WHERE id=%s" % fldvID sql += " ORDER BY name" res = run_sql(sql) return res except StandardError, e: return "" def get_pbx_pos(): """Returns a list of all the positions for a portalbox""" position = {} position["rt"] = "Right Top" position["lt"] = "Left Top" position["te"] = "Title Epilog" position["tp"] = "Title Prolog" position["ne"] = "Narrow by coll epilog" position["np"] = "Narrow by coll prolog" return position def get_sort_nametypes(): """Return a list of the various translationnames for the fields""" type = {} type['soo'] = 'Sort options' type['seo'] = 'Search options' type['sew'] = 'Search within' return type def get_fmt_nametypes(): """Return a list of the various translationnames for the output formats""" type = [] type.append(('ln', 'Long name')) return type def get_fld_nametypes(): """Return a list of the various translationnames for the fields""" type = [] type.append(('ln', 'Long name')) return type def get_col_nametypes(): """Return a list of the various translationnames for the collections""" type = [] type.append(('ln', 'Long name')) return type def find_last(tree, start_son): """Find the previous collection in the tree with the same father as start_son""" id_dad = tree[start_son][3] while start_son > 0: start_son -= 1 if tree[start_son][3] == id_dad: return start_son def find_next(tree, start_son): """Find the next collection in the tree with the same father as start_son""" id_dad = tree[start_son][3] while start_son < len(tree): start_son += 1 if tree[start_son][3] == id_dad: return start_son def remove_col_subcol(id_son, id_dad, type): """Remove a collection as a son of another collection in the tree, if collection isn't used elsewhere in the tree, remove all registered sons of the id_son. id_son - collection id of son to remove id_dad - the id of the dad""" try: if id_son != id_dad: tree = get_col_tree(id_son) res = run_sql("DELETE FROM collection_collection WHERE id_son=%s and id_dad=%s" % (id_son, id_dad)) else: tree = get_col_tree(id_son, type) res = run_sql("DELETE FROM collection_collection WHERE id_son=%s and id_dad=%s and type='%s'" % (id_son, id_dad, type)) if not run_sql("SELECT * from collection_collection WHERE id_son=%s and type='%s'" % (id_son, type)): for (id, up, down, dad, rtype) in tree: res = run_sql("DELETE FROM collection_collection WHERE id_son=%s and id_dad=%s" % (id, dad)) return (1, "") except StandardError, e: return (0, e) def check_col(add_dad, add_son): """Check if the collection can be placed as a son of the dad without causing loops. add_dad - collection id add_son - collection id""" try: stack = [add_dad] res = run_sql("SELECT id_dad FROM collection_collection WHERE id_dad=%s AND id_son=%s" % (add_dad,add_son)) if res: raise StandardError while len(stack) > 0: colID = stack.pop() res = run_sql("SELECT id_dad FROM collection_collection WHERE id_son=%s" % colID) for id in res: if int(id[0]) == int(add_son): raise StandardError else: stack.append(id[0]) return (1, "") except StandardError, e: return (0, e) def attach_rnk_col(colID, rnkID): """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_rnk_col(colID, rnkID): """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 switch_col_treescore(col_1, col_2): try: res1 = run_sql("SELECT score FROM collection_collection WHERE id_dad=%s and id_son=%s" % (col_1[3], col_1[0])) res2 = run_sql("SELECT score FROM collection_collection WHERE id_dad=%s and id_son=%s" % (col_2[3], col_2[0])) res = run_sql("UPDATE collection_collection SET score=%s WHERE id_dad=%s and id_son=%s" % (res2[0][0], col_1[3], col_1[0])) res = run_sql("UPDATE collection_collection SET score=%s WHERE id_dad=%s and id_son=%s" % (res1[0][0], col_2[3], col_2[0])) return (1, "") except StandardError, e: return (0, e) def move_col_tree(col_from, col_to, move_to_rtype=''): """Move a collection from one point in the tree to another. becomes a son of the endpoint. col_from - move this collection from current point col_to - and set it as a son of this collection. move_to_rtype - either virtual or regular collection""" try: res = run_sql("SELECT score FROM collection_collection WHERE id_dad=%s ORDER BY score asc" % col_to[0]) highscore = 0 for score in res: if int(score[0]) > highscore: highscore = int(score[0]) highscore += 1 if not move_to_rtype: move_to_rtype = col_from[4] res = run_sql("DELETE FROM collection_collection WHERE id_son=%s and id_dad=%s" % (col_from[0], col_from[3])) res = run_sql("INSERT INTO collection_collection(id_dad,id_son,score,type) values(%s,%s,%s,'%s')" % (col_to[0], col_from[0], highscore, move_to_rtype)) return (1, "") except StandardError, e: return (0, e) def remove_pbx(colID, pbxID, ln): """Removes a portalbox from the collection given. colID - the collection the format is connected to pbxID - the portalbox which should be removed from the collection. ln - the language of the portalbox to be removed""" try: res = run_sql("DELETE FROM collection_portalbox WHERE id_collection=%s AND id_portalbox=%s AND ln='%s'" % (colID, pbxID, ln)) return (1, "") except StandardError, e: return (0, e) def remove_fmt(colID,fmtID): """Removes a format from the collection given. colID - the collection the format is connected to fmtID - the format which should be removed from the collection.""" try: res = run_sql("DELETE FROM collection_format WHERE id_collection=%s AND id_format=%s" % (colID, fmtID)) return (1, "") except StandardError, e: return (0, e) def remove_fld(colID,fldID, fldvID=''): """Removes a field from the collection given. colID - the collection the format is connected to fldID - the field which should be removed from the collection.""" try: sql = "DELETE FROM collection_field_fieldvalue WHERE id_collection=%s AND id_field=%s" % (colID, fldID) if fldvID: if fldvID != "None": sql += " AND id_fieldvalue=%s" % fldvID else: sql += " AND id_fieldvalue is NULL" res = run_sql(sql) return (1, "") except StandardError, e: return (0, e) def delete_fldv(fldvID): """Deletes all data for the given fieldvalue fldvID - delete all data in the tables associated with fieldvalue and this id""" try: res = run_sql("DELETE FROM collection_field_fieldvalue WHERE id_fieldvalue=%s" % fldvID) res = run_sql("DELETE FROM fieldvalue WHERE id=%s" % fldvID) return (1, "") except StandardError, e: return (0, e) def delete_pbx(pbxID): """Deletes all data for the given portalbox pbxID - delete all data in the tables associated with portalbox and this id """ try: res = run_sql("DELETE FROM collection_portalbox WHERE id_portalbox=%s" % pbxID) res = run_sql("DELETE FROM portalbox WHERE id=%s" % pbxID) return (1, "") except StandardError, e: return (0, e) def delete_fmt(fmtID): """Deletes all data for the given format fmtID - delete all data in the tables associated with format and this id """ try: res = run_sql("DELETE FROM format WHERE id=%s" % fmtID) res = run_sql("DELETE FROM collection_format WHERE id_format=%s" % fmtID) res = run_sql("DELETE FROM formatname WHERE id_format=%s" % fmtID) return (1, "") except StandardError, e: return (0, e) def delete_col(colID): """Deletes all data for the given collection colID - delete all data in the tables associated with collection and this id """ try: res = run_sql("DELETE FROM collection WHERE id=%s" % colID) res = run_sql("DELETE FROM collectionname WHERE id_collection=%s" % colID) res = run_sql("DELETE FROM collection_rnkMETHOD WHERE id_collection=%s" % colID) res = run_sql("DELETE FROM collection_collection WHERE id_dad=%s" % colID) res = run_sql("DELETE FROM collection_collection WHERE id_son=%s" % colID) res = run_sql("DELETE FROM collection_portalbox WHERE id_collection=%s" % colID) res = run_sql("DELETE FROM collection_format WHERE id_collection=%s" % colID) res = run_sql("DELETE FROM collection_field_fieldvalue WHERE id_collection=%s" % colID) return (1, "") except StandardError, e: return (0, e) def add_fmt(code, name, rtype): """Add a new output format. Returns the id of the format. code - the code for the format, max 6 chars. name - the default name for the default language of the format. rtype - the default nametype""" try: res = run_sql("INSERT INTO format (code, name) values ('%s','%s')" % (escape_string(code), escape_string(name))) fmtID = run_sql("SELECT id FROM format WHERE code='%s'" % escape_string(code)) res = run_sql("INSERT INTO formatname(id_format, type, ln, value) VALUES (%s,'%s','%s','%s')" % (fmtID[0][0], rtype, cdslang, escape_string(name))) return (1, fmtID) except StandardError, e: return (0, e) def update_fldv(fldvID, name, value): """Modify existing fieldvalue fldvID - id of fieldvalue to modify value - the value of the fieldvalue name - the name of the fieldvalue.""" try: res = run_sql("UPDATE fieldvalue set name='%s' where id=%s" % (escape_string(name), fldvID)) res = run_sql("UPDATE fieldvalue set value='%s' where id=%s" % (escape_string(value), fldvID)) return (1, "") except StandardError, e: return (0, e) def add_fldv(name, value): """Add a new fieldvalue, returns id of fieldvalue value - the value of the fieldvalue name - the name of the fieldvalue.""" try: res = run_sql("SELECT id FROM fieldvalue WHERE name='%s' and value='%s'" % (escape_string(name), escape_string(value))) if not res: res = run_sql("INSERT INTO fieldvalue (name, value) values ('%s','%s')" % (escape_string(name), escape_string(value))) res = run_sql("SELECT id FROM fieldvalue WHERE name='%s' and value='%s'" % (escape_string(name), escape_string(value))) if res: return (1, res[0][0]) else: raise StandardError except StandardError, e: return (0, e) def add_pbx(title, body): try: res = run_sql("INSERT INTO portalbox (title, body) values ('%s','%s')" % (escape_string(title), escape_string(body))) res = run_sql("SELECT id FROM portalbox WHERE title='%s' AND body='%s'" % (escape_string(title), escape_string(body))) if res: return (1, res[0][0]) else: raise StandardError except StandardError, e: return (0, e) def add_col(colNAME, dbquery, rest): """Adds a new collection to collection table colNAME - the default name for the collection, saved to collection and collectionname dbquery - query related to the collection rest - name of apache group allowed to access collection""" try: rtype = get_col_nametypes()[0][0] colID = run_sql("SELECT id FROM collection WHERE id=1") if colID: sql = "INSERT INTO collection(name,dbquery,restricted) VALUES('%s'" % escape_string(colNAME) else: sql = "INSERT INTO collection(id,name,dbquery,restricted) VALUES(1,'%s'" % escape_string(colNAME) if dbquery: sql += ",'%s'" % escape_string(dbquery) else: sql += ",null" if rest: sql += ",'%s'" % escape_string(rest) else: sql += ",null" sql += ")" res = run_sql(sql) colID = run_sql("SELECT id FROM collection WHERE name='%s'" % escape_string(colNAME)) res = run_sql("INSERT INTO collectionname(id_collection, type, ln, value) VALUES (%s,'%s','%s','%s')" % (colID[0][0], rtype, cdslang, escape_string(colNAME))) if colID: return (1, colID[0][0]) else: raise StandardError except StandardError, e: return (0, e) def add_col_pbx(colID, pbxID, ln, position, score=''): """add a portalbox to the collection. colID - the id of the collection involved pbxID - the portalbox to add ln - which language the portalbox is for score - decides which portalbox is the most important position - position on page the portalbox should appear.""" try: if score: res = run_sql("INSERT INTO collection_portalbox(id_portalbox, id_collection, ln, score, position) values (%s,%s,'%s',%s,'%s')" % (pbxID, colID, ln, score, position)) else: res = run_sql("SELECT score FROM collection_portalbox WHERE id_collection=%s and ln='%s' and position='%s' ORDER BY score desc, ln, position" % (colID, ln, position)) if res: score = int(res[0][0]) else: score = 0 res = run_sql("INSERT INTO collection_portalbox(id_portalbox, id_collection, ln, score, position) values (%s,%s,'%s',%s,'%s')" % (pbxID, colID, ln, (score + 1), position)) return (1, "") except StandardError, e: return (0, e) def add_col_fmt(colID, fmtID, score=''): """Add a output format to the collection. colID - the id of the collection involved fmtID - the id of the format. score - the score of the format, decides sorting, if not given, place the format on top""" try: if score: res = run_sql("INSERT INTO collection_format(id_format, id_collection, score) values (%s,%s,%s)" % (fmtID, colID, score)) else: res = run_sql("SELECT score FROM collection_format WHERE id_collection=%s ORDER BY score desc" % colID) if res: score = int(res[0][0]) else: score = 0 res = run_sql("INSERT INTO collection_format(id_format, id_collection, score) values (%s,%s,%s)" % (fmtID, colID, (score + 1))) return (1, "") except StandardError, e: return (0, e) def add_col_fld(colID, fldID, type, fldvID=''): """Add a sort/search/field to the collection. colID - the id of the collection involved fldID - the id of the field. fldvID - the id of the fieldvalue. type - which type, seo, sew... score - the score of the format, decides sorting, if not given, place the format on top""" try: if fldvID and fldvID not in [-1, "-1"]: run_sql("DELETE FROM collection_field_fieldvalue WHERE id_collection=%s AND id_field=%s and type='%s' and id_fieldvalue is NULL" % (colID, fldID, type)) res = run_sql("SELECT score FROM collection_field_fieldvalue WHERE id_collection=%s AND id_field=%s and type='%s' ORDER BY score desc" % (colID, fldID, type)) if res: score = int(res[0][0]) res = run_sql("SELECT score_fieldvalue FROM collection_field_fieldvalue WHERE id_collection=%s AND id_field=%s and type='%s' ORDER BY score_fieldvalue desc" % (colID, fldID, type)) else: res = run_sql("SELECT score FROM collection_field_fieldvalue WHERE id_collection=%s and type='%s' ORDER BY score desc" % (colID, type)) if res: score = int(res[0][0]) + 1 else: score = 1 res = run_sql("SELECT * FROM collection_field_fieldvalue where id_field=%s and id_collection=%s and type='%s' and id_fieldvalue=%s" % (fldID, colID, type, fldvID)) if not res: run_sql("UPDATE collection_field_fieldvalue SET score_fieldvalue=score_fieldvalue+1 WHERE id_field=%s AND id_collection=%s and type='%s'" % (fldID, colID, type)) res = run_sql("INSERT INTO collection_field_fieldvalue(id_field, id_fieldvalue, id_collection, type, score, score_fieldvalue) values (%s,%s,%s,'%s',%s,%s)" % (fldID, fldvID, colID, type, score, 1)) else: return (0, (1, "Already exists")) else: res = run_sql("SELECT * FROM collection_field_fieldvalue WHERE id_collection=%s AND type='%s' and id_field=%s and id_fieldvalue is NULL" % (colID, type, fldID)) if res: return (0, (1, "Already exists")) else: run_sql("UPDATE collection_field_fieldvalue SET score=score+1") res = run_sql("INSERT INTO collection_field_fieldvalue(id_field, id_collection, type, score,score_fieldvalue) values (%s,%s,'%s',%s, 0)" % (fldID, colID, type, 1)) return (1, "") except StandardError, e: return (0, e) def modify_restricted(colID, rest): """Modify which apache group is allowed to use the collection. colID - the id of the collection involved restricted - the new group""" try: sql = "UPDATE collection SET restricted=" if rest: sql += "'%s'" % escape_string(rest) else: sql += "null" sql += " WHERE id=%s" % colID res = run_sql(sql) return (1, "") except StandardError, e: return (0, e) def modify_dbquery(colID, dbquery): """Modify the dbquery of an collection. colID - the id of the collection involved dbquery - the new dbquery""" try: sql = "UPDATE collection SET dbquery=" if dbquery: sql += "'%s'" % escape_string(dbquery) else: sql += "null" sql += " WHERE id=%s" % colID res = run_sql(sql) return (1, "") except StandardError, e: return (0, e) def modify_pbx(colID, pbxID, sel_ln, score='', position='', title='', body=''): """Modify a portalbox colID - the id of the collection involved pbxID - the id of the portalbox that should be modified sel_ln - the language of the portalbox that should be modified title - the title body - the content score - if several portalboxes in one position, who should appear on top. position - position on page""" try: if title: res = run_sql("UPDATE portalbox SET title='%s' WHERE id=%s" % (escape_string(title), pbxID)) if body: res = run_sql("UPDATE portalbox SET body='%s' WHERE id=%s" % (escape_string(body), pbxID)) if score: res = run_sql("UPDATE collection_portalbox SET score='%s' WHERE id_collection=%s and id_portalbox=%s and ln='%s'" % (score, colID, pbxID, sel_ln)) if position: res = run_sql("UPDATE collection_portalbox SET position='%s' WHERE id_collection=%s and id_portalbox=%s and ln='%s'" % (position, colID, pbxID, sel_ln)) return (1, "") except Exception, e: return (0, e) def switch_fld_score(colID, id_1, id_2): """Switch the scores of id_1 and id_2 in collection_field_fieldvalue colID - collection the id_1 or id_2 is connected to id_1/id_2 - id field from tables like format..portalbox... table - name of the table""" try: res1 = run_sql("SELECT score FROM collection_field_fieldvalue WHERE id_collection=%s and id_field=%s" % (colID, id_1)) res2 = run_sql("SELECT score FROM collection_field_fieldvalue WHERE id_collection=%s and id_field=%s" % (colID, id_2)) if res1[0][0] == res2[0][0]: return (0, (1, "Cannot rearrange the selected fields, either rearrange by name or use the mySQL client to fix the problem.")) else: res = run_sql("UPDATE collection_field_fieldvalue SET score=%s WHERE id_collection=%s and id_field=%s" % (res2[0][0], colID, id_1)) res = run_sql("UPDATE collection_field_fieldvalue SET score=%s WHERE id_collection=%s and id_field=%s" % (res1[0][0], colID, id_2)) return (1, "") except StandardError, e: return (0, e) def switch_fld_value_score(colID, id_1, fldvID_1, fldvID_2): """Switch the scores of two field_value colID - collection the id_1 or id_2 is connected to id_1/id_2 - id field from tables like format..portalbox... table - name of the table""" try: res1 = run_sql("SELECT score_fieldvalue FROM collection_field_fieldvalue WHERE id_collection=%s and id_field=%s and id_fieldvalue=%s" % (colID, id_1, fldvID_1)) res2 = run_sql("SELECT score_fieldvalue FROM collection_field_fieldvalue WHERE id_collection=%s and id_field=%s and id_fieldvalue=%s" % (colID, id_1, fldvID_2)) if res1[0][0] == res2[0][0]: return (0, (1, "Cannot rearrange the selected fields, either rearrange by name or use the mySQL client to fix the problem.")) else: res = run_sql("UPDATE collection_field_fieldvalue SET score_fieldvalue=%s WHERE id_collection=%s and id_field=%s and id_fieldvalue=%s" % (res2[0][0], colID, id_1, fldvID_1)) res = run_sql("UPDATE collection_field_fieldvalue SET score_fieldvalue=%s WHERE id_collection=%s and id_field=%s and id_fieldvalue=%s" % (res1[0][0], colID, id_1, fldvID_2)) return (1, "") except Exception, e: return (0, e) def switch_pbx_score(colID, id_1, id_2, sel_ln): """Switch the scores of id_1 and id_2 in the table given by the argument. colID - collection the id_1 or id_2 is connected to id_1/id_2 - id field from tables like format..portalbox... table - name of the table""" try: res1 = run_sql("SELECT score FROM collection_portalbox WHERE id_collection=%s and id_portalbox=%s and ln='%s'" % (colID, id_1, sel_ln)) res2 = run_sql("SELECT score FROM collection_portalbox WHERE id_collection=%s and id_portalbox=%s and ln='%s'" % (colID, id_2, sel_ln)) if res1[0][0] == res2[0][0]: return (0, (1, "Cannot rearrange the selected fields, either rearrange by name or use the mySQL client to fix the problem.")) res = run_sql("UPDATE collection_portalbox SET score=%s WHERE id_collection=%s and id_portalbox=%s and ln='%s'" % (res2[0][0], colID, id_1, sel_ln)) res = run_sql("UPDATE collection_portalbox SET score=%s WHERE id_collection=%s and id_portalbox=%s and ln='%s'" % (res1[0][0], colID, id_2, sel_ln)) return (1, "") except Exception, e: return (0, e) def switch_score(colID, id_1, id_2, table): """Switch the scores of id_1 and id_2 in the table given by the argument. colID - collection the id_1 or id_2 is connected to id_1/id_2 - id field from tables like format..portalbox... table - name of the table""" try: res1 = run_sql("SELECT score FROM collection_%s WHERE id_collection=%s and id_%s=%s" % (table, colID, table, id_1)) res2 = run_sql("SELECT score FROM collection_%s WHERE id_collection=%s and id_%s=%s" % (table, colID, table, id_2)) if res1[0][0] == res2[0][0]: return (0, (1, "Cannot rearrange the selected fields, either rearrange by name or use the mySQL client to fix the problem.")) res = run_sql("UPDATE collection_%s SET score=%s WHERE id_collection=%s and id_%s=%s" % (table, res2[0][0], colID, table, id_1)) res = run_sql("UPDATE collection_%s SET score=%s WHERE id_collection=%s and id_%s=%s" % (table, res1[0][0], colID, table, id_2)) return (1, "") except Exception, e: return (0, e) diff --git a/modules/websearch/web/admin/websearchadmin.py b/modules/websearch/web/admin/websearchadmin.py index c2c724527..c082808e5 100644 --- a/modules/websearch/web/admin/websearchadmin.py +++ b/modules/websearch/web/admin/websearchadmin.py @@ -1,1055 +1,1077 @@ ## $Id$ ## ## This file is part of CDS Invenio. ## Copyright (C) 2002, 2003, 2004, 2005, 2006 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 WebSearch Administrator Interface.""" __lastupdated__ = """$Date$""" import sys import invenio.websearchadminlib as wsc #reload(wsc) from invenio.webpage import page, create_error_box from invenio.config import weburl, sweburl, cdslang from invenio.dbquery import Error from invenio.webuser import getUid, page_not_authorized from invenio.messages import gettext_set_language __version__ = "$Id$" def switchfmtscore(req, colID, type, id_1, id_2, ln=cdslang): navtrail_previous_links = wsc.getnavtrail() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) +def update_external_collections(req, colID, ln=cdslang, action='', collection_name='', recurse=0): + navtrail_previous_links = wsc.getnavtrail() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) + + try: + uid = getUid(req) + except Error, e: + return error_page(req) + + recurse = int(recurse) + + auth = wsc.check_user(uid,'cfgwebsearch') + if not auth[0]: + return page(title="Edit Collection", + body = wsc.perform_update_external_collections(colID, ln, action, collection_name, 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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 <a href="%s/youraccount/login?referer=%s/admin/websearch/">login</a> 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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 <a href="%s/youraccount/login?referer=%s/admin/websearch/">login</a> 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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 <a href="%s/youraccount/login?referer=%s/admin/websearch/">login</a> 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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 <a href="%s/youraccount/login?referer=%s/admin/websearch/">login</a> 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'cfgwebsearch') if not auth[0]: return page(title="Edit Collection", body=wsc.perform_modifyfieldvalue(colID=colID, 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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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 <a href="%s/youraccount/login?referer=%s/admin/websearch/">login</a> 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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__) 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() + """> <a class=navtrail href="%s/admin/websearch/websearchadmin.py/">Collection Management</a> """ % (weburl) try: uid = getUid(req) except Error, e: return error_page(req) auth = wsc.check_user(uid,'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 = wsc.check_user(uid,'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__) else: return page_not_authorized(req=req, text=auth[1], navtrail=navtrail_previous_links) def error_page(req, ln = cdslang): _ = gettext_set_language(ln) 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) diff --git a/modules/webstyle/css/cds.css b/modules/webstyle/css/cds.css index 59e726f4d..f003aaa01 100644 --- a/modules/webstyle/css/cds.css +++ b/modules/webstyle/css/cds.css @@ -1,1286 +1,1349 @@ /* * -*- mode: text; coding: utf-8; -*- $Id$ This file is part of CDS Invenio. Copyright (C) 2002, 2003, 2004, 2005, 2006 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. */ body { color: #000; background: #fff; margin: 0px; padding: 0px; } h1 { font-size: 173%; font-weight: 700; margin-top: 5px; margin-left: 0px; color: #36c; background: transparent; } .h1 { font-size: 173%; font-weight: 700; margin-left: 0px; color: #36c; background: transparent; } h2 { font-size: 144%; font-weight: 650; margin-left: 0px; color: #36c; background: transparent; } h3 { font-size: 120%; font-weight: 600; font-variant: small-caps; margin-top: 40px; margin-left: 0px; margin-bottom: 10px; color: #36c; background: transparent; border-bottom: dotted 2px #36c; width: 50%; } h4 { font-size: 110%; font-weight: 600; font-style: italic; color: #36c; margin-left: 0px; background: transparent; } h5 { font-size: 110%; font-weight: 400; color: #36c; margin-left: 0px; background: transparent; } h6 { font-size: 110%; font-weight: 200; font-style: italic; color: #36c; margin-left: 0px; background: transparent; } a:link { color: #00c; background: transparent; } a:visited { color: #006; background: transparent; } a:active { color: #00c; background: transparent; } a:hover { color: #00c; background: transparent; } a.moreinfo:link { color: #060; background: transparent; } a.moreinfo:visited { color: #060; background: transparent; } a.moreinfo:active { color: #060; background: transparent; } a.moreinfo:hover { color: #060; background: transparent; } a.img:hover { color: #00c; background: transparent; } a.img:active { color: #00c; background: transparent; font-weight: normal; } a.note:link { color: #666; background: transparent; } a.note:visited { color: #666; background: transparent; } a.note:active { color: #666; background: transparent; } a.note:hover { color: #666; background: transparent; } .headerbox { color: #000; background: transparent; width: 100%; padding: 0px; margin-top: 0px; margin-bottom: 0px; border-collapse: collapse; border-bottom: 2px solid #3366cc; } .headerboxbody { color: #000; padding: 0px; margin: 0px; } .headerboxbodylogo { width: 200px; padding-left: 5px; color: #36c; font-size: 20px; font-weight: bold; font-variant: small-caps; letter-spacing: 6px; } .headermodulebox { color: #fff; background: transparent; border-collapse: collapse; margin: 0px; padding: 0px; } .headermoduleboxbody { color: #000; background: #36c; font-size: x-small; font-weight: bold; text-align: center; margin: 0px; padding: 0px; width: 75px; } .headermoduleboxbodyblank { width: 12px; padding: 0px; margin: 0px; } .headermoduleboxbodyselected { color: #000; background: #fff; font-size: x-small; font-weight: bold; text-align: center; border-left: 2px solid #36c; border-right: 2px solid #36c; border-top: 2px solid #36c; margin: 5px; padding: 0px; width: 75px; } a.header:link { color: #fff; background: #36c; text-decoration: none; } a.header:visited { color: #fff; background: #36c; text-decoration: none; } a.header:active { color: #fff; background: #36c; text-decoration: none; } a.header:hover { color: #fff; background: #36c; text-decoration: none; } a.headerselected:link { color: #36c; background: #fff; text-decoration: none; } a.headerselected:visited { color: #36c; background: #fff; text-decoration: none; } a.headerselected:active { color: #36c; background: #fff; text-decoration: none; } a.headerselected:hover { color: #36c; background: #fff; text-decoration: none; } .navtrailbox { color: #36c; background: #fff; padding: 0px; margin-top: 7px; border-spacing: 0px; border-collapse: collapse; font-size: x-small; } .navtrailboxbody { color: #36c; padding: 0px 0px 0px 10px; border-spacing: 0px; background: #fff; font-size: x-small; } a.navtrail:link { color: #36c; background: transparent; } a.navtrail:visited { color: #36c; background: transparent; } a.navtrail:active { color: #36c; background: transparent; } a.navtrail:hover { color: #36c; background: transparent; } .info { color: #060; background: transparent; } .snapshot { color: #000; background: transparent; border: 2px solid #999; margin: 10px 10px 0px 40px; } .pageheader { color: #999; font-size: x-small; background: transparent; padding: 0px; margin: 0px; width: 100%; } .pagebody { color: #000; background: transparent; margin:0px; padding: 20px; } .pagebodystripeleft { color: #000; background: #fff; font-size: x-small; width: 120px; margin: 0px; padding-left: 10px; float: left; } .pagebodystripemiddle { color: #000; background: #fff; padding: 0px; margin: 0px; width: 100%; } .pagebodystriperight { color: #000; background: #fff; font-size: x-small; width: 120px; float: right; } .pageboxlefttop { color: #000; background: transparent; font-size: x-small; } .pageboxlefttopadd { color: #000; background: transparent; font-size: x-small; } .pageboxleftbottom { color: #000; background: transparent; font-size: x-small; } .pageboxleftbottomadd { color: #000; background: transparent; font-size: x-small; } .pageboxrighttop { color: #000; background: transparent; font-size: x-small; } .pageboxrighttopadd { color: #000; background: transparent; font-size: x-small; } .pageboxrightbottom { color: #000; background: transparent; font-size: x-small; } .pageboxrightbottomadd { color: #000; background: transparent; font-size: x-small; } .pagefooter { color: #666; background: #fff; font-size: x-small; margin-top: 50px; padding: 0px; border-top: 1px solid #666; width: 100%; clear: both; } .pagefooterstripeleft { color: #666; background: #fff; font-size: x-small; margin-left: 5px; width: 60%; float: left; text-align: left; } .pagefooterstriperight { color: #666; background: #fff; margin-right: 5px; font-size: x-small; text-align: right; } a.footer:link { color: #666; background: transparent; } a.footer:visited { color: #666; background: transparent; } a.footer:active { color: #666; background: transparent; } a.footer:hover { color: #666; background: transparent; } .errorbox { color: #000; background: #ffcccc; padding: 1px; margin: 5px 30px 5px 30px; border-collapse: collapse; border: 2px solid #900; } .errorboxheader { color: #000; background: #ffcccc; padding: 3px; border-spacing: 0px; font-weight: bold; text-align: left; } .errorboxbody { color: #000; background: #ffcccc; padding: 3px; } .searchbox { color: #000; background: #fff; padding: 1px; margin: 5px 0px 5px 0px; border-collapse: collapse; border-top: 1px solid #36c; } .searchboxheader { color: #000; background: #f1f1f1; padding: 3px; border-spacing: 0px; font-size: small; text-align: left; } .searchboxbody { color: #000; background: #fff; padding: 3px; } .narrowsearchbox { color: #000; background: #fff; padding: 1px; margin: 20px 20px 5px 0px; border-collapse: collapse; border-top: 1px solid #36c; } .narrowsearchboxheader { color: #000; background: #f1f1f1; padding: 3px; border-spacing: 0px; font-size: small; text-align: left; } .narrowsearchboxbody { color: #000; background: #fff; padding: 3px; } .latestadditionsbox { color: #000; background: #fff; padding: 5px; margin: 5px 20px 5px 0px; border-spacing: 5px; } .latestadditionsboxtimebody { color: #000; background: #fff; padding: 3px; white-space: nowrap; text-align: right; vertical-align: top; font-size: xx-small; } .latestadditionsboxrecordbody { color: #000; background: #fff; padding: 3px; text-align: left; vertical-align: top; font-size: small; } .portalbox { color: #000; background: #fff; margin: 0px 0px 15px 0px; border-collapse: collapse; border-top: 1px solid #abb; font-size: x-small; width: 100%; } .portalboxheader { color: #000; background: #f1f1f1; padding: 2px; border-spacing: 0px; border-bottom: 1px solid #999; text-align: left; font-size: x-small; } .portalboxbody { color: #000; background: #fff; padding: 2px; font-size: x-small; } .admin_wvar, .admin_w200, .admin_wvar_nomargin { color: #000; background: white; padding: 1px; margin: 0px 0px 5px 20px; border-spacing: 0px; border-top: 1px solid #36c; } .admin_w200 { width: 250px; } .admin_wvar_nomargin { margin: 0px; } .adminlabel { width: 100px; font-size: small; background: #f1f1f1; vertical-align: top; } .adminheader, .adminheaderleft, .adminheadercenter, .adminheaderright { color: #000; background: #f1f1f1; border-spacing: 0px; font-size: small; padding: 3px 5px; text-align: center; } .adminheaderleft { text-align: left; } .adminheaderright { text-align: right; } .adminbutton { color: #fff; background: #36c; font-weight: bold; margin: 5px 10px 5px 10px; border-collapse: collapse; border-top: 1px solid #36c; } .admintd, .admintdleft, .admintdright { font-size: small; padding: 0px 10px; text-align: center; vertical-align: top; } .admintdleft { text-align: left; } .admintdright { text-align: right; } a.google:link { color: #333; background: transparent; } a.google:visited { color: #333; background: transparent; } a.google:active { color: #333; background: transparent; } a.google:hover { color: #333; background: transparent; } .googlebox { color: #333; background: #fff; text-align: left; margin-left: auto; margin-right: auto; margin-top: 50px; padding: 10px; font-size: small; border-collapse: collapse; border-top: 1px solid #fc0; } .googleboxheader { color: #333; background: #ffc; font-weight: normal; font-size: small; vertical-align: top; } .googleboxbody { color: #333; background: #fff; padding: 0px 5px 0px 5px; font-size: small; text-align: left; vertical-align: top; } .adminbox { color: #000; background: #f1f1f1; margin: 0px; padding: 0px; width: 120px; } .adminboxheader { color: #000; background: #f1f1f1; font-size: x-small; text-align: left; } .adminboxbody { color: #000; background: #f1f1f1; font-size: x-small; } .formbutton { color: #fff; background: #36c; font-weight: bold; } .headline { color: #36c; background: transparent; } .quicknote { color: #603; background: transparent; } .important { color: #f00; background: transparent; } .popupselected { color: #fff; background: #006; } .searchresultsbox { color: #000; background: #ffe; padding: 0px; margin-top: 15px; border-collapse: collapse; border-top: 1px solid #fc0; width: 100%; } .searchresultsboxheader { color: #000; background: #ffc; padding: 2px; border-spacing: 0px; text-align: left; font-weight: normal; } .searchresultsboxbody { color: #000; background: #ffe; border-top: 1px dotted #fc0; border-bottom: 1px dotted #fc0; padding: 2px; } .searchresultsboxrecords { color: #000; background: transparent; margin-left: 0px; margin-right: 20px; } .nearesttermsbox { color: #603; background: #ffe; padding: 0px; border-collapse: collapse; } .nearesttermsboxheader { color: #603; background: #ffc; padding: 0px; border-spacing: 0px; text-align: left; font-weight: normal; } .nearesttermsboxbody { color: #603; background: #fff; padding: 0px; } a.nearestterms:link { color: #603; background: transparent; } a.nearestterms:visited { color: #603; background: transparent; } a.nearestterms:active { color: #603; background: transparent; } a.nearestterms:hover { color: #603; background: transparent; } .nearesttermsboxbodyselected { color: #999; background: #fff; padding: 0px; } a.nearesttermsselected:link { color: #999; background: transparent; } a.nearesttermsselected:visited { color: #999; background: transparent; } a.nearesttermsselected:active { color: #999; background: transparent; } a.nearesttermsselected:hover { color: #999; background: transparent; } .moreinfo { color: #060; font-size: small; background: transparent; } .rankscoreinfo { color: #666; font-size: x-small; background: transparent; } .userinfobox { color: #039; font-size: x-small; width: 150px; margin-bottom: 15px; } .userinfoboxheader { color: #039; font-size: x-small; font-weight: bold; border-top: 1px solid #060; border-bottom: 1px solid #060; } .userinfoboxbody { color: #039; padding: 0px 5px 2px 0px; font-size: x-small; font-weight: normal; } a.userinfo:link { color: #039; background: transparent; } a.userinfo:visited { color: #039; background: transparent; } a.userinfo:active { color: #039; background: transparent; } a.userinfo:hover { color: #039; background: transparent; } a.langinfo:link { color: #666; background: transparent; } a.langinfo:visited { color: #666; background: transparent; } a.langinfo:active { color: #666; background: transparent; } a.langinfo:hover { color: #666; background: transparent; } .faq { margin-left: 12%; margin-right: 3%; } .faqq { margin-left: 18%; margin-right: 3%; } .exampleleader { color: #060; background: transparent; } .example { color: #039; background: transparent; } .blocknote { color: #000; background: #ccc; } .blocknotebis { color: #000; background: #999; } .devel { color: #600; background: #fff; border-color: #600; border-left-width: medium; border-left-style: solid; font-size: 90%; } .normal { color: #000; background: #fff; } .address { font-style: normal; font-size: x-small; } .note { color: #666; background: transparent; } .warning { color: #603; background: transparent; } .light { color: #ccc; background: transparent; } .nbdoccoll { color: #666; background: transparent; } hr { width: 100%; height: 1px; color: #999; background-color: #999; border-width: 0; } input,select { color: #000; background: #fff; } .wsactionbutton { width: 150px; height: 25px; color: #039; margin: 0px; background-color: #fff; border: 2px solid #039; vertical-align: middle; font-size: small; padding: 5px 5px 0px 5px; } .wsactionbuttonh { width: 150px; height: 25px; color: #039; margin: 0px; background-color: #9cf; border: 2px solid #039; vertical-align: middle; font-size: small; padding: 5px 5px 0px 5px; } .textbutton { color: #039; font-weight: bold; text-decoration: none; } .submitBody { color: #000; background: #9cf; } .submitHeader { color: #fff; background: #006; } .submitCurrentPage { color: #000; background: #9cf; border-top: 1px solid #039; border-left: 1px solid #039; border-right: 1px solid #039; } .submitEmptyPage { color: #fff; background: #fff; border-bottom: 1px solid #039; } .submitPage { color: #000; background: #fff; border-top: 1px solid #039; border-left: 1px solid #039; border-right: 1px solid #039; } .mycdscell { border-right: 1px solid #fff; } .guideimg { border: 2px dotted #777; padding: 5px; margin: 5px; } .guideheader { font-size: 120%; font-weight: 600; font-variant: small-caps; color: #36c; margin-left: 10px; background: transparent; } .recordlastmodifiedbox { text-align: left; font-size: small; color: #603; background: #fff; } .commentbox { color: #000; width: 100%; padding: 0px 10px 10px 10px; border-left: 2px solid #36c; } .warninggreen { color: #060; background: transparent; } .warningred { color: #f00; background: transparent; } .reportabuse { color: #000; background: #fff; font-size: small; vertical-align: bottom; } /* WebMessage module */ .mailbox{ border-collapse: collapse; color: #000; margin-top: 15px; padding: 0px; width: auto; } .mailboxheader tr{ background: #ffc; } .inboxheader { text-align:center; padding: 5px 30px 5px 30px; border-top: 1px solid #fc0; border-bottom: 1px solid #fc0; } .messageheader{ width: 100%; padding: 0px; border: 0px; } .mailboxinput{ width: 100%; } .mailboxlabel{ white-space: nowrap; padding-right: 15px; } .mailboxbody{ background: #ffe; } .mailboxrecord{ /* each record */ } .mailboxrecord td{ /* each cell of a record */ padding: 4px 30px 4px 30px; border-top: 1px dashed #fff; } .mailboxfooter{ background-color: #fff; } .mailboxfooter td{ padding: 10px 0px 0px 0px; border-top: 1px solid #fc0; border-bottom: none; border-left: none; border-right: none; } .mailboxsearch td { padding-top: 10px; padding-bottom: 10px; } .mailboxresults td { padding-bottom: 5px; border-bottom: 1px solid #fc0; } .nonsubmitbutton { color: #000; background: #fc0; font-weight: bold; } .confirmoperation{ margin: auto; width: 400px; height: 100px; background-color: #ddf; } .confirmmessage{ font-weight: bold; text-align: center; } .infobox{ background-color: #ffc; padding: 7px; border-collapse: collapse; border: 1px solid #fc0; } .warningbox{ background-color: #cff; padding: 7px; border-collapse: collapse; border: 1px solid #ccff00; } .quotabox{ background-color: #ffc; width: 200px; height: 15px; border: 1px solid #fc0; margin: 3px 0px 3px 0px; } .quotabar{ background-color: #fc0; border: 0px none black; height: 15px; } /* WebBasket module */ #bskcontainer{ float: left; background: transparent; } #bsktabs{ float: left; background:transparent; padding: 0px; margin: 0px; text-align: center; } .bsktab{ float: left; vertical-align: center; margin: 0px 20px 0px 20px; padding: 4px 10px 5px 5px; background-repeat: no-repeat; background-position: top-left; background-color: #ffe; } #bsktab_selected{ background-color: #ffc; font-weight: bold; border-bottom: hidden; } .bsktab a{ color: #000; text-decoration: none; } .bsktab a:hover{ text-decoration: underline; } .bsktab img{ margin: 0px 5px 0px 0px; } #bskcontent{ float: left; width: 100%; border-collapse: collapse; background: #ffe; border: none; } #bsktopics{ background-color: #ffc; padding: 10px; width: 100%; } .bsktopic{ white-space: nowrap; font-weight: bold; margin: 0px 20px 0px 20px; } .bsktopic a{ font-weight: normal; text-decoration: none; color: #000; } .bsktopic a:hover{ text-decoration: underline; } #bskbaskets{ padding: 10px; } #bskinfos{ background-color: transparent; } .bskbasket{ margin-bottom: 20px; border-collapse: collapse; border: 1px solid #fc0; background-color:white; } .bskbasketheader{ background-color: #ffc; } .bskbasketheader td{ padding: 5px; border-bottom: 1px solid #fc0; border-collapse: collapse; vertical-align: top; } .bskbasketfooter{ border-top: 1px solid #fc0; background-color: #ffc; padding: 3px; } .bskbasketheaderactions{ text-align: center; white-space: nowrap; } .bskbasketheaderactions td{ border: none; } .bskbasketheaderactions img{ border: 0px; margin: 2px; } .bskbasketheaderactions a{ font-size: small; color: #000; } .bskbasketfooter td{ padding: 5px 0px 5px 0px; } .bskactions{ text-align: center; white-space: nowrap; border-bottom: 1px solid #fc0; } .bskactions td{ border: none; } .bskactions img{ border: 0px; margin: 2px; } .bskactions a{ font-size: x-small; } .bsktitle { width: 100%; } .bskcmtcol{ white-space: nowrap; text-align: right; } .bskcontentcol{ border-bottom: 1px solid #fc0; padding: 5px; } .bskcontentcol a{ font-size: small; } .bskcomment { padding: 15px 10px 15px 10px; margin-bottom: 5px; border-bottom: 1px solid #fc0; } .bsklabel{ font-size: small; font-weight: bold; white-space: nowrap; padding-right: 15px; } .bsk_create_link{ padding-top: 5px; padding-bottom: 10px; background-color: transparent; } .bsk_create_link a{ color: black; } .bsk_create_link img{ border: none; } dd{ margin-bottom: 10px; } /* end of WebBasket module */ /* WebSubmit module */ form.hyperlinkform { /* used in form tag for a form that should be hidden, but contains a button styled like a hyperlink */ display: inline; padding: 0; margin: 0; height: 0; width: 0; } input.hyperlinkformHiddenInput { /* used in a hidden input tag for a form that should be hidden, but contains a button styled like a hyperlink */ display: inline; padding: 0; margin: 0; height: 0; width: 0; } input.hyperlinkformSubmitButton { /* used in a submit input tag for a form that should be hidden, but contains a button styled like a hyperlink */ display: inline; padding: 0; margin: 0; border: 0; background-color: transparent; font-size: 1em; line-height: 1em; text-decoration: underline; cursor: pointer; color: blue; } /* end of WebSubmit module */ /* BibEdit module */ .bibEditTable{ background: #ececec; border: 0px; padding: 0px; border-collapse: collapse; } .bibEditTable th{ background: #ccc; text-align: left; padding: 5px; } .bibEditCellRight{ font-size: small; text-align: right; padding: 0px; } .bibEditCellTag{ font-size: small; text-align: right; vertical-align: top; padding: 2px 5px 2px 5px; font-weight: bold; } /* end of BibEdit module*/ /* WebAlert module */ .alrtTable{ border: 1px solid black; width: 100%; padding: 0px; border-collapse: collapse; } .alrtTable td{ border: 1px solid black; padding: 3px; } /* end of WebAlert module */ + +/* externalcollections */ +.externalcollectionsbox { + color: #333; + background: ##fffbf5; + text-align: left; + margin-left: auto; + margin-right: auto; + margin-top: 50px; + padding: 10px; + font-size: small; + border-collapse: collapse; + border-top: 1px solid #fc0; +} + +.externalcollectionsboxheader { + color: #333; + background: #ffeacc; + font-weight: normal; + font-size: small; + vertical-align: top; +} + +.externalcollectionsboxbody { + color: #333; + background: ##fffbf5; + padding: 0px 5px 0px 5px; + font-size: small; + text-align: left; + vertical-align: top; +} + +.externalcollectionsresultsbox { + color: #000; + background: #fffbf5; + padding: 0px; + margin-top: 15px; + border-collapse: collapse; + border-top: 1px solid #fc0; + width: 100%; +} +.externalcollectionsresultsboxheader { + color: #000; + background: #ffeacc; + padding: 2px; + border-spacing: 0px; + text-align: left; + font-weight: normal; +} +.externalcollectionsresultsboxbody { + color: #000; + background: #fffbf5; + border-top: 1px dotted #fc0; + border-bottom: 1px dotted #fc0; + padding: 2px; +} +.externalcollectionsresultsboxrecords { + color: #000; + background: transparent; + margin-left: 0px; + margin-right: 20px; +} + /* end of cds.css */