VeuReu commited on
Commit
f0b643a
·
verified ·
1 Parent(s): af8a801

Upload file_manager.py

Browse files
Files changed (1) hide show
  1. storage/files/file_manager.py +152 -0
storage/files/file_manager.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ file_manager.py
3
+
4
+ This module provides the FileManager class, a high-level interface for managing
5
+ files and directories inside a specified media folder. It centralizes common
6
+ operations such as reading, writing, listing, copying, moving, and deleting files,
7
+ ensuring that all actions are safely constrained within the defined root directory.
8
+ The class is designed to simplify file handling logic in larger applications by
9
+ offering a consistent, validated, and extensible API for filesystem interactions.
10
+ """
11
+
12
+ from pathlib import Path
13
+
14
+ class FileManager:
15
+ """
16
+ FileManager is a utility class that encapsulates common filesystem operations
17
+ within a defined media directory. It ensures that all file manipulations remain
18
+ inside the configured root folder and provides helper methods to interact with
19
+ files and subdirectories in a structured, safe, and predictable manner.
20
+
21
+ Typical use cases include managing uploaded media, performing batch operations
22
+ on directory contents, and abstracting filesystem complexity behind a clean API.
23
+ """
24
+
25
+ def __init__(self, media_folder: Path):
26
+ """
27
+ Initialize the FileManager with a specific root directory for all file
28
+ operations.
29
+
30
+ Parameters
31
+ ----------
32
+ media_folder : Path
33
+ The base directory where all file and folder operations will be performed.
34
+ It must be a valid filesystem path. If the directory does not exist, the
35
+ instance will attempt to create it automatically.
36
+
37
+ Raises
38
+ ------
39
+ ValueError
40
+ If the provided media_folder path is not a valid directory or cannot be
41
+ created.
42
+ """
43
+ self.media_folder = Path(media_folder)
44
+
45
+ if not self.media_folder.exists():
46
+ try:
47
+ self.media_folder.mkdir(parents=True)
48
+ except Exception as exc:
49
+ raise ValueError(
50
+ f"Unable to create media folder at: {self.media_folder}"
51
+ ) from exc
52
+
53
+ if not self.media_folder.is_dir():
54
+ raise ValueError(f"Media folder is not a directory: {self.media_folder}")
55
+
56
+
57
+ def upload_file(self, file_handler, destination: Path):
58
+ """
59
+ Upload a file to a target destination inside the media folder.
60
+
61
+ This method takes a file-like object and writes its contents to the
62
+ specified destination within the media folder. The method ensures the path
63
+ remains inside the media folder and creates necessary directories. It
64
+ returns a structured response indicating whether the operation succeeded
65
+ or failed, along with any relevant error message.
66
+
67
+ Parameters
68
+ ----------
69
+ file_handler : file-like object
70
+ A file-like object opened in binary mode that provides a `.read()` method.
71
+ destination : Path
72
+ The relative or absolute path (within the media folder) where the file
73
+ should be saved.
74
+
75
+ Returns
76
+ -------
77
+ dict
78
+ A dictionary with:
79
+ - "operation_success" (bool): True if the file was saved successfully.
80
+ - "error" (str): An empty string on success, or the error message on failure.
81
+
82
+ Raises
83
+ ------
84
+ None
85
+ Any exceptions are captured and returned inside the result dictionary.
86
+ """
87
+ try:
88
+ destination = self.media_folder / destination
89
+ destination = destination.resolve()
90
+
91
+ # Ensure the destination lies inside the media folder
92
+ if self.media_folder not in destination.parents:
93
+ return {
94
+ "operation_success": False,
95
+ "error": "Destination path is outside the media folder."
96
+ }
97
+
98
+ # Create parent directories if needed
99
+ destination.parent.mkdir(parents=True, exist_ok=True)
100
+
101
+ with open(destination, "wb") as f:
102
+ f.write(file_handler.read())
103
+
104
+ return {"operation_success": True, "error": ""}
105
+
106
+ except Exception as exc:
107
+ return {
108
+ "operation_success": False,
109
+ "error": str(exc)
110
+ }
111
+
112
+ def get_file(self, file_path: Path):
113
+ """
114
+ Retrieve a file inside the media folder and return an open file handler.
115
+
116
+ This method receives a path pointing to a file expected to be located
117
+ inside the media folder. If the file exists and is valid, the method
118
+ returns a file handler opened in binary read mode. If the file does not
119
+ exist or the resolved path escapes the media folder, the method returns
120
+ None.
121
+
122
+ Parameters
123
+ ----------
124
+ file_path : Path
125
+ The relative or absolute path to the file within the media folder.
126
+
127
+ Returns
128
+ -------
129
+ file object or None
130
+ A file handler opened in 'rb' mode if the file exists and is accessible.
131
+ Returns None if the file does not exist or the path is invalid.
132
+
133
+ Raises
134
+ ------
135
+ None
136
+ All exceptions are handled internally and result in returning None.
137
+ """
138
+ try:
139
+ target = self.media_folder / file_path
140
+ target = target.resolve()
141
+
142
+ # Ensure the resolved path is inside the media folder
143
+ if self.media_folder not in target.parents:
144
+ return None
145
+
146
+ if not target.exists() or not target.is_file():
147
+ return None
148
+
149
+ return open(target, "rb")
150
+
151
+ except Exception:
152
+ return None