Compare commits
55 Commits
db-rework1
...
master
Author | SHA1 | Date | |
---|---|---|---|
059d45b117 | |||
39b7d25a57 | |||
fc9f1c5c05 | |||
7f90e104d3 | |||
2c3206fc06 | |||
b704aee0fc | |||
99ac2acc0d | |||
6a771c589b | |||
2c60e14260 | |||
21aef6ec6c | |||
20dfa6dcc4 | |||
e1a7c4023b | |||
50a7d8251c | |||
6ae5b811f4 | |||
21d72f17b2 | |||
dcd2ff5b89 | |||
a316374da6 | |||
a034f17a63 | |||
40030c91a1 | |||
cdf3a6dfb1 | |||
35f0e8abb4 | |||
6942d4881d | |||
6a3d9d9e95 | |||
ae5f4e040d | |||
0a4a560ac5 | |||
fdb5be583b | |||
c2048d8dba | |||
84db98b6f6 | |||
2811b8a5ef | |||
b394bd9f2b | |||
4fdd7c231c | |||
b790c6657a | |||
0125f3e5fc | |||
6f45fc95aa | |||
3bcb333df6 | |||
2eed2db77e | |||
d9f3a9da4e | |||
4789b2778c | |||
6850823ae8 | |||
2d7ba032a8 | |||
e45e335d50 | |||
311058f09b | |||
01e6c990f7 | |||
bf14c97cb6 | |||
317b3825c3 | |||
7c94abebe5 | |||
1006baa212 | |||
868c97fe73 | |||
89f0bc354c | |||
80f6c629d4 | |||
2b4d3bf7f5 | |||
3a6a1ccefd | |||
244b7c6b91 | |||
232ff82c46 | |||
59757ae269 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,4 +5,5 @@ server.orig.key
|
|||||||
__pycache__
|
__pycache__
|
||||||
venv/
|
venv/
|
||||||
*.db
|
*.db
|
||||||
|
sql_app.db*
|
||||||
.vscode/
|
.vscode/
|
||||||
|
130
0001-admin-All-admin-path-functions-require-an-APIKey.patch
Normal file
130
0001-admin-All-admin-path-functions-require-an-APIKey.patch
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
From b08a24bedfb247fd148c48e00ee5d9b544991dfe Mon Sep 17 00:00:00 2001
|
||||||
|
From: HeshamTB <hishaminv@gmail.com>
|
||||||
|
Date: Thu, 14 Apr 2022 07:16:28 +0300
|
||||||
|
Subject: [PATCH] admin: All admin path functions require an APIKey
|
||||||
|
|
||||||
|
Signed-off-by: HeshamTB <hishaminv@gmail.com>
|
||||||
|
---
|
||||||
|
sql_app/auth_helper.py | 10 +++++++++-
|
||||||
|
sql_app/main.py | 19 ++++++++++---------
|
||||||
|
2 files changed, 19 insertions(+), 10 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/sql_app/auth_helper.py b/sql_app/auth_helper.py
|
||||||
|
index a9b866b..12aa271 100644
|
||||||
|
--- a/sql_app/auth_helper.py
|
||||||
|
+++ b/sql_app/auth_helper.py
|
||||||
|
@@ -3,18 +3,22 @@ from typing import Optional
|
||||||
|
from decouple import config
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
-from fastapi import Depends
|
||||||
|
+from fastapi import Depends, Security, HTTPException
|
||||||
|
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||||
|
+from fastapi.security.api_key import APIKey, APIKeyHeader
|
||||||
|
from . import crud, crypto, schemas
|
||||||
|
import jwt
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
JWT_SECRET = config('jwt_secret')
|
||||||
|
JWT_ALGO = config('jwt_algorithm')
|
||||||
|
|
||||||
|
+__API_KEY = config('API_KEY')
|
||||||
|
+__API_KEY_NAME = config('API_KEY_NAME')
|
||||||
|
|
||||||
|
+api_key_header = APIKeyHeader(name=__API_KEY_NAME)
|
||||||
|
|
||||||
|
def create_access_token(data : dict, expires_delta : Optional[timedelta] = None):
|
||||||
|
# TODO: Consider making non-expiring token
|
||||||
|
@@ -33,3 +37,7 @@ def authenticate_user(db: Session, username : str, password : str):
|
||||||
|
return False
|
||||||
|
return crypto.verify_key(password, user.passwd_salt, user.hashed_password)
|
||||||
|
|
||||||
|
+def valid_api_key(key = Security(api_key_header)):
|
||||||
|
+ if not __API_KEY == key:
|
||||||
|
+ raise HTTPException(401, detail="invalid key")
|
||||||
|
+ return
|
||||||
|
diff --git a/sql_app/main.py b/sql_app/main.py
|
||||||
|
index 413db35..9a9434e 100644
|
||||||
|
--- a/sql_app/main.py
|
||||||
|
+++ b/sql_app/main.py
|
||||||
|
@@ -1,5 +1,6 @@
|
||||||
|
from fastapi import Depends, FastAPI, HTTPException, status
|
||||||
|
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||||
|
+from fastapi.security.api_key import APIKey
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from . import crud, models, schemas, auth_helper
|
||||||
|
@@ -65,31 +66,31 @@ def get_user_details(current_user: schemas.User = Depends(get_current_active_use
|
||||||
|
return current_user
|
||||||
|
|
||||||
|
@app.get("/admin/users/", response_model=List[schemas.User], tags=['Admin'])
|
||||||
|
-def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
|
||||||
|
+def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
|
||||||
|
users = crud.get_users(db, skip=skip, limit=limit)
|
||||||
|
return users
|
||||||
|
|
||||||
|
@app.get("/admin/iotentities/", response_model=List[schemas.IotEntity], tags=['Admin'])
|
||||||
|
-def read_iot_entities(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
|
||||||
|
+def read_iot_entities(skip: int = 0, limit: int = 100, db: Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
|
||||||
|
iot_entities = crud.get_iot_entities(db, skip=skip, limit=limit)
|
||||||
|
return iot_entities
|
||||||
|
|
||||||
|
# TODO: Can duplicate
|
||||||
|
@app.post("/admin/iotentities/create", response_model=schemas.IotEntity, tags=['Admin'])
|
||||||
|
-def create_iot_entities(iot_entity: schemas.IotEntityCreate, db: Session = Depends(get_db)):
|
||||||
|
+def create_iot_entities(iot_entity: schemas.IotEntityCreate, db: Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
|
||||||
|
iot_entities = crud.create_iot_entity(db, iot_entity)
|
||||||
|
return iot_entities
|
||||||
|
|
||||||
|
@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), api_key: APIKey = Depends(auth_helper.valid_api_key)):
|
||||||
|
db_user = crud.get_user(db, user_id=user_id)
|
||||||
|
if db_user is None:
|
||||||
|
raise HTTPException(status_code=404, detail="User not found")
|
||||||
|
return db_user
|
||||||
|
|
||||||
|
# TODO: Can duplicate
|
||||||
|
@app.post("/admin/users/allowdevice/id", tags=['Admin'])
|
||||||
|
-def allow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db)):
|
||||||
|
+def allow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
|
||||||
|
user = crud.get_user(db, request.user_id)
|
||||||
|
if not user:
|
||||||
|
raise HTTPException(status_code=404, detail="User not found")
|
||||||
|
@@ -105,7 +106,7 @@ def allow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityReques
|
||||||
|
return user
|
||||||
|
|
||||||
|
@app.post("/admin/users/disallowdevice/id", tags=['Admin'])
|
||||||
|
-def disallow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db)):
|
||||||
|
+def disallow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
|
||||||
|
user = crud.get_user(db, request.user_id)
|
||||||
|
if not user:
|
||||||
|
raise HTTPException(status_code=404, detail="User not found")
|
||||||
|
@@ -122,7 +123,7 @@ def disallow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityReq
|
||||||
|
return
|
||||||
|
|
||||||
|
@app.post("/admin/users/allowdevice/name", tags=['Admin'])
|
||||||
|
-def allow_user_for_iot_entity_by_name(request: schemas.UserAllowForIotEntityRequestByUsername, db: Session = Depends(get_db)):
|
||||||
|
+def allow_user_for_iot_entity_by_name(request: schemas.UserAllowForIotEntityRequestByUsername, db: Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
|
||||||
|
user = crud.get_user_by_username(db, request.username)
|
||||||
|
if not user:
|
||||||
|
raise HTTPException(status_code=404, detail="User not found")
|
||||||
|
@@ -138,11 +139,11 @@ def allow_user_for_iot_entity_by_name(request: schemas.UserAllowForIotEntityRequ
|
||||||
|
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), api_key: APIKey = Depends(auth_helper.valid_api_key)):
|
||||||
|
return
|
||||||
|
|
||||||
|
@app.post("/admin/users/{user_id}/activeate", tags=['Admin'])
|
||||||
|
-def deactiveate_user(user_id: int, db:Session = Depends(get_db)):
|
||||||
|
+def deactiveate_user(user_id: int, db:Session = Depends(get_db), api_key: APIKey = Depends(auth_helper.valid_api_key)):
|
||||||
|
return
|
||||||
|
|
||||||
|
@app.get("/users/acesslist/", response_model=List[schemas.IotEntity], tags=['Users'])
|
||||||
|
--
|
||||||
|
libgit2 1.4.3
|
||||||
|
|
33
encryption/encryption.c
Normal file
33
encryption/encryption.c
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Wrapper around mbedtls to provide AES encryption
|
||||||
|
*
|
||||||
|
* Needs esp32 arduino platform libraries
|
||||||
|
*
|
||||||
|
* Hesham T. Banafa
|
||||||
|
* May 9th, 2022
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include "encryption.h"
|
||||||
|
|
||||||
|
static int valid_time(long long time_epoch);
|
||||||
|
|
||||||
|
extern void aes_init(aes_t *ctx, char *key)
|
||||||
|
{
|
||||||
|
mbedtls_aes_init(&ctx->aes_ctx);
|
||||||
|
//mbedtls_aes_setkey_enc(ctx->aes_ctx, (const unsigned char*)key, strlen(key) * 8 );
|
||||||
|
ctx->psk_key = key; // Save key ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void aes_encrypt(aes_t *ctx, char *plain_text, char *out_buf)
|
||||||
|
{
|
||||||
|
if (ctx == NULL) return; // What are you doing? out_buf remains as is.
|
||||||
|
mbedtls_aes_setkey_enc(&ctx->aes_ctx, (const unsigned char*)ctx->psk_key, strlen(ctx->psk_key) * 8 );
|
||||||
|
mbedtls_aes_crypt_ecb(&ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, (const unsigned char*)plain_text, (unsigned char*)out_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void aes_decrypt(aes_t *ctx, char *cipher_text, char *out_buf)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
24
encryption/encryption.h
Normal file
24
encryption/encryption.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Wrapper around mbedtls to provide AES encryption
|
||||||
|
*
|
||||||
|
* Needs esp32 arduino platform libraries
|
||||||
|
*
|
||||||
|
* Hesham T. Banafa
|
||||||
|
* May 9th, 2022
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mbedtls/aes.h"
|
||||||
|
|
||||||
|
typedef struct aes_t
|
||||||
|
{
|
||||||
|
const char *psk_key;
|
||||||
|
mbedtls_aes_context aes_ctx;
|
||||||
|
} aes_t;
|
||||||
|
|
||||||
|
static int valid_time(long long time_epoch);
|
||||||
|
|
||||||
|
extern void aes_init(aes_t *ctx, char *key);
|
||||||
|
extern void aes_encrypt(aes_t *ctx, char *plain_text, char *out_buf);
|
||||||
|
extern void aes_decrypt(aes_t *ctx, char *cipher_text, char *out_buf);
|
||||||
|
|
12
reqs.txt
12
reqs.txt
@ -1,9 +1,12 @@
|
|||||||
aiocoap==0.4.3
|
aiocoap==0.4.3
|
||||||
anyio==3.5.0
|
anyio==3.5.0
|
||||||
asgiref==3.5.0
|
asgiref==3.5.0
|
||||||
|
attrs==21.4.0
|
||||||
bitlist==0.6.2
|
bitlist==0.6.2
|
||||||
cbor2==5.4.2.post1
|
cbor2==5.4.2.post1
|
||||||
|
certifi==2022.5.18.1
|
||||||
cffi==1.15.0
|
cffi==1.15.0
|
||||||
|
charset-normalizer==2.0.12
|
||||||
click==8.0.4
|
click==8.0.4
|
||||||
cryptography==36.0.1
|
cryptography==36.0.1
|
||||||
Cython==0.29.28
|
Cython==0.29.28
|
||||||
@ -17,22 +20,31 @@ greenlet==1.1.2
|
|||||||
h11==0.13.0
|
h11==0.13.0
|
||||||
httptools==0.3.0
|
httptools==0.3.0
|
||||||
idna==3.3
|
idna==3.3
|
||||||
|
iniconfig==1.1.1
|
||||||
LinkHeader==0.4.3
|
LinkHeader==0.4.3
|
||||||
|
packaging==21.3
|
||||||
parts==1.2.2
|
parts==1.2.2
|
||||||
|
pluggy==1.0.0
|
||||||
|
py==1.11.0
|
||||||
pycparser==2.21
|
pycparser==2.21
|
||||||
pydantic==1.9.0
|
pydantic==1.9.0
|
||||||
Pygments==2.11.2
|
Pygments==2.11.2
|
||||||
PyJWT==2.3.0
|
PyJWT==2.3.0
|
||||||
|
pyparsing==3.0.9
|
||||||
|
pytest==7.1.2
|
||||||
python-decouple==3.6
|
python-decouple==3.6
|
||||||
python-dotenv==0.19.2
|
python-dotenv==0.19.2
|
||||||
python-multipart==0.0.5
|
python-multipart==0.0.5
|
||||||
PyYAML==6.0
|
PyYAML==6.0
|
||||||
|
requests==2.27.1
|
||||||
six==1.16.0
|
six==1.16.0
|
||||||
sniffio==1.2.0
|
sniffio==1.2.0
|
||||||
SQLAlchemy==1.4.31
|
SQLAlchemy==1.4.31
|
||||||
starlette==0.17.1
|
starlette==0.17.1
|
||||||
termcolor==1.1.0
|
termcolor==1.1.0
|
||||||
|
tomli==2.0.1
|
||||||
typing_extensions==4.1.1
|
typing_extensions==4.1.1
|
||||||
|
urllib3==1.26.9
|
||||||
uvicorn==0.17.5
|
uvicorn==0.17.5
|
||||||
uvloop==0.16.0
|
uvloop==0.16.0
|
||||||
watchgod==0.7
|
watchgod==0.7
|
||||||
|
10
run-tls
10
run-tls
@ -1,4 +1,14 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
|
|
||||||
|
cd sql_app/
|
||||||
|
|
||||||
|
./file_permissios.py
|
||||||
|
if [ $? == 1 ]
|
||||||
|
then
|
||||||
|
echo "enviorment file_permissions are incorrect"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cd ../
|
||||||
exec uvicorn sql_app.main:app --ssl-certfile server.crt --ssl-keyfile server.key --port 4040 --host 0.0.0.0 --no-server-header
|
exec uvicorn sql_app.main:app --ssl-certfile server.crt --ssl-keyfile server.key --port 4040 --host 0.0.0.0 --no-server-header
|
||||||
|
4
run-tls-reload
Executable file
4
run-tls-reload
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
source venv/bin/activate
|
||||||
|
exec uvicorn sql_app.main:app --ssl-certfile server.crt --ssl-keyfile server.key --port 4040 --host 0.0.0.0 --no-server-header --reload
|
46
sql_app/TODO
46
sql_app/TODO
@ -1,13 +1,45 @@
|
|||||||
- [ ] Redesign database
|
- [x] Constrcut DB Schema
|
||||||
- [ ] Define emrgancy triggers (manual and automatic)
|
- [x] Issue requests from Lap to Pi or vica versa
|
||||||
|
- [x] Decide HTTP vs MQTT vs CoAP
|
||||||
|
- [x] Hash passwords
|
||||||
|
- [x] Salt passwords
|
||||||
|
- [x] User registraion
|
||||||
|
- [x] User login in API
|
||||||
|
- [x] JWT token access
|
||||||
|
- [x] Look into how to revoke a signed key
|
||||||
|
- [ ] Record Session info in token & db (allow for session cancel)
|
||||||
|
- [x] Add username for users (now only email)
|
||||||
|
- [X] Expose Room monitor function (temp, count humid..)
|
||||||
|
- [X] Expose door lock function
|
||||||
|
- [X] Record access log
|
||||||
|
- [X] Expose data analysis
|
||||||
|
- [X] Load backend onto RPi
|
||||||
|
- [X] Test connections in lab network
|
||||||
|
- [X] Define emrgancy triggers (manual and automatic)
|
||||||
- [ ] Expose temporary control in case of emergancy
|
- [ ] Expose temporary control in case of emergancy
|
||||||
- Triggers
|
- Triggers
|
||||||
- Acccess
|
- Acccess
|
||||||
- Resolve (revoke access)
|
- Resolve (revoke access)
|
||||||
- [ ] Temporal door open commands (Needs door state to operate efficiatly)
|
- [X] Temporal door open commands (Needs door state to operate efficiatly)
|
||||||
- Open for 1H
|
- [X] Open for 1H
|
||||||
- Open to 1:30PM
|
- [ ] Open to 1:30PM
|
||||||
- Set schedual
|
- [ ] Set schedual
|
||||||
- [X] Issue door open command
|
- [X] Issue door open command
|
||||||
- [X] Make functions to gen a IotEntity token
|
- [X] Make functions to gen a IotEntity token
|
||||||
- [ ] Save prefix of token to allow/revoke token??
|
- [ ] Write a small program/script to generate new Iot token and add new Iot Device into database
|
||||||
|
- [X] Make inital database entries automatic for easy reset
|
||||||
|
- [X] Expose access list endpoint for doors
|
||||||
|
- [X] Access list coutner for iot door
|
||||||
|
- [X] Force close in middle of timed open request
|
||||||
|
- [ ] Record user connections and time
|
||||||
|
- [ ] Record Iot dev connection and time
|
||||||
|
- [ ] Write unit tests
|
||||||
|
- [ ] Develop a program to visualize the data
|
||||||
|
- [ ] CLI frontend
|
||||||
|
- [X] Emergaency
|
||||||
|
- [X] Send state with accesslist
|
||||||
|
- [X] Split monitor into different class
|
||||||
|
- [ ] Make a script that adds types, and thier basic database ops?? (avoid writing boiler-plate)
|
||||||
|
- [ ] Make a script that emulates a door and monitor
|
||||||
|
- [ ] Check file premissions on .env file, if global reject
|
||||||
|
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJibHVldG9vdGhfbWFjIjoic3RyaW5nIn0.ELl5AfBR1NdM4_OFhl_SCTm9EMPpqjiCKOSS0CrOJps
|
@ -1,3 +1,5 @@
|
|||||||
|
# May 2022
|
||||||
|
# Hesham T. Banafa <hishaminv@gmail.com>
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from decouple import config
|
from decouple import config
|
||||||
@ -55,4 +57,14 @@ def valid_iot_token(token : str, db: Session):
|
|||||||
|
|
||||||
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_iot_entity_by_bluetooth_mac(db, mac_signed)
|
||||||
return device
|
return device
|
||||||
|
|
||||||
|
def valid_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")
|
||||||
|
monitor = crud.get_monitor_bluetooth(db, mac_signed)
|
||||||
|
return monitor
|
||||||
|
178
sql_app/crud.py
178
sql_app/crud.py
@ -1,10 +1,15 @@
|
|||||||
|
# March 2022
|
||||||
|
# Hesham T. Banafa <hishaminv@gmail.com>
|
||||||
|
|
||||||
# CRUD (Create, Read, Update, Delete) from db
|
# CRUD (Create, Read, Update, Delete) from db
|
||||||
|
|
||||||
|
from sqlalchemy import select, join
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from . import models, schemas, crypto, auth_helper
|
from . import models, schemas, crypto, auth_helper
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from warnings import warn
|
||||||
|
|
||||||
# TODO: Data we can collect or log
|
# TODO: Data we can collect or log
|
||||||
# - Last user connection (link to user)
|
# - Last user connection (link to user)
|
||||||
@ -12,49 +17,71 @@ from datetime import datetime
|
|||||||
# - Any open request (link to user)
|
# - Any open request (link to user)
|
||||||
# - Any polling from IotEntity? Maybe to much data
|
# - Any polling from IotEntity? Maybe to much data
|
||||||
|
|
||||||
def get_user(db: Session, user_id: int):
|
def get_user(db: Session, user_id: int) -> models.User:
|
||||||
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_iot_entity(db: Session, id: int) -> models.IotEntity:
|
||||||
return db.query(models.IotEntity).get(id)
|
return db.query(models.IotEntity).get(id)
|
||||||
|
|
||||||
def get_iot_entity_by_description(db: Session, description: str):
|
def get_iot_entity_by_description(db: Session, description: str):
|
||||||
return db.query(models.IotEntity).filter(models.IotEntity.description == description).first()
|
return db.query(models.IotEntity).filter(models.IotEntity.description == description).first()
|
||||||
|
|
||||||
def get_iot_entity_by_bluetooth_mac(db: Session, bluetooth_mac: str):
|
def get_iot_entity_by_bluetooth_mac(db: Session, bluetooth_mac: str) -> models.IotEntity:
|
||||||
return db.query(models.IotEntity).filter(models.IotEntity.bluetooth_mac == bluetooth_mac).first()
|
return db.query(models.IotEntity).filter(models.IotEntity.bluetooth_mac == bluetooth_mac).first()
|
||||||
|
|
||||||
def get_user_by_email(db: Session, email: str):
|
def get_user_by_email(db: Session, email: str) -> models.User:
|
||||||
return db.query(models.User).filter(models.User.email == email).first()
|
return db.query(models.User).filter(models.User.email == email).first()
|
||||||
|
|
||||||
def get_user_by_username(db: Session, username: str):
|
def get_user_by_username(db: Session, username: str) -> models.User:
|
||||||
return db.query(models.User).filter(models.User.username == username).first()
|
return db.query(models.User).filter(models.User.username == username).first()
|
||||||
|
|
||||||
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_door_by_door_mac(db: Session, iot_id: str):
|
||||||
return db.query(models.DoorAccessLog).filter(models.DoorAccessLog.iot_dev_bluetooth_mac == bluetooth_mac).all()
|
warn("Manual access log read is deprecated. Use device.access_log",
|
||||||
|
DeprecationWarning, stacklevel=2)
|
||||||
|
return db.query(models.DoorAccessLog)\
|
||||||
|
.filter(models.DoorAccessLog.iot_id == iot_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, door_id: int) -> models.RoomSensorData:
|
||||||
return db.query(models.RoomSensorData)[-1]
|
# door = get_iot_entity(db, door_id)
|
||||||
|
# monitor : models.Monitors = door.monitor
|
||||||
|
# if not monitor: return -1
|
||||||
|
# if len(monitor.sensor_history) == 0: return -2
|
||||||
|
# return monitor.sensor_history[-1]
|
||||||
|
|
||||||
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)
|
||||||
salt = key[1]
|
salt = key[1]
|
||||||
hashed_pass = key[0]
|
hashed_pass = key[0]
|
||||||
db_user = models.User(email=user.email, username=user.username,hashed_password=hashed_pass, passwd_salt=salt)
|
db_user = models.User(email=user.email,
|
||||||
|
username=user.username,
|
||||||
|
hashed_password=hashed_pass,
|
||||||
|
passwd_salt=salt)
|
||||||
db.add(db_user)
|
db.add(db_user)
|
||||||
db.commit()
|
db.commit()
|
||||||
db.refresh(db_user)
|
db.refresh(db_user)
|
||||||
return db_user
|
return db_user
|
||||||
|
|
||||||
|
def update_user_password(db: Session, user: models.User, request: schemas.UserUpdatePassword):
|
||||||
|
key = crypto.gen_new_key(request.password)
|
||||||
|
salt = key[1]
|
||||||
|
hashed_pass = key[0]
|
||||||
|
user.passwd_salt = salt
|
||||||
|
user.hashed_password = hashed_pass
|
||||||
|
db.add(user)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(user)
|
||||||
|
|
||||||
def get_iot_entities(db: Session, skip: int = 0, limit: int = 100):
|
def get_iot_entities(db: Session, skip: int = 0, limit: int = 100):
|
||||||
return db.query(models.IotEntity).offset(skip).limit(limit).all()
|
return db.query(models.IotEntity).offset(skip).limit(limit).all()
|
||||||
|
|
||||||
|
def get_monitors(db: Session, skip: int = 0, limit: int = 100):
|
||||||
|
return db.query(models.Monitors).offset(skip).limit(limit).all()
|
||||||
|
|
||||||
def create_iot_entity(db: Session, iot_entity: schemas.IotEntityCreate):
|
def create_iot_entity(db: Session, iot_entity: schemas.IotEntityCreate):
|
||||||
db_item = models.IotEntity(bluetooth_mac=iot_entity.bluetooth_mac,
|
db_item = models.IotEntity(bluetooth_mac=iot_entity.bluetooth_mac,
|
||||||
@ -64,11 +91,44 @@ def create_iot_entity(db: Session, iot_entity: schemas.IotEntityCreate):
|
|||||||
db.refresh(db_item)
|
db.refresh(db_item)
|
||||||
return db_item
|
return db_item
|
||||||
|
|
||||||
|
def create_monitor(db: Session, monitor: schemas.IotEntityBase):
|
||||||
|
db_item = models.Monitors(bluetooth_mac=monitor.bluetooth_mac,
|
||||||
|
description=monitor.description)
|
||||||
|
|
||||||
|
db.add(db_item)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(db_item)
|
||||||
|
return db_item
|
||||||
|
|
||||||
|
def get_monitor(db: Session, id: int) -> models.Monitors:
|
||||||
|
return db.query(models.Monitors).get(id)
|
||||||
|
|
||||||
|
def get_monitor_bluetooth(db: Session, bluetooth_mac: str) -> models.Monitors:
|
||||||
|
return db.query(models.Monitors).filter(models.Monitors.bluetooth_mac == bluetooth_mac).first()
|
||||||
|
|
||||||
|
def update_monitor(db: Session, monitor: models.Monitors):
|
||||||
|
db.add(monitor)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(monitor)
|
||||||
|
|
||||||
|
def update_monitor_readings(db: Session, monitor_upadte: schemas.MonitorUpdateReadings, bluetooth_mac: str):
|
||||||
|
monitor = get_monitor_bluetooth(db, bluetooth_mac)
|
||||||
|
monitor.humidity = monitor_upadte.humidity
|
||||||
|
monitor.people = monitor_upadte.people
|
||||||
|
monitor.smoke_sensor_reading = monitor_upadte.smoke_sensor_reading
|
||||||
|
monitor.temperature = monitor_upadte.temperature
|
||||||
|
|
||||||
|
db.add(monitor)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(monitor)
|
||||||
|
|
||||||
def create_user_link_to_iot(db: Session, user_id: int, iot_dev_id: int):
|
def create_user_link_to_iot(db: Session, user_id: int, iot_dev_id: int):
|
||||||
# Ensure link is not already present and it does not allow duplicates
|
# Ensure link is not already present and it does not allow duplicates
|
||||||
link = db.query(models.UserAuthToIoTDev).filter(models.UserAuthToIoTDev.user_id == user_id).filter(models.UserAuthToIoTDev.iot_entity_id == iot_dev_id).first()
|
link = db.query(models.UserAuthToIoTDev).filter(models.UserAuthToIoTDev.user_id == user_id).filter(models.UserAuthToIoTDev.iot_id == iot_dev_id).first()
|
||||||
if link: return True
|
if link: return True
|
||||||
new_link = models.UserAuthToIoTDev(user_id=user_id, iot_entity_id=iot_dev_id)
|
new_link = models.UserAuthToIoTDev(user_id=user_id,
|
||||||
|
iot_id=iot_dev_id,
|
||||||
|
timestamp=datetime.now())
|
||||||
db.add(new_link)
|
db.add(new_link)
|
||||||
db.commit()
|
db.commit()
|
||||||
db.refresh(new_link)
|
db.refresh(new_link)
|
||||||
@ -76,7 +136,10 @@ def create_user_link_to_iot(db: Session, user_id: int, iot_dev_id: int):
|
|||||||
|
|
||||||
def remove_user_link_to_iot(db: Session, user_id: int, iot_dev_id: int):
|
def remove_user_link_to_iot(db: Session, user_id: int, iot_dev_id: int):
|
||||||
# Ensure link is not already present and it does not allow duplicates
|
# Ensure link is not already present and it does not allow duplicates
|
||||||
link = db.query(models.UserAuthToIoTDev).filter(models.UserAuthToIoTDev.user_id == user_id).filter(models.UserAuthToIoTDev.iot_entity_id == iot_dev_id).first()
|
link = (db.query(models.UserAuthToIoTDev)
|
||||||
|
.filter(models.UserAuthToIoTDev.user_id == user_id)
|
||||||
|
.filter(models.UserAuthToIoTDev.iot_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()
|
||||||
@ -95,6 +158,38 @@ def set_open_door_request(db: Session, iot_entity_id: int, time_seconds : int):
|
|||||||
db.refresh(device)
|
db.refresh(device)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def set_close_door_request(db: Session, iot_id: int):
|
||||||
|
device : models.IotEntity = get_iot_entity(db, iot_id)
|
||||||
|
device.force_close = True
|
||||||
|
db.add(device)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(device)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def clear_close_door_request(db: Session, iot_id: int):
|
||||||
|
device : models.IotEntity = get_iot_entity(db, iot_id)
|
||||||
|
device.force_close = False
|
||||||
|
db.add(device)
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
def set_user_last_token(db: Session, username: str, token: str):
|
||||||
|
user : models.User = get_user_by_username(db, username)
|
||||||
|
user.last_token = token
|
||||||
|
db.add(user)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(user)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def set_door_state(db: Session, iot_device: models.IotEntity, state: bool):
|
||||||
|
iot_device.state = state
|
||||||
|
db.add(iot_device)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(iot_device)
|
||||||
|
|
||||||
|
def get_user_last_token(db: Session, username: str):
|
||||||
|
user : models.User = get_user_by_username(db, username)
|
||||||
|
return user.last_token # This method is bad security practice.
|
||||||
|
|
||||||
def clear_open_door_request(db: Session, iot_entity_id: int):
|
def clear_open_door_request(db: Session, iot_entity_id: int):
|
||||||
device = get_iot_entity(db, iot_entity_id)
|
device = get_iot_entity(db, iot_entity_id)
|
||||||
setattr(device, "open_request", False)
|
setattr(device, "open_request", False)
|
||||||
@ -106,18 +201,65 @@ def clear_open_door_request(db: Session, iot_entity_id: int):
|
|||||||
|
|
||||||
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,
|
iot_id=entry.iot_id,
|
||||||
timestamp=entry.time)
|
command=entry.command,
|
||||||
|
timestamp=entry.timestamp)
|
||||||
db.add(db_item)
|
db.add(db_item)
|
||||||
db.commit()
|
db.commit()
|
||||||
db.refresh(db_item)
|
db.refresh(db_item)
|
||||||
|
|
||||||
def record_room_sensor_data(db: Session, entry: schemas.IotMonitorRoomInfo):
|
def record_room_sensor_data(db: Session, entry: schemas.MonitorUpdateReadings,
|
||||||
|
monitor :models.Monitors):
|
||||||
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_sensor_reading=entry.smoke_sensor_reading,
|
||||||
timestamp=datetime.now())
|
timestamp=datetime.now(),
|
||||||
|
monitor_id=monitor.id)
|
||||||
db.add(db_item)
|
db.add(db_item)
|
||||||
db.commit()
|
db.commit()
|
||||||
db.refresh(db_item)
|
db.refresh(db_item)
|
||||||
|
|
||||||
|
monitor.humidity = entry.humidity
|
||||||
|
monitor.temperature = entry.temperature
|
||||||
|
monitor.people = entry.people
|
||||||
|
monitor.smoke_sensor_reading = entry.smoke_sensor_reading
|
||||||
|
|
||||||
|
db.add(monitor)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(monitor)
|
||||||
|
|
||||||
|
def increment_door_access_list_counter(db: Session, iot_entity: models.IotEntity):
|
||||||
|
iot_entity.acces_list_counter = iot_entity.acces_list_counter + 1
|
||||||
|
db.add(iot_entity)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(iot_entity)
|
||||||
|
|
||||||
|
def record_user_connection(db: Session, user: models.User, time: datetime):
|
||||||
|
entry = models.UserConnectionHistory(user_id=user.id, timestamp=time)
|
||||||
|
db.add(entry)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(entry)
|
||||||
|
|
||||||
|
# def get_sensor_data_for_room(db: Session, monitor_id: int, count_last: int):
|
||||||
|
# data = db.query(models.RoomSensorData).all()
|
||||||
|
# if not data or len(data) == 0: return -1
|
||||||
|
# return data[-count_last]
|
||||||
|
|
||||||
|
def update_user_status(db: Session, user: models.User, state: bool):
|
||||||
|
user.is_active = state
|
||||||
|
db.add(user)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(user)
|
||||||
|
|
||||||
|
def record_emergancy_entry(db: Session, monitor_data: schemas.MonitorUpdateReadings, monitor_id: int):
|
||||||
|
new_entry : models.EmergancyNotice = models.EmergancyNotice(
|
||||||
|
monitor_id=monitor_id,
|
||||||
|
people=monitor_data.people,
|
||||||
|
temperature=monitor_data.temperature,
|
||||||
|
smoke_sensor_reading=monitor_data.smoke_sensor_reading,
|
||||||
|
timestamp=datetime.now()
|
||||||
|
)
|
||||||
|
db.add(new_entry)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(new_entry)
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# March 2022
|
||||||
|
# Hesham T. Banafa <hishaminv@gmail.com>
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from hashlib import pbkdf2_hmac
|
from hashlib import pbkdf2_hmac
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# March 2022
|
||||||
|
# Hesham T. Banafa <hishaminv@gmail.com>
|
||||||
|
|
||||||
from sqlalchemy import create_engine
|
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
|
||||||
|
45
sql_app/enroll_door.py
Normal file
45
sql_app/enroll_door.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# Quick enroll new device
|
||||||
|
# Hesham T. Banafa
|
||||||
|
# Jun 12th, 2022
|
||||||
|
|
||||||
|
from decouple import config
|
||||||
|
import requests
|
||||||
|
|
||||||
|
# idk if this stays in memory...
|
||||||
|
headers = {
|
||||||
|
"accept": "application/json",
|
||||||
|
"Content-type": "application/json"
|
||||||
|
}
|
||||||
|
def main():
|
||||||
|
|
||||||
|
if len(sys.argv) != 4:
|
||||||
|
print_help()
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
device_type = sys.argv[1]
|
||||||
|
bluetooth_mac = sys.argv[2]
|
||||||
|
description = sys.argv[3]
|
||||||
|
if device_type == 'DOOR':
|
||||||
|
mkdoor(bluetooth_mac, description)
|
||||||
|
elif device_type == 'MONITOR':
|
||||||
|
mkmonitor(bluetooth_mac, description)
|
||||||
|
else:
|
||||||
|
print('Device type not DOOR or MONITOR', file=sys.stderr)
|
||||||
|
exit(1)
|
||||||
|
# gen print token of bluetooth_mac
|
||||||
|
print(create_iot_dev_token(bluetooth_mac))
|
||||||
|
|
||||||
|
def mkdoor(bluetooth_mac: str, description: str):
|
||||||
|
data = {
|
||||||
|
"bluetooth_mac": bluetooth_mac,
|
||||||
|
"description": description
|
||||||
|
}
|
||||||
|
|
||||||
|
#response = requests.post("")
|
||||||
|
|
||||||
|
def mkmonitor(bluetooth_mac: str, description: str):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def print_help():
|
||||||
|
msg = 'usgae: enroll_iotdevice <DOOR|MONITOR> <bluetooth_mac> <description>'
|
||||||
|
print(msg)
|
18
sql_app/file_permissios.py
Executable file
18
sql_app/file_permissios.py
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/python
|
||||||
|
|
||||||
|
# Hesham T. Banafa
|
||||||
|
# Jun 12th, 2022
|
||||||
|
# Check enviorment file permissions and return -1 if fails or 0
|
||||||
|
|
||||||
|
import os
|
||||||
|
import stat
|
||||||
|
|
||||||
|
ENV_FILE='.env'
|
||||||
|
|
||||||
|
st = os.stat(ENV_FILE)
|
||||||
|
if st.st_mode & stat.S_IROTH or \
|
||||||
|
st.st_mode & stat.S_IWOTH or \
|
||||||
|
st.st_mode & stat.S_IXOTH:
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
exit(0)
|
137
sql_app/init_db.py
Normal file
137
sql_app/init_db.py
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
# June 2022
|
||||||
|
# Hesham T. Banafa <hishaminv@gmail.com>
|
||||||
|
|
||||||
|
from . import crud, main, schemas, auth_helper
|
||||||
|
from decouple import config
|
||||||
|
from .database import SessionLocal
|
||||||
|
from datetime import timedelta, datetime
|
||||||
|
from random import randint
|
||||||
|
|
||||||
|
db = SessionLocal()
|
||||||
|
|
||||||
|
def init_user():
|
||||||
|
user = schemas.UserCreate(email="hisham@banafa.com.sa",
|
||||||
|
username="Hesham",
|
||||||
|
password=config('first_user_pass'))
|
||||||
|
user_exists = crud.get_user_by_email(db, user.email)
|
||||||
|
if user_exists: return
|
||||||
|
crud.create_user(db, user)
|
||||||
|
token = auth_helper.create_access_token(data={"sub": user.username}, expires_delta=timedelta(minutes=15))
|
||||||
|
res = crud.set_user_last_token(db, user.username, token)
|
||||||
|
|
||||||
|
user_exists = None
|
||||||
|
user = schemas.UserCreate(email="osama@mail.none",
|
||||||
|
username="Osama",
|
||||||
|
password=config('first_user_pass'))
|
||||||
|
user_exists = crud.get_user_by_email(db, user.email)
|
||||||
|
if user_exists: return
|
||||||
|
crud.create_user(db, user)
|
||||||
|
token = auth_helper.create_access_token(data={"sub": user.username}, expires_delta=timedelta(minutes=15))
|
||||||
|
res = crud.set_user_last_token(db, user.username, token)
|
||||||
|
|
||||||
|
user_exists = None
|
||||||
|
user = schemas.UserCreate(email="Hussain@mail.none",
|
||||||
|
username="Hussain",
|
||||||
|
password=config('first_user_pass'))
|
||||||
|
user_exists = crud.get_user_by_email(db, user.email)
|
||||||
|
if user_exists: return
|
||||||
|
crud.create_user(db, user)
|
||||||
|
token = auth_helper.create_access_token(data={"sub": user.username}, expires_delta=timedelta(minutes=15))
|
||||||
|
res = crud.set_user_last_token(db, user.username, token)
|
||||||
|
|
||||||
|
user_exists = None
|
||||||
|
user = schemas.UserCreate(email="Assad@mail.none",
|
||||||
|
username="Assad",
|
||||||
|
password=config('first_user_pass'))
|
||||||
|
user_exists = crud.get_user_by_email(db, user.email)
|
||||||
|
if user_exists: return
|
||||||
|
crud.create_user(db, user)
|
||||||
|
token = auth_helper.create_access_token(data={"sub": user.username}, expires_delta=timedelta(minutes=15))
|
||||||
|
res = crud.set_user_last_token(db, user.username, token)
|
||||||
|
|
||||||
|
def init_door():
|
||||||
|
iot_door = schemas.IotEntityCreate(bluetooth_mac="94:b9:7e:fb:57:1a",
|
||||||
|
description="Iot Lab Door")
|
||||||
|
door_exists = crud.get_iot_entity_by_bluetooth_mac(db, iot_door.bluetooth_mac)
|
||||||
|
if door_exists: return
|
||||||
|
crud.create_iot_entity(db, iot_door)
|
||||||
|
|
||||||
|
def init_monitor():
|
||||||
|
iot_monitor = schemas.IotEntityCreate(bluetooth_mac="ff:ff:ff",
|
||||||
|
description="Iot Lab Monitor")
|
||||||
|
monitor_exists = crud.get_monitor_bluetooth(db, iot_monitor.bluetooth_mac)
|
||||||
|
if monitor_exists: return
|
||||||
|
crud.create_monitor(db, iot_monitor)
|
||||||
|
|
||||||
|
def init_allowance():
|
||||||
|
crud.create_user_link_to_iot(db, 1, 1)
|
||||||
|
|
||||||
|
def init_sensor_data():
|
||||||
|
monitor = crud.get_monitor(db, 1)
|
||||||
|
if monitor.sensor_history: return
|
||||||
|
for i in range(50):
|
||||||
|
room_data = \
|
||||||
|
schemas.\
|
||||||
|
IotMonitorRoomInfo\
|
||||||
|
(humidity=randint(20, 80),
|
||||||
|
people=randint(0, 10),
|
||||||
|
temperature=randint(18, 27),
|
||||||
|
smoke_sensor_reading=randint(150, 700),
|
||||||
|
token='dummy')
|
||||||
|
crud.record_room_sensor_data(db, room_data, monitor)
|
||||||
|
|
||||||
|
def init_open_close_requests():
|
||||||
|
user = crud.get_user_by_email(db, "hisham@banafa.com.sa")
|
||||||
|
if user.access_log: return
|
||||||
|
crud.set_open_door_request(db, 1, 10)
|
||||||
|
log_entry = schemas.DoorAccessLog(user_id=user.id,
|
||||||
|
iot_id=1,
|
||||||
|
command="OPEN",
|
||||||
|
timestamp=datetime.now())
|
||||||
|
crud.record_door_access_log(db, log_entry)
|
||||||
|
|
||||||
|
log_entry = schemas.DoorAccessLog(user_id=user.id,
|
||||||
|
iot_id=1,
|
||||||
|
command="OPEN",
|
||||||
|
timestamp=datetime.now())
|
||||||
|
crud.record_door_access_log(db, log_entry)
|
||||||
|
|
||||||
|
log_entry = schemas.DoorAccessLog(user_id=user.id,
|
||||||
|
iot_id=1,
|
||||||
|
command="OPEN",
|
||||||
|
timestamp=datetime.now())
|
||||||
|
crud.record_door_access_log(db, log_entry)
|
||||||
|
|
||||||
|
|
||||||
|
log_entry = schemas.DoorAccessLog(user_id=user.id,
|
||||||
|
iot_id=1,
|
||||||
|
command="CLOSE",
|
||||||
|
timestamp=datetime.now())
|
||||||
|
crud.record_door_access_log(db, log_entry)
|
||||||
|
|
||||||
|
def init_user_connections():
|
||||||
|
users = [ crud.get_user(db, 1),
|
||||||
|
crud.get_user(db, 2),
|
||||||
|
crud.get_user(db, 3)]
|
||||||
|
|
||||||
|
for i in range(3):
|
||||||
|
crud.record_user_connection(db, users[i], datetime.now())
|
||||||
|
crud.record_user_connection(db, users[i], datetime.now())
|
||||||
|
crud.record_user_connection(db, users[i], datetime.now())
|
||||||
|
|
||||||
|
def init_link_room_monitor():
|
||||||
|
monitor = crud.get_monitor(db, 1)
|
||||||
|
door = crud.get_iot_entity(db, 1)
|
||||||
|
monitor.door = door
|
||||||
|
crud.update_monitor(db, monitor)
|
||||||
|
|
||||||
|
def init():
|
||||||
|
init_user()
|
||||||
|
init_door()
|
||||||
|
init_monitor()
|
||||||
|
init_allowance()
|
||||||
|
init_sensor_data()
|
||||||
|
init_open_close_requests()
|
||||||
|
init_user_connections()
|
||||||
|
init_link_room_monitor()
|
||||||
|
|
@ -4,3 +4,17 @@ echo "API_KEY=$(./gen_secret.sh)" >> .env
|
|||||||
echo "API_KEY_NAME=big_boy" >> .env
|
echo "API_KEY_NAME=big_boy" >> .env
|
||||||
echo "jwt_secret=$(./gen_secret.sh)" >> .env
|
echo "jwt_secret=$(./gen_secret.sh)" >> .env
|
||||||
echo "jwt_algorithm=HS256" >> .env
|
echo "jwt_algorithm=HS256" >> .env
|
||||||
|
|
||||||
|
read -s -p "First User password: " firstpass
|
||||||
|
echo
|
||||||
|
read -s -p "Retype First User password: " secondpass
|
||||||
|
echo
|
||||||
|
|
||||||
|
if [ $firstpass != $secondpass ];
|
||||||
|
then
|
||||||
|
echo "Passwords dont match!"
|
||||||
|
exit 255
|
||||||
|
fi
|
||||||
|
echo "first_user_pass=$firstpass" >> .env
|
||||||
|
|
||||||
|
chmod 600 .env
|
||||||
|
469
sql_app/main.py
469
sql_app/main.py
@ -1,10 +1,15 @@
|
|||||||
|
# March 2022
|
||||||
|
# Hesham T. Banafa <hishaminv@gmail.com>
|
||||||
|
|
||||||
from fastapi import Depends, FastAPI, HTTPException, status
|
from fastapi import Depends, FastAPI, HTTPException, status
|
||||||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm, OAuth2AuthorizationCodeBearer
|
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm, OAuth2AuthorizationCodeBearer
|
||||||
from fastapi.security.api_key import APIKey
|
from fastapi.security.api_key import APIKey
|
||||||
|
from fastapi.responses import PlainTextResponse
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from . import crud, models, schemas, auth_helper
|
from . import crud, models, schemas, auth_helper, init_db
|
||||||
from .database import SessionLocal, engine
|
from .database import SessionLocal, engine
|
||||||
|
from .utils import get_db, EMERG_SMOKE, EMERG_TEMP, EMERG_OPEN_TIME_SEC
|
||||||
|
|
||||||
from typing import List
|
from typing import List
|
||||||
from datetime import timedelta, datetime
|
from datetime import timedelta, datetime
|
||||||
@ -15,13 +20,10 @@ oauth = OAuth2PasswordBearer(tokenUrl="tkn")
|
|||||||
|
|
||||||
app = FastAPI(title="IoT Building System")
|
app = FastAPI(title="IoT Building System")
|
||||||
|
|
||||||
|
# Split into endpoints modules
|
||||||
|
#app.include_router(users.router,prefix="/users", tags=["User"])
|
||||||
|
init_db.init()
|
||||||
|
|
||||||
def get_db():
|
|
||||||
db = SessionLocal()
|
|
||||||
try:
|
|
||||||
yield db
|
|
||||||
finally:
|
|
||||||
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(
|
credentials_exception = HTTPException(
|
||||||
@ -64,135 +66,29 @@ def get_current_iot_device(current_device: schemas.IotBluetoothMac = Depends(),
|
|||||||
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 HTTPException(status_code=400, detail="Email/Username already registered")
|
||||||
|
|
||||||
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 HTTPException(status_code=400, detail="Email/Username already registered")
|
||||||
|
|
||||||
return crud.create_user(db=db, user=user)
|
db_user = crud.create_user(db=db, user=user)
|
||||||
|
if not db_user:
|
||||||
|
raise HTTPException(status_code=500, detail="Failed to create user")
|
||||||
|
|
||||||
|
access_token = auth_helper.create_access_token(
|
||||||
|
data={"sub": db_user.username}, expires_delta=timedelta(minutes=15)
|
||||||
|
)
|
||||||
|
crud.set_user_last_token(db, db_user.username, access_token)
|
||||||
|
#crud.record_user_connection(db, db_user, datetime.now())
|
||||||
|
return db_user
|
||||||
|
|
||||||
@app.get("/users/me/", response_model=schemas.User, tags=['Users'])
|
@app.get("/users/me/", response_model=schemas.User, tags=['Users'])
|
||||||
def get_user_details(current_user: schemas.User = Depends(get_current_active_user)):
|
def get_user_details(db: Session = Depends(get_db),
|
||||||
|
current_user: schemas.User = Depends(get_current_active_user)):
|
||||||
|
#crud.record_user_connection(db, current_user, datetime.now())
|
||||||
return current_user
|
return current_user
|
||||||
|
|
||||||
@app.get("/admin/users/", response_model=List[schemas.User], tags=['Admin'])
|
|
||||||
def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
|
|
||||||
users = crud.get_users(db, skip=skip, limit=limit)
|
|
||||||
return users
|
|
||||||
|
|
||||||
@app.get("/admin/iotentities/", response_model=List[schemas.IotEntity], tags=['Admin'])
|
|
||||||
def read_iot_entities(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
|
|
||||||
iot_entities = crud.get_iot_entities(db, skip=skip, limit=limit)
|
|
||||||
return iot_entities
|
|
||||||
|
|
||||||
# TODO: Can duplicate
|
|
||||||
@app.post("/admin/iotentities/create", response_model=schemas.IotEntity, tags=['Admin'])
|
|
||||||
def create_iot_entities(iot_entity: schemas.IotEntityCreate, db: Session = Depends(get_db)):
|
|
||||||
iot_entities = crud.create_iot_entity(db, iot_entity)
|
|
||||||
return iot_entities
|
|
||||||
|
|
||||||
@app.get("/admin/users/{user_id}", response_model=schemas.User, tags=['Admin'])
|
|
||||||
def read_user(user_id: int, db: Session = Depends(get_db)):
|
|
||||||
db_user = crud.get_user(db, user_id=user_id)
|
|
||||||
if db_user is None:
|
|
||||||
raise HTTPException(status_code=404, detail="User not found")
|
|
||||||
return db_user
|
|
||||||
|
|
||||||
@app.post("/admin/users/allowdevice/id", tags=['Admin'])
|
|
||||||
def allow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db)):
|
|
||||||
user = crud.get_user(db, request.user_id)
|
|
||||||
if not user:
|
|
||||||
raise HTTPException(status_code=404, detail="User not found")
|
|
||||||
|
|
||||||
iot_entity = crud.get_iot_entity(db, request.iot_entity_id)
|
|
||||||
if not iot_entity:
|
|
||||||
raise HTTPException(status_code=404, detail="Iot Entity not found")
|
|
||||||
|
|
||||||
res = crud.create_user_link_to_iot(db, request.user_id, request.iot_entity_id)
|
|
||||||
if not res:
|
|
||||||
raise HTTPException(status_code=500, detail="Could not complete operation")
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
@app.post("/admin/users/disallowdevice/id", tags=['Admin'])
|
|
||||||
def disallow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db)):
|
|
||||||
user = crud.get_user(db, request.user_id)
|
|
||||||
if not user:
|
|
||||||
raise HTTPException(status_code=404, detail="User not found")
|
|
||||||
|
|
||||||
iot_entity = crud.get_iot_entity(db, request.iot_entity_id)
|
|
||||||
if not iot_entity:
|
|
||||||
raise HTTPException(status_code=404, detail="Iot Entity not found")
|
|
||||||
|
|
||||||
res = crud.remove_user_link_to_iot(db, request.user_id, request.iot_entity_id)
|
|
||||||
if not res:
|
|
||||||
raise HTTPException(status_code=500, detail="Could not complete operation")
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
@app.post("/admin/users/allowdevice/name", tags=['Admin'])
|
|
||||||
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)):
|
|
||||||
return
|
|
||||||
|
|
||||||
@app.post("/admin/users/{user_id}/activeate", tags=['Admin'])
|
|
||||||
def deactiveate_user(user_id: int, db:Session = Depends(get_db)):
|
|
||||||
return
|
|
||||||
|
|
||||||
@app.post("/admin/iotdevice/gentoken/", response_model=schemas.Token, tags=['Admin'])
|
|
||||||
def generate_token_for_iot_device(bluetooth_mac : schemas.IotBluetoothMac,
|
|
||||||
api_key: APIKey = Depends(auth_helper.valid_api_key)):
|
|
||||||
# We get here after a valid admin key, so send back permenant token
|
|
||||||
data = {"bluetooth_mac": bluetooth_mac.bluetooth_mac}
|
|
||||||
tkn = auth_helper.create_iot_dev_token(data)
|
|
||||||
return {"access_token": tkn, "token_type": "bearer"}
|
|
||||||
|
|
||||||
@app.post("/admin/iotdevice/accesslog/", tags=['Admin'])
|
|
||||||
def get_access_log_for_door(request : schemas.AccessLogRequest,
|
|
||||||
db : Session = Depends(get_db)):
|
|
||||||
device = crud.get_iot_entity_by_bluetooth_mac(db, request.bluetooth_mac)
|
|
||||||
if not device: raise HTTPException(status_code=404, detail="Iot Entity not found")
|
|
||||||
return crud.get_access_log_for_door_by_door_mac(db, request.bluetooth_mac)
|
|
||||||
|
|
||||||
@app.post("/admin/user/accesslog/email/", tags=['Admin'])
|
|
||||||
def get_access_log_history_for_user(request : schemas.UserAccessLogRequestEmail,
|
|
||||||
db : Session = Depends(get_db)):
|
|
||||||
user = crud.get_user_by_email(db, request.email)
|
|
||||||
if not user: raise HTTPException(status_code=404, detail="User not found")
|
|
||||||
return crud.get_access_log_for_user_by_id(db, user.id)
|
|
||||||
|
|
||||||
@app.post("/admin/user/accesslog/username/", tags=['Admin'])
|
|
||||||
def get_access_log_history_for_user(request : schemas.UserAccessLogRequestUsername,
|
|
||||||
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")
|
|
||||||
return crud.get_access_log_for_user_by_id(db, user.id)
|
|
||||||
|
|
||||||
@app.get("/users/acesslist/", response_model=List[schemas.IotEntity], tags=['Users'])
|
|
||||||
def get_iot_access_list_for_user(db: Session = Depends(get_db), current_user: schemas.User = Depends(get_current_active_user)):
|
|
||||||
user = crud.get_user_by_username(db, current_user.username)
|
|
||||||
return user.authorized_devices
|
|
||||||
|
|
||||||
@app.get("/admin/roominfo/now/", tags=['Admin'])
|
|
||||||
def get_room_data(db: Session = Depends(get_db)):
|
|
||||||
return crud.get_room_data_now(db)
|
|
||||||
|
|
||||||
@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(command: schemas.OpenDoorRequestTime,
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
@ -207,12 +103,70 @@ def issue_open_door_command(command: schemas.OpenDoorRequestTime,
|
|||||||
if dev.bluetooth_mac == device.bluetooth_mac:
|
if dev.bluetooth_mac == device.bluetooth_mac:
|
||||||
crud.set_open_door_request(db, device.id, command.time_seconds)
|
crud.set_open_door_request(db, device.id, command.time_seconds)
|
||||||
log_entry = schemas.DoorAccessLog(user_id=current_user.id,
|
log_entry = schemas.DoorAccessLog(user_id=current_user.id,
|
||||||
door_bluetooth_mac=command.bluetooth_mac,
|
iot_id=device.id,
|
||||||
time=datetime.now())
|
command="OPEN",
|
||||||
|
timestamp=datetime.now())
|
||||||
crud.record_door_access_log(db, log_entry)
|
crud.record_door_access_log(db, log_entry)
|
||||||
|
#crud.record_user_connection(db, current_user, datetime.now())
|
||||||
|
|
||||||
return device
|
return device
|
||||||
raise err
|
raise err
|
||||||
|
|
||||||
|
@app.post("/users/close", tags=['Users'])
|
||||||
|
def issue_close_door_command(command: schemas.CloseDoorRequest,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_user: schemas.User = Depends(get_current_active_user)):
|
||||||
|
err = HTTPException(status.HTTP_401_UNAUTHORIZED,
|
||||||
|
detail="Unaithrized to close")
|
||||||
|
device = crud.get_iot_entity_by_bluetooth_mac(db, command.bluetooth_mac)
|
||||||
|
if not device: raise err
|
||||||
|
user = crud.get_user(db, current_user.id)
|
||||||
|
for dev in user.authorized_devices:
|
||||||
|
if dev.bluetooth_mac == device.bluetooth_mac:
|
||||||
|
crud.set_close_door_request(db, device.id)
|
||||||
|
log_entry = schemas.DoorAccessLog(user_id=current_user.id,
|
||||||
|
iot_id=device.id,
|
||||||
|
command="CLOSE",
|
||||||
|
timestamp=datetime.now())
|
||||||
|
crud.record_door_access_log(db, log_entry)
|
||||||
|
#crud.record_user_connection(db, current_user, datetime.now())
|
||||||
|
|
||||||
|
return device
|
||||||
|
|
||||||
|
@app.get("/users/acesslist/", response_model=List[schemas.RoomOverview], tags=['Users'])
|
||||||
|
def get_iot_access_list_for_user(db: Session = Depends(get_db), current_user: schemas.User = Depends(get_current_active_user)):
|
||||||
|
user = crud.get_user_by_username(db, current_user.username)
|
||||||
|
access_list = list()
|
||||||
|
for device in user.authorized_devices:
|
||||||
|
door : models.IotEntity = device
|
||||||
|
monitor : models.Monitors = door.monitor
|
||||||
|
if not monitor: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail="No Room link")
|
||||||
|
entry : schemas.RoomOverview = schemas.RoomOverview(
|
||||||
|
id=door.id,
|
||||||
|
description=door.description,
|
||||||
|
bluetooth_mac=door.bluetooth_mac,
|
||||||
|
open_request=door.open_request,
|
||||||
|
time_seconds=door.time_seconds,
|
||||||
|
acces_list_counter=door.acces_list_counter,
|
||||||
|
humidity=monitor.humidity,
|
||||||
|
people=monitor.people,
|
||||||
|
temperature=monitor.temperature,
|
||||||
|
smoke_sensor_reading=monitor.smoke_sensor_reading,
|
||||||
|
force_close=door.force_close,
|
||||||
|
state=door.state
|
||||||
|
)
|
||||||
|
access_list.append(entry)
|
||||||
|
#crud.record_user_connection(db, user, datetime.now())
|
||||||
|
return access_list
|
||||||
|
|
||||||
|
@app.patch("/users/updatepassword", tags=['Users'])
|
||||||
|
def change_user_password(request: schemas.UserUpdatePassword,
|
||||||
|
current_user: models.User = Depends(get_current_active_user),
|
||||||
|
db: Session = Depends(get_db)):
|
||||||
|
crud.update_user_password(db, current_user, request)
|
||||||
|
return
|
||||||
|
|
||||||
@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'])
|
||||||
def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)):
|
def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)):
|
||||||
@ -227,14 +181,201 @@ def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(), db:
|
|||||||
access_token = auth_helper.create_access_token(
|
access_token = auth_helper.create_access_token(
|
||||||
data={"sub": form_data.username}, expires_delta=timedelta(minutes=15)
|
data={"sub": form_data.username}, expires_delta=timedelta(minutes=15)
|
||||||
)
|
)
|
||||||
|
crud.set_user_last_token(db, form_data.username, access_token)
|
||||||
|
#crud.record_user_connection(db, user, datetime.now())
|
||||||
return {"access_token": access_token, "token_type": "bearer"}
|
return {"access_token": access_token, "token_type": "bearer"}
|
||||||
|
|
||||||
|
@app.get("/admin/users/", response_model=List[schemas.User], tags=['Admin'])
|
||||||
|
def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
|
||||||
|
users = crud.get_users(db, skip=skip, limit=limit)
|
||||||
|
return users
|
||||||
|
|
||||||
|
@app.get("/admin/iotentities/", response_model=List[schemas.IotEntity], tags=['Admin'])
|
||||||
|
def read_iot_entities(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
|
||||||
|
iot_entities = crud.get_iot_entities(db, skip=skip, limit=limit)
|
||||||
|
return iot_entities
|
||||||
|
|
||||||
|
@app.get("/admin/monitors/", response_model=List[schemas.Monitor], tags=['Admin'])
|
||||||
|
def read_iot_monitors(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
|
||||||
|
monitors = crud.get_monitors(db, skip=skip, limit=limit)
|
||||||
|
return monitors
|
||||||
|
|
||||||
|
# TODO: Can duplicate
|
||||||
|
@app.post("/admin/iotentities/create", response_model=schemas.IotEntity, tags=['Admin'])
|
||||||
|
def create_iot_entities(iot_entity: schemas.IotEntityCreate, db: Session = Depends(get_db)):
|
||||||
|
iot_entities = crud.create_iot_entity(db, iot_entity)
|
||||||
|
return iot_entities
|
||||||
|
|
||||||
|
@app.post("/admin/monitor/create", response_model=schemas.Monitor, tags=['Admin'])
|
||||||
|
def create_monitor(iot_entity: schemas.IotEntityBase,
|
||||||
|
db: Session = Depends(get_db)):
|
||||||
|
monitor = crud.create_monitor(db, iot_entity)
|
||||||
|
return monitor
|
||||||
|
|
||||||
|
@app.get("/admin/users/{user_id}", response_model=schemas.User, tags=['Admin'])
|
||||||
|
def read_user(user_id: int, db: Session = Depends(get_db)):
|
||||||
|
db_user = crud.get_user(db, user_id=user_id)
|
||||||
|
if db_user is None:
|
||||||
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="User not found")
|
||||||
|
return db_user
|
||||||
|
|
||||||
|
@app.patch("/admin/users/allowdevice/id", tags=['Admin'])
|
||||||
|
def allow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db)):
|
||||||
|
user = crud.get_user(db, request.user_id)
|
||||||
|
if not user:
|
||||||
|
raise HTTPException(status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="User not found")
|
||||||
|
|
||||||
|
iot_entity = crud.get_iot_entity(db, request.iot_entity_id)
|
||||||
|
if not iot_entity:
|
||||||
|
raise HTTPException(status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="Iot Entity not found")
|
||||||
|
|
||||||
|
res = crud.create_user_link_to_iot(db, request.user_id, request.iot_entity_id)
|
||||||
|
if not res:
|
||||||
|
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail="Could not complete operation")
|
||||||
|
|
||||||
|
crud.increment_door_access_list_counter(db, iot_entity)
|
||||||
|
return
|
||||||
|
|
||||||
|
@app.patch("/admin/users/disallowdevice/id", tags=['Admin'])
|
||||||
|
def disallow_user_for_iot_entity_by_id(request: schemas.UserAllowForIotEntityRequestByID, db: Session = Depends(get_db)):
|
||||||
|
user = crud.get_user(db, request.user_id)
|
||||||
|
if not user:
|
||||||
|
raise HTTPException(status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="User not found")
|
||||||
|
|
||||||
|
iot_entity = crud.get_iot_entity(db, request.iot_entity_id)
|
||||||
|
if not iot_entity:
|
||||||
|
raise HTTPException(status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="Iot Entity not found")
|
||||||
|
|
||||||
|
res = crud.remove_user_link_to_iot(db, request.user_id, request.iot_entity_id)
|
||||||
|
if not res:
|
||||||
|
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail="Could not complete operation")
|
||||||
|
|
||||||
|
crud.increment_door_access_list_counter(db, iot_entity)
|
||||||
|
return
|
||||||
|
|
||||||
|
@app.patch("/admin/users/allowdevice/name", tags=['Admin'])
|
||||||
|
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.HTTP_404_NOT_FOUND,
|
||||||
|
detail="User not found")
|
||||||
|
|
||||||
|
iot_entity = crud.get_iot_entity_by_description(db, request.description)
|
||||||
|
if not iot_entity:
|
||||||
|
raise HTTPException(status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="Iot Entity not found")
|
||||||
|
|
||||||
|
res = crud.create_user_link_to_iot(db, user.id, iot_entity.id)
|
||||||
|
if not res:
|
||||||
|
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail="Could not complete operation")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
@app.patch("/admin/users/{user_id}/deactiveate", tags=['Admin'])
|
||||||
|
def deactiveate_user(user_id: int, db:Session = Depends(get_db)):
|
||||||
|
user = crud.get_user(db, user_id)
|
||||||
|
crud.update_user_status(db, user, False)
|
||||||
|
|
||||||
|
@app.patch("/admin/users/{user_id}/activeate", tags=['Admin'])
|
||||||
|
def deactiveate_user(user_id: int, db:Session = Depends(get_db)):
|
||||||
|
user = crud.get_user(db, user_id)
|
||||||
|
crud.update_user_status(db, user, True)
|
||||||
|
|
||||||
|
@app.post("/admin/iotdevice/gentoken/", response_model=schemas.Token, tags=['Admin'])
|
||||||
|
def generate_token_for_iot_device(bluetooth_mac : schemas.IotBluetoothMac):
|
||||||
|
# api_key: APIKey = Depends(auth_helper.valid_api_key)
|
||||||
|
# We get here after a valid admin key, so send back permenant token
|
||||||
|
data = {"bluetooth_mac": bluetooth_mac.bluetooth_mac}
|
||||||
|
tkn = auth_helper.create_iot_dev_token(data)
|
||||||
|
return {"access_token": tkn, "token_type": "bearer"}
|
||||||
|
|
||||||
|
@app.patch("/admin/link/monitor/{monitor_id}/door/{door_id}", tags=['Admin'])
|
||||||
|
def link_monitor_with_door(monitor_id: int, door_id: int,
|
||||||
|
db: Session = Depends(get_db)):
|
||||||
|
monitor = crud.get_monitor(db, monitor_id)
|
||||||
|
door = crud.get_iot_entity(db, door_id)
|
||||||
|
monitor.door = door
|
||||||
|
crud.update_monitor(db, monitor)
|
||||||
|
return monitor
|
||||||
|
|
||||||
|
@app.post("/admin/user/accesslog/email/", tags=['Admin'])
|
||||||
|
def get_access_log_history_for_user(request : schemas.UserAccessLogRequestEmail,
|
||||||
|
db : Session = Depends(get_db)):
|
||||||
|
user = crud.get_user_by_email(db, request.email)
|
||||||
|
if not user: raise HTTPException(status.HTTP_404_NOT_FOUND, detail="User not found")
|
||||||
|
return user.access_log
|
||||||
|
|
||||||
|
@app.post("/admin/user/accesslog/username/", tags=['Admin'])
|
||||||
|
def get_access_log_history_for_user(request : schemas.UserAccessLogRequestUsername,
|
||||||
|
db : Session = Depends(get_db)):
|
||||||
|
user = crud.get_user_by_username(db, request.username)
|
||||||
|
if not user: raise HTTPException(status.HTTP_404_NOT_FOUND, detail="User not found")
|
||||||
|
return user.access_log
|
||||||
|
|
||||||
|
@app.get("/admin/roominfo/{door_id}/now", tags=['Admin'])
|
||||||
|
def get_room_data(door_id: int, db: Session = Depends(get_db)):
|
||||||
|
door = crud.get_iot_entity(db, door_id)
|
||||||
|
if not door:
|
||||||
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="Door not found")
|
||||||
|
monitor : models.Monitors = door.monitor
|
||||||
|
if not monitor:
|
||||||
|
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail="No Room link")
|
||||||
|
data = monitor.sensor_history
|
||||||
|
if not data or len(data) == 0:
|
||||||
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="No Sensor data")
|
||||||
|
return data[-1]
|
||||||
|
|
||||||
|
@app.get("/admin/roominfo/{monitor_id}/now", tags=['Admin'])
|
||||||
|
def get_room_data(monitor_id: int, db: Session = Depends(get_db)):
|
||||||
|
monitor = crud.get_monitor(db, monitor_id)
|
||||||
|
if not monitor: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="Monitor not found")
|
||||||
|
if not monitor.door_id:
|
||||||
|
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail="Monitor not linked")
|
||||||
|
|
||||||
|
data = crud.get_room_data_now(db, monitor.door_id)
|
||||||
|
if data == -1: raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail="No Room link")
|
||||||
|
if data == -2: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="No Sensor data")
|
||||||
|
return data
|
||||||
|
|
||||||
|
@app.get("/admin/roominfo/{monitor_id}/last/{count}", tags=['Admin'])
|
||||||
|
def get_all_sensor_history(monitor_id: int, count: int,
|
||||||
|
db: Session = Depends(get_db)):
|
||||||
|
monitor = crud.get_monitor(db, monitor_id)
|
||||||
|
if not monitor: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="Monitor not found")
|
||||||
|
data = monitor.sensor_history
|
||||||
|
if not data or len(data) == 0:
|
||||||
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail="No Sensor data")
|
||||||
|
return data[-count:]
|
||||||
|
|
||||||
|
@app.post("/admin/roominfo/accesslog",response_model=List[schemas.DoorAccessLog], tags=['Admin'])
|
||||||
|
def get_access_log_for_door(request : schemas.AccessLogRequest,
|
||||||
|
db : Session = Depends(get_db)):
|
||||||
|
device: models.IotEntity = crud.get_iot_entity(db, request.iot_id)
|
||||||
|
if not device: raise HTTPException(status.HTTP_404_NOT_FOUND, detail="Iot Entity not found")
|
||||||
|
return device.access_log
|
||||||
|
|
||||||
@app.post("/iotdevice/door/status", response_model=schemas.IotDoorPollingResponse, tags=['Iot'])
|
@app.post("/iotdevice/door/status", response_model=schemas.IotDoorPollingResponse, tags=['Iot'])
|
||||||
def polling_method_for_iot_entity(request: schemas.IotDoorPollingRequest,
|
def polling_method_for_iot_entity(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.IotEntity = auth_helper.valid_iot_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,
|
||||||
@ -242,19 +383,71 @@ def polling_method_for_iot_entity(request: schemas.IotDoorPollingRequest,
|
|||||||
|
|
||||||
response : schemas.IotDoorPollingResponse = schemas.IotDoorPollingResponse(
|
response : schemas.IotDoorPollingResponse = schemas.IotDoorPollingResponse(
|
||||||
open_command=device.open_request,
|
open_command=device.open_request,
|
||||||
acces_list_counter=0,
|
acces_list_counter=device.acces_list_counter,
|
||||||
time_seconds=device.time_seconds)
|
time_seconds=device.time_seconds,
|
||||||
|
force_close=device.force_close,
|
||||||
|
state=device.state)
|
||||||
# Reset open_request to False
|
# Reset open_request to False
|
||||||
crud.clear_open_door_request(db, device.id)
|
crud.clear_open_door_request(db, device.id)
|
||||||
|
crud.clear_close_door_request(db, device.id)
|
||||||
|
crud.set_door_state(db, device, bool(request.state))
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@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.MonitorUpdateReadings,
|
||||||
db: Session = Depends(get_db)):
|
db: Session = Depends(get_db)):
|
||||||
device : schemas.IotEntity = auth_helper.valid_iot_token(request.token, db)
|
device : models.Monitors = auth_helper.valid_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,
|
||||||
detail="Could not validate credentials")
|
detail="Could not validate credentials")
|
||||||
crud.record_room_sensor_data(db, request)
|
crud.record_room_sensor_data(db, request, device)
|
||||||
return request
|
if request.temperature >= EMERG_TEMP or request.smoke_sensor_reading >= EMERG_SMOKE:
|
||||||
|
print("********EMERGENCY AT %s********" % device.description)
|
||||||
|
door : models.IotEntity = device.door
|
||||||
|
print("********OPENING DOOR %s ID:%d********" % (door.description, door.id))
|
||||||
|
crud.set_open_door_request(db, door.id, EMERG_OPEN_TIME_SEC)
|
||||||
|
crud.record_emergancy_entry(db, request, device.id)
|
||||||
|
# Call into a hook to notify with room and people
|
||||||
|
|
||||||
|
print(request)
|
||||||
|
return request
|
||||||
|
|
||||||
|
@app.post("/iotdevice/door/users", response_class=PlainTextResponse, tags=['Iot'])
|
||||||
|
def get_allowed_usernames(request: schemas.IotDoorPollingRequest,
|
||||||
|
db: Session = Depends(get_db)):
|
||||||
|
|
||||||
|
iot_door : models.IotEntity = auth_helper.valid_iot_token(request.token, db)
|
||||||
|
if not iot_door:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
detail="Could not validate credentials")
|
||||||
|
usernames = str()
|
||||||
|
for user in iot_door.authorized_users:
|
||||||
|
db_user : models.User = user
|
||||||
|
usernames = usernames + db_user.username + '\n'
|
||||||
|
|
||||||
|
return usernames
|
||||||
|
|
||||||
|
@app.post("/iotdevice/door/tkns", response_class=PlainTextResponse, tags=['Iot'])
|
||||||
|
def get_allowed_usernames(request: schemas.IotDoorPollingRequest,
|
||||||
|
db: Session = Depends(get_db)):
|
||||||
|
|
||||||
|
iot_door : models.IotEntity = auth_helper.valid_iot_token(request.token, db)
|
||||||
|
if not iot_door:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
detail="Could not validate credentials")
|
||||||
|
tkns = str()
|
||||||
|
for user in iot_door.authorized_users:
|
||||||
|
db_user : models.User = user
|
||||||
|
tkns = tkns + db_user.last_token + '\n'
|
||||||
|
|
||||||
|
return tkns
|
||||||
|
|
||||||
|
@app.get("/test")
|
||||||
|
def get(db: Session = Depends(get_db)):
|
||||||
|
mon = crud.get_monitor(db, "ff:ff:ff:ff")
|
||||||
|
|
||||||
|
return mon.door
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# March 2022
|
||||||
|
# Hesham T. Banafa <hishaminv@gmail.com>
|
||||||
|
|
||||||
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, DateTime
|
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, DateTime
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
@ -13,43 +16,87 @@ class User(Base):
|
|||||||
hashed_password = Column(String, nullable=False)
|
hashed_password = Column(String, nullable=False)
|
||||||
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)
|
||||||
|
last_token = Column(String, nullable=True)
|
||||||
authorized_devices = relationship("IotEntity", secondary= 'user_iot_link')
|
connections = relationship("UserConnectionHistory")
|
||||||
|
authorized_devices = relationship("IotEntity", secondary="user_iot_link", back_populates="authorized_users")
|
||||||
|
connections = relationship("UserConnectionHistory")
|
||||||
|
access_log = relationship("DoorAccessLog", back_populates="user")
|
||||||
|
|
||||||
class IotEntity(Base):
|
class IotEntity(Base):
|
||||||
__tablename__ = "iot_entities"
|
__tablename__ = "iot_entities"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
bluetooth_mac = Column(String(512))
|
bluetooth_mac = Column(String(512), index=True, unique=True)
|
||||||
description = Column(String(512))
|
description = Column(String(512))
|
||||||
open_request = Column(Boolean, default=False)
|
open_request = Column(Boolean, default=False)
|
||||||
time_seconds = Column(Integer, default=10)
|
time_seconds = Column(Integer, default=10)
|
||||||
authorized_users = relationship("User", secondary= 'user_iot_link')
|
acces_list_counter = Column(Integer, default=0)
|
||||||
|
force_close = Column(Boolean, default=False)
|
||||||
|
state = Column(Boolean, default=False) # True is open, False is closed
|
||||||
|
authorized_users = relationship("User", secondary="user_iot_link", back_populates="authorized_devices")
|
||||||
|
access_log = relationship("DoorAccessLog", back_populates="iot_device") # one-to-many
|
||||||
|
monitor = relationship("Monitors", back_populates="door", uselist=False) # one-to-one
|
||||||
|
|
||||||
|
class Monitors(Base):
|
||||||
|
__tablename__ = "monitors"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
bluetooth_mac = Column(String(512), index=True, unique=True)
|
||||||
|
description = Column(String(512))
|
||||||
|
humidity = Column(Integer, default=0)
|
||||||
|
people = Column(Integer, default=0)
|
||||||
|
temperature = Column(Integer, default=0)
|
||||||
|
smoke_sensor_reading = Column(Integer, default=0)
|
||||||
|
door_id = Column(Integer, ForeignKey("iot_entities.id"))
|
||||||
|
door = relationship("IotEntity", back_populates="monitor")
|
||||||
|
sensor_history = relationship("RoomSensorData", back_populates="monitor")
|
||||||
|
|
||||||
class UserAuthToIoTDev(Base):
|
class UserAuthToIoTDev(Base):
|
||||||
__tablename__ = "user_iot_link"
|
__tablename__ = "user_iot_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)
|
||||||
iot_entity_id = Column(Integer, ForeignKey('iot_entities.id'), primary_key=True, index=True)
|
iot_id = Column(Integer, ForeignKey("iot_entities.id"), primary_key=True)
|
||||||
|
timestamp = Column(DateTime)
|
||||||
|
|
||||||
class DoorAccessLog(Base):
|
class DoorAccessLog(Base):
|
||||||
__tablename__ = "door_access_log"
|
__tablename__ = "door_access_log"
|
||||||
|
|
||||||
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'), index=True)
|
||||||
iot_dev_bluetooth_mac = Column(Integer, ForeignKey('iot_entities.id'))
|
user = relationship("User", back_populates="access_log")
|
||||||
|
iot_id = Column(Integer, ForeignKey('iot_entities.id'), index=True)
|
||||||
|
iot_device = relationship("IotEntity", back_populates="access_log")
|
||||||
|
command = Column(String(16))
|
||||||
timestamp = Column(DateTime)
|
timestamp = Column(DateTime)
|
||||||
|
|
||||||
class RoomSensorData(Base):
|
class RoomSensorData(Base):
|
||||||
__tablename__ = "room_sensor_data"
|
__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)
|
reading_id = Column(Integer, primary_key=True, index=True)
|
||||||
humidity = Column(Integer)
|
humidity = Column(Integer)
|
||||||
people = Column(Integer)
|
people = Column(Integer)
|
||||||
temperature = Column(Integer)
|
temperature = Column(Integer)
|
||||||
smoke_sensor_reading = Column(Integer)
|
smoke_sensor_reading = Column(Integer)
|
||||||
timestamp = Column(DateTime)
|
timestamp = Column(DateTime)
|
||||||
|
monitor_id = Column(Integer, ForeignKey("monitors.id"), index=True)
|
||||||
|
monitor = relationship("Monitors", back_populates="sensor_history")
|
||||||
|
|
||||||
# TODO: Add table to store active sessions. May periodically clear.
|
class UserConnectionHistory(Base):
|
||||||
|
__tablename__ = "user_connection_history"
|
||||||
|
|
||||||
|
reading_id = Column(Integer, primary_key=True)
|
||||||
|
user_id = Column(Integer, ForeignKey("user_accounts.id"), index=True)
|
||||||
|
timestamp = Column(DateTime)
|
||||||
|
# TODO: add ip
|
||||||
|
|
||||||
|
class EmergancyNotice(Base):
|
||||||
|
__tablename__ = "emergency_notice"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
monitor_id = Column(Integer, ForeignKey("monitors.id"), index=True)
|
||||||
|
people = Column(Integer)
|
||||||
|
temperature = Column(Integer)
|
||||||
|
smoke_sensor_reading = Column(Integer)
|
||||||
|
timestamp = Column(DateTime)
|
||||||
|
|
||||||
|
# TODO: Add table to store active sessions. May periodically clear.
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# March 2022
|
||||||
|
# Hesham T. Banafa <hishaminv@gmail.com>
|
||||||
|
|
||||||
from typing import Any, List, Optional
|
from typing import Any, List, Optional
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
@ -26,12 +29,35 @@ class IotEntity(IotEntityBase):
|
|||||||
#authorized_users: List[User] = []
|
#authorized_users: List[User] = []
|
||||||
open_request: bool # Flag to open
|
open_request: bool # Flag to open
|
||||||
time_seconds: int
|
time_seconds: int
|
||||||
|
force_close: bool
|
||||||
|
acces_list_counter: int
|
||||||
|
state: bool
|
||||||
class Config:
|
class Config:
|
||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
class IotBluetoothMac(BaseModel):
|
class IotBluetoothMac(BaseModel):
|
||||||
bluetooth_mac : str
|
bluetooth_mac : str
|
||||||
|
|
||||||
|
class Monitor(IotEntityBase):
|
||||||
|
# bluetooth_mac: str
|
||||||
|
# description: str
|
||||||
|
id: int
|
||||||
|
bluetooth_mac: str
|
||||||
|
description: str
|
||||||
|
humidity: int
|
||||||
|
people: int
|
||||||
|
temperature: int
|
||||||
|
smoke_sensor_reading: int
|
||||||
|
class Config:
|
||||||
|
orm_mode = True
|
||||||
|
|
||||||
|
class MonitorUpdateReadings(BaseModel):
|
||||||
|
humidity : int
|
||||||
|
people : int
|
||||||
|
temperature : int
|
||||||
|
smoke_sensor_reading : int
|
||||||
|
token: str # Contains mac
|
||||||
|
|
||||||
class User(UserBase):
|
class User(UserBase):
|
||||||
id: int
|
id: int
|
||||||
is_active: bool
|
is_active: bool
|
||||||
@ -58,6 +84,9 @@ class UserAllowForIotEntityRequestByUsername(BaseModel):
|
|||||||
username: str
|
username: str
|
||||||
description: str
|
description: str
|
||||||
|
|
||||||
|
class UserUpdatePassword(BaseModel):
|
||||||
|
password: str
|
||||||
|
|
||||||
class OpenDoorRequestBase(BaseModel):
|
class OpenDoorRequestBase(BaseModel):
|
||||||
username: str
|
username: str
|
||||||
bluetooth_mac: str
|
bluetooth_mac: str
|
||||||
@ -65,17 +94,20 @@ class OpenDoorRequestBase(BaseModel):
|
|||||||
class OpenDoorRequestTime(OpenDoorRequestBase):
|
class OpenDoorRequestTime(OpenDoorRequestBase):
|
||||||
time_seconds: int
|
time_seconds: int
|
||||||
|
|
||||||
|
class CloseDoorRequest(OpenDoorRequestBase):
|
||||||
|
pass
|
||||||
# Device sends this periodcally
|
# Device sends this periodcally
|
||||||
class IotDoorPollingRequest(BaseModel):
|
class IotDoorPollingRequest(BaseModel):
|
||||||
bluetooth_mac : str
|
bluetooth_mac : str
|
||||||
|
state: int
|
||||||
token : str
|
token : str
|
||||||
class Config:
|
|
||||||
orm_mode = True
|
|
||||||
|
|
||||||
class IotDoorPollingResponse(BaseModel):
|
class IotDoorPollingResponse(BaseModel):
|
||||||
open_command : bool
|
open_command : bool
|
||||||
acces_list_counter : int
|
acces_list_counter : int
|
||||||
time_seconds : int
|
time_seconds : int
|
||||||
|
force_close: bool
|
||||||
|
state: bool
|
||||||
|
|
||||||
class IotMonitorRoomInfo(BaseModel):
|
class IotMonitorRoomInfo(BaseModel):
|
||||||
humidity : int
|
humidity : int
|
||||||
@ -83,8 +115,8 @@ class IotMonitorRoomInfo(BaseModel):
|
|||||||
temperature : int
|
temperature : int
|
||||||
smoke_sensor_reading : int
|
smoke_sensor_reading : int
|
||||||
token: str
|
token: str
|
||||||
class Config:
|
# class Config:
|
||||||
orm_mode = True
|
# orm_mode = True
|
||||||
|
|
||||||
class IotMonitorRoomInfoTimestamped(IotMonitorRoomInfo):
|
class IotMonitorRoomInfoTimestamped(IotMonitorRoomInfo):
|
||||||
time: datetime
|
time: datetime
|
||||||
@ -93,13 +125,14 @@ class IotMonitorRoomInfoTimestamped(IotMonitorRoomInfo):
|
|||||||
|
|
||||||
class DoorAccessLog(BaseModel):
|
class DoorAccessLog(BaseModel):
|
||||||
user_id: int
|
user_id: int
|
||||||
door_bluetooth_mac: str
|
iot_id: str
|
||||||
time: datetime
|
command: str
|
||||||
|
timestamp: datetime
|
||||||
class Config:
|
class Config:
|
||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
class AccessLogRequest(BaseModel):
|
class AccessLogRequest(BaseModel):
|
||||||
bluetooth_mac : str
|
iot_id : int
|
||||||
|
|
||||||
class UserAccessLogRequestUsername(BaseModel):
|
class UserAccessLogRequestUsername(BaseModel):
|
||||||
username : str
|
username : str
|
||||||
@ -109,3 +142,9 @@ class UserAccessLogRequestEmail(BaseModel):
|
|||||||
|
|
||||||
class UserAccessLogRequestID(BaseModel):
|
class UserAccessLogRequestID(BaseModel):
|
||||||
id : int
|
id : int
|
||||||
|
|
||||||
|
class RoomOverview(IotEntity):
|
||||||
|
humidity : int
|
||||||
|
people : int
|
||||||
|
temperature : int
|
||||||
|
smoke_sensor_reading : int
|
||||||
|
0
sql_app/tests/__init__.py
Normal file
0
sql_app/tests/__init__.py
Normal file
4
sql_app/tests/run-tests
Executable file
4
sql_app/tests/run-tests
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
source ../../venv/bin/activate
|
||||||
|
pytest
|
92
sql_app/tests/test_user.py
Normal file
92
sql_app/tests/test_user.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
|
||||||
|
from sys import path
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
from requests import Response
|
||||||
|
|
||||||
|
from ..main import app
|
||||||
|
from ..schemas import UserCreate
|
||||||
|
|
||||||
|
|
||||||
|
MAX_ASCII = 255
|
||||||
|
RAND_CHAR_SET = string.ascii_letters
|
||||||
|
|
||||||
|
client = TestClient(app)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_rand_str(size: int) -> str:
|
||||||
|
return ''.join(random.choice(RAND_CHAR_SET) for x in range(size))
|
||||||
|
|
||||||
|
def gen_new_user_dict() -> UserCreate:
|
||||||
|
noune = gen_rand_str(16)
|
||||||
|
new_user = UserCreate(email=f"testuser{noune}@mail.none",
|
||||||
|
username=f"testuser{noune}",
|
||||||
|
password=noune)
|
||||||
|
return new_user
|
||||||
|
|
||||||
|
def get_user_json(user: UserCreate) -> dict:
|
||||||
|
if type(user) != UserCreate: assert False
|
||||||
|
new_user_json = {
|
||||||
|
'email' : user.email,
|
||||||
|
'username': user.username,
|
||||||
|
'password': user.password
|
||||||
|
}
|
||||||
|
return new_user_json
|
||||||
|
|
||||||
|
def post_request(response: Response):
|
||||||
|
print(response.text)
|
||||||
|
print(response.reason)
|
||||||
|
|
||||||
|
test_user : UserCreate = gen_new_user_dict()
|
||||||
|
|
||||||
|
common_headres = {
|
||||||
|
'accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_create_user():
|
||||||
|
|
||||||
|
response = client.request("POST", "/users/reg",
|
||||||
|
json=get_user_json(test_user),
|
||||||
|
headers=common_headres)
|
||||||
|
assert response.status_code == 200
|
||||||
|
post_request(response)
|
||||||
|
|
||||||
|
def test_create_user_duplicate_fields():
|
||||||
|
# Assumed that this test runs after test_create_user()
|
||||||
|
|
||||||
|
response = client.request("POST", "/users/reg",
|
||||||
|
json=get_user_json(test_user),
|
||||||
|
headers=common_headres)
|
||||||
|
assert response.status_code == 400
|
||||||
|
post_request(response)
|
||||||
|
|
||||||
|
|
||||||
|
def test_obtain_user_token():
|
||||||
|
headers = {
|
||||||
|
'accept': 'application/json',
|
||||||
|
'Content-type': 'application/x-www-form-urlencoded'
|
||||||
|
}
|
||||||
|
data = f"grant_type=&username={test_user.username}&password={test_user.password}&scope=&client_id=&client_secret="
|
||||||
|
response = client.request("POST", "/users/tkn", headers=headers, data=data)
|
||||||
|
# if response.status_code == 200 and 'application/json' in response.headers.get('Content-Type',''):
|
||||||
|
# print(response.json())
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
post_request(response)
|
||||||
|
|
||||||
|
|
||||||
|
def test_reject_false_creds():
|
||||||
|
headers = {
|
||||||
|
'accept': 'application/json',
|
||||||
|
'Content-type': 'application/x-www-form-urlencoded'
|
||||||
|
}
|
||||||
|
data = f"grant_type=&username={test_user.username}flaty&password=badpass{test_user.password}&scope=&client_id=&client_secret="
|
||||||
|
response = client.request("POST", "/users/tkn", headers=headers, data=data)
|
||||||
|
|
||||||
|
assert response.status_code == 401
|
||||||
|
post_request(response)
|
||||||
|
|
||||||
|
def test_create_iot_entity():
|
||||||
|
pass
|
40
sql_app/tools/emulate_door.py
Normal file
40
sql_app/tools/emulate_door.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# EE495
|
||||||
|
# Hesham T. Banafa
|
||||||
|
# Jun 11th, 2022
|
||||||
|
|
||||||
|
from time import sleep
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
def poll(poll_url: str, data: dict, headers: dict) -> dict:
|
||||||
|
res : requests.Response = \
|
||||||
|
requests.post(poll_url, json=data, headers=headers)
|
||||||
|
#print('sent ', data)
|
||||||
|
print(res.text, res, res.reason)
|
||||||
|
if res.status_code != 200: return None
|
||||||
|
return res.json()
|
||||||
|
|
||||||
|
def emulate(poll_url, token_in: str):
|
||||||
|
mac = "94:b9:7e:fb:57:1a"
|
||||||
|
polling_interval_secons = 1
|
||||||
|
polling_headers = {
|
||||||
|
'accept' : 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
stop = False
|
||||||
|
state = False
|
||||||
|
while (not stop):
|
||||||
|
sleep(polling_interval_secons)
|
||||||
|
data = {
|
||||||
|
'bluetooth_mac': mac,
|
||||||
|
'state': state,
|
||||||
|
'token': token_in
|
||||||
|
}
|
||||||
|
data_dict = poll(poll_url, data, polling_headers)
|
||||||
|
if not data_dict: continue
|
||||||
|
if data_dict['open_command']: state = True
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
emulate("https://ibs.cronos.typedef.cf:4040/iotdevice/door/status",
|
||||||
|
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJibHVldG9vdGhfbWFjIjoiOTQ6Yjk6N2U6ZmI6NTc6MWEifQ.oRbL0U70g8HGkKIOnwkesDiB40VWTPmwIWiysvP-hXA")
|
31
sql_app/tools/ibs.service
Normal file
31
sql_app/tools/ibs.service
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# This is templte to use for python venv applications
|
||||||
|
# from https://broplanner.com/wp-content/webpc-passthru.php?src=https://broplanner.com/wp-content/uploads/2022/01/Screenshot-2022-01-25-224223-1536x237.png&nocache=1
|
||||||
|
[Unit]
|
||||||
|
After = network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=ibs
|
||||||
|
Group=ibs
|
||||||
|
WorkingDirectory=/srv/ibs/ibs
|
||||||
|
ExecStart=/srv/ibs/ibs/run-tls
|
||||||
|
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=15
|
||||||
|
|
||||||
|
# Security
|
||||||
|
ReadWritePaths=/srv/ibs/ibs
|
||||||
|
PrivateDevices=yes
|
||||||
|
PrivateMounts=yes
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateUsers=yes
|
||||||
|
ProtectClock=yes
|
||||||
|
ProtectControlGroups=yes
|
||||||
|
ProtectHome=yes
|
||||||
|
ProtectKernelLogs=yes
|
||||||
|
ProtectKernelModules=yes
|
||||||
|
ProtectKernelTunables=yes
|
||||||
|
ProtectProc=yes
|
||||||
|
ProtectHostname=yes
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
16
sql_app/utils.py
Normal file
16
sql_app/utils.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# May 2022
|
||||||
|
# Hesham T. Banafa <hishaminv@gmail.com>
|
||||||
|
|
||||||
|
from .database import SessionLocal
|
||||||
|
|
||||||
|
def get_db():
|
||||||
|
db = SessionLocal()
|
||||||
|
try:
|
||||||
|
yield db
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
EMERG_TEMP = 50
|
||||||
|
EMERG_SMOKE = 1000
|
||||||
|
EMERG_OPEN_TIME_SEC = 500
|
||||||
|
|
Loading…
Reference in New Issue
Block a user