codex: Start showing archives for user
Currently only under group/user, since most archive access is only gained through the group.
This commit is contained in:
@@ -97,7 +97,8 @@ type Archives =
|
||||
| Ok archives ->
|
||||
setArchives archives
|
||||
setError None
|
||||
| Error err -> setError (Some "Error fetching archives")
|
||||
| Error err ->
|
||||
setError (Some "Error fetching archives")
|
||||
|
||||
setLoading false
|
||||
)
|
||||
@@ -196,4 +197,4 @@ type Archives =
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
@@ -5,6 +5,7 @@ module Utils =
|
||||
open Fable.Core
|
||||
open Fable.Core.JsInterop
|
||||
open Fable.Remoting.Client
|
||||
open FsToolkit.ErrorHandling
|
||||
|
||||
open Oceanbox.Codex
|
||||
open Oceanbox.Codex.Types
|
||||
@@ -71,3 +72,52 @@ module Utils =
|
||||
return Error "Error fetching archive count"
|
||||
}
|
||||
|
||||
let private fetchArchmaesterArchives (group: string) : JS.Promise<Result<Archmaester.Dto.ArchiveProps array, string>> =
|
||||
promise {
|
||||
let filter : Archmaester.Dto.ArchiveFilter = {
|
||||
id = None
|
||||
searchTerm = None
|
||||
archiveType = None
|
||||
owner = None
|
||||
user = None
|
||||
groups = Some [| group |]
|
||||
}
|
||||
let! result = Remoting.adminApi.getArchives 0 -1 filter |> Async.StartAsPromise
|
||||
return result
|
||||
}
|
||||
|
||||
let fetchGroupArchiveProps (group: string) : JS.Promise<Types.Archive array> =
|
||||
promise {
|
||||
let fgaUser = sprintf "group:%s#member" (Groups.Utils.canonicalizeName group)
|
||||
let! archivesRes = fetchArchmaesterArchives group
|
||||
let! viewsRes =
|
||||
OpenFGA.fetchObjects(fgaUser, "view", "archive", context = {| time = System.DateTime.Now |})
|
||||
let! execsRes =
|
||||
OpenFGA.fetchObjects(fgaUser, "exec", "archive", context = {| task = "*"; usage = -1; time = System.DateTime.Now |})
|
||||
|
||||
let res =
|
||||
result {
|
||||
// TODO: Create specific exception
|
||||
let! props = archivesRes |> Result.mapError System.Exception
|
||||
let! views = viewsRes |> Result.mapError System.Exception
|
||||
let! execs = execsRes |> Result.mapError System.Exception
|
||||
let viewArchiveIds = views |> Array.choose extractFgaArchiveId
|
||||
let execArchiveIds = execs |> Array.choose extractFgaArchiveId
|
||||
let archives =
|
||||
props
|
||||
|> Array.map (fun prop -> {
|
||||
Props = prop
|
||||
CanView = viewArchiveIds |> Array.contains prop.archiveId
|
||||
CanExec = execArchiveIds |> Array.contains prop.archiveId
|
||||
})
|
||||
|
||||
return archives
|
||||
}
|
||||
|
||||
match res with
|
||||
| Ok archives ->
|
||||
return archives
|
||||
| Error ex ->
|
||||
raise ex
|
||||
return [||]
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ namespace Oceanbox.Codex
|
||||
module Group =
|
||||
open Browser
|
||||
open Fable.Core
|
||||
open FsToolkit.ErrorHandling
|
||||
|
||||
open Oceanbox.Codex.Types
|
||||
|
||||
@@ -17,59 +16,9 @@ module Group =
|
||||
return Error (sprintf "Error fetching users for group %s" group)
|
||||
}
|
||||
|
||||
let private fetchArchmaesterArchives (group: string) : JS.Promise<Result<Archmaester.Dto.ArchiveProps array, string>> =
|
||||
promise {
|
||||
let filter : Archmaester.Dto.ArchiveFilter = {
|
||||
id = None
|
||||
searchTerm = None
|
||||
archiveType = None
|
||||
owner = None
|
||||
user = None
|
||||
groups = Some [| group |]
|
||||
}
|
||||
let! result = Remoting.adminApi.getArchives 0 -1 filter |> Async.StartAsPromise
|
||||
return result
|
||||
}
|
||||
|
||||
module private Elmish =
|
||||
open Elmish
|
||||
|
||||
let fetchArchiveProps (group: string) : JS.Promise<Types.Archive array> =
|
||||
promise {
|
||||
let fgaUser = sprintf "group:%s#member" (Groups.Utils.canonicalizeName group)
|
||||
let! archivesRes = fetchArchmaesterArchives group
|
||||
let! viewsRes =
|
||||
OpenFGA.fetchObjects(fgaUser, "view", "archive", context = {| time = System.DateTime.Now |})
|
||||
let! execsRes =
|
||||
OpenFGA.fetchObjects(fgaUser, "exec", "archive", context = {| task = "*"; usage = -1; time = System.DateTime.Now |})
|
||||
|
||||
let res =
|
||||
result {
|
||||
// TODO: Create specific exception
|
||||
let! props = archivesRes |> Result.mapError System.Exception
|
||||
let! views = viewsRes |> Result.mapError System.Exception
|
||||
let! execs = execsRes |> Result.mapError System.Exception
|
||||
let viewArchiveIds = views |> Array.choose Archives.Utils.extractFgaArchiveId
|
||||
let execArchiveIds = execs |> Array.choose Archives.Utils.extractFgaArchiveId
|
||||
let archives =
|
||||
props
|
||||
|> Array.map (fun prop -> {
|
||||
Props = prop
|
||||
CanView = viewArchiveIds |> Array.contains prop.archiveId
|
||||
CanExec = execArchiveIds |> Array.contains prop.archiveId
|
||||
})
|
||||
|
||||
return archives
|
||||
}
|
||||
|
||||
match res with
|
||||
| Ok archives ->
|
||||
return archives
|
||||
| Error ex ->
|
||||
raise ex
|
||||
return [||]
|
||||
}
|
||||
|
||||
type Msg =
|
||||
| FetchArchives of string
|
||||
| SetArchiveAdding of bool
|
||||
@@ -97,7 +46,7 @@ module Group =
|
||||
let update msg model =
|
||||
match msg with
|
||||
| FetchArchives group ->
|
||||
model, Cmd.OfPromise.either fetchArchiveProps group SetArchives HandleExn
|
||||
model, Cmd.OfPromise.either Archives.Utils.fetchGroupArchiveProps group SetArchives HandleExn
|
||||
| HandleExn ex ->
|
||||
let msg =
|
||||
match ex with
|
||||
@@ -470,4 +419,4 @@ module Group =
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
@@ -4,6 +4,71 @@ open Feliz
|
||||
open Feliz.Router
|
||||
|
||||
module GroupUser =
|
||||
[<ReactComponent>]
|
||||
let private ArchiveList key (group: string) (title: string) (archives: Types.Archive array) =
|
||||
Html.div [
|
||||
prop.style [
|
||||
style.flexBasis (length.px 256)
|
||||
]
|
||||
prop.children [
|
||||
Html.h3 title
|
||||
|
||||
Html.ul [
|
||||
prop.children (
|
||||
archives
|
||||
|> Array.sortBy _.Props.name
|
||||
|> Array.map (fun archive ->
|
||||
let text = Archives.Utils.archiveName archive
|
||||
Html.li [
|
||||
prop.children [
|
||||
Html.a [
|
||||
prop.href (Router.format("groups", group, "archives", string archive.Props.archiveId))
|
||||
prop.text text
|
||||
]
|
||||
]
|
||||
]
|
||||
)
|
||||
)
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
[<ReactComponent>]
|
||||
let private ArchiveLists (group: string) =
|
||||
let archives, setArchives = React.useState<Types.Archive array> [||]
|
||||
|
||||
React.useEffect (
|
||||
(fun () ->
|
||||
Archives.Utils.fetchGroupArchiveProps group
|
||||
|> Promise.iter (fun res ->
|
||||
setArchives res
|
||||
)
|
||||
),
|
||||
[| box group |]
|
||||
)
|
||||
let fvcom =
|
||||
archives
|
||||
|> Array.filter (fun archive ->
|
||||
match archive.Props.archiveType with
|
||||
| Archmaester.Dto.Fvcom _ -> true
|
||||
| _ -> false
|
||||
)
|
||||
let drifters =
|
||||
archives
|
||||
|> Array.filter (fun archive ->
|
||||
match archive.Props.archiveType with
|
||||
| Archmaester.Dto.Drifters _ -> true
|
||||
| _ -> false
|
||||
)
|
||||
|
||||
Html.div [
|
||||
prop.classes ["flex-row-start"; "gap-8"]
|
||||
prop.children [
|
||||
ArchiveList "fvcom-ul-list" group "FVCOM" fvcom
|
||||
ArchiveList "drifters-ul-list" group "Drifters" drifters
|
||||
]
|
||||
]
|
||||
|
||||
[<ReactComponent>]
|
||||
let View (group: string) (user: string) =
|
||||
let fgaUser = sprintf "user:%s" user
|
||||
@@ -128,4 +193,12 @@ module GroupUser =
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
Html.section [
|
||||
prop.children [
|
||||
Html.h2 "Archives via group"
|
||||
|
||||
ArchiveLists group
|
||||
]
|
||||
]
|
||||
]
|
||||
Reference in New Issue
Block a user