files-server-fastapi 0.1.6__tar.gz → 0.1.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/PKG-INFO +1 -1
  2. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/pyproject.toml +1 -1
  3. files_server_fastapi-0.1.7/src/files_server_fastapi/files/acls_router.py +98 -0
  4. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/files/dependencies.py +12 -2
  5. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/files/folder_router.py +1 -1
  6. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/files/list_router.py +1 -0
  7. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/.gitignore +0 -0
  8. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/.python-version +0 -0
  9. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/LICENSE +0 -0
  10. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/MANIFEST.in +0 -0
  11. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/README.md +0 -0
  12. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/__init__.py +0 -0
  13. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/files/__init__.py +0 -0
  14. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/files/constants.py +0 -0
  15. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/files/download_router.py +0 -0
  16. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/files/open_url_router.py +0 -0
  17. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/files/tree_router.py +0 -0
  18. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/files/upload_router.py +0 -0
  19. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/models/__init__.py +0 -0
  20. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/models/area_model.py +0 -0
  21. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/models/permisos_model.py +0 -0
  22. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/models/rol_model.py +0 -0
  23. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/models/rutas_model.py +0 -0
  24. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/models/users_extend_model.py +0 -0
  25. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/routers/__init__.py +0 -0
  26. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/routers/area_router.py +0 -0
  27. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/routers/files_router.py +0 -0
  28. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/routers/permisos_router.py +0 -0
  29. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/routers/rol_router.py +0 -0
  30. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/routers/rutas_router.py +0 -0
  31. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/src/files_server_fastapi/routers/users_extend_router.py +0 -0
  32. {files_server_fastapi-0.1.6 → files_server_fastapi-0.1.7}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: files-server-fastapi
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: Este repositorio es un paquete python desarrollado con FastAPI, gestiona la comunicación con un servidor Samba y utiliza PostgreSQL para administrar rutas de archivos y el control de acceso basado en roles (RBAC) de los usuarios.
5
5
  Project-URL: Homepage, https://github.com/AldoBP/files-server-fastapi
6
6
  Project-URL: Repository, https://github.com/AldoBP/files-server-fastapi
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "files-server-fastapi"
3
- version = "0.1.6"
3
+ version = "0.1.7"
4
4
  description = "Este repositorio es un paquete python desarrollado con FastAPI, gestiona la comunicación con un servidor Samba y utiliza PostgreSQL para administrar rutas de archivos y el control de acceso basado en roles (RBAC) de los usuarios."
5
5
  readme = "README.md"
6
6
  license = { file = "LICENSE" }
