This repository has been archived on 2020-02-17. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
infomentor/infomentor/model.py

193 lines
6.1 KiB
Python
Executable File

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey, Enum, DateTime, Boolean
from sqlalchemy.orm import relationship
from Crypto.Cipher import AES
import base64
import enum
import hashlib
from infomentor import config
cfg = config.load()
ModelBase = declarative_base()
_PASSWORD_SECRET_KEY = cfg['general']['secretkey']
BS = 16
def pad(s):
diff = BS - len(s) % BS
return (s + (diff) * chr(diff)).encode('utf8')
def unpad(s):
return s[0:-s[-1]].decode('utf8')
class User(ModelBase):
'''The infomentor user.'''
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
enc_password = Column(String)
notification = relationship("Notification", back_populates="user", uselist=False)
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")
def __init__(self, *args, **kwargs):
self._setup_cipher()
super().__init__(*args, **kwargs)
def _setup_cipher(self):
if not hasattr(self, 'cipher'):
aeskey = hashlib.sha256(_PASSWORD_SECRET_KEY.encode()).digest()
self.cipher = AES.new(aeskey,AES.MODE_ECB)
@property
def password(self):
self._setup_cipher()
decoded = self.cipher.decrypt(base64.b64decode(self.enc_password))
return unpad(decoded)
@password.setter
def password(self, value):
self._setup_cipher()
encoded = base64.b64encode(self.cipher.encrypt(pad(value)))
self.enc_password = encoded
def __repr__(self):
return "<User(name='%s', password='%s')>" % (
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'
class Types(enum.Enum):
'''Supported notification types'''
PUSHOVER = 1
EMAIL = 2
FAKE = 3
id = Column(Integer, primary_key=True)
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)
class Attachment(ModelBase):
'''General attachment type for homework and news'''
__tablename__ = 'attachments'
id = Column(Integer, primary_key=True)
attachment_id = Column(Integer)
filetype = Column(String)
url = Column(String)
title = Column(String)
localpath = Column(String)
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'
id = Column(Integer, primary_key=True)
news_id = Column(Integer)
user_id = Column(Integer, ForeignKey('users.id'))
title = Column(String)
content = Column(String)
category = Column(String)
date = Column(String)
imageUrl = Column(String)
imagefile = Column(String)
notified = Column(Boolean, default=False)
raw = Column(String)
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)
class Homework(ModelBase):
'''A homework entry'''
__tablename__ = 'homework'
id = Column(Integer, primary_key=True)
homework_id = Column(Integer)
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")
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'
id = Column(Integer, primary_key=True)
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)
def updateobj(self, data):
for key, value in data.items():
setattr(self, key, value)
def __repr__(self):
return "<ApiStatus(ok='%s', NOKs='%d', info='%s')>" % (
self.ok, self.degraded_count, self.info)
class ICloudCalendar(ModelBase):
'''An icloud account with a calendar name'''
__tablename__ = 'icloud_calendar'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id'))
icloud_user = Column(String)
icloud_pwd = Column(String)
calendarname = Column(String)
user = relationship("User", back_populates="icalendar", uselist=False)
def __init__(self, *args, **kwargs):
self._setup_cipher()
super().__init__(*args, **kwargs)
def _setup_cipher(self):
if not hasattr(self, 'cipher'):
aeskey = hashlib.sha256(_PASSWORD_SECRET_KEY.encode()).digest()
self.cipher = AES.new(aeskey,AES.MODE_ECB)
@property
def password(self):
self._setup_cipher()
decoded = self.cipher.decrypt(base64.b64decode(self.icloud_pwd))
return unpad(decoded)
@password.setter
def password(self, value):
self._setup_cipher()
encoded = base64.b64encode(self.cipher.encrypt(pad(value)))
self.icloud_pwd = encoded
def __repr__(self):
return "<ICloudCalendar(user='%s' cal='%s')>" % (
self.icloud_user, self.calendarname)