mirror of
https://github.com/miniflux/v2.git
synced 2025-06-27 16:36:00 +00:00
fix(googlereader): /items/contents
should accept short form item IDs
This commit is contained in:
parent
50395f13ca
commit
6cc8d8abf1
3 changed files with 177 additions and 27 deletions
|
@ -60,8 +60,6 @@ const (
|
|||
BroadcastFriends = "broadcast-friends"
|
||||
// Like is the suffix for like stream
|
||||
Like = "like"
|
||||
// EntryIDLong is the long entry id representation
|
||||
EntryIDLong = "tag:google.com,2005:reader/item/%016x"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -370,28 +368,6 @@ func checkAndSimplifyTags(addTags []Stream, removeTags []Stream) (map[StreamType
|
|||
return tags, nil
|
||||
}
|
||||
|
||||
func getItemIDs(r *http.Request) ([]int64, error) {
|
||||
items := r.Form[ParamItemIDs]
|
||||
if len(items) == 0 {
|
||||
return nil, fmt.Errorf("googlereader: no items requested")
|
||||
}
|
||||
|
||||
itemIDs := make([]int64, len(items))
|
||||
|
||||
for i, item := range items {
|
||||
var itemID int64
|
||||
_, err := fmt.Sscanf(item, EntryIDLong, &itemID)
|
||||
if err != nil {
|
||||
itemID, err = strconv.ParseInt(item, 16, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("googlereader: could not parse item: %v", item)
|
||||
}
|
||||
}
|
||||
itemIDs[i] = itemID
|
||||
}
|
||||
return itemIDs, nil
|
||||
}
|
||||
|
||||
func checkOutputFormat(r *http.Request) error {
|
||||
var output string
|
||||
if r.Method == http.MethodPost {
|
||||
|
@ -568,7 +544,7 @@ func (h *handler) editTagHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
itemIDs, err := getItemIDs(r)
|
||||
itemIDs, err := parseItemIDsFromRequest(r)
|
||||
if err != nil {
|
||||
json.ServerError(w, r, err)
|
||||
return
|
||||
|
@ -985,7 +961,7 @@ func (h *handler) streamItemContentsHandler(w http.ResponseWriter, r *http.Reque
|
|||
userRead := fmt.Sprintf(UserStreamPrefix, userID) + Read
|
||||
userStarred := fmt.Sprintf(UserStreamPrefix, userID) + Starred
|
||||
|
||||
itemIDs, err := getItemIDs(r)
|
||||
itemIDs, err := parseItemIDsFromRequest(r)
|
||||
if err != nil {
|
||||
json.ServerError(w, r, err)
|
||||
return
|
||||
|
@ -1058,7 +1034,7 @@ func (h *handler) streamItemContentsHandler(w http.ResponseWriter, r *http.Reque
|
|||
entry.Enclosures.ProxifyEnclosureURL(h.router)
|
||||
|
||||
contentItems[i] = contentItem{
|
||||
ID: fmt.Sprintf(EntryIDLong, entry.ID),
|
||||
ID: convertEntryIDToLongFormItemID(entry.ID),
|
||||
Title: entry.Title,
|
||||
Author: entry.Author,
|
||||
TimestampUsec: fmt.Sprintf("%d", entry.Date.UnixMicro()),
|
||||
|
|
65
internal/googlereader/item.go
Normal file
65
internal/googlereader/item.go
Normal file
|
@ -0,0 +1,65 @@
|
|||
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package googlereader // import "miniflux.app/v2/internal/googlereader"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
ItemIDPrefix = "tag:google.com,2005:reader/item/"
|
||||
)
|
||||
|
||||
func convertEntryIDToLongFormItemID(entryID int64) string {
|
||||
// The entry ID is a 64-bit integer, so we need to format it as a 16-character hexadecimal string.
|
||||
return ItemIDPrefix + fmt.Sprintf("%016x", entryID)
|
||||
}
|
||||
|
||||
// parseItemID parses a Google Reader ID string.
|
||||
// It supports both the long form (tag:google.com,2005:reader/item/<hex_id>) and the short form (<decimal_id>).
|
||||
// It returns the parsed ID as a int64 and an error if parsing fails.
|
||||
func parseItemID(itemIDValue string) (int64, error) {
|
||||
if strings.HasPrefix(itemIDValue, ItemIDPrefix) {
|
||||
hexID := strings.TrimPrefix(itemIDValue, ItemIDPrefix)
|
||||
|
||||
// It's always 16 characters wide.
|
||||
if len(hexID) != 16 {
|
||||
return 0, errors.New("long form ID has incorrect length")
|
||||
}
|
||||
|
||||
parsedID, err := strconv.ParseInt(hexID, 16, 64)
|
||||
if err != nil {
|
||||
return 0, errors.New("failed to parse long form hex ID: " + err.Error())
|
||||
}
|
||||
return parsedID, nil
|
||||
} else {
|
||||
parsedID, err := strconv.ParseInt(itemIDValue, 10, 64)
|
||||
if err != nil {
|
||||
return 0, errors.New("failed to parse short form decimal ID: " + err.Error())
|
||||
}
|
||||
return parsedID, nil
|
||||
}
|
||||
}
|
||||
|
||||
func parseItemIDsFromRequest(r *http.Request) ([]int64, error) {
|
||||
items := r.Form[ParamItemIDs]
|
||||
if len(items) == 0 {
|
||||
return nil, fmt.Errorf("googlereader: no items requested")
|
||||
}
|
||||
|
||||
itemIDs := make([]int64, len(items))
|
||||
for i, item := range items {
|
||||
itemID, err := parseItemID(item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("googlereader: failed to parse item ID %s: %w", item, err)
|
||||
}
|
||||
itemIDs[i] = itemID
|
||||
}
|
||||
|
||||
return itemIDs, nil
|
||||
}
|
109
internal/googlereader/item_test.go
Normal file
109
internal/googlereader/item_test.go
Normal file
|
@ -0,0 +1,109 @@
|
|||
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package googlereader // import "miniflux.app/v2/internal/googlereader"
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConvertEntryIDToLongFormItemID(t *testing.T) {
|
||||
entryID := int64(344691561)
|
||||
expected := "tag:google.com,2005:reader/item/00000000148b9369"
|
||||
result := convertEntryIDToLongFormItemID(entryID)
|
||||
|
||||
if result != expected {
|
||||
t.Errorf("expected %s, got %s", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseItemIDsFromRequest(t *testing.T) {
|
||||
formValues := url.Values{}
|
||||
formValues.Add("i", "12345")
|
||||
formValues.Add("i", convertEntryIDToLongFormItemID(45678))
|
||||
|
||||
request := &http.Request{
|
||||
Form: formValues,
|
||||
}
|
||||
|
||||
result, err := parseItemIDsFromRequest(request)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
var expected = []int64{12345, 45678}
|
||||
if !reflect.DeepEqual(result, expected) {
|
||||
t.Errorf("expected %v, got %v", expected, result)
|
||||
}
|
||||
|
||||
// Test with no item IDs
|
||||
formValues = url.Values{}
|
||||
request = &http.Request{
|
||||
Form: formValues,
|
||||
}
|
||||
_, err = parseItemIDsFromRequest(request)
|
||||
if err == nil {
|
||||
t.Fatalf("expected error, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseItemID(t *testing.T) {
|
||||
// Test with long form ID
|
||||
result, err := parseItemID("tag:google.com,2005:reader/item/0000000000000001")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expected := int64(1)
|
||||
if result != expected {
|
||||
t.Errorf("expected %d, got %d", expected, result)
|
||||
}
|
||||
|
||||
// Test with short form ID
|
||||
result, err = parseItemID("12345")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expected = int64(12345)
|
||||
if result != expected {
|
||||
t.Errorf("expected %d, got %d", expected, result)
|
||||
}
|
||||
|
||||
// Test with invalid long form ID
|
||||
_, err = parseItemID("tag:google.com,2005:reader/item/000000000000000g")
|
||||
if err == nil {
|
||||
t.Fatalf("expected error, got nil")
|
||||
}
|
||||
|
||||
// Test with invalid short form ID
|
||||
_, err = parseItemID("invalid_id")
|
||||
if err == nil {
|
||||
t.Fatalf("expected error, got nil")
|
||||
}
|
||||
|
||||
// Test with empty ID
|
||||
_, err = parseItemID("")
|
||||
if err == nil {
|
||||
t.Fatalf("expected error, got nil")
|
||||
}
|
||||
|
||||
// Test with ID that is too short
|
||||
_, err = parseItemID("tag:google.com,2005:reader/item/00000000000000")
|
||||
if err == nil {
|
||||
t.Fatalf("expected error, got nil")
|
||||
}
|
||||
|
||||
// Test with ID that is too long
|
||||
_, err = parseItemID("tag:google.com,2005:reader/item/000000000000000000")
|
||||
if err == nil {
|
||||
t.Fatalf("expected error, got nil")
|
||||
}
|
||||
|
||||
// Test with ID that is not a number
|
||||
_, err = parseItemID("tag:google.com,2005:reader/item/abc")
|
||||
if err == nil {
|
||||
t.Fatalf("expected error, got nil")
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue