feat(sharing): remove code redeem, unify Teilen button and team/user sharing across lists and notes
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 58s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 58s
This commit is contained in:
1 parent
20c50aa8d6
commit
7c47f245e2
6 files changed
+440
-226
No files matched your search
+59
-2
@@ -921,18 +921,46 @@ func (s *Server) handleCreateDocShare(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
UserID string `json:"userId"`
|
||||
Email string `json:"email"`
|
||||
TeamID string `json:"teamId"`
|
||||
Permission string `json:"permission"` // read | write
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "Ungültiges JSON")
|
||||
return
|
||||
}
|
||||
|
||||
if req.TeamID != "" {
|
||||
members, err := s.store.GetTeamMembers(req.TeamID)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "Team nicht gefunden")
|
||||
return
|
||||
}
|
||||
var lastShare *domain.DocShare
|
||||
for _, tm := range members {
|
||||
if tm.UserID == userID {
|
||||
continue
|
||||
}
|
||||
share, err := s.store.CreateDocShare(userID, docID, tm.UserID, req.Permission)
|
||||
if err == nil && share != nil {
|
||||
lastShare = share
|
||||
s.wsHub.BroadcastToUser(share.UserID, "DOC_SHARED", share)
|
||||
s.wsHub.BroadcastDocEvent(docID, "DOC_SHARED", share)
|
||||
}
|
||||
}
|
||||
if lastShare != nil {
|
||||
writeJSON(w, http.StatusCreated, lastShare)
|
||||
} else {
|
||||
writeJSON(w, http.StatusOK, map[string]bool{"success": true})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
target := req.UserID
|
||||
if target == "" {
|
||||
target = req.Email
|
||||
}
|
||||
if target == "" {
|
||||
writeError(w, http.StatusBadRequest, "Benutzer-ID oder E-Mail erforderlich")
|
||||
writeError(w, http.StatusBadRequest, "Benutzer-ID, E-Mail oder Team erforderlich")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1089,18 +1117,47 @@ func (s *Server) handleAddSpaceMember(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
UserID string `json:"userId"`
|
||||
Email string `json:"email"`
|
||||
TeamID string `json:"teamId"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "Ungültiges JSON")
|
||||
return
|
||||
}
|
||||
|
||||
if req.Role != "owner" && req.Role != "editor" && req.Role != "viewer" {
|
||||
req.Role = "editor"
|
||||
}
|
||||
|
||||
if req.TeamID != "" {
|
||||
members, err := s.store.GetTeamMembers(req.TeamID)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusBadRequest, "Team nicht gefunden")
|
||||
return
|
||||
}
|
||||
var lastMember *domain.SpaceMember
|
||||
for _, tm := range members {
|
||||
member, err := s.store.AddSpaceMember(currentUserID, spaceID, tm.UserID, req.Role)
|
||||
if err == nil && member != nil {
|
||||
lastMember = member
|
||||
s.wsHub.BroadcastToUser(member.UserID, "SPACE_JOINED", map[string]interface{}{"spaceId": spaceID})
|
||||
s.wsHub.Broadcast(spaceID, "", "MEMBER_ADDED", member)
|
||||
}
|
||||
}
|
||||
if lastMember != nil {
|
||||
writeJSON(w, http.StatusCreated, lastMember)
|
||||
} else {
|
||||
writeJSON(w, http.StatusOK, map[string]bool{"success": true})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
target := req.UserID
|
||||
if target == "" {
|
||||
target = req.Email
|
||||
}
|
||||
if target == "" {
|
||||
writeError(w, http.StatusBadRequest, "Benutzer-ID, Benutzername oder E-Mail erforderlich")
|
||||
writeError(w, http.StatusBadRequest, "Benutzer-ID, Benutzername, E-Mail oder Team erforderlich")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -618,6 +618,44 @@ func TestSpaceMembersDirectInvitationAPI(t *testing.T) {
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200 OK for remove member, got %d: %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
|
||||
// 5. Test adding a team to a space
|
||||
team, err := store.CreateTeam("", "WG Team", "Haushalt")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create team: %v", err)
|
||||
}
|
||||
_ = store.AddTeamMember(team.ID, normalUser.ID, "member")
|
||||
|
||||
addTeamBody := []byte(`{"teamId":"` + team.ID + `","role":"editor"}`)
|
||||
req = httptest.NewRequest(http.MethodPost, "/api/v1/spaces/"+createdSpace.ID+"/members", bytes.NewReader(addTeamBody))
|
||||
req.Header.Set("Authorization", "Bearer "+adminToken)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
rec = httptest.NewRecorder()
|
||||
router.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusCreated && rec.Code != http.StatusOK {
|
||||
t.Fatalf("expected 201 or 200 for add space team, got %d: %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
|
||||
// User should see the space again because their team was added
|
||||
req = httptest.NewRequest(http.MethodGet, "/api/v1/spaces", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+userToken)
|
||||
rec = httptest.NewRecorder()
|
||||
router.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200 OK for user spaces after team add, got %d", rec.Code)
|
||||
}
|
||||
userSpaces = nil
|
||||
_ = json.Unmarshal(rec.Body.Bytes(), &userSpaces)
|
||||
found = false
|
||||
for _, s := range userSpaces {
|
||||
if s.ID == createdSpace.ID {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatalf("expected space %s to be visible to user via team, got %+v", createdSpace.ID, userSpaces)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorkspaceTagsAPI(t *testing.T) {
|
||||
|
||||
@@ -2977,6 +2977,24 @@ func (s *Store) CreateTeam(orgID, name, description string) (*domain.Team, error
|
||||
if name == "" {
|
||||
return nil, errors.New("team name required")
|
||||
}
|
||||
orgID = strings.TrimSpace(orgID)
|
||||
if orgID == "" {
|
||||
orgID = "default"
|
||||
}
|
||||
|
||||
var orgExists int
|
||||
_ = s.db.QueryRow(`SELECT COUNT(*) FROM organizations WHERE id = ?`, orgID).Scan(&orgExists)
|
||||
if orgExists == 0 {
|
||||
var ownerID string
|
||||
_ = s.db.QueryRow(`SELECT id FROM users ORDER BY created_at ASC LIMIT 1`).Scan(&ownerID)
|
||||
if ownerID != "" {
|
||||
_, _ = s.db.Exec(
|
||||
`INSERT OR IGNORE INTO organizations (id, name, owner_id, created_at) VALUES (?, ?, ?, ?)`,
|
||||
orgID, "Standard", ownerID, domain.NowISO(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
team := &domain.Team{
|
||||
ID: domain.NewID("team"),
|
||||
OrgID: orgID,
|
||||
|
||||
Reference in new issue
Block a user