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")
- })
}