diff --git a/director/api/public.py b/director/api/public.py index 4d1d0aa..c192cbd 100644 --- a/director/api/public.py +++ b/director/api/public.py @@ -1,5 +1,6 @@ -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') @@ -7,3 +8,91 @@ 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//terminal/', methods=["GET"]) +@PublicAPI.route('/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_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//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 + 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//terminal//', 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 \ No newline at end of file diff --git a/director/model/terminal.py b/director/model/terminal.py index 4177892..10c7d4a 100644 --- a/director/model/terminal.py +++ b/director/model/terminal.py @@ -2,8 +2,10 @@ 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 @@ -11,6 +13,14 @@ class Status(enum.Enum): 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 + 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 '' % (self.id, self.host_name,