From b03ca999a52f0dcbd4be2c560af76ae7487fdf5d Mon Sep 17 00:00:00 2001 From: Sung <8265228+sungwoncho@users.noreply.github.com> Date: Sun, 19 Oct 2025 18:32:20 -0700 Subject: [PATCH] Remove the unused encrypted and public fields (#700) * Remove encrypted fields from notes and books * Remove public from notes * Use consistent flags --- pkg/cli/cmd/sync/sync.go | 3 +- pkg/cli/crypt/crypto.go | 123 -------------- pkg/cli/crypt/crypto_test.go | 118 ------------- pkg/e2e/server_test.go | 30 +++- pkg/server/app/books.go | 13 +- pkg/server/app/notes.go | 53 ++---- pkg/server/app/notes_test.go | 49 +++--- pkg/server/cmd/helpers.go | 25 ++- pkg/server/controllers/books.go | 11 -- pkg/server/controllers/notes.go | 27 +-- pkg/server/controllers/notes_test.go | 185 ++------------------- pkg/server/controllers/routes.go | 2 +- pkg/server/controllers/sync.go | 2 - pkg/server/database/models.go | 3 - pkg/server/middleware/auth.go | 6 +- pkg/server/middleware/auth_test.go | 34 ++++ pkg/server/operations/notes_test.go | 51 ++---- pkg/server/permissions/permissions.go | 3 - pkg/server/permissions/permissions_test.go | 44 +---- pkg/server/presenters/note.go | 2 - pkg/server/presenters/note_test.go | 4 - pkg/server/tmpl/app_test.go | 40 ----- 22 files changed, 175 insertions(+), 653 deletions(-) delete mode 100644 pkg/cli/crypt/crypto.go delete mode 100644 pkg/cli/crypt/crypto_test.go diff --git a/pkg/cli/cmd/sync/sync.go b/pkg/cli/cmd/sync/sync.go index 28ec71a7..ec66a2cb 100644 --- a/pkg/cli/cmd/sync/sync.go +++ b/pkg/cli/cmd/sync/sync.go @@ -97,8 +97,7 @@ func (l syncList) getLength() int { return len(l.Notes) + len(l.Books) + len(l.ExpungedNotes) + len(l.ExpungedBooks) } -// processFragments categorizes items in sync fragments into a sync list. It also decrypts any -// encrypted data in sync fragments. +// processFragments categorizes items in sync fragments into a sync list. func processFragments(fragments []client.SyncFragment) (syncList, error) { notes := map[string]client.SyncFragNote{} books := map[string]client.SyncFragBook{} diff --git a/pkg/cli/crypt/crypto.go b/pkg/cli/crypt/crypto.go deleted file mode 100644 index 3637c7ca..00000000 --- a/pkg/cli/crypt/crypto.go +++ /dev/null @@ -1,123 +0,0 @@ -/* Copyright (C) 2019, 2020, 2021, 2022, 2023, 2024, 2025 Dnote contributors - * - * This file is part of Dnote. - * - * Dnote is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Dnote is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Dnote. If not, see . - */ - -// Package crypt provides cryptographic funcitonalities -package crypt - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/rand" - "crypto/sha256" - "encoding/base64" - "io" - - "github.com/pkg/errors" - "golang.org/x/crypto/hkdf" - "golang.org/x/crypto/pbkdf2" -) - -var aesGcmNonceSize = 12 - -func runHkdf(secret, salt, info []byte) ([]byte, error) { - r := hkdf.New(sha256.New, secret, salt, info) - - ret := make([]byte, 32) - _, err := io.ReadFull(r, ret) - if err != nil { - return []byte{}, errors.Wrap(err, "reading key bytes") - } - - return ret, nil -} - -// MakeKeys derives, from the given credential, a key set comprising of an encryption key -// and an authentication key -func MakeKeys(password, email []byte, iteration int) ([]byte, []byte, error) { - masterKey := pbkdf2.Key([]byte(password), []byte(email), iteration, 32, sha256.New) - - authKey, err := runHkdf(masterKey, email, []byte("auth")) - if err != nil { - return nil, nil, errors.Wrap(err, "deriving auth key") - } - - return masterKey, authKey, nil -} - -// AesGcmEncrypt encrypts the plaintext using AES in a GCM mode. It returns -// a ciphertext prepended by a 12 byte pseudo-random nonce, encoded in base64. -func AesGcmEncrypt(key, plaintext []byte) (string, error) { - if key == nil { - return "", errors.New("no key provided") - } - - block, err := aes.NewCipher(key) - if err != nil { - return "", errors.Wrap(err, "initializing aes") - } - - aesgcm, err := cipher.NewGCM(block) - if err != nil { - return "", errors.Wrap(err, "initializing gcm") - } - - nonce := make([]byte, aesGcmNonceSize) - if _, err := io.ReadFull(rand.Reader, nonce); err != nil { - return "", errors.Wrap(err, "generating nonce") - } - - ciphertext := aesgcm.Seal(nonce, nonce, []byte(plaintext), nil) - cipherKeyB64 := base64.StdEncoding.EncodeToString(ciphertext) - - return cipherKeyB64, nil -} - -// AesGcmDecrypt decrypts the encrypted data using AES in a GCM mode. The data should be -// a base64 encoded string in the format of 12 byte nonce followed by a ciphertext. -func AesGcmDecrypt(key []byte, dataB64 string) ([]byte, error) { - if key == nil { - return nil, errors.New("no key provided") - } - - data, err := base64.StdEncoding.DecodeString(dataB64) - if err != nil { - return nil, errors.Wrap(err, "decoding base64 data") - } - - block, err := aes.NewCipher(key) - if err != nil { - return nil, errors.Wrap(err, "initializing aes") - } - - aesgcm, err := cipher.NewGCM(block) - if err != nil { - return nil, errors.Wrap(err, "initializing gcm") - } - - if len(data) < aesGcmNonceSize { - return nil, errors.Wrap(err, "malformed data") - } - - nonce, ciphertext := data[:aesGcmNonceSize], data[aesGcmNonceSize:] - plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil) - if err != nil { - return nil, errors.Wrap(err, "decrypting") - } - - return plaintext, nil -} diff --git a/pkg/cli/crypt/crypto_test.go b/pkg/cli/crypt/crypto_test.go deleted file mode 100644 index 805e2724..00000000 --- a/pkg/cli/crypt/crypto_test.go +++ /dev/null @@ -1,118 +0,0 @@ -/* Copyright (C) 2019, 2020, 2021, 2022, 2023, 2024, 2025 Dnote contributors - * - * This file is part of Dnote. - * - * Dnote is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Dnote is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Dnote. If not, see . - */ - -package crypt - -import ( - "crypto/aes" - "crypto/cipher" - "encoding/base64" - "fmt" - "testing" - - "github.com/dnote/dnote/pkg/assert" - "github.com/pkg/errors" -) - -func TestAesGcmEncrypt(t *testing.T) { - testCases := []struct { - key []byte - plaintext []byte - }{ - { - key: []byte("AES256Key-32Characters1234567890"), - plaintext: []byte("foo bar baz quz"), - }, - { - key: []byte("AES256Key-32Charactersabcdefghij"), - plaintext: []byte("1234 foo 5678 bar 7890 baz"), - }, - } - - for _, tc := range testCases { - t.Run(fmt.Sprintf("key %s plaintext %s", tc.key, tc.plaintext), func(t *testing.T) { - // encrypt - dataB64, err := AesGcmEncrypt(tc.key, tc.plaintext) - if err != nil { - t.Fatal(errors.Wrap(err, "performing encryption")) - } - - // test that data can be decrypted - data, err := base64.StdEncoding.DecodeString(dataB64) - if err != nil { - t.Fatal(errors.Wrap(err, "decoding data from base64")) - } - - nonce, ciphertext := data[:12], data[12:] - - fmt.Println(string(data)) - - block, err := aes.NewCipher([]byte(tc.key)) - if err != nil { - t.Fatal(errors.Wrap(err, "initializing aes")) - } - - aesgcm, err := cipher.NewGCM(block) - if err != nil { - t.Fatal(errors.Wrap(err, "initializing gcm")) - } - - plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil) - if err != nil { - t.Fatal(errors.Wrap(err, "decode")) - } - - assert.DeepEqual(t, plaintext, tc.plaintext, "plaintext mismatch") - }) - } -} - -func TestAesGcmDecrypt(t *testing.T) { - testCases := []struct { - key []byte - ciphertextB64 string - expectedPlaintext string - }{ - { - key: []byte("AES256Key-32Characters1234567890"), - ciphertextB64: "M2ov9hWMQ52v1S/zigwX3bJt4cVCV02uiRm/grKqN/rZxNkJrD7vK4Ii0g==", - expectedPlaintext: "foo bar baz quz", - }, - { - key: []byte("AES256Key-32Characters1234567890"), - ciphertextB64: "M4csFKUIUbD1FBEzLgHjscoKgN0lhMGJ0n2nKWiCkE/qSKlRP7kS", - expectedPlaintext: "foo\n1\nbar\n2", - }, - { - key: []byte("AES256Key-32Characters1234567890"), - ciphertextB64: "pe/fnw73MR1clmVIlRSJ5gDwBdnPly/DF7DsR5dJVz4dHZlv0b10WzvJEGOCHZEr+Q==", - expectedPlaintext: "föo\nbār\nbåz & qūz", - }, - } - - for _, tc := range testCases { - t.Run(fmt.Sprintf("key %s ciphertext %s", tc.key, tc.ciphertextB64), func(t *testing.T) { - plaintext, err := AesGcmDecrypt(tc.key, tc.ciphertextB64) - if err != nil { - t.Fatal(errors.Wrap(err, "performing decryption")) - } - - assert.DeepEqual(t, plaintext, []byte(tc.expectedPlaintext), "plaintext mismatch") - }) - } -} diff --git a/pkg/e2e/server_test.go b/pkg/e2e/server_test.go index cfe6a711..39da46de 100644 --- a/pkg/e2e/server_test.go +++ b/pkg/e2e/server_test.go @@ -50,7 +50,7 @@ func TestServerStart(t *testing.T) { port := "13456" // Use different port to avoid conflicts with main test server // Start server in background - cmd := exec.Command(testServerBinary, "start", "-port", port) + cmd := exec.Command(testServerBinary, "start", "--port", port) cmd.Env = append(os.Environ(), "DBPath="+tmpDB, "WebURL=http://localhost:"+port, @@ -143,11 +143,11 @@ func TestServerStartHelp(t *testing.T) { outputStr := string(output) assert.Equal(t, strings.Contains(outputStr, "dnote-server start [flags]"), true, "output should contain usage") - assert.Equal(t, strings.Contains(outputStr, "-appEnv"), true, "output should contain appEnv flag") - assert.Equal(t, strings.Contains(outputStr, "-port"), true, "output should contain port flag") - assert.Equal(t, strings.Contains(outputStr, "-webUrl"), true, "output should contain webUrl flag") - assert.Equal(t, strings.Contains(outputStr, "-dbPath"), true, "output should contain dbPath flag") - assert.Equal(t, strings.Contains(outputStr, "-disableRegistration"), true, "output should contain disableRegistration flag") + assert.Equal(t, strings.Contains(outputStr, "--appEnv"), true, "output should contain appEnv flag") + assert.Equal(t, strings.Contains(outputStr, "--port"), true, "output should contain port flag") + assert.Equal(t, strings.Contains(outputStr, "--webUrl"), true, "output should contain webUrl flag") + assert.Equal(t, strings.Contains(outputStr, "--dbPath"), true, "output should contain dbPath flag") + assert.Equal(t, strings.Contains(outputStr, "--disableRegistration"), true, "output should contain disableRegistration flag") } func TestServerStartInvalidConfig(t *testing.T) { @@ -166,7 +166,7 @@ func TestServerStartInvalidConfig(t *testing.T) { assert.Equal(t, strings.Contains(outputStr, "Error:"), true, "output should contain error message") assert.Equal(t, strings.Contains(outputStr, "Invalid WebURL"), true, "output should mention invalid WebURL") assert.Equal(t, strings.Contains(outputStr, "dnote-server start [flags]"), true, "output should show usage") - assert.Equal(t, strings.Contains(outputStr, "-webUrl"), true, "output should show flags") + assert.Equal(t, strings.Contains(outputStr, "--webUrl"), true, "output should show flags") } func TestServerUnknownCommand(t *testing.T) { @@ -321,3 +321,19 @@ func TestServerUserRemove(t *testing.T) { db.Table("users").Count(&count) assert.Equal(t, count, int64(0), "should have 0 users after removal") } + +func TestServerUserCreateHelp(t *testing.T) { + cmd := exec.Command(testServerBinary, "user", "create", "--help") + output, err := cmd.CombinedOutput() + + if err != nil { + t.Fatalf("help command failed: %v\nOutput: %s", err, output) + } + + outputStr := string(output) + + // Verify help shows double-dash flags for consistency with CLI + assert.Equal(t, strings.Contains(outputStr, "--email"), true, "help should show --email (double dash)") + assert.Equal(t, strings.Contains(outputStr, "--password"), true, "help should show --password (double dash)") + assert.Equal(t, strings.Contains(outputStr, "--dbPath"), true, "help should show --dbPath (double dash)") +} diff --git a/pkg/server/app/books.go b/pkg/server/app/books.go index c3b89ec0..a476a0c4 100644 --- a/pkg/server/app/books.go +++ b/pkg/server/app/books.go @@ -41,12 +41,11 @@ func (a *App) CreateBook(user database.User, name string) (database.Book, error) } book := database.Book{ - UUID: uuid, - UserID: user.ID, - Label: name, - AddedOn: a.Clock.Now().UnixNano(), - USN: nextUSN, - Encrypted: false, + UUID: uuid, + UserID: user.ID, + Label: name, + AddedOn: a.Clock.Now().UnixNano(), + USN: nextUSN, } if err := tx.Create(&book).Error; err != nil { tx.Rollback() @@ -99,8 +98,6 @@ func (a *App) UpdateBook(tx *gorm.DB, user database.User, book database.Book, la book.USN = nextUSN book.EditedOn = a.Clock.Now().UnixNano() book.Deleted = false - // TODO: remove after all users have been migrated - book.Encrypted = false if err := tx.Save(&book).Error; err != nil { return book, errors.Wrap(err, "updating the book") diff --git a/pkg/server/app/notes.go b/pkg/server/app/notes.go index 7773953d..e9f6f60b 100644 --- a/pkg/server/app/notes.go +++ b/pkg/server/app/notes.go @@ -30,7 +30,7 @@ import ( // CreateNote creates a note with the next usn and updates the user's max_usn. // It returns the created note. -func (a *App) CreateNote(user database.User, bookUUID, content string, addedOn *int64, editedOn *int64, public bool, client string) (database.Note, error) { +func (a *App) CreateNote(user database.User, bookUUID, content string, addedOn *int64, editedOn *int64, client string) (database.Note, error) { tx := a.DB.Begin() nextUSN, err := incrementUserUSN(tx, user.ID) @@ -59,16 +59,14 @@ func (a *App) CreateNote(user database.User, bookUUID, content string, addedOn * } note := database.Note{ - UUID: uuid, - BookUUID: bookUUID, - UserID: user.ID, - AddedOn: noteAddedOn, - EditedOn: noteEditedOn, - USN: nextUSN, - Body: content, - Public: public, - Encrypted: false, - Client: client, + UUID: uuid, + BookUUID: bookUUID, + UserID: user.ID, + AddedOn: noteAddedOn, + EditedOn: noteEditedOn, + USN: nextUSN, + Body: content, + Client: client, } if err := tx.Create(¬e).Error; err != nil { tx.Rollback() @@ -84,7 +82,6 @@ func (a *App) CreateNote(user database.User, bookUUID, content string, addedOn * type UpdateNoteParams struct { BookUUID *string Content *string - Public *bool } // GetBookUUID gets the bookUUID from the UpdateNoteParams @@ -105,15 +102,6 @@ func (r UpdateNoteParams) GetContent() string { return *r.Content } -// GetPublic gets the public field from the UpdateNoteParams -func (r UpdateNoteParams) GetPublic() bool { - if r.Public == nil { - return false - } - - return *r.Public -} - // UpdateNote creates a note with the next usn and updates the user's max_usn func (a *App) UpdateNote(tx *gorm.DB, user database.User, note database.Note, p *UpdateNoteParams) (database.Note, error) { nextUSN, err := incrementUserUSN(tx, user.ID) @@ -127,15 +115,10 @@ func (a *App) UpdateNote(tx *gorm.DB, user database.User, note database.Note, p if p.Content != nil { note.Body = p.GetContent() } - if p.Public != nil { - note.Public = p.GetPublic() - } note.USN = nextUSN note.EditedOn = a.Clock.Now().UnixNano() note.Deleted = false - // TODO: remove after all users are migrated - note.Encrypted = false if err := tx.Save(¬e).Error; err != nil { return note, pkgErrors.Wrap(err, "editing note") @@ -180,13 +163,12 @@ func (a *App) GetUserNoteByUUID(userID int, uuid string) (*database.Note, error) // GetNotesParams is params for finding notes type GetNotesParams struct { - Year int - Month int - Page int - Books []string - Search string - Encrypted bool - PerPage int + Year int + Month int + Page int + Books []string + Search string + PerPage int } type ftsParams struct { @@ -215,14 +197,13 @@ notes.added_on, notes.edited_on, notes.usn, notes.deleted, -notes.encrypted, ` + bodyExpr) } func getNotesBaseQuery(db *gorm.DB, userID int, q GetNotesParams) *gorm.DB { conn := db.Where( - "notes.user_id = ? AND notes.deleted = ? AND notes.encrypted = ?", - userID, false, q.Encrypted, + "notes.user_id = ? AND notes.deleted = ?", + userID, false, ) if q.Search != "" { diff --git a/pkg/server/app/notes_test.go b/pkg/server/app/notes_test.go index 7813c54b..42a0bd8a 100644 --- a/pkg/server/app/notes_test.go +++ b/pkg/server/app/notes_test.go @@ -91,7 +91,7 @@ func TestCreateNote(t *testing.T) { a.DB = db a.Clock = mockClock - if _, err := a.CreateNote(user, b1.UUID, "note content", tc.addedOn, tc.editedOn, false, ""); err != nil { + if _, err := a.CreateNote(user, b1.UUID, "note content", tc.addedOn, tc.editedOn, ""); err != nil { t.Fatal(errors.Wrapf(err, "creating note for test case %d", idx)) } @@ -139,7 +139,7 @@ func TestCreateNote_EmptyBody(t *testing.T) { a.Clock = clock.NewMock() // Create note with empty body - note, err := a.CreateNote(user, b1.UUID, "", nil, nil, false, "") + note, err := a.CreateNote(user, b1.UUID, "", nil, nil, "") if err != nil { t.Fatal(errors.Wrap(err, "creating note with empty body")) } @@ -188,7 +188,6 @@ func TestUpdateNote(t *testing.T) { c := clock.NewMock() content := "updated test content" - public := true a := NewTest() a.DB = db @@ -197,7 +196,6 @@ func TestUpdateNote(t *testing.T) { tx := db.Begin() if _, err := a.UpdateNote(tx, user, note, &UpdateNoteParams{ Content: &content, - Public: &public, }); err != nil { tx.Rollback() t.Fatal(errors.Wrap(err, "updating note")) @@ -218,7 +216,6 @@ func TestUpdateNote(t *testing.T) { assert.Equal(t, noteCount, int64(1), "note count mismatch") assert.Equal(t, noteRecord.UserID, user.ID, "note UserID mismatch") assert.Equal(t, noteRecord.Body, content, "note Body mismatch") - assert.Equal(t, noteRecord.Public, public, "note Public mismatch") assert.Equal(t, noteRecord.Deleted, false, "note Deleted mismatch") assert.Equal(t, noteRecord.USN, expectedUSN, "note USN mismatch") assert.Equal(t, userRecord.MaxUSN, expectedUSN, "user MaxUSN mismatch") @@ -374,10 +371,9 @@ func TestGetNotes_FTSSearch(t *testing.T) { // Search "baz" result, err := a.GetNotes(user.ID, GetNotesParams{ - Search: "baz", - Encrypted: false, - Page: 1, - PerPage: 30, + Search: "baz", + Page: 1, + PerPage: 30, }) if err != nil { t.Fatal(errors.Wrap(err, "getting notes with FTS search")) @@ -390,10 +386,9 @@ func TestGetNotes_FTSSearch(t *testing.T) { // Search for "running" - should return 1 note result, err = a.GetNotes(user.ID, GetNotesParams{ - Search: "running", - Encrypted: false, - Page: 1, - PerPage: 30, + Search: "running", + Page: 1, + PerPage: 30, }) if err != nil { t.Fatal(errors.Wrap(err, "getting notes with FTS search for review")) @@ -405,10 +400,9 @@ func TestGetNotes_FTSSearch(t *testing.T) { // Search for non-existent term - should return 0 notes result, err = a.GetNotes(user.ID, GetNotesParams{ - Search: "nonexistent", - Encrypted: false, - Page: 1, - PerPage: 30, + Search: "nonexistent", + Page: 1, + PerPage: 30, }) if err != nil { t.Fatal(errors.Wrap(err, "getting notes with FTS search for nonexistent")) @@ -437,10 +431,9 @@ func TestGetNotes_FTSSearch_Snippet(t *testing.T) { // Search for "keyword" in long note - should return snippet with "..." result, err := a.GetNotes(user.ID, GetNotesParams{ - Search: "keyword", - Encrypted: false, - Page: 1, - PerPage: 30, + Search: "keyword", + Page: 1, + PerPage: 30, }) if err != nil { t.Fatal(errors.Wrap(err, "getting notes with FTS search for keyword")) @@ -472,10 +465,9 @@ func TestGetNotes_FTSSearch_ShortWord(t *testing.T) { a.Clock = clock.NewMock() result, err := a.GetNotes(user.ID, GetNotesParams{ - Search: "a", - Encrypted: false, - Page: 1, - PerPage: 30, + Search: "a", + Page: 1, + PerPage: 30, }) if err != nil { t.Fatal(errors.Wrap(err, "getting notes with FTS search for 'a'")) @@ -504,10 +496,9 @@ func TestGetNotes_All(t *testing.T) { a.Clock = clock.NewMock() result, err := a.GetNotes(user.ID, GetNotesParams{ - Search: "", - Encrypted: false, - Page: 1, - PerPage: 30, + Search: "", + Page: 1, + PerPage: 30, }) if err != nil { t.Fatal(errors.Wrap(err, "getting notes with FTS search for 'a'")) diff --git a/pkg/server/cmd/helpers.go b/pkg/server/cmd/helpers.go index a22c8721..eb58c318 100644 --- a/pkg/server/cmd/helpers.go +++ b/pkg/server/cmd/helpers.go @@ -65,6 +65,29 @@ func initApp(cfg config.Config) app.App { } } +// printFlags prints flags with -- prefix for consistency with CLI +func printFlags(fs *flag.FlagSet) { + fs.VisitAll(func(f *flag.Flag) { + fmt.Printf(" --%s", f.Name) + + // Print type hint for non-boolean flags + name, usage := flag.UnquoteUsage(f) + if name != "" { + fmt.Printf(" %s", name) + } + fmt.Println() + + // Print usage description with indentation + if usage != "" { + fmt.Printf(" \t%s", usage) + if f.DefValue != "" && f.DefValue != "false" { + fmt.Printf(" (default: %s)", f.DefValue) + } + fmt.Println() + } + }) +} + // setupFlagSet creates a FlagSet with standard usage format func setupFlagSet(name, usageCmd string) *flag.FlagSet { fs := flag.NewFlagSet(name, flag.ExitOnError) @@ -74,7 +97,7 @@ func setupFlagSet(name, usageCmd string) *flag.FlagSet { Flags: `, usageCmd) - fs.PrintDefaults() + printFlags(fs) } return fs } diff --git a/pkg/server/controllers/books.go b/pkg/server/controllers/books.go index e2aa6de0..1b4f3810 100644 --- a/pkg/server/controllers/books.go +++ b/pkg/server/controllers/books.go @@ -56,22 +56,11 @@ func (b *Books) getBooks(r *http.Request) ([]database.Book, error) { query := r.URL.Query() name := query.Get("name") - encryptedStr := query.Get("encrypted") if name != "" { part := fmt.Sprintf("%%%s%%", name) conn = conn.Where("LOWER(label) LIKE ?", part) } - if encryptedStr != "" { - var encrypted bool - if encryptedStr == "true" { - encrypted = true - } else { - encrypted = false - } - - conn = conn.Where("encrypted = ?", encrypted) - } var books []database.Book if err := conn.Find(&books).Error; err != nil { diff --git a/pkg/server/controllers/notes.go b/pkg/server/controllers/notes.go index a7434366..dd34a78d 100644 --- a/pkg/server/controllers/notes.go +++ b/pkg/server/controllers/notes.go @@ -73,7 +73,6 @@ func parseGetNotesQuery(q url.Values) (app.GetNotesParams, error) { yearStr := q.Get("year") monthStr := q.Get("month") books := q["book"] - encryptedStr := q.Get("encrypted") pageStr := q.Get("page") page, err := parsePageQuery(q) @@ -107,21 +106,13 @@ func parseGetNotesQuery(q url.Values) (app.GetNotesParams, error) { month = m } - var encrypted bool - if strings.ToLower(encryptedStr) == "true" { - encrypted = true - } else { - encrypted = false - } - ret := app.GetNotesParams{ - Year: year, - Month: month, - Page: page, - Search: parseSearchQuery(q), - Books: books, - Encrypted: encrypted, - PerPage: notesPerPage, + Year: year, + Month: month, + Page: page, + Search: parseSearchQuery(q), + Books: books, + PerPage: notesPerPage, } return ret, nil @@ -231,7 +222,7 @@ func (n *Notes) create(r *http.Request) (database.Note, error) { } client := getClientType(r) - note, err := n.app.CreateNote(*user, params.BookUUID, params.Content, params.AddedOn, params.EditedOn, false, client) + note, err := n.app.CreateNote(*user, params.BookUUID, params.Content, params.AddedOn, params.EditedOn, client) if err != nil { return database.Note{}, errors.Wrap(err, "creating note") } @@ -310,11 +301,10 @@ func (n *Notes) V3Delete(w http.ResponseWriter, r *http.Request) { type updateNotePayload struct { BookUUID *string `schema:"book_uuid" json:"book_uuid"` Content *string `schema:"content" json:"content"` - Public *bool `schema:"public" json:"public"` } func validateUpdateNotePayload(p updateNotePayload) error { - if p.BookUUID == nil && p.Content == nil && p.Public == nil { + if p.BookUUID == nil && p.Content == nil { return app.ErrEmptyUpdate } @@ -350,7 +340,6 @@ func (n *Notes) update(r *http.Request) (database.Note, error) { note, err = n.app.UpdateNote(tx, *user, note, &app.UpdateNoteParams{ BookUUID: params.BookUUID, Content: params.Content, - Public: params.Public, }) if err != nil { tx.Rollback() diff --git a/pkg/server/controllers/notes_test.go b/pkg/server/controllers/notes_test.go index 6bf3c06b..ce3f20c7 100644 --- a/pkg/server/controllers/notes_test.go +++ b/pkg/server/controllers/notes_test.go @@ -42,7 +42,6 @@ func getExpectedNotePayload(n database.Note, b database.Book, u database.User) p UpdatedAt: truncateMicro(n.UpdatedAt), Body: n.Body, AddedOn: n.AddedOn, - Public: n.Public, USN: n.USN, Book: presenters.NoteBook{ UUID: b.UUID, @@ -189,7 +188,9 @@ func TestGetNote(t *testing.T) { defer server.Close() user := testutils.SetupUserData(db) + testutils.SetupAccountData(db, user, "user@test.com", "pass1234") anotherUser := testutils.SetupUserData(db) + testutils.SetupAccountData(db, anotherUser, "another@test.com", "pass1234") b1 := database.Book{ UUID: testutils.MustUUID(t), @@ -198,22 +199,13 @@ func TestGetNote(t *testing.T) { } testutils.MustExec(t, db.Save(&b1), "preparing b1") - privateNote := database.Note{ + note := database.Note{ UUID: testutils.MustUUID(t), UserID: user.ID, BookUUID: b1.UUID, - Body: "privateNote content", - Public: false, + Body: "note content", } - testutils.MustExec(t, db.Save(&privateNote), "preparing privateNote") - publicNote := database.Note{ - UUID: testutils.MustUUID(t), - UserID: user.ID, - BookUUID: b1.UUID, - Body: "publicNote content", - Public: true, - } - testutils.MustExec(t, db.Save(&publicNote), "preparing publicNote") + testutils.MustExec(t, db.Save(¬e), "preparing note") deletedNote := database.Note{ UUID: testutils.MustUUID(t), UserID: user.ID, @@ -226,9 +218,9 @@ func TestGetNote(t *testing.T) { return fmt.Sprintf("/api/v3/notes/%s", noteUUID) } - t.Run("owner accessing private note", func(t *testing.T) { + t.Run("owner accessing note", func(t *testing.T) { // Execute - url := getURL(publicNote.UUID) + url := getURL(note.UUID) req := testutils.MakeReq(server.URL, "GET", url, "") res := testutils.HTTPAuthDo(t, db, req, user) @@ -240,58 +232,16 @@ func TestGetNote(t *testing.T) { t.Fatal(errors.Wrap(err, "decoding payload")) } - var n2Record database.Note - testutils.MustExec(t, db.Where("uuid = ?", publicNote.UUID).First(&n2Record), "finding n2Record") + var noteRecord database.Note + testutils.MustExec(t, db.Where("uuid = ?", note.UUID).First(¬eRecord), "finding noteRecord") - expected := getExpectedNotePayload(n2Record, b1, user) + expected := getExpectedNotePayload(noteRecord, b1, user) assert.DeepEqual(t, payload, expected, "payload mismatch") }) - t.Run("owner accessing public note", func(t *testing.T) { + t.Run("non-owner accessing note", func(t *testing.T) { // Execute - url := getURL(publicNote.UUID) - req := testutils.MakeReq(server.URL, "GET", url, "") - res := testutils.HTTPAuthDo(t, db, req, user) - - // Test - assert.StatusCodeEquals(t, res, http.StatusOK, "") - - var payload presenters.Note - if err := json.NewDecoder(res.Body).Decode(&payload); err != nil { - t.Fatal(errors.Wrap(err, "decoding payload")) - } - - var n2Record database.Note - testutils.MustExec(t, db.Where("uuid = ?", publicNote.UUID).First(&n2Record), "finding n2Record") - - expected := getExpectedNotePayload(n2Record, b1, user) - assert.DeepEqual(t, payload, expected, "payload mismatch") - }) - - t.Run("non-owner accessing public note", func(t *testing.T) { - // Execute - url := getURL(publicNote.UUID) - req := testutils.MakeReq(server.URL, "GET", url, "") - res := testutils.HTTPAuthDo(t, db, req, anotherUser) - - // Test - assert.StatusCodeEquals(t, res, http.StatusOK, "") - - var payload presenters.Note - if err := json.NewDecoder(res.Body).Decode(&payload); err != nil { - t.Fatal(errors.Wrap(err, "decoding payload")) - } - - var n2Record database.Note - testutils.MustExec(t, db.Where("uuid = ?", publicNote.UUID).First(&n2Record), "finding n2Record") - - expected := getExpectedNotePayload(n2Record, b1, user) - assert.DeepEqual(t, payload, expected, "payload mismatch") - }) - - t.Run("non-owner accessing private note", func(t *testing.T) { - // Execute - url := getURL(privateNote.UUID) + url := getURL(note.UUID) req := testutils.MakeReq(server.URL, "GET", url, "") res := testutils.HTTPAuthDo(t, db, req, anotherUser) @@ -306,42 +256,21 @@ func TestGetNote(t *testing.T) { assert.DeepEqual(t, string(body), "not found\n", "payload mismatch") }) - t.Run("guest accessing public note", func(t *testing.T) { + t.Run("guest accessing note", func(t *testing.T) { // Execute - url := getURL(publicNote.UUID) + url := getURL(note.UUID) req := testutils.MakeReq(server.URL, "GET", url, "") res := testutils.HTTPDo(t, req) // Test - assert.StatusCodeEquals(t, res, http.StatusOK, "") - - var payload presenters.Note - if err := json.NewDecoder(res.Body).Decode(&payload); err != nil { - t.Fatal(errors.Wrap(err, "decoding payload")) - } - - var n2Record database.Note - testutils.MustExec(t, db.Where("uuid = ?", publicNote.UUID).First(&n2Record), "finding n2Record") - - expected := getExpectedNotePayload(n2Record, b1, user) - assert.DeepEqual(t, payload, expected, "payload mismatch") - }) - - t.Run("guest accessing private note", func(t *testing.T) { - // Execute - url := getURL(privateNote.UUID) - req := testutils.MakeReq(server.URL, "GET", url, "") - res := testutils.HTTPDo(t, req) - - // Test - assert.StatusCodeEquals(t, res, http.StatusNotFound, "") + assert.StatusCodeEquals(t, res, http.StatusUnauthorized, "") body, err := io.ReadAll(res.Body) if err != nil { t.Fatal(errors.Wrap(err, "reading body")) } - assert.DeepEqual(t, string(body), "not found\n", "payload mismatch") + assert.DeepEqual(t, string(body), "unauthorized\n", "payload mismatch") }) t.Run("nonexistent", func(t *testing.T) { @@ -533,7 +462,6 @@ func TestUpdateNote(t *testing.T) { type payloadData struct { Content *string `schema:"content" json:"content,omitempty"` BookUUID *string `schema:"book_uuid" json:"book_uuid,omitempty"` - Public *bool `schema:"public" json:"public,omitempty"` } testCases := []struct { @@ -541,12 +469,10 @@ func TestUpdateNote(t *testing.T) { noteUUID string noteBookUUID string noteBody string - notePublic bool noteDeleted bool expectedNoteBody string expectedNoteBookName string expectedNoteBookUUID string - expectedNotePublic bool }{ { payload: testutils.PayloadWrapper{ @@ -556,13 +482,11 @@ func TestUpdateNote(t *testing.T) { }, noteUUID: "ab50aa32-b232-40d8-b10f-10a7f9134053", noteBookUUID: b1UUID, - notePublic: false, noteBody: "original content", noteDeleted: false, expectedNoteBookUUID: b1UUID, expectedNoteBody: "some updated content", expectedNoteBookName: "css", - expectedNotePublic: false, }, { payload: testutils.PayloadWrapper{ @@ -572,13 +496,11 @@ func TestUpdateNote(t *testing.T) { }, noteUUID: "ab50aa32-b232-40d8-b10f-10a7f9134053", noteBookUUID: b1UUID, - notePublic: false, noteBody: "original content", noteDeleted: false, expectedNoteBookUUID: b1UUID, expectedNoteBody: "original content", expectedNoteBookName: "css", - expectedNotePublic: false, }, { payload: testutils.PayloadWrapper{ @@ -588,13 +510,11 @@ func TestUpdateNote(t *testing.T) { }, noteUUID: "ab50aa32-b232-40d8-b10f-10a7f9134053", noteBookUUID: b1UUID, - notePublic: false, noteBody: "original content", noteDeleted: false, expectedNoteBookUUID: b2UUID, expectedNoteBody: "original content", expectedNoteBookName: "js", - expectedNotePublic: false, }, { payload: testutils.PayloadWrapper{ @@ -605,13 +525,11 @@ func TestUpdateNote(t *testing.T) { }, noteUUID: "ab50aa32-b232-40d8-b10f-10a7f9134053", noteBookUUID: b1UUID, - notePublic: false, noteBody: "original content", noteDeleted: false, expectedNoteBookUUID: b2UUID, expectedNoteBody: "some updated content", expectedNoteBookName: "js", - expectedNotePublic: false, }, { payload: testutils.PayloadWrapper{ @@ -622,80 +540,11 @@ func TestUpdateNote(t *testing.T) { }, noteUUID: "ab50aa32-b232-40d8-b10f-10a7f9134053", noteBookUUID: b1UUID, - notePublic: false, noteBody: "", noteDeleted: true, expectedNoteBookUUID: b1UUID, expectedNoteBody: updatedBody, expectedNoteBookName: "js", - expectedNotePublic: false, - }, - { - payload: testutils.PayloadWrapper{ - Data: payloadData{ - Public: &testutils.TrueVal, - }, - }, - noteUUID: "ab50aa32-b232-40d8-b10f-10a7f9134053", - noteBookUUID: b1UUID, - notePublic: false, - noteBody: "original content", - noteDeleted: false, - expectedNoteBookUUID: b1UUID, - expectedNoteBody: "original content", - expectedNoteBookName: "css", - expectedNotePublic: true, - }, - { - payload: testutils.PayloadWrapper{ - Data: payloadData{ - Public: &testutils.FalseVal, - }, - }, - noteUUID: "ab50aa32-b232-40d8-b10f-10a7f9134053", - noteBookUUID: b1UUID, - notePublic: true, - noteBody: "original content", - noteDeleted: false, - expectedNoteBookUUID: b1UUID, - expectedNoteBody: "original content", - expectedNoteBookName: "css", - expectedNotePublic: false, - }, - { - payload: testutils.PayloadWrapper{ - Data: payloadData{ - Content: &updatedBody, - Public: &testutils.FalseVal, - }, - }, - noteUUID: "ab50aa32-b232-40d8-b10f-10a7f9134053", - noteBookUUID: b1UUID, - notePublic: true, - noteBody: "original content", - noteDeleted: false, - expectedNoteBookUUID: b1UUID, - expectedNoteBody: updatedBody, - expectedNoteBookName: "css", - expectedNotePublic: false, - }, - { - payload: testutils.PayloadWrapper{ - Data: payloadData{ - BookUUID: &b2UUID, - Content: &updatedBody, - Public: &testutils.TrueVal, - }, - }, - noteUUID: "ab50aa32-b232-40d8-b10f-10a7f9134053", - noteBookUUID: b1UUID, - notePublic: false, - noteBody: "original content", - noteDeleted: false, - expectedNoteBookUUID: b2UUID, - expectedNoteBody: updatedBody, - expectedNoteBookName: "js", - expectedNotePublic: true, }, } @@ -734,7 +583,6 @@ func TestUpdateNote(t *testing.T) { BookUUID: tc.noteBookUUID, Body: tc.noteBody, Deleted: tc.noteDeleted, - Public: tc.notePublic, } testutils.MustExec(t, db.Save(¬e), "preparing note") @@ -765,7 +613,6 @@ func TestUpdateNote(t *testing.T) { assert.Equal(t, noteRecord.UUID, tc.noteUUID, "note uuid mismatch for test case") assert.Equal(t, noteRecord.Body, tc.expectedNoteBody, "note content mismatch for test case") assert.Equal(t, noteRecord.BookUUID, tc.expectedNoteBookUUID, "note book_uuid mismatch for test case") - assert.Equal(t, noteRecord.Public, tc.expectedNotePublic, "note public mismatch for test case") assert.Equal(t, noteRecord.USN, 102, "note usn mismatch for test case") assert.Equal(t, userRecord.MaxUSN, 102, "user max_usn mismatch for test case") diff --git a/pkg/server/controllers/routes.go b/pkg/server/controllers/routes.go index db8b706d..ff7be403 100644 --- a/pkg/server/controllers/routes.go +++ b/pkg/server/controllers/routes.go @@ -82,7 +82,7 @@ func NewAPIRoutes(a *app.App, c *Controllers) []Route { {"POST", "/v3/signout", c.Users.V3Logout, true}, {"OPTIONS", "/v3/signout", c.Users.logoutOptions, true}, {"GET", "/v3/notes", mw.Auth(a.DB, c.Notes.V3Index, nil), true}, - {"GET", "/v3/notes/{noteUUID}", c.Notes.V3Show, true}, + {"GET", "/v3/notes/{noteUUID}", mw.Auth(a.DB, c.Notes.V3Show, nil), true}, {"POST", "/v3/notes", mw.Auth(a.DB, c.Notes.V3Create, nil), true}, {"DELETE", "/v3/notes/{noteUUID}", mw.Auth(a.DB, c.Notes.V3Delete, nil), true}, {"PATCH", "/v3/notes/{noteUUID}", mw.Auth(a.DB, c.Notes.V3Update, nil), true}, diff --git a/pkg/server/controllers/sync.go b/pkg/server/controllers/sync.go index 2ce8d02c..e93be7cd 100644 --- a/pkg/server/controllers/sync.go +++ b/pkg/server/controllers/sync.go @@ -75,7 +75,6 @@ type SyncFragNote struct { AddedOn int64 `json:"added_on"` EditedOn int64 `json:"edited_on"` Body string `json:"content"` - Public bool `json:"public"` Deleted bool `json:"deleted"` } @@ -89,7 +88,6 @@ func NewFragNote(note database.Note) SyncFragNote { AddedOn: note.AddedOn, EditedOn: note.EditedOn, Body: note.Body, - Public: note.Public, Deleted: note.Deleted, BookUUID: note.BookUUID, } diff --git a/pkg/server/database/models.go b/pkg/server/database/models.go index 98571e10..99e41c96 100644 --- a/pkg/server/database/models.go +++ b/pkg/server/database/models.go @@ -40,7 +40,6 @@ type Book struct { EditedOn int64 `json:"edited_on"` USN int `json:"-" gorm:"index"` Deleted bool `json:"-" gorm:"default:false"` - Encrypted bool `json:"-" gorm:"default:false"` } // Note is a model for a note @@ -54,10 +53,8 @@ type Note struct { Body string `json:"content"` AddedOn int64 `json:"added_on"` EditedOn int64 `json:"edited_on"` - Public bool `json:"public" gorm:"default:false"` USN int `json:"-" gorm:"index"` Deleted bool `json:"-" gorm:"default:false"` - Encrypted bool `json:"-" gorm:"default:false"` Client string `gorm:"index"` } diff --git a/pkg/server/middleware/auth.go b/pkg/server/middleware/auth.go index 984079e4..f74d1efa 100644 --- a/pkg/server/middleware/auth.go +++ b/pkg/server/middleware/auth.go @@ -101,7 +101,11 @@ func WithAccount(db *gorm.DB, next http.HandlerFunc) http.HandlerFunc { user := context.User(r.Context()) var account database.Account - if err := db.Where("user_id = ?", user.ID).First(&account).Error; err != nil { + err := db.Where("user_id = ?", user.ID).First(&account).Error + if errors.Is(err, gorm.ErrRecordNotFound) { + DoError(w, "account not found", err, http.StatusForbidden) + return + } else if err != nil { DoError(w, "finding account", err, http.StatusInternalServerError) return } diff --git a/pkg/server/middleware/auth_test.go b/pkg/server/middleware/auth_test.go index 1485befa..c0d94096 100644 --- a/pkg/server/middleware/auth_test.go +++ b/pkg/server/middleware/auth_test.go @@ -233,3 +233,37 @@ func TestTokenAuth(t *testing.T) { assert.Equal(t, res.StatusCode, http.StatusUnauthorized, "status code mismatch") }) } + +func TestWithAccount(t *testing.T) { + db := testutils.InitMemoryDB(t) + + handler := func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + } + + t.Run("user with account", func(t *testing.T) { + user := testutils.SetupUserData(db) + testutils.SetupAccountData(db, user, "alice@test.com", "pass1234") + + server := httptest.NewServer(Auth(db, handler, nil)) + defer server.Close() + + req := testutils.MakeReq(server.URL, "GET", "/", "") + res := testutils.HTTPAuthDo(t, db, req, user) + + assert.Equal(t, res.StatusCode, http.StatusOK, "status code mismatch") + }) + + t.Run("user without account", func(t *testing.T) { + user := testutils.SetupUserData(db) + // Note: not creating account for this user + + server := httptest.NewServer(Auth(db, handler, nil)) + defer server.Close() + + req := testutils.MakeReq(server.URL, "GET", "/", "") + res := testutils.HTTPAuthDo(t, db, req, user) + + assert.Equal(t, res.StatusCode, http.StatusForbidden, "status code mismatch") + }) +} diff --git a/pkg/server/operations/notes_test.go b/pkg/server/operations/notes_test.go index 6124b7e0..f003f7cb 100644 --- a/pkg/server/operations/notes_test.go +++ b/pkg/server/operations/notes_test.go @@ -40,29 +40,17 @@ func TestGetNote(t *testing.T) { } testutils.MustExec(t, db.Save(&b1), "preparing b1") - privateNote := database.Note{ + note := database.Note{ UUID: testutils.MustUUID(t), UserID: user.ID, BookUUID: b1.UUID, - Body: "privateNote content", + Body: "note content", Deleted: false, - Public: false, } - testutils.MustExec(t, db.Save(&privateNote), "preparing privateNote") + testutils.MustExec(t, db.Save(¬e), "preparing note") - publicNote := database.Note{ - UUID: testutils.MustUUID(t), - UserID: user.ID, - BookUUID: b1.UUID, - Body: "privateNote content", - Deleted: false, - Public: true, - } - testutils.MustExec(t, db.Save(&publicNote), "preparing privateNote") - - var privateNoteRecord, publicNoteRecord database.Note - testutils.MustExec(t, db.Where("uuid = ?", privateNote.UUID).Preload("Book").Preload("User").First(&privateNoteRecord), "finding privateNote") - testutils.MustExec(t, db.Where("uuid = ?", publicNote.UUID).Preload("Book").Preload("User").First(&publicNoteRecord), "finding publicNote") + var noteRecord database.Note + testutils.MustExec(t, db.Where("uuid = ?", note.UUID).Preload("Book").Preload("User").First(¬eRecord), "finding note") testCases := []struct { name string @@ -72,40 +60,26 @@ func TestGetNote(t *testing.T) { expectedNote database.Note }{ { - name: "owner accessing private note", + name: "owner accessing note", user: user, - note: privateNote, + note: note, expectedOK: true, - expectedNote: privateNoteRecord, + expectedNote: noteRecord, }, { - name: "non-owner accessing private note", + name: "non-owner accessing note", user: anotherUser, - note: privateNote, + note: note, expectedOK: false, expectedNote: database.Note{}, }, { - name: "non-owner accessing public note", - user: anotherUser, - note: publicNote, - expectedOK: true, - expectedNote: publicNoteRecord, - }, - { - name: "guest accessing private note", + name: "guest accessing note", user: database.User{}, - note: privateNote, + note: note, expectedOK: false, expectedNote: database.Note{}, }, - { - name: "guest accessing public note", - user: database.User{}, - note: publicNote, - expectedOK: true, - expectedNote: publicNoteRecord, - }, } for _, tc := range testCases { @@ -139,7 +113,6 @@ func TestGetNote_nonexistent(t *testing.T) { BookUUID: b1.UUID, Body: "n1 content", Deleted: false, - Public: false, } testutils.MustExec(t, db.Save(&n1), "preparing n1") diff --git a/pkg/server/permissions/permissions.go b/pkg/server/permissions/permissions.go index e3e10e63..d9d017d9 100644 --- a/pkg/server/permissions/permissions.go +++ b/pkg/server/permissions/permissions.go @@ -24,9 +24,6 @@ import ( // ViewNote checks if the given user can view the given note func ViewNote(user *database.User, note database.Note) bool { - if note.Public { - return true - } if user == nil { return false } diff --git a/pkg/server/permissions/permissions_test.go b/pkg/server/permissions/permissions_test.go index 4054b66f..ed439d28 100644 --- a/pkg/server/permissions/permissions_test.go +++ b/pkg/server/permissions/permissions_test.go @@ -39,53 +39,27 @@ func TestViewNote(t *testing.T) { } testutils.MustExec(t, db.Save(&b1), "preparing b1") - privateNote := database.Note{ + note := database.Note{ UUID: testutils.MustUUID(t), UserID: user.ID, BookUUID: b1.UUID, - Body: "privateNote content", + Body: "note content", Deleted: false, - Public: false, } - testutils.MustExec(t, db.Save(&privateNote), "preparing privateNote") + testutils.MustExec(t, db.Save(¬e), "preparing note") - publicNote := database.Note{ - UUID: testutils.MustUUID(t), - UserID: user.ID, - BookUUID: b1.UUID, - Body: "privateNote content", - Deleted: false, - Public: true, - } - testutils.MustExec(t, db.Save(&publicNote), "preparing privateNote") - - t.Run("owner accessing private note", func(t *testing.T) { - result := ViewNote(&user, privateNote) + t.Run("owner accessing note", func(t *testing.T) { + result := ViewNote(&user, note) assert.Equal(t, result, true, "result mismatch") }) - t.Run("owner accessing public note", func(t *testing.T) { - result := ViewNote(&user, publicNote) - assert.Equal(t, result, true, "result mismatch") - }) - - t.Run("non-owner accessing private note", func(t *testing.T) { - result := ViewNote(&anotherUser, privateNote) + t.Run("non-owner accessing note", func(t *testing.T) { + result := ViewNote(&anotherUser, note) assert.Equal(t, result, false, "result mismatch") }) - t.Run("non-owner accessing public note", func(t *testing.T) { - result := ViewNote(&anotherUser, publicNote) - assert.Equal(t, result, true, "result mismatch") - }) - - t.Run("guest accessing private note", func(t *testing.T) { - result := ViewNote(nil, privateNote) + t.Run("guest accessing note", func(t *testing.T) { + result := ViewNote(nil, note) assert.Equal(t, result, false, "result mismatch") }) - - t.Run("guest accessing public note", func(t *testing.T) { - result := ViewNote(nil, publicNote) - assert.Equal(t, result, true, "result mismatch") - }) } diff --git a/pkg/server/presenters/note.go b/pkg/server/presenters/note.go index 4119dd28..a20bb879 100644 --- a/pkg/server/presenters/note.go +++ b/pkg/server/presenters/note.go @@ -31,7 +31,6 @@ type Note struct { UpdatedAt time.Time `json:"updated_at"` Body string `json:"content"` AddedOn int64 `json:"added_on"` - Public bool `json:"public"` USN int `json:"usn"` Book NoteBook `json:"book"` User NoteUser `json:"user"` @@ -57,7 +56,6 @@ func PresentNote(note database.Note) Note { UpdatedAt: FormatTS(note.UpdatedAt), Body: note.Body, AddedOn: note.AddedOn, - Public: note.Public, USN: note.USN, Book: NoteBook{ UUID: note.Book.UUID, diff --git a/pkg/server/presenters/note_test.go b/pkg/server/presenters/note_test.go index 822c5cea..878acf67 100644 --- a/pkg/server/presenters/note_test.go +++ b/pkg/server/presenters/note_test.go @@ -41,7 +41,6 @@ func TestPresentNote(t *testing.T) { BookUUID: "f1e2d3c4-b5a6-4987-b654-321fedcba098", Body: "Test note content", AddedOn: 1234567890, - Public: true, USN: 100, Book: database.Book{ UUID: "f1e2d3c4-b5a6-4987-b654-321fedcba098", @@ -57,7 +56,6 @@ func TestPresentNote(t *testing.T) { assert.Equal(t, got.UUID, "a1b2c3d4-e5f6-4789-a012-3456789abcde", "UUID mismatch") assert.Equal(t, got.Body, "Test note content", "Body mismatch") assert.Equal(t, got.AddedOn, int64(1234567890), "AddedOn mismatch") - assert.Equal(t, got.Public, true, "Public mismatch") assert.Equal(t, got.USN, 100, "USN mismatch") assert.Equal(t, got.CreatedAt, FormatTS(createdAt), "CreatedAt mismatch") assert.Equal(t, got.UpdatedAt, FormatTS(updatedAt), "UpdatedAt mismatch") @@ -84,7 +82,6 @@ func TestPresentNotes(t *testing.T) { BookUUID: "f1e2d3c4-b5a6-4987-b654-321fedcba098", Body: "First note", AddedOn: 1000000000, - Public: false, USN: 10, Book: database.Book{ UUID: "f1e2d3c4-b5a6-4987-b654-321fedcba098", @@ -105,7 +102,6 @@ func TestPresentNotes(t *testing.T) { BookUUID: "abcdef01-2345-4678-9abc-def012345678", Body: "Second note", AddedOn: 2000000000, - Public: true, USN: 20, Book: database.Book{ UUID: "abcdef01-2345-4678-9abc-def012345678", diff --git a/pkg/server/tmpl/app_test.go b/pkg/server/tmpl/app_test.go index fba9bed4..8772bf92 100644 --- a/pkg/server/tmpl/app_test.go +++ b/pkg/server/tmpl/app_test.go @@ -19,12 +19,10 @@ package tmpl import ( - "fmt" "net/http" "testing" "github.com/dnote/dnote/pkg/assert" - "github.com/dnote/dnote/pkg/server/database" "github.com/dnote/dnote/pkg/server/testutils" "github.com/pkg/errors" ) @@ -50,42 +48,4 @@ func TestAppShellExecute(t *testing.T) { assert.Equal(t, string(b), "Dnote", "result mismatch") }) - - t.Run("note", func(t *testing.T) { - db := testutils.InitMemoryDB(t) - - user := testutils.SetupUserData(db) - b1 := database.Book{ - UUID: testutils.MustUUID(t), - UserID: user.ID, - Label: "js", - } - testutils.MustExec(t, db.Save(&b1), "preparing b1") - n1 := database.Note{ - UUID: testutils.MustUUID(t), - UserID: user.ID, - BookUUID: b1.UUID, - Public: true, - Body: "n1 content", - } - testutils.MustExec(t, db.Save(&n1), "preparing note") - - a, err := NewAppShell(db, []byte("{{ .MetaTags }}")) - if err != nil { - t.Fatal(errors.Wrap(err, "preparing app shell")) - } - - endpoint := fmt.Sprintf("http://mock.url/notes/%s", n1.UUID) - r, err := http.NewRequest("GET", endpoint, nil) - if err != nil { - t.Fatal(errors.Wrap(err, "preparing request")) - } - - b, err := a.Execute(r) - if err != nil { - t.Fatal(errors.Wrap(err, "executing")) - } - - assert.NotEqual(t, string(b), "", "result should not be empty") - }) }