def delete_envelope_by_uuid(uuid): """json route for deleting an envelope, expects envelope.uuid """ try: data = request.json # check supplier password if not db_session.query(exists().where( \ and_(Supplier.id == data["supplier_id"], \ Supplier.password == data["password"]))).scalar(): return jsonify({"failed": True, "invalid_password": True}) # if there are any parts that have this envelope, delete their relationship for part, _ in db_session.query(Part, Envelope).join(Envelope) \ .filter(Envelope.uuid == uuid).all(): part.envelope = None db_session.flush() delete_envelope(find_envelope(uuid)) return jsonify({"failed": False, \ "envelope_html": render_template("envelope_table.html", envelope=None)}) except: return jsonify({"failed": True, "error_message": stacktrace()})
def create_part(): """json route for creating a new part, expects a simple object containing the fields in the Part data model. """ data = request.json response_data = {} response_data["incorrect_password"] = not \ supplier_password_is_correct(data["supplier_id"], data["password"]) if response_data["incorrect_password"]: return jsonify(response_data) try: part = Part() # read off the fields from the posted data and set the new part's attributes for col in Part.__table__.columns: if col.key != "id": if col.key in data: setattr(part, col.key, data[col.key]) part.categories = [category for category in db_session.query(Category) \ if str(category.id) in data["categories"] ] supplier = db_session.query(Supplier).filter( Supplier.id == data["supplier_id"]).one() assert not part.blockchain or supplier.blockchain, "The supplier '" + supplier.name \ + "' is not registered with the blockchain network. None of its" \ + " software parts can be registered with the network." # call the ledger service to add this part and its relations to the blockchain if part.blockchain: part.save_to_blockchain() for category in part.categories: save_part_category_relation(part, category) save_part_supplier_relation(part, supplier) db_session.add(part) db_session.flush() db_session.commit() response_data["failed"] = False response_data["part_id"] = part.id except (APIError, AssertionError) as error: response_data["failed"] = True response_data["error_message"] = str(error) except: response_data["failed"] = True response_data["error_message"] = stacktrace() return jsonify(response_data)
def edit_part(): """json route for editing a part """ data = request.json response_data = {} # validate supplier password response_data["incorrect_password"] = \ not supplier_password_is_correct(data["supplier_id"], data["password"]) if response_data["incorrect_password"]: return jsonify(response_data) # make sure that the part exists part_query = db_session.query(Part).filter(Part.id == data["part_id"]) response_data["part_exists"] = (part_query.count() == 1) if not response_data["part_exists"]: return jsonify(response_data) # update the part try: part = part_query.one() for col in Part.__table__.columns: if col.key != "id": if col.key in data: setattr(part, col.key, data[col.key]) # update the categories if "categories" in data: part.categories = [category for category in db_session.query(Category).all() \ if category.id in data["categories"] ] db_session.flush() db_session.commit() response_data["failed"] = False except: response_data["failed"] = True response_data["error_message"] = stacktrace() return jsonify(response_data)
def delete_part(): """json route for deleting a part. expects part_id. """ response_data = {} data = request.json # validate supplier password response_data["incorrect_password"] = \ not supplier_password_is_correct(data["supplier_id"], data["password"]) if response_data["incorrect_password"]: return jsonify(response_data) # make sure that the part exists part_query = db_session.query(Part).filter(Part.id == data["part_id"]) response_data["part_exists"] = (part_query.count() == 1) if not response_data["part_exists"]: return jsonify(response_data) try: part = part_query.one() db_session.delete(part) db_session.flush() if part.envelope: delete_envelope(part.envelope) db_session.commit() response_data["failed"] = False except: response_data["failed"] = True response_data["error_message"] = stacktrace() return jsonify(response_data)
def create_supplier(): """json route for creating a new supplier. expects a simple object containing the fields in the Supplier data model. """ response_data = {"failed": False} try: data = request.json assert "supplier_name" in data, "Bad call, missing required 'supplier_name'." assert "password" in data, "Bad call, missing required 'password'." supplier_name = data["supplier_name"] pwd = data["password"] assert not db_session.query(exists().where(Supplier.name == supplier_name)).scalar(), \ "Another supplier with this name already exists." supplier = Supplier() supplier.name = supplier_name supplier.password = pwd supplier.blockchain = data["blockchain"] # call the ledger service to add this supplier to the blockchain if supplier.blockchain: supplier.save_to_blockchain() db_session.add(supplier) db_session.flush() db_session.commit() response_data["supplier_table_html"] = render_template("supplier_table.html", \ suppliers=db_session.query(Supplier)) except (APIError, AssertionError) as error: response_data["failed"] = True response_data["error_message"] = str(error) except: response_data["failed"] = True response_data["error_message"] = stacktrace() return jsonify(response_data)
def reset_handler(): """respond to conductor call RESET by purging the database and repopulating with sample data """ response_data = {} try: # clear all the tables for part in db_session.query(Part).all(): part.categories = [] part.envelope = None part.supplier = None db_session.delete(part) db_session.flush() db_session.query(Category).delete() db_session.query(Supplier).delete() for envelope in db_session.query(Envelope).all(): envelope.boms = [] envelope.artifacts = [] db_session.delete(envelope) db_session.flush() for bom in db_session.query(BOM).all(): bom.items = [] bom.artifact = None db_session.delete(bom) db_session.flush() db_session.query(Artifact).delete() db_session.query(BOMItem).delete() db_session.flush() db_session.commit() # delete all envelope and artifact files empty_directory(app.config["UPLOAD_FOLDER"]) empty_directory(app.config["ARTIFACT_FOLDER"]) # insert suppliers for supplier_dict in read_csv_file("suppliers.csv"): supplier = Supplier() supplier.name = supplier_dict["name"] supplier.uuid = supplier_dict["uuid"] supplier.password = hashlib.md5(codecs.encode(supplier_dict["password"], "utf-8"))\ .hexdigest() supplier.blockchain = (supplier_dict["blockchain"] == "true") if supplier.blockchain: supplier.save_to_blockchain() db_session.add(supplier) db_session.flush() # insert categories categories_by_uuid = {} for category_dict in read_csv_file("categories.csv"): category = Category() category.name = category_dict["name"] category.uuid = category_dict["uuid"] category.description = category_dict["description"] db_session.add(category) category.save_to_blockchain() categories_by_uuid[category.uuid] = category db_session.flush() # read part category association table part_category_instances = {} for part_category_relation in read_csv_file("part-categories.csv"): if part_category_relation[ "part_uuid"] not in part_category_instances: part_category_instances[ part_category_relation["part_uuid"]] = [] part_category_instances[part_category_relation["part_uuid"]].append( \ categories_by_uuid[part_category_relation["category_uuid"]]) # insert parts categories = db_session.query(Category).all() for part_dict in read_csv_file("parts.csv"): part = Part() part_supplier_query = db_session.query(Supplier)\ .filter(Supplier.uuid == part_dict["supplier_uuid"]) assert part_supplier_query.count() == 1, \ "Invalid supplier UUID in the following sample part. \n" \ + json.dumps(part_dict) + " Could not find a supplier with UUID '" \ + part_dict["supplier_uuid"] + "'" part.supplier = part_supplier_query.one() part.blockchain = (part_dict["blockchain"] == "true") for field in ["uuid", "usku", "supplier_part_id", "name", "version", \ "licensing", "url", "status", "description", "checksum", "src_uri"]: setattr(part, field, part_dict[field]) if part.uuid in part_category_instances: for category in part_category_instances[part.uuid]: part.categories.append(category) db_session.add(part) if part.blockchain: part.save_to_blockchain() for category in part.categories: save_part_category_relation(part, category) save_part_supplier_relation(part, part.supplier) db_session.flush() # read envelope part association table envelope_parts = {} for envelope_parts_dict in read_csv_file("part-envelopes.csv"): envelope_parts[envelope_parts_dict[ "envelope_uuid"]] = envelope_parts_dict["part_uuid"] # unpack and parse envelopes for envelope_path in glob.glob(\ os.path.join(app.config["SAMPLE_DATA_FOLDER"], "envelopes/*")): envelope = create_envelope(envelope_path) part_query = db_session.query(Part).filter( Part.uuid == envelope_parts[envelope.uuid]) assert part_query.count() == 1, \ "Invalid sample data. No part was found with UUID " + envelope_parts[envelope.uuid] part = part_query.one() part.envelope = envelope envelope.blockchain = part.blockchain if envelope.blockchain: envelope.save_to_blockchain() save_part_envelope_relation(part, envelope) db_session.flush() db_session.commit() response_data["status"] = "success" except AssertionError as error: response_data["status"] = "failed" response_data["error_message"] = str(error) except APIError as error: response_data["status"] = "failed" response_data["error_message"] = "Encountered an error while calling blockchain API. " \ + str(error) except (OSError, IOError): response_data["status"] = "failed" response_data["error_message"] = stacktrace() except: response_data["status"] = "failed" response_data[ "error_message"] = "Unhandled Exception \n\n" + stacktrace() return jsonify(response_data)
def ping_handler(): """respond to a simple "ping" request, indicating whether this app (sparts catalog) is running """ return jsonify({"status": "success"})
def upload_envelope(): """route for uploading an envelope file""" response_data = {} # compute a unique, random extract path directory name baseed on time base_dirname = hashlib.sha1( codecs.encode(str(datetime.datetime.now()), "utf-8")).hexdigest() base_path = os.path.join(app.config["UPLOAD_FOLDER"], base_dirname) try: assert "envelope" in request.files, "Envelope file was not submitted" file = request.files["envelope"] assert file.filename != "", "No file was selected" filename = secure_filename(file.filename) file_path = os.path.join(base_path, filename) extract_path = os.path.join(base_path, "envelope") assert not os.path.exists(base_path), \ "Could not create unique directory to extract envelope files." + \ " Please try again later." try: os.makedirs(extract_path) except: raise EnvelopeError( "Failed to create directory to extract envelope") file.save(file_path) # to ensure atomic operation on this file os.rename(file_path, file_path) assert "part_id" in request.args, "Invalid request, part_id was missing." part_query = db_session.query(Part).filter( Part.id == request.args["part_id"]) assert part_query.count( ) == 1, "Part no longer existed in the database." part = part_query.one() envelope = extract_and_parse_envelope(file_path, extract_path) envelope.blockchain = part.blockchain part.envelope_id = envelope.id db_session.flush() db_session.commit() #remove zip file os.remove(file_path) response_data["successfully_uploaded"] = True response_data["envelope_html"] = render_template("envelope_table.html", envelope=envelope) except (AssertionError, EnvelopeError) as error: response_data["error_message"] = str(error) except: response_data["error_message"] = stacktrace() # delete the extracted files in case something went wrong if "error_message" in response_data: shutil.rmtree(base_path) return jsonify(response_data)