File size: 2,814 Bytes
01d5a5d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
from pathlib import Path
import os
from typing import Union
from flask import send_from_directory, jsonify, redirect, Response
from .models import FileItem, DirectoryListing
from ...common.logging import logger


class FileServerHandler:
    def __init__(self, base_dir: str):
        self.base_dir = base_dir
        logger.info(f"Initializing file server with base directory: {base_dir}")

    def handle_request(self, path: str, request_path: str) -> Union[Response, tuple]:
        """Handle file/directory access requests"""
        clean_path = path.rstrip("/")
        full_path = os.path.join(self.base_dir, clean_path)

        # security check
        try:
            Path(full_path).resolve().relative_to(Path(self.base_dir).resolve())
        except ValueError:
            return jsonify({"error": "Access denied"}), 403

        # check type and handle
        if os.path.isfile(full_path):
            return self._handle_file(clean_path, request_path)
        elif os.path.isdir(full_path):
            return self._handle_directory(clean_path, request_path)

        return jsonify({"error": "Not found"}), 404

    def _handle_file(
        self, clean_path: str, request_path: str
    ) -> Union[Response, tuple]:
        """Handle file access"""
        if request_path.endswith("/"):
            return redirect(f"/raw_content/{clean_path}", code=301)
        return send_from_directory(self.base_dir, clean_path, as_attachment=False)

    def _handle_directory(
        self, clean_path: str, request_path: str
    ) -> Union[Response, tuple]:
        """Handle directory access"""
        if not request_path.endswith("/"):
            return redirect(f"/raw_content/{clean_path}/", code=301)
        listing = self._list_directory(clean_path)
        return jsonify(
            listing.model_dump()
        )  # convert Pydantic model to dict, then to JSON response

    def _list_directory(self, path: str) -> DirectoryListing:
        """List directory content"""
        target_dir = os.path.join(self.base_dir, path)

        items = []
        for item in os.scandir(target_dir):
            item_type = "directory" if item.is_dir() else "file"
            item_size = os.path.getsize(item.path) if item.is_file() else None
            file_path = (Path(path) / item.name).as_posix()
            items.append(
                FileItem(
                    name=item.name,
                    type=item_type,
                    size=item_size,
                    path=file_path,
                    url=f"/raw_content/{file_path}"
                    if item.is_file()
                    else None,
                )
            )

        return DirectoryListing(
            current_path=path,
            items=sorted(items, key=lambda x: (x.type == "file", x.name)),
        )