def dumpExtensions(): '''Writes the list of registered extensions to stderr.''' Utils.Error('List of registered extensions:', prefix='Info: ') for extensionName in _registered_extensions_.keys(): (category, shortDesc, longDesc, author, copyright, date, isSimpleExtension, extensionClass) = _registered_extensions_[extensionName] p = extensionClass() Utils.Error(p.name(), prefix='- ')
def NoValidFunction(req, res, e): # We save the result in a temporary directory as well as the exception # message. Then we remove the ValidatorIcon. tmp = tempfile.mktemp() os.mkdir(tmp) fn = 'novalid_' + os.path.basename(req.path) Utils.FileString(os.path.join(tmp, fn), res[1]) Utils.Error('Saved in dir ' + tmp, prefix='See: ') Utils.FileString(os.path.join(tmp, 'message'), str(e)) # Remove ValidatorIcon: res[1] = string.replace(res[1], WebWorkers.ValidatorIconText, '') # Adjust Content-length: res[0]['Content-length'] = str(len(res[1]))
def createSuccessMessage(self): examnr = self.examnr # evaluate the changes registrations = {} l = Utils.SortNumerAlpha(Data.people.keys()) for k in l: p = Data.people[k] wasRegistered = (examnr < len(p.exams) and p.exams[examnr] != None and p.exams[examnr].registration == 1) shouldBeRegistered = self.options.has_key('T' + k) if wasRegistered != shouldBeRegistered: registrations[k] = int(shouldBeRegistered) # put the changes into the database registered = [] unregistered = [] Data.Lock.acquire() timestamp = int(time.time()) for k in Utils.SortNumerAlpha(registrations.keys()): v = registrations[k] line = AsciiData.LineTuple( (k, str(examnr), str(v), str(timestamp))) try: Data.examregdesc.AppendLine(line) except: Data.Lock.release() Utils.Error('[' + Utils.LocalTimeString() + '] Failed to register person for exam:\n' + line) return '<emph>Error: The changes could not be saved.</emph>' p = Data.people[k] while len(p.exams) < examnr + 1: p.exams.append(None) if p.exams[examnr] == None: p.exams[examnr] = Data.Exam() p.exams[examnr].timestamp = timestamp p.exams[examnr].registration = v if Data.Exam.maxexamnumber < examnr + 1: Data.Exam.maxexamnumber = examnr + 1 line = (Utils.CleanWeb(p.lname) + ', ' + Utils.CleanWeb(p.fname) + ' (' + k + ')') if v == 1: registered.append(line) else: unregistered.append(line) Data.Lock.release() Utils.Error('[' + Utils.LocalTimeString() + '] Changed registrations ' 'for exam ' + str(examnr), prefix='BulkExamRegistration: ') s = '<h3>An-/Abmeldung von Klausur ' + str(examnr) + '</h3>\n' if len(registered) > 0: s += ('<div>Die folgenden Personen wurden zur Klausur angemeldet:' '</div>\n' '<ul>\n<li>' + str('</li>\n<li>').join(registered) + '</li>\n</ul>\n') if len(unregistered) > 0: s += ('<div>Die folgenden Personen wurden von der Klausur ' ' abgemeldet:</div>\n' '<ul>\n<li>' + str('</li>\n<li>').join(unregistered) + '</li>\n</ul>\n') return s
def PostProcessing(): '''This routine is called by the server to bring configuration options into a usable form. Some values are changed into other data types.''' try: l = map(string.strip, conf['Resolutions'].split(',')) conf['Resolutions'] = map(int, l) except: Utils.Error('Value of "Resolutions" option must be a comma-separated' + ' list of positive integers.') FailMiserably() try: conf['IdCheckRegExp'] = re.compile(conf['IdCheckRegExp']) except: Utils.Error('Regular expression in "IdCheckRegExp" cannot be ' 'compiled.') etype, value, tb = sys.exc_info() lines = traceback.format_exception(etype, value, tb) Utils.Error(string.join(lines), prefix="") FailMiserably() if not (conf.has_key('GuestIdRegExp')): conf['GuestIdRegExp'] = '^$' # matches only the empty string try: conf['GuestIdRegExp'] = re.compile(conf['GuestIdRegExp']) except: Utils.Error('Regular expression in "GuestIdRegExp" cannot be ' 'compiled.') etype, value, tb = sys.exc_info() lines = traceback.format_exception(etype, value, tb) Utils.Error(string.join(lines), prefix="") FailMiserably() try: conf['GeneralMessages'] = Utils.StringFile(conf['GeneralMessageFile']) except: Utils.Error( 'Cannot read general messages for results pages, assuming' ' no messages.', prefix="Warning:") conf['GeneralMessages'] = '' traceback.print_exc() for i in range(len(conf['AccessList'])): s = conf['AccessList'][i] try: pos = s.find('/') if pos < 0: Utils.Error('Range in AccessList must contain a slash:\n' + s) FailMiserably() # Handle a bug in Python 2.2: if s[pos + 1:] == '255.255.255.255': conf['AccessList'][i] = (socket.inet_aton(s[:pos]), '\xff\xff\xff\xff') else: conf['AccessList'][i] = (socket.inet_aton(s[:pos]), socket.inet_aton(s[pos + 1:])) except: traceback.print_exc() Utils.Error('Cannot parse IP range for AccessList: ' + s) FailMiserably() for i in range(len(conf['AdministrationAccessList'])): s = conf['AdministrationAccessList'][i] try: pos = s.find('/') if pos < 0: Utils.Error('Range in AdministrationAccessList must contain ' 'a slash:\n' + s) FailMiserably() # Handle a bug in Python 2.2: if s[pos + 1:] == '255.255.255.255': conf['AdministrationAccessList'][i] = \ (socket.inet_aton(s[:pos]),'\xff\xff\xff\xff') else: conf['AdministrationAccessList'][i] = \ (socket.inet_aton(s[:pos]),socket.inet_aton(s[pos+1:])) except: traceback.print_exc() Utils.Error( 'Cannot parse IP range for AdministrationAccessList: ' + s) FailMiserably() # Give a default for Header: if not (conf.has_key('Header')): conf['Header'] = '' # Give a default for Footer: if not (conf.has_key('Footer')): conf['Footer'] = '' # Give a default for MaxStringInputLength: if not (conf.has_key('MaxStringInputLength')): conf['MaxStringInputLength'] = 20 # Give a default for InteractiveMode: if not (conf.has_key('InteractiveMode')): conf['InteractiveMode'] = 0 # Give a default for RestrictToOwnGroup: if not (conf.has_key('RestrictToOwnGroup')): conf['RestrictToOwnGroup'] = 1 # Give a default for MCScoreCorrectDefault: if not (conf.has_key('MCScoreCorrectDefault')): conf['MCScoreCorrectDefault'] = 1 # Give a default for MCScoreWrongDefault: if not (conf.has_key('MCScoreWrongDefault')): conf['MCScoreWrongDefault'] = -1 # Give a default for MCScoreExerciseLowerLimitDefault: if not (conf.has_key('MCScoreExerciseLowerLimitDefault')): conf['MCScoreExerciseLowerLimitDefault'] = 0 # Give a default for the DocumentRoot: if not (conf.has_key('DocumentRoot')): conf['DocumentRoot'] = os.path.join(home, 'html') # Give a default for GroupInfoFile: if not (conf.has_key('GroupInfoFile')): conf['GroupInfoFile'] = os.path.join(home, 'data/groupinfo.txt') # Give a default for ExtraLaTeXHeader: if not (conf.has_key('ExtraLaTeXHeader')): conf['ExtraLaTeXHeader'] = '' # Preparse the PDFTemplate: conf['PDFTemplate'] = SimpleTemplate.ParseString(conf['PDFTemplate']) # Same for NoTable variant: if not conf.has_key('PDFTemplateNoTable'): conf['PDFTemplateNoTable'] = '' conf['PDFTemplateNoTable'] = SimpleTemplate.ParseString( conf['PDFTemplateNoTable']) # Now parse the GradingFunction if applicable: if conf.has_key('GradingFunction'): d = {} try: exec conf['GradingFunction'] + '\n' in d conf['GradingFunction'] = d['Grade'] except: etype, value, tb = sys.exc_info() lines = traceback.format_exception(etype, value, tb) Utils.Error('Cannot parse GradingFunction.\n' + string.join(lines)) conf['GradingFunction'] = None else: conf['GradingFunction'] = None if not (conf.has_key('GradingActive')): conf['GradingActive'] = 0 # Now parse the ExamGradingFunction if applicable: if conf.has_key('ExamGradingFunction'): d = {} try: exec conf['ExamGradingFunction'] + '\n' in d conf['ExamGradingFunction'] = d['Grade'] except: etype, value, tb = sys.exc_info() lines = traceback.format_exception(etype, value, tb) Utils.Error('Cannot parse ExamGradingFunction.\n' + string.join(lines)) conf['ExamGradingFunction'] = None else: conf['ExamGradingFunction'] = None if not (conf.has_key('ExamGradingActive')): conf['ExamGradingActive'] = 0 if not (conf.has_key('DateTimeFormat')): conf['DateTimeFormat'] = '%c' # Also parse the EMailHeaderFunction: d = {} try: exec conf['EMailHeaderFunction'] + '\n' in d conf['EMailHeaderFunction'] = d['EMailHeaderFunction'] except: etype, value, tb = sys.exc_info() lines = traceback.format_exception(etype, value, tb) Utils.Error('Cannot parse EMailHeaderFunction.\n' + string.join(lines)) FailMiserably() # Compile regular expression for valid email addresses try: conf['reValidEmail'] = re.compile(conf['ValidEmailAddresses'], re.I) except: Utils.Error('Regular expression in "ValidEmailAddresses" cannot be ' 'compiled.') etype, value, tb = sys.exc_info() lines = traceback.format_exception(etype, value, tb) Utils.Error(string.join(lines), prefix="") FailMiserably()
def ReadConfig(): global conf configfile = os.path.join(home, "Config.xml") parseconf = { 'fourth': pyRXPU.recordLocation, 'ReturnDefaultedAttributes': 0, 'MergePCData': 1, 'Validate': 1, 'eoCB': OurDtdOpener } tree = XMLRewrite.Parse(config=parseconf, file=configfile) if not tree: Utils.Error("Cannot parse the Config.xml file!") FailMiserably() # Now run through the tree: # We know by the DTD that there is exactly one "Config" element. if tree[2] != None: # there might be no subelements for node in tree[2]: if type(node) == types.TupleType: # We know by the DTD that there is only element content, but # strings in between are still reported by pyRXP. key = node[0].encode('ISO-8859-1', 'replace') if Parameters.has_key(key): info = Parameters[key] # special case 'ConfigData', create dictionary if not there if key == 'ConfigData': if not conf.has_key(key): conf[key] = {} cnf = conf[key] key = node[1]['key'].encode('ISO-8859-1', 'replace') else: cnf = conf if info[0] == 'STRING' or info[0] == 'INT' or \ info[0] == 'FLOAT' or info[0] == 'PATH': # We know by the DTD that there is only #PCDATA content # Usually this will come as one chunk because of # "MergePCData=1" above. We strip whitespace at # beginning and end: cnf[key] = string.strip(string.join(node[2])) if info[0] == 'STRING' or info[0] == 'PATH': try: cnf[key] = cnf[key].encode('ISO8859-1') except: Utils.Error( 'Value "' + cnf[key] + '" of ' + 'configuration field "' + key + '" at ' + Utils.StrPos(node[3]) + ' has no ISO8859-1' + ' encoding. We assume the empty string.', prefix='Warning: ') cnf[key] = "" if info[0] == 'PATH': cnf[key] = os.path.join(home, cnf[key]) elif info[0] == 'INT': try: cnf[key] = int(cnf[key]) except: Utils.Error('Value "' + cnf[key] + '" of ' + 'configuration field "' + key + '" at ' + Utils.StrPos(node[3]) + ' is not an integer. We' + ' assume 0.', prefix='Warning: ') cnf[key] = 0 elif info[0] == 'FLOAT': try: cnf[key] = float(cnf[key]) except: Utils.Error('Value "' + cnf[key] + '" of ' + 'configuration field "' + key + '" at ' + Utils.StrPos(node[3]) + ' is not a float. We' + ' assume 0.0 .', prefix='Warning: ') cnf[key] = 0.0 elif info[0] == 'LIST' or info[0] == 'PATHLIST': # We know by the DTD, that the children are just a list # of elements with #PCDATA content: cnf[key] = [] for subnode in node[2]: if type(subnode) == types.TupleType: s = string.strip(string.join(subnode[2])) try: s = s.encode('ISO8859-1') except: Utils.Error('Value "' + s + '" of ' + 'configuration field "' + key + '" at ' + Utils.StrPos(node[3]) + ' has no ISO8859-1' + ' encoding. We ignore it.', prefix='Warning: ') if info[0] == 'PATHLIST': s = os.path.join(home, s) cnf[key].append(s) else: # A configuration field that we do not know! Utils.Error('Unknown configuration field "' + key + '" at ' + Utils.StrPos(node[3]) + ', ignoring.', prefix='Warning: ') abort = 0 for k in Parameters.keys(): if Parameters[k][1] and not (conf.has_key(k)): Utils.Error('Essential configuration option not found: "' + k + '".') abort = 1 if abort: FailMiserably() # See whether we can find the VERSION file: try: f = file(os.path.join(home, "VERSION")) version = f.readline() f.close() conf["Version"] = string.strip(version) except: conf["Version"] = 'UNKNOWN' pass # we silently ignore, if the VERSION file is not found
def FailMiserably(): Utils.Error("Aborting.", prefix="") sys.exit(1)
# (at your option) any later version. # # This program 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 this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import os, sys from fmTools import Utils Utils.Error('Loading extensions...', prefix='Info: ') import plugins pluginsPath = os.path.join(plugins.__path__[0]) for pluginDir in os.listdir(pluginsPath): if pluginDir in ['CVS', '.svn', '.git']: continue # skip the CVS and similae directory if not os.path.isdir(os.path.join(pluginsPath, pluginDir)): continue # skip non-directories # load modules in this directory module = None try: module = __import__(plugins.__name__ + '.' + pluginDir) except ImportError: Utils.Error('Importing plugin ' + pluginDir + '.' + name + ' failed')
import os, sys, string, time, tempfile, traceback, locale, signal import Config # this automatically determines our home dir # but does not read the configuration file # try to get correct locale from environment try: locale.setlocale(locale.LC_ALL, '') except: pass # Fetch the "Utils" and switch error reporting to log file: from fmTools import Utils Utils.ErrorLogFileName = os.path.join(Config.home, 'log/server.log') Utils.currentError = Utils.ErrorToLogfile Utils.Error(time.asctime(time.localtime()) + ' Starting server...', prefix='') # Now we can read our configuration file with proper error reporting # (note that this might fail miserably): Config.ReadConfig() Config.PostProcessing() # some postprocessing of configuration data # We perform a few sanity checks and give appropriate messages: if not (os.path.isdir(Config.conf['DocumentRoot'])): Utils.Error('Cannot find DocumentRoot directory: ' + Config.conf['DocumentRoot']) Utils.Error('Aborting.', prefix='') sys.exit(0) if not (os.path.isdir(os.path.join(Config.conf['DocumentRoot'], 'images'))): Utils.Error('DocumentRoot directory does not contain an "images" '
Config.ReadConfig() Config.PostProcessing() # some postprocessing of configuration data f = file("log/server.log", "r") f.seek(0, 2) # seek to end of file p = f.tell() # Now send the request: try: u = urllib.urlopen('http://localhost:' + str(Config.conf['Port']) + '/AdminWork?Action=PID') spid = u.read() u.close() except: Utils.Error('Cannot contact server. No server running?') sys.exit(1) pid = os.fork() if pid == 0: time.sleep(0.5) # Let the parent get hold of the log file os.kill(int(spid), signal.SIGUSR1) try: # generate a request such that server notices the signal u = urllib.urlopen('http://localhost:' + str(Config.conf['Port']) + '/') u.close() except: pass print 'Sent server with PID ' + spid + ' a USR1 signal.' sys.exit(0) # Terminate this child process
import sys, os, time # get paths right homedir = os.path.abspath(sys.path[0]) okudir = os.path.join(homedir, '..') os.environ["OKUSONHOME"] = okudir sys.path = [os.path.join(okudir, 'server')] + sys.path # read config import Config Config.ReadConfig() Config.PostProcessing() # read exercises and sheets from fmTools import Utils, AsciiData Utils.Error('Reading exercises and sheets...', prefix='Info: ') import Exercises for d in Config.conf['ExerciseDirectories']: Exercises.ReadExercisesDirectory(d) for d in Config.conf['SheetDirectories']: Exercises.ReadSheetsDirectory(d) # list of triples (number, name, sheet) sheets = Exercises.SheetList() # read data import Data Utils.Error('Reading personal data...', prefix='Info: ') Data.peopledesc.LoadFile() Utils.Error('Reading multiple choice data...', prefix='Info: ') Data.mcresultsdesc.LoadFile()
def createSummary(self): examnr = self.examnr maxscore = self.maxscore scores = self.scores oldscores = self.oldscores # put the changes into the database table = [] table.append([ '', 'Matr.-Nr.', 'Name', 'Punkte', 'Punkte in den einzelnen Aufgaben' ]) unchanged = [] unchanged.append([ '', 'Matr.-Nr.', 'Name', 'Punkte (alt)', 'Punkte (aktuell)', 'Punkte (Ihre Angabe)', 'Details (alt)', 'Details (aktuell)', 'Details (Ihre Angabe)' ]) counter = 0 unchangedcount = 0 Data.Lock.acquire() for k in Utils.SortNumerAlpha(scores.keys()): p = Data.people[k] while len(p.exams) < examnr + 1: p.exams.append(None) exam = p.exams[examnr] newOrChanged = False # we only have to save non-default values for not yet existing # entries or changed values for existing entries newtotalscore = scores[k][0] newdetails = scores[k][1] oldtotalscore = oldscores[k][0] olddetails = oldscores[k][1] # if ( exam == None ): # only needed for the following print # curtotalscore = -1 # curdetails = '<None>' # else: # curtotalscore = exam.totalscore # curdetails = exam.scores # print ( k + ': totalscore (old/cur/new): ' + str(oldtotalscore) + # '/' + str(curtotalscore) + '/' + str(newtotalscore) + # ' -- details (old/cur/new): "' + olddetails + '"/"' + # curdetails + '"/"' + newdetails + '"' ) if (exam == None): # do we have non-default values? if (newtotalscore != -1 or newdetails != ''): exam = Data.Exam() newOrChanged = True else: # has the user made changes? valuesChanged = ((newtotalscore != oldtotalscore) or (newdetails != olddetails)) # are there changes with respect to the currently stored values # (because of changes by another user while the first user editted # the values) needsSaving = ((newtotalscore != exam.totalscore) or (newdetails != exam.scores)) # have there been changes behind our back changedBehindBack = ((oldtotalscore != exam.totalscore) or (olddetails != exam.scores)) if (valuesChanged and needsSaving and changedBehindBack): # the user has changed a value and additionally this value has # been changed by another user while the first user editted # the values; in this case we don't save our values unchangedcount += 1 if newtotalscore == -1: newtotalscorestr = '-' else: newtotalscorestr = locale.str(newtotalscore) if oldtotalscore == -1: oldtotalscorestr = '-' else: oldtotalscorestr = locale.str(oldtotalscore) if exam.totalscore == -1: curtotalscorestr = '-' else: curtotalscorestr = locale.str(exam.totalscore) unchanged.append([ str(unchangedcount), k, Utils.CleanWeb(p.lname) + ', ' + Utils.CleanWeb(p.fname), oldtotalscorestr, curtotalscorestr, newtotalscorestr, olddetails, exam.scores, newdetails ]) elif (valuesChanged): newOrChanged = True elif (exam.maxscore != maxscore and (oldtotalscore != -1 or olddetails != '')): newOrChanged = True if newOrChanged: exam.totalscore = newtotalscore exam.scores = newdetails exam.maxscore = maxscore line = AsciiData.LineTuple((k, str(examnr), str(newtotalscore), str(maxscore), newdetails)) try: Data.examdesc.AppendLine(line) except: Data.Lock.release() Utils.Error('[' + Utils.LocalTimeString() + '] Failed to store exam result:\n' + line) return '<em>Error: The results could not be saved.</em>' p.exams[examnr] = exam counter += 1 if newtotalscore == -1: newtotalscorestr = '-' else: newtotalscorestr = locale.str(newtotalscore) table.append([ str(counter), k, Utils.CleanWeb(p.lname) + ', ' + Utils.CleanWeb(p.fname), newtotalscorestr, newdetails ]) Data.Lock.release() Utils.Error('[' + Utils.LocalTimeString() + '] Changed results ' 'for exam ' + str(examnr), prefix=self.name() + ': ') s = '<h3>Ergebnisse von Klausur ' + str(examnr) + '</h3>\n' if len(unchanged) > 1: s += ( '<p>Einige Werte wurden geändert, während Sie die Werte editiert ' 'haben. Daher wurden die folgenden Änderungen <strong>nicht</strong> ' 'gespeichert.') s += createHTMLTable(unchanged) s += '<p>Die folgenden Änderungen wurden gespeichert.</p>' s += createHTMLTable(table) return s