Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
160
cloud/maplefile-backend/internal/repo/collection/check.go
Normal file
160
cloud/maplefile-backend/internal/repo/collection/check.go
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
// monorepo/cloud/maplefile-backend/internal/maplefile/repo/collection/check.go
|
||||
package collection
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
dom_collection "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/collection"
|
||||
)
|
||||
|
||||
func (impl *collectionRepositoryImpl) CheckIfExistsByID(ctx context.Context, id gocql.UUID) (bool, error) {
|
||||
var count int
|
||||
|
||||
query := `SELECT COUNT(*) FROM collections_by_id WHERE id = ?`
|
||||
|
||||
if err := impl.Session.Query(query, id).WithContext(ctx).Scan(&count); err != nil {
|
||||
return false, fmt.Errorf("failed to check collection existence: %w", err)
|
||||
}
|
||||
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
// IsCollectionOwner demonstrates the memory-filtering approach for better performance
|
||||
// Instead of forcing Cassandra to scan with ALLOW FILTERING, we query efficiently and filter in memory
|
||||
func (impl *collectionRepositoryImpl) IsCollectionOwner(ctx context.Context, collectionID, userID gocql.UUID) (bool, error) {
|
||||
// Strategy: Use the compound partition key table to efficiently check ownership
|
||||
// This query is fast because both user_id and access_type are part of the partition key
|
||||
var collectionExists gocql.UUID
|
||||
|
||||
query := `SELECT collection_id FROM collections_by_user_id_and_access_type_with_desc_modified_at_and_asc_collection_id
|
||||
WHERE user_id = ? AND access_type = 'owner' AND collection_id = ? LIMIT 1 ALLOW FILTERING`
|
||||
|
||||
err := impl.Session.Query(query, userID, collectionID).WithContext(ctx).Scan(&collectionExists)
|
||||
if err != nil {
|
||||
if err == gocql.ErrNotFound {
|
||||
return false, nil
|
||||
}
|
||||
return false, fmt.Errorf("failed to check ownership: %w", err)
|
||||
}
|
||||
|
||||
// If we got a result, the user is an owner of this collection
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Alternative implementation using the memory-filtering approach
|
||||
// This demonstrates a different strategy when you can't avoid some filtering
|
||||
func (impl *collectionRepositoryImpl) IsCollectionOwnerAlternative(ctx context.Context, collectionID, userID gocql.UUID) (bool, error) {
|
||||
// Memory-filtering approach: Get all collections for this user, filter for the specific collection
|
||||
// This is efficient when users don't have thousands of collections
|
||||
|
||||
query := `SELECT collection_id, access_type FROM collections_by_user_id_with_desc_modified_at_and_asc_collection_id
|
||||
WHERE user_id = ?`
|
||||
|
||||
iter := impl.Session.Query(query, userID).WithContext(ctx).Iter()
|
||||
|
||||
var currentCollectionID gocql.UUID
|
||||
var accessType string
|
||||
|
||||
for iter.Scan(¤tCollectionID, &accessType) {
|
||||
// Check if this is the collection we're looking for and if the user is the owner
|
||||
if currentCollectionID == collectionID && accessType == "owner" {
|
||||
iter.Close()
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
if err := iter.Close(); err != nil {
|
||||
return false, fmt.Errorf("failed to check ownership: %w", err)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// CheckAccess uses the efficient compound partition key approach
|
||||
func (impl *collectionRepositoryImpl) CheckAccess(ctx context.Context, collectionID, userID gocql.UUID, requiredPermission string) (bool, error) {
|
||||
// First check if user is owner (owners have all permissions)
|
||||
isOwner, err := impl.IsCollectionOwner(ctx, collectionID, userID)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to check ownership: %w", err)
|
||||
}
|
||||
|
||||
if isOwner {
|
||||
return true, nil // Owners have all permissions
|
||||
}
|
||||
|
||||
// Check if user is a member with sufficient permissions
|
||||
var permissionLevel string
|
||||
|
||||
query := `SELECT permission_level FROM collections_by_user_id_and_access_type_with_desc_modified_at_and_asc_collection_id
|
||||
WHERE user_id = ? AND access_type = 'member' AND collection_id = ? LIMIT 1 ALLOW FILTERING`
|
||||
|
||||
err = impl.Session.Query(query, userID, collectionID).WithContext(ctx).Scan(&permissionLevel)
|
||||
if err != nil {
|
||||
if err == gocql.ErrNotFound {
|
||||
return false, nil // No access
|
||||
}
|
||||
return false, fmt.Errorf("failed to check member access: %w", err)
|
||||
}
|
||||
|
||||
// Check if user's permission level meets requirement
|
||||
return impl.hasPermission(permissionLevel, requiredPermission), nil
|
||||
}
|
||||
|
||||
// GetUserPermissionLevel efficiently determines a user's permission level for a collection
|
||||
func (impl *collectionRepositoryImpl) GetUserPermissionLevel(ctx context.Context, collectionID, userID gocql.UUID) (string, error) {
|
||||
// Check ownership first using the efficient compound key table
|
||||
isOwner, err := impl.IsCollectionOwner(ctx, collectionID, userID)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to check ownership: %w", err)
|
||||
}
|
||||
|
||||
if isOwner {
|
||||
return dom_collection.CollectionPermissionAdmin, nil
|
||||
}
|
||||
|
||||
// Check member permissions
|
||||
var permissionLevel string
|
||||
|
||||
query := `SELECT permission_level FROM collections_by_user_id_and_access_type_with_desc_modified_at_and_asc_collection_id
|
||||
WHERE user_id = ? AND access_type = 'member' AND collection_id = ? LIMIT 1 ALLOW FILTERING`
|
||||
|
||||
err = impl.Session.Query(query, userID, collectionID).WithContext(ctx).Scan(&permissionLevel)
|
||||
if err != nil {
|
||||
if err == gocql.ErrNotFound {
|
||||
return "", nil // No access
|
||||
}
|
||||
return "", fmt.Errorf("failed to get permission level: %w", err)
|
||||
}
|
||||
|
||||
return permissionLevel, nil
|
||||
}
|
||||
|
||||
// Demonstration of a completely ALLOW FILTERING-free approach using direct collection lookup
|
||||
// This approach queries the main collection table and checks ownership directly
|
||||
func (impl *collectionRepositoryImpl) CheckAccessByCollectionLookup(ctx context.Context, collectionID, userID gocql.UUID, requiredPermission string) (bool, error) {
|
||||
// Strategy: Get the collection directly and check ownership/membership from the collection object
|
||||
collection, err := impl.Get(ctx, collectionID)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to get collection: %w", err)
|
||||
}
|
||||
|
||||
if collection == nil {
|
||||
return false, nil // Collection doesn't exist
|
||||
}
|
||||
|
||||
// Check if user is the owner
|
||||
if collection.OwnerID == userID {
|
||||
return true, nil // Owners have all permissions
|
||||
}
|
||||
|
||||
// Check if user is a member with sufficient permissions
|
||||
for _, member := range collection.Members {
|
||||
if member.RecipientID == userID {
|
||||
return impl.hasPermission(member.PermissionLevel, requiredPermission), nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil // User has no access
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue