-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Public terminal management #6
base: master
Are you sure you want to change the base?
Changes from all commits
6dc84b5
31c6856
3ce36dd
0eab998
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,98 @@ | ||
from flask import Blueprint | ||
from flask import Blueprint, request | ||
from director.model import User | ||
from functools import wraps | ||
|
||
PublicAPI = Blueprint('public_api', __name__, url_prefix='/api/public') | ||
|
||
@PublicAPI.route('/user/<username>') | ||
def get_user(username): | ||
user = User.query.filter_by(username=username).first_or_404() | ||
return user.serialize() | ||
|
||
|
||
from director.model import Terminal as terminal_model | ||
|
||
@PublicAPI.route('/lab/<int:lab>/terminal/<int:terminal>', methods=["GET"]) | ||
@PublicAPI.route('/lab/<int:lab>/terminals', methods=["GET"]) | ||
def get_terminals(lab, terminal = None): | ||
# GET: /terminals | ||
if terminal == None: | ||
terminals = terminal_model.query.filter_by(lab_id=lab).all() | ||
jsonArray = {'terminals': []} | ||
|
||
for _ in terminals: | ||
jsonArray['terminals'].append(_.serialize()) | ||
|
||
return jsonArray | ||
#end if: GET: /terminals | ||
|
||
# GET: /terminal/<terminal> | ||
terminal_result = terminal_model.query.filter_by(lab_id=lab,id=terminal).first_or_404() | ||
|
||
return terminal_result.serialize() | ||
|
||
# Checks if the client sends a (not-empty-also) json | ||
def empty_json_body(f): | ||
@wraps(f) | ||
def decorated(*args, **kwargs): | ||
try: | ||
# Check if empty | ||
if len(request.get_json()) == 0: | ||
return {'message': 'Provide some values.'}, 400 | ||
except: | ||
# There was no json in request data | ||
return {"message": "Provide a json body."}, 400 | ||
return f(*args,**kwargs) | ||
return decorated | ||
|
||
@PublicAPI.route('/lab/<int:lab>/terminal/<int:terminal>', methods=["PATCH", "PUT"]) | ||
@empty_json_body | ||
def patch_terminal(lab, terminal): | ||
|
||
terminal_result = terminal_model.query.filter_by(lab_id=lab,id=terminal).first_or_404() | ||
|
||
valid_options = ['host_name', 'ip', 'status', 'room', 'lab_id'] | ||
|
||
changes = {} | ||
for key, value in dict(request.json).items(): | ||
if key in valid_options: | ||
value = None if value == "" else value | ||
changes[key] = value | ||
|
||
# If not any value is assigned, assign the uri's lab otherwise the terminal | ||
# will be lost forever from the client (only the database will be able to see it) | ||
if changes.get("lab_id") == None: | ||
changes["lab_id"] = lab | ||
|
||
# possible TODO: check status value (is it 0 1 2 3) or (down, locked, up, logged_in) | ||
|
||
# PATCH: Update only the parameters we are given | ||
if request.method == 'PATCH': | ||
if changes['ip'] == None: # IP is not nullable | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe run this check in the model? We should check if validations are supported by SQAlchemy. |
||
return {"error": "Terminal IP can't be null or empty"}, 400 | ||
|
||
return terminal_result.update(changes) | ||
# end if:PATCH | ||
|
||
# PUT: Update all parameters | ||
for option in valid_options: | ||
if option not in changes.keys(): | ||
changes[option] = None | ||
|
||
if changes['ip'] == None: # IP is not nullable | ||
return {"error": "Terminal IP can't be null or empty"}, 400 | ||
|
||
return terminal_result.update_all(changes) | ||
|
||
@PublicAPI.route('/lab/<int:lab>/terminal/<int:terminal>/<command>', methods=["PATCH"]) | ||
def patch_terminal_c(lab, terminal, command): | ||
|
||
valid_commands = ['restart','shutdown','hibernate','log-out'] | ||
|
||
if command not in valid_commands: | ||
return {"error": "Invalid command"}, 406 | ||
|
||
# TODO | ||
# communicate with user-agent | ||
|
||
return {"message": "Not implemented"}, 501 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,15 +2,25 @@ | |
|
||
from sqlalchemy import ForeignKey | ||
|
||
from director import db | ||
from marshmallow import Schema, fields | ||
from marshmallow_enum import EnumField | ||
|
||
from director import db | ||
|
||
class Status(enum.Enum): | ||
down = 0 | ||
locked = 1 | ||
up = 2 | ||
logged_in = 3 | ||
|
||
class TerminalSchema(Schema): | ||
id = fields.Int(dump_only=True) | ||
host_name = fields.Str() | ||
ip = fields.Str() | ||
status = EnumField(Status) | ||
room = fields.Str() | ||
lab_id = fields.Int(dump_only=True) | ||
|
||
|
||
class Terminal(db.Model): | ||
id = db.Column(db.Integer, primary_key=True) | ||
|
@@ -21,6 +31,33 @@ class Terminal(db.Model): | |
lab_id = db.Column(db.Integer, ForeignKey('lab.id')) | ||
sessions = db.relationship("Session", backref="terminal") | ||
|
||
def serialize(self): | ||
return TerminalSchema().dump(self) | ||
|
||
def update_all(self, changes): | ||
try: | ||
self.host_name = changes["host_name"] | ||
self.ip = changes["ip"] | ||
self.status = Status.down if changes["status"] == None else changes["status"] | ||
self.room = changes["room"] | ||
self.lab_id = changes["lab_id"] | ||
db.session.commit() | ||
except: | ||
return {"error", "Possible duplicate host name or IP."}, 400 | ||
|
||
return {"message": "Update successful"} | ||
|
||
def update(self, changes): | ||
madeChanges = 204 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's keep status codes out of the model classes, and reply inside the API classes! |
||
for key, value in changes.items(): | ||
madeChanges = 200 | ||
setattr(self, key, value) | ||
try: | ||
db.session.commit() | ||
except: | ||
return {"error", "Possible duplicate host name or IP."}, 400 | ||
return {"Success": "Updated."}, madeChanges | ||
|
||
def __repr__(self): | ||
return '<Terminal %r %r %r %r %r %r>' % (self.id, | ||
self.host_name, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really nice, but maybe rename it to something like @require_json_body?