Example #1
0
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()})
Example #2
0
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)
Example #3
0
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)
Example #4
0
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)
Example #5
0
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)
Example #6
0
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)
Example #7
0
def ping_handler():
    """respond to a simple "ping" request, indicating whether this app (sparts catalog) is running
    """
    return jsonify({"status": "success"})
Example #8
0
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)