package webui import ( "net/http" "net/http/httptest" "strings" "testing" ) // TestWebmailFolderCreateShowsUpEvenWhenEmpty confirms a freshly created folder is // listed in the sidebar before it holds any messages — the reason // esrv_mailbox_folders exists at all (DistinctFoldersForMailbox alone can't prove a // folder exists until something's actually stored in it). func TestWebmailFolderCreateShowsUpEvenWhenEmpty(t *testing.T) { app := newTestApp(t) mux := app.Mux() domains, _ := app.DB.ListDomains() mailboxID := createTestMailboxWithPassword(t, app, "organizer2@example.com", domains[0].ID, "organizer-password-1!") cookie := webmailLoginSession(t, app, mailboxID) req := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/mail/folders/add", strings.NewReader("name=Receipts")) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.AddCookie(cookie) rec := httptest.NewRecorder() mux.ServeHTTP(rec, req) if rec.Code != http.StatusFound { t.Fatalf("add folder: status=%d body=%s", rec.Code, rec.Body.String()) } folders, err := app.DB.ListMailboxFolders(mailboxID) if err != nil || len(folders) != 1 || folders[0] != "Receipts" { t.Fatalf("expected [Receipts] in ListMailboxFolders, got %v (err=%v)", folders, err) } inboxReq := httptest.NewRequest(http.MethodGet, MailboxPrefix+"/mail/INBOX", nil) inboxReq.AddCookie(cookie) inboxRec := httptest.NewRecorder() mux.ServeHTTP(inboxRec, inboxReq) if !strings.Contains(inboxRec.Body.String(), `data-folder="Receipts"`) { t.Error("expected the empty new folder to appear in the sidebar") } } // TestWebmailFolderCreateRejectsStandardAndDuplicateNames confirms you can't create a // folder that collides with a standard folder or an existing custom one. func TestWebmailFolderCreateRejectsStandardAndDuplicateNames(t *testing.T) { app := newTestApp(t) mux := app.Mux() domains, _ := app.DB.ListDomains() mailboxID := createTestMailboxWithPassword(t, app, "organizer3@example.com", domains[0].ID, "organizer-password-1!") cookie := webmailLoginSession(t, app, mailboxID) create := func(name string) { t.Helper() req := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/mail/folders/add", strings.NewReader("name="+name)) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.AddCookie(cookie) rec := httptest.NewRecorder() mux.ServeHTTP(rec, req) if rec.Code != http.StatusFound { t.Fatalf("create %s: status=%d", name, rec.Code) } } create("Sent") // standard folder name — should be rejected, not duplicated create("Work") create("Work") // duplicate — should be rejected, not duplicated folders, err := app.DB.ListMailboxFolders(mailboxID) if err != nil { t.Fatal(err) } if len(folders) != 1 || folders[0] != "Work" { t.Fatalf("expected exactly [Work] (Sent rejected as standard, duplicate Work rejected), got %v", folders) } } // TestWebmailFolderDeleteMovesMessagesToInboxAndCannotDeleteStandard confirms // deleting a custom folder relocates its messages to INBOX, and that a standard // folder can't be deleted via the same route even if requested directly. func TestWebmailFolderDeleteMovesMessagesToInboxAndCannotDeleteStandard(t *testing.T) { app := newTestApp(t) mux := app.Mux() domains, _ := app.DB.ListDomains() mailboxID := createTestMailboxWithPassword(t, app, "organizer4@example.com", domains[0].ID, "organizer-password-1!") cookie := webmailLoginSession(t, app, mailboxID) if err := app.DB.CreateMailboxFolder(mailboxID, "Newsletters"); err != nil { t.Fatal(err) } raw := "From: a@example.com\r\nTo: organizer4@example.com\r\nSubject: hi\r\n\r\nbody" if _, err := app.Mailstore.StoreMessage(mailboxID, "Newsletters", []byte(raw), "m@example.com", "a@example.com", "hi"); err != nil { t.Fatal(err) } req := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/mail/folders/Newsletters/remove", nil) req.AddCookie(cookie) rec := httptest.NewRecorder() mux.ServeHTTP(rec, req) if rec.Code != http.StatusFound { t.Fatalf("delete folder: status=%d", rec.Code) } remaining, err := app.DB.ListMailboxFolders(mailboxID) if err != nil || len(remaining) != 0 { t.Fatalf("expected the folder record gone, got %v (err=%v)", remaining, err) } inboxMsgs, err := app.DB.ListMessagesInFolder(mailboxID, "INBOX") if err != nil || len(inboxMsgs) != 1 { t.Fatalf("expected the message relocated to INBOX, got %d (err=%v)", len(inboxMsgs), err) } // Attempting to delete a standard folder must be rejected, not silently succeed. stdReq := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/mail/folders/Sent/remove", nil) stdReq.AddCookie(cookie) stdRec := httptest.NewRecorder() mux.ServeHTTP(stdRec, stdReq) if stdRec.Code != http.StatusFound { t.Fatalf("delete standard folder: status=%d", stdRec.Code) } sentReq := httptest.NewRequest(http.MethodGet, MailboxPrefix+"/mail/Sent", nil) sentReq.AddCookie(cookie) sentRec := httptest.NewRecorder() mux.ServeHTTP(sentRec, sentReq) if sentRec.Code != http.StatusOK { t.Fatalf("Sent folder should still exist and render normally, status=%d", sentRec.Code) } }