299 lines
9.2 KiB
Plaintext
299 lines
9.2 KiB
Plaintext
Module FileSystem
|
|
EnableExplicit
|
|
|
|
; Private constants
|
|
#BlobsDir = "blobs/"
|
|
|
|
;- Helpers
|
|
Procedure CanAccess(UserID, NodeID)
|
|
Protected OwnerID = Database::FSGetOwner(NodeID)
|
|
ProcedureReturn Bool(OwnerID = UserID Or OwnerID = 0)
|
|
EndProcedure
|
|
|
|
Procedure ResolveFromQuery(*Request, UserID)
|
|
Protected IDStr.s = General::GetQueryField(*Request, "id")
|
|
If IDStr <> "" : ProcedureReturn Val(IDStr) : EndIf
|
|
ProcedureReturn Database::FSResolve(UserID, General::GetQueryField(*Request, "path"))
|
|
EndProcedure
|
|
|
|
Procedure ResolveFromPost(*Request, UserID)
|
|
Protected IDStr.s = General::GetPostField(*Request, "id")
|
|
If IDStr <> "" : ProcedureReturn Val(IDStr) : EndIf
|
|
ProcedureReturn Database::FSResolve(UserID, General::GetPostField(*Request, "path"))
|
|
EndProcedure
|
|
|
|
Procedure ResolveParent(UserID, Path.s)
|
|
While Right(Path, 1) = "/" : Path = Left(Path, Len(Path) - 1) : Wend
|
|
ProcedureReturn Database::FSResolve(UserID, Path)
|
|
EndProcedure
|
|
|
|
;- Public procedures
|
|
|
|
; GET /api/fs/list?path=... or ?id=...
|
|
Procedure HandleList(*Request)
|
|
Protected UserID, NodeID
|
|
Protected Username.s
|
|
|
|
Username = Auth::GetSessionUser(*Request)
|
|
If Username = ""
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Unauthorized\"}", "401 Unauthorized")
|
|
ProcedureReturn
|
|
EndIf
|
|
UserID = Database::FindUser(Username)
|
|
NodeID = ResolveFromQuery(*Request, UserID)
|
|
|
|
If NodeID = 0
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Not found\"}", "404 Not Found")
|
|
ProcedureReturn
|
|
EndIf
|
|
If Not CanAccess(UserID, NodeID)
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Forbidden\"}", "403 Forbidden")
|
|
ProcedureReturn
|
|
EndIf
|
|
|
|
General::RespondJSON(*Request, Database::FSList(NodeID))
|
|
EndProcedure
|
|
|
|
; GET /api/fs/stat?path=... or ?id=...
|
|
Procedure HandleStat(*Request)
|
|
Protected UserID, NodeID
|
|
Protected Username.s, Stat.s
|
|
|
|
Username = Auth::GetSessionUser(*Request)
|
|
If Username = ""
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Unauthorized\"}", "401 Unauthorized")
|
|
ProcedureReturn
|
|
EndIf
|
|
UserID = Database::FindUser(Username)
|
|
NodeID = ResolveFromQuery(*Request, UserID)
|
|
|
|
If NodeID = 0
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Not found\"}", "404 Not Found")
|
|
ProcedureReturn
|
|
EndIf
|
|
If Not CanAccess(UserID, NodeID)
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Forbidden\"}", "403 Forbidden")
|
|
ProcedureReturn
|
|
EndIf
|
|
|
|
Stat = Database::FSStat(NodeID)
|
|
If Stat = ""
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Not found\"}", "404 Not Found")
|
|
Else
|
|
General::RespondJSON(*Request, Stat)
|
|
EndIf
|
|
EndProcedure
|
|
|
|
; GET /api/fs/read?path=... or ?id=...
|
|
Procedure HandleRead(*Request)
|
|
Protected UserID, NodeID
|
|
Protected IsDir.Integer
|
|
Protected Username.s
|
|
|
|
Username = Auth::GetSessionUser(*Request)
|
|
If Username = ""
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Unauthorized\"}", "401 Unauthorized")
|
|
ProcedureReturn
|
|
EndIf
|
|
UserID = Database::FindUser(Username)
|
|
NodeID = ResolveFromQuery(*Request, UserID)
|
|
|
|
If NodeID = 0
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Not found\"}", "404 Not Found")
|
|
ProcedureReturn
|
|
EndIf
|
|
If Not CanAccess(UserID, NodeID)
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Forbidden\"}", "403 Forbidden")
|
|
ProcedureReturn
|
|
EndIf
|
|
|
|
Database::FSGetOwner(NodeID, @IsDir)
|
|
If IsDir\i
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Is a directory\"}", "400 Bad Request")
|
|
ProcedureReturn
|
|
EndIf
|
|
|
|
If Not FastCGI::RespondFile(*Request, #BlobsDir + NodeID)
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Blob missing\"}", "404 Not Found")
|
|
EndIf
|
|
EndProcedure
|
|
|
|
; POST /api/fs/write body: path=...&content=... [&mime_type=...]
|
|
Procedure HandleWrite(*Request)
|
|
Protected UserID, ParentID, NodeID, FileID, BufLen, Size, *Buf
|
|
Protected Username.s, Path.s, Content.s, MimeType.s
|
|
|
|
Username = Auth::GetSessionUser(*Request)
|
|
If Username = ""
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Unauthorized\"}", "401 Unauthorized")
|
|
ProcedureReturn
|
|
EndIf
|
|
UserID = Database::FindUser(Username)
|
|
Path = General::GetPostField(*Request, "path")
|
|
Content = General::GetPostField(*Request, "content")
|
|
MimeType = General::GetPostField(*Request, "mime_type")
|
|
|
|
If Path = ""
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Missing path\"}")
|
|
ProcedureReturn
|
|
EndIf
|
|
If MimeType = "" : MimeType = "text/plain" : EndIf
|
|
|
|
ParentID = ResolveParent(UserID, GetPathPart(Path))
|
|
If ParentID = 0
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Parent directory not found\"}", "404 Not Found")
|
|
ProcedureReturn
|
|
EndIf
|
|
If Not CanAccess(UserID, ParentID)
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Forbidden\"}", "403 Forbidden")
|
|
ProcedureReturn
|
|
EndIf
|
|
|
|
NodeID = Database::FSResolve(UserID, Path)
|
|
If NodeID = 0
|
|
NodeID = Database::FSCreateFile(UserID, ParentID, GetFilePart(Path), MimeType)
|
|
EndIf
|
|
If NodeID = 0
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Could not create node\"}", "500 Internal Server Error")
|
|
ProcedureReturn
|
|
EndIf
|
|
|
|
FileID = CreateFile(#PB_Any, #BlobsDir + NodeID)
|
|
If FileID
|
|
BufLen = StringByteLength(Content, #PB_UTF8)
|
|
If BufLen > 0
|
|
*Buf = AllocateMemory(BufLen)
|
|
If *Buf
|
|
PokeS(*Buf, Content, -1, #PB_UTF8 | #PB_String_NoZero)
|
|
WriteData(FileID, *Buf, BufLen)
|
|
FreeMemory(*Buf)
|
|
EndIf
|
|
EndIf
|
|
Size = Lof(FileID)
|
|
CloseFile(FileID)
|
|
Database::FSUpdateFile(NodeID, Size)
|
|
General::RespondJSON(*Request, ~"{\"success\":true,\"id\":" + NodeID + "}")
|
|
Else
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Could not write blob\"}", "500 Internal Server Error")
|
|
EndIf
|
|
EndProcedure
|
|
|
|
; POST /api/fs/mkdir body: path=...
|
|
Procedure HandleMkdir(*Request)
|
|
Protected UserID, ParentID, DirID
|
|
Protected Username.s, Path.s
|
|
|
|
Username = Auth::GetSessionUser(*Request)
|
|
If Username = ""
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Unauthorized\"}", "401 Unauthorized")
|
|
ProcedureReturn
|
|
EndIf
|
|
UserID = Database::FindUser(Username)
|
|
Path = General::GetPostField(*Request, "path")
|
|
|
|
If Path = ""
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Missing path\"}")
|
|
ProcedureReturn
|
|
EndIf
|
|
|
|
ParentID = ResolveParent(UserID, GetPathPart(Path))
|
|
If ParentID = 0
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Parent not found\"}", "404 Not Found")
|
|
ProcedureReturn
|
|
EndIf
|
|
If Not CanAccess(UserID, ParentID)
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Forbidden\"}", "403 Forbidden")
|
|
ProcedureReturn
|
|
EndIf
|
|
|
|
DirID = Database::FSMkdir(UserID, ParentID, GetFilePart(Path))
|
|
If DirID = 0
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Already exists or could not create\"}", "409 Conflict")
|
|
Else
|
|
General::RespondJSON(*Request, ~"{\"success\":true,\"id\":" + DirID + "}")
|
|
EndIf
|
|
EndProcedure
|
|
|
|
; POST /api/fs/delete body: path=... or id=...
|
|
Procedure HandleDelete(*Request)
|
|
Protected UserID, NodeID, OwnerID
|
|
Protected IsDir.Integer
|
|
Protected Username.s
|
|
|
|
Username = Auth::GetSessionUser(*Request)
|
|
If Username = ""
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Unauthorized\"}", "401 Unauthorized")
|
|
ProcedureReturn
|
|
EndIf
|
|
UserID = Database::FindUser(Username)
|
|
NodeID = ResolveFromPost(*Request, UserID)
|
|
|
|
If NodeID = 0
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Not found\"}", "404 Not Found")
|
|
ProcedureReturn
|
|
EndIf
|
|
|
|
OwnerID = Database::FSGetOwner(NodeID, @IsDir)
|
|
If OwnerID <> UserID
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Forbidden\"}", "403 Forbidden")
|
|
ProcedureReturn
|
|
EndIf
|
|
|
|
If Not IsDir\i : DeleteFile(#BlobsDir + NodeID) : EndIf
|
|
|
|
Database::FSDelete(NodeID)
|
|
General::RespondJSON(*Request, ~"{\"success\":true}")
|
|
EndProcedure
|
|
|
|
; POST /api/fs/move body: path=...&to=... or id=...&to_parent_id=...&name=...
|
|
Procedure HandleMove(*Request)
|
|
Protected UserID, NodeID, NewParentID, OwnerID
|
|
Protected IsDir.Integer
|
|
Protected Username.s, IDStr.s, NewName.s, FromPath.s, ToPath.s
|
|
|
|
Username = Auth::GetSessionUser(*Request)
|
|
If Username = ""
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Unauthorized\"}", "401 Unauthorized")
|
|
ProcedureReturn
|
|
EndIf
|
|
UserID = Database::FindUser(Username)
|
|
IDStr = General::GetPostField(*Request, "id")
|
|
|
|
If IDStr <> ""
|
|
NodeID = Val(IDStr)
|
|
NewParentID = Val(General::GetPostField(*Request, "to_parent_id"))
|
|
NewName = General::GetPostField(*Request, "name")
|
|
Else
|
|
FromPath = General::GetPostField(*Request, "path")
|
|
ToPath = General::GetPostField(*Request, "to")
|
|
NodeID = Database::FSResolve(UserID, FromPath)
|
|
NewParentID = ResolveParent(UserID, GetPathPart(ToPath))
|
|
NewName = GetFilePart(ToPath)
|
|
EndIf
|
|
|
|
If NodeID = 0 Or NewParentID = 0 Or NewName = ""
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Not found\"}", "404 Not Found")
|
|
ProcedureReturn
|
|
EndIf
|
|
|
|
OwnerID = Database::FSGetOwner(NodeID, @IsDir)
|
|
If OwnerID <> UserID
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Forbidden\"}", "403 Forbidden")
|
|
ProcedureReturn
|
|
EndIf
|
|
If Not CanAccess(UserID, NewParentID)
|
|
General::RespondJSON(*Request, ~"{\"error\":\"Forbidden\"}", "403 Forbidden")
|
|
ProcedureReturn
|
|
EndIf
|
|
|
|
Database::FSMove(NodeID, NewParentID, NewName)
|
|
General::RespondJSON(*Request, ~"{\"success\":true}")
|
|
EndProcedure
|
|
|
|
EndModule
|
|
|
|
; IDE Options = PureBasic 6.30 (Windows - x64)
|
|
; CursorPosition = 2
|
|
; Folding = BA-
|
|
; EnableXP
|
|
; DPIAware |