mirror of
https://github.com/hanzoui/registry-backend.git
synced 2026-10-30 20:30:45 +00:00
1154 lines
47 KiB
Go
1154 lines
47 KiB
Go
package implementation
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"registry-backend/drip"
|
|
"registry-backend/ent"
|
|
"registry-backend/ent/publisher"
|
|
"registry-backend/ent/schema"
|
|
"registry-backend/entity"
|
|
drip_logging "registry-backend/logging"
|
|
"registry-backend/mapper"
|
|
drip_services "registry-backend/services/registry"
|
|
"registry-backend/tracing"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/mixpanel/mixpanel-go"
|
|
"github.com/rs/zerolog/log"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
func (impl *DripStrictServerImplementation) ListPublishersForUser(
|
|
ctx context.Context, request drip.ListPublishersForUserRequestObject) (drip.ListPublishersForUserResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.ListPublishersForUser")()
|
|
|
|
// Extract user ID from context
|
|
userId, err := mapper.GetUserIDFromContext(ctx)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to get user ID from context w/ err: %v", err)
|
|
return drip.ListPublishersForUser400JSONResponse{Message: "Invalid user ID"}, err
|
|
}
|
|
|
|
// Call the service to list publishers
|
|
log.Ctx(ctx).Info().Msgf("Fetching publishers for user %s", userId)
|
|
publishers, err := impl.RegistryService.ListPublishers(ctx, impl.Client, &entity.PublisherFilter{
|
|
UserID: userId,
|
|
})
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to list publishers w/ err: %v", err)
|
|
return drip.ListPublishersForUser500JSONResponse{
|
|
Message: "Failed to fetch list of publishers", Error: err.Error()}, err
|
|
}
|
|
|
|
// Map the publishers to API format
|
|
apiPublishers := make([]drip.Publisher, 0, len(publishers))
|
|
log.Ctx(ctx).Info().Msgf(
|
|
"Successfully fetched publishers for user %s, count %d", userId, len(apiPublishers))
|
|
for _, dbPublisher := range publishers {
|
|
apiPublishers = append(apiPublishers, *mapper.DbPublisherToApiPublisher(dbPublisher, true))
|
|
}
|
|
|
|
return drip.ListPublishersForUser200JSONResponse(apiPublishers), nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) ValidatePublisher(
|
|
ctx context.Context, request drip.ValidatePublisherRequestObject) (drip.ValidatePublisherResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.ValidatePublisher")()
|
|
|
|
// Check if the username is empty
|
|
name := request.Params.Username
|
|
if name == "" {
|
|
log.Ctx(ctx).Warn().Msg("Username parameter is missing")
|
|
return drip.ValidatePublisher400JSONResponse{Message: "Username parameter is required"}, nil
|
|
}
|
|
|
|
isValid := mapper.IsValidPublisherID(name)
|
|
if !isValid {
|
|
return drip.ValidatePublisher400JSONResponse{
|
|
Message: "Must start with a lowercase letter and can only contain lowercase letters, digits, and hyphens.",
|
|
}, nil
|
|
}
|
|
|
|
// Note: username = id field in publisher table, display = name field in publisher table
|
|
count, err := s.Client.Publisher.Query().Where(publisher.ID(name)).Count(ctx)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to query username %s w/ err: %v", name, err)
|
|
return drip.ValidatePublisher500JSONResponse{Message: "Failed to query username", Error: err.Error()}, err
|
|
}
|
|
|
|
// Log the result of the count query
|
|
log.Ctx(ctx).Info().Msgf("Count for username %s: %d", name, count)
|
|
if count > 0 {
|
|
return drip.ValidatePublisher400JSONResponse{
|
|
Message: "Publisher ID already exists.",
|
|
}, nil
|
|
}
|
|
|
|
return drip.ValidatePublisher200JSONResponse{
|
|
IsAvailable: proto.Bool(true),
|
|
}, nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) CreatePublisher(
|
|
ctx context.Context, request drip.CreatePublisherRequestObject) (drip.CreatePublisherResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.CreatePublisher")()
|
|
|
|
// Extract user ID from context
|
|
userId, err := mapper.GetUserIDFromContext(ctx)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to get user ID from context w/ err: %v", err)
|
|
return drip.CreatePublisher400JSONResponse{Message: "Invalid user ID"}, err
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Checking if user ID %s has reached the maximum number of publishers", userId)
|
|
userPublishers, err := s.RegistryService.ListPublishers(
|
|
ctx, s.Client, &entity.PublisherFilter{UserID: userId})
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to list publishers for user ID %s w/ err: %v", userId, err)
|
|
return drip.CreatePublisher500JSONResponse{Message: "Failed to list publishers", Error: err.Error()}, err
|
|
}
|
|
if len(userPublishers) >= 5 {
|
|
log.Ctx(ctx).Info().Msgf("User ID %s has reached the maximum number of publishers", userId)
|
|
return drip.CreatePublisher403JSONResponse{
|
|
Message: "User has reached the maximum number of publishers.",
|
|
}, nil
|
|
}
|
|
|
|
// Create a new publisher
|
|
log.Ctx(ctx).Info().Msgf("Creating publisher for user ID %s", userId)
|
|
publisher, err := s.RegistryService.CreatePublisher(ctx, s.Client, userId, request.Body)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to create publisher for user ID %s w/ err: %v", userId, err)
|
|
if ent.IsConstraintError(err) {
|
|
return drip.CreatePublisher400JSONResponse{Message: "Constraint error", Error: err.Error()}, nil
|
|
}
|
|
|
|
return drip.CreatePublisher500JSONResponse{Message: "Internal server error", Error: err.Error()}, err
|
|
}
|
|
|
|
// Log the successful creation
|
|
log.Ctx(ctx).Info().Msgf("Publisher created successfully for user ID: %s", userId)
|
|
return drip.CreatePublisher201JSONResponse(*mapper.DbPublisherToApiPublisher(publisher, true)), nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) ListPublishers(
|
|
ctx context.Context, request drip.ListPublishersRequestObject) (drip.ListPublishersResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.ListPublishers")()
|
|
|
|
pubs, err := s.RegistryService.ListPublishers(ctx, s.Client, nil)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to retrieve list of publishers w/ err: %v", err)
|
|
return drip.ListPublishers500JSONResponse{Message: "Failed to get publisher", Error: err.Error()}, err
|
|
}
|
|
|
|
res := drip.ListPublishers200JSONResponse{}
|
|
for _, pub := range pubs {
|
|
res = append(res, *mapper.DbPublisherToApiPublisher(pub, false))
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("List of Publishers retrieved successfully")
|
|
return res, nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) DeletePublisher(
|
|
ctx context.Context, request drip.DeletePublisherRequestObject) (drip.DeletePublisherResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.DeletePublisher")()
|
|
|
|
err := s.RegistryService.DeletePublisher(ctx, s.Client, request.PublisherId)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to delete publisher with ID %s w/ err: %v", request.PublisherId, err)
|
|
return drip.DeletePublisher500JSONResponse{}, nil
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Publisher with ID %s deleted successfully", request.PublisherId)
|
|
return drip.DeletePublisher204Response{}, nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) GetPublisher(
|
|
ctx context.Context, request drip.GetPublisherRequestObject) (drip.GetPublisherResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.GetPublisher")()
|
|
|
|
publisherId := request.PublisherId
|
|
publisher, err := s.RegistryService.GetPublisher(ctx, s.Client, request.PublisherId)
|
|
if ent.IsNotFound(err) {
|
|
log.Ctx(ctx).Info().Msgf("Publisher with ID %s not found", publisherId)
|
|
return drip.GetPublisher404JSONResponse{Message: "Publisher not found"}, nil
|
|
}
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to retrieve publisher with ID %s w/ err: %v", publisherId, err)
|
|
return drip.GetPublisher500JSONResponse{Message: "Failed to get publisher", Error: err.Error()}, err
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Publisher with ID %s retrieved successfully", publisherId)
|
|
return drip.GetPublisher200JSONResponse(*mapper.DbPublisherToApiPublisher(publisher, false)), nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) UpdatePublisher(
|
|
ctx context.Context, request drip.UpdatePublisherRequestObject) (drip.UpdatePublisherResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.UpdatePublisher")()
|
|
|
|
updateOne := mapper.ApiUpdatePublisherToUpdateFields(request.PublisherId, request.Body, s.Client)
|
|
updatedPublisher, err := s.RegistryService.UpdatePublisher(ctx, s.Client, updateOne)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to update publisher with ID %s w/ err: %v", request.PublisherId, err)
|
|
return drip.UpdatePublisher500JSONResponse{Message: "Failed to update publisher", Error: err.Error()}, err
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Publisher with ID %s updated successfully", request.PublisherId)
|
|
return drip.UpdatePublisher200JSONResponse(*mapper.DbPublisherToApiPublisher(updatedPublisher, true)), nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) CreateNode(
|
|
ctx context.Context, request drip.CreateNodeRequestObject) (drip.CreateNodeResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.CreateNode")()
|
|
|
|
node, err := s.RegistryService.CreateNode(ctx, s.Client, request.PublisherId, request.Body)
|
|
if mapper.IsErrorBadRequest(err) || ent.IsConstraintError(err) {
|
|
log.Ctx(ctx).Error().Msgf(
|
|
"Failed to create node for publisher ID %s w/ err: %v", request.PublisherId, err)
|
|
return drip.CreateNode400JSONResponse{Message: "The node already exists", Error: err.Error()}, err
|
|
}
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to create node for publisher ID %s w/ err: %v", request.PublisherId, err)
|
|
return drip.CreateNode500JSONResponse{Message: "Failed to create node", Error: err.Error()}, err
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Node created successfully for publisher ID: %s", request.PublisherId)
|
|
return drip.CreateNode201JSONResponse(*mapper.DbNodeToApiNode(node)), nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) ListNodesForPublisher(
|
|
ctx context.Context, request drip.ListNodesForPublisherRequestObject) (drip.ListNodesForPublisherResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.ListNodesForPublisher")()
|
|
|
|
nodeResults, err := s.RegistryService.ListNodes(
|
|
ctx, s.Client /*page=*/, 1 /*limit=*/, 10, &entity.NodeFilter{
|
|
PublisherID: request.PublisherId,
|
|
})
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf(
|
|
"Failed to list nodes for publisher ID %s w/ err: %v", request.PublisherId, err)
|
|
return drip.ListNodesForPublisher500JSONResponse{Message: "Failed to list nodes", Error: err.Error()}, err
|
|
}
|
|
|
|
if len(nodeResults.Nodes) == 0 {
|
|
log.Ctx(ctx).Info().Msgf("No nodes found for publisher ID: %s", request.PublisherId)
|
|
return drip.ListNodesForPublisher200JSONResponse([]drip.Node{}), nil
|
|
}
|
|
|
|
apiNodes := make([]drip.Node, 0, len(nodeResults.Nodes))
|
|
for _, dbNode := range nodeResults.Nodes {
|
|
apiNodes = append(apiNodes, *mapper.DbNodeToApiNode(dbNode))
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf(
|
|
"Found %d nodes for publisher ID: %s", len(apiNodes), request.PublisherId)
|
|
return drip.ListNodesForPublisher200JSONResponse(apiNodes), nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) ListAllNodes(
|
|
ctx context.Context, request drip.ListAllNodesRequestObject) (drip.ListAllNodesResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.ListAllNodes")()
|
|
|
|
err := s.MixpanelService.Track(ctx, []*mixpanel.Event{
|
|
s.MixpanelService.NewEvent("List All Nodes", "", map[string]any{
|
|
"page": request.Params.Page,
|
|
"limit": request.Params.Limit,
|
|
}),
|
|
})
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to track event w/ err: %v", err)
|
|
}
|
|
|
|
// Set default values for pagination parameters
|
|
page := 1
|
|
if request.Params.Page != nil {
|
|
page = *request.Params.Page
|
|
}
|
|
limit := 10
|
|
if request.Params.Limit != nil {
|
|
limit = *request.Params.Limit
|
|
}
|
|
|
|
// Initialize the node filter
|
|
filter := &entity.NodeFilter{
|
|
Timestamp: request.Params.Timestamp,
|
|
IncludeBanned: request.Params.IncludeBanned,
|
|
}
|
|
|
|
// List nodes from the registry service
|
|
latest := false
|
|
if request.Params.Latest != nil {
|
|
latest = *request.Params.Latest
|
|
}
|
|
nodeResults, err := s.RegistryService.ListNodesWithCache(ctx, s.Client, page, limit, filter, latest)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to list nodes w/ err: %v", err)
|
|
return drip.ListAllNodes500JSONResponse{Message: "Failed to list nodes", Error: err.Error()}, err
|
|
}
|
|
|
|
// Handle case when no nodes are found
|
|
if len(nodeResults.Nodes) == 0 {
|
|
log.Ctx(ctx).Info().Msg("No nodes found")
|
|
return drip.ListAllNodes200JSONResponse{
|
|
Nodes: &[]drip.Node{},
|
|
Total: &nodeResults.Total,
|
|
Page: &nodeResults.Page,
|
|
Limit: &nodeResults.Limit,
|
|
TotalPages: &nodeResults.TotalPages,
|
|
}, nil
|
|
}
|
|
|
|
// Convert database nodes to API nodes
|
|
apiNodes := make([]drip.Node, 0, len(nodeResults.Nodes))
|
|
for _, dbNode := range nodeResults.Nodes {
|
|
apiNode := mapper.DbNodeToApiNode(dbNode)
|
|
|
|
// attach information of latest version if available
|
|
if len(dbNode.Edges.Versions) > 0 {
|
|
apiNode.LatestVersion = mapper.DbNodeVersionToApiNodeVersion(dbNode.Edges.Versions[0])
|
|
apiNode.LatestVersion.StatusReason = nil
|
|
}
|
|
|
|
// Map publisher information
|
|
apiNode.Publisher = mapper.DbPublisherToApiPublisher(dbNode.Edges.Publisher, false)
|
|
apiNodes = append(apiNodes, *apiNode)
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Found %d nodes", len(apiNodes))
|
|
return drip.ListAllNodes200JSONResponse{
|
|
Nodes: &apiNodes,
|
|
Total: &nodeResults.Total,
|
|
Page: &nodeResults.Page,
|
|
Limit: &nodeResults.Limit,
|
|
TotalPages: &nodeResults.TotalPages,
|
|
}, nil
|
|
}
|
|
|
|
// SearchNodes implements drip.StrictServerInterface.
|
|
func (s *DripStrictServerImplementation) SearchNodes(ctx context.Context, request drip.SearchNodesRequestObject) (drip.SearchNodesResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.SearchNodes")()
|
|
|
|
// Set default values for pagination parameters
|
|
page := 1
|
|
if request.Params.Page != nil {
|
|
page = *request.Params.Page
|
|
}
|
|
limit := 10
|
|
if request.Params.Limit != nil {
|
|
limit = *request.Params.Limit
|
|
}
|
|
|
|
f := &entity.NodeFilter{
|
|
IncludeBanned: request.Params.IncludeBanned,
|
|
}
|
|
if request.Params.Search != nil {
|
|
f.Search = *request.Params.Search
|
|
}
|
|
// List nodes from the registry service
|
|
nodeResults, err := s.RegistryService.ListNodes(ctx, s.Client, page, limit, f)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to search nodes w/ err: %v", err)
|
|
return drip.SearchNodes500JSONResponse{Message: "Failed to search nodes", Error: err.Error()}, err
|
|
}
|
|
|
|
if len(nodeResults.Nodes) == 0 {
|
|
log.Ctx(ctx).Info().Msg("No nodes found")
|
|
return drip.SearchNodes200JSONResponse{
|
|
Nodes: &[]drip.Node{},
|
|
Total: &nodeResults.Total,
|
|
Page: &nodeResults.Page,
|
|
Limit: &nodeResults.Limit,
|
|
TotalPages: &nodeResults.TotalPages,
|
|
}, nil
|
|
}
|
|
|
|
apiNodes := make([]drip.Node, 0, len(nodeResults.Nodes))
|
|
for _, dbNode := range nodeResults.Nodes {
|
|
apiNode := mapper.DbNodeToApiNode(dbNode)
|
|
if len(dbNode.Edges.Versions) > 0 {
|
|
latestVersion := dbNode.Edges.Versions[0]
|
|
apiNode.LatestVersion = mapper.DbNodeVersionToApiNodeVersion(latestVersion)
|
|
}
|
|
apiNode.Publisher = mapper.DbPublisherToApiPublisher(dbNode.Edges.Publisher, false)
|
|
apiNodes = append(apiNodes, *apiNode)
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Found %d nodes", len(apiNodes))
|
|
return drip.SearchNodes200JSONResponse{
|
|
Nodes: &apiNodes,
|
|
Total: &nodeResults.Total,
|
|
Page: &nodeResults.Page,
|
|
Limit: &nodeResults.Limit,
|
|
TotalPages: &nodeResults.TotalPages,
|
|
}, nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) DeleteNode(
|
|
ctx context.Context, request drip.DeleteNodeRequestObject) (drip.DeleteNodeResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.DeleteNode")()
|
|
|
|
err := s.RegistryService.DeleteNode(ctx, s.Client, request.NodeId)
|
|
if err != nil && !ent.IsNotFound(err) {
|
|
log.Ctx(ctx).Error().Msgf("Failed to delete node %s w/ err: %v", request.NodeId, err)
|
|
return drip.DeleteNode500JSONResponse{Message: "Internal server error"}, err
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Node %s deleted successfully", request.NodeId)
|
|
return drip.DeleteNode204Response{}, nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) GetNode(
|
|
ctx context.Context, request drip.GetNodeRequestObject) (drip.GetNodeResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.GetNode")()
|
|
|
|
node, err := s.RegistryService.GetNode(ctx, s.Client, request.NodeId)
|
|
if ent.IsNotFound(err) {
|
|
log.Ctx(ctx).Error().Msgf("Failed to get node %s w/ err: %v", request.NodeId, err)
|
|
return drip.GetNode404JSONResponse{Message: "Node not found"}, nil
|
|
}
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to get node %s w/ err: %v", request.NodeId, err)
|
|
return drip.GetNode500JSONResponse{Message: "Failed to get node"}, err
|
|
}
|
|
|
|
nodeVersion, err := s.RegistryService.GetLatestNodeVersion(ctx, s.Client, request.NodeId)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf(
|
|
"Failed to get latest node version for node %s w/ err: %v", request.NodeId, err)
|
|
return drip.GetNode500JSONResponse{Message: "Failed to get latest node version", Error: err.Error()}, err
|
|
}
|
|
|
|
apiNode := mapper.DbNodeToApiNode(node)
|
|
apiNode.LatestVersion = mapper.DbNodeVersionToApiNodeVersion(nodeVersion)
|
|
|
|
log.Ctx(ctx).Info().Msgf("Node %s retrieved successfully", request.NodeId)
|
|
return drip.GetNode200JSONResponse(*apiNode), nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) UpdateNode(
|
|
ctx context.Context, request drip.UpdateNodeRequestObject) (drip.UpdateNodeResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.UpdateNode")()
|
|
|
|
updateOneFunc := func(client *ent.Client) *ent.NodeUpdateOne {
|
|
return mapper.ApiUpdateNodeToUpdateFields(request.NodeId, request.Body, client)
|
|
}
|
|
updatedNode, err := s.RegistryService.UpdateNode(ctx, s.Client, updateOneFunc)
|
|
if ent.IsNotFound(err) {
|
|
log.Ctx(ctx).Error().Msgf("Node %s not found w/ err: %v", request.NodeId, err)
|
|
return drip.UpdateNode404JSONResponse{Message: "Not Found"}, nil
|
|
}
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to update node %s w/ err: %v", request.NodeId, err)
|
|
return drip.UpdateNode500JSONResponse{Message: "Failed to update node", Error: err.Error()}, err
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Node %s updated successfully", request.NodeId)
|
|
return drip.UpdateNode200JSONResponse(*mapper.DbNodeToApiNode(updatedNode)), nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) ListNodeVersions(
|
|
ctx context.Context, request drip.ListNodeVersionsRequestObject) (drip.ListNodeVersionsResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.ListNodeVersions")()
|
|
|
|
apiStatus := mapper.ApiNodeVersionStatusesToDbNodeVersionStatuses(request.Params.Statuses)
|
|
|
|
nodeVersionsResult, err := s.RegistryService.ListNodeVersions(ctx, s.Client, &entity.NodeVersionFilter{
|
|
NodeId: request.NodeId,
|
|
Status: apiStatus,
|
|
IncludeStatusReason: mapper.BoolPtrToBool(request.Params.IncludeStatusReason),
|
|
})
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to list node versions for node %s w/ err: %v", request.NodeId, err)
|
|
return drip.ListNodeVersions500JSONResponse{Message: "Failed to list node versions", Error: err.Error()}, err
|
|
}
|
|
nodeVersions := nodeVersionsResult.NodeVersions
|
|
apiNodeVersions := make([]drip.NodeVersion, 0, len(nodeVersions))
|
|
for _, dbNodeVersion := range nodeVersions {
|
|
apiNodeVersions = append(apiNodeVersions, *mapper.DbNodeVersionToApiNodeVersion(dbNodeVersion))
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Found %d versions for node %s", len(apiNodeVersions), request.NodeId)
|
|
return drip.ListNodeVersions200JSONResponse(apiNodeVersions), nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) PublishNodeVersion(
|
|
ctx context.Context, request drip.PublishNodeVersionRequestObject) (drip.PublishNodeVersionResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.PublishNodeVersion")()
|
|
|
|
// Check if node exists, create if not
|
|
node, err := s.RegistryService.GetNode(ctx, s.Client, request.NodeId)
|
|
if err != nil && !ent.IsNotFound(err) {
|
|
// Case #1: Internal server error when getting node
|
|
log.Ctx(ctx).Error().Msgf("Failed to get node w/ err: %v", err)
|
|
return drip.PublishNodeVersion500JSONResponse{}, err
|
|
} else if err != nil {
|
|
// Case #2: Node not found, create a new node
|
|
node, err = s.RegistryService.CreateNode(ctx, s.Client, request.PublisherId, &request.Body.Node)
|
|
if mapper.IsErrorBadRequest(err) || ent.IsConstraintError(err) {
|
|
log.Ctx(ctx).Error().Msgf("Node creation failed w/ err: %v", err)
|
|
return drip.PublishNodeVersion400JSONResponse{Message: "Failed to create node", Error: err.Error()}, nil
|
|
}
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Node creation failed w/ err: %v", err)
|
|
return drip.PublishNodeVersion500JSONResponse{Message: "Failed to create node", Error: err.Error()}, nil
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Node %s created successfully", node.ID)
|
|
} else {
|
|
// Case #3: Node already exist, update the node
|
|
updateOneFunc := func(client *ent.Client) *ent.NodeUpdateOne {
|
|
return mapper.ApiUpdateNodeToUpdateFields(node.ID, &request.Body.Node, s.Client)
|
|
}
|
|
_, err = s.RegistryService.UpdateNode(ctx, s.Client, updateOneFunc)
|
|
if err != nil {
|
|
errMessage := "Failed to update node: " + err.Error()
|
|
log.Ctx(ctx).Error().Msgf("Node update failed w/ err: %v", err)
|
|
return drip.PublishNodeVersion400JSONResponse{Message: errMessage}, err
|
|
}
|
|
log.Ctx(ctx).Info().Msgf("Node %s updated successfully", node.ID)
|
|
}
|
|
|
|
// Create node version
|
|
nodeVersionCreation, err := s.RegistryService.CreateNodeVersion(
|
|
ctx, s.Client, request.PublisherId, node.ID, &request.Body.NodeVersion)
|
|
if err != nil {
|
|
if ent.IsConstraintError(err) {
|
|
return drip.PublishNodeVersion400JSONResponse{Message: "The node version already exists"}, nil
|
|
}
|
|
log.Ctx(ctx).Error().Msgf("Node version creation failed w/ err: %v", err)
|
|
return drip.PublishNodeVersion400JSONResponse{
|
|
Message: "Failed to create node version: " + err.Error(),
|
|
}, err
|
|
}
|
|
|
|
apiNodeVersion := mapper.DbNodeVersionToApiNodeVersion(nodeVersionCreation.NodeVersion)
|
|
log.Ctx(ctx).Info().Msgf("Node version %s published successfully", nodeVersionCreation.NodeVersion.ID)
|
|
return drip.PublishNodeVersion201JSONResponse{
|
|
NodeVersion: apiNodeVersion,
|
|
SignedUrl: &nodeVersionCreation.SignedUrl,
|
|
}, nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) UpdateNodeVersion(
|
|
ctx context.Context, request drip.UpdateNodeVersionRequestObject) (drip.UpdateNodeVersionResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.UpdateNodeVersion")()
|
|
|
|
// Update node version
|
|
updateOne := mapper.ApiUpdateNodeVersionToUpdateFields(request.VersionId, request.Body, s.Client)
|
|
version, err := s.RegistryService.UpdateNodeVersion(ctx, s.Client, updateOne)
|
|
if ent.IsNotFound(err) {
|
|
log.Ctx(ctx).Error().Msgf("Node %s or it's version not found w/ err: %v", request.NodeId, err)
|
|
return drip.UpdateNodeVersion404JSONResponse{Message: "Not Found"}, nil
|
|
}
|
|
if err != nil {
|
|
errMessage := "Failed to update node version"
|
|
log.Ctx(ctx).Error().Msgf("Node version update failed w/ err: %v", err)
|
|
return drip.UpdateNodeVersion500JSONResponse{Message: errMessage, Error: err.Error()}, err
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Node version %s updated successfully", request.VersionId)
|
|
return drip.UpdateNodeVersion200JSONResponse{
|
|
Changelog: &version.Changelog,
|
|
Deprecated: &version.Deprecated,
|
|
}, nil
|
|
}
|
|
|
|
// PostNodeVersionReview implements drip.StrictServerInterface.
|
|
func (s *DripStrictServerImplementation) PostNodeReview(ctx context.Context, request drip.PostNodeReviewRequestObject) (drip.PostNodeReviewResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.PostNodeReview")()
|
|
|
|
if request.Params.Star < 1 || request.Params.Star > 5 {
|
|
log.Ctx(ctx).Error().Msgf("Invalid star received: %d", request.Params.Star)
|
|
return drip.PostNodeReview400Response{}, nil
|
|
}
|
|
|
|
userId, err := mapper.GetUserIDFromContext(ctx)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to get user ID from context w/ err: %v", err)
|
|
return drip.PostNodeReview404JSONResponse{}, err
|
|
}
|
|
|
|
nv, err := s.RegistryService.AddNodeReview(ctx, s.Client, request.NodeId, userId, request.Params.Star)
|
|
if ent.IsNotFound(err) {
|
|
log.Ctx(ctx).Error().Msgf("Error retrieving node version w/ err: %v", err)
|
|
return drip.PostNodeReview404JSONResponse{}, nil
|
|
}
|
|
|
|
node := mapper.DbNodeToApiNode(nv)
|
|
log.Ctx(ctx).Info().Msgf("Node review for %s stored successfully", request.NodeId)
|
|
return drip.PostNodeReview200JSONResponse(*node), nil
|
|
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) DeleteNodeVersion(
|
|
ctx context.Context, request drip.DeleteNodeVersionRequestObject) (drip.DeleteNodeVersionResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.DeleteNodeVersion")()
|
|
|
|
nodeVersion, err := s.RegistryService.GetNodeVersion(ctx, s.Client, request.VersionId)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to get node version w/ err: %v", err)
|
|
return drip.DeleteNodeVersion404JSONResponse{Message: proto.String("Node version not found")}, nil
|
|
}
|
|
|
|
err = s.RegistryService.DeleteNodeVersion(ctx, s.Client, nodeVersion.ID.String())
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to delete node version w/ err: %v", err)
|
|
return drip.DeleteNodeVersion500JSONResponse{Message: "Failed to delete node version", Error: err.Error()}, err
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Node version %s deleted successfully", request.VersionId)
|
|
return drip.DeleteNodeVersion204Response{}, nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) GetNodeVersion(
|
|
ctx context.Context, request drip.GetNodeVersionRequestObject) (drip.GetNodeVersionResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.GetNodeVersion")()
|
|
|
|
nodeVersion, err := s.RegistryService.GetNodeVersionByVersion(ctx, s.Client, request.NodeId, request.VersionId)
|
|
if ent.IsNotFound(err) {
|
|
log.Ctx(ctx).Error().Msgf("Error retrieving node version w/ err: %v", err)
|
|
return drip.GetNodeVersion404JSONResponse{}, nil
|
|
}
|
|
if err != nil {
|
|
errMessage := "Failed to get node version"
|
|
log.Ctx(ctx).Error().Msgf("Error retrieving node version w/ err: %v", err)
|
|
return drip.GetNodeVersion500JSONResponse{
|
|
Message: errMessage,
|
|
Error: err.Error(),
|
|
}, err
|
|
}
|
|
|
|
apiNodeVersion := mapper.DbNodeVersionToApiNodeVersion(nodeVersion)
|
|
log.Ctx(ctx).Info().Msgf("Node version %s retrieved successfully", request.VersionId)
|
|
return drip.GetNodeVersion200JSONResponse(*apiNodeVersion), nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) ListPersonalAccessTokens(
|
|
ctx context.Context, request drip.ListPersonalAccessTokensRequestObject) (drip.ListPersonalAccessTokensResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.ListPersonalAccessTokens")()
|
|
|
|
// List personal access tokens
|
|
personalAccessTokens, err := s.RegistryService.ListPersonalAccessTokens(ctx, s.Client, request.PublisherId)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to list personal access tokens w/ err: %v", err)
|
|
errMessage := "Failed to list personal access tokens."
|
|
return drip.ListPersonalAccessTokens500JSONResponse{Message: errMessage, Error: err.Error()}, err
|
|
}
|
|
|
|
apiTokens := make([]drip.PersonalAccessToken, 0, len(personalAccessTokens))
|
|
for _, dbToken := range personalAccessTokens {
|
|
apiTokens = append(apiTokens, *mapper.DbToApiPersonalAccessToken(dbToken))
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Listed %d personal access tokens for "+
|
|
"publisher ID: %s", len(apiTokens), request.PublisherId)
|
|
return drip.ListPersonalAccessTokens200JSONResponse(apiTokens), nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) CreatePersonalAccessToken(
|
|
ctx context.Context, request drip.CreatePersonalAccessTokenRequestObject) (drip.CreatePersonalAccessTokenResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.CreatePersonalAccessToken")()
|
|
|
|
// Create personal access token
|
|
description := ""
|
|
if request.Body.Description != nil {
|
|
description = *request.Body.Description
|
|
}
|
|
|
|
personalAccessToken, err := s.RegistryService.CreatePersonalAccessToken(
|
|
ctx, s.Client, request.PublisherId, *request.Body.Name, description)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to create personal access token w/ err: %v", err)
|
|
errMessage := "Failed to create personal access token: " + err.Error()
|
|
return drip.CreatePersonalAccessToken500JSONResponse{Message: errMessage}, err
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Personal access token created "+
|
|
"successfully for publisher ID: %s", request.PublisherId)
|
|
return drip.CreatePersonalAccessToken201JSONResponse{
|
|
Token: &personalAccessToken.Token,
|
|
}, nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) DeletePersonalAccessToken(
|
|
ctx context.Context, request drip.DeletePersonalAccessTokenRequestObject) (drip.DeletePersonalAccessTokenResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.DeletePersonalAccessToken")()
|
|
|
|
// Retrieve user ID from context
|
|
userId, err := mapper.GetUserIDFromContext(ctx)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to get user ID from context w/ err: %v", err)
|
|
return drip.DeletePersonalAccessToken404JSONResponse{Message: "Invalid user ID"}, err
|
|
}
|
|
|
|
// Assert access token belongs to publisher
|
|
err = s.RegistryService.AssertAccessTokenBelongsToPublisher(ctx, s.Client, request.PublisherId, uuid.MustParse(request.TokenId))
|
|
switch {
|
|
case ent.IsNotFound(err):
|
|
log.Ctx(ctx).Warn().Msgf("Publisher with ID %s not found", request.PublisherId)
|
|
return drip.DeletePersonalAccessToken404JSONResponse{Message: "Publisher not found"}, nil
|
|
|
|
case drip_services.IsPermissionError(err):
|
|
log.Ctx(ctx).Warn().Msgf(
|
|
"Permission denied for user ID %s on publisher ID %s w/ err: %v", userId, request.PublisherId, err)
|
|
return drip.DeletePersonalAccessToken403JSONResponse{}, err
|
|
|
|
case err != nil:
|
|
log.Ctx(ctx).Warn().Msgf("Failed to assert publisher permission %s w/ err: %v", request.PublisherId, err)
|
|
return drip.DeletePersonalAccessToken500JSONResponse{Message: "Failed to assert publisher permission", Error: err.Error()}, err
|
|
}
|
|
|
|
// Delete personal access token
|
|
err = s.RegistryService.DeletePersonalAccessToken(ctx, s.Client, uuid.MustParse(request.TokenId))
|
|
if err != nil {
|
|
errMessage := "Failed to delete personal access token: " + err.Error()
|
|
log.Ctx(ctx).Error().Msgf("Token deletion failed w/ err: %v", err)
|
|
return drip.DeletePersonalAccessToken500JSONResponse{Message: errMessage}, err
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Personal access token %s deleted successfully", request.TokenId)
|
|
return drip.DeletePersonalAccessToken204Response{}, nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) InstallNode(
|
|
ctx context.Context, request drip.InstallNodeRequestObject) (drip.InstallNodeResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.InstallNode")()
|
|
|
|
// TODO(robinhuang): Refactor to separate class
|
|
// Get node
|
|
node, err := s.RegistryService.GetNode(ctx, s.Client, request.NodeId)
|
|
if ent.IsNotFound(err) {
|
|
log.Ctx(ctx).Error().Msgf("Error retrieving node w/ err: %v", err)
|
|
return drip.InstallNode404JSONResponse{Message: "Node not found"}, nil
|
|
}
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Error retrieving node w/ err: %v", err)
|
|
return drip.InstallNode500JSONResponse{Message: "Failed to get node"}, err
|
|
}
|
|
|
|
// Install node version
|
|
if request.Params.Version == nil {
|
|
s.MixpanelService.Track(ctx, []*mixpanel.Event{
|
|
s.MixpanelService.NewEvent("Install Node", "", map[string]any{
|
|
"Node ID": request.NodeId,
|
|
"Version": "latest",
|
|
}),
|
|
})
|
|
nodeVersion, err := s.RegistryService.GetLatestNodeVersion(ctx, s.Client, request.NodeId)
|
|
if err == nil && nodeVersion == nil {
|
|
log.Ctx(ctx).Error().Msgf("Latest node version not found")
|
|
return drip.InstallNode404JSONResponse{Message: "Not found"}, nil
|
|
}
|
|
if err != nil {
|
|
errMessage := "Failed to get latest node version: " + err.Error()
|
|
log.Ctx(ctx).Error().Msgf("Error retrieving latest node version w/ err: %v", err)
|
|
return drip.InstallNode500JSONResponse{Message: errMessage}, err
|
|
}
|
|
|
|
_, err = s.RegistryService.RecordNodeInstallation(ctx, s.Client, node)
|
|
if err != nil {
|
|
errMessage := "Failed to get increment number of node version install: " + err.Error()
|
|
log.Ctx(ctx).Error().Msgf("Error incrementing number of latest node version install w/ err: %v", err)
|
|
return drip.InstallNode500JSONResponse{Message: errMessage}, err
|
|
}
|
|
|
|
return drip.InstallNode200JSONResponse(
|
|
*mapper.DbNodeVersionToApiNodeVersion(nodeVersion),
|
|
), nil
|
|
} else {
|
|
|
|
nodeVersion, err := s.RegistryService.GetNodeVersionByVersion(ctx, s.Client, request.NodeId, *request.Params.Version)
|
|
if ent.IsNotFound(err) {
|
|
log.Ctx(ctx).Error().Msgf("Error retrieving node version w/ err: %v", err)
|
|
return drip.InstallNode404JSONResponse{Message: "Not found"}, nil
|
|
}
|
|
if err != nil {
|
|
errMessage := "Failed to get specified node version: " + err.Error()
|
|
log.Ctx(ctx).Error().Msgf("Error retrieving node version w/ err: %v", err)
|
|
return drip.InstallNode500JSONResponse{Message: errMessage}, err
|
|
}
|
|
s.MixpanelService.Track(ctx, []*mixpanel.Event{
|
|
s.MixpanelService.NewEvent("Install Node", "", map[string]any{
|
|
"Node ID": request.NodeId,
|
|
"Version": request.Params.Version,
|
|
}),
|
|
})
|
|
_, err = s.RegistryService.RecordNodeInstallation(ctx, s.Client, node)
|
|
if err != nil {
|
|
errMessage := "Failed to get increment number of node version install: " + err.Error()
|
|
log.Ctx(ctx).Error().Msgf("Error incrementing number of latest node version install w/ err: %v", err)
|
|
return drip.InstallNode500JSONResponse{Message: errMessage}, err
|
|
}
|
|
return drip.InstallNode200JSONResponse(
|
|
*mapper.DbNodeVersionToApiNodeVersion(nodeVersion),
|
|
), nil
|
|
}
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) GetPermissionOnPublisherNodes(
|
|
ctx context.Context, request drip.GetPermissionOnPublisherNodesRequestObject) (drip.GetPermissionOnPublisherNodesResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.GetPermissionOnPublisherNodes")()
|
|
|
|
err := s.RegistryService.AssertNodeBelongsToPublisher(ctx, s.Client, request.PublisherId, request.NodeId)
|
|
if err != nil {
|
|
return drip.GetPermissionOnPublisherNodes200JSONResponse{CanEdit: proto.Bool(false)}, nil
|
|
}
|
|
|
|
return drip.GetPermissionOnPublisherNodes200JSONResponse{CanEdit: proto.Bool(true)}, nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) GetPermissionOnPublisher(
|
|
ctx context.Context, request drip.GetPermissionOnPublisherRequestObject) (drip.GetPermissionOnPublisherResponseObject, error) {
|
|
|
|
return drip.GetPermissionOnPublisher200JSONResponse{CanEdit: proto.Bool(true)}, nil
|
|
}
|
|
|
|
// BanPublisher implements drip.StrictServerInterface.
|
|
func (s *DripStrictServerImplementation) BanPublisher(ctx context.Context, request drip.BanPublisherRequestObject) (drip.BanPublisherResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.BanPublisher")()
|
|
|
|
userId, err := mapper.GetUserIDFromContext(ctx)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to get user ID from context w/ err: %v", err)
|
|
return drip.BanPublisher401Response{}, nil
|
|
}
|
|
user, err := s.Client.User.Get(ctx, userId)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to get user ID from context w/ err: %v", err)
|
|
return drip.BanPublisher401Response{}, nil
|
|
}
|
|
if !user.IsAdmin {
|
|
log.Ctx(ctx).Error().Msgf("User is not admin w/ err")
|
|
return drip.BanPublisher403JSONResponse{
|
|
Message: "User is not admin",
|
|
}, nil
|
|
}
|
|
|
|
err = s.RegistryService.BanPublisher(ctx, s.Client, request.PublisherId)
|
|
if ent.IsNotFound(err) {
|
|
log.Ctx(ctx).Error().Msgf("Publisher '%s' not found w/ err: %v", request.PublisherId, err)
|
|
return drip.BanPublisher404JSONResponse{
|
|
Message: "Publisher not found",
|
|
}, nil
|
|
}
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Error banning publisher w/ err: %v", err)
|
|
return drip.BanPublisher500JSONResponse{
|
|
Message: "Error banning publisher",
|
|
Error: err.Error(),
|
|
}, nil
|
|
}
|
|
return drip.BanPublisher204Response{}, nil
|
|
}
|
|
|
|
// BanPublisherNode implements drip.StrictServerInterface.
|
|
func (s *DripStrictServerImplementation) BanPublisherNode(ctx context.Context, request drip.BanPublisherNodeRequestObject) (drip.BanPublisherNodeResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.BanPublisherNode")()
|
|
|
|
userId, err := mapper.GetUserIDFromContext(ctx)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to get user ID from context w/ err: %v", err)
|
|
return drip.BanPublisherNode401Response{}, nil
|
|
}
|
|
user, err := s.Client.User.Get(ctx, userId)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to get user ID from context w/ err: %v", err)
|
|
return drip.BanPublisherNode401Response{}, nil
|
|
}
|
|
if !user.IsAdmin {
|
|
log.Ctx(ctx).Error().Msgf("User is not admin w/ err")
|
|
return drip.BanPublisherNode403JSONResponse{
|
|
Message: "User is not admin",
|
|
}, nil
|
|
}
|
|
|
|
err = s.RegistryService.BanNode(ctx, s.Client, request.PublisherId, request.NodeId)
|
|
if ent.IsNotFound(err) {
|
|
log.Ctx(ctx).Error().Msgf("Publisher '%s' or node '%s' not found w/ err: %v", request.PublisherId, request.NodeId, err)
|
|
return drip.BanPublisherNode404JSONResponse{
|
|
Message: "Publisher or Node not found",
|
|
}, nil
|
|
}
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Error banning node w/ err: %v", err)
|
|
return drip.BanPublisherNode500JSONResponse{
|
|
Message: "Error banning node",
|
|
Error: err.Error(),
|
|
}, nil
|
|
}
|
|
return drip.BanPublisherNode204Response{}, nil
|
|
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) AdminUpdateNodeVersion(
|
|
ctx context.Context, request drip.AdminUpdateNodeVersionRequestObject) (drip.AdminUpdateNodeVersionResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.AdminUpdateNodeVersion")()
|
|
|
|
userId, err := mapper.GetUserIDFromContext(ctx)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to get user ID from context w/ err: %v", err)
|
|
return drip.AdminUpdateNodeVersion401Response{}, nil
|
|
}
|
|
user, err := s.Client.User.Get(ctx, userId)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to get user ID from context w/ err: %v", err)
|
|
return drip.AdminUpdateNodeVersion401Response{}, nil
|
|
}
|
|
if !user.IsAdmin {
|
|
log.Ctx(ctx).Error().Msgf("User is not admin w/ err")
|
|
return drip.AdminUpdateNodeVersion403JSONResponse{
|
|
Message: "User is not admin",
|
|
}, nil
|
|
}
|
|
|
|
nodeVersion, err := s.RegistryService.GetNodeVersionByVersion(ctx, s.Client, request.NodeId, request.VersionNumber)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Error retrieving node version w/ err: %v", err)
|
|
if ent.IsNotFound(err) {
|
|
return drip.AdminUpdateNodeVersion404JSONResponse{}, nil
|
|
}
|
|
return drip.AdminUpdateNodeVersion500JSONResponse{}, err
|
|
}
|
|
|
|
dbNodeVersion := mapper.ApiNodeVersionStatusToDbNodeVersionStatus(*request.Body.Status)
|
|
statusReason := ""
|
|
if request.Body.StatusReason != nil {
|
|
statusReason = *request.Body.StatusReason
|
|
}
|
|
err = nodeVersion.Update().SetStatus(dbNodeVersion).SetStatusReason(statusReason).Exec(ctx)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to update node version w/ err: %v", err)
|
|
return drip.AdminUpdateNodeVersion500JSONResponse{}, err
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Node version %s updated successfully", request.VersionNumber)
|
|
return drip.AdminUpdateNodeVersion200JSONResponse{
|
|
Status: request.Body.Status,
|
|
}, nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) SecurityScan(
|
|
ctx context.Context, request drip.SecurityScanRequestObject) (drip.SecurityScanResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.SecurityScan")()
|
|
|
|
minAge := 30 * time.Minute
|
|
if request.Params.MinAge != nil {
|
|
minAge = *request.Params.MinAge
|
|
}
|
|
maxNodes := 50
|
|
if request.Params.MaxNodes != nil {
|
|
maxNodes = *request.Params.MaxNodes
|
|
}
|
|
|
|
nodeVersionsResult, err := s.RegistryService.ListNodeVersions(ctx, s.Client, &entity.NodeVersionFilter{
|
|
Status: []schema.NodeVersionStatus{schema.NodeVersionStatusPending},
|
|
MinAge: minAge,
|
|
PageSize: maxNodes,
|
|
Page: 1,
|
|
})
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to list node versions w/ err: %v", err)
|
|
return drip.SecurityScan500JSONResponse{}, err
|
|
}
|
|
|
|
nodeVersions := nodeVersionsResult.NodeVersions
|
|
log.Ctx(ctx).Info().Msgf("Found %d node versions to scan", len(nodeVersions))
|
|
for _, nodeVersion := range nodeVersions {
|
|
err := s.RegistryService.PerformSecurityCheck(ctx, s.Client, nodeVersion)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to perform security scan w/ err: %v", err)
|
|
}
|
|
}
|
|
return drip.SecurityScan200Response{}, nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) ListAllNodeVersions(
|
|
ctx context.Context, request drip.ListAllNodeVersionsRequestObject) (drip.ListAllNodeVersionsResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.ListAllNodeVersions")()
|
|
|
|
// Default values for pagination
|
|
page := 1
|
|
if request.Params.Page != nil {
|
|
page = *request.Params.Page
|
|
}
|
|
|
|
pageSize := 10
|
|
maxPageSize := 100
|
|
if request.Params.PageSize != nil {
|
|
// Validate pageSize
|
|
if *request.Params.PageSize > maxPageSize {
|
|
log.Ctx(ctx).Error().Msgf(
|
|
"Requested pageSize %d exceeds maximum allowed %d", *request.Params.PageSize, maxPageSize)
|
|
return drip.ListAllNodeVersions400JSONResponse{
|
|
Message: fmt.Sprintf(
|
|
"Invalid pageSize: %d. The maximum allowed is %d.", *request.Params.PageSize, maxPageSize),
|
|
}, nil
|
|
}
|
|
pageSize = *request.Params.PageSize
|
|
}
|
|
|
|
f := &entity.NodeVersionFilter{
|
|
Page: page,
|
|
PageSize: pageSize,
|
|
IncludeStatusReason: mapper.BoolPtrToBool(request.Params.IncludeStatusReason),
|
|
}
|
|
|
|
if request.Params.Statuses != nil {
|
|
f.Status = mapper.ApiNodeVersionStatusesToDbNodeVersionStatuses(request.Params.Statuses)
|
|
}
|
|
|
|
// Log the constructed filter
|
|
log.Ctx(ctx).Info().Msgf("Constructed Filter: %+v", f)
|
|
|
|
// List nodes from the registry service
|
|
nodeVersionResults, err := s.RegistryService.ListNodeVersions(ctx, s.Client, f)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to list node versions w/ err: %v", err)
|
|
return drip.ListAllNodeVersions500JSONResponse{
|
|
Message: "Failed to list node versions",
|
|
Error: err.Error(),
|
|
}, nil
|
|
}
|
|
|
|
// Handle no results
|
|
if len(nodeVersionResults.NodeVersions) == 0 {
|
|
log.Ctx(ctx).Info().Msgf("No node versions found. Total: %d", nodeVersionResults.Total)
|
|
return drip.ListAllNodeVersions200JSONResponse{
|
|
Versions: &[]drip.NodeVersion{},
|
|
Total: &nodeVersionResults.Total,
|
|
Page: &nodeVersionResults.Page,
|
|
PageSize: &nodeVersionResults.Limit,
|
|
TotalPages: &nodeVersionResults.TotalPages,
|
|
}, nil
|
|
}
|
|
|
|
// Transform DB results into API results
|
|
apiNodeVersions := make([]drip.NodeVersion, 0, len(nodeVersionResults.NodeVersions))
|
|
for _, dbNodeVersion := range nodeVersionResults.NodeVersions {
|
|
apiNodeVersions = append(apiNodeVersions, *mapper.DbNodeVersionToApiNodeVersion(dbNodeVersion))
|
|
}
|
|
|
|
// Log success
|
|
log.Ctx(ctx).Info().Msgf(
|
|
"Found %d node versions. Total: %d", len(nodeVersionResults.NodeVersions), nodeVersionResults.Total)
|
|
return drip.ListAllNodeVersions200JSONResponse{
|
|
Versions: &apiNodeVersions,
|
|
Total: &nodeVersionResults.Total,
|
|
Page: &nodeVersionResults.Page,
|
|
PageSize: &nodeVersionResults.Limit,
|
|
TotalPages: &nodeVersionResults.TotalPages,
|
|
}, nil
|
|
}
|
|
|
|
func (s *DripStrictServerImplementation) ReindexNodes(ctx context.Context, request drip.ReindexNodesRequestObject) (res drip.ReindexNodesResponseObject, err error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.ReindexNodes")()
|
|
|
|
// create new context with logger from original Context
|
|
reindexCtx := drip_logging.ReuseContextLogger(ctx, context.Background())
|
|
|
|
err = s.RegistryService.ReindexAllNodesBackground(
|
|
reindexCtx, s.Client, request.Params.MaxBatch, request.Params.MinAge)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to trigger reindex all nodes w/ err: %v", err)
|
|
return drip.ReindexNodes500JSONResponse{Message: "Failed to trigger reindex nodes", Error: err.Error()}, nil
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msgf("Triggering Reindex nodes successful")
|
|
return drip.ReindexNodes200Response{}, nil
|
|
}
|
|
|
|
// CreateComfyNodes bulk-stores comfy-nodes extraction result for a node version
|
|
func (impl *DripStrictServerImplementation) CreateComfyNodes(
|
|
ctx context.Context, request drip.CreateComfyNodesRequestObject) (res drip.CreateComfyNodesResponseObject, err error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.CreateComfyNodes")()
|
|
|
|
cb := mapper.ApiComfyNodeCloudBuildToDbComfyNodeCloudBuild(request.Body.CloudBuildInfo)
|
|
// Check if extraction was marked as unsuccessful
|
|
if request.Body.Success != nil && !*request.Body.Success {
|
|
reason := "unknown"
|
|
if request.Body.Reason != nil {
|
|
reason = *request.Body.Reason
|
|
}
|
|
log.Ctx(ctx).Warn().Msgf(
|
|
"Comfy nodes extraction failed for %s %s: %s", request.NodeId, request.Version, reason)
|
|
|
|
err = impl.RegistryService.MarkComfyNodeExtractionFailed(ctx, impl.Client, request.NodeId, request.Version, cb)
|
|
|
|
} else {
|
|
// Attempt to create comfy nodes in the registry
|
|
err = impl.RegistryService.CreateComfyNodes(
|
|
ctx, impl.Client, request.NodeId, request.Version, *request.Body.Nodes, cb)
|
|
}
|
|
|
|
// Handle specific error scenarios
|
|
if ent.IsNotFound(err) {
|
|
log.Ctx(ctx).Error().Stringer("cloud_build_info", cb).Msgf("Node or node version not found w/ err: %v", err)
|
|
return drip.CreateComfyNodes404JSONResponse{
|
|
Message: "Node or node version not found", Error: err.Error()}, nil
|
|
}
|
|
|
|
if errors.Is(err, drip_services.ErrComfyNodesAlreadyExist) {
|
|
log.Ctx(ctx).Error().Stringer("cloud_build_info", cb).Msgf(
|
|
"Comfy nodes extraction result for %s %s already set", request.NodeId, request.Version)
|
|
return drip.CreateComfyNodes409JSONResponse{
|
|
Message: "Comfy nodes extraction result already set", Error: err.Error()}, nil
|
|
}
|
|
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Stringer("cloud_build_info", cb).Msgf("Failed to store comfy nodes extraction w/ err: %v", err)
|
|
return drip.CreateComfyNodes500JSONResponse{
|
|
Message: "Failed to store comfy nodes extraction", Error: err.Error()}, nil
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Stringer("cloud_build_info", cb).Msg("CreateComfyNodes successful")
|
|
return drip.CreateComfyNodes204Response{}, nil
|
|
}
|
|
|
|
// GetComfyNode returns a specific comfy-node of a certain node version
|
|
func (impl *DripStrictServerImplementation) GetComfyNode(
|
|
ctx context.Context, request drip.GetComfyNodeRequestObject) (res drip.GetComfyNodeResponseObject, err error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.GetComfyNode")()
|
|
|
|
// Retrieve the comfy-node from the registry
|
|
n, err := impl.RegistryService.GetComfyNode(ctx, impl.Client, request.NodeId, request.Version, request.ComfyNodeId)
|
|
|
|
// Handle node or version not found
|
|
if ent.IsNotFound(err) {
|
|
log.Ctx(ctx).Error().Msgf("Node or node version or comfy node not found w/ err: %v", err)
|
|
return drip.GetComfyNode404JSONResponse{
|
|
Message: "Node or node version or comfy node not found", Error: err.Error()}, nil
|
|
}
|
|
|
|
// Map database comfy-node to API representation
|
|
cn := mapper.DBComfyNodeToApiComfyNode(n)
|
|
if cn == nil {
|
|
log.Ctx(ctx).Error().Msg("Comfy Node not found")
|
|
return drip.GetComfyNode404JSONResponse{Message: "Comfy Node not found"}, nil
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msg("GetComfyNode successful")
|
|
res = drip.GetComfyNode200JSONResponse(*cn)
|
|
return
|
|
}
|
|
|
|
// ComfyNodesBackfill triggers a backfill process for comfy-nodes
|
|
func (impl *DripStrictServerImplementation) ComfyNodesBackfill(
|
|
ctx context.Context, request drip.ComfyNodesBackfillRequestObject) (drip.ComfyNodesBackfillResponseObject, error) {
|
|
defer tracing.TraceDefaultSegment(ctx, "DripStrictServerImplementation.ComfyNodesBackfill")()
|
|
|
|
// Trigger the backfill process with a specified maximum node
|
|
err := impl.RegistryService.TriggerComfyNodesBackfill(ctx, impl.Client, request.Params.MaxNode)
|
|
if err != nil {
|
|
log.Ctx(ctx).Error().Msgf("Failed to trigger comfy nodes backfill w/ err: %v", err)
|
|
return drip.ComfyNodesBackfill500JSONResponse{
|
|
Message: "Failed to trigger comfy nodes backfill", Error: err.Error()}, nil
|
|
}
|
|
|
|
log.Ctx(ctx).Info().Msg("ComfyNodesBackfill successful")
|
|
return drip.ComfyNodesBackfill204Response{}, nil
|
|
}
|