Loading README.md 0 → 100644 +21 −0 Original line number Diff line number Diff line # myfab Fablab 3d printing request application ## Minimum Viable Version - [x] User Connection - [ ] Submit a print request - [ ] Upload a STL file - [ ] Create a new Print Request - [ ] Accept/Reject print request - [ ] See STL file in 3d - [ ] See print status - [ ] Change Print status (see enum in api) - [ ] Slice - [ ] Upload GCODE - [ ] **V2**: Open slicer window - [ ] **V2**: Send to printer - [ ] Working queues - [ ] Printer management - [ ] Post to octoprint back/myfab/api.py +52 −8 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ from myfab.model import * from flask_api import status from flask import jsonify import string import random import os init_db_connection() Loading @@ -26,14 +27,26 @@ jwt = JWTManager(app) def identity(payload): payload = get_raw_jwt() return get_or_create_user(payload['login_name'], payload['firstname'] + ' '+ payload['lastname']) ### ENUMS ### REQUEST_STATUS_PENDING_REVIEW = 0 REQUEST_STATUS_PENDING_REVIEW = 0 # initial state REQUEST_STATUS_APPROVED = 1 # approved, waiting slicing REQUEST_STATUS_AWAITING_PRINT = 2 # sliced, in print queur REQUEST_STATUS_PRINTING = 3 # currently printing REQUEST_STATUS_FINISHED = 4 # done printing, waiting for recuperation REQUEST_STATUS_CLOSED = 5 # archived REQUEST_STATUS_REJECTED = 10 # refused by operator REQUEST_STATUS_PRINT_FAILED = 11 # print failed more than allowed REQUEST_STATUS_STANDBY = 12 # on hold, from any state REQUEST_ACCESS_DENIED = 0 # Not allowed to see this request REQUEST_ACCESS_OBSERVER = 1 # Allowed to see this request REQUEST_ACCESS_USER = 2 # Is the author of this request REQUEST_ACCESS_OPERATOR = 3 # Is an operator of the system REQUEST_ACCESS_DENIED = 0 REQUEST_ACCESS_OBSERVER = 1 REQUEST_ACCESS_USER = 2 REQUEST_ACCESS_OPERATOR = 3 # Elements that can be modified by a user (not op) REQUEST_USER_ELEMENTS = set(["title","description","project"]) ### UTILS #### Loading Loading @@ -81,8 +94,14 @@ def loop_requests(reqs): def get_access_level_to_request(req, user): #req is id or req same for user # TODO return REQUEST_ACCESS_OPERATOR # FIXME def update_requires_operator_rights(update_json): s = set(update_json) s.discard(REQUEST_USER_ELEMENTS) return len(s) > 0 #### ROUTES #### @app.route("/whoami") Loading @@ -96,6 +115,24 @@ def get_my_requests(): return jsonify(loop_requests(lookup_requests(current_user.username))) @app.route("/requests/<req_id>", methods=['PUT']) @jwt_required def update_request(req_id): # Author can update request initial parameters when status is 0 # Operator can update all request parameters # req = get_request_by_id(req_id) if req is None: return jsonify({'error': 'No such request'}, status.HTTP_404_NOT_FOUND) required_access = REQUEST_ACCESS_OPERATOR if req.status > 0 and if get_access_level_to_request(req, current_user) < REQUEST_ACCESS_OPERATOR: return jsonify({'error': 'Access denied'}, status.HTTP_401_UNAUTHORIZED) request.get_json() @app.route("/requests/new", methods=['POST']) @jwt_required def add_new_request(): Loading Loading @@ -135,11 +172,18 @@ def stl_upload(kind, req_id): if file.filename == '': return jsonify({'error': 'No file'}, status.HTTP_400_BAD_REQUEST) name = ''.join([random.choice(string.ascii_letters + string.digits) for n in xrange(32)]) file.save(os.path.join(FILE_SAVE_PATH, name)) name = ''.join([random.choice(string.ascii_letters + string.digits) for n in range(64)]) if kind == "stl": request.stl = name elif kind == "gcode": request.gcode = name else: return jsonify({'error': "Invalid file kind"}, status.HTTP_400_BAD_REQUEST) file.save(os.path.join(FILE_SAVE_PATH, name)) request.save() add_request_event(request, "Added stl file") add_request_event(request, f'Added {kind} file') return jsonify({'ok': True}) Loading back/myfab/model.py +1 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ class PrintRequest(Model): description = TextField() author = ForeignKeyField(User) stl = TextField(null=True, default=None) gcode = TextField(null=True, default=None) status = IntegerField(default=0) project = TextField() operator = ForeignKeyField(User, null=True, default=None) Loading Loading
README.md 0 → 100644 +21 −0 Original line number Diff line number Diff line # myfab Fablab 3d printing request application ## Minimum Viable Version - [x] User Connection - [ ] Submit a print request - [ ] Upload a STL file - [ ] Create a new Print Request - [ ] Accept/Reject print request - [ ] See STL file in 3d - [ ] See print status - [ ] Change Print status (see enum in api) - [ ] Slice - [ ] Upload GCODE - [ ] **V2**: Open slicer window - [ ] **V2**: Send to printer - [ ] Working queues - [ ] Printer management - [ ] Post to octoprint
back/myfab/api.py +52 −8 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ from myfab.model import * from flask_api import status from flask import jsonify import string import random import os init_db_connection() Loading @@ -26,14 +27,26 @@ jwt = JWTManager(app) def identity(payload): payload = get_raw_jwt() return get_or_create_user(payload['login_name'], payload['firstname'] + ' '+ payload['lastname']) ### ENUMS ### REQUEST_STATUS_PENDING_REVIEW = 0 REQUEST_STATUS_PENDING_REVIEW = 0 # initial state REQUEST_STATUS_APPROVED = 1 # approved, waiting slicing REQUEST_STATUS_AWAITING_PRINT = 2 # sliced, in print queur REQUEST_STATUS_PRINTING = 3 # currently printing REQUEST_STATUS_FINISHED = 4 # done printing, waiting for recuperation REQUEST_STATUS_CLOSED = 5 # archived REQUEST_STATUS_REJECTED = 10 # refused by operator REQUEST_STATUS_PRINT_FAILED = 11 # print failed more than allowed REQUEST_STATUS_STANDBY = 12 # on hold, from any state REQUEST_ACCESS_DENIED = 0 # Not allowed to see this request REQUEST_ACCESS_OBSERVER = 1 # Allowed to see this request REQUEST_ACCESS_USER = 2 # Is the author of this request REQUEST_ACCESS_OPERATOR = 3 # Is an operator of the system REQUEST_ACCESS_DENIED = 0 REQUEST_ACCESS_OBSERVER = 1 REQUEST_ACCESS_USER = 2 REQUEST_ACCESS_OPERATOR = 3 # Elements that can be modified by a user (not op) REQUEST_USER_ELEMENTS = set(["title","description","project"]) ### UTILS #### Loading Loading @@ -81,8 +94,14 @@ def loop_requests(reqs): def get_access_level_to_request(req, user): #req is id or req same for user # TODO return REQUEST_ACCESS_OPERATOR # FIXME def update_requires_operator_rights(update_json): s = set(update_json) s.discard(REQUEST_USER_ELEMENTS) return len(s) > 0 #### ROUTES #### @app.route("/whoami") Loading @@ -96,6 +115,24 @@ def get_my_requests(): return jsonify(loop_requests(lookup_requests(current_user.username))) @app.route("/requests/<req_id>", methods=['PUT']) @jwt_required def update_request(req_id): # Author can update request initial parameters when status is 0 # Operator can update all request parameters # req = get_request_by_id(req_id) if req is None: return jsonify({'error': 'No such request'}, status.HTTP_404_NOT_FOUND) required_access = REQUEST_ACCESS_OPERATOR if req.status > 0 and if get_access_level_to_request(req, current_user) < REQUEST_ACCESS_OPERATOR: return jsonify({'error': 'Access denied'}, status.HTTP_401_UNAUTHORIZED) request.get_json() @app.route("/requests/new", methods=['POST']) @jwt_required def add_new_request(): Loading Loading @@ -135,11 +172,18 @@ def stl_upload(kind, req_id): if file.filename == '': return jsonify({'error': 'No file'}, status.HTTP_400_BAD_REQUEST) name = ''.join([random.choice(string.ascii_letters + string.digits) for n in xrange(32)]) file.save(os.path.join(FILE_SAVE_PATH, name)) name = ''.join([random.choice(string.ascii_letters + string.digits) for n in range(64)]) if kind == "stl": request.stl = name elif kind == "gcode": request.gcode = name else: return jsonify({'error': "Invalid file kind"}, status.HTTP_400_BAD_REQUEST) file.save(os.path.join(FILE_SAVE_PATH, name)) request.save() add_request_event(request, "Added stl file") add_request_event(request, f'Added {kind} file') return jsonify({'ok': True}) Loading
back/myfab/model.py +1 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ class PrintRequest(Model): description = TextField() author = ForeignKeyField(User) stl = TextField(null=True, default=None) gcode = TextField(null=True, default=None) status = IntegerField(default=0) project = TextField() operator = ForeignKeyField(User, null=True, default=None) Loading