slash-e/server/route/api/v1/collection_service.go
2024-08-31 22:04:24 +08:00

201 lines
7.0 KiB
Go

package v1
import (
"context"
"time"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
"google.golang.org/protobuf/types/known/timestamppb"
v1pb "github.com/yourselfhosted/slash/proto/gen/api/v1"
storepb "github.com/yourselfhosted/slash/proto/gen/store"
"github.com/yourselfhosted/slash/server/service/license"
"github.com/yourselfhosted/slash/store"
)
func (s *APIV1Service) ListCollections(ctx context.Context, _ *v1pb.ListCollectionsRequest) (*v1pb.ListCollectionsResponse, error) {
collections, err := s.Store.ListCollections(ctx, &store.FindCollection{})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get collection list, err: %v", err)
}
convertedCollections := []*v1pb.Collection{}
for _, collection := range collections {
convertedCollections = append(convertedCollections, convertCollectionFromStore(collection))
}
response := &v1pb.ListCollectionsResponse{
Collections: convertedCollections,
}
return response, nil
}
func (s *APIV1Service) GetCollection(ctx context.Context, request *v1pb.GetCollectionRequest) (*v1pb.Collection, error) {
collection, err := s.Store.GetCollection(ctx, &store.FindCollection{
ID: &request.Id,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get collection by name: %v", err)
}
if collection == nil {
return nil, status.Errorf(codes.NotFound, "collection not found")
}
user, err := getCurrentUser(ctx, s.Store)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
}
if user == nil && collection.Visibility != storepb.Visibility_PUBLIC {
return nil, status.Errorf(codes.PermissionDenied, "Permission denied")
}
return convertCollectionFromStore(collection), nil
}
func (s *APIV1Service) GetCollectionByName(ctx context.Context, request *v1pb.GetCollectionByNameRequest) (*v1pb.Collection, error) {
collection, err := s.Store.GetCollection(ctx, &store.FindCollection{
Name: &request.Name,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get collection by name: %v", err)
}
if collection == nil {
return nil, status.Errorf(codes.NotFound, "collection not found")
}
user, err := getCurrentUser(ctx, s.Store)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
}
if user == nil && collection.Visibility != storepb.Visibility_PUBLIC {
return nil, status.Errorf(codes.PermissionDenied, "Permission denied")
}
return convertCollectionFromStore(collection), nil
}
func (s *APIV1Service) CreateCollection(ctx context.Context, request *v1pb.CreateCollectionRequest) (*v1pb.Collection, error) {
if request.Collection.Name == "" || request.Collection.Title == "" {
return nil, status.Errorf(codes.InvalidArgument, "name and title are required")
}
if !s.LicenseService.IsFeatureEnabled(license.FeatureTypeUnlimitedCollections) {
collections, err := s.Store.ListCollections(ctx, &store.FindCollection{})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get collection list, err: %v", err)
}
collectionsLimit := int(s.LicenseService.GetSubscription().CollectionsLimit)
if len(collections) >= collectionsLimit {
return nil, status.Errorf(codes.PermissionDenied, "Maximum number of collections %d reached", collectionsLimit)
}
}
user, err := getCurrentUser(ctx, s.Store)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
}
collectionCreate := &storepb.Collection{
CreatorId: user.ID,
Name: request.Collection.Name,
Title: request.Collection.Title,
Description: request.Collection.Description,
ShortcutIds: request.Collection.ShortcutIds,
Visibility: convertVisibilityToStorepb(request.Collection.Visibility),
}
collection, err := s.Store.CreateCollection(ctx, collectionCreate)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to create collection, err: %v", err)
}
return convertCollectionFromStore(collection), nil
}
func (s *APIV1Service) UpdateCollection(ctx context.Context, request *v1pb.UpdateCollectionRequest) (*v1pb.Collection, error) {
if request.UpdateMask == nil || len(request.UpdateMask.Paths) == 0 {
return nil, status.Errorf(codes.InvalidArgument, "updateMask is required")
}
user, err := getCurrentUser(ctx, s.Store)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
}
collection, err := s.Store.GetCollection(ctx, &store.FindCollection{
ID: &request.Collection.Id,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get collection by name: %v", err)
}
if collection == nil {
return nil, status.Errorf(codes.NotFound, "collection not found")
}
if collection.CreatorId != user.ID && user.Role != store.RoleAdmin {
return nil, status.Errorf(codes.PermissionDenied, "Permission denied")
}
update := &store.UpdateCollection{
ID: collection.Id,
}
for _, path := range request.UpdateMask.Paths {
switch path {
case "name":
update.Name = &request.Collection.Name
case "title":
update.Title = &request.Collection.Title
case "description":
update.Description = &request.Collection.Description
case "shortcut_ids":
update.ShortcutIDs = request.Collection.ShortcutIds
case "visibility":
visibility := convertVisibilityToStorepb(request.Collection.Visibility)
update.Visibility = &visibility
}
}
collection, err = s.Store.UpdateCollection(ctx, update)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to update collection, err: %v", err)
}
return convertCollectionFromStore(collection), nil
}
func (s *APIV1Service) DeleteCollection(ctx context.Context, request *v1pb.DeleteCollectionRequest) (*emptypb.Empty, error) {
user, err := getCurrentUser(ctx, s.Store)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
}
collection, err := s.Store.GetCollection(ctx, &store.FindCollection{
ID: &request.Id,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get collection by name: %v", err)
}
if collection == nil {
return nil, status.Errorf(codes.NotFound, "collection not found")
}
if collection.CreatorId != user.ID && user.Role != store.RoleAdmin {
return nil, status.Errorf(codes.PermissionDenied, "Permission denied")
}
err = s.Store.DeleteCollection(ctx, &store.DeleteCollection{
ID: collection.Id,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to delete collection, err: %v", err)
}
return &emptypb.Empty{}, nil
}
func convertCollectionFromStore(collection *storepb.Collection) *v1pb.Collection {
return &v1pb.Collection{
Id: collection.Id,
CreatorId: collection.CreatorId,
CreatedTime: timestamppb.New(time.Unix(collection.CreatedTs, 0)),
UpdatedTime: timestamppb.New(time.Unix(collection.UpdatedTs, 0)),
Name: collection.Name,
Title: collection.Title,
Description: collection.Description,
ShortcutIds: collection.ShortcutIds,
Visibility: convertVisibilityFromStorepb(collection.Visibility),
}
}