WIP: database rework 1 (broken state)

Signed-off-by: HeshamTB <hishaminv@gmail.com>
This commit is contained in:
HeshamTB 2022-06-05 13:54:31 +03:00
parent 2c4840b5c3
commit 7d0d1b0f0e
Signed by: Hesham
GPG Key ID: 74876157D199B09E
6 changed files with 509 additions and 246 deletions

View File

@ -47,12 +47,22 @@ def create_iot_dev_token(data: dict):
encoded_jwt = jwt.encode(to_encode, JWT_SECRET, algorithm=JWT_ALGO) encoded_jwt = jwt.encode(to_encode, JWT_SECRET, algorithm=JWT_ALGO)
return encoded_jwt return encoded_jwt
def valid_iot_token(token : str, db: Session): def valid_iot_door_token(token : str, db: Session):
try: try:
payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGO]) payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGO])
except jwt.DecodeError: except jwt.DecodeError:
return None return None
mac_signed = payload.get("bluetooth_mac") mac_signed = payload.get("bluetooth_mac")
device = crud.get_iot_entity_by_bluetooth_mac(db, mac_signed) device = crud.get_door_by_bluetooth_mac(db, mac_signed)
return device
def valid_iot_monitor_token(token : str, db: Session):
try:
payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGO])
except jwt.DecodeError:
return None
mac_signed = payload.get("bluetooth_mac")
device = crud.get_monitor_by_bluetooth_mac(db, mac_signed)
return device return device

View File

