mirror of
https://github.com/photoprism/photoprism.git
synced 2025-12-12 00:34:13 +01:00
API: Move "service/cluster" package from "pkg" to "internal" #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
@@ -9,9 +9,9 @@ import (
|
||||
"github.com/photoprism/photoprism/internal/auth/acl"
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
"github.com/photoprism/photoprism/internal/photoprism/get"
|
||||
"github.com/photoprism/photoprism/internal/service/cluster"
|
||||
reg "github.com/photoprism/photoprism/internal/service/cluster/registry"
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
"github.com/photoprism/photoprism/pkg/service/cluster"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
)
|
||||
|
||||
@@ -103,9 +103,9 @@ func ClusterListNodes(router *gin.RouterGroup) {
|
||||
page := items[offset:end]
|
||||
|
||||
// Build response with session-based redaction.
|
||||
opts := ClusterNodeOptionsForSession(s)
|
||||
opts := reg.NodeOptsForSession(s)
|
||||
|
||||
resp := BuildClusterNodes(page, opts)
|
||||
resp := reg.BuildClusterNodes(page, opts)
|
||||
|
||||
// Audit list access.
|
||||
event.AuditInfo([]string{ClientIP(c), "session %s", string(acl.ResourceCluster), "nodes", "list", event.Succeeded, "count=%d", "offset=%d", "returned=%d"}, s.RefID, count, offset, len(resp))
|
||||
@@ -162,8 +162,8 @@ func ClusterGetNode(router *gin.RouterGroup) {
|
||||
}
|
||||
|
||||
// Build response with session-based redaction.
|
||||
opts := ClusterNodeOptionsForSession(s)
|
||||
resp := BuildClusterNode(*n, opts)
|
||||
opts := reg.NodeOptsForSession(s)
|
||||
resp := reg.BuildClusterNode(*n, opts)
|
||||
|
||||
// Audit get access.
|
||||
event.AuditInfo([]string{ClientIP(c), "session %s", string(acl.ResourceCluster), "nodes", "get", n.ID, event.Succeeded}, s.RefID)
|
||||
|
||||
@@ -10,11 +10,11 @@ import (
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
"github.com/photoprism/photoprism/internal/photoprism/get"
|
||||
"github.com/photoprism/photoprism/internal/server/limiter"
|
||||
"github.com/photoprism/photoprism/internal/service/cluster"
|
||||
"github.com/photoprism/photoprism/internal/service/cluster/provisioner"
|
||||
reg "github.com/photoprism/photoprism/internal/service/cluster/registry"
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
"github.com/photoprism/photoprism/pkg/service/cluster"
|
||||
"github.com/photoprism/photoprism/pkg/service/http/header"
|
||||
)
|
||||
|
||||
@@ -134,9 +134,9 @@ func ClusterNodesRegister(router *gin.RouterGroup) {
|
||||
}
|
||||
|
||||
// Build response with struct types.
|
||||
opts := ClusterNodeOptionsForSession(nil) // registration is token-based, not session; default redaction is fine
|
||||
opts := reg.NodeOptsForSession(nil) // registration is token-based, not session; default redaction is fine
|
||||
resp := cluster.RegisterResponse{
|
||||
Node: BuildClusterNode(*n, opts),
|
||||
Node: reg.BuildClusterNode(*n, opts),
|
||||
DB: cluster.RegisterDB{Host: conf.DatabaseHost(), Port: conf.DatabasePort(), Name: n.DB.Name, User: n.DB.User},
|
||||
Secrets: respSecret,
|
||||
AlreadyRegistered: true,
|
||||
@@ -184,7 +184,7 @@ func ClusterNodesRegister(router *gin.RouterGroup) {
|
||||
}
|
||||
|
||||
resp := cluster.RegisterResponse{
|
||||
Node: BuildClusterNode(*n, ClusterNodeOptionsForSession(nil)),
|
||||
Node: reg.BuildClusterNode(*n, reg.NodeOptsForSession(nil)),
|
||||
Secrets: &cluster.RegisterSecrets{NodeSecret: n.Secret, NodeSecretLastRotatedAt: n.SecretRot},
|
||||
DB: cluster.RegisterDB{Host: conf.DatabaseHost(), Port: conf.DatabasePort(), Name: creds.Name, User: creds.User, Password: creds.Password, DSN: creds.DSN, DBLastRotatedAt: creds.LastRotatedAt},
|
||||
AlreadyRegistered: false,
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/service/cluster"
|
||||
reg "github.com/photoprism/photoprism/internal/service/cluster/registry"
|
||||
"github.com/photoprism/photoprism/pkg/service/cluster"
|
||||
)
|
||||
|
||||
func TestClusterNodesRegister(t *testing.T) {
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/service/cluster"
|
||||
reg "github.com/photoprism/photoprism/internal/service/cluster/registry"
|
||||
"github.com/photoprism/photoprism/pkg/service/cluster"
|
||||
)
|
||||
|
||||
func TestClusterEndpoints(t *testing.T) {
|
||||
|
||||
@@ -8,12 +8,11 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/config"
|
||||
"github.com/photoprism/photoprism/internal/service/cluster"
|
||||
"github.com/photoprism/photoprism/pkg/authn"
|
||||
"github.com/photoprism/photoprism/pkg/service/cluster"
|
||||
"github.com/photoprism/photoprism/pkg/service/http/header"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
entitypkg "github.com/photoprism/photoprism/internal/entity"
|
||||
reg "github.com/photoprism/photoprism/internal/service/cluster/registry"
|
||||
"github.com/photoprism/photoprism/pkg/service/cluster"
|
||||
)
|
||||
|
||||
// ClusterNodeOptions controls which optional fields get included in responses.
|
||||
type ClusterNodeOptions struct {
|
||||
IncludeInternalURL bool
|
||||
IncludeDBMeta bool
|
||||
}
|
||||
|
||||
// ClusterNodeOptionsForSession returns the default exposure policy for a session.
|
||||
// Admin users see internalUrl and DB metadata; others get a redacted view.
|
||||
func ClusterNodeOptionsForSession(s *entitypkg.Session) ClusterNodeOptions {
|
||||
if s != nil && s.User() != nil && s.User().IsAdmin() {
|
||||
return ClusterNodeOptions{IncludeInternalURL: true, IncludeDBMeta: true}
|
||||
}
|
||||
|
||||
return ClusterNodeOptions{}
|
||||
}
|
||||
|
||||
// BuildClusterNode builds a ClusterNode DTO from a registry.Node with redaction according to opts.
|
||||
func BuildClusterNode(n reg.Node, opts ClusterNodeOptions) cluster.Node {
|
||||
out := cluster.Node{
|
||||
ID: n.ID,
|
||||
Name: n.Name,
|
||||
Type: n.Type,
|
||||
Labels: n.Labels,
|
||||
CreatedAt: n.CreatedAt,
|
||||
UpdatedAt: n.UpdatedAt,
|
||||
}
|
||||
|
||||
if opts.IncludeInternalURL && n.Internal != "" {
|
||||
out.InternalURL = n.Internal
|
||||
}
|
||||
|
||||
if opts.IncludeDBMeta {
|
||||
out.DB = &cluster.NodeDB{
|
||||
Name: n.DB.Name,
|
||||
User: n.DB.User,
|
||||
DBLastRotatedAt: n.DB.RotAt,
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// BuildClusterNodes builds DTOs for a slice of registry.Node.
|
||||
func BuildClusterNodes(list []reg.Node, opts ClusterNodeOptions) []cluster.Node {
|
||||
if len(list) == 0 {
|
||||
return []cluster.Node{}
|
||||
}
|
||||
|
||||
out := make([]cluster.Node, 0, len(list))
|
||||
|
||||
for _, n := range list {
|
||||
out = append(out, BuildClusterNode(n, opts))
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
|
||||
"github.com/photoprism/photoprism/internal/auth/acl"
|
||||
"github.com/photoprism/photoprism/internal/photoprism/get"
|
||||
"github.com/photoprism/photoprism/internal/service/cluster"
|
||||
reg "github.com/photoprism/photoprism/internal/service/cluster/registry"
|
||||
"github.com/photoprism/photoprism/pkg/service/cluster"
|
||||
"github.com/photoprism/photoprism/pkg/service/http/header"
|
||||
)
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/service/cluster"
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
"github.com/photoprism/photoprism/pkg/service/cluster"
|
||||
"github.com/photoprism/photoprism/pkg/service/http/header"
|
||||
)
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ import (
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/service/cluster"
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
"github.com/photoprism/photoprism/pkg/service/cluster"
|
||||
)
|
||||
|
||||
// NodeName returns the unique name of this node within the cluster (lowercase letters and numbers only).
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/service/cluster"
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
"github.com/photoprism/photoprism/pkg/service/cluster"
|
||||
)
|
||||
|
||||
func TestConfig_Cluster(t *testing.T) {
|
||||
|
||||
63
internal/service/cluster/registry/response.go
Normal file
63
internal/service/cluster/registry/response.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
"github.com/photoprism/photoprism/internal/service/cluster"
|
||||
)
|
||||
|
||||
// NodeOpts controls which optional fields get included in responses.
|
||||
type NodeOpts struct {
|
||||
IncludeInternalURL bool
|
||||
IncludeDBMeta bool
|
||||
}
|
||||
|
||||
// NodeOptsForSession returns the default exposure policy for a session.
|
||||
// Admin users see internalUrl and DB metadata; others get a redacted view.
|
||||
func NodeOptsForSession(s *entity.Session) NodeOpts {
|
||||
if s != nil && s.User() != nil && s.User().IsAdmin() {
|
||||
return NodeOpts{IncludeInternalURL: true, IncludeDBMeta: true}
|
||||
}
|
||||
|
||||
return NodeOpts{}
|
||||
}
|
||||
|
||||
// BuildClusterNode builds a cluster.Node DTO from a registry.Node with redaction according to opts.
|
||||
func BuildClusterNode(n Node, opts NodeOpts) cluster.Node {
|
||||
out := cluster.Node{
|
||||
ID: n.ID,
|
||||
Name: n.Name,
|
||||
Type: n.Type,
|
||||
Labels: n.Labels,
|
||||
CreatedAt: n.CreatedAt,
|
||||
UpdatedAt: n.UpdatedAt,
|
||||
}
|
||||
|
||||
if opts.IncludeInternalURL && n.Internal != "" {
|
||||
out.InternalURL = n.Internal
|
||||
}
|
||||
|
||||
if opts.IncludeDBMeta {
|
||||
out.DB = &cluster.NodeDB{
|
||||
Name: n.DB.Name,
|
||||
User: n.DB.User,
|
||||
DBLastRotatedAt: n.DB.RotAt,
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// BuildClusterNodes creates a cluster node slice from the given registry node slice.
|
||||
func BuildClusterNodes(list []Node, opts NodeOpts) []cluster.Node {
|
||||
if len(list) == 0 {
|
||||
return []cluster.Node{}
|
||||
}
|
||||
|
||||
out := make([]cluster.Node, 0, len(list))
|
||||
|
||||
for _, n := range list {
|
||||
out = append(out, BuildClusterNode(n, opts))
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user