feat: organizations decide who sees whom; sharing only by owners
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m30s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m30s
- Server admins manage organizations (one per user); new admin section, organization on user creation and invites, setup creates the first one - Sharing modes private / organizations / open, enforced centrally (CanSee, CanShareWith) for directory, all shares and groups; unknown and invisible targets give the same error - Losing visibility (org change, mode change, leaving a group) prunes shares, group memberships and task assignments; dry run warns before tightening - Only owners share; editors can no longer reshare lists or remove others' shares; legacy task_lists.team_id and old /organizations endpoints removed (FLAW-06, FLAW-10, FLAW-24) - Schema version: outdated databases are wiped and recreated on start - Fix setup sample data (createSampleData was ignored); setup and admin use a shared ToggleSwitch instead of checkboxes - Docs: sharing-and-permissions rewritten, ui-patterns, REST, DB, flaws Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
73fad1c5db
commit
84395f3322
26 files changed
+1421
-609
No files matched your search
@@ -15,6 +15,7 @@ func TestStoreLifecycle(t *testing.T) {
|
||||
dbPath := filepath.Join(tmpDir, "test_mindsift.db")
|
||||
|
||||
store, err := NewStore(dbPath)
|
||||
openSharing(t, store)
|
||||
if err != nil {
|
||||
t.Fatalf("NewStore failed: %v", err)
|
||||
}
|
||||
@@ -106,7 +107,7 @@ func TestStoreLifecycle(t *testing.T) {
|
||||
}
|
||||
|
||||
// 6. Test Organizations & Teams
|
||||
org, err := store.CreateOrganization(user.ID, "Mindsift Inc")
|
||||
org, err := store.CreateOrganization("Mindsift Inc")
|
||||
if err != nil || org.ID == "" {
|
||||
t.Fatalf("CreateOrganization failed: %v", err)
|
||||
}
|
||||
@@ -138,7 +139,7 @@ func TestStoreLifecycle(t *testing.T) {
|
||||
if err != nil || sysSettings.InstanceName == "" {
|
||||
t.Fatalf("GetSystemSettings failed: %v", err)
|
||||
}
|
||||
sysSettings.SharingMode = "teams_only"
|
||||
sysSettings.SharingMode = SharingOpen
|
||||
err = store.UpdateSystemSettings(sysSettings)
|
||||
if err != nil {
|
||||
t.Fatalf("UpdateSystemSettings failed: %v", err)
|
||||
@@ -179,7 +180,7 @@ func TestStoreLifecycle(t *testing.T) {
|
||||
t.Fatalf("viewer must not delete tasks, got %v", err)
|
||||
}
|
||||
newTitle := "Umbenannt"
|
||||
if _, err := store.UpdateTaskList(user2.ID, taskList.ID, &newTitle, nil, nil, nil, nil, nil); !errors.Is(err, ErrTaskListReadOnly) {
|
||||
if _, err := store.UpdateTaskList(user2.ID, taskList.ID, &newTitle, nil, nil, nil, nil); !errors.Is(err, ErrTaskListReadOnly) {
|
||||
t.Fatalf("viewer must not update task list, got %v", err)
|
||||
}
|
||||
if _, err := store.AddTaskListShare(taskList.ID, "user", user2.ID, "editor", user.ID); err != nil {
|
||||
@@ -236,6 +237,7 @@ func TestPerUserDocPinning(t *testing.T) {
|
||||
dbPath := filepath.Join(tmpDir, "pin_test.db")
|
||||
|
||||
store, err := NewStore(dbPath)
|
||||
openSharing(t, store)
|
||||
if err != nil {
|
||||
t.Fatalf("NewStore failed: %v", err)
|
||||
}
|
||||
@@ -312,6 +314,7 @@ func TestEnsureDemoAccountsAndLoginLookup(t *testing.T) {
|
||||
dbPath := filepath.Join(tmpDir, "demo_test.db")
|
||||
|
||||
store, err := NewStore(dbPath)
|
||||
openSharing(t, store)
|
||||
if err != nil {
|
||||
t.Fatalf("NewStore failed: %v", err)
|
||||
}
|
||||
@@ -368,6 +371,7 @@ func TestFolderManagementAndDeletion(t *testing.T) {
|
||||
dbPath := filepath.Join(tmpDir, "folder_test.db")
|
||||
|
||||
store, err := NewStore(dbPath)
|
||||
openSharing(t, store)
|
||||
if err != nil {
|
||||
t.Fatalf("NewStore failed: %v", err)
|
||||
}
|
||||
@@ -441,6 +445,7 @@ func TestWorkspaceBlockHashtagsAndDetails(t *testing.T) {
|
||||
dbPath := filepath.Join(tmpDir, "tags_test.db")
|
||||
|
||||
store, err := NewStore(dbPath)
|
||||
openSharing(t, store)
|
||||
if err != nil {
|
||||
t.Fatalf("NewStore failed: %v", err)
|
||||
}
|
||||
@@ -542,6 +547,7 @@ func TestDatabaseFirstWorkspaceArchitecture(t *testing.T) {
|
||||
dbPath := filepath.Join(tmpDir, "test_db_first.db")
|
||||
|
||||
store, err := NewStore(dbPath)
|
||||
openSharing(t, store)
|
||||
if err != nil {
|
||||
t.Fatalf("NewStore failed: %v", err)
|
||||
}
|
||||
@@ -692,6 +698,7 @@ func TestBlockListAndDerivedData(t *testing.T) {
|
||||
dbPath := filepath.Join(tmpDir, "tabula_rasa_test.db")
|
||||
|
||||
store, err := NewStore(dbPath)
|
||||
openSharing(t, store)
|
||||
if err != nil {
|
||||
t.Fatalf("NewStore failed: %v", err)
|
||||
}
|
||||
@@ -752,4 +759,18 @@ func TestBlockListAndDerivedData(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// openSharing lets tests that are not about visibility share freely between their users.
|
||||
func openSharing(t *testing.T, store *Store) {
|
||||
t.Helper()
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
sys, err := store.GetSystemSettings()
|
||||
if err != nil {
|
||||
t.Fatalf("GetSystemSettings: %v", err)
|
||||
}
|
||||
sys.SharingMode = SharingOpen
|
||||
if err := store.UpdateSystemSettings(sys); err != nil {
|
||||
t.Fatalf("UpdateSystemSettings: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user