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
|
|
@ -0,0 +1,28 @@
|
|||
package collection
|
||||
|
||||
// Repository defines the data access operations for collections
|
||||
type Repository interface {
|
||||
// Create stores a new collection record
|
||||
Create(collection *Collection) error
|
||||
|
||||
// Get retrieves a collection by its ID
|
||||
Get(id string) (*Collection, error)
|
||||
|
||||
// Update modifies an existing collection record
|
||||
Update(collection *Collection) error
|
||||
|
||||
// Delete removes a collection record by its ID
|
||||
Delete(id string) error
|
||||
|
||||
// List returns all collection records
|
||||
List() ([]*Collection, error)
|
||||
|
||||
// ListByParent returns all collections with a specific parent ID
|
||||
ListByParent(parentID string) ([]*Collection, error)
|
||||
|
||||
// ListRoot returns all root-level collections (no parent)
|
||||
ListRoot() ([]*Collection, error)
|
||||
|
||||
// Exists checks if a collection with the given ID exists
|
||||
Exists(id string) (bool, error)
|
||||
}
|
||||
98
native/desktop/maplefile/internal/domain/collection/model.go
Normal file
98
native/desktop/maplefile/internal/domain/collection/model.go
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
package collection
|
||||
|
||||
import "time"
|
||||
|
||||
// Collection represents a collection (folder/album) stored locally with sync capabilities.
|
||||
type Collection struct {
|
||||
// Identifiers (from cloud)
|
||||
ID string `json:"id"`
|
||||
ParentID string `json:"parent_id,omitempty"`
|
||||
OwnerID string `json:"owner_id"` // UserID from cloud
|
||||
|
||||
// Encryption data (from cloud)
|
||||
EncryptedCollectionKey string `json:"encrypted_collection_key"`
|
||||
Nonce string `json:"nonce"`
|
||||
|
||||
// Collection metadata (from cloud - name is decrypted client-side)
|
||||
Name string `json:"name"` // Decrypted name
|
||||
Description string `json:"description,omitempty"` // Optional description
|
||||
// CustomIcon is the decrypted custom icon for this collection.
|
||||
// Empty string means use default folder/album icon.
|
||||
// Contains either an emoji character (e.g., "📷") or "icon:<identifier>" for predefined icons.
|
||||
CustomIcon string `json:"custom_icon,omitempty"`
|
||||
|
||||
// Statistics (from cloud)
|
||||
TotalFiles int `json:"total_files"`
|
||||
TotalSizeInBytes int64 `json:"total_size_in_bytes"`
|
||||
|
||||
// Sharing info (from cloud)
|
||||
PermissionLevel string `json:"permission_level,omitempty"` // read_only, read_write, admin
|
||||
IsOwner bool `json:"is_owner"`
|
||||
OwnerName string `json:"owner_name,omitempty"`
|
||||
OwnerEmail string `json:"owner_email,omitempty"`
|
||||
|
||||
// Sync tracking (local only)
|
||||
SyncStatus SyncStatus `json:"sync_status"`
|
||||
LastSyncedAt time.Time `json:"last_synced_at,omitempty"`
|
||||
|
||||
// State from cloud
|
||||
State string `json:"state"` // active, deleted
|
||||
|
||||
// Timestamps (from cloud)
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ModifiedAt time.Time `json:"modified_at"`
|
||||
}
|
||||
|
||||
// SyncStatus defines the synchronization status of a collection
|
||||
type SyncStatus int
|
||||
|
||||
const (
|
||||
// SyncStatusCloudOnly indicates the collection metadata is synced from cloud
|
||||
SyncStatusCloudOnly SyncStatus = iota
|
||||
|
||||
// SyncStatusSynced indicates the collection is fully synchronized
|
||||
SyncStatusSynced
|
||||
)
|
||||
|
||||
// String returns a human-readable string representation of the sync status
|
||||
func (s SyncStatus) String() string {
|
||||
switch s {
|
||||
case SyncStatusCloudOnly:
|
||||
return "cloud_only"
|
||||
case SyncStatusSynced:
|
||||
return "synced"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// Collection state constants
|
||||
const (
|
||||
// StateActive indicates the collection is active
|
||||
StateActive = "active"
|
||||
|
||||
// StateDeleted indicates the collection is deleted
|
||||
StateDeleted = "deleted"
|
||||
)
|
||||
|
||||
// Permission level constants
|
||||
const (
|
||||
PermissionReadOnly = "read_only"
|
||||
PermissionReadWrite = "read_write"
|
||||
PermissionAdmin = "admin"
|
||||
)
|
||||
|
||||
// IsDeleted returns true if the collection is marked as deleted
|
||||
func (c *Collection) IsDeleted() bool {
|
||||
return c.State == StateDeleted
|
||||
}
|
||||
|
||||
// CanWrite returns true if the user has write permissions
|
||||
func (c *Collection) CanWrite() bool {
|
||||
return c.IsOwner || c.PermissionLevel == PermissionReadWrite || c.PermissionLevel == PermissionAdmin
|
||||
}
|
||||
|
||||
// CanAdmin returns true if the user has admin permissions
|
||||
func (c *Collection) CanAdmin() bool {
|
||||
return c.IsOwner || c.PermissionLevel == PermissionAdmin
|
||||
}
|
||||
58
native/desktop/maplefile/internal/domain/file/constants.go
Normal file
58
native/desktop/maplefile/internal/domain/file/constants.go
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package file
|
||||
|
||||
// SyncStatus defines the synchronization status of a file
|
||||
type SyncStatus int
|
||||
|
||||
const (
|
||||
// SyncStatusLocalOnly indicates the file exists only locally (not uploaded to cloud)
|
||||
SyncStatusLocalOnly SyncStatus = iota
|
||||
|
||||
// SyncStatusCloudOnly indicates the file exists only in the cloud (metadata synced, content not downloaded)
|
||||
SyncStatusCloudOnly
|
||||
|
||||
// SyncStatusSynced indicates the file exists both locally and in the cloud and is synchronized
|
||||
SyncStatusSynced
|
||||
|
||||
// SyncStatusModifiedLocally indicates the file exists in both places but has local changes pending upload
|
||||
SyncStatusModifiedLocally
|
||||
)
|
||||
|
||||
// String returns a human-readable string representation of the sync status
|
||||
func (s SyncStatus) String() string {
|
||||
switch s {
|
||||
case SyncStatusLocalOnly:
|
||||
return "local_only"
|
||||
case SyncStatusCloudOnly:
|
||||
return "cloud_only"
|
||||
case SyncStatusSynced:
|
||||
return "synced"
|
||||
case SyncStatusModifiedLocally:
|
||||
return "modified_locally"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// Storage mode constants define which file versions to keep locally
|
||||
const (
|
||||
// StorageModeEncryptedOnly - Only keep encrypted version locally (most secure)
|
||||
StorageModeEncryptedOnly = "encrypted_only"
|
||||
|
||||
// StorageModeDecryptedOnly - Only keep decrypted version locally (not recommended)
|
||||
StorageModeDecryptedOnly = "decrypted_only"
|
||||
|
||||
// StorageModeHybrid - Keep both encrypted and decrypted versions (default, convenient)
|
||||
StorageModeHybrid = "hybrid"
|
||||
)
|
||||
|
||||
// File state constants
|
||||
const (
|
||||
// StatePending is the initial state of a file before it is uploaded
|
||||
StatePending = "pending"
|
||||
|
||||
// StateActive indicates that the file is fully uploaded and ready for use
|
||||
StateActive = "active"
|
||||
|
||||
// StateDeleted marks the file as deleted
|
||||
StateDeleted = "deleted"
|
||||
)
|
||||
28
native/desktop/maplefile/internal/domain/file/interface.go
Normal file
28
native/desktop/maplefile/internal/domain/file/interface.go
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package file
|
||||
|
||||
// Repository defines the data access operations for files
|
||||
type Repository interface {
|
||||
// Create stores a new file record
|
||||
Create(file *File) error
|
||||
|
||||
// Get retrieves a file by its ID
|
||||
Get(id string) (*File, error)
|
||||
|
||||
// Update modifies an existing file record
|
||||
Update(file *File) error
|
||||
|
||||
// Delete removes a file record by its ID
|
||||
Delete(id string) error
|
||||
|
||||
// List returns all file records
|
||||
List() ([]*File, error)
|
||||
|
||||
// ListByCollection returns all files belonging to a specific collection
|
||||
ListByCollection(collectionID string) ([]*File, error)
|
||||
|
||||
// ListByStatus returns all files with a specific sync status
|
||||
ListByStatus(status SyncStatus) ([]*File, error)
|
||||
|
||||
// Exists checks if a file with the given ID exists
|
||||
Exists(id string) (bool, error)
|
||||
}
|
||||
88
native/desktop/maplefile/internal/domain/file/model.go
Normal file
88
native/desktop/maplefile/internal/domain/file/model.go
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
package file
|
||||
|
||||
import "time"
|
||||
|
||||
// File represents a file stored locally with sync capabilities.
|
||||
// This model combines cloud metadata with local storage tracking.
|
||||
type File struct {
|
||||
// Identifiers (from cloud)
|
||||
ID string `json:"id"`
|
||||
CollectionID string `json:"collection_id"`
|
||||
OwnerID string `json:"owner_id"` // UserID from cloud
|
||||
|
||||
// Encryption data (from cloud API response)
|
||||
EncryptedFileKey EncryptedFileKeyData `json:"encrypted_file_key"`
|
||||
FileKeyNonce string `json:"file_key_nonce"`
|
||||
EncryptedMetadata string `json:"encrypted_metadata"`
|
||||
MetadataNonce string `json:"metadata_nonce"`
|
||||
FileNonce string `json:"file_nonce"`
|
||||
|
||||
// File sizes (from cloud)
|
||||
EncryptedSizeInBytes int64 `json:"encrypted_file_size_in_bytes"`
|
||||
DecryptedSizeInBytes int64 `json:"decrypted_size_in_bytes,omitempty"`
|
||||
|
||||
// Local storage paths (local only)
|
||||
EncryptedFilePath string `json:"encrypted_file_path,omitempty"`
|
||||
FilePath string `json:"file_path,omitempty"`
|
||||
ThumbnailPath string `json:"thumbnail_path,omitempty"`
|
||||
|
||||
// Decrypted metadata (local only - populated after decryption)
|
||||
Name string `json:"name,omitempty"`
|
||||
MimeType string `json:"mime_type,omitempty"`
|
||||
Metadata *FileMetadata `json:"metadata,omitempty"`
|
||||
|
||||
// Sync tracking (local only)
|
||||
SyncStatus SyncStatus `json:"sync_status"`
|
||||
LastSyncedAt time.Time `json:"last_synced_at,omitempty"`
|
||||
|
||||
// State from cloud
|
||||
State string `json:"state"` // pending, active, deleted
|
||||
StorageMode string `json:"storage_mode"` // encrypted_only, hybrid, decrypted_only
|
||||
Version int `json:"version"` // Cloud version for conflict resolution
|
||||
|
||||
// Timestamps (from cloud)
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ModifiedAt time.Time `json:"modified_at"`
|
||||
|
||||
// Thumbnail URL (from cloud, for remote access)
|
||||
ThumbnailURL string `json:"thumbnail_url,omitempty"`
|
||||
}
|
||||
|
||||
// EncryptedFileKeyData matches the cloud API structure exactly
|
||||
type EncryptedFileKeyData struct {
|
||||
Ciphertext string `json:"ciphertext"`
|
||||
Nonce string `json:"nonce"`
|
||||
}
|
||||
|
||||
// FileMetadata represents decrypted file metadata (populated after decryption)
|
||||
type FileMetadata struct {
|
||||
Name string `json:"name"`
|
||||
MimeType string `json:"mime_type"`
|
||||
Size int64 `json:"size"`
|
||||
FileExtension string `json:"file_extension"`
|
||||
}
|
||||
|
||||
// IsCloudOnly returns true if the file only exists in the cloud
|
||||
func (f *File) IsCloudOnly() bool {
|
||||
return f.SyncStatus == SyncStatusCloudOnly
|
||||
}
|
||||
|
||||
// IsSynced returns true if the file is synchronized between local and cloud
|
||||
func (f *File) IsSynced() bool {
|
||||
return f.SyncStatus == SyncStatusSynced
|
||||
}
|
||||
|
||||
// IsLocalOnly returns true if the file only exists locally
|
||||
func (f *File) IsLocalOnly() bool {
|
||||
return f.SyncStatus == SyncStatusLocalOnly
|
||||
}
|
||||
|
||||
// HasLocalContent returns true if the file has local content (not just metadata)
|
||||
func (f *File) HasLocalContent() bool {
|
||||
return f.FilePath != "" || f.EncryptedFilePath != ""
|
||||
}
|
||||
|
||||
// IsDeleted returns true if the file is marked as deleted
|
||||
func (f *File) IsDeleted() bool {
|
||||
return f.State == StateDeleted
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package session
|
||||
|
||||
// Repository interface defines data access operations for sessions
|
||||
type Repository interface {
|
||||
// Save stores a session
|
||||
Save(session *Session) error
|
||||
|
||||
// Get retrieves the current session
|
||||
Get() (*Session, error)
|
||||
|
||||
// Delete removes the current session
|
||||
Delete() error
|
||||
|
||||
// Exists checks if a session exists
|
||||
Exists() (bool, error)
|
||||
}
|
||||
30
native/desktop/maplefile/internal/domain/session/model.go
Normal file
30
native/desktop/maplefile/internal/domain/session/model.go
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
package session
|
||||
|
||||
import "time"
|
||||
|
||||
// Session represents a user authentication session (domain entity)
|
||||
type Session struct {
|
||||
UserID string
|
||||
Email string
|
||||
AccessToken string
|
||||
RefreshToken string
|
||||
ExpiresAt time.Time
|
||||
CreatedAt time.Time
|
||||
|
||||
// Encrypted user data for password verification (stored during login)
|
||||
Salt string // Base64 encoded salt for password derivation
|
||||
EncryptedMasterKey string // Base64 encoded encrypted master key
|
||||
EncryptedPrivateKey string // Base64 encoded encrypted private key
|
||||
PublicKey string // Base64 encoded public key
|
||||
KDFAlgorithm string // Key derivation algorithm: "PBKDF2-SHA256"
|
||||
}
|
||||
|
||||
// IsExpired checks if the session has expired
|
||||
func (s *Session) IsExpired() bool {
|
||||
return time.Now().After(s.ExpiresAt)
|
||||
}
|
||||
|
||||
// IsValid checks if the session is valid (not expired and has tokens)
|
||||
func (s *Session) IsValid() bool {
|
||||
return !s.IsExpired() && s.AccessToken != "" && s.RefreshToken != ""
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package syncstate
|
||||
|
||||
// Repository defines the data access operations for sync state
|
||||
type Repository interface {
|
||||
// Get retrieves the current sync state
|
||||
Get() (*SyncState, error)
|
||||
|
||||
// Save persists the sync state
|
||||
Save(state *SyncState) error
|
||||
|
||||
// Reset clears the sync state (for fresh sync)
|
||||
Reset() error
|
||||
}
|
||||
77
native/desktop/maplefile/internal/domain/syncstate/model.go
Normal file
77
native/desktop/maplefile/internal/domain/syncstate/model.go
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
package syncstate
|
||||
|
||||
import "time"
|
||||
|
||||
// SyncState tracks the synchronization progress for collections and files.
|
||||
// It stores cursors from the API for incremental sync and timestamps for tracking.
|
||||
type SyncState struct {
|
||||
// Timestamps for tracking when sync occurred
|
||||
LastCollectionSync time.Time `json:"last_collection_sync"`
|
||||
LastFileSync time.Time `json:"last_file_sync"`
|
||||
|
||||
// Cursors from API responses (used for pagination)
|
||||
CollectionCursor string `json:"collection_cursor,omitempty"`
|
||||
FileCursor string `json:"file_cursor,omitempty"`
|
||||
|
||||
// Sync completion flags
|
||||
CollectionSyncComplete bool `json:"collection_sync_complete"`
|
||||
FileSyncComplete bool `json:"file_sync_complete"`
|
||||
}
|
||||
|
||||
// NewSyncState creates a new empty SyncState
|
||||
func NewSyncState() *SyncState {
|
||||
return &SyncState{}
|
||||
}
|
||||
|
||||
// IsCollectionSyncComplete returns true if all collections have been synced
|
||||
func (s *SyncState) IsCollectionSyncComplete() bool {
|
||||
return s.CollectionSyncComplete
|
||||
}
|
||||
|
||||
// IsFileSyncComplete returns true if all files have been synced
|
||||
func (s *SyncState) IsFileSyncComplete() bool {
|
||||
return s.FileSyncComplete
|
||||
}
|
||||
|
||||
// IsFullySynced returns true if both collections and files are fully synced
|
||||
func (s *SyncState) IsFullySynced() bool {
|
||||
return s.CollectionSyncComplete && s.FileSyncComplete
|
||||
}
|
||||
|
||||
// ResetCollectionSync resets the collection sync state for a fresh sync
|
||||
func (s *SyncState) ResetCollectionSync() {
|
||||
s.CollectionCursor = ""
|
||||
s.CollectionSyncComplete = false
|
||||
s.LastCollectionSync = time.Time{}
|
||||
}
|
||||
|
||||
// ResetFileSync resets the file sync state for a fresh sync
|
||||
func (s *SyncState) ResetFileSync() {
|
||||
s.FileCursor = ""
|
||||
s.FileSyncComplete = false
|
||||
s.LastFileSync = time.Time{}
|
||||
}
|
||||
|
||||
// Reset resets both collection and file sync states
|
||||
func (s *SyncState) Reset() {
|
||||
s.ResetCollectionSync()
|
||||
s.ResetFileSync()
|
||||
}
|
||||
|
||||
// UpdateCollectionSync updates the collection sync state after a sync operation
|
||||
func (s *SyncState) UpdateCollectionSync(cursor string, hasMore bool) {
|
||||
s.CollectionCursor = cursor
|
||||
s.CollectionSyncComplete = !hasMore
|
||||
if !hasMore {
|
||||
s.LastCollectionSync = time.Now()
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateFileSync updates the file sync state after a sync operation
|
||||
func (s *SyncState) UpdateFileSync(cursor string, hasMore bool) {
|
||||
s.FileCursor = cursor
|
||||
s.FileSyncComplete = !hasMore
|
||||
if !hasMore {
|
||||
s.LastFileSync = time.Now()
|
||||
}
|
||||
}
|
||||
10
native/desktop/maplefile/internal/domain/user/interface.go
Normal file
10
native/desktop/maplefile/internal/domain/user/interface.go
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package user
|
||||
|
||||
// Repository defines the interface for user data persistence
|
||||
type Repository interface {
|
||||
Save(user *User) error
|
||||
GetByID(id string) (*User, error)
|
||||
GetByEmail(email string) (*User, error)
|
||||
Delete(id string) error
|
||||
Exists(id string) (bool, error)
|
||||
}
|
||||
19
native/desktop/maplefile/internal/domain/user/model.go
Normal file
19
native/desktop/maplefile/internal/domain/user/model.go
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package user
|
||||
|
||||
import "time"
|
||||
|
||||
// User represents a MapleFile user profile stored locally
|
||||
type User struct {
|
||||
ID string
|
||||
Email string
|
||||
FirstName string
|
||||
LastName string
|
||||
StorageQuotaBytes int64
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// IsValid checks if the user has the minimum required fields
|
||||
func (u *User) IsValid() bool {
|
||||
return u.ID != "" && u.Email != ""
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue