From 693711abc1b17a178e097ff9cdfd9307ce4e86a4 Mon Sep 17 00:00:00 2001 From: Matthias Bilger Date: Wed, 8 May 2019 05:06:37 +0200 Subject: [PATCH] update format using black --- README.md | 16 ++ infomentor/__main__.py | 159 ++++++++------- infomentor/config.py | 36 ++-- infomentor/connector.py | 361 +++++++++++++++++------------------ infomentor/db.py | 8 +- infomentor/flock.py | 29 +-- infomentor/icloudcalendar.py | 70 ++++--- infomentor/informer.py | 18 +- infomentor/model.py | 125 +++++++----- infomentor/web.py | 45 +++-- infomentor/wsgi.py | 2 +- setup.py | 27 ++- 12 files changed, 488 insertions(+), 408 deletions(-) diff --git a/README.md b/README.md index 01396e4..c8d3493 100644 --- a/README.md +++ b/README.md @@ -50,3 +50,19 @@ python -m infomentor --addcalendar The login process is a bit scary and mostly hacked. It happens often on the first run, that the login is not ready, the second run then should work without errors. The script shall be run every 10 minutes, that will keep the session alive and minimize errors. + + + + + + + + +TODO: + +:: + +{'id': 1342049, 'title': 'Jade LZK HSU 1. und 2. Klasse', 'time': '10:30 - 11:30', 'notes': '', 'enumType': 'Custom1', 'type': 'cal-custom1', 'info': {'id': 0, 'type': None, + 'resources': [{'id': 589680, 'fileType': 'docx', 'title': 'Lernziele HSU das Jahr.docx', 'url': '/Resources/Resource/Download/589680?api=IM2', 'fileTypeName': 'Word processor', 'apiType': 'IM2', 'connectionId': 1342049, 'connectionType': + 'Calendar'}]}, 'establishmentName': None, 'date': '18.01.2019', 'isEditable': False, 'isDeletable': False, 'startDate': '2019-01-18', 'startTime': '10:30', 'endDate': '2019-01-18', 'endTime': '11:30', 'allDayEvent': False, 'resourcesNeed + ingConnection': None, 'thirdPartyApiCalendarEventId': None, 'thirdPartyApiCalendarSeriesId': None, 'thirdPartyApiCalendarId': None, 'attendeeIds': None} diff --git a/infomentor/__main__.py b/infomentor/__main__.py index a65102d..1d8a017 100644 --- a/infomentor/__main__.py +++ b/infomentor/__main__.py @@ -7,45 +7,50 @@ import os from infomentor import db, model, connector, informer -logformat='{asctime} - {name:25s} - {levelname:8s} - {message}' +logformat = "{asctime} - {name:25s} - {levelname:8s} - {message}" + + def logtofile(): from logging.handlers import RotatingFileHandler - handler = RotatingFileHandler('log.txt', maxBytes=51200, backupCount=5) + + handler = RotatingFileHandler("log.txt", maxBytes=51200, backupCount=5) logging.basicConfig( - level=logging.INFO, - format=logformat, - handlers=[handler], - style='{' - ) -def logtoconsole(): - logging.basicConfig( - level=logging.DEBUG, - format=logformat, - style='{' + level=logging.INFO, format=logformat, handlers=[handler], style="{" ) + +def logtoconsole(): + logging.basicConfig(level=logging.DEBUG, format=logformat, style="{") + + def parse_args(arglist): - parser = argparse.ArgumentParser(description='Infomentor Grabber and Notifier') - parser.add_argument('--nolog', action='store_true', help='print log instead of logging to file') - parser.add_argument('--adduser', type=str, help='add user') - parser.add_argument('--addfake', type=str, help='add fake') - parser.add_argument('--addpushover', type=str, help='add pushover') - parser.add_argument('--addmail', type=str, help='add mail') - parser.add_argument('--addcalendar', type=str, help='add icloud calendar') - parser.add_argument('--test', action='store_true', help='test') + parser = argparse.ArgumentParser(description="Infomentor Grabber and Notifier") + parser.add_argument( + "--nolog", action="store_true", help="print log instead of logging to file" + ) + parser.add_argument("--adduser", type=str, help="add user") + parser.add_argument("--addfake", type=str, help="add fake") + parser.add_argument("--addpushover", type=str, help="add pushover") + parser.add_argument("--addmail", type=str, help="add mail") + parser.add_argument("--addcalendar", type=str, help="add icloud calendar") + parser.add_argument("--test", action="store_true", help="test") args = parser.parse_args(arglist) return args + def add_user(username): session = db.get_db() - existing_user = session.query(model.User).filter(model.User.name == username).one_or_none() + existing_user = ( + session.query(model.User).filter(model.User.name == username).one_or_none() + ) if existing_user is not None: - print('user exists, change pw') + print("user exists, change pw") else: - print(f'Adding user: {username}') + print(f"Adding user: {username}") import getpass - password = getpass.getpass(prompt='Password: ') + + password = getpass.getpass(prompt="Password: ") if existing_user is not None: existing_user.password = password else: @@ -58,98 +63,111 @@ def add_pushover(username): session = db.get_db() user = session.query(model.User).filter(model.User.name == username).one_or_none() if user is None: - print('user does not exist') + print("user does not exist") return else: - print(f'Adding PUSHOVER for user: {username}') - id = input('PUSHOVER ID: ') - user.notification = model.Notification(ntype=model.Notification.Types.PUSHOVER, info=id) + print(f"Adding PUSHOVER for user: {username}") + id = input("PUSHOVER ID: ") + user.notification = model.Notification( + ntype=model.Notification.Types.PUSHOVER, info=id + ) session.commit() + def add_fake(username): session = db.get_db() user = session.query(model.User).filter(model.User.name == username).one_or_none() if user is None: - print('user does not exist') + print("user does not exist") return else: - print(f'Adding FAKE for user: {username}') - user.notification = model.Notification(ntype=model.Notification.Types.FAKE, info='') + print(f"Adding FAKE for user: {username}") + user.notification = model.Notification(ntype=model.Notification.Types.FAKE, info="") session.commit() + def add_calendar(username): session = db.get_db() user = session.query(model.User).filter(model.User.name == username).one_or_none() if user is None: - print('user does not exist') + print("user does not exist") return else: - print(f'Adding icloud calendar for user: {username}') - id = input('Apple ID: ') + print(f"Adding icloud calendar for user: {username}") + id = input("Apple ID: ") import getpass - password = getpass.getpass(prompt='iCloud Password: ') - calendar = input('Calendar: ') - user.icalendar = model.ICloudCalendar(icloud_user=id, password=password, calendarname=calendar) + + password = getpass.getpass(prompt="iCloud Password: ") + calendar = input("Calendar: ") + user.icalendar = model.ICloudCalendar( + icloud_user=id, password=password, calendarname=calendar + ) session.commit() + def add_mail(username): session = db.get_db() user = session.query(model.User).filter(model.User.name == username).one_or_none() if user is None: - print('user does not exist') + print("user does not exist") return else: - print(f'Adding MAIL for user: {username}') - address = input('MAIL ADDRESS: ') - user.notification = model.Notification(ntype=model.Notification.Types.EMAIL, info=address) + print(f"Adding MAIL for user: {username}") + address = input("MAIL ADDRESS: ") + user.notification = model.Notification( + ntype=model.Notification.Types.EMAIL, info=address + ) session.commit() + def notify_users(): logger = logging.getLogger(__name__) session = db.get_db() for user in session.query(model.User): - logger.info('==== USER: %s =====', user.name) - if user.password == '': - logger.warning('User %s not enabled', user.name) + logger.info("==== USER: %s =====", user.name) + if user.password == "": + logger.warning("User %s not enabled", user.name) continue now = datetime.datetime.now() im = connector.Infomentor(user.name) im.login(user.password) - logger.info('User loggedin') - statusinfo = {'datetime': now, 'ok': False, 'info': '', 'degraded_count':0} + logger.info("User loggedin") + statusinfo = {"datetime": now, "ok": False, "info": "", "degraded_count": 0} if user.apistatus is None: user.apistatus = model.ApiStatus(**statusinfo) - logger.info('Former API status: %s', user.apistatus) + logger.info("Former API status: %s", user.apistatus) try: i = informer.Informer(user, im, logger=logger) i.update_news() i.update_homework() i.update_calendar() - statusinfo['ok'] = True - statusinfo['degraded'] = False + statusinfo["ok"] = True + statusinfo["degraded"] = False except Exception as e: - inforstr = 'Exception occured:\n{}:{}\n'.format(type(e).__name__, e) - statusinfo['ok'] = False - statusinfo['info'] = inforstr + inforstr = "Exception occured:\n{}:{}\n".format(type(e).__name__, e) + statusinfo["ok"] = False + statusinfo["info"] = inforstr logger.exception("Something went wrong") finally: - if user.apistatus.ok == True and statusinfo['ok'] == False: - logger.error('Switching to degraded state %s', user.name) - statusinfo['degraded_count'] = 1 - if user.apistatus.ok == False and statusinfo['ok'] == False: + if user.apistatus.ok == True and statusinfo["ok"] == False: + logger.error("Switching to degraded state %s", user.name) + statusinfo["degraded_count"] = 1 + if user.apistatus.ok == False and statusinfo["ok"] == False: if user.apistatus.degraded_count == 1 and user.wantstatus: - im.send_status_update(statusinfo['info']) + im.send_status_update(statusinfo["info"]) try: - statusinfo['degraded_count'] = user.apistatus['degraded_count'] + 1 + statusinfo["degraded_count"] = user.apistatus["degraded_count"] + 1 except Exception as e: - statusinfo['degraded_count'] = 1 - if user.apistatus.ok == False and statusinfo['ok'] == True: - statusinfo['info'] = 'Works as expected, failed {} times'.format(user.apistatus.degraded_count) - statusinfo['degraded_count'] = 0 + statusinfo["degraded_count"] = 1 + if user.apistatus.ok == False and statusinfo["ok"] == True: + statusinfo["info"] = "Works as expected, failed {} times".format( + user.apistatus.degraded_count + ) + statusinfo["degraded_count"] = 0 if user.wantstatus: - im.send_status_update(statusinfo['info']) + im.send_status_update(statusinfo["info"]) user.apistatus.updateobj(statusinfo) - logger.info('New API status: %s', user.apistatus) + logger.info("New API status: %s", user.apistatus) session.commit() @@ -161,12 +179,12 @@ def main(): logtoconsole() else: logtofile() - logger = logging.getLogger('Infomentor Notifier') - logger.info('STARTING-------------------- %s', os.getpid()) + logger = logging.getLogger("Infomentor Notifier") + logger.info("STARTING-------------------- %s", os.getpid()) try: lock = flock.flock() if not lock.aquire(): - logger.info('EXITING - PREVIOUS IS RUNNING') + logger.info("EXITING - PREVIOUS IS RUNNING") raise Exception() if args.addfake: add_fake(args.addfake) @@ -181,10 +199,11 @@ def main(): else: notify_users() except Exception as e: - logger.info('Exceptional exit') - logger.exception('Info') + logger.info("Exceptional exit") + logger.exception("Info") finally: - logger.info('EXITING--------------------- %s', os.getpid()) + logger.info("EXITING--------------------- %s", os.getpid()) + if __name__ == "__main__": main() diff --git a/infomentor/config.py b/infomentor/config.py index 07ea746..2fc21e8 100644 --- a/infomentor/config.py +++ b/infomentor/config.py @@ -5,21 +5,22 @@ _config = None def _set_defaults(config): - config.add_section('pushover') - config.add_section('general') - config.add_section('smtp') - config['pushover']['apikey'] = '' - config['general']['secretkey'] = '' - config['general']['baseurl'] = '' - config['general']['adminmail'] = '' - config['general']['im1url'] = 'https://im1.infomentor.de/Germany/Germany/Production' - config['general']['mimurl'] = 'https://mein.infomentor.de' - config['smtp']['server'] = '' - config['smtp']['username'] = '' - config['smtp']['password'] = '' + config.add_section("pushover") + config.add_section("general") + config.add_section("smtp") + config["pushover"]["apikey"] = "" + config["general"]["secretkey"] = "" + config["general"]["baseurl"] = "" + config["general"]["adminmail"] = "" + config["general"]["im1url"] = "https://im1.infomentor.de/Germany/Germany/Production" + config["general"]["mimurl"] = "https://mein.infomentor.de" + config["smtp"]["server"] = "" + config["smtp"]["username"] = "" + config["smtp"]["password"] = "" -def load(cfg_file='infomentor.ini'): - '''Load the config from the file''' + +def load(cfg_file="infomentor.ini"): + """Load the config from the file""" global _config if _config is None: _config = configparser.ConfigParser() @@ -29,8 +30,9 @@ def load(cfg_file='infomentor.ini'): _config.read(cfg_file) return _config -def save(cfg_file='infomentor.ini'): - '''Write config to file''' + +def save(cfg_file="infomentor.ini"): + """Write config to file""" global _config - with open(cfg_file, 'w+') as f: + with open(cfg_file, "w+") as f: _config.write(f) diff --git a/infomentor/connector.py b/infomentor/connector.py index f663ebd..f702fec 100644 --- a/infomentor/connector.py +++ b/infomentor/connector.py @@ -12,82 +12,85 @@ import urllib.parse import uuid from infomentor import model, config + class InfomentorFile(object): - '''Represent a file which is downloaded''' + """Represent a file which is downloaded""" + def __init__(self, directory, filename): if directory is None: - raise Exception('directory is required') + raise Exception("directory is required") self.filename = filename self.randomid = str(uuid.uuid4()) self.directory = directory @property def targetfile(self): - '''Get the files output path''' + """Get the files output path""" return os.path.join(self.directory, self.fullfilename) @property def targetdir(self): - '''Get the files output directory''' + """Get the files output directory""" return os.path.join(self.directory, self.randomid) @property def fullfilename(self): if self.filename is None: - raise Exception('no filename set') + raise Exception("no filename set") return os.path.join(self.randomid, self.filename) def save_file(self, content): - '''Write file to the registered path''' + """Write file to the registered path""" os.makedirs(self.targetdir, exist_ok=True) - with open(self.targetfile, 'wb+') as f: + with open(self.targetfile, "wb+") as f: f.write(content) class Infomentor(object): - '''Basic object for handling infomentor site login and fetching of data''' + """Basic object for handling infomentor site login and fetching of data""" def __init__(self, user, logger=None): - '''Create informentor object for username''' + """Create informentor object for username""" self.logger = logger or logging.getLogger(__name__) self._last_result = None self.user = user self.cfg = config.load() - self.BASE_IM1 = self.cfg['general']['im1url'] - self.BASE_MIM = self.cfg['general']['mimurl'] + self.BASE_IM1 = self.cfg["general"]["im1url"] + self.BASE_MIM = self.cfg["general"]["mimurl"] self._create_session() def _create_session(self): - '''Create the session for handling all further requests''' + """Create the session for handling all further requests""" self.session = requests.Session() - self.session.headers.update({'User-Agent': 'Mozilla/5.0'}) + self.session.headers.update({"User-Agent": "Mozilla/5.0"}) self._load_cookies() def _load_cookies(self): - '''Setup the cookie requests''' - os.makedirs('cookiejars', exist_ok=True) + """Setup the cookie requests""" + os.makedirs("cookiejars", exist_ok=True) self.session.cookies = http.cookiejar.MozillaCookieJar( - filename='cookiejars/{}.cookies'.format(self.user) + filename="cookiejars/{}.cookies".format(self.user) ) with contextlib.suppress(FileNotFoundError): self.session.cookies.load(ignore_discard=True, ignore_expires=True) def login(self, password): - '''Login using the given password''' + """Login using the given password""" if self.logged_in(self.user): return True self._do_login(self.user, password) return self.logged_in(self.user) def logged_in(self, username): - '''Check if user is logged in (with cookies)''' + """Check if user is logged in (with cookies)""" ts = math.floor(time.time()) - auth_check_url = 'authentication/authentication/' + \ - 'isauthenticated/?_={}000'.format(ts) + auth_check_url = ( + "authentication/authentication/" + "isauthenticated/?_={}000".format(ts) + ) url = self._mim_url(auth_check_url) r = self._do_post(url) - self.logger.info('%s loggedin: %s', username, r.text) - return r.text.lower() == 'true' + self.logger.info("%s loggedin: %s", username, r.text) + return r.text.lower() == "true" def _do_login(self, user, password): self._do_request_initial_token() @@ -95,121 +98,116 @@ class Infomentor(object): self._finalize_login() def _do_request_initial_token(self): - '''Request initial oauth_token''' + """Request initial oauth_token""" # Get the initial oauth token self._do_get(self._mim_url()) self._oauth_token = self._get_auth_token() # This request is performed by the browser, the reason is unclear - login_url = self._mim_url( - 'Authentication/Authentication/Login?ReturnUrl=%2F') + login_url = self._mim_url("Authentication/Authentication/Login?ReturnUrl=%2F") self._do_get(login_url) def _get_auth_token(self): - '''Reading oauth_token from response text''' + """Reading oauth_token from response text""" token_re = r'name="oauth_token" value="([^"]*)"' tokens = re.findall(token_re, self._last_result.text) if len(tokens) != 1: - self.logger.error('OAUTH_TOKEN not found') - raise Exception('Invalid Count of tokens') + self.logger.error("OAUTH_TOKEN not found") + raise Exception("Invalid Count of tokens") return tokens[0] def _perform_login(self, password): - self._do_post( - self._im1_url('mentor/'), - data={'oauth_token': self._oauth_token} - ) + self._do_post(self._im1_url("mentor/"), data={"oauth_token": self._oauth_token}) # Extract the hidden fields content payload = self._get_hidden_fields() # update with the missing and the login parameters - payload.update({ - 'login_ascx$txtNotandanafn': self.user, - 'login_ascx$txtLykilord': password, - '__EVENTTARGET': 'login_ascx$btnLogin', - '__EVENTARGUMENT': '' - }) - - # perform the login - self._do_post( - self._im1_url('mentor/'), - data=payload, - headers={ - 'Referer': self._im1_url('mentor/'), - 'Content-Type': 'application/x-www-form-urlencoded' + payload.update( + { + "login_ascx$txtNotandanafn": self.user, + "login_ascx$txtLykilord": password, + "__EVENTTARGET": "login_ascx$btnLogin", + "__EVENTARGUMENT": "", } ) + # perform the login + self._do_post( + self._im1_url("mentor/"), + data=payload, + headers={ + "Referer": self._im1_url("mentor/"), + "Content-Type": "application/x-www-form-urlencoded", + }, + ) + def _get_hidden_fields(self): - '''Extracts key/value elements from hidden fields''' + """Extracts key/value elements from hidden fields""" hiddenfields = self._extract_hidden_fields() field_values = {} for f in hiddenfields: names = re.findall('name="([^"]*)"', f) if len(names) != 1: - self.logger.error('Could not parse hidden field (fieldname)') + self.logger.error("Could not parse hidden field (fieldname)") continue values = re.findall('value="([^"]*)"', f) if len(values) != 1: - self.logger.error('Could not parse hidden field (value)') + self.logger.error("Could not parse hidden field (value)") continue field_values[names[0]] = values[0] return field_values def _extract_hidden_fields(self): - '''Extracts all the hidden fields from a infomentor login page''' + """Extracts all the hidden fields from a infomentor login page""" hidden_re = '' hiddenfields = re.findall(hidden_re, self._last_result.text) return hiddenfields def _finalize_login(self): - '''The final login step to get the cookie''' + """The final login step to get the cookie""" # Read the oauth token which is the final token for the login oauth_token = self._get_auth_token() - self._do_post( - self._im1_url('mentor/'), - data={'oauth_token': oauth_token} - ) + self._do_post(self._im1_url("mentor/"), data={"oauth_token": oauth_token}) self._do_get(self._mim_url()) def _do_post(self, url, **kwargs): - '''Post request for session''' - self.logger.info('post to: %s', url) - if 'data' in kwargs: - self.logger.info('data: %s', json.dumps(kwargs['data'])) + """Post request for session""" + self.logger.info("post to: %s", url) + if "data" in kwargs: + self.logger.info("data: %s", json.dumps(kwargs["data"])) self._last_result = self.session.post(url, **kwargs) - self.logger.info('result: %d', self._last_result.status_code) + self.logger.info("result: %d", self._last_result.status_code) self._save_cookies() return self._last_result def _do_get(self, url, **kwargs): - '''get request for session''' - self.logger.info('get: %s', url) + """get request for session""" + self.logger.info("get: %s", url) self._last_result = self.session.get(url, **kwargs) - self.logger.info('result: %d', self._last_result.status_code) + self.logger.info("result: %d", self._last_result.status_code) self._save_cookies() if self._last_result.status_code != 200: - raise Exception('Got response with code {}'.format( - self._last_result.status_code - )) + raise Exception( + "Got response with code {}".format(self._last_result.status_code) + ) return self._last_result def _save_cookies(self): - '''Save cookies''' + """Save cookies""" self.session.cookies.save(ignore_discard=True, ignore_expires=True) def download_file(self, url, filename=None, directory=None): - '''download a file with given name or provided filename''' - self.logger.info('fetching download: %s', url) + """download a file with given name or provided filename""" + self.logger.info("fetching download: %s", url) if filename is not None or directory is not None: return self._download_file(url, directory, filename) else: - self.logger.error('fetching download requires filename or folder') - raise Exception('Download Failed') + self.logger.error("fetching download requires filename or folder") + raise Exception("Download Failed") def _get_filename_from_cd(self): - '''determine filename from headers or random uuid''' - cd = self._last_result.headers.get('content-disposition') + """determine filename from headers or random uuid""" + cd = self._last_result.headers.get("content-disposition") if cd: - filename_re = r''' + filename_re = r""" .* # Anything (?: filename=(?P.+) # normal filename @@ -217,198 +215,188 @@ class Infomentor(object): filename\*=(?P.+) # extended filename ) # The filename (?:$|;.*) # End or more - ''' + """ fname = re.match(filename_re, cd, flags=re.VERBOSE) - filename = fname.group('native') + filename = fname.group("native") if filename is not None and len(filename) != 0: return filename - filename = fname.group('extended') + filename = fname.group("extended") if filename is not None and len(filename) != 0: encoding, string = filename.split("''") return urllib.parse.unquote(string, encoding) filename = str(uuid.uuid4()) self.logger.warning( - 'no filename detected in %s: using random filename %s', - cd, filename) + "no filename detected in %s: using random filename %s", cd, filename + ) return filename def _download_file(self, url, directory, filename=None): - '''download a file with provided filename''' + """download a file with provided filename""" file = InfomentorFile(directory, filename) - self.logger.info('to (randomized) directory %s', file.targetdir) + self.logger.info("to (randomized) directory %s", file.targetdir) url = self._mim_url(url) self._do_get(url) if filename is None: - self.logger.info('determine filename from headers') + self.logger.info("determine filename from headers") filename = self._get_filename_from_cd() - self.logger.info('determined filename: %s', filename) + self.logger.info("determined filename: %s", filename) file.filename = filename - self.logger.info('full filename: %s', file.fullfilename) + self.logger.info("full filename: %s", file.fullfilename) file.save_file(self._last_result.content) return file.fullfilename - def _build_url(self, path='', base=None): - '''Builds a general infomentor (IM1) url''' + def _build_url(self, path="", base=None): + """Builds a general infomentor (IM1) url""" if base is None: base = self.BASE_IM1 - return '{}/{}'.format(base, path) + return "{}/{}".format(base, path) - def _mim_url(self, path=''): - '''Builds a general mein.infomentor (MIM) url''' + def _mim_url(self, path=""): + """Builds a general mein.infomentor (MIM) url""" return self._build_url(path, base=self.BASE_MIM) - def _im1_url(self, path=''): - '''Builds a general infomentor (IM1) url''' + def _im1_url(self, path=""): + """Builds a general infomentor (IM1) url""" return self._build_url(path, base=self.BASE_IM1) def get_news_list(self): - '''Fetches the list of news''' - self.logger.info('fetching news') - self._do_post(self._mim_url('News/news/GetArticleList')) + """Fetches the list of news""" + self.logger.info("fetching news") + self._do_post(self._mim_url("News/news/GetArticleList")) news_json = self.get_json_return() - return [str(i['id']) for i in news_json['items']] + return [str(i["id"]) for i in news_json["items"]] def get_news_article(self, id): - '''Receive all the article information''' + """Receive all the article information""" article_json = self.get_article(id) - storenewsdata = { - k: article_json[k] for k in ('title', 'content', 'date') - } - storenewsdata['news_id'] = article_json['id'] - storenewsdata['raw'] = json.dumps(article_json) - storenewsdata['attachments'] = [] - for attachment in article_json['attachments']: - self.logger.info('found attachment %s', attachment['title']) - att_id = re.findall('Download/([0-9]+)?', attachment['url'])[0] - f = self.download_file(attachment['url'], directory='files') + storenewsdata = {k: article_json[k] for k in ("title", "content", "date")} + storenewsdata["news_id"] = article_json["id"] + storenewsdata["raw"] = json.dumps(article_json) + storenewsdata["attachments"] = [] + for attachment in article_json["attachments"]: + self.logger.info("found attachment %s", attachment["title"]) + att_id = re.findall("Download/([0-9]+)?", attachment["url"])[0] + f = self.download_file(attachment["url"], directory="files") try: - storenewsdata['attachments'].append(model.Attachment(attachment_id=att_id, url=attachment['url'], localpath=f, title=attachment['title'])) + storenewsdata["attachments"].append( + model.Attachment( + attachment_id=att_id, + url=attachment["url"], + localpath=f, + title=attachment["title"], + ) + ) except Exception as e: - self.logger.exception('failed to store attachment') + self.logger.exception("failed to store attachment") news = model.News(**storenewsdata) with contextlib.suppress(Exception): news.imagefile = self.get_newsimage(id) return news def get_article(self, id): - '''Receive the article details''' - self.logger.info('fetching article: %s', id) - self._do_post( - self._mim_url('News/news/GetArticle'), - data={'id': id} - ) + """Receive the article details""" + self.logger.info("fetching article: %s", id) + self._do_post(self._mim_url("News/news/GetArticle"), data={"id": id}) return self.get_json_return() def get_newsimage(self, id): - '''Fetches the image to a corresponding news entry''' - self.logger.info('fetching article image: %s', id) - filename = '{}.image'.format(id) - url = 'News/NewsImage/GetImage?id={}'.format(id) - return self.download_file(url, directory='images', filename=filename) + """Fetches the image to a corresponding news entry""" + self.logger.info("fetching article image: %s", id) + filename = "{}.image".format(id) + url = "News/NewsImage/GetImage?id={}".format(id) + return self.download_file(url, directory="images", filename=filename) def get_calendar(self, offset=0, weeks=1): - '''Fetches a list of calendar entries''' - self.logger.info('fetching calendar') + """Fetches a list of calendar entries""" + self.logger.info("fetching calendar") utcoffset = self._get_utc_offset() - data = { - 'UTCOffset': utcoffset, - } - schoolyear = int(datetime.datetime.now().strftime('%Y')) - if int(datetime.datetime.now().strftime('%m')) <= 7: + data = {"UTCOffset": utcoffset} + schoolyear = int(datetime.datetime.now().strftime("%Y")) + if int(datetime.datetime.now().strftime("%m")) <= 7: schoolyear -= 1 - data['start'] = '{}-08-01'.format(schoolyear) - data['end'] = '{}-07-31'.format(schoolyear+1) - self._do_post( - self._mim_url('Calendar/Calendar/getEntries'), - data=data - ) + data["start"] = "{}-08-01".format(schoolyear) + data["end"] = "{}-07-31".format(schoolyear + 1) + self._do_post(self._mim_url("Calendar/Calendar/getEntries"), data=data) return self.get_json_return() def get_event(self, eventid): - '''Request the event details from the server''' - self.logger.info('fetching calendar entry') - data = {'id': eventid} - self._do_post( - self._mim_url('Calendar/Calendar/getEntry'), - data=data - ) + """Request the event details from the server""" + self.logger.info("fetching calendar entry") + data = {"id": eventid} + self._do_post(self._mim_url("Calendar/Calendar/getEntry"), data=data) return self.get_json_return() def get_homework(self, offset=0): - '''Receives a list of homework for the week''' - self.logger.info('fetching homework') + """Receives a list of homework for the week""" + self.logger.info("fetching homework") startofweek = self._get_start_of_week(offset) - timestamp = startofweek.strftime('%Y-%m-%dT00:00:00.000Z') - data = { - 'date': timestamp, - 'isWeek': True, - } - self._do_post( - self._mim_url('Homework/homework/GetHomework'), - data=data - ) + timestamp = startofweek.strftime("%Y-%m-%dT00:00:00.000Z") + data = {"date": timestamp, "isWeek": True} + self._do_post(self._mim_url("Homework/homework/GetHomework"), data=data) return self.get_json_return() def get_homework_list(self): - '''Receives a list of homework''' + """Receives a list of homework""" self._homework = {} homeworklist = [] homework = [] homework.extend(self.get_homework()) homework.extend(self.get_homework(1)) for dategroup in homework: - for hw in dategroup['items']: - if hw['id'] == 0: + for hw in dategroup["items"]: + if hw["id"] == 0: continue else: - self._homework[hw['id']] = hw - homeworklist.append(hw['id']) + self._homework[hw["id"]] = hw + homeworklist.append(hw["id"]) return homeworklist def get_homework_info(self, id): hw = self._homework[id] - storehw = { - k: hw[k] for k in ('subject', 'courseElement') - } - storehw['homework_id'] = hw['id'] - storehw['text'] = hw['homeworkText'] - storehw['attachments'] = [] - for attachment in hw['attachments']: - self.logger.info('found attachment %s', attachment['title']) - att_id = re.findall('Download/([0-9]+)?', attachment['url'])[0] - f = self.download_file(attachment['url'], directory='files') + storehw = {k: hw[k] for k in ("subject", "courseElement")} + storehw["homework_id"] = hw["id"] + storehw["text"] = hw["homeworkText"] + storehw["attachments"] = [] + for attachment in hw["attachments"]: + self.logger.info("found attachment %s", attachment["title"]) + att_id = re.findall("Download/([0-9]+)?", attachment["url"])[0] + f = self.download_file(attachment["url"], directory="files") try: - storehw['attachments'].append(model.Attachment(attachment_id=att_id, url=attachment['url'], localpath=f, title=attachment['title'])) + storehw["attachments"].append( + model.Attachment( + attachment_id=att_id, + url=attachment["url"], + localpath=f, + title=attachment["title"], + ) + ) except Exception as e: - self.logger.exception('failed to store attachment') + self.logger.exception("failed to store attachment") hw = model.Homework(**storehw) return hw def get_timetable(self, offset=0): - self.logger.info('fetching timetable') + self.logger.info("fetching timetable") data = self._get_week_dates(offset) - self._do_post( - self._mim_url('timetable/timetable/gettimetablelist'), - data=data - ) + self._do_post(self._mim_url("timetable/timetable/gettimetablelist"), data=data) return self.get_json_return() def get_json_return(self): - '''Read the json from the result or write the response to the log''' + """Read the json from the result or write the response to the log""" try: return self._last_result.json() except json.JSONDecodeError as jse: - self.logger.exception('JSON coudl not be decoded') - self.logger.info('status code: %d', self._last_result.status_code) - self.logger.info('response was: %s', self._last_result.text) + self.logger.exception("JSON coudl not be decoded") + self.logger.info("status code: %d", self._last_result.status_code) + self.logger.info("response was: %s", self._last_result.text) raise def _get_week_dates(self, offset=0, weeks=1): - '''Convert the current week, an offset and the timespan in weeks to start and end days''' - weekoffset = datetime.timedelta(days=7*offset) + """Convert the current week, an offset and the timespan in weeks to start and end days""" + weekoffset = datetime.timedelta(days=7 * offset) startofweek = self._get_start_of_week() - endofweek = startofweek + datetime.timedelta(days=5+7*(weeks-1)) + endofweek = startofweek + datetime.timedelta(days=5 + 7 * (weeks - 1)) startofweek += weekoffset endofweek += weekoffset @@ -416,23 +404,22 @@ class Infomentor(object): utcoffset = self._get_utc_offset() data = { - 'UTCOffset': utcoffset, - 'start': startofweek.strftime('%Y-%m-%d'), - 'end': endofweek.strftime('%Y-%m-%d'), + "UTCOffset": utcoffset, + "start": startofweek.strftime("%Y-%m-%d"), + "end": endofweek.strftime("%Y-%m-%d"), } return data def _get_utc_offset(self): - '''Calculate the UTCoffset''' + """Calculate the UTCoffset""" now = datetime.datetime.now() utctime = datetime.datetime.utcnow() - return (now.hour - utctime.hour)*60 + return (now.hour - utctime.hour) * 60 def _get_start_of_week(self, offset=0): - '''Get the start of the current + offset week''' + """Get the start of the current + offset week""" now = datetime.datetime.now() dayofweek = now.weekday() startofweek = now - datetime.timedelta(days=dayofweek) - startofweek -= datetime.timedelta(days=offset*7) + startofweek -= datetime.timedelta(days=offset * 7) return startofweek - diff --git a/infomentor/db.py b/infomentor/db.py index 87e3729..0d185d5 100755 --- a/infomentor/db.py +++ b/infomentor/db.py @@ -4,14 +4,14 @@ from sqlalchemy.orm import sessionmaker _session = None -def get_db(filename='infomentor.db'): - '''Get the database session for infomentor''' + +def get_db(filename="infomentor.db"): + """Get the database session for infomentor""" global _session if _session is None: - engine = create_engine(f'sqlite:///{filename}') + engine = create_engine(f"sqlite:///{filename}") model.ModelBase.metadata.create_all(engine) model.ModelBase.metadata.bind = engine DBSession = sessionmaker(bind=engine) _session = DBSession() return _session - diff --git a/infomentor/flock.py b/infomentor/flock.py index b498f2f..0b31874 100644 --- a/infomentor/flock.py +++ b/infomentor/flock.py @@ -1,44 +1,46 @@ import os + class flock(object): - '''A simple filelocking mechanism to prevent execution at the same time''' - filename = '.im.lock' + """A simple filelocking mechanism to prevent execution at the same time""" + + filename = ".im.lock" def __init__(self): - '''Creates an object with the current pid''' + """Creates an object with the current pid""" self.pid = os.getpid() def aquire(self): - '''Try to get the lock, if it fails it returns False''' + """Try to get the lock, if it fails it returns False""" if self.is_locked(): return False - with open(self.filename, 'w+') as f: - f.write('{}'.format(self.pid)) + with open(self.filename, "w+") as f: + f.write("{}".format(self.pid)) return True def release(self): - '''Release the lock''' + """Release the lock""" if self.own_lock(): os.unlink(self.filename) def __del__(self): - '''Release on delete''' + """Release on delete""" self.release() def own_lock(self): - '''Check if the lock is assigned to the current pid''' + """Check if the lock is assigned to the current pid""" lockinfo = self._get_lockinfo() return lockinfo == self.pid def is_locked(self): - '''Check if it is currently locked''' + """Check if it is currently locked""" lockinfo = self._get_lockinfo() if not lockinfo: return False return self._is_process_active(lockinfo) def _is_process_active(self, pid): - '''Check if the processed having the lock is still running''' + """Check if the processed having the lock is still running""" try: os.kill(pid, 0) return pid != self.pid @@ -46,12 +48,11 @@ class flock(object): return False def _get_lockinfo(self): - '''Retrieve the information about the lock''' + """Retrieve the information about the lock""" try: lock = {} - with open(self.filename, 'r') as f: + with open(self.filename, "r") as f: pid = int(f.read().strip()) return pid except Exception as e: return False - diff --git a/infomentor/icloudcalendar.py b/infomentor/icloudcalendar.py index c942f4a..dc4f55f 100644 --- a/infomentor/icloudcalendar.py +++ b/infomentor/icloudcalendar.py @@ -8,26 +8,27 @@ from lxml import etree import requests from requests.auth import HTTPBasicAuth + class iCloudConnector(object): icloud_url = "https://caldav.icloud.com" username = None password = None propfind_principal = ( - u'''''' - u'''''' + u"""""" + u"""""" ) propfind_calendar_home_set = ( - u'''''' - u'''''' + u"""""" + u"""""" ) def __init__(self, username, password, **kwargs): self.username = username self.password = password - if 'icloud_url' in kwargs: - self.icloud_url = kwargs['icloud_url'] + if "icloud_url" in kwargs: + self.icloud_url = kwargs["icloud_url"] self.discover() self.get_calendars() @@ -42,45 +43,40 @@ class iCloudConnector(object): def discover(self): # Build and dispatch a request to discover the prncipal us for the # given credentials - headers = { - 'Depth': '1', - } + headers = {"Depth": "1"} auth = HTTPBasicAuth(self.username, self.password) principal_response = requests.request( - 'PROPFIND', + "PROPFIND", self.icloud_url, auth=auth, headers=headers, - data=self.propfind_principal.encode('utf-8') + data=self.propfind_principal.encode("utf-8"), ) if principal_response.status_code != 207: - print('Failed to retrieve Principal: ', - principal_response.status_code) + print("Failed to retrieve Principal: ", principal_response.status_code) exit(-1) # Parse the resulting XML response - soup = BeautifulSoup(principal_response.content, 'lxml') - self.principal_path = soup.find( - 'current-user-principal' - ).find('href').get_text() + soup = BeautifulSoup(principal_response.content, "lxml") + self.principal_path = ( + soup.find("current-user-principal").find("href").get_text() + ) discovery_url = self.icloud_url + self.principal_path # Next use the discovery URL to get more detailed properties - such as # the calendar-home-set home_set_response = requests.request( - 'PROPFIND', + "PROPFIND", discovery_url, auth=auth, headers=headers, - data=self.propfind_calendar_home_set.encode('utf-8') + data=self.propfind_calendar_home_set.encode("utf-8"), ) if home_set_response.status_code != 207: - print('Failed to retrieve calendar-home-set', - home_set_response.status_code) + print("Failed to retrieve calendar-home-set", home_set_response.status_code) exit(-1) # And then extract the calendar-home-set URL - soup = BeautifulSoup(home_set_response.content, 'lxml') + soup = BeautifulSoup(home_set_response.content, "lxml") self.calendar_home_set_url = soup.find( - 'href', - attrs={'xmlns':'DAV:'} + "href", attrs={"xmlns": "DAV:"} ).get_text() # get_calendars @@ -88,9 +84,9 @@ class iCloudConnector(object): # we can create a local object to control calendars (thin wrapper around # CALDAV library) def get_calendars(self): - self.caldav = caldav.DAVClient(self.calendar_home_set_url, - username=self.username, - password=self.password) + self.caldav = caldav.DAVClient( + self.calendar_home_set_url, username=self.username, password=self.password + ) self.principal = self.caldav.principal() self.calendars = self.principal.calendars() @@ -98,16 +94,16 @@ class iCloudConnector(object): if len(self.calendars) > 0: for calendar in self.calendars: - properties = calendar.get_properties([dav.DisplayName(), ]) - display_name = properties['{DAV:}displayname'] + properties = calendar.get_properties([dav.DisplayName()]) + display_name = properties["{DAV:}displayname"] if display_name == name: return calendar return None - def create_calendar(self,name): + def create_calendar(self, name): return self.principal.make_calendar(name=name) - def delete_all_events(self,calendar): + def delete_all_events(self, calendar): for event in calendar.events(): event.delete() return True @@ -116,12 +112,14 @@ class iCloudConnector(object): # to do pass - def create_simple_timed_event(self,start_datetime, end_datetime, summary, - description): + def create_simple_timed_event( + self, start_datetime, end_datetime, summary, description + ): # to do pass - def create_simple_dated_event(self,start_datetime, end_datetime, summary, - description): + def create_simple_dated_event( + self, start_datetime, end_datetime, summary, description + ): # to do pass diff --git a/infomentor/informer.py b/infomentor/informer.py index 857f677..0a7efb3 100755 --- a/infomentor/informer.py +++ b/infomentor/informer.py @@ -266,12 +266,17 @@ class Informer(object): new_cal_hash = hashlib.sha1(new_cal_entry).hexdigest() session = db.get_db() storedata = { - 'calendar_id': uid, - 'ical': new_cal_entry, - 'hash': new_cal_hash + "calendar_id": uid, + "ical": new_cal_entry, + "hash": new_cal_hash, } - calendarentry = session.query(model.CalendarEntry).filter(model.CalendarEntry.calendar_id == uid) .with_parent(self.user, "calendarentries").one_or_none() - if calendarentry is not None : + calendarentry = ( + session.query(model.CalendarEntry) + .filter(model.CalendarEntry.calendar_id == uid) + .with_parent(self.user, "calendarentries") + .one_or_none() + ) + if calendarentry is not None: if calendarentry.hash == new_cal_hash: self.logger.info("no change for calendar entry {}".format(uid)) continue @@ -286,6 +291,5 @@ class Informer(object): self.user.calendarentries.append(calendarentry) session.commit() - self.logger.debug(new_cal_entry.decode('utf-8')) + self.logger.debug(new_cal_entry.decode("utf-8")) cal.add_event(calend.to_ical()) - diff --git a/infomentor/model.py b/infomentor/model.py index 30c79f9..eba0db1 100755 --- a/infomentor/model.py +++ b/infomentor/model.py @@ -11,17 +11,23 @@ cfg = config.load() ModelBase = declarative_base() -_PASSWORD_SECRET_KEY = cfg['general']['secretkey'] +_PASSWORD_SECRET_KEY = cfg["general"]["secretkey"] BS = 16 + + def pad(s): diff = BS - len(s) % BS - return (s + (diff) * chr(diff)).encode('utf8') + return (s + (diff) * chr(diff)).encode("utf8") + + def unpad(s): - return s[0:-s[-1]].decode('utf8') + return s[0 : -s[-1]].decode("utf8") + class User(ModelBase): - '''The infomentor user.''' - __tablename__ = 'users' + """The infomentor user.""" + + __tablename__ = "users" id = Column(Integer, primary_key=True) name = Column(String) @@ -30,8 +36,8 @@ class User(ModelBase): apistatus = relationship("ApiStatus", back_populates="user", uselist=False) icalendar = relationship("ICloudCalendar", back_populates="user", uselist=False) wantstatus = Column(Boolean) - homeworks = relationship("Homework", back_populates="user") - news = relationship("News",back_populates="user") + homeworks = relationship("Homework", back_populates="user") + news = relationship("News", back_populates="user") calendarentries = relationship("CalendarEntry", back_populates="user", uselist=True) def __init__(self, *args, **kwargs): @@ -39,9 +45,9 @@ class User(ModelBase): super().__init__(*args, **kwargs) def _setup_cipher(self): - if not hasattr(self, 'cipher'): + if not hasattr(self, "cipher"): aeskey = hashlib.sha256(_PASSWORD_SECRET_KEY.encode()).digest() - self.cipher = AES.new(aeskey,AES.MODE_ECB) + self.cipher = AES.new(aeskey, AES.MODE_ECB) @property def password(self): @@ -57,33 +63,37 @@ class User(ModelBase): def __repr__(self): return "" % ( - self.name, '*' * len(self.password)) + self.name, + "*" * len(self.password), + ) class Notification(ModelBase): - '''This contains the information about the type of notification and additional the key to reach out to the user''' - __tablename__ = 'notifications' + """This contains the information about the type of notification and additional the key to reach out to the user""" + + __tablename__ = "notifications" class Types(enum.Enum): - '''Supported notification types''' + """Supported notification types""" + PUSHOVER = 1 EMAIL = 2 FAKE = 3 id = Column(Integer, primary_key=True) - user_id = Column(Integer, ForeignKey('users.id')) + user_id = Column(Integer, ForeignKey("users.id")) ntype = Column(Enum(Types)) info = Column(String) user = relationship("User", back_populates="notification") def __repr__(self): - return "".format( - self.ntype, self.info) + return "".format(self.ntype, self.info) class Attachment(ModelBase): - '''General attachment type for homework and news''' - __tablename__ = 'attachments' + """General attachment type for homework and news""" + + __tablename__ = "attachments" id = Column(Integer, primary_key=True) attachment_id = Column(Integer) @@ -91,20 +101,21 @@ class Attachment(ModelBase): url = Column(String) title = Column(String) localpath = Column(String) - news_id = Column(Integer, ForeignKey('news.id')) - homework_id = Column(Integer, ForeignKey('homework.id')) + news_id = Column(Integer, ForeignKey("news.id")) + homework_id = Column(Integer, ForeignKey("homework.id")) news = relationship("News", back_populates="attachments") homework = relationship("Homework", back_populates="attachments") class News(ModelBase): - '''A News entry''' - __tablename__ = 'news' + """A News entry""" + + __tablename__ = "news" id = Column(Integer, primary_key=True) news_id = Column(Integer) - user_id = Column(Integer, ForeignKey('users.id')) + user_id = Column(Integer, ForeignKey("users.id")) title = Column(String) content = Column(String) category = Column(String) @@ -113,52 +124,64 @@ class News(ModelBase): imagefile = Column(String) notified = Column(Boolean, default=False) raw = Column(String) - attachments = relationship("Attachment", order_by=Attachment.id, back_populates="news", uselist=True) + attachments = relationship( + "Attachment", order_by=Attachment.id, back_populates="news", uselist=True + ) user = relationship("User", back_populates="news") def __repr__(self): - return "" % ( - self.id, self.title) + return "" % (self.id, self.title) + class CalendarEntry(ModelBase): - '''A News entry''' - __tablename__ = 'calendarentries' + """A News entry""" + + __tablename__ = "calendarentries" id = Column(Integer, primary_key=True) calendar_id = Column(Integer) title = Column(String) - user_id = Column(Integer, ForeignKey('users.id')) + user_id = Column(Integer, ForeignKey("users.id")) ical = Column(String) hash = Column(String) user = relationship("User", back_populates="calendarentries") def __repr__(self): return "" % ( - self.id, self.title, hash) + self.id, + self.title, + hash, + ) + class Homework(ModelBase): - '''A homework entry''' - __tablename__ = 'homework' + """A homework entry""" + + __tablename__ = "homework" id = Column(Integer, primary_key=True) homework_id = Column(Integer) - user_id = Column(Integer, ForeignKey('users.id')) + user_id = Column(Integer, ForeignKey("users.id")) subject = Column(String) courseElement = Column(String) text = Column(String) date = Column(String) imageUrl = Column(String) - attachments = relationship("Attachment", order_by=Attachment.id, back_populates="homework") + attachments = relationship( + "Attachment", order_by=Attachment.id, back_populates="homework" + ) user = relationship("User", back_populates="homeworks") + class ApiStatus(ModelBase): - '''Representing the result of the last trys to access the api, represented as one status''' - __tablename__ = 'api_status' + """Representing the result of the last trys to access the api, represented as one status""" + + __tablename__ = "api_status" id = Column(Integer, primary_key=True) - user_id = Column(Integer, ForeignKey('users.id')) - degraded_count = Column(Integer) - datetime = Column(DateTime) + user_id = Column(Integer, ForeignKey("users.id")) + degraded_count = Column(Integer) + datetime = Column(DateTime) info = Column(String) ok = Column(Boolean) user = relationship("User", back_populates="apistatus", uselist=False) @@ -169,14 +192,19 @@ class ApiStatus(ModelBase): def __repr__(self): return "" % ( - self.ok, self.degraded_count, self.info) + self.ok, + self.degraded_count, + self.info, + ) + class ICloudCalendar(ModelBase): - '''An icloud account with a calendar name''' - __tablename__ = 'icloud_calendar' - + """An icloud account with a calendar name""" + + __tablename__ = "icloud_calendar" + id = Column(Integer, primary_key=True) - user_id = Column(Integer, ForeignKey('users.id')) + user_id = Column(Integer, ForeignKey("users.id")) icloud_user = Column(String) icloud_pwd = Column(String) calendarname = Column(String) @@ -187,9 +215,9 @@ class ICloudCalendar(ModelBase): super().__init__(*args, **kwargs) def _setup_cipher(self): - if not hasattr(self, 'cipher'): + if not hasattr(self, "cipher"): aeskey = hashlib.sha256(_PASSWORD_SECRET_KEY.encode()).digest() - self.cipher = AES.new(aeskey,AES.MODE_ECB) + self.cipher = AES.new(aeskey, AES.MODE_ECB) @property def password(self): @@ -205,5 +233,6 @@ class ICloudCalendar(ModelBase): def __repr__(self): return "" % ( - self.icloud_user, self.calendarname) - + self.icloud_user, + self.calendarname, + ) diff --git a/infomentor/web.py b/infomentor/web.py index a60b512..7996149 100644 --- a/infomentor/web.py +++ b/infomentor/web.py @@ -5,34 +5,47 @@ from flask_bootstrap import Bootstrap app = Flask(__name__) Bootstrap(app) -@app.route('/') + +@app.route("/") def home(): - return render_template('notfound.html') + return render_template("notfound.html") -@app.route('/addlogin') + +@app.route("/addlogin") def extra(): - return render_template('addlogin.html') + return render_template("addlogin.html") -@app.route('/create', methods=['POST']) + +@app.route("/create", methods=["POST"]) def create(): - if request.form['accesscode'] != 'fhKjzgV/BXWq4YRxUPO4qYlHWCDf': - return redirect(url_for('home')) + if request.form["accesscode"] != "fhKjzgV/BXWq4YRxUPO4qYlHWCDf": + return redirect(url_for("home")) session = db.get_db() - username = request.form['username'] - existing_user = session.query(model.User).filter(model.User.name == username).one_or_none() + username = request.form["username"] + existing_user = ( + session.query(model.User).filter(model.User.name == username).one_or_none() + ) if existing_user is not None: - return redirect(url_for('home')) + return redirect(url_for("home")) - password = request.form['password'] + password = request.form["password"] user = model.User(name=username, password=password) - if request.form['notify'] == 'mail': - user.notification = [model.Notification(ntype=model.Notification.Types.EMAIL, info=request.form['info'])] + if request.form["notify"] == "mail": + user.notification = [ + model.Notification( + ntype=model.Notification.Types.EMAIL, info=request.form["info"] + ) + ] else: - user.notification = [model.Notification(ntype=model.Notification.Types.PUSHOVER, info=request.form['info'])] + user.notification = [ + model.Notification( + ntype=model.Notification.Types.PUSHOVER, info=request.form["info"] + ) + ] session.add(user) session.commit() return "success" -if __name__ == '__main__': - app.run(debug=True) +if __name__ == "__main__": + app.run(debug=True) diff --git a/infomentor/wsgi.py b/infomentor/wsgi.py index b344968..40ae99a 100644 --- a/infomentor/wsgi.py +++ b/infomentor/wsgi.py @@ -1,4 +1,4 @@ from infomentor.web import app if __name__ == "__main__": - app.run() + app.run() diff --git a/setup.py b/setup.py index 0920d3a..a939076 100644 --- a/setup.py +++ b/setup.py @@ -1,12 +1,23 @@ from setuptools import setup, find_packages setup( - name = 'infomentor', - version = '1.0.0', - url = 'https://github.com/mypackage.git', - author = 'Matthias Bilger', - author_email = 'matthias@bilger.info', - description = 'grab infomentor news and push or mail them', - packages = find_packages(), - install_requires = ['pycrypto', 'request', 'sqlalchemy', 'dateparser', 'python-pushover', 'flask', 'flask-bootstrap', 'caldav', 'bs4', 'icalendar' ], + name="infomentor", + version="1.0.0", + url="https://github.com/mypackage.git", + author="Matthias Bilger", + author_email="matthias@bilger.info", + description="grab infomentor news and push or mail them", + packages=find_packages(), + install_requires=[ + "pycrypto", + "request", + "sqlalchemy", + "dateparser", + "python-pushover", + "flask", + "flask-bootstrap", + "caldav", + "bs4", + "icalendar", + ], )