diff --git a/backend/router/spaces.py b/backend/router/spaces.py index f0960db7..264743c7 100644 --- a/backend/router/spaces.py +++ b/backend/router/spaces.py @@ -2,17 +2,19 @@ import uuid import logging +from decimal import Decimal from http import HTTPStatus from flask import jsonify, request, Response, Blueprint from sqlalchemy import not_ -from backend.model import db +from backend.middleware.token_service import jwt_or_api_token_required +from backend.model import db, response from backend.model.api_requests import APIRequests from backend.model.common import update_record from backend.model.space import Space from backend.model.user import User -from backend.service import space_service +from backend.service import space_service, config_service from backend.utils import constant space_bp = Blueprint("space_bp", __name__) @@ -103,3 +105,114 @@ def get_space_detail(wallet_address, name) -> tuple[Response, HTTPStatus]: APIRequests.add_request_record(space.id, requester_adr) return jsonify(space_response), HTTPStatus.OK + + +@space_bp.route("/space/deployment", methods=["POST"]) +@jwt_or_api_token_required +def create_space_deployment(user): + """ + Create a space deployment based on the provided parameters. + + Args: + user: User object representing the authenticated user. + + Returns: + JSON response with status and message. + + Raises: + BadRequest: When required parameters are missing or invalid. + InternalServerError: When an unexpected error occurs. + + """ + + # Initialize a response object with a default status of STATUS_FAILED - Parameters that send to backend by FrondEnd + response = Response(constant.STATUS_FAILED) + + try: + # Parse request parameters + space_name = str(request.form.get("space_name")) + paid = Decimal(request.form.get("paid")) + duration = int(request.form.get("duration")) + tx_hash = str(request.form.get("tx_hash")) + chain_id = int(request.form.get("chain_id")) + cfg_name = str(request.form.get("cfg_name")) + region = str(request.form.get("region")) + start_in = int(request.form.get("start_in")) + except: + # Handle missing or invalid parameters + response.message = "Required more parameters or parameters are missing." + return jsonify(response.to_dict()), HTTPStatus.BAD_REQUEST + else: + try: + # Get the space by name + try: + space = space_service.get_space_by_name(user, space_name) + except Exception: + response.message = "Can not get space for this user." + return jsonify(response.to_dict()), HTTPStatus.BAD_REQUEST + else: + if space is None: + response.message = "No space could be found for this payment." + return jsonify(response.to_dict()), HTTPStatus.BAD_REQUEST + + # Check if duration is provided + if duration is None: + response.message = "No provided duration." + return jsonify(response.to_dict()), HTTPStatus.BAD_REQUEST + + # Check if payment amount is provided + if paid is None: + response.message = "No provided payment amount." + return jsonify(response.to_dict()), HTTPStatus.BAD_REQUEST + + if paid > 0: + # Check if transaction hash, chain id, config name, and region are provided + if not tx_hash: + response.message = "No provided transaction hash." + return jsonify(response.to_dict()), HTTPStatus.BAD_REQUEST + + if not chain_id: + response.message = "No provided chain id." + return jsonify(response.to_dict()), HTTPStatus.BAD_REQUEST + + if not cfg_name: + response.message = "No provided config." + return jsonify(response.to_dict()), HTTPStatus.BAD_REQUEST + + if not region: + response.message = "Region not provided." + return jsonify(response.to_dict()), HTTPStatus.BAD_REQUEST + + # Get the config by name + cfg = config_service.get_config_by_name(cfg_name) + if cfg is None: + response.message = "Invalid config name." + return jsonify(response.to_dict()), HTTPStatus.BAD_REQUEST + + # Create space config order, payment, and deployment request + config_order = space_service.save_space_config_order(space, cfg, duration, region, start_in) + payment = space_service.create_space_payment(tx_hash, chain_id, paid, user, config_order) + deployment_request = space_service.create_deployment_request( + tx_hash, chain_id, space, config_order, user, payment, start_in + ) + response.message = "Deployment request created. Waiting for payment to complete before deploying." + response.data = {"payment": payment.to_dict(), "deployment_request": deployment_request.to_dict()} + response.status = constant.STATUS_SUCCESS + return jsonify(response.to_dict()), HTTPStatus.OK + else: + # If no payment was made, deploy with free config + cfg = config_service.get_config_by_name("C1ae.small") + config_order = space_service.save_space_config_order(space, cfg, duration, region, start_in) + space, task = space_service.deploy_space_service(space, config_order, user, duration) + response.message = "Free Tier deployment created." + response.data = {"space": space.to_dict(), "task": task.to_dict()} + response.status = constant.STATUS_SUCCESS + return jsonify(response.to_dict()), HTTPStatus.OK + except Exception as err: + # Return Internal Error if any issue comesup + logging.info( + f"Error during space deployment by user id:{user.id} Error: {str(err)} \n" + traceback.format_exc() + ) + response.message = "Error during space deployment." + response.status = "error" + return jsonify(response.to_dict()), HTTPStatus.INTERNAL_SERVER_ERROR