Browse Source

feat(storage): make removed entries' status immutable

This is a first step towards "keeping only metadata for removed entries" #3524.
jvoisin 7 months ago
parent
commit
eb6f7f30bb
2 changed files with 71 additions and 2 deletions
  1. 58 0
      internal/api/api_integration_test.go
  2. 13 2
      internal/storage/entry.go

+ 58 - 0
internal/api/api_integration_test.go

@@ -2589,6 +2589,64 @@ func TestUpdateEntryStatusEndpoint(t *testing.T) {
 	}
 }
 
+func TestUpdateEntryRemovedStatusEndpoint(t *testing.T) {
+	testConfig := newIntegrationTestConfig()
+	if !testConfig.isConfigured() {
+		t.Skip(skipIntegrationTestsMessage)
+	}
+
+	adminClient := miniflux.NewClient(testConfig.testBaseURL, testConfig.testAdminUsername, testConfig.testAdminPassword)
+
+	regularTestUser, err := adminClient.CreateUser(testConfig.genRandomUsername(), testConfig.testRegularPassword, false)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer adminClient.DeleteUser(regularTestUser.ID)
+
+	regularUserClient := miniflux.NewClient(testConfig.testBaseURL, regularTestUser.Username, testConfig.testRegularPassword)
+
+	feedID, err := regularUserClient.CreateFeed(&miniflux.FeedCreationRequest{
+		FeedURL: testConfig.testFeedURL,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	result, err := regularUserClient.FeedEntries(feedID, nil)
+	if err != nil {
+		t.Fatalf(`Failed to get entries: %v`, err)
+	}
+
+	// First we set the entry as "removed"
+	if err := regularUserClient.UpdateEntries([]int64{result.Entries[0].ID}, miniflux.EntryStatusRemoved); err != nil {
+		t.Fatal(err)
+	}
+
+	entry, err := regularUserClient.Entry(result.Entries[0].ID)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if entry.Status != miniflux.EntryStatusRemoved {
+		t.Fatalf(`Invalid status, got %q instead of %q`, entry.Status, miniflux.EntryStatusRemoved)
+	}
+
+	// Then we try to set it to "unread"
+	if err := regularUserClient.UpdateEntries([]int64{result.Entries[0].ID}, miniflux.EntryStatusUnread); err != nil {
+		t.Fatal(err)
+	}
+
+	entry, err = regularUserClient.Entry(result.Entries[0].ID)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// It should stay set to "removed"
+	if entry.Status != miniflux.EntryStatusRemoved {
+		t.Fatalf(`Modified immutable status: got %q instead of %q`, entry.Status, miniflux.EntryStatusRemoved)
+	}
+}
+
 func TestUpdateEntryEndpoint(t *testing.T) {
 	testConfig := newIntegrationTestConfig()
 	if !testConfig.isConfigured() {

+ 13 - 2
internal/storage/entry.go

@@ -378,8 +378,19 @@ func (s *Storage) ArchiveEntries(status string, days, limit int) (int64, error)
 
 // SetEntriesStatus update the status of the given list of entries.
 func (s *Storage) SetEntriesStatus(userID int64, entryIDs []int64, status string) error {
-	query := `UPDATE entries SET status=$1, changed_at=now() WHERE user_id=$2 AND id=ANY($3)`
-	if _, err := s.db.Exec(query, status, userID, pq.Array(entryIDs)); err != nil {
+	// Entries that have the model.EntryStatusRemoved status are immutable.
+	query := `
+		UPDATE
+			entries
+		SET
+			status=$1,
+			changed_at=now()
+		WHERE
+			user_id=$2 AND
+			id=ANY($3) AND
+			status!=$4
+		`
+	if _, err := s.db.Exec(query, status, userID, pq.Array(entryIDs), model.EntryStatusRemoved); err != nil {
 		return fmt.Errorf(`store: unable to update entries statuses %v: %v`, entryIDs, err)
 	}