| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 | 
							- from mimetypes import guess_extension
 - from typing import Optional
 - 
 - from flask_restx import Resource, reqparse
 - from flask_restx.api import HTTPStatus
 - from werkzeug.datastructures import FileStorage
 - from werkzeug.exceptions import Forbidden
 - 
 - import services
 - from controllers.common.errors import (
 -     FileTooLargeError,
 -     UnsupportedFileTypeError,
 - )
 - from controllers.console.wraps import setup_required
 - from controllers.files import files_ns
 - from controllers.inner_api.plugin.wraps import get_user
 - from core.file.helpers import verify_plugin_file_signature
 - from core.tools.tool_file_manager import ToolFileManager
 - from fields.file_fields import build_file_model
 - 
 - # Define parser for both documentation and validation
 - upload_parser = reqparse.RequestParser()
 - upload_parser.add_argument("file", location="files", type=FileStorage, required=True, help="File to upload")
 - upload_parser.add_argument(
 -     "timestamp", type=str, required=True, location="args", help="Unix timestamp for signature verification"
 - )
 - upload_parser.add_argument(
 -     "nonce", type=str, required=True, location="args", help="Random string for signature verification"
 - )
 - upload_parser.add_argument(
 -     "sign", type=str, required=True, location="args", help="HMAC signature for request validation"
 - )
 - upload_parser.add_argument("tenant_id", type=str, required=True, location="args", help="Tenant identifier")
 - upload_parser.add_argument("user_id", type=str, required=False, location="args", help="User identifier")
 - 
 - 
 - @files_ns.route("/upload/for-plugin")
 - class PluginUploadFileApi(Resource):
 -     @setup_required
 -     @files_ns.expect(upload_parser)
 -     @files_ns.doc("upload_plugin_file")
 -     @files_ns.doc(description="Upload a file for plugin usage with signature verification")
 -     @files_ns.doc(
 -         responses={
 -             201: "File uploaded successfully",
 -             400: "Invalid request parameters",
 -             403: "Forbidden - Invalid signature or missing parameters",
 -             413: "File too large",
 -             415: "Unsupported file type",
 -         }
 -     )
 -     @files_ns.marshal_with(build_file_model(files_ns), code=HTTPStatus.CREATED)
 -     def post(self):
 -         """Upload a file for plugin usage.
 - 
 -         Accepts a file upload with signature verification for security.
 -         The file must be accompanied by valid timestamp, nonce, and signature parameters.
 - 
 -         Returns:
 -             dict: File metadata including ID, URLs, and properties
 -             int: HTTP status code (201 for success)
 - 
 -         Raises:
 -             Forbidden: Invalid signature or missing required parameters
 -             FileTooLargeError: File exceeds size limit
 -             UnsupportedFileTypeError: File type not supported
 -         """
 -         # Parse and validate all arguments
 -         args = upload_parser.parse_args()
 - 
 -         file: FileStorage = args["file"]
 -         timestamp: str = args["timestamp"]
 -         nonce: str = args["nonce"]
 -         sign: str = args["sign"]
 -         tenant_id: str = args["tenant_id"]
 -         user_id: Optional[str] = args.get("user_id")
 -         user = get_user(tenant_id, user_id)
 - 
 -         filename: Optional[str] = file.filename
 -         mimetype: Optional[str] = file.mimetype
 - 
 -         if not filename or not mimetype:
 -             raise Forbidden("Invalid request.")
 - 
 -         if not verify_plugin_file_signature(
 -             filename=filename,
 -             mimetype=mimetype,
 -             tenant_id=tenant_id,
 -             user_id=user_id,
 -             timestamp=timestamp,
 -             nonce=nonce,
 -             sign=sign,
 -         ):
 -             raise Forbidden("Invalid request.")
 - 
 -         try:
 -             tool_file = ToolFileManager().create_file_by_raw(
 -                 user_id=user.id,
 -                 tenant_id=tenant_id,
 -                 file_binary=file.read(),
 -                 mimetype=mimetype,
 -                 filename=filename,
 -                 conversation_id=None,
 -             )
 - 
 -             extension = guess_extension(tool_file.mimetype) or ".bin"
 -             preview_url = ToolFileManager.sign_file(tool_file_id=tool_file.id, extension=extension)
 - 
 -             # Create a dictionary with all the necessary attributes
 -             result = {
 -                 "id": tool_file.id,
 -                 "user_id": tool_file.user_id,
 -                 "tenant_id": tool_file.tenant_id,
 -                 "conversation_id": tool_file.conversation_id,
 -                 "file_key": tool_file.file_key,
 -                 "mimetype": tool_file.mimetype,
 -                 "original_url": tool_file.original_url,
 -                 "name": tool_file.name,
 -                 "size": tool_file.size,
 -                 "mime_type": mimetype,
 -                 "extension": extension,
 -                 "preview_url": preview_url,
 -             }
 - 
 -             return result, 201
 -         except services.errors.file.FileTooLargeError as file_too_large_error:
 -             raise FileTooLargeError(file_too_large_error.description)
 -         except services.errors.file.UnsupportedFileTypeError:
 -             raise UnsupportedFileTypeError()
 
 
  |