@@ -0,0 +1,98 @@
1
+ import os
2
+ from fastapi import APIRouter, Depends, HTTPException, status
3
+ from pydantic import BaseModel
4
+ from sqlalchemy.ext.asyncio import AsyncSession
5
+ from sqlalchemy import select
6
+
7
+ from pgsqlasync2fast_fastapi.dependencies import get_db_session
8
+ from oauth2fast_fastapi import get_current_user, User
9
+ from files_server_fastapi.models.permisos_model import User_Ruta_Access
10
+ from files_server_fastapi.models.rutas_model import Rutas
11
+ from files_server_fastapi.models.area_model import Area
12
+
13
+ router = APIRouter()
14
+
15
+ class AclDetail(BaseModel):
16
+ path: str
17
+ permission: str
18
+
19
+ class AclCreate(BaseModel):
20
+ area: str
21
+ user_id: int
22
+ acls: list[AclDetail]
23
+
24
+ @router.post("/acls", summary="Asignar acceso a una carpeta específica (ACL)")
25
+ async def create_acl(
26
+ req: AclCreate,
27
+ current_user: User = Depends(get_current_user),
28
+ db: AsyncSession = Depends(get_db_session)
29
+ ):
30
+ """
31
+ Crea o actualiza los accesos (ACLs) enviados desde el frontend.
32
+ """
33
+ # 0. Validar que el usuario existe en la BD
34
+ user_result = await db.execute(select(User).where(User.id == req.user_id))
35
+ if not user_result.scalars().first():
36
+ raise HTTPException(status_code=404, detail=f"El usuario con ID {req.user_id} no existe en la base de datos.")
37
+
38
+ # 1. Verificar si el Área existe para crear la Ruta adecuadamente
39
+ area_result = await db.execute(select(Area).where(Area.area_name.ilike(req.area)))
40
+ area_obj = area_result.scalars().first()
41
+ if not area_obj:
42
+ raise HTTPException(status_code=404, detail=f"Área '{req.area}' no encontrada")
43
+
44
+ processed_acls = []
45
+
46
+ for acl_item in req.acls:
47
+ # Limpiar subpath y contruir ruta lógica completa
48
+ subpath = acl_item.path.strip("/")
49
+ logical_path_full = f"/{req.area.upper()}/{subpath}".replace("//", "/")
50
+
51
+ parts = logical_path_full.strip("/").split("/")
52
+ folder_name = parts[-1] if len(parts) > 0 else req.area.upper()
53
+
54
+ # Mapear permisos del Frontend ("EDITOR" / "VIEWER") a tipos de DB ("allow_write" / "allow_read")
55
+ db_access_type = "allow_read" # Por defecto
56
+ if acl_item.permission.upper() == "EDITOR":
57
+ db_access_type = "allow_write"
58
+ elif acl_item.permission.upper() == "DENY":
59
+ db_access_type = "deny_all"
60
+
61
+ # 2. Buscar si la ruta ya existe en la tabla Rutas
62
+ ruta_result = await db.execute(select(Rutas).where(Rutas.ruta == logical_path_full))
63
+ ruta_obj = ruta_result.scalars().first()
64
+
65
+ # Si no existe, crearla
66
+ if not ruta_obj:
67
+ ruta_obj = Rutas(
68
+ ruta=logical_path_full,
69
+ name=folder_name,
70
+ area_id=area_obj.id
71
+ )
72
+ db.add(ruta_obj)
73
+ await db.commit()
74
+ await db.refresh(ruta_obj)
75
+
76
+ # 3. Asignar el ACL en User_Ruta_Access
77
+ acl_result = await db.execute(
78
+ select(User_Ruta_Access)
79
+ .where(User_Ruta_Access.user_id == req.user_id)
80
+ .where(User_Ruta_Access.ruta_id == ruta_obj.id)
81
+ )
82
+ existing_acl = acl_result.scalars().first()
83
+
84
+ if existing_acl:
85
+ existing_acl.access_type = db_access_type
86
+ processed_acls.append(existing_acl.id)
87
+ else:
88
+ new_acl = User_Ruta_Access(
89
+ user_id=req.user_id,
90
+ ruta_id=ruta_obj.id,
91
+ access_type=db_access_type
92
+ )
93
+ db.add(new_acl)
94
+ await db.commit()
95
+ await db.refresh(new_acl)
96
+ processed_acls.append(new_acl.id)
97
+
98
+ return {"message": "ACLs asignados correctamente", "processed_acls": processed_acls}
@@ -21,14 +21,24 @@ async def check_folder_access(
21
21
  Verifica si el usuario actual tiene acceso al área y subpath indicados.
22
22
  required_access: 'allow_read' (por defecto) o 'allow_write'
23
23
  """
24
- # 1. Obtener extensión de usuario y verificar pertenencia al área
24
+ # 1. Obtener extensión de usuario y verificar roles/áreas
25
25
  result_ext = await db.execute(
26
26
  select(Users_extend).where(Users_extend.user_id == current_user.id)
27
27
  )
28
28
  user_exts = result_ext.scalars().all()
29
+
30
+ # 2. Verificar si el usuario es SUPER_ADMIN en cualquier área
31
+ for ext in user_exts:
32
+ res_rol = await db.execute(select(Rol).where(Rol.id == ext.rol_id))
33
+ rol = res_rol.scalars().first()
34
+ if rol and rol.role_name.upper() == "SUPER_ADMIN":
35
+ return True # SUPER_ADMIN tiene acceso universal a todas las carpetas, salta otras validaciones.
29
36
 
37
+ # 3. Si no es SUPER_ADMIN, verificar pertenencia al área indicada
30
38
  area_obj = None
31
39
  user_ext_match = None
40
+ rol_name = ""
41
+
32
42
  for ext in user_exts:
33
43
  res_area = await db.execute(select(Area).where(Area.id == ext.area_id))
34
44
  a = res_area.scalars().first()
@@ -40,7 +50,7 @@ async def check_folder_access(
40
50
  if not area_obj or not user_ext_match:
41
51
  raise HTTPException(status_code=403, detail="No perteneces a esta área")
42
52
 
43
- # Obtener el Rol Base del usuario en esta área
53
+ # Obtener el Rol Base del usuario en ESTA área específica
44
54
  res_rol = await db.execute(select(Rol).where(Rol.id == user_ext_match.rol_id))
45
55
  rol_obj = res_rol.scalars().first()
46
56
  rol_name = rol_obj.role_name.lower() if rol_obj else ""
@@ -29,7 +29,7 @@ async def create_folder(
29
29
 
30
30
  safe_subpath = req.subpath.strip("/")
31
31
  ruta_final = os.path.join(BASE_DIR, req.area.upper(), safe_subpath, req.folder_name) if safe_subpath else os.path.join(BASE_DIR, req.area.upper(), req.folder_name)
32
-
32
+ print(ruta_final)
33
33
  try:
34
34
  os.makedirs(ruta_final, exist_ok=False)
35
35
  return {"message": "Carpeta creada exitosamente", "path": ruta_final}
@@ -19,6 +19,7 @@ async def list_directory(
19
19
 
20
20
  safe_subpath = subpath.strip("/")
21
21
  ruta_real = os.path.join(BASE_DIR, area.upper(), safe_subpath) if safe_subpath else os.path.join(BASE_DIR, area.upper())
22
+ print(ruta_real)
22
23
 
23
24
  if not os.path.exists(ruta_real):
24
25
  return []