Revize 2fe004b1
Přidáno uživatelem Matěj Zeman před více než 2 roky(ů)
server/requirements.txt | ||
---|---|---|
5 | 5 |
psycopg2-binary==2.8.6 |
6 | 6 |
jinja2==3.1.1 |
7 | 7 |
python-multipart==0.0.5 |
8 |
fastapi-jwt-auth=0.5.0 |
|
8 |
fastapi-jwt-auth==0.5.0 |
server/sql_app/api/auth.py | ||
---|---|---|
1 |
|
|
2 |
|
|
3 |
from fastapi import Depends, APIRouter, Form |
|
4 |
from fastapi import Request |
|
5 |
from fastapi.responses import HTMLResponse |
|
6 |
from fastapi.templating import Jinja2Templates |
|
7 |
from fastapi.responses import HTMLResponse |
|
8 |
from fastapi_jwt_auth import AuthJWT |
|
9 |
from pydantic import BaseModel |
|
10 |
|
|
11 |
|
|
12 |
# Path to html templates used in this file |
|
13 |
templates = Jinja2Templates(directory="templates/auth") |
|
14 |
|
|
15 |
# prefix used for all endpoints in this file |
|
16 |
auth = APIRouter(prefix="") |
|
17 |
|
|
18 |
|
|
19 |
|
|
20 |
class Settings(BaseModel): |
|
21 |
authjwt_secret_key: str = "secret" |
|
22 |
# Configure application to store and get JWT from cookies |
|
23 |
authjwt_token_location: set = {"cookies"} |
|
24 |
# Disable CSRF Protection for this example. default is True |
|
25 |
authjwt_cookie_csrf_protect: bool = False |
|
26 |
|
|
27 |
|
|
28 |
@AuthJWT.load_config |
|
29 |
def get_config(): |
|
30 |
return Settings() |
|
31 |
|
|
32 |
|
|
33 |
fake_users_db = { |
|
34 |
"admin": { |
|
35 |
"username": "admin", |
|
36 |
"password": "admin" |
|
37 |
} |
|
38 |
} |
|
39 |
|
|
40 |
|
|
41 |
@auth.get("/login", response_class=HTMLResponse) |
|
42 |
async def login_get(request: Request): |
|
43 |
return templates.TemplateResponse("login.html", {"request": request}) |
|
44 |
|
|
45 |
|
|
46 |
@auth.post("/login", response_class=HTMLResponse) |
|
47 |
async def login(username: str = Form(...), password: str = Form(...), Authorize: AuthJWT = Depends()): |
|
48 |
user_dict = fake_users_db.get(username) |
|
49 |
|
|
50 |
if user_dict != None: |
|
51 |
if user_dict["username"] == username and user_dict["password"] == password: |
|
52 |
access_token = Authorize.create_access_token(subject="admin", expires_time=False) |
|
53 |
refresh_token = Authorize.create_refresh_token(subject="admin", expires_time=False) |
|
54 |
else: |
|
55 |
access_token = Authorize.create_access_token(subject="host", expires_time=False) |
|
56 |
refresh_token = Authorize.create_refresh_token(subject="host", expires_time=False) |
|
57 |
else: |
|
58 |
access_token = Authorize.create_access_token(subject="host", expires_time=False) |
|
59 |
refresh_token = Authorize.create_refresh_token(subject="host", expires_time=False) |
|
60 |
|
|
61 |
# Set the JWT cookies in the response |
|
62 |
Authorize.set_access_cookies(access_token) |
|
63 |
Authorize.set_refresh_cookies(refresh_token) |
|
64 |
return """ |
|
65 |
<html> |
|
66 |
<head> |
|
67 |
<title>Login</title> |
|
68 |
</head> |
|
69 |
<body> |
|
70 |
<h1>Logged in</h1> |
|
71 |
<form action="/logs-web" method="get"> |
|
72 |
<input type="submit" value="Back" /> |
|
73 |
</form> |
|
74 |
</body> |
|
75 |
</html> |
|
76 |
""" |
|
77 |
|
|
78 |
|
|
79 |
@auth.post('/refresh') |
|
80 |
def refresh(Authorize: AuthJWT = Depends()): |
|
81 |
Authorize.jwt_refresh_token_required() |
|
82 |
|
|
83 |
current_user = Authorize.get_jwt_subject() |
|
84 |
new_access_token = Authorize.create_access_token(subject=current_user) |
|
85 |
# Set the JWT cookies in the response |
|
86 |
Authorize.set_access_cookies(new_access_token) |
|
87 |
return {"msg": "The token has been refresh"} |
|
88 |
|
|
89 |
|
|
90 |
@auth.get('/logout', response_class=HTMLResponse) |
|
91 |
def logout(Authorize: AuthJWT = Depends()): |
|
92 |
""" |
|
93 |
Because the JWT are stored in an httponly cookie now, we cannot |
|
94 |
log the user out by simply deleting the cookies in the frontend. |
|
95 |
We need the backend to send us a response to delete the cookies. |
|
96 |
""" |
|
97 |
Authorize.jwt_optional() |
|
98 |
|
|
99 |
Authorize.unset_jwt_cookies() |
|
100 |
return """ |
|
101 |
<html> |
|
102 |
<head> |
|
103 |
<title>Logout</title> |
|
104 |
</head> |
|
105 |
<body> |
|
106 |
<h1>Logged Out</h1> |
|
107 |
<form action="/logs-web" method="get"> |
|
108 |
<input type="submit" value="Back" /> |
|
109 |
</form> |
|
110 |
</body> |
|
111 |
</html> |
|
112 |
""" |
server/sql_app/api/devices_web.py | ||
---|---|---|
2 | 2 |
|
3 | 3 |
from fastapi import Depends, APIRouter, Form |
4 | 4 |
from fastapi import Request |
5 |
from fastapi.responses import HTMLResponse |
|
5 |
from fastapi.responses import HTMLResponse, RedirectResponse
|
|
6 | 6 |
from fastapi.templating import Jinja2Templates |
7 | 7 |
from fastapi_jwt_auth import AuthJWT |
8 | 8 |
from pydantic import BaseModel |
9 | 9 |
from sqlalchemy.orm import Session |
10 |
|
|
10 |
from sql_app.api.auth import fake_users_db |
|
11 | 11 |
from sql_app import crud, models |
12 | 12 |
from ..database import SessionLocal, engine |
13 | 13 |
|
... | ... | |
20 | 20 |
device_web = APIRouter(prefix="") |
21 | 21 |
|
22 | 22 |
|
23 |
|
|
24 |
class Settings(BaseModel): |
|
25 |
authjwt_secret_key: str = "secret" |
|
26 |
# Configure application to store and get JWT from cookies |
|
27 |
authjwt_token_location: set = {"cookies"} |
|
28 |
# Disable CSRF Protection for this example. default is True |
|
29 |
authjwt_cookie_csrf_protect: bool = False |
|
30 |
|
|
31 |
|
|
32 |
@AuthJWT.load_config |
|
33 |
def get_config(): |
|
34 |
return Settings() |
|
35 |
|
|
36 |
|
|
37 |
fake_users_db = { |
|
38 |
"admin": { |
|
39 |
"username": "admin", |
|
40 |
"password": "admin" |
|
41 |
}, |
|
42 |
"editor": { |
|
43 |
"username": "editor", |
|
44 |
"password": "editor" |
|
45 |
}, |
|
46 |
} |
|
47 |
|
|
48 |
|
|
49 | 23 |
# Dependency |
50 | 24 |
def get_db(): |
51 | 25 |
db = SessionLocal() |
... | ... | |
55 | 29 |
db.close() |
56 | 30 |
|
57 | 31 |
|
58 |
@device_web.get("/token", response_class=HTMLResponse) |
|
59 |
async def login_get(request: Request): |
|
60 |
return templates.TemplateResponse("login.html", {"request": request}) |
|
61 |
|
|
62 |
|
|
63 |
@device_web.post("/token", response_class=HTMLResponse) |
|
64 |
async def login(username: str = Form(...), password: str = Form(...), Authorize: AuthJWT = Depends()): |
|
65 |
user_dict = fake_users_db.get(username) |
|
66 |
|
|
67 |
access_token = Authorize.create_access_token(subject=username, expires_time=False) |
|
68 |
refresh_token = Authorize.create_refresh_token(subject=username, expires_time=False) |
|
69 |
|
|
70 |
# Set the JWT cookies in the response |
|
71 |
Authorize.set_access_cookies(access_token) |
|
72 |
Authorize.set_refresh_cookies(refresh_token) |
|
73 |
return """ |
|
74 |
<html> |
|
75 |
<head> |
|
76 |
<title>Some HTML in here</title> |
|
77 |
</head> |
|
78 |
<body> |
|
79 |
<h1>Look ma! HTML!</h1> |
|
80 |
<form action="/devices-web" method="get"> |
|
81 |
<input type="submit" value="Login" /> |
|
82 |
</form> |
|
83 |
</body> |
|
84 |
</html> |
|
85 |
""" |
|
86 |
|
|
87 |
|
|
88 |
@device_web.post('/refresh') |
|
89 |
def refresh(Authorize: AuthJWT = Depends()): |
|
90 |
Authorize.jwt_refresh_token_required() |
|
91 |
|
|
92 |
current_user = Authorize.get_jwt_subject() |
|
93 |
new_access_token = Authorize.create_access_token(subject=current_user) |
|
94 |
# Set the JWT cookies in the response |
|
95 |
Authorize.set_access_cookies(new_access_token) |
|
96 |
return {"msg": "The token has been refresh"} |
|
97 |
|
|
98 |
|
|
99 |
@device_web.get('/logout', response_class=HTMLResponse) |
|
100 |
def logout(Authorize: AuthJWT = Depends()): |
|
101 |
""" |
|
102 |
Because the JWT are stored in an httponly cookie now, we cannot |
|
103 |
log the user out by simply deleting the cookies in the frontend. |
|
104 |
We need the backend to send us a response to delete the cookies. |
|
105 |
""" |
|
106 |
Authorize.jwt_required() |
|
107 |
|
|
108 |
Authorize.unset_jwt_cookies() |
|
109 |
return """ |
|
110 |
<html> |
|
111 |
<head> |
|
112 |
<title>Some HTML in here</title> |
|
113 |
</head> |
|
114 |
<body> |
|
115 |
<h1>Look ma! HTML!</h1> |
|
116 |
<form action="/devices-web" method="get"> |
|
117 |
<input type="submit" value="Login" /> |
|
118 |
</form> |
|
119 |
</body> |
|
120 |
</html> |
|
121 |
""" |
|
122 |
|
|
123 |
|
|
124 | 32 |
@device_web.get("/devices-web", response_class=HTMLResponse) |
125 | 33 |
async def read_devices(request: Request, skip: int = 0, limit: int = 100, db: Session = Depends(get_db), |
126 | 34 |
Authorize: AuthJWT = Depends()): |
... | ... | |
136 | 44 |
for i in range(0, len(devices)): |
137 | 45 |
statuses.append(devices[i].logs[len(devices[i].logs) - 1].status) |
138 | 46 |
licenses = crud.get_licenses(db, skip=skip, limit=limit) |
139 |
return templates.TemplateResponse("devices.html", {"request": request, "devs": len(devices), "devices": devices, |
|
140 |
"statuses": statuses, "licenses": licenses}) |
|
47 |
if current_user == "admin": |
|
48 |
return templates.TemplateResponse("devices.html", {"request": request, "devs": len(devices), "devices": devices, |
|
49 |
"statuses": statuses, "licenses": licenses}) |
|
50 |
else: |
|
51 |
return templates.TemplateResponse("devices_normal.html", {"request": request, "devs": len(devices), "devices": devices, |
|
52 |
"statuses": statuses, "licenses": licenses}) |
|
141 | 53 |
|
142 | 54 |
|
143 | 55 |
@device_web.post("/devices-web", response_class=HTMLResponse) |
... | ... | |
177 | 89 |
|
178 | 90 |
|
179 | 91 |
@device_web.post("/devices-web/{device_id}", response_class=HTMLResponse) |
180 |
async def connect_post(request: Request, device_id: int, lic: str = Form(...), skip: int = 0, limit: int = 100, |
|
181 |
db: Session = Depends(get_db)): |
|
92 |
async def connect_post(device_id: int, lic: str = Form(...), db: Session = Depends(get_db)): |
|
182 | 93 |
""" |
183 | 94 |
Endpoint called from template for connecting device with license. Adds entry to devices_licenses |
184 | 95 |
table and returns template with all devices in database |
185 | 96 |
""" |
186 | 97 |
crud.create_device_license(db, device_id, int(lic), datetime.now()) |
187 |
devices = crud.get_devices(db, skip=skip, limit=limit) |
|
188 |
statuses = [] |
|
189 |
# adding state for each device in list |
|
190 |
for i in range(0, len(devices)): |
|
191 |
statuses.append(devices[i].logs[len(devices[i].logs) - 1].status) |
|
192 |
licenses = crud.get_licenses(db, skip=skip, limit=limit) |
|
193 |
return templates.TemplateResponse("devices.html", {"request": request, "devs": len(devices), "devices": devices, |
|
194 |
"statuses": statuses, "licenses": licenses}) |
|
98 |
return RedirectResponse("/devices-web") |
server/sql_app/api/licenses_web.py | ||
---|---|---|
6 | 6 |
from sql_app import crud, models, schemas |
7 | 7 |
from ..database import SessionLocal, engine |
8 | 8 |
from fastapi import FastAPI, Request |
9 |
from fastapi.responses import HTMLResponse |
|
9 |
from fastapi.responses import HTMLResponse, RedirectResponse
|
|
10 | 10 |
from fastapi.staticfiles import StaticFiles |
11 | 11 |
from fastapi.templating import Jinja2Templates |
12 | 12 |
|
... | ... | |
47 | 47 |
|
48 | 48 |
|
49 | 49 |
@licenses_web.post("/licenses-web", response_class=HTMLResponse) |
50 |
def create_license(request: Request, name: str = Form(...), expdate: date = Form(...), skip: int = 0, limit: int = 100, |
|
51 |
db: Session = Depends(get_db)): |
|
50 |
def create_license(name: str = Form(...), expdate: date = Form(...), db: Session = Depends(get_db)): |
|
52 | 51 |
""" |
53 | 52 |
Endpoint called from create license form. Creates new license and returns template with all licenses in database |
54 | 53 |
""" |
55 | 54 |
db_license = crud.create_license(db, name, expdate) |
56 | 55 |
if db_license is None: |
57 | 56 |
print("something went wrong") |
58 |
devices = crud.get_devices(db, skip=skip, limit=limit) |
|
59 |
statuses = [] |
|
60 |
for i in range(0, len(devices)): |
|
61 |
statuses.append(devices[i].logs[len(devices[i].logs) - 1].status) |
|
62 |
licenses = crud.get_licenses(db, skip=skip, limit=limit) |
|
63 |
return device_templates.TemplateResponse("devices.html", {"request": request, "devs": len(devices), "devices": devices, |
|
64 |
"statuses": statuses, "licenses": licenses}) |
|
57 |
return RedirectResponse("/devices-web") |
server/sql_app/api/pcs_web.py | ||
---|---|---|
4 | 4 |
from sql_app import crud, models, schemas |
5 | 5 |
from ..database import SessionLocal, engine |
6 | 6 |
from fastapi import FastAPI, Request |
7 |
from fastapi.responses import HTMLResponse |
|
7 |
from fastapi.responses import HTMLResponse, RedirectResponse |
|
8 |
from fastapi_jwt_auth import AuthJWT |
|
8 | 9 |
from fastapi.staticfiles import StaticFiles |
9 | 10 |
from fastapi.templating import Jinja2Templates |
10 | 11 |
|
... | ... | |
27 | 28 |
|
28 | 29 |
|
29 | 30 |
@pcs_web.get("/pcs-web", response_class=HTMLResponse) |
30 |
async def read_pcs(request: Request, skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): |
|
31 |
async def read_pcs(request: Request, skip: int = 0, limit: int = 100, db: Session = Depends(get_db), |
|
32 |
Authorize: AuthJWT = Depends()): |
|
31 | 33 |
""" |
32 | 34 |
Returns template with all pcs currently saved in database |
33 | 35 |
""" |
36 |
Authorize.jwt_optional() |
|
37 |
current_user = Authorize.get_jwt_subject() |
|
34 | 38 |
pcs = crud.get_pcs(db, skip=skip, limit=limit) |
35 |
return templates.TemplateResponse("pcs.html", {"request": request, "pcs": pcs}) |
|
39 |
if current_user == "admin": |
|
40 |
return templates.TemplateResponse("pcs.html", {"request": request, "pcs": pcs}) |
|
41 |
else: |
|
42 |
return templates.TemplateResponse("pcs_normal.html", {"request": request, "pcs": pcs}) |
|
36 | 43 |
|
37 | 44 |
|
38 | 45 |
@pcs_web.get("/pc-team/{pc_id}", response_class=HTMLResponse) |
... | ... | |
47 | 54 |
|
48 | 55 |
|
49 | 56 |
@pcs_web.post("/pcs-web/{pc_id}", response_class=HTMLResponse) |
50 |
async def connect_post(request: Request, pc_id: int, team: str = Form(...), skip: int = 0, limit: int = 100, |
|
51 |
db: Session = Depends(get_db)): |
|
57 |
async def connect_post(pc_id: int, team: str = Form(...), db: Session = Depends(get_db)): |
|
52 | 58 |
""" |
53 | 59 |
Endpoint called from within form for connecting pc with team. Updates certain pc with new team. |
54 | 60 |
""" |
55 | 61 |
old_pc = crud.update_pc(db, pc_id, team) |
56 |
pcs = crud.get_pcs(db, skip=skip, limit=limit) |
|
57 |
return templates.TemplateResponse("pcs.html", {"request": request, "pcs": pcs}) |
|
62 |
RedirectResponse("/pcs-web") |
server/sql_app/api/teams_web.py | ||
---|---|---|
5 | 5 |
from sql_app import crud, models, schemas |
6 | 6 |
from ..database import SessionLocal, engine |
7 | 7 |
from fastapi import FastAPI, Request |
8 |
from fastapi.responses import HTMLResponse |
|
8 |
from fastapi.responses import HTMLResponse, RedirectResponse |
|
9 |
from fastapi_jwt_auth import AuthJWT |
|
9 | 10 |
from fastapi.staticfiles import StaticFiles |
10 | 11 |
from fastapi.templating import Jinja2Templates |
11 | 12 |
|
... | ... | |
28 | 29 |
|
29 | 30 |
|
30 | 31 |
@teams_web.get("/teams-web", response_class=HTMLResponse) |
31 |
async def read_devices(request: Request, skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): |
|
32 |
async def read_devices(request: Request, skip: int = 0, limit: int = 100, db: Session = Depends(get_db), |
|
33 |
Authorize: AuthJWT = Depends()): |
|
32 | 34 |
""" |
33 | 35 |
Returns template with all teams currently saved in database |
34 | 36 |
""" |
37 |
Authorize.jwt_optional() |
|
38 |
current_user = Authorize.get_jwt_subject() |
|
35 | 39 |
teams = crud.get_teams(db, skip=skip, limit=limit) |
36 |
return templates.TemplateResponse("teams.html", {"request": request, "teams": teams}) |
|
40 |
if current_user == "admin": |
|
41 |
return templates.TemplateResponse("teams.html", {"request": request, "teams": teams}) |
|
42 |
else: |
|
43 |
return templates.TemplateResponse("teams_normal.html", {"request": request, "teams": teams}) |
|
37 | 44 |
|
38 | 45 |
|
39 | 46 |
@teams_web.get("/team-create", response_class=HTMLResponse) |
... | ... | |
45 | 52 |
|
46 | 53 |
|
47 | 54 |
@teams_web.post("/teams-web", response_class=HTMLResponse) |
48 |
def create_team(request: Request, name: str = Form(...), skip: int = 0, limit: int = 100, |
|
49 |
db: Session = Depends(get_db)): |
|
55 |
def create_team(name: str = Form(...), db: Session = Depends(get_db)): |
|
50 | 56 |
""" |
51 | 57 |
Endpoint called from within form for creating new team. Creates new team and returns all teams in database |
52 | 58 |
""" |
53 | 59 |
team = crud.create_team(db, name) |
54 | 60 |
if team is None: |
55 | 61 |
print("something went wrong") |
56 |
teams = crud.get_teams(db, skip=skip, limit=limit) |
|
57 |
return templates.TemplateResponse("teams.html", {"request": request, "teams": teams}) |
|
62 |
RedirectResponse("/teams-web") |
server/sql_app/main.py | ||
---|---|---|
9 | 9 |
from sql_app.api.usb_logs_web import usblogs_web |
10 | 10 |
from sql_app.api.teams import teams |
11 | 11 |
from sql_app.api.teams_web import teams_web |
12 |
from sql_app.api.auth import auth |
|
12 | 13 |
from fastapi import FastAPI |
13 | 14 |
|
14 | 15 |
|
... | ... | |
27 | 28 |
app.include_router(pcs_web) |
28 | 29 |
app.include_router(teams_web) |
29 | 30 |
app.include_router(usblogs_web) |
31 |
app.include_router(auth) |
|
30 | 32 |
|
31 | 33 |
''' |
32 | 34 |
if __name__ == "__main__": |
server/templates/auth/login.html | ||
---|---|---|
1 |
<!DOCTYPE html> |
|
2 |
<html lang="en"> |
|
3 |
<head> |
|
4 |
<meta charset="UTF-8"> |
|
5 |
<title>Login</title> |
|
6 |
</head> |
|
7 |
<body> |
|
8 |
<form action="/login" method="post"> |
|
9 |
<label for="username">Username:</label><br> |
|
10 |
<input type="text" id="username" name="username"><br><br> |
|
11 |
<label for="password">Expiration Date</label> |
|
12 |
<input type="text" id="password" name="password"> |
|
13 |
<input type="submit" value="Submit"> |
|
14 |
</form> |
|
15 |
</body> |
|
16 |
</html> |
server/templates/devices/devices.html | ||
---|---|---|
3 | 3 |
<title>Devices Details</title> |
4 | 4 |
</head> |
5 | 5 |
<body> |
6 |
<div style='float:left'> |
|
6 | 7 |
<form action="" method="get"> |
7 | 8 |
<label for="view">Choose view:</label> |
8 | 9 |
<select id="view" name="view" onchange="this.form.action=this.value;"> |
... | ... | |
14 | 15 |
</select> |
15 | 16 |
<input type="submit" value="OK"> |
16 | 17 |
</form> |
17 |
<form action="/token" method="get"> |
|
18 |
</div> |
|
19 |
<div style='float:left'> |
|
20 |
<form action="/login" method="get"> |
|
18 | 21 |
<input type="submit" value="Login" /> |
19 | 22 |
</form> |
23 |
</div> |
|
24 |
<form action="/logout" method="get"> |
|
25 |
<input type="submit" value="Logout" /> |
|
26 |
</form> |
|
20 | 27 |
<form action="/devices-web" method="post"> |
21 | 28 |
<label for="lic">License:</label> |
22 | 29 |
<input id="lic" name="lic" type="text" list="licenses" value="" placeholder="all"> |
server/templates/devices/devices_normal.html | ||
---|---|---|
1 |
<html> |
|
2 |
<head> |
|
3 |
<title>Devices Details</title> |
|
4 |
</head> |
|
5 |
<body> |
|
6 |
<div style='float:left'> |
|
7 |
<form action="" method="get"> |
|
8 |
<label for="view">Choose view:</label> |
|
9 |
<select id="view" name="view" onchange="this.form.action=this.value;"> |
|
10 |
<option value=""></option> |
|
11 |
<option value="/logs-web">Logs</option> |
|
12 |
<option value="/devices-web">Devices</option> |
|
13 |
<option value="/teams-web">Teams</option> |
|
14 |
<option value="/pcs-web">PCs</option> |
|
15 |
</select> |
|
16 |
<input type="submit" value="OK"> |
|
17 |
</form> |
|
18 |
</div> |
|
19 |
<div style='float:left'> |
|
20 |
<form action="/login" method="get"> |
|
21 |
<input type="submit" value="Login" /> |
|
22 |
</form> |
|
23 |
</div> |
|
24 |
<form action="/logout" method="get"> |
|
25 |
<input type="submit" value="Logout" /> |
|
26 |
</form> |
|
27 |
<form action="/devices-web" method="post"> |
|
28 |
<label for="lic">License:</label> |
|
29 |
<input id="lic" name="lic" type="text" list="licenses" value="" placeholder="all"> |
|
30 |
<datalist id="licenses"> |
|
31 |
{% for license in licenses %} |
|
32 |
<option value="{{license.name}}"></option> |
|
33 |
{% endfor %} |
|
34 |
</datalist> |
|
35 |
<input type="submit" value="Filter"> |
|
36 |
</form> |
|
37 |
<table> |
|
38 |
<TR> |
|
39 |
<TH>ID</TH> |
|
40 |
<TH>Vendor ID</TH> |
|
41 |
<TH>Product ID</TH> |
|
42 |
<TH>Serial Number</TH> |
|
43 |
<TH>Licenses</TH> |
|
44 |
<TH>Status</TH> |
|
45 |
</TR> |
|
46 |
{% for i in range(devs) %} |
|
47 |
<TR> |
|
48 |
<TD class="ID">{{devices[i].id}}</TD> |
|
49 |
<TD class="Vendor ID">{{devices[i].vendor_id}}</TD> |
|
50 |
<TD class="Product ID">{{devices[i].product_id}}</TD> |
|
51 |
<TD class="Serial Number">{{devices[i].serial_number}}</TD> |
|
52 |
<TD class="License"> |
|
53 |
{% for lic in devices[i].licenses %} |
|
54 |
{{lic.licenses.name}}<BR> |
|
55 |
{% endfor %} |
|
56 |
</TD> |
|
57 |
<TD class="Status">{{statuses[i]}}</TD> |
|
58 |
</TR> |
|
59 |
{% endfor %} |
|
60 |
</table> |
|
61 |
</body> |
|
62 |
</html> |
server/templates/devices/login.html | ||
---|---|---|
1 |
<!DOCTYPE html> |
|
2 |
<html lang="en"> |
|
3 |
<head> |
|
4 |
<meta charset="UTF-8"> |
|
5 |
<title>Login</title> |
|
6 |
</head> |
|
7 |
<body> |
|
8 |
<form action="/token" method="post"> |
|
9 |
<label for="username">Username:</label><br> |
|
10 |
<input type="text" id="username" name="username"><br><br> |
|
11 |
<label for="password">Expiration Date</label> |
|
12 |
<input type="text" id="password" name="password"> |
|
13 |
<input type="submit" value="Submit"> |
|
14 |
</form> |
|
15 |
</body> |
|
16 |
</html> |
server/templates/licenses/licenses.html | ||
---|---|---|
3 | 3 |
<title>Licenses Details</title> |
4 | 4 |
</head> |
5 | 5 |
<body> |
6 |
<div style='float:left'> |
|
6 | 7 |
<form action="" method="get"> |
7 | 8 |
<label for="view">Choose view:</label> |
8 | 9 |
<select id="view" name="view" onchange="this.form.action=this.value;"> |
... | ... | |
14 | 15 |
</select> |
15 | 16 |
<input type="submit" value="OK"> |
16 | 17 |
</form> |
18 |
</div> |
|
19 |
<div style='float:left'> |
|
20 |
<form action="/login" method="get"> |
|
21 |
<input type="submit" value="Login" /> |
|
22 |
</form> |
|
23 |
</div> |
|
24 |
<form action="/logout" method="get"> |
|
25 |
<input type="submit" value="Logout" /> |
|
26 |
</form> |
|
17 | 27 |
<table> |
18 | 28 |
<TR> |
19 | 29 |
<TH>ID</TH> |
server/templates/pcs/pcs.html | ||
---|---|---|
3 | 3 |
<title>Pcs Details</title> |
4 | 4 |
</head> |
5 | 5 |
<body> |
6 |
<div style='float:left'> |
|
6 | 7 |
<form action="" method="get"> |
7 | 8 |
<label for="view">Choose view:</label> |
8 | 9 |
<select id="view" name="view" onchange="this.form.action=this.value;"> |
... | ... | |
14 | 15 |
</select> |
15 | 16 |
<input type="submit" value="OK"> |
16 | 17 |
</form> |
18 |
</div> |
|
19 |
<div style='float:left'> |
|
20 |
<form action="/login" method="get"> |
|
21 |
<input type="submit" value="Login" /> |
|
22 |
</form> |
|
23 |
</div> |
|
24 |
<form action="/logout" method="get"> |
|
25 |
<input type="submit" value="Logout" /> |
|
26 |
</form> |
|
17 | 27 |
<table> |
18 | 28 |
<TR> |
19 | 29 |
<TH>ID</TH> |
server/templates/pcs/pcs_normal.html | ||
---|---|---|
1 |
<html> |
|
2 |
<head> |
|
3 |
<title>Pcs Details</title> |
|
4 |
</head> |
|
5 |
<body> |
|
6 |
<div style='float:left'> |
|
7 |
<form action="" method="get"> |
|
8 |
<label for="view">Choose view:</label> |
|
9 |
<select id="view" name="view" onchange="this.form.action=this.value;"> |
|
10 |
<option value=""></option> |
|
11 |
<option value="/logs-web">Logs</option> |
|
12 |
<option value="/devices-web">Devices</option> |
|
13 |
<option value="/teams-web">Teams</option> |
|
14 |
<option value="/pcs-web">PCs</option> |
|
15 |
</select> |
|
16 |
<input type="submit" value="OK"> |
|
17 |
</form> |
|
18 |
</div> |
|
19 |
<div style='float:left'> |
|
20 |
<form action="/login" method="get"> |
|
21 |
<input type="submit" value="Login" /> |
|
22 |
</form> |
|
23 |
</div> |
|
24 |
<form action="/logout" method="get"> |
|
25 |
<input type="submit" value="Logout" /> |
|
26 |
</form> |
|
27 |
<table> |
|
28 |
<TR> |
|
29 |
<TH>ID</TH> |
|
30 |
<TH>Username</TH> |
|
31 |
<TH>Hostname</TH> |
|
32 |
<TH>Team</TH> |
|
33 |
</TR> |
|
34 |
{% for pc in pcs %} |
|
35 |
<TR> |
|
36 |
<TD class="ID">{{pc.id}}</TD> |
|
37 |
<TD class="Vendor ID">{{pc.username}}</TD> |
|
38 |
<TD class="Product ID">{{pc.hostname}}</TD> |
|
39 |
{% if pc.team == None %} |
|
40 |
<TD class="Team">NONE</TD> |
|
41 |
{% else %} |
|
42 |
<TD class="Team">{{pc.team.name}}</TD> |
|
43 |
{% endif %} |
|
44 |
</TR> |
|
45 |
{% endfor %} |
|
46 |
</table> |
|
47 |
</body> |
|
48 |
</html> |
server/templates/teams/teams.html | ||
---|---|---|
3 | 3 |
<title>Teams Details</title> |
4 | 4 |
</head> |
5 | 5 |
<body> |
6 |
<div style='float:left'> |
|
6 | 7 |
<form action="" method="get"> |
7 | 8 |
<label for="view">Choose view:</label> |
8 | 9 |
<select id="view" name="view" onchange="this.form.action=this.value;"> |
... | ... | |
14 | 15 |
</select> |
15 | 16 |
<input type="submit" value="OK"> |
16 | 17 |
</form> |
18 |
</div> |
|
19 |
<div style='float:left'> |
|
20 |
<form action="/login" method="get"> |
|
21 |
<input type="submit" value="Login" /> |
|
22 |
</form> |
|
23 |
</div> |
|
24 |
<form action="/logout" method="get"> |
|
25 |
<input type="submit" value="Logout" /> |
|
26 |
</form> |
|
17 | 27 |
<table> |
18 | 28 |
<TR> |
19 | 29 |
<TH>ID</TH> |
server/templates/teams/teams_normal.html | ||
---|---|---|
1 |
<html> |
|
2 |
<head> |
|
3 |
<title>Teams Details</title> |
|
4 |
</head> |
|
5 |
<body> |
|
6 |
<div style='float:left'> |
|
7 |
<form action="" method="get"> |
|
8 |
<label for="view">Choose view:</label> |
|
9 |
<select id="view" name="view" onchange="this.form.action=this.value;"> |
|
10 |
<option value=""></option> |
|
11 |
<option value="/logs-web">Logs</option> |
|
12 |
<option value="/devices-web">Devices</option> |
|
13 |
<option value="/teams-web">Teams</option> |
|
14 |
<option value="/pcs-web">PCs</option> |
|
15 |
</select> |
|
16 |
<input type="submit" value="OK"> |
|
17 |
</form> |
|
18 |
</div> |
|
19 |
<div style='float:left'> |
|
20 |
<form action="/login" method="get"> |
|
21 |
<input type="submit" value="Login" /> |
|
22 |
</form> |
|
23 |
</div> |
|
24 |
<form action="/logout" method="get"> |
|
25 |
<input type="submit" value="Logout" /> |
|
26 |
</form> |
|
27 |
<table> |
|
28 |
<TR> |
|
29 |
<TH>ID</TH> |
|
30 |
<TH>Name</TH> |
|
31 |
</TR> |
|
32 |
{% for team in teams %} |
|
33 |
<TR> |
|
34 |
<TD class="ID">{{team.id}}</TD> |
|
35 |
<TD class="Vendor ID">{{team.name}}</TD> |
|
36 |
</TR> |
|
37 |
{% endfor %} |
|
38 |
</table> |
|
39 |
</body> |
|
40 |
</html> |
server/templates/usb-logs/logs.html | ||
---|---|---|
3 | 3 |
<title>Logs Details</title> |
4 | 4 |
</head> |
5 | 5 |
<body> |
6 |
<div style='float:left'> |
|
6 | 7 |
<form action="" method="get"> |
7 | 8 |
<label for="view">Choose view:</label> |
8 | 9 |
<select id="view" name="view" onchange="this.form.action=this.value;"> |
... | ... | |
14 | 15 |
</select> |
15 | 16 |
<input type="submit" value="OK"> |
16 | 17 |
</form> |
18 |
</div> |
|
19 |
<div style='float:left'> |
|
20 |
<form action="/login" method="get"> |
|
21 |
<input type="submit" value="Login" /> |
|
22 |
</form> |
|
23 |
</div> |
|
24 |
<form action="/logout" method="get"> |
|
25 |
<input type="submit" value="Logout" /> |
|
26 |
</form> |
|
17 | 27 |
<form action="/logs-web" method="post"> |
18 | 28 |
<label for="pc">PC:</label> |
19 | 29 |
<input id="pc" name="pc" type="text" list="pcs" value="" placeholder="all"> |
Také k dispozici: Unified diff
re #9708 updated requirements. Added logout and template versions for host users.