Diffdown is a real-time collaborative Markdown editor/previewer built on the AT Protocol diffdown.com

fix: correct invite URL path and fetch document from owner's PDS on accept

+27 -13
+27 -13
internal/handler/handler.go
··· 6 6 "html/template" 7 7 "log" 8 8 "net/http" 9 + "net/url" 9 10 "regexp" 10 11 "strings" 11 12 "time" ··· 502 503 return 503 504 } 504 505 505 - inviteLink := fmt.Sprintf("%s/doc/%s?invite=%s", h.BaseURL, rkey, invite.Token) 506 + inviteLink := fmt.Sprintf("%s/docs/%s/accept?invite=%s", h.BaseURL, rkey, invite.Token) 506 507 h.jsonResponse(w, map[string]string{"inviteLink": inviteLink}, http.StatusOK) 507 508 } 508 509 ··· 510 511 func (h *Handler) AcceptInvite(w http.ResponseWriter, r *http.Request) { 511 512 user := h.currentUser(r) 512 513 if user == nil { 513 - http.Redirect(w, r, "/auth/login", http.StatusSeeOther) 514 + // Preserve invite token through the login redirect. 515 + http.Redirect(w, r, "/auth/login?next="+url.QueryEscape(r.URL.String()), http.StatusSeeOther) 514 516 return 515 517 } 516 518 ··· 527 529 return 528 530 } 529 531 530 - session, err := h.DB.GetATProtoSession(user.ID) 531 - if err != nil || session == nil { 532 - http.Redirect(w, r, "/auth/atproto", http.StatusSeeOther) 532 + // The collaborator's session — needed to get their DID. 533 + collabSession, err := h.DB.GetATProtoSession(user.ID) 534 + if err != nil || collabSession == nil { 535 + http.Redirect(w, r, "/auth/atproto?next="+url.QueryEscape(r.URL.String()), http.StatusSeeOther) 536 + return 537 + } 538 + 539 + // Fetch and update the document from the OWNER's PDS, not the collaborator's. 540 + // The invite records the owner's DID in CreatedBy. 541 + ownerUser, err := h.DB.GetUserByDID(invite.CreatedBy) 542 + if err != nil { 543 + log.Printf("AcceptInvite: get owner by DID %s: %v", invite.CreatedBy, err) 544 + http.Error(w, "Document owner not found", http.StatusInternalServerError) 533 545 return 534 546 } 535 547 536 - client, err := h.xrpcClient(user.ID) 548 + ownerClient, err := h.xrpcClient(ownerUser.ID) 537 549 if err != nil { 538 - log.Printf("AcceptInvite: xrpc client: %v", err) 550 + log.Printf("AcceptInvite: owner xrpc client: %v", err) 539 551 http.Error(w, "Failed to connect to ATProto", http.StatusInternalServerError) 540 552 return 541 553 } 542 554 543 - doc, err := client.GetDocument(rKey) 555 + doc, err := ownerClient.GetDocument(rKey) 544 556 if err != nil { 557 + log.Printf("AcceptInvite: get document: %v", err) 545 558 http.Error(w, "Document not found", http.StatusNotFound) 546 559 return 547 560 } 548 561 562 + // Already a collaborator — just redirect. 549 563 for _, c := range doc.Collaborators { 550 - if c == session.DID { 564 + if c == collabSession.DID { 551 565 http.Redirect(w, r, "/docs/"+rKey, http.StatusSeeOther) 552 566 return 553 567 } 554 568 } 555 569 556 - doc.Collaborators = append(doc.Collaborators, session.DID) 557 - _, _, err = client.PutDocument(rKey, doc) 558 - if err != nil { 559 - log.Printf("AcceptInvite: add collaborator: %v", err) 570 + // Add collaborator DID and PUT back to owner's PDS. 571 + doc.Collaborators = append(doc.Collaborators, collabSession.DID) 572 + if _, _, err = ownerClient.PutDocument(rKey, doc); err != nil { 573 + log.Printf("AcceptInvite: put document: %v", err) 560 574 http.Error(w, "Failed to add collaborator", http.StatusInternalServerError) 561 575 return 562 576 }