def initTray(self): menu = ( ('Planer hochladen', None, self.getNewFiles), ('Beenden', None, self.bye), ) if os.name in "nt": from taskbardemo import DemoTaskbar, Taskbar self.tray = DemoTaskbar(self,'fls_logo.ico', 'FLS Vertretungsplaner', menu) elif os.name == 'posix': #from linuxtaskbar import Taskbar #w = QtGui.QWidget() #self.tray = Taskbar(w, QtGui.QIcon('fls_logo.ico'), 'FLS Vertretungsplaner', menu) #self.tray.show() pass if self.tray is not None: self.tray.showInfo('Vertretungsplaner startet...', 'Bei Problemen wenden Sie sich bitte an das Website-Team der Friedrich-List-Schule Wiesbaden.')
class Vertretungsplaner(QObject): showDlg = pyqtSignal() hideDlg = pyqtSignal() cleanupDlg = pyqtSignal() def getWatchPath(self): return self.config.get("default", "path") def getSendURL(self): return self.config.get("default", "url") def getAPIKey(self): return self.config.get("default", "api") def getStatus(self): return self.locked def getOption(self, name): if self.config.has_option('options', name): if self.config.get('options', name) in ['True', True]: return True else: return False else: return False def getIntervall(self): return float(self.config.get("default", "intervall")) def isProxyEnabled(self): if self.config.get('proxy', 'enable') == 'True' or \ self.config.get('proxy', 'enable') is True: return True else: return False def filesAreUTF8(self): if self.config.get('default', 'utf8') == 'True' or \ self.config.get('default', 'utf8') is True: return True else: return False def getRun(self): return self.run def setRun(self, run): self.run = run def showToolTip(self, title, msg, msgtype): if self.tray is not None: self.tray.showInfo(title, msg) else: # ok.. than let us print on console print('[%s] %s: %s' % (msgtype, title, msg)) return True def getNewFiles(self): print('Starte suche...') self.locked = True pathToWatch = self.getWatchPath() try: after = dict([(f, WatchFile(pathToWatch, f)) for f in os.listdir(pathToWatch)]) except FileNotFoundError as e: print('\nCould not poll directory %s (does not exist!)' % (pathToWatch,)) # try recreate the directory (maybe it does not exist in base path: try: os.makedirs(pathToWatch) except: pass self.locked = False return added = [f for f in after if not f in self.before] removed = [f for f in self.before if not f in after] same = [f for f in after if f in self.before] changed = [f for f in same if self.before[f].mtime != after[f].mtime] todo = added + changed if todo: print("\nChanged/Added new Files: ", ", ".join(todo)) for f in todo: f = f.strip() execFound = False if self.config.get('vplan', 'type') == 'daVinci': if int(self.config.get('vplan', 'version')) == 6: if f.lower().endswith('.csv'): execFound = True try: self.handlingFlsCSV(f) except: pass elif f.lower().endswith('.json'): execFound = True # As we have an error dialog here, do not send in background! #Thread(target=self.handlingDavinciJson, args=(f,)).start() try: self.handlingDavinciJson(f) except: pass elif f.lower().endswith('.json') and not execFound: execFound = True Thread(target=self.handlingJson, args=(f,)).start() elif not execFound: print('"%s" will be ignored.' % (f,)) if removed: print("\nRemoved files: ", ", ".join(removed)) self.before = after self.locked = False def initPlan(self): pathToWatch = self.getWatchPath() try: if not os.path.exists(pathToWatch): os.makedirs(pathToWatch) self.before = dict([(f, WatchFile(pathToWatch, f)) for f in os.listdir(pathToWatch)]) except FileNotFoundError as e: print('\nCould not poll directory %s (does not exist!)' % (pathToWatch,)) self.before = {} # Now start Looping self.search = Thread(target=SearchPlaner, args=(self,)).start() def convert(self, table): for i,v in enumerate(table): for k,x in enumerate(v): if self.filesAreUTF8() and type(x).__name__ != 'str': table[i][k] = x.decode("utf8") elif type(x).__name__ != 'str': print(type(x).__name__) table[i][k] = x.decode("iso-8859-1") return table def send_table(self, table, absFile, planType = 'all', convert = True): # jau.. send it to the top url! if convert: table = self.convert(table) data = json.dumps(table).encode('utf8') data = base64.encodestring(data).decode('utf8').replace('\n', '') values = { 'apikey': base64.encodestring(self.getAPIKey().encode('utf8')).decode('utf8').replace('\n', ''), 'data': data, 'type': planType } if self.getOption('debugOnline'): values['XDEBUG_SESSION_START'] = '1' d = urllib.parse.urlencode(values) opener = None if self.isProxyEnabled(): print('Proxy is activated') httpproxy = "http://"+self.config.get("proxy", "phost")+":"+self.config.get("proxy", "pport") proxies = { "http" : httpproxy } opener = urllib.request.build_opener(urllib.request.ProxyHandler(proxies)) urllib.request.install_opener(opener) else: print('Proxy is deactivated') opener = urllib.request.build_opener(urllib.request.HTTPHandler) urllib.request.install_opener(opener) request = urllib.request.Request(self.getSendURL(), d.encode('utf8')) if self.config.has_option("siteauth", "enable") and self.config.get("siteauth", "enable") == 'True': authstr = base64.encodestring( ('%s:%s' % ( self.config.get("siteauth", "username"), self.config.get("siteauth", "password") )).encode('utf8') ).decode('utf8').replace('\n', '') request.add_header("Authorization", "Basic %s" % authstr) # add post info request.add_header('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8') try: response = opener.open(request) code = response.read() self.showToolTip('Vertretungsplan hochgeladen','Die Datei wurde erfolgreich hochgeladen.','info') print('Erfolgreich hochgeladen.') except urllib.error.URLError as err: self.createCoreDump(err) self.showToolTip('Warnung','Der Vertretungsplan konnte eventuell nicht korrekt hochgeladen werden. Bitte kontaktieren Sie das Website-Team der FLS!','error') print("URL-Fehler aufgetreten: %s" % ( err.reason, )) except urllib.error.HTTPError as err: self.createCoreDump(err) self.showToolTip('Warnung','Der Vertretungsplan konnte eventuell nicht korrekt hochgeladen werden. Bitte kontaktieren Sie das Website-Team der FLS!','error') print("HTTP-Fehler aufgetreten: %i - %s" % ( err.code, err.reason )) except Exception as err: self.createCoreDump(err) self.showToolTip('Warnung','Der Vertretungsplan konnte eventuell nicht korrekt hochgeladen werden. Bitte kontaktieren Sie das Website-Team der FLS!','error') print("Unbekannter Fehler aufgetreten: ", err) # now move the file and save an backup. Also delete the older one. self.moveAndDeleteVPlanFile(absFile) def createCoreDump(self, err): if not self.getOption('createCoreDump'): return try: __file__ except NameError: __file__ = 'flsvplan.py' path = os.path.dirname(__file__) if len(os.path.dirname(__file__)) > 0 else sys.path[0] if len(path) > 0 and not os.path.isdir(path): path = os.path.dirname(path) path = '%s%scoredump' % (path, os.sep) filename = '%s%s%s-%s.dump' % (path, os.sep, __file__, datetime.now().strftime('%Y%m%d%H%M%S%f')) # truncate folder if os.path.exists(path): shutil.rmtree(path, ignore_errors=False, onerror=None) os.makedirs(path) dump = {} #dump['url'] = err.geturl() #dump['code'] = err.getcode() #dump['info'] = err.info() #dump['hdrs'] = err.hdrs #dump['msg'] = err.msg dump['tb'] = traceback.format_exc() dump['tbTrace'] = {} excInfo = sys.exc_info() i = 0 while i < len(excInfo): dump['tbTrace'][i] = 'No args available: %s' % (excInfo[i],) i += 1 with open(filename, 'wb') as f: pickle.dump(dump, f) print('Coredump created in %s' % (filename,)) def moveAndDeleteVPlanFile(self, absFile): # file => Actual file (move to lastFile) # self.lastFile => last File (delete) path = absFile if os.path.exists(self.lastFile) and self.lastFile != '': # delete os.remove(self.lastFile) print('File %s removed' % (self.lastFile)) # move file_new = '' if self.config.get('options','backupFiles') == 'True': file_new = "%s.backup" % (path) if self.config.get('options', 'backupFolder') != 'False': backdir = self.config.get('options', 'backupFolder') if backdir[-1:] is not os.sep: backdir = '%s%s' % (backdir, os.sep) file_new = '%s%s%s%s.backup' % (self.getWatchPath(), os.sep, backdir, file) # before: check if folder eixsts. backdir = '%s%s%s' % (self.getWatchPath(), os.sep, backdir) if not os.path.exists(backdir): os.makedirs(backdir) print('Copy %s to %s for backup.' % (path, file_new)) shutil.copyfile(path, file_new) if self.config.get('options', 'delUpFile') == 'True' and os.path.exists(path): print('Delete uploaded file %s' % (path)) os.remove(path) self.lastFile = file_new def handlingFlsCSV(self, fileName): # send a notification self.showToolTip('Neuer Vertretungsplan','Es wurde eine neue Datei gefunden und wird jetzt verarbeitet.','info') absPath = os.path.join(self.config.get('default', 'path'), fileName) try: djp = FlsCsvParser(self.config, self.dlg, absPath) djp.planFileLoaded.connect(self.planFileLoaded) djp.planParserPrepared.connect(self.planParserPrepared) djp.loadFile() djp.preParse() djp.parse() djp.postParse() data = djp.getResult() self.showToolTip('Neuer Vertretungsplan','Vertretungsplan wurde verarbeitet und wird nun hochgeladen.','info') self.send_table(data, absPath) except Exception as e: self.showToolTip('Neuer Vertretungsplan','Vertretungsplan konnte nicht verarbeitet werden, weil die Datei fehlerhaft ist.','error') print('Error: %s' % (str(e),)) import traceback traceback.print_exc() self.dlg.addError(str(e)) self.showDlg.emit() raise # something to show? if self.dlg.hasData: self.showDlg.emit() def handlingDavinciJson(self, fileName): # send a notification self.showToolTip('Neuer Vertretungsplan','Es wurde eine neue Datei gefunden und wird jetzt verarbeitet.','info') absPath = os.path.join(self.config.get('default', 'path'), fileName) try: djp = DavinciJsonParser(self.config, self.dlg, absPath) djp.planFileLoaded.connect(self.planFileLoaded) djp.planParserPrepared.connect(self.planParserPrepared) djp.loadFile() djp.preParse() djp.parse() djp.postParse() data = djp.getResult() self.showToolTip('Neuer Vertretungsplan','Vertretungsplan wurde verarbeitet und wird nun hochgeladen.','info') self.send_table(data, absPath) except Exception as e: self.showToolTip('Neuer Vertretungsplan','Vertretungsplan konnte nicht verarbeitet werden, weil die Datei fehlerhaft ist.','error') print('Error: %s' % (str(e),)) import traceback traceback.print_exc() self.dlg.addError(str(e)) self.showDlg.emit() raise # something to show? if self.dlg.hasData: self.showDlg.emit() def handlingJson(self, fileName): path = self.getWatchPath() sep = os.sep absPath = path+sep+fileName content = None with open(absPath, 'rb') as f: content = f.read() try: if self.filesAreUTF8(): content = content.decode('utf-8') else: content = content.decode('iso-8859-1') except: self.showToolTip('Neuer Vertretungsplan','Vertretungsplan konnte nicht verarbeitet werden, weil die Datei fehlerhaft encodiert ist.','error') return None if content is None: self.showToolTip('Neuer Vertretungsplan','Vertretungsplan konnte nicht verarbeitet werden, weil die Datei keine Daten enthält.','error') return None # now decode. try: jsonDta = json.loads(content) except: self.showToolTip('Neuer Vertretungsplan','Vertretungsplan konnte nicht verarbeitet werden, weil die Datei fehlerhaft ist.','error') return None else: self.showToolTip('Neuer Vertretungsplan','Vertretungsplan wurde verarbeitet und wird nun hochgeladen.','info') self.send_table(jsonDta, absPath) @pyqtSlot() def planFileLoaded(self): pass @pyqtSlot() def planParserPrepared(self): if self.dlg.isVisible(): self.hideDlg.emit() self.cleanupDlg.emit() def loadConfig(self): self.config = configparser.ConfigParser() self.config.read(["config.ini"], encoding='utf-8') def bye(self): print("Auf Wiedersehen!") self.tray.sayGoodbye() os._exit(0) def initTray(self): menu = ( ('Planer hochladen', None, self.getNewFiles), ('Beenden', None, self.bye), ) if os.name in "nt": from taskbardemo import DemoTaskbar, Taskbar self.tray = DemoTaskbar(self,'fls_logo.ico', 'FLS Vertretungsplaner', menu) elif os.name == 'posix': #from linuxtaskbar import Taskbar #w = QtGui.QWidget() #self.tray = Taskbar(w, QtGui.QIcon('fls_logo.ico'), 'FLS Vertretungsplaner', menu) #self.tray.show() pass if self.tray is not None: self.tray.showInfo('Vertretungsplaner startet...', 'Bei Problemen wenden Sie sich bitte an das Website-Team der Friedrich-List-Schule Wiesbaden.') def getXmlRaw(self, element): return element.childNodes[0].wholeText def __init__(self): super().__init__() self.lastFile = '' self.run = True self.config = None self.tray = None self.search = None self.before = None self.locked = False self.loadConfig() self.initTray() debugLog = False try: debugLog = self.config.getboolean('options', 'debugLogs') except KeyError: pass except configparser.NoOptionError: pass self.dlg = ErrorDialog(debugLog) self.showDlg.connect(self.dlg.open) self.hideDlg.connect(self.dlg.close) self.cleanupDlg.connect(self.dlg.cleanup) self.initPlan()