commit cbd239c6c463b12d81e19d33ee2a53bd68e64c40
Author: Matej Zeman <zeman339@gmail.com>
Date:   Mon May 9 17:48:57 2022 +0200

    Added signup and users table in database. Passwords are hashed. Added view for changing users roles.

diff --git a/server/requirements.txt b/server/requirements.txt
index e70f09c..7d8e232 100644
--- a/server/requirements.txt
+++ b/server/requirements.txt
@@ -5,4 +5,6 @@ uvicorn==0.17.6
 psycopg2-binary==2.8.6
 jinja2==3.1.1
 python-multipart==0.0.5
-fastapi-jwt-auth==0.5.0
\ No newline at end of file
+fastapi-jwt-auth==0.5.0
+passlib==1.7.4
+bcrypt==3.2.2
\ No newline at end of file
diff --git a/server/sql_app/api/auth.py b/server/sql_app/api/auth.py
index f01ef83..cf8aeba 100644
--- a/server/sql_app/api/auth.py
+++ b/server/sql_app/api/auth.py
@@ -3,15 +3,29 @@ from fastapi import Request
 from fastapi.responses import HTMLResponse, RedirectResponse
 from fastapi.templating import Jinja2Templates
 from fastapi_jwt_auth import AuthJWT
+from sqlalchemy.orm import Session
+from sql_app import crud
+from passlib.context import CryptContext
 from pydantic import BaseModel
+from ..database import SessionLocal, engine
 
 # Path to html templates used in this file
 templates = Jinja2Templates(directory="templates/auth")
 
+pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
+
 # prefix used for all endpoints in this file
 auth = APIRouter(prefix="")
 
 
+# Dependency
+def get_db():
+    db = SessionLocal()
+    try:
+        yield db
+    finally:
+        db.close()
+
 
 class Settings(BaseModel):
     authjwt_secret_key: str = "secret"
@@ -25,6 +39,7 @@ class Settings(BaseModel):
 def get_config():
     return Settings()
 
+
 # admin username and password
 fake_users_db = {
     "admin": {
@@ -34,6 +49,72 @@ fake_users_db = {
 }
 
 
+def verify_password(plain_password, hashed_password):
+    return pwd_context.verify(plain_password, hashed_password)
+
+
+def get_hash_password(password):
+    return pwd_context.hash(password)
+
+
+def auth_user(db, username: str, password: str):
+    user = crud.find_user(db, username)
+    if not user:
+        return None
+    if not verify_password(password, user.password):
+        return None
+    return user
+
+
+@auth.get("/signup", response_class=HTMLResponse)
+async def signup_get(request: Request):
+    """
+    return html template for signup
+    """
+    return templates.TemplateResponse("signup.html", {"request": request})
+
+
+@auth.post("/signup", response_class=HTMLResponse)
+async def signup(username: str = Form(...), password: str = Form(...), db: Session = Depends(get_db)):
+    """
+    Endpoint called form signup template. Creates new user with role guest that can be changed by admin user
+    """
+    users = crud.get_users(db, 0, 100)
+    users_names = []
+    for u in users:
+        users_names.append(u.username)
+    if username not in users_names:
+        new_user = crud.create_user(db, username, get_hash_password(password), "guest")
+        if new_user is None:
+            print("something went wrong")
+        return """
+            <html>
+                <head>
+                    <title>Signup</title>
+                </head>
+                <body>
+                    <h1>Signed in</h1>
+                    <form action="/logs-web" method="get">
+                        <input type="submit" value="Back" />
+                    </form>
+                </body>
+            </html>
+            """
+    else:
+        return """
+                    <html>
+                        <head>
+                            <title>Signup</title>
+                        </head>
+                        <body>
+                            <h1>Username taken</h1>
+                            <form action="/logs-web" method="get">
+                                <input type="submit" value="Back" />
+                            </form>
+                        </body>
+                    </html>
+                    """
+
 @auth.get("/login", response_class=HTMLResponse)
 async def login_get(request: Request):
     """
@@ -43,22 +124,40 @@ async def login_get(request: Request):
 
 
 @auth.post("/login", response_class=HTMLResponse)
-async def login(username: str = Form(...), password: str = Form(...), Authorize: AuthJWT = Depends()):
+async def login(username: str = Form(...), password: str = Form(...), db: Session = Depends(get_db),
+                Authorize: AuthJWT = Depends()):
     """
     Endpoint called from login template. Checks if given username and password aligns with admin
     username and password and returns token for browser according to given username and password
     """
-    user_dict = fake_users_db.get(username)
-    if user_dict != None:
-        if user_dict["username"] == username and user_dict["password"] == password:
+    user = auth_user(db, username, password)
+    if user != None:
+        if user.role == "admin":
             access_token = Authorize.create_access_token(subject="admin", expires_time=False)
             refresh_token = Authorize.create_refresh_token(subject="admin", expires_time=False)
         else:
-            access_token = Authorize.create_access_token(subject="host", expires_time=False)
-            refresh_token = Authorize.create_refresh_token(subject="host", expires_time=False)
+            access_token = Authorize.create_access_token(subject="guest", expires_time=False)
+            refresh_token = Authorize.create_refresh_token(subject="guest", expires_time=False)
     else:
-        access_token = Authorize.create_access_token(subject="host", expires_time=False)
-        refresh_token = Authorize.create_refresh_token(subject="host", expires_time=False)
+        usr = fake_users_db.get(username)
+        if usr != None:
+            if usr["username"] == username and usr["password"] == password:
+                access_token = Authorize.create_access_token(subject="admin", expires_time=False)
+                refresh_token = Authorize.create_refresh_token(subject="admin", expires_time=False)
+        else:
+            return """
+                <html>
+                    <head>
+                        <title>Login</title>
+                    </head>
+                    <body>
+                        <h1>Wrong Username or Password</h1>
+                        <form action="/login" method="get">
+                            <input type="submit" value="Back" />
+                        </form>
+                    </body>
+                </html>
+                """
 
     # Set the JWT cookies in the response
     Authorize.set_access_cookies(access_token)
@@ -112,4 +211,4 @@ def logout(Authorize: AuthJWT = Depends()):
                 </form>
             </body>
         </html>
-        """
\ No newline at end of file
+        """
diff --git a/server/sql_app/api/ld_logs_web.py b/server/sql_app/api/ld_logs_web.py
index fbebfec..aef3733 100644
--- a/server/sql_app/api/ld_logs_web.py
+++ b/server/sql_app/api/ld_logs_web.py
@@ -44,10 +44,14 @@ async def read_logs(request: Request, skip: int = 0, limit: int = 100, db: Sessi
     pc_obj = crud.find_pcs(db, pcs)
     teams = crud.get_teams(db, skip=skip, limit=limit)
     licenses = crud.get_licenses(db, skip=skip, limit=limit)
-    if current_user != "admin":
+    if current_user == "admin":
+        return templates.TemplateResponse("ldlogs.html", {"request": request, "logs": logs, "pcs": pc_obj, "teams": teams,
+                                                          "licenses": licenses, "user": current_user})
+    else:
         current_user = "guest"
-    return templates.TemplateResponse("ldlogs.html", {"request": request, "logs": logs, "pcs": pc_obj, "teams": teams,
-                                                      "licenses": licenses, "user": current_user})
+        return templates.TemplateResponse("ldlogs_normal.html",
+                                          {"request": request, "logs": logs, "pcs": pc_obj, "teams": teams,
+                                           "licenses": licenses, "user": current_user})
 
 
 @ldlogs_web.post("/ldlogs-web", response_class=HTMLResponse)
@@ -67,7 +71,11 @@ async def filter_logs(request: Request, pc: str = Form("all"), team: str = Form(
     pc_obj = crud.get_pcs(db, skip=skip, limit=limit)
     teams = crud.get_teams(db, skip=skip, limit=limit)
     licenses = crud.get_licenses(db, skip=skip, limit=limit)
-    if current_user != "admin":
+    if current_user == "admin":
+        return templates.TemplateResponse("ldlogs.html", {"request": request, "logs": logs, "pcs": pc_obj, "teams": teams,
+                                                          "licenses": licenses, "user": current_user})
+    else:
         current_user = "guest"
-    return templates.TemplateResponse("ldlogs.html", {"request": request, "logs": logs, "pcs": pc_obj, "teams": teams,
-                                                      "licenses": licenses, "user": current_user})
+        return templates.TemplateResponse("ldlogs_normal.html",
+                                          {"request": request, "logs": logs, "pcs": pc_obj, "teams": teams,
+                                           "licenses": licenses, "user": current_user})
diff --git a/server/sql_app/api/usb_logs_web.py b/server/sql_app/api/usb_logs_web.py
index a4f57d0..75ebdc6 100644
--- a/server/sql_app/api/usb_logs_web.py
+++ b/server/sql_app/api/usb_logs_web.py
@@ -44,10 +44,13 @@ async def read_logs(request: Request, skip: int = 0, limit: int = 100, db: Sessi
     pc_obj = crud.find_pcs(db, pcs)
     teams = crud.get_teams(db, skip=skip, limit=limit)
     licenses = crud.get_licenses(db, skip=skip, limit=limit)
-    if current_user != "admin":
+    if current_user == "admin":
+        return templates.TemplateResponse("logs.html", {"request": request, "logs": logs, "pcs": pc_obj, "teams": teams,
+                                                        "licenses": licenses, "user": current_user})
+    else:
         current_user = "guest"
-    return templates.TemplateResponse("logs.html", {"request": request, "logs": logs, "pcs": pc_obj, "teams": teams,
-                                                    "licenses": licenses, "user": current_user})
+        return templates.TemplateResponse("logs_normal.html", {"request": request, "logs": logs, "pcs": pc_obj, "teams": teams,
+                                                        "licenses": licenses, "user": current_user})
 
 
 @usblogs_web.post("/logs-web", response_class=HTMLResponse)
@@ -67,10 +70,13 @@ async def filter_logs(request: Request, pc: str = Form("all"), team: str = Form(
     pc_obj = crud.get_pcs(db, skip=skip, limit=limit)
     teams = crud.get_teams(db, skip=skip, limit=limit)
     licenses = crud.get_licenses(db, skip=skip, limit=limit)
-    if current_user != "admin":
+    if current_user == "admin":
+        return templates.TemplateResponse("logs.html", {"request": request, "logs": logs, "pcs": pc_obj, "teams": teams,
+                                                        "licenses": licenses, "user": current_user})
+    else:
         current_user = "guest"
-    return templates.TemplateResponse("logs.html", {"request": request, "logs": logs, "pcs": pc_obj, "teams": teams,
-                                                    "licenses": licenses, "user": current_user})
+        return templates.TemplateResponse("logs_normal.html", {"request": request, "logs": logs, "pcs": pc_obj, "teams": teams,
+                                                        "licenses": licenses, "user": current_user})
 
 
 @usblogs_web.get("/", response_class=HTMLResponse)
diff --git a/server/sql_app/api/users_web.py b/server/sql_app/api/users_web.py
new file mode 100644
index 0000000..523b22f
--- /dev/null
+++ b/server/sql_app/api/users_web.py
@@ -0,0 +1,59 @@
+from typing import List
+from fastapi import Depends, FastAPI, HTTPException, APIRouter, Form
+from sqlalchemy.orm import Session
+from sql_app import crud, models, schemas
+from ..database import SessionLocal, engine
+from fastapi import FastAPI, Request
+from fastapi.responses import HTMLResponse, RedirectResponse
+from fastapi_jwt_auth import AuthJWT
+from fastapi.staticfiles import StaticFiles
+from fastapi.templating import Jinja2Templates
+
+models.Base.metadata.create_all(bind=engine)
+
+# Path to html templates used in this file
+templates = Jinja2Templates(directory="templates/users")
+
+# prefix used for all endpoints in this file
+users = APIRouter(prefix="")
+
+
+# Dependency
+def get_db():
+    db = SessionLocal()
+    try:
+        yield db
+    finally:
+        db.close()
+
+
+@users.get("/users-web", response_class=HTMLResponse)
+async def read_usrs(request: Request, skip: int = 0, limit: int = 100, db: Session = Depends(get_db),
+                   Authorize: AuthJWT = Depends()):
+    """
+    Returns template with all users currently saved in database
+    """
+    Authorize.jwt_optional()
+    current_user = Authorize.get_jwt_subject()
+    users = crud.get_users(db, skip, limit)
+    if current_user == "admin":
+        return templates.TemplateResponse("users.html", {"request": request, "users": users})
+    else:
+        return RedirectResponse(url=f"/logs-web", status_code=303)
+
+
+@users.get("/user-role/{usr_id}", response_class=HTMLResponse)
+async def connect_pc_team(usr_id: int, db: Session = Depends(get_db), Authorize: AuthJWT = Depends()):
+    """
+    Changes role of user to either guest or admin depending on old role.
+    """
+    Authorize.jwt_optional()
+    current_user = Authorize.get_jwt_subject()
+    if current_user != "admin":
+        return RedirectResponse(url=f"/logs-web", status_code=303)
+    user = crud.find_user_byid(db, usr_id)
+    if user.role == "admin":
+        crud.change_role(db, usr_id, "guest")
+    else:
+        crud.change_role(db, usr_id, "admin")
+    return RedirectResponse(url=f"/users-web", status_code=303)
\ No newline at end of file
diff --git a/server/sql_app/crud.py b/server/sql_app/crud.py
index cc20541..f2b3a9b 100644
--- a/server/sql_app/crud.py
+++ b/server/sql_app/crud.py
@@ -99,7 +99,7 @@ def get_bodydevicelicense_by_bodydevicelicense(db: Session, device_id: int, lice
     returns entry in bodydevices_licenses table with given body device id and license id
     """
     return db.query(models.BodyDeviceLicense).filter(and_(models.BodyDeviceLicense.bodydevice_id == device_id,
-                                                      models.BodyDeviceLicense.license_id == license_id)).first()
+                                                          models.BodyDeviceLicense.license_id == license_id)).first()
 
 
 def get_license_bodydevice(db: Session, license_id: int):
@@ -188,6 +188,18 @@ def update_pc(db: Session, pc_id: int, team: str):
     db.refresh(old_pc)
     return old_pc
 
+def change_role(db: Session, usr_id: int, role: str):
+    """
+    Updates team of one specific pc
+    """
+    old_usr = find_user_byid(db, usr_id)
+    new = {'id': old_usr.id, 'username': old_usr.username, 'password': old_usr.password, 'role': role}
+    for key, value in new.items():
+        setattr(old_usr, key, value)
+    db.commit()
+    db.refresh(old_usr)
+    return old_usr
+
 
 def get_pcs(db: Session, skip: int = 0, limit: int = 100):
     """
@@ -482,3 +494,35 @@ def create_device_logs(db: Session, item: schemas.USBTempBase, dev_id: int, pc_i
     db.commit()
     db.refresh(db_log)
     return db_log
+
+
+def get_users(db: Session, skip: int = 0, limit: int = 100):
+    """
+    Returns all users saved in database
+    """
+    return db.query(models.User).offset(skip).limit(limit).all()
+
+
+def find_user(db: Session, name: str):
+    """
+    Finds one user by given username
+    """
+    return db.query(models.User).filter(models.User.username == name).first()
+
+
+def find_user_byid(db: Session, id: int):
+    """
+    Finds one user by given id
+    """
+    return db.query(models.User).filter(models.User.id == id).first()
+
+
+def create_user(db: Session, name: str, passw: str, rol: str):
+    """
+    Creates new user
+    """
+    db_user = models.User(username=name, password=passw, role=rol)
+    db.add(db_user)
+    db.commit()
+    db.refresh(db_user)
+    return db_user
diff --git a/server/sql_app/main.py b/server/sql_app/main.py
index 99026c6..224d136 100644
--- a/server/sql_app/main.py
+++ b/server/sql_app/main.py
@@ -12,6 +12,7 @@ from sql_app.api.teams_web import teams_web
 from sql_app.api.auth import auth
 from sql_app.api.ld_logs_web import ldlogs_web
 from sql_app.api.bodydevices_web import body_device_web
+from sql_app.api.users_web import users
 from fastapi import FastAPI
 
 
@@ -32,6 +33,7 @@ app.include_router(teams_web)
 app.include_router(usblogs_web)
 app.include_router(ldlogs_web)
 app.include_router(body_device_web)
+app.include_router(users)
 app.include_router(auth)
 
 '''
diff --git a/server/sql_app/models.py b/server/sql_app/models.py
index 8d62fe9..d91cfa5 100644
--- a/server/sql_app/models.py
+++ b/server/sql_app/models.py
@@ -165,3 +165,14 @@ class LDLog(Base):
     ldpc = relationship("PC", back_populates="ld_pc")
     head_device = relationship("HeadDevice", back_populates="h_logs")
     body_device = relationship("BodyDevice", back_populates="b_logs")
+
+class User(Base):
+    """
+    Class defining user in database with its own role
+    """
+    __tablename__ = "users"
+
+    id = Column(Integer, primary_key=True, index=True)
+    username = Column(String, index=True, nullable=False)
+    password = Column(String, index=True, nullable=False)
+    role = Column(String, index=True, nullable=False)
diff --git a/server/sql_app/schemas.py b/server/sql_app/schemas.py
index c0fe099..79becdc 100644
--- a/server/sql_app/schemas.py
+++ b/server/sql_app/schemas.py
@@ -232,3 +232,22 @@ class LDTemp(LDTempCreate):
 
     class Config:
         orm_mode = True
+
+
+class UserBase(BaseModel):
+    """
+    Classes used for creating new User entry
+    """
+    username: str
+    password: str
+    role: str
+
+class UserCreate(UserBase):
+    pass
+
+
+class User(UserCreate):
+    id: int
+
+    class Config:
+        orm_mode = True
diff --git a/server/templates/auth/login.html b/server/templates/auth/login.html
index 0def994..fa536c5 100644
--- a/server/templates/auth/login.html
+++ b/server/templates/auth/login.html
@@ -8,9 +8,9 @@
 <form action="/login" method="post">
   <label for="username">Username:</label><br>
   <input type="text" id="username" name="username"><br><br>
-    <label for="password">Password</label>
+    <label for="password">Password:</label>
   <input type="password" id="password" name="password">
-  <input type="submit" value="Submit">
+  <input type="submit" value="LogIn">
 </form>
 </body>
 </html>
\ No newline at end of file
diff --git a/server/templates/auth/signup.html b/server/templates/auth/signup.html
new file mode 100644
index 0000000..b8b19ff
--- /dev/null
+++ b/server/templates/auth/signup.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Sign Up</title>
+</head>
+<body>
+<form action="/signup" method="post">
+  <label for="username">Username:</label><br>
+  <input type="text" id="username" name="username"><br><br>
+    <label for="password">Password:</label>
+  <input type="password" id="password" name="password">
+  <input type="submit" value="Signup">
+</form>
+</body>
+</html>
\ No newline at end of file
diff --git a/server/templates/body-devices/body_devices.html b/server/templates/body-devices/body_devices.html
index 1116968..251afd4 100644
--- a/server/templates/body-devices/body_devices.html
+++ b/server/templates/body-devices/body_devices.html
@@ -15,6 +15,7 @@
       <option value="/teams-web">Teams</option>
       <option value="/pcs-web">PCs</option>
       <option value="/licenses-web">Licenses</option>
+      <option value="/users-web">Users</option>
   </select>
   <input type="submit" value="OK">
 </form>
@@ -25,6 +26,11 @@
 </form>
 </div>
 <div style='float:left'>
+<form action="/signup" method="get">
+    <input type="submit" value="Sign Up" />
+</form>
+</div>
+<div style='float:left'>
 <form action="/logout" method="get">
     <input type="submit" value="Logout" />
 </form>
diff --git a/server/templates/body-devices/body_devices_normal.html b/server/templates/body-devices/body_devices_normal.html
index d0ce81b..84db09c 100644
--- a/server/templates/body-devices/body_devices_normal.html
+++ b/server/templates/body-devices/body_devices_normal.html
@@ -25,6 +25,11 @@
 </form>
 </div>
 <div style='float:left'>
+<form action="/signup" method="get">
+    <input type="submit" value="Sign Up" />
+</form>
+</div>
+<div style='float:left'>
 <form action="/logout" method="get">
     <input type="submit" value="Logout" />
 </form>
diff --git a/server/templates/devices/devices.html b/server/templates/devices/devices.html
index 3685a70..7457c96 100644
--- a/server/templates/devices/devices.html
+++ b/server/templates/devices/devices.html
@@ -15,6 +15,7 @@
       <option value="/teams-web">Teams</option>
       <option value="/pcs-web">PCs</option>
       <option value="/licenses-web">Licenses</option>
+      <option value="/users-web">Users</option>
   </select>
   <input type="submit" value="OK">
 </form>
@@ -25,6 +26,11 @@
 </form>
 </div>
 <div style='float:left'>
+<form action="/signup" method="get">
+    <input type="submit" value="Sign Up" />
+</form>
+</div>
+<div style='float:left'>
 <form action="/logout" method="get">
     <input type="submit" value="Logout" />
 </form>
diff --git a/server/templates/devices/devices_normal.html b/server/templates/devices/devices_normal.html
index 7b5d898..fe35d04 100644
--- a/server/templates/devices/devices_normal.html
+++ b/server/templates/devices/devices_normal.html
@@ -25,6 +25,11 @@
 </form>
 </div>
 <div style='float:left'>
+<form action="/signup" method="get">
+    <input type="submit" value="Sign Up" />
+</form>
+</div>
+<div style='float:left'>
 <form action="/logout" method="get">
     <input type="submit" value="Logout" />
 </form>
diff --git a/server/templates/ld-logs/ldlogs.html b/server/templates/ld-logs/ldlogs.html
index a936ff4..d2793e1 100644
--- a/server/templates/ld-logs/ldlogs.html
+++ b/server/templates/ld-logs/ldlogs.html
@@ -15,6 +15,7 @@
       <option value="/teams-web">Teams</option>
       <option value="/pcs-web">PCs</option>
       <option value="/licenses-web">Licenses</option>
+      <option value="/users-web">Users</option>
   </select>
   <input type="submit" value="OK">
 </form>
@@ -25,6 +26,11 @@
 </form>
 </div>
 <div style='float:left'>
+<form action="/signup" method="get">
+    <input type="submit" value="Sign Up" />
+</form>
+</div>
+<div style='float:left'>
 <form action="/logout" method="get">
     <input type="submit" value="Logout" />
 </form>
diff --git a/server/templates/ld-logs/ldlogs_normal.html b/server/templates/ld-logs/ldlogs_normal.html
new file mode 100644
index 0000000..435b9f6
--- /dev/null
+++ b/server/templates/ld-logs/ldlogs_normal.html
@@ -0,0 +1,91 @@
+<html>
+<head>
+    <title> LD Logs Details</title>
+</head>
+<body>
+<div style='float:left'>
+<form action="" method="get">
+  <label for="view">Choose view:</label>
+  <select id="view" name="view" onchange="this.form.action=this.value;">
+      <option value=""></option>
+      <option value="/logs-web">Logs</option>
+      <option value="/ldlogs-web">LD Logs</option>
+      <option value="/devices-web">Devices</option>
+      <option value="/body-devices-web">Body Devices</option>
+      <option value="/teams-web">Teams</option>
+      <option value="/pcs-web">PCs</option>
+      <option value="/licenses-web">Licenses</option>
+  </select>
+  <input type="submit" value="OK">
+</form>
+</div>
+<div style='float:left'>
+<form action="/login" method="get">
+    <input type="submit" value="Login" />
+</form>
+</div>
+<div style='float:left'>
+<form action="/signup" method="get">
+    <input type="submit" value="Sign Up" />
+</form>
+</div>
+<div style='float:left'>
+<form action="/logout" method="get">
+    <input type="submit" value="Logout" />
+</form>
+</div>
+<h4>{{user}}</h4>
+<form action="/ldlogs-web" method="post">
+  <label for="pc">PC:</label>
+  <input id="pc" name="pc" type="text" list="pcs" value="" placeholder="all">
+    <datalist id="pcs">
+        {% for pc in pcs %}
+        <option value="{{pc.username}}"></option>
+        {% endfor %}
+    </datalist>
+    <label for="team">Team:</label>
+  <input id="team" name="team" type="text" list="teams" value="" placeholder="all">
+    <datalist id="teams">
+        {% for team in teams %}
+        <option value="{{team.name}}"></option>
+        {% endfor %}
+    </datalist>
+    <label for="lic">License:</label>
+    <input id="lic" name="lic" type="text" list="licenses" value="" placeholder="all">
+    <datalist id="licenses">
+        {% for license in licenses %}
+        <option value="{{license.name}}"></option>
+        {% endfor %}
+    </datalist>
+  <input type="submit" value="Filter">
+</form>
+    <table>
+    <TR>
+        <TH>ID</TH>
+        <TH>PC Username</TH>
+        <TH>PC Hostname</TH>
+        <TH>Team</TH>
+        <TH>Timestamp</TH>
+        <TH>Status</TH>
+        <TH>Head Device Serial Number</TH>
+        <TH>Body Device Serial Number</TH>
+    </TR>
+    {% for log in logs %}
+    <TR>
+        <TD class="ID">{{log.id}}</TD>
+        <TD class="Username">{{log.ldpc.username}}</TD>
+        <TD class="Hostname">{{log.ldpc.hostname}}</TD>
+        {% if log.ldpc.team == None %}
+            <TD class="Team">NONE</TD>
+        {% else %}
+            <TD class="Team">{{log.ldpc.team.name}}</TD>
+        {% endif %}
+        <TD class="Timestamp">{{log.timestamp}}</TD>
+        <TD class="Status">{{log.status}}</TD>
+        <TD class="HeadDeviceSerialNumber">{{log.head_device.serial_number}}</TD>
+        <TD class="BodyDeviceSerialNumber">{{log.body_device.serial_number}}</TD>
+    </TR>
+    {% endfor %}
+</table>
+</body>
+</html>
\ No newline at end of file
diff --git a/server/templates/licenses/licenses.html b/server/templates/licenses/licenses.html
index e66abfe..9b2471d 100644
--- a/server/templates/licenses/licenses.html
+++ b/server/templates/licenses/licenses.html
@@ -15,6 +15,7 @@
       <option value="/teams-web">Teams</option>
       <option value="/pcs-web">PCs</option>
       <option value="/licenses-web">Licenses</option>
+      <option value="/users-web">Users</option>
   </select>
   <input type="submit" value="OK">
 </form>
@@ -25,6 +26,11 @@
 </form>
 </div>
 <div style='float:left'>
+<form action="/signup" method="get">
+    <input type="submit" value="Sign Up" />
+</form>
+</div>
+<div style='float:left'>
 <form action="/logout" method="get">
     <input type="submit" value="Logout" />
 </form>
diff --git a/server/templates/licenses/licenses_normal.html b/server/templates/licenses/licenses_normal.html
index 7b5b644..7b672a1 100644
--- a/server/templates/licenses/licenses_normal.html
+++ b/server/templates/licenses/licenses_normal.html
@@ -25,6 +25,11 @@
 </form>
 </div>
 <div style='float:left'>
+<form action="/signup" method="get">
+    <input type="submit" value="Sign Up" />
+</form>
+</div>
+<div style='float:left'>
 <form action="/logout" method="get">
     <input type="submit" value="Logout" />
 </form>
diff --git a/server/templates/pcs/pcs.html b/server/templates/pcs/pcs.html
index 79f3156..f8897b7 100644
--- a/server/templates/pcs/pcs.html
+++ b/server/templates/pcs/pcs.html
@@ -15,6 +15,7 @@
       <option value="/teams-web">Teams</option>
       <option value="/pcs-web">PCs</option>
       <option value="/licenses-web">Licenses</option>
+      <option value="/users-web">Users</option>
   </select>
   <input type="submit" value="OK">
 </form>
@@ -25,6 +26,11 @@
 </form>
 </div>
 <div style='float:left'>
+<form action="/signup" method="get">
+    <input type="submit" value="Sign Up" />
+</form>
+</div>
+<div style='float:left'>
 <form action="/logout" method="get">
     <input type="submit" value="Logout" />
 </form>
diff --git a/server/templates/pcs/pcs_normal.html b/server/templates/pcs/pcs_normal.html
index 52d9085..3925ad0 100644
--- a/server/templates/pcs/pcs_normal.html
+++ b/server/templates/pcs/pcs_normal.html
@@ -25,6 +25,11 @@
 </form>
 </div>
 <div style='float:left'>
+<form action="/signup" method="get">
+    <input type="submit" value="Sign Up" />
+</form>
+</div>
+<div style='float:left'>
 <form action="/logout" method="get">
     <input type="submit" value="Logout" />
 </form>
diff --git a/server/templates/teams/teams.html b/server/templates/teams/teams.html
index 546666b..6dc7168 100644
--- a/server/templates/teams/teams.html
+++ b/server/templates/teams/teams.html
@@ -15,6 +15,7 @@
       <option value="/teams-web">Teams</option>
       <option value="/pcs-web">PCs</option>
       <option value="/licenses-web">Licenses</option>
+      <option value="/users-web">Users</option>
   </select>
   <input type="submit" value="OK">
 </form>
@@ -25,6 +26,11 @@
 </form>
 </div>
 <div style='float:left'>
+<form action="/signup" method="get">
+    <input type="submit" value="Sign Up" />
+</form>
+</div>
+<div style='float:left'>
 <form action="/logout" method="get">
     <input type="submit" value="Logout" />
 </form>
diff --git a/server/templates/teams/teams_normal.html b/server/templates/teams/teams_normal.html
index 50a7883..6e21020 100644
--- a/server/templates/teams/teams_normal.html
+++ b/server/templates/teams/teams_normal.html
@@ -25,6 +25,11 @@
 </form>
 </div>
 <div style='float:left'>
+<form action="/signup" method="get">
+    <input type="submit" value="Sign Up" />
+</form>
+</div>
+<div style='float:left'>
 <form action="/logout" method="get">
     <input type="submit" value="Logout" />
 </form>
diff --git a/server/templates/usb-logs/logs.html b/server/templates/usb-logs/logs.html
index e1d0a17..c69de25 100644
--- a/server/templates/usb-logs/logs.html
+++ b/server/templates/usb-logs/logs.html
@@ -15,6 +15,7 @@
       <option value="/teams-web">Teams</option>
       <option value="/pcs-web">PCs</option>
       <option value="/licenses-web">Licenses</option>
+      <option value="/users-web">Users</option>
   </select>
   <input type="submit" value="OK">
 </form>
@@ -25,6 +26,11 @@
 </form>
 </div>
 <div style='float:left'>
+<form action="/signup" method="get">
+    <input type="submit" value="Sign Up" />
+</form>
+</div>
+<div style='float:left'>
 <form action="/logout" method="get">
     <input type="submit" value="Logout" />
 </form>
diff --git a/server/templates/usb-logs/logs_normal.html b/server/templates/usb-logs/logs_normal.html
new file mode 100644
index 0000000..1a7bf53
--- /dev/null
+++ b/server/templates/usb-logs/logs_normal.html
@@ -0,0 +1,91 @@
+<html>
+<head>
+    <title>Logs Details</title>
+</head>
+<body>
+<div style='float:left'>
+<form action="" method="get">
+  <label for="view">Choose view:</label>
+  <select id="view" name="view" onchange="this.form.action=this.value;">
+      <option value=""></option>
+      <option value="/logs-web">Logs</option>
+      <option value="/ldlogs-web">LD Logs</option>
+      <option value="/devices-web">Devices</option>
+      <option value="/body-devices-web">Body Devices</option>
+      <option value="/teams-web">Teams</option>
+      <option value="/pcs-web">PCs</option>
+      <option value="/licenses-web">Licenses</option>
+  </select>
+  <input type="submit" value="OK">
+</form>
+</div>
+<div style='float:left'>
+<form action="/login" method="get">
+    <input type="submit" value="Login" />
+</form>
+</div>
+<div style='float:left'>
+<form action="/signup" method="get">
+    <input type="submit" value="Sign Up" />
+</form>
+</div>
+<div style='float:left'>
+<form action="/logout" method="get">
+    <input type="submit" value="Logout" />
+</form>
+</div>
+<h4>{{user}}</h4>
+<form action="/logs-web" method="post">
+  <label for="pc">PC:</label>
+  <input id="pc" name="pc" type="text" list="pcs" value="" placeholder="all">
+    <datalist id="pcs">
+        {% for pc in pcs %}
+        <option value="{{pc.username}}"></option>
+        {% endfor %}
+    </datalist>
+    <label for="team">Team:</label>
+  <input id="team" name="team" type="text" list="teams" value="" placeholder="all">
+    <datalist id="teams">
+        {% for team in teams %}
+        <option value="{{team.name}}"></option>
+        {% endfor %}
+    </datalist>
+    <label for="lic">License:</label>
+    <input id="lic" name="lic" type="text" list="licenses" value="" placeholder="all">
+    <datalist id="licenses">
+        {% for license in licenses %}
+        <option value="{{license.name}}"></option>
+        {% endfor %}
+    </datalist>
+  <input type="submit" value="Filter">
+</form>
+    <table>
+    <TR>
+        <TH>ID</TH>
+        <TH>PC Username</TH>
+        <TH>PC Hostname</TH>
+        <TH>Team</TH>
+        <TH>Timestamp</TH>
+        <TH>Status</TH>
+        <TH>Device Product ID</TH>
+        <TH>Device Serial Number</TH>
+    </TR>
+    {% for log in logs %}
+    <TR>
+        <TD class="ID">{{log.id}}</TD>
+        <TD class="Username">{{log.pc.username}}</TD>
+        <TD class="Hostname">{{log.pc.hostname}}</TD>
+        {% if log.pc.team == None %}
+            <TD class="Team">NONE</TD>
+        {% else %}
+            <TD class="Team">{{log.pc.team.name}}</TD>
+        {% endif %}
+        <TD class="Timestamp">{{log.timestamp}}</TD>
+        <TD class="Status">{{log.status}}</TD>
+        <TD class="DeviceProductID">{{log.device.product_id}}</TD>
+        <TD class="DeviceSerialNumber">{{log.device.serial_number}}</TD>
+    </TR>
+    {% endfor %}
+</table>
+</body>
+</html>
\ No newline at end of file
diff --git a/server/templates/users/users.html b/server/templates/users/users.html
new file mode 100644
index 0000000..904942e
--- /dev/null
+++ b/server/templates/users/users.html
@@ -0,0 +1,50 @@
+<html>
+<head>
+    <title>Users Details</title>
+</head>
+<body>
+<div style='float:left'>
+<form action="" method="get">
+  <label for="view">Choose view:</label>
+  <select id="view" name="view" onchange="this.form.action=this.value;">
+      <option value=""></option>
+      <option value="/logs-web">Logs</option>
+      <option value="/ldlogs-web">LD Logs</option>
+      <option value="/devices-web">Devices</option>
+      <option value="/body-devices-web">Body Devices</option>
+      <option value="/teams-web">Teams</option>
+      <option value="/pcs-web">PCs</option>
+      <option value="/licenses-web">Licenses</option>
+  </select>
+  <input type="submit" value="OK">
+</form>
+</div>
+<div style='float:left'>
+<form action="/login" method="get">
+    <input type="submit" value="Login" />
+</form>
+</div>
+<div style='float:left'>
+<form action="/signup" method="get">
+    <input type="submit" value="Sign Up" />
+</form>
+</div>
+<form action="/logout" method="get">
+    <input type="submit" value="Logout" />
+</form>
+<table>
+    <TR>
+        <TH>ID</TH>
+        <TH>Username</TH>
+        <TH>Role</TH>
+    </TR>
+    {% for user in users %}
+    <TR>
+        <TD class="ID"><a href="/user-role/{{user.id}}">{{user.id}}</a></TD>
+        <TD class="Username">{{user.username}}</TD>
+        <TD class="Role">{{user.role}}</TD>
+    </TR>
+    {% endfor %}
+</table>
+</body>
+</html>
\ No newline at end of file