@ -7,22 +7,23 @@ from . import models, schemas, crypto, auth_helper
from datetime import datetime from datetime import datetime
# TODO: Data we can collect or log # TODO: Data we can collect or log
# - Last user connection (link to user)
# - Last Iot Entity Connection (link to IotEntity)
# - Any open request (link to user) # - Any open request (link to user)
# - Any polling from IotEntity? Maybe to much data
def get_user(db: Session, user_id: int): def get_user(db: Session, user_id: int):
return db.query(models.User).get(user_id) return db.query(models.User).get(user_id)
def get_iot_entity(db: Session, id: int): def get_door_by_id(door_id: int):
return db.query(models.IotEntity).get(id) return db.query(models.IotDoor).get(door_id)
def get_iot_entity_by_description(db: Session, description: str): def get_door_by_description(db: Session, description: str):
return db.query(models.IotEntity).filter(models.IotEntity.description == description).first() # TODO: 2 or more Desciptions may collide
return db.query(models.IotDoor).filter(models.IotDoor.description == description).first()
def get_iot_entity_by_bluetooth_mac(db: Session, bluetooth_mac: str): def get_door_by_bluetooth_mac(db: Session, bluetooth_mac: str):
return db.query(models.IotEntity).filter(models.IotEntity.bluetooth_mac == bluetooth_mac).first() return db.query(models.IotDoor).filter(models.IotDoor.bluetooth_mac == bluetooth_mac).first()
def get_monitor_by_bluetooth_mac(db: Session, bluetooth_mac: str):
return db.query(models.IotMonitor).filter(models.IotMonitor.bluetooth_mac == bluetooth_mac).first()
def get_user_by_email(db: Session, email: str): def get_user_by_email(db: Session, email: str):
return db.query(models.User).filter(models.User.email == email).first() return db.query(models.User).filter(models.User.email == email).first()
@ -33,14 +34,56 @@ def get_user_by_username(db: Session, username: str):
def get_users(db: Session, skip: int = 0, limit: int = 100): def get_users(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.User).offset(skip).limit(limit).all() return db.query(models.User).offset(skip).limit(limit).all()
def get_access_log_for_door_by_door_mac(db: Session, bluetooth_mac : str): def get_access_log_for_room(db: Session, room_id: int):
return db.query(models.DoorAccessLog).filter(models.DoorAccessLog.iot_dev_bluetooth_mac == bluetooth_mac).all() return db.query(models.DoorAccessLog).filter(models.DoorAccessLog.room == room_id).all()
def get_access_log_for_user_by_id(db: Session, id : str): def get_access_log_for_user_by_id(db: Session, id : str):
return db.query(models.DoorAccessLog).filter(models.DoorAccessLog.user_id == id).all() return db.query(models.DoorAccessLog).filter(models.DoorAccessLog.user_id == id).all()
def get_room_data_now(db: Session): def get_room_data_now(db: Session, room_id: int):
return db.query(models.RoomSensorData)[-1] return db.query(models.IotMonitor).filter(models.IotMonitor.room_id == room_id)
def get_doors(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.IotDoor).offset(skip).limit(limit).all()
def get_monitors(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.IotMonitor).offset(skip).limit(limit).all()
def get_rooms(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.Room).offset(skip).limit(limit).all()
def get_user_room_access_list_by_username(db: Session, username: str):
user : models.User = get_user_by_username(db, username)
links : List[models.UserRoomAuth] = db.query(models.UserRoomAuth).filter(models.UserRoomAuth.user_id == user.id).all()
return db.query(models.Room).filter(models.Room.authorized_users == user.id).all()
def get_room_door(db: Session, room_id: int):
door = db.query(models.IotDoor).filter(models.IotDoor.room_id == room_id).first()
return door
def get_room(db: Session, room_id: int):
room = db.query(models.Room).get(room_id)
return room
def get_room_access_log_for_user(db: Session, user_id: int, room_id: int):
log = db.query(models.DoorAccessLog).filter(models.DoorAccessLog.user_id == user_id, models.DoorAccessLog.room == room_id).all()
return log
def get_room_current_readings(db: Session, room: schemas.Room) -> models.IotMonitor:
room : models.Room = get_room(db, room.id)
monitor = db.query(models.IotMonitor).filter(models.IotMonitor.room_id == room.id).first()
return mon
def get_monitor_for_room(db: Session, room: schemas.Room) -> models.IotMonitor:
return db.query(models.IotMonitor).filter(models.IotMonitor.room_id == room.id).first()
def get_door_for_room(db: Session, room_id: int) -> models.IotDoor:
return db.query(models.IotDoor).filter(models.IotDoor.room_id == room_id).first()
def get_room_from_door(db: Session, door: models.IotDoor):
return get_room(db, door.room_id)
def create_user(db: Session, user: schemas.UserCreate): def create_user(db: Session, user: schemas.UserCreate):
key = crypto.gen_new_key(user.password) key = crypto.gen_new_key(user.password)
@ -52,62 +95,77 @@ def create_user(db: Session, user: schemas.UserCreate):
db.refresh(db_user) db.refresh(db_user)
return db_user return db_user
def get_iot_entities(db: Session, skip: int = 0, limit: int = 100): def create_door(db: Session, door: schemas.IotDoorCreate):
return db.query(models.IotEntity).offset(skip).limit(limit).all() db_item = models.IotDoor(room_id=door.room_id,
description=door.description,
bluetooth_mac=door.bluetooth_mac)
def create_iot_entity(db: Session, iot_entity: schemas.IotEntityCreate):
db_item = models.IotEntity(bluetooth_mac=iot_entity.bluetooth_mac,
description=iot_entity.description)
db.add(db_item) db.add(db_item)
db.commit() db.commit()
db.refresh(db_item) db.refresh(db_item)
return db_item return db_item
def create_user_link_to_iot(db: Session, user_id: int, iot_dev_id: int): def create_monitor(db: Session, monitor: schemas.IotMonitorCreate):
# Ensure link is not already present and it does not allow duplicates db_item = models.IotMonitor(room_id=monitor.room_id,
link = db.query(models.UserAuthToIoTDev).filter(models.UserAuthToIoTDev.user_id == user_id).filter(models.UserAuthToIoTDev.iot_entity_id == iot_dev_id).first() description=monitor.description,
if link: return True bluetooth_mac=monitor.bluetooth_mac)
new_link = models.UserAuthToIoTDev(user_id=user_id, iot_entity_id=iot_dev_id) db.add(db_item)
db.commit()
db.refresh(db_item)
return
def create_room(db: Session, room: schemas.RoomCreate):
db_item = models.Room(building_name=room.building_name,
building_number=room.building_number)
db.add(db_item)
db.commit()
db.refresh(db_item)
return db_item
def allow_user_room_access(db: Session, user_id: int, room_id: int):
link = db.query(models.UserRoomAuth).filter(models.UserRoomAuth.user_id == user_id, models.UserRoomAuth.room_id == room_id).first()
if link: return link
new_link = models.UserRoomAuth(user_id=user_id, room_id=room_id)
db.add(new_link) db.add(new_link)
db.commit() db.commit()
db.refresh(new_link) db.refresh(new_link)
return True return link
def remove_user_link_to_iot(db: Session, user_id: int, iot_dev_id: int): def disallow_user_room_access(db: Session, user_id, room_id: int):
# Ensure link is not already present and it does not allow duplicates link = db.query(models.UserRoomAuth).filter(models.UserRoomAuth.user_id == user_id, models.UserRoomAuth.room_id == room_id)
link = db.query(models.UserAuthToIoTDev).filter(models.UserAuthToIoTDev.user_id == user_id).filter(models.UserAuthToIoTDev.iot_entity_id == iot_dev_id).first()
if not link: return True if not link: return True
db.delete(link) db.delete(link)
db.flush() db.flush()
db.commit() db.commit()
#db.refresh(link)
return True return True
def set_open_door_request(db: Session, iot_entity_id: int, time_seconds : int): def open_door_request(db: Session, request: schemas.OpenRoomRequest, time_seconds: int = 10):
device = get_iot_entity(db, iot_entity_id) link = db.query(models.UserRoomAuth).filter(models.UserRoomAuth.user_id == request.user_id,
setattr(device, "open_request", True) models.UserRoomAuth.room_id == request.room_id).first()
if not link: return False
door : models.IotDoor = db.query(models.IotDoor).filter(models.IotDoor.room_id == request.room_id).first()
if not door: return False
setattr(door, "open_request", True)
if time_seconds < 1: if time_seconds < 1:
time_seconds = 10 # Magic number move to global constant time_seconds = 10 # Magic number move to global constant
setattr(device, "time_seconds", time_seconds) setattr(door, "time_seconds", time_seconds)
db.add(device) db.add(door)
db.commit() db.commit()
db.refresh(device) db.refresh(door)
return True return True
def clear_open_door_request(db: Session, iot_entity_id: int): def clear_open_door_request(db: Session, room_id: int):
device = get_iot_entity(db, iot_entity_id) door : models.IotDoor = db.query(models.IotDoor).filter(models.IotDoor.room_id == room_id).first()
setattr(device, "open_request", False) setattr(door, "open_request", False)
setattr(device, "time_seconds", 10) setattr(door, "time_seconds", 10)
db.add(device) db.add(door)
db.commit() db.commit()
db.refresh(device) db.refresh(door)
return True return True
def record_door_access_log(db: Session, entry: schemas.DoorAccessLog): def record_door_access_log(db: Session, entry: schemas.DoorAccessLog):
db_item = models.DoorAccessLog(user_id=entry.user_id, db_item = models.DoorAccessLog(user_id=entry.user_id,
iot_dev_bluetooth_mac=entry.door_bluetooth_mac, room=entry.room_id,
timestamp=entry.time) timestamp=entry.timestamp)
db.add(db_item) db.add(db_item)
db.commit() db.commit()
db.refresh(db_item) db.refresh(db_item)
@ -116,8 +174,19 @@ def record_room_sensor_data(db: Session, entry: schemas.IotMonitorRoomInfo):
db_item = models.RoomSensorData(humidity=entry.humidity, db_item = models.RoomSensorData(humidity=entry.humidity,
people=entry.people, people=entry.people,
temperature=entry.temperature, temperature=entry.temperature,
smoke_sensor_reading=entry.smoke_sensor_reading, smoke=entry.smoke,
timestamp=datetime.now()) timestamp=datetime.now())
db.add(db_item) db.add(db_item)
db.commit() db.commit()
db.refresh(db_item) db.refresh(db_item)
def on_access_list_change(db: Session, room_id: int, allow: bool):
# Use when a user is allowed or disallowed to a room.
door = get_door_for_room(db, room_id)
door.accesslist_counter = door.accesslist_counter + 1
db.add(door)
db.commit()
db.refresh(door)
# TODO: Get room sensor data
# TODO: Get room door status

View File

@ -2,7 +2,7 @@ from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db" SQLALCHEMY_DATABASE_URL = "sqlite:///./data.db"
# SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db" # SQLALCHEMY_DATABASE_URL = "postgresql://user:password@postgresserver/db"
# For sqlite # For sqlite

View File

@ -15,6 +15,30 @@ oauth = OAuth2PasswordBearer(tokenUrl="tkn")
app = FastAPI(title="IoT Building System") app = FastAPI(title="IoT Building System")
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"})
inactive_user_exception = HTTPException(status_code=status.HTTP_403_FORBIDDEN,
detail="Inactive user")
email_used_exception = HTTPException(status_code=400,
detail="Email already registered")
username_used_exception = HTTPException(status_code=400,
detail="Username already registerd")
user_not_found_exception = HTTPException(status_code=404,
detail="User not found")
room_not_found_exception = HTTPException(status_code=404,
detail="Room not found")
unauth_to_open = HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail="Unauthrized to open")
str_not_implemented = 'Not Implemented'
def get_db(): def get_db():
db = SessionLocal() db = SessionLocal()
@ -24,51 +48,33 @@ def get_db():
db.close() db.close()
def get_current_user(token: str = Depends(oauth), db: Session = Depends(get_db)): def get_current_user(token: str = Depends(oauth), db: Session = Depends(get_db)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try: try:
payload = jwt.decode(token, auth_helper.JWT_SECRET, algorithms=[auth_helper.JWT_ALGO]) payload = jwt.decode(token, auth_helper.JWT_SECRET, algorithms=[auth_helper.JWT_ALGO])
username: str = payload.get("sub") username: str = payload.get("sub")
if username is None: if username is None:
raise credentials_exception raise credentials_exception
token_data = schemas.TokenData(username=username) #token_data = schemas.TokenData(username=username)
except jwt.PyJWTError: except jwt.PyJWTError:
raise credentials_exception raise credentials_exception
user = crud.get_user_by_username(db, username=token_data.username) user = crud.get_user_by_username(db, username=username)
if user is None: if user is None:
raise credentials_exception raise credentials_exception
return user return user
def get_current_active_user(current_user: schemas.User = Depends(get_current_user)): def get_current_active_user(current_user: schemas.User = Depends(get_current_user)):
if not current_user.is_active: if not current_user.is_active:
raise HTTPException(status_code=400, detail="Inactive user") raise inactive_user_exception
return current_user return current_user
def get_current_iot_device(current_device: schemas.IotBluetoothMac = Depends(),
db: Session = Depends(get_db)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
payload = jwt.decode(token, auth_helper.JWT_SECRET, algorithms=[auth_helper.JWT_ALGO])
mac_signed = payload.get("bluetooth_mac")
if (mac_signed != current_device): raise credentials_exception
device = crud.get_iot_entity_by_bluetooth_mac(db, mac_signed)
return device
@app.post("/users/reg", response_model=schemas.User, tags=['Users']) @app.post("/users/reg", response_model=schemas.User, tags=['Users'])
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)): def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
db_user = crud.get_user_by_email(db, email=user.email) db_user = crud.get_user_by_email(db, email=user.email)
if db_user: if db_user:
raise HTTPException(status_code=400, detail="Email already registered") raise email_used_exception
db_user = crud.get_user_by_username(db, username=user.username) db_user = crud.get_user_by_username(db, username=user.username)
if db_user: if db_user:
raise HTTPException(status_code=400, detail="Username already registerd") raise username_used_exception
return crud.create_user(db=db, user=user) return crud.create_user(db=db, user=user)
@ -81,77 +87,85 @@ def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
users = crud.get_users(db, skip=skip, limit=limit) users = crud.get_users(db, skip=skip, limit=limit)
return users return users
@app.get("/admin/iotentities/", response_model=List[schemas.IotEntity], tags=['Admin']) @app.get("/admin/doors/", response_model=List[schemas.IotDoor], tags=['Admin'])
def read_iot_entities(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): def read_iot_doors(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
iot_entities = crud.get_iot_entities(db, skip=skip, limit=limit) doors = crud.get_doors(db, skip=skip, limit=limit)
return iot_entities return doors
# TODO: Can duplicate @app.get("/admin/monitors/", response_model=List[schemas.IotMonitor], tags=['Admin'])
@app.post("/admin/iotentities/create", response_model=schemas.IotEntity, tags=['Admin']) def read_iot_doors(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
def create_iot_entities(iot_entity: schemas.IotEntityCreate, db: Session = Depends(get_db)): monitors = crud.get_monitors(db, skip=skip, limit=limit)
iot_entities = crud.create_iot_entity(db, iot_entity) return monitors
return iot_entities
@app.get("/admin/rooms/", response_model=List[schemas.Room], tags=['Admin'])
def read_iot_doors(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
rooms = crud.get_rooms(db, skip=skip, limit=limit)
return rooms
@app.post("/admin/create/door/", response_model=schemas.IotDoor, tags=['Admin'])
def create_iot_entities(door: schemas.IotDoorCreate, db: Session = Depends(get_db)):
#iot_entities = crud.create_iot_entity(db, iot_entity)
new_door = crud.create_door(db, door)
return new_door
@app.post("/admin/create/monitor/", response_model=schemas.IotMonitor, tags=['Admin'])
def create_iot_entities(monitor: schemas.IotMonitorCreate, db: Session = Depends(get_db)):
#iot_entities = crud.create_iot_entity(db, iot_entity)
new_monitor = crud.create_monitor(db, monitor)
return new_monitor
@app.post("/admin/create/room/", response_model=schemas.Room, tags=['Admin'])
def create_iot_entities(room: schemas.RoomCreate, db: Session = Depends(get_db)):
new_room = crud.create_room(db, room)
return new_room
@app.get("/admin/users/{user_id}", response_model=schemas.User, tags=['Admin']) @app.get("/admin/users/{user_id}", response_model=schemas.User, tags=['Admin'])
def read_user(user_id: int, db: Session = Depends(get_db)): def read_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.get_user(db, user_id=user_id) db_user = crud.get_user(db, user_id=user_id)
if db_user is None: if db_user is None:
raise HTTPException(status_code=404, detail="User not found") raise user_not_found_exception
return db_user return db_user
@app.post("/admin/users/allowdevice/id", tags=['Admin']) @app.post("/admin/users/allowaccess/id", response_model=schemas.AllowRoomAccessRequestID, tags=['Admin'])
def allow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db)): def allow_user_room_access_by_id(request: schemas.AllowRoomAccessRequestID,
db: Session = Depends(get_db)):
user = crud.get_user(db, request.user_id) user = crud.get_user(db, request.user_id)
if not user: if not user:
raise HTTPException(status_code=404, detail="User not found") raise user_not_found_exception
iot_entity = crud.get_iot_entity(db, request.iot_entity_id) room = crud.get_room(db, request.room_id)
if not iot_entity: if not room:
raise HTTPException(status_code=404, detail="Iot Entity not found") raise room_not_found_exception
res = crud.create_user_link_to_iot(db, request.user_id, request.iot_entity_id) #res = crud.create_user_link_to_iot(db, request.user_id, request.iot_entity_id)
res = crud.allow_user_room_access(db, request.user_id, request.room_id)
if not res: if not res:
raise HTTPException(status_code=500, detail="Could not complete operation") raise HTTPException(status_code=500, detail="Could not complete operation")
return return request
@app.post("/admin/users/disallowdevice/id", tags=['Admin']) @app.post("/admin/users/disallowaccess/id", tags=['Admin'])
def disallow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db)): def disallow_user_room_access_by_id(request: schemas.AllowRoomAccessRequestID,
db: Session = Depends(get_db)):
user = crud.get_user(db, request.user_id) user = crud.get_user(db, request.user_id)
if not user: if not user:
raise HTTPException(status_code=404, detail="User not found") raise user_not_found_exception
iot_entity = crud.get_iot_entity(db, request.iot_entity_id) room = crud.get_room(db, request.room_id)
if not iot_entity: if not room:
raise HTTPException(status_code=404, detail="Iot Entity not found") raise room_not_found_exception
res = crud.remove_user_link_to_iot(db, request.user_id, request.iot_entity_id) res = crud.disallow_user_room_access(db, request.user_id, request.room_id)
if not res: if not res:
raise HTTPException(status_code=500, detail="Could not complete operation") raise HTTPException(status_code=500, detail="Could not complete operation")
return return
@app.post("/admin/users/allowdevice/name", tags=['Admin']) @app.post("/admin/users/{user_id}/deactiveate", tags=['Admin'], description=str_not_implemented)
def allow_user_for_iot_entity_by_name(request: schemas.UserAllowForIotEntityRequestByUsername, db: Session = Depends(get_db)):
user = crud.get_user_by_username(db, request.username)
if not user:
raise HTTPException(status_code=404, detail="User not found")
iot_entity = crud.get_iot_entity_by_description(db, request.description)
if not iot_entity:
raise HTTPException(status_code=404, detail="Iot Entity not found")
res = crud.create_user_link_to_iot(db, user.id, iot_entity.id)
if not res:
raise HTTPException(status_code=500, detail="Could not complete operation")
return
@app.post("/admin/users/{user_id}/deactiveate", tags=['Admin'])
def deactiveate_user(user_id: int, db:Session = Depends(get_db)): def deactiveate_user(user_id: int, db:Session = Depends(get_db)):
return return
@app.post("/admin/users/{user_id}/activeate", tags=['Admin']) @app.post("/admin/users/{user_id}/activeate", tags=['Admin'], description=str_not_implemented)
def deactiveate_user(user_id: int, db:Session = Depends(get_db)): def deactiveate_user(user_id: int, db:Session = Depends(get_db)):
return return
@ -163,55 +177,68 @@ def generate_token_for_iot_device(bluetooth_mac : schemas.IotBluetoothMac,
tkn = auth_helper.create_iot_dev_token(data) tkn = auth_helper.create_iot_dev_token(data)
return {"access_token": tkn, "token_type": "bearer"} return {"access_token": tkn, "token_type": "bearer"}
@app.post("/admin/iotdevice/accesslog/", tags=['Admin']) @app.post("/admin/room/accesslog/", tags=['Admin'])
def get_access_log_for_door(request : schemas.AccessLogRequest, def get_access_log_for_door(request : schemas.RoomAccessLogRequest,
db : Session = Depends(get_db)): db : Session = Depends(get_db)):
device = crud.get_iot_entity_by_bluetooth_mac(db, request.bluetooth_mac) room = crud.get_room(db, request.room_id)
if not device: raise HTTPException(status_code=404, detail="Iot Entity not found") if not room: raise room_not_found_exception
return crud.get_access_log_for_door_by_door_mac(db, request.bluetooth_mac) return crud.get_access_log_for_room(db, request.room_id)
@app.post("/admin/user/accesslog/email/", tags=['Admin']) @app.post("/admin/room/authrizedusers/", tags=['Admin'])
def get_access_log_history_for_user(request : schemas.UserAccessLogRequestEmail, def get_room_authrized_users(room: schemas.Room,
db: Session = Depends(get_db)):
room: models.Room = crud.get_room(db, room_id=room.id)
return room.authorized_users
@app.post("/admin/user/accesslog/room/", tags=['Admin'])
def get_room_access_log_history_for_user(request : schemas.RoomAccessLogRequestUserID,
db : Session = Depends(get_db)): db : Session = Depends(get_db)):
user = crud.get_user_by_email(db, request.email) user = crud.get_user(db, request.user_id)
if not user: raise HTTPException(status_code=404, detail="User not found") if not user: raise user_not_found_exception
return crud.get_access_log_for_user_by_id(db, user.id) room = crud.get_room(db, request.room_id)
if not room: raise room_not_found_exception
return crud.get_room_access_log_for_user(db, request.user_id, request.room_id)
@app.post("/admin/user/accesslog/username/", tags=['Admin']) @app.post("/admin/user/accesslog/room/username", tags=['Admin'])
def get_access_log_history_for_user(request : schemas.UserAccessLogRequestUsername, def get_room_access_log_history_for_user_by_username(request : schemas.RoomAccessLogRequestUserUsername,
db : Session = Depends(get_db)): db : Session = Depends(get_db)):
user = crud.get_user_by_username(db, request.username) user = crud.get_user_by_username(db, request.username)
if not user: raise HTTPException(status_code=404, detail="User not found") if not user: raise user_not_found_exception
return crud.get_access_log_for_user_by_id(db, user.id) return crud.get_room_access_log_for_user(db, user.id, request.room_id)
@app.get("/users/acesslist/", response_model=List[schemas.IotEntity], tags=['Users']) @app.get("/users/acesslist/", response_model=List[schemas.Room], tags=['Users'])
def get_iot_access_list_for_user(db: Session = Depends(get_db), current_user: schemas.User = Depends(get_current_active_user)): def get_room_access_list_for_user(db: Session = Depends(get_db),
user = crud.get_user_by_username(db, current_user.username) current_user: models.User = Depends(get_current_active_user)):
return user.authorized_devices
@app.get("/admin/roominfo/now/", tags=['Admin']) # Can use the ORM method current_user.authrized_rooms pulls from database on demand...
def get_room_data(db: Session = Depends(get_db)): return current_user.authorized_rooms
return crud.get_room_data_now(db)
@app.get("/admin/roominfo/now/", response_model=schemas.IotMonitor, tags=['Admin'])
def get_room_data(room : schemas.Room,
db: Session = Depends(get_db)):
monitor = crud.get_room_current_readings(db, room)
return monitor
@app.get("/admin/roominfo/now/all", response_model=List[schemas.IotMonitor], tags=['Admin'])
def get_all_rooms_data(db: Session = Depends(get_db)):
monitors = crud.get_monitors(db)
return monitors
@app.post("/users/open", tags=['Users']) @app.post("/users/open", tags=['Users'])
def issue_open_door_command(command: schemas.OpenDoorRequestTime, def issue_open_door_command(request: schemas.OpenRoomRequest,
db: Session = Depends(get_db), db: Session = Depends(get_db),
current_user: schemas.User = Depends(get_current_active_user)): current_user: schemas.User = Depends(get_current_active_user)):
err = HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail="Unauthrized to open") #device = crud.open_door_request(db, request.room_id, request.time_seconds)
device = crud.get_iot_entity_by_bluetooth_mac(db, command.bluetooth_mac) #if not device: raise unauth_to_open # To no leak info
if not device: raise err user : models.User = crud.get_user(db, current_user.id)
# TODO: Use database search rather then this linear search log_entry = schemas.DoorAccessLog(user_id=current_user.id,
user = crud.get_user(db, current_user.id) room_id=request.room_id,
for dev in user.authorized_devices: timestamp=datetime.now())
if dev.bluetooth_mac == device.bluetooth_mac: res = crud.open_door_request(db, request=request)
crud.set_open_door_request(db, device.id, command.time_seconds) if not res: raise unauth_to_open
log_entry = schemas.DoorAccessLog(user_id=current_user.id, crud.record_door_access_log(db, log_entry)
door_bluetooth_mac=command.bluetooth_mac, return
time=datetime.now())
crud.record_door_access_log(db, log_entry)
return device
raise err
@app.post("/users/tkn", response_model=schemas.Token, tags=['Users']) @app.post("/users/tkn", response_model=schemas.Token, tags=['Users'])
@app.post("/tkn", response_model=schemas.Token, tags=['Users']) @app.post("/tkn", response_model=schemas.Token, tags=['Users'])
@ -230,28 +257,24 @@ def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(), db:
return {"access_token": access_token, "token_type": "bearer"} return {"access_token": access_token, "token_type": "bearer"}
@app.post("/iotdevice/door/status", response_model=schemas.IotDoorPollingResponse, tags=['Iot']) @app.post("/iotdevice/door/status", response_model=schemas.IotDoor, tags=['Iot'])
def polling_method_for_iot_entity(request: schemas.IotDoorPollingRequest, def polling_method_for_door(request: schemas.IotDoorPollingRequest,
db: Session = Depends(get_db)): db: Session = Depends(get_db)):
device: schemas.IotEntity = auth_helper.valid_iot_token(request.token, db) device: models.IotDoor = auth_helper.valid_iot_door_token(request.token, db)
if not device: if not device:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials") detail="Could not validate credentials")
room : models.Room = crud.get_room_from_door(db, device)
response : schemas.IotDoorPollingResponse = schemas.IotDoorPollingResponse(
open_command=device.open_request,
acces_list_counter=0,
time_seconds=device.time_seconds)
# Reset open_request to False # Reset open_request to False
crud.clear_open_door_request(db, device.id) #crud.clear_open_door_request(db, room_id=room.id) # Make response object to perserve values;
return response return device
@app.post("/iotdevice/monitor/status", tags=['Iot']) @app.post("/iotdevice/monitor/status", tags=['Iot'])
def polling_method_for_room_monitor(request: schemas.IotMonitorRoomInfo, def polling_method_for_room_monitor(request: schemas.IotMonitorRoomInfo,
db: Session = Depends(get_db)): db: Session = Depends(get_db)):
device : schemas.IotEntity = auth_helper.valid_iot_token(request.token, db) device : schemas.IotMonitor = auth_helper.valid_iot_monitor_token(request.token, db)
if not device: if not device:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,

View File

@ -14,42 +14,121 @@ class User(Base):
passwd_salt = Column(String, nullable=False) passwd_salt = Column(String, nullable=False)
is_active = Column(Boolean, default=True, nullable=False) is_active = Column(Boolean, default=True, nullable=False)
authorized_devices = relationship("IotEntity", secondary= 'user_iot_link') authorized_rooms = relationship("Room", secondary= 'user_room_link', lazy='dynamic')
class Room(Base):
class IotEntity(Base): __tablename__ = 'rooms'
__tablename__ = "iot_entities"
id = Column(Integer, primary_key=True, index=True) id = Column(Integer, primary_key=True, index=True)
bluetooth_mac = Column(String(512)) #door_id = Column(Integer, ForeignKey('iot_doors.id'))
description = Column(String(512)) building_name = Column(String(512))
open_request = Column(Boolean, default=False) building_number = Column(Integer)
time_seconds = Column(Integer, default=10)
authorized_users = relationship("User", secondary= 'user_iot_link')
class UserAuthToIoTDev(Base): authorized_users = relationship("User", secondary='user_room_link')
__tablename__ = "user_iot_link"
class UserRoomAuth(Base):
__tablename__ = 'user_room_link'
user_id = Column(Integer, ForeignKey('user_accounts.id'), primary_key=True, index=True) user_id = Column(Integer, ForeignKey('user_accounts.id'), primary_key=True, index=True)
iot_entity_id = Column(Integer, ForeignKey('iot_entities.id'), primary_key=True, index=True) room_id = Column(Integer, ForeignKey('rooms.id'), primary_key=True, index=True)
class IotMonitor(Base):
__tablename__ = 'iot_monitors'
id = Column(Integer, primary_key=True, index=True)
room_id = Column(Integer, ForeignKey('rooms.id'))
temp_c = Column(Integer, default=0)
smoke = Column(Integer, default=0)
humidity = Column(Integer, default=0)
people = Column(Integer, default=0)
description = Column(String(512))
bluetooth_mac = Column(String(512))
class IotDoor(Base):
__tablename__ = 'iot_doors'
id = Column(Integer, primary_key=True, index=True)
room_id = Column(Integer, ForeignKey('rooms.id'))
open_request = Column(Boolean, default=False)
time_seconds = Column(Integer, default=10)
is_open = Column(Boolean, default=False)
force_close = Column(Boolean, default=False)
accesslist_counter = Column(Integer, default=0)
description = Column(String(512))
bluetooth_mac = Column(String(512))
class MonitorReadings(Base):
__tablename__ = 'monitor_readings'
reading_id = Column(Integer, primary_key=True, index=True)
timestamp = Column(DateTime)
temp_c = Column(Integer)
smoke = Column(Integer)
humidity = Column(Integer)
people = Column(Integer)
class DoorAccessLog(Base): class DoorAccessLog(Base):
__tablename__ = "door_access_log" __tablename__ = 'door_access_log'
entry_id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey('user_accounts.id'), index=True)
room = Column(Integer, ForeignKey('rooms.id'), index=True)
timestamp = Column(DateTime)
class UserConnections(Base):
__tablename__ = 'user_connection_history'
entry_id = Column(Integer, primary_key=True, index=True) entry_id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey('user_accounts.id')) user_id = Column(Integer, ForeignKey('user_accounts.id'))
iot_dev_bluetooth_mac = Column(Integer, ForeignKey('iot_entities.id'))
timestamp = Column(DateTime) timestamp = Column(DateTime)
class RoomSensorData(Base): class IotDoorConnections(Base):
__tablename__ = "room_sensor_data" __tablename__ = 'door_connection_history'
# Data is now not related to a room. We should have a construct for rooms entry_id = Column(Integer, primary_key=True, index=True)
reading_id = Column(Integer, primary_key=True, index=True) door_id = Column(Integer, ForeignKey('iot_doors.id'))
humidity = Column(Integer)
people = Column(Integer)
temperature = Column(Integer)
smoke_sensor_reading = Column(Integer)
timestamp = Column(DateTime) timestamp = Column(DateTime)
class IotMonitorConnections(Base):
__tablename__ = 'monitor_connection_history'
entry_id = Column(Integer, primary_key=True, index=True)
monitor_id = Column(Integer, ForeignKey('iot_monitors.id'))
timestamp = Column(DateTime)
# class IotEntity(Base):
# __tablename__ = "iot_entities"
# id = Column(Integer, primary_key=True, index=True)
# bluetooth_mac = Column(String(512))
# description = Column(String(512))
# open_request = Column(Boolean, default=False)
# time_seconds = Column(Integer, default=10)
# authorized_users = relationship("User", secondary= 'user_iot_link')
# class UserAuthToIoTDev(Base):
# __tablename__ = "user_iot_link"
# user_id = Column(Integer, ForeignKey('user_accounts.id'), primary_key=True, index=True)
# iot_entity_id = Column(Integer, ForeignKey('iot_entities.id'), primary_key=True, index=True)
# class DoorAccessLog(Base):
# __tablename__ = "door_access_log"
# entry_id = Column(Integer, primary_key=True, index=True)
# user_id = Column(Integer, ForeignKey('user_accounts.id'))
# iot_dev_bluetooth_mac = Column(Integer, ForeignKey('iot_entities.id'))
# timestamp = Column(DateTime)
# class RoomSensorData(Base):
# __tablename__ = "room_sensor_data"
# # Data is now not related to a room. We should have a construct for rooms
# reading_id = Column(Integer, primary_key=True, index=True)
# humidity = Column(Integer)
# people = Column(Integer)
# temperature = Column(Integer)
# smoke_sensor_reading = Column(Integer)
# timestamp = Column(DateTime)
# TODO: Add table to store active sessions. May periodically clear. # TODO: Add table to store active sessions. May periodically clear.

View File

@ -5,6 +5,8 @@ from datetime import datetime
class IotEntityBase(BaseModel): class IotEntityBase(BaseModel):
# Common attributes for all Iot devices
room_id: int # Used to link with sensors and other devices
bluetooth_mac: str bluetooth_mac: str
description: str description: str
@ -12,100 +14,180 @@ class UserBase(BaseModel):
email: str email: str
username: str username: str
class IotEntityCreate(IotEntityBase):
pass
class UserCreate(UserBase): class UserCreate(UserBase):
# For when creating users (needs password once to store)
password: str password: str
class IotEntity(IotEntityBase): class IotDoor(IotEntityBase):
id: int id: int # Door ID
description: str open_request: bool # Standing flag to open
bluetooth_mac: str time_seconds: int # Used when open request
#authorized_users: List[User] = [] force_close: bool # Force a close mid timed open request
open_request: bool # Flag to open is_open: bool
time_seconds: int accesslist_counter: int
class Config: class Config:
orm_mode = True orm_mode = True
class IotDoorPollingRequest(BaseModel):
bluetooth_mac: str
token: str
class IotMonitor(IotEntityBase):
# Info of room monitor and current readings
id: int
room_id: int
people: int
temp_c: int
smoke: int
humidity: int
class Config:
orm_mode = True
class IotMonitorRoomInfo(BaseModel):
humidity : int
people : int
temperature : int
smoke : int
token: str
class IotDoorCreate(IotEntityBase):
room_id: int
class IotMonitorCreate(IotEntityBase):
room_id: int
class Room(BaseModel):
id: int
building_name: str
building_number: int
class Config:
orm_mode = True
class RoomCreate(BaseModel):
building_name: str
building_number: int
class IotBluetoothMac(BaseModel): class IotBluetoothMac(BaseModel):
bluetooth_mac : str bluetooth_mac : str
class User(UserBase): class User(UserBase):
id: int id: int
is_active: bool is_active: bool
authorized_devices: List[IotEntity] = [] authorized_rooms: List[Room] = [] # TODO: Change to auth rooms not devs
class Config: class Config:
orm_mode = True orm_mode = True
class Token(BaseModel): class Token(BaseModel):
access_token : str access_token: str
token_type : str token_type: str
class TokenData(BaseModel): class UserTokenData(BaseModel):
username : str
# Token can conatin information. But we are already recording this in a database
# for scalability.
class UserAllowForIotEntityRequestByID(BaseModel):
user_id: int
iot_entity_id: int
class UserAllowForIotEntityRequestByUsername(BaseModel):
username: str username: str
description: str
class OpenDoorRequestBase(BaseModel): class IotDeviceTokenData(BaseModel):
username: str
bluetooth_mac: str bluetooth_mac: str
class OpenDoorRequestTime(OpenDoorRequestBase): class DoorAccessLog(BaseModel):
time_seconds: int user_id: int
room_id: int
timestamp: datetime
#token: str
# Device sends this periodcally
class IotDoorPollingRequest(BaseModel):
bluetooth_mac : str
token : str
class Config:
orm_mode = True
class IotDoorPollingResponse(BaseModel): class IotMonitorRoomEntry(BaseModel):
open_command : bool
acces_list_counter : int
time_seconds : int
class IotMonitorRoomInfo(BaseModel):
humidity : int humidity : int
people : int people : int
temperature : int temperature : int
smoke_sensor_reading : int smoke: int
token: str token: str
class Config: class Config:
orm_mode = True orm_mode = True
class IotMonitorRoomInfoTimestamped(IotMonitorRoomInfo): class AllowRoomAccessRequestID(BaseModel):
time: datetime
class Config:
orm_mode = True
class DoorAccessLog(BaseModel):
user_id: int user_id: int
door_bluetooth_mac: str room_id: int
time: datetime
class Config:
orm_mode = True
class AccessLogRequest(BaseModel): class AllowRoomAccessRequestName(BaseModel):
bluetooth_mac : str username: str
description: int
class UserAccessLogRequestUsername(BaseModel): class UserRoomAccessLogRequest(BaseModel):
username : str username: str
class UserAccessLogRequestEmail(BaseModel): class RoomAccessLogRequest(BaseModel):
email : str room_id: int
class UserAccessLogRequestID(BaseModel): class RoomAccessLogRequestUserID(BaseModel):
id : int room_id: int
user_id: int
class RoomAccessLogRequestUserUsername(BaseModel):
username: str
room_id: int
class OpenRoomRequest(BaseModel):
user_id: int
room_id: int
time_seconds: int
# class UserAllowForIotEntityRequestByID(BaseModel):
# user_id: int
# iot_entity_id: int
# class UserAllowForIotEntityRequestByUsername(BaseModel):
# username: str
# description: str
# class OpenDoorRequestBase(BaseModel):
# username: str
# bluetooth_mac: str
# class OpenDoorRequestTime(OpenDoorRequestBase):
# time_seconds: int
# # Device sends this periodcally
# class IotDoorPollingRequest(BaseModel):
# bluetooth_mac : str
# token : str
# class Config:
# orm_mode = True
# class IotDoorPollingResponse(BaseModel):
# open_command : bool
# acces_list_counter : int
# time_seconds : int
# class IotMonitorRoomInfo(BaseModel):
# humidity : int
# people : int
# temperature : int
# smoke_sensor_reading : int
# token: str
# class Config:
# orm_mode = True
# class IotMonitorRoomInfoTimestamped(IotMonitorRoomInfo):
# time: datetime
# class Config:
# orm_mode = True
# class DoorAccessLog(BaseModel):
# user_id: int
# door_bluetooth_mac: str
# time: datetime
# class Config:
# orm_mode = True
# class AccessLogRequest(BaseModel):
# bluetooth_mac : str
# class UserAccessLogRequestUsername(BaseModel):
# username : str
# class UserAccessLogRequestEmail(BaseModel):
# email : str
# class UserAccessLogRequestID(BaseModel):
# id : int