update format using black
This commit is contained in:
16
README.md
16
README.md
@@ -50,3 +50,19 @@ python -m infomentor --addcalendar <username>
|
||||
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}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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'''<?xml version="1.0" encoding="utf-8"?><propfind xmlns='DAV:'>'''
|
||||
u'''<prop><current-user-principal/></prop></propfind>'''
|
||||
u"""<?xml version="1.0" encoding="utf-8"?><propfind xmlns='DAV:'>"""
|
||||
u"""<prop><current-user-principal/></prop></propfind>"""
|
||||
)
|
||||
propfind_calendar_home_set = (
|
||||
u'''<?xml version="1.0" encoding="utf-8"?><propfind xmlns='DAV:' '''
|
||||
u'''xmlns:cd='urn:ietf:params:xml:ns:caldav'><prop>'''
|
||||
u'''<cd:calendar-home-set/></prop></propfind>'''
|
||||
u"""<?xml version="1.0" encoding="utf-8"?><propfind xmlns='DAV:' """
|
||||
u"""xmlns:cd='urn:ietf:params:xml:ns:caldav'><prop>"""
|
||||
u"""<cd:calendar-home-set/></prop></propfind>"""
|
||||
)
|
||||
|
||||
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,8 +94,8 @@ 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
|
||||
@@ -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
|
||||
|
||||
@@ -266,11 +266,16 @@ 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()
|
||||
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))
|
||||
@@ -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())
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -39,7 +45,7 @@ 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)
|
||||
|
||||
@@ -57,33 +63,37 @@ class User(ModelBase):
|
||||
|
||||
def __repr__(self):
|
||||
return "<User(name='%s', password='%s')>" % (
|
||||
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 "<Notification(type='{}', info='{}')>".format(
|
||||
self.ntype, self.info)
|
||||
return "<Notification(type='{}', info='{}')>".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,50 +124,62 @@ 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 "<News(id='%d', title='%s')>" % (
|
||||
self.id, self.title)
|
||||
return "<News(id='%d', title='%s')>" % (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 "<CalendarEntry(id='%d', title='%s', hash='%s')>" % (
|
||||
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'))
|
||||
user_id = Column(Integer, ForeignKey("users.id"))
|
||||
degraded_count = Column(Integer)
|
||||
datetime = Column(DateTime)
|
||||
info = Column(String)
|
||||
@@ -169,14 +192,19 @@ class ApiStatus(ModelBase):
|
||||
|
||||
def __repr__(self):
|
||||
return "<ApiStatus(ok='%s', NOKs='%d', info='%s')>" % (
|
||||
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,7 +215,7 @@ 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)
|
||||
|
||||
@@ -205,5 +233,6 @@ class ICloudCalendar(ModelBase):
|
||||
|
||||
def __repr__(self):
|
||||
return "<ICloudCalendar(user='%s' cal='%s')>" % (
|
||||
self.icloud_user, self.calendarname)
|
||||
|
||||
self.icloud_user,
|
||||
self.calendarname,
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
25
setup.py
25
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',
|
||||
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' ],
|
||||
install_requires=[
|
||||
"pycrypto",
|
||||
"request",
|
||||
"sqlalchemy",
|
||||
"dateparser",
|
||||
"python-pushover",
|
||||
"flask",
|
||||
"flask-bootstrap",
|
||||
"caldav",
|
||||
"bs4",
|
||||
"icalendar",
|
||||
],
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user