From f49b42f70f902d4da1e0fa4080e99164b331b716 Mon Sep 17 00:00:00 2001 From: Frédéric Guillot Date: Sun, 29 Apr 2018 16:35:04 -0700 Subject: Use vanilla HTTP handlers (refactoring) --- api/category.go | 59 ++++++++++++----------- api/entry.go | 132 ++++++++++++++++++++++++++-------------------------- api/feed.go | 119 ++++++++++++++++++++++++---------------------- api/icon.go | 22 +++++---- api/payload.go | 30 +++++++----- api/subscription.go | 15 +++--- api/user.go | 99 +++++++++++++++++++++------------------ 7 files changed, 254 insertions(+), 222 deletions(-) (limited to 'api') diff --git a/api/category.go b/api/category.go index 67c7e52..30b12f4 100644 --- a/api/category.go +++ b/api/category.go @@ -6,98 +6,105 @@ package api import ( "errors" + "net/http" - "github.com/miniflux/miniflux/http/handler" + "github.com/miniflux/miniflux/http/context" + "github.com/miniflux/miniflux/http/request" + "github.com/miniflux/miniflux/http/response/json" ) // CreateCategory is the API handler to create a new category. -func (c *Controller) CreateCategory(ctx *handler.Context, request *handler.Request, response *handler.Response) { - userID := ctx.UserID() - category, err := decodeCategoryPayload(request.Body()) +func (c *Controller) CreateCategory(w http.ResponseWriter, r *http.Request) { + category, err := decodeCategoryPayload(r.Body) if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } + ctx := context.New(r) + userID := ctx.UserID() category.UserID = userID if err := category.ValidateCategoryCreation(); err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } if c, err := c.store.CategoryByTitle(userID, category.Title); err != nil || c != nil { - response.JSON().BadRequest(errors.New("This category already exists")) + json.BadRequest(w, errors.New("This category already exists")) return } err = c.store.CreateCategory(category) if err != nil { - response.JSON().ServerError(errors.New("Unable to create this category")) + json.ServerError(w, errors.New("Unable to create this category")) return } - response.JSON().Created(category) + json.Created(w, category) } // UpdateCategory is the API handler to update a category. -func (c *Controller) UpdateCategory(ctx *handler.Context, request *handler.Request, response *handler.Response) { - categoryID, err := request.IntegerParam("categoryID") +func (c *Controller) UpdateCategory(w http.ResponseWriter, r *http.Request) { + categoryID, err := request.IntParam(r, "categoryID") if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } - category, err := decodeCategoryPayload(request.Body()) + category, err := decodeCategoryPayload(r.Body) if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } + ctx := context.New(r) category.UserID = ctx.UserID() category.ID = categoryID if err := category.ValidateCategoryModification(); err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } err = c.store.UpdateCategory(category) if err != nil { - response.JSON().ServerError(errors.New("Unable to update this category")) + json.ServerError(w, errors.New("Unable to update this category")) return } - response.JSON().Created(category) + json.Created(w, category) } // GetCategories is the API handler to get a list of categories for a given user. -func (c *Controller) GetCategories(ctx *handler.Context, request *handler.Request, response *handler.Response) { +func (c *Controller) GetCategories(w http.ResponseWriter, r *http.Request) { + ctx := context.New(r) categories, err := c.store.Categories(ctx.UserID()) if err != nil { - response.JSON().ServerError(errors.New("Unable to fetch categories")) + json.ServerError(w, errors.New("Unable to fetch categories")) return } - response.JSON().Standard(categories) + json.OK(w, categories) } // RemoveCategory is the API handler to remove a category. -func (c *Controller) RemoveCategory(ctx *handler.Context, request *handler.Request, response *handler.Response) { +func (c *Controller) RemoveCategory(w http.ResponseWriter, r *http.Request) { + ctx := context.New(r) userID := ctx.UserID() - categoryID, err := request.IntegerParam("categoryID") + categoryID, err := request.IntParam(r, "categoryID") if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } if !c.store.CategoryExists(userID, categoryID) { - response.JSON().NotFound(errors.New("Category not found")) + json.NotFound(w, errors.New("Category not found")) return } if err := c.store.RemoveCategory(userID, categoryID); err != nil { - response.JSON().ServerError(errors.New("Unable to remove this category")) + json.ServerError(w, errors.New("Unable to remove this category")) return } - response.JSON().NoContent() + json.NoContent(w) } diff --git a/api/entry.go b/api/entry.go index 4152da8..390f9ec 100644 --- a/api/entry.go +++ b/api/entry.go @@ -6,107 +6,110 @@ package api import ( "errors" + "net/http" - "github.com/miniflux/miniflux/http/handler" + "github.com/miniflux/miniflux/http/context" + "github.com/miniflux/miniflux/http/request" + "github.com/miniflux/miniflux/http/response/json" "github.com/miniflux/miniflux/model" ) // GetFeedEntry is the API handler to get a single feed entry. -func (c *Controller) GetFeedEntry(ctx *handler.Context, request *handler.Request, response *handler.Response) { - userID := ctx.UserID() - feedID, err := request.IntegerParam("feedID") +func (c *Controller) GetFeedEntry(w http.ResponseWriter, r *http.Request) { + feedID, err := request.IntParam(r, "feedID") if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } - entryID, err := request.IntegerParam("entryID") + entryID, err := request.IntParam(r, "entryID") if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } + ctx := context.New(r) + userID := ctx.UserID() + builder := c.store.NewEntryQueryBuilder(userID) builder.WithFeedID(feedID) builder.WithEntryID(entryID) entry, err := builder.GetEntry() if err != nil { - response.JSON().ServerError(errors.New("Unable to fetch this entry from the database")) + json.ServerError(w, errors.New("Unable to fetch this entry from the database")) return } if entry == nil { - response.JSON().NotFound(errors.New("Entry not found")) + json.NotFound(w, errors.New("Entry not found")) return } - response.JSON().Standard(entry) + json.OK(w, entry) } // GetEntry is the API handler to get a single entry. -func (c *Controller) GetEntry(ctx *handler.Context, request *handler.Request, response *handler.Response) { - userID := ctx.UserID() - entryID, err := request.IntegerParam("entryID") +func (c *Controller) GetEntry(w http.ResponseWriter, r *http.Request) { + entryID, err := request.IntParam(r, "entryID") if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } - builder := c.store.NewEntryQueryBuilder(userID) + builder := c.store.NewEntryQueryBuilder(context.New(r).UserID()) builder.WithEntryID(entryID) entry, err := builder.GetEntry() if err != nil { - response.JSON().ServerError(errors.New("Unable to fetch this entry from the database")) + json.ServerError(w, errors.New("Unable to fetch this entry from the database")) return } if entry == nil { - response.JSON().NotFound(errors.New("Entry not found")) + json.NotFound(w, errors.New("Entry not found")) return } - response.JSON().Standard(entry) + json.OK(w, entry) } // GetFeedEntries is the API handler to get all feed entries. -func (c *Controller) GetFeedEntries(ctx *handler.Context, request *handler.Request, response *handler.Response) { - userID := ctx.UserID() - feedID, err := request.IntegerParam("feedID") +func (c *Controller) GetFeedEntries(w http.ResponseWriter, r *http.Request) { + feedID, err := request.IntParam(r, "feedID") if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } - status := request.QueryStringParam("status", "") + status := request.QueryParam(r, "status", "") if status != "" { if err := model.ValidateEntryStatus(status); err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } } - order := request.QueryStringParam("order", model.DefaultSortingOrder) + order := request.QueryParam(r, "order", model.DefaultSortingOrder) if err := model.ValidateEntryOrder(order); err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } - direction := request.QueryStringParam("direction", model.DefaultSortingDirection) + direction := request.QueryParam(r, "direction", model.DefaultSortingDirection) if err := model.ValidateDirection(direction); err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } - limit := request.QueryIntegerParam("limit", 100) - offset := request.QueryIntegerParam("offset", 0) + limit := request.QueryIntParam(r, "limit", 100) + offset := request.QueryIntParam(r, "offset", 0) if err := model.ValidateRange(offset, limit); err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } - builder := c.store.NewEntryQueryBuilder(userID) + builder := c.store.NewEntryQueryBuilder(context.New(r).UserID()) builder.WithFeedID(feedID) builder.WithStatus(status) builder.WithOrder(order) @@ -116,51 +119,49 @@ func (c *Controller) GetFeedEntries(ctx *handler.Context, request *handler.Reque entries, err := builder.GetEntries() if err != nil { - response.JSON().ServerError(errors.New("Unable to fetch the list of entries")) + json.ServerError(w, errors.New("Unable to fetch the list of entries")) return } count, err := builder.CountEntries() if err != nil { - response.JSON().ServerError(errors.New("Unable to count the number of entries")) + json.ServerError(w, errors.New("Unable to count the number of entries")) return } - response.JSON().Standard(&entriesResponse{Total: count, Entries: entries}) + json.OK(w, &entriesResponse{Total: count, Entries: entries}) } // GetEntries is the API handler to fetch entries. -func (c *Controller) GetEntries(ctx *handler.Context, request *handler.Request, response *handler.Response) { - userID := ctx.UserID() - - status := request.QueryStringParam("status", "") +func (c *Controller) GetEntries(w http.ResponseWriter, r *http.Request) { + status := request.QueryParam(r, "status", "") if status != "" { if err := model.ValidateEntryStatus(status); err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } } - order := request.QueryStringParam("order", model.DefaultSortingOrder) + order := request.QueryParam(r, "order", model.DefaultSortingOrder) if err := model.ValidateEntryOrder(order); err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } - direction := request.QueryStringParam("direction", model.DefaultSortingDirection) + direction := request.QueryParam(r, "direction", model.DefaultSortingDirection) if err := model.ValidateDirection(direction); err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } - limit := request.QueryIntegerParam("limit", 100) - offset := request.QueryIntegerParam("offset", 0) + limit := request.QueryIntParam(r, "limit", 100) + offset := request.QueryIntParam(r, "offset", 0) if err := model.ValidateRange(offset, limit); err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } - builder := c.store.NewEntryQueryBuilder(userID) + builder := c.store.NewEntryQueryBuilder(context.New(r).UserID()) builder.WithStatus(status) builder.WithOrder(order) builder.WithDirection(direction) @@ -169,55 +170,52 @@ func (c *Controller) GetEntries(ctx *handler.Context, request *handler.Request, entries, err := builder.GetEntries() if err != nil { - response.JSON().ServerError(errors.New("Unable to fetch the list of entries")) + json.ServerError(w, errors.New("Unable to fetch the list of entries")) return } count, err := builder.CountEntries() if err != nil { - response.JSON().ServerError(errors.New("Unable to count the number of entries")) + json.ServerError(w, errors.New("Unable to count the number of entries")) return } - response.JSON().Standard(&entriesResponse{Total: count, Entries: entries}) + json.OK(w, &entriesResponse{Total: count, Entries: entries}) } // SetEntryStatus is the API handler to change the status of entries. -func (c *Controller) SetEntryStatus(ctx *handler.Context, request *handler.Request, response *handler.Response) { - userID := ctx.UserID() - - entryIDs, status, err := decodeEntryStatusPayload(request.Body()) +func (c *Controller) SetEntryStatus(w http.ResponseWriter, r *http.Request) { + entryIDs, status, err := decodeEntryStatusPayload(r.Body) if err != nil { - response.JSON().BadRequest(errors.New("Invalid JSON payload")) + json.BadRequest(w, errors.New("Invalid JSON payload")) return } if err := model.ValidateEntryStatus(status); err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } - if err := c.store.SetEntriesStatus(userID, entryIDs, status); err != nil { - response.JSON().ServerError(errors.New("Unable to change entries status")) + if err := c.store.SetEntriesStatus(context.New(r).UserID(), entryIDs, status); err != nil { + json.ServerError(w, errors.New("Unable to change entries status")) return } - response.JSON().NoContent() + json.NoContent(w) } // ToggleBookmark is the API handler to toggle bookmark status. -func (c *Controller) ToggleBookmark(ctx *handler.Context, request *handler.Request, response *handler.Response) { - userID := ctx.UserID() - entryID, err := request.IntegerParam("entryID") +func (c *Controller) ToggleBookmark(w http.ResponseWriter, r *http.Request) { + entryID, err := request.IntParam(r, "entryID") if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } - if err := c.store.ToggleBookmark(userID, entryID); err != nil { - response.JSON().ServerError(errors.New("Unable to toggle bookmark value")) + if err := c.store.ToggleBookmark(context.New(r).UserID(), entryID); err != nil { + json.ServerError(w, errors.New("Unable to toggle bookmark value")) return } - response.JSON().NoContent() + json.NoContent(w) } diff --git a/api/feed.go b/api/feed.go index 16e3d7d..72eaa41 100644 --- a/api/feed.go +++ b/api/feed.go @@ -6,44 +6,49 @@ package api import ( "errors" + "net/http" + "github.com/miniflux/miniflux/http/context" + "github.com/miniflux/miniflux/http/request" + "github.com/miniflux/miniflux/http/response/json" + "github.com/miniflux/miniflux/http/response/xml" "github.com/miniflux/miniflux/reader/opml" - - "github.com/miniflux/miniflux/http/handler" ) // CreateFeed is the API handler to create a new feed. -func (c *Controller) CreateFeed(ctx *handler.Context, request *handler.Request, response *handler.Response) { - userID := ctx.UserID() - feedURL, categoryID, err := decodeFeedCreationPayload(request.Body()) +func (c *Controller) CreateFeed(w http.ResponseWriter, r *http.Request) { + feedURL, categoryID, err := decodeFeedCreationPayload(r.Body) if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } if feedURL == "" { - response.JSON().BadRequest(errors.New("The feed_url is required")) + json.BadRequest(w, errors.New("The feed_url is required")) return } if categoryID <= 0 { - response.JSON().BadRequest(errors.New("The category_id is required")) + json.BadRequest(w, errors.New("The category_id is required")) return } + ctx := context.New(r) + userID := ctx.UserID() + if c.store.FeedURLExists(userID, feedURL) { - response.JSON().BadRequest(errors.New("This feed_url already exists")) + json.BadRequest(w, errors.New("This feed_url already exists")) return } if !c.store.CategoryExists(userID, categoryID) { - response.JSON().BadRequest(errors.New("This category_id doesn't exists or doesn't belongs to this user")) + json.BadRequest(w, errors.New("This category_id doesn't exists or doesn't belongs to this user")) return } feed, err := c.feedHandler.CreateFeed(userID, categoryID, feedURL, false) if err != nil { - response.JSON().ServerError(errors.New("Unable to create this feed")) + json.ServerError(w, errors.New("Unable to create this feed")) return } @@ -51,142 +56,146 @@ func (c *Controller) CreateFeed(ctx *handler.Context, request *handler.Request, FeedID int64 `json:"feed_id"` } - response.JSON().Created(&result{FeedID: feed.ID}) + json.Created(w, &result{FeedID: feed.ID}) } // RefreshFeed is the API handler to refresh a feed. -func (c *Controller) RefreshFeed(ctx *handler.Context, request *handler.Request, response *handler.Response) { - userID := ctx.UserID() - feedID, err := request.IntegerParam("feedID") +func (c *Controller) RefreshFeed(w http.ResponseWriter, r *http.Request) { + feedID, err := request.IntParam(r, "feedID") if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } + ctx := context.New(r) + userID := ctx.UserID() + if !c.store.FeedExists(userID, feedID) { - response.JSON().NotFound(errors.New("Unable to find this feed")) + json.NotFound(w, errors.New("Unable to find this feed")) return } err = c.feedHandler.RefreshFeed(userID, feedID) if err != nil { - response.JSON().ServerError(errors.New("Unable to refresh this feed")) + json.ServerError(w, errors.New("Unable to refresh this feed")) return } - response.JSON().NoContent() + json.NoContent(w) } // UpdateFeed is the API handler that is used to update a feed. -func (c *Controller) UpdateFeed(ctx *handler.Context, request *handler.Request, response *handler.Response) { - userID := ctx.UserID() - feedID, err := request.IntegerParam("feedID") +func (c *Controller) UpdateFeed(w http.ResponseWriter, r *http.Request) { + feedID, err := request.IntParam(r, "feedID") if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } - newFeed, err := decodeFeedModificationPayload(request.Body()) + newFeed, err := decodeFeedModificationPayload(r.Body) if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } + ctx := context.New(r) + userID := ctx.UserID() + if newFeed.Category != nil && newFeed.Category.ID != 0 && !c.store.CategoryExists(userID, newFeed.Category.ID) { - response.JSON().BadRequest(errors.New("This category_id doesn't exists or doesn't belongs to this user")) + json.BadRequest(w, errors.New("This category_id doesn't exists or doesn't belongs to this user")) return } originalFeed, err := c.store.FeedByID(userID, feedID) if err != nil { - response.JSON().NotFound(errors.New("Unable to find this feed")) + json.NotFound(w, errors.New("Unable to find this feed")) return } if originalFeed == nil { - response.JSON().NotFound(errors.New("Feed not found")) + json.NotFound(w, errors.New("Feed not found")) return } originalFeed.Merge(newFeed) if err := c.store.UpdateFeed(originalFeed); err != nil { - response.JSON().ServerError(errors.New("Unable to update this feed")) + json.ServerError(w, errors.New("Unable to update this feed")) return } originalFeed, err = c.store.FeedByID(userID, feedID) if err != nil { - response.JSON().ServerError(errors.New("Unable to fetch this feed")) + json.ServerError(w, errors.New("Unable to fetch this feed")) return } - response.JSON().Created(originalFeed) + json.Created(w, originalFeed) } // GetFeeds is the API handler that get all feeds that belongs to the given user. -func (c *Controller) GetFeeds(ctx *handler.Context, request *handler.Request, response *handler.Response) { - feeds, err := c.store.Feeds(ctx.UserID()) +func (c *Controller) GetFeeds(w http.ResponseWriter, r *http.Request) { + feeds, err := c.store.Feeds(context.New(r).UserID()) if err != nil { - response.JSON().ServerError(errors.New("Unable to fetch feeds from the database")) + json.ServerError(w, errors.New("Unable to fetch feeds from the database")) return } - response.JSON().Standard(feeds) + json.OK(w, feeds) } // Export is the API handler that incoves an OPML export. -func (c *Controller) Export(ctx *handler.Context, request *handler.Request, response *handler.Response) { +func (c *Controller) Export(w http.ResponseWriter, r *http.Request) { opmlHandler := opml.NewHandler(c.store) - - opml, err := opmlHandler.Export(ctx.LoggedUser().ID) + opml, err := opmlHandler.Export(context.New(r).UserID()) if err != nil { - response.JSON().ServerError(errors.New("unable to export feeds to OPML")) + json.ServerError(w, errors.New("unable to export feeds to OPML")) } - response.XML().Serve(opml) + xml.OK(w, opml) } // GetFeed is the API handler to get a feed. -func (c *Controller) GetFeed(ctx *handler.Context, request *handler.Request, response *handler.Response) { - userID := ctx.UserID() - feedID, err := request.IntegerParam("feedID") +func (c *Controller) GetFeed(w http.ResponseWriter, r *http.Request) { + feedID, err := request.IntParam(r, "feedID") if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } - feed, err := c.store.FeedByID(userID, feedID) + feed, err := c.store.FeedByID(context.New(r).UserID(), feedID) if err != nil { - response.JSON().ServerError(errors.New("Unable to fetch this feed")) + json.ServerError(w, errors.New("Unable to fetch this feed")) return } if feed == nil { - response.JSON().NotFound(errors.New("Feed not found")) + json.NotFound(w, errors.New("Feed not found")) return } - response.JSON().Standard(feed) + json.OK(w, feed) } // RemoveFeed is the API handler to remove a feed. -func (c *Controller) RemoveFeed(ctx *handler.Context, request *handler.Request, response *handler.Response) { - userID := ctx.UserID() - feedID, err := request.IntegerParam("feedID") +func (c *Controller) RemoveFeed(w http.ResponseWriter, r *http.Request) { + feedID, err := request.IntParam(r, "feedID") if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } + ctx := context.New(r) + userID := ctx.UserID() + if !c.store.FeedExists(userID, feedID) { - response.JSON().NotFound(errors.New("Feed not found")) + json.NotFound(w, errors.New("Feed not found")) return } if err := c.store.RemoveFeed(userID, feedID); err != nil { - response.JSON().ServerError(errors.New("Unable to remove this feed")) + json.ServerError(w, errors.New("Unable to remove this feed")) return } - response.JSON().NoContent() + json.NoContent(w) } diff --git a/api/icon.go b/api/icon.go index 7734dbf..0f5aa1b 100644 --- a/api/icon.go +++ b/api/icon.go @@ -6,36 +6,38 @@ package api import ( "errors" + "net/http" - "github.com/miniflux/miniflux/http/handler" + "github.com/miniflux/miniflux/http/context" + "github.com/miniflux/miniflux/http/request" + "github.com/miniflux/miniflux/http/response/json" ) // FeedIcon returns a feed icon. -func (c *Controller) FeedIcon(ctx *handler.Context, request *handler.Request, response *handler.Response) { - userID := ctx.UserID() - feedID, err := request.IntegerParam("feedID") +func (c *Controller) FeedIcon(w http.ResponseWriter, r *http.Request) { + feedID, err := request.IntParam(r, "feedID") if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } if !c.store.HasIcon(feedID) { - response.JSON().NotFound(errors.New("This feed doesn't have any icon")) + json.NotFound(w, errors.New("This feed doesn't have any icon")) return } - icon, err := c.store.IconByFeedID(userID, feedID) + icon, err := c.store.IconByFeedID(context.New(r).UserID(), feedID) if err != nil { - response.JSON().ServerError(errors.New("Unable to fetch feed icon")) + json.ServerError(w, errors.New("Unable to fetch feed icon")) return } if icon == nil { - response.JSON().NotFound(errors.New("This feed doesn't have any icon")) + json.NotFound(w, errors.New("This feed doesn't have any icon")) return } - response.JSON().Standard(&feedIcon{ + json.OK(w, &feedIcon{ ID: icon.ID, MimeType: icon.MimeType, Data: icon.DataURL(), diff --git a/api/payload.go b/api/payload.go index 46c3b04..bf470eb 100644 --- a/api/payload.go +++ b/api/payload.go @@ -23,10 +23,11 @@ type entriesResponse struct { Entries model.Entries `json:"entries"` } -func decodeUserPayload(data io.Reader) (*model.User, error) { +func decodeUserPayload(r io.ReadCloser) (*model.User, error) { var user model.User - decoder := json.NewDecoder(data) + decoder := json.NewDecoder(r) + defer r.Close() if err := decoder.Decode(&user); err != nil { return nil, fmt.Errorf("Unable to decode user JSON object: %v", err) } @@ -34,13 +35,14 @@ func decodeUserPayload(data io.Reader) (*model.User, error) { return &user, nil } -func decodeURLPayload(data io.Reader) (string, error) { +func decodeURLPayload(r io.ReadCloser) (string, error) { type payload struct { URL string `json:"url"` } var p payload - decoder := json.NewDecoder(data) + decoder := json.NewDecoder(r) + defer r.Close() if err := decoder.Decode(&p); err != nil { return "", fmt.Errorf("invalid JSON payload: %v", err) } @@ -48,14 +50,15 @@ func decodeURLPayload(data io.Reader) (string, error) { return p.URL, nil } -func decodeEntryStatusPayload(data io.Reader) ([]int64, string, error) { +func decodeEntryStatusPayload(r io.ReadCloser) ([]int64, string, error) { type payload struct { EntryIDs []int64 `json:"entry_ids"` Status string `json:"status"` } var p payload - decoder := json.NewDecoder(data) + decoder := json.NewDecoder(r) + defer r.Close() if err := decoder.Decode(&p); err != nil { return nil, "", fmt.Errorf("invalid JSON payload: %v", err) } @@ -63,14 +66,15 @@ func decodeEntryStatusPayload(data io.Reader) ([]int64, string, error) { return p.EntryIDs, p.Status, nil } -func decodeFeedCreationPayload(data io.Reader) (string, int64, error) { +func decodeFeedCreationPayload(r io.ReadCloser) (string, int64, error) { type payload struct { FeedURL string `json:"feed_url"` CategoryID int64 `json:"category_id"` } var p payload - decoder := json.NewDecoder(data) + decoder := json.NewDecoder(r) + defer r.Close() if err := decoder.Decode(&p); err != nil { return "", 0, fmt.Errorf("invalid JSON payload: %v", err) } @@ -78,10 +82,11 @@ func decodeFeedCreationPayload(data io.Reader) (string, int64, error) { return p.FeedURL, p.CategoryID, nil } -func decodeFeedModificationPayload(data io.Reader) (*model.Feed, error) { +func decodeFeedModificationPayload(r io.ReadCloser) (*model.Feed, error) { var feed model.Feed - decoder := json.NewDecoder(data) + decoder := json.NewDecoder(r) + defer r.Close() if err := decoder.Decode(&feed); err != nil { return nil, fmt.Errorf("Unable to decode feed JSON object: %v", err) } @@ -89,10 +94,11 @@ func decodeFeedModificationPayload(data io.Reader) (*model.Feed, error) { return &feed, nil } -func decodeCategoryPayload(data io.Reader) (*model.Category, error) { +func decodeCategoryPayload(r io.ReadCloser) (*model.Category, error) { var category model.Category - decoder := json.NewDecoder(data) + decoder := json.NewDecoder(r) + defer r.Close() if err := decoder.Decode(&category); err != nil { return nil, fmt.Errorf("Unable to decode category JSON object: %v", err) } diff --git a/api/subscription.go b/api/subscription.go index 8a8feff..c858f0e 100644 --- a/api/subscription.go +++ b/api/subscription.go @@ -7,29 +7,30 @@ package api import ( "errors" "fmt" + "net/http" - "github.com/miniflux/miniflux/http/handler" + "github.com/miniflux/miniflux/http/response/json" "github.com/miniflux/miniflux/reader/subscription" ) // GetSubscriptions is the API handler to find subscriptions. -func (c *Controller) GetSubscriptions(ctx *handler.Context, request *handler.Request, response *handler.Response) { - websiteURL, err := decodeURLPayload(request.Body()) +func (c *Controller) GetSubscriptions(w http.ResponseWriter, r *http.Request) { + websiteURL, err := decodeURLPayload(r.Body) if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } subscriptions, err := subscription.FindSubscriptions(websiteURL) if err != nil { - response.JSON().ServerError(errors.New("Unable to discover subscriptions")) + json.ServerError(w, errors.New("Unable to discover subscriptions")) return } if subscriptions == nil { - response.JSON().NotFound(fmt.Errorf("No subscription found")) + json.NotFound(w, fmt.Errorf("No subscription found")) return } - response.JSON().Standard(subscriptions) + json.OK(w, subscriptions) } diff --git a/api/user.go b/api/user.go index 359a9f7..3cddb46 100644 --- a/api/user.go +++ b/api/user.go @@ -6,182 +6,191 @@ package api import ( "errors" + "net/http" - "github.com/miniflux/miniflux/http/handler" + "github.com/miniflux/miniflux/http/context" + "github.com/miniflux/miniflux/http/request" + "github.com/miniflux/miniflux/http/response/json" ) // CreateUser is the API handler to create a new user. -func (c *Controller) CreateUser(ctx *handler.Context, request *handler.Request, response *handler.Response) { +func (c *Controller) CreateUser(w http.ResponseWriter, r *http.Request) { + ctx := context.New(r) if !ctx.IsAdminUser() { - response.JSON().Forbidden() + json.Forbidden(w) return } - user, err := decodeUserPayload(request.Body()) + user, err := decodeUserPayload(r.Body) if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } if err := user.ValidateUserCreation(); err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } if c.store.UserExists(user.Username) { - response.JSON().BadRequest(errors.New("This user already exists")) + json.BadRequest(w, errors.New("This user already exists")) return } err = c.store.CreateUser(user) if err != nil { - response.JSON().ServerError(errors.New("Unable to create this user")) + json.ServerError(w, errors.New("Unable to create this user")) return } user.Password = "" - response.JSON().Created(user) + json.Created(w, user) } // UpdateUser is the API handler to update the given user. -func (c *Controller) UpdateUser(ctx *handler.Context, request *handler.Request, response *handler.Response) { +func (c *Controller) UpdateUser(w http.ResponseWriter, r *http.Request) { + ctx := context.New(r) if !ctx.IsAdminUser() { - response.JSON().Forbidden() + json.Forbidden(w) return } - userID, err := request.IntegerParam("userID") + userID, err := request.IntParam(r, "userID") if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } - user, err := decodeUserPayload(request.Body()) + user, err := decodeUserPayload(r.Body) if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } if err := user.ValidateUserModification(); err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } originalUser, err := c.store.UserByID(userID) if err != nil { - response.JSON().BadRequest(errors.New("Unable to fetch this user from the database")) + json.BadRequest(w, errors.New("Unable to fetch this user from the database")) return } if originalUser == nil { - response.JSON().NotFound(errors.New("User not found")) + json.NotFound(w, errors.New("User not found")) return } originalUser.Merge(user) if err = c.store.UpdateUser(originalUser); err != nil { - response.JSON().ServerError(errors.New("Unable to update this user")) + json.ServerError(w, errors.New("Unable to update this user")) return } - response.JSON().Created(originalUser) + json.Created(w, originalUser) } // Users is the API handler to get the list of users. -func (c *Controller) Users(ctx *handler.Context, request *handler.Request, response *handler.Response) { +func (c *Controller) Users(w http.ResponseWriter, r *http.Request) { + ctx := context.New(r) if !ctx.IsAdminUser() { - response.JSON().Forbidden() + json.Forbidden(w) return } users, err := c.store.Users() if err != nil { - response.JSON().ServerError(errors.New("Unable to fetch the list of users")) + json.ServerError(w, errors.New("Unable to fetch the list of users")) return } users.UseTimezone(ctx.UserTimezone()) - response.JSON().Standard(users) + json.OK(w, users) } // UserByID is the API handler to fetch the given user by the ID. -func (c *Controller) UserByID(ctx *handler.Context, request *handler.Request, response *handler.Response) { +func (c *Controller) UserByID(w http.ResponseWriter, r *http.Request) { + ctx := context.New(r) if !ctx.IsAdminUser() { - response.JSON().Forbidden() + json.Forbidden(w) return } - userID, err := request.IntegerParam("userID") + userID, err := request.IntParam(r, "userID") if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } user, err := c.store.UserByID(userID) if err != nil { - response.JSON().BadRequest(errors.New("Unable to fetch this user from the database")) + json.BadRequest(w, errors.New("Unable to fetch this user from the database")) return } if user == nil { - response.JSON().NotFound(errors.New("User not found")) + json.NotFound(w, errors.New("User not found")) return } user.UseTimezone(ctx.UserTimezone()) - response.JSON().Standard(user) + json.OK(w, user) } // UserByUsername is the API handler to fetch the given user by the username. -func (c *Controller) UserByUsername(ctx *handler.Context, request *handler.Request, response *handler.Response) { +func (c *Controller) UserByUsername(w http.ResponseWriter, r *http.Request) { + ctx := context.New(r) if !ctx.IsAdminUser() { - response.JSON().Forbidden() + json.Forbidden(w) return } - username := request.StringParam("username", "") + username := request.Param(r, "username", "") user, err := c.store.UserByUsername(username) if err != nil { - response.JSON().BadRequest(errors.New("Unable to fetch this user from the database")) + json.BadRequest(w, errors.New("Unable to fetch this user from the database")) return } if user == nil { - response.JSON().NotFound(errors.New("User not found")) + json.NotFound(w, errors.New("User not found")) return } - response.JSON().Standard(user) + json.OK(w, user) } // RemoveUser is the API handler to remove an existing user. -func (c *Controller) RemoveUser(ctx *handler.Context, request *handler.Request, response *handler.Response) { +func (c *Controller) RemoveUser(w http.ResponseWriter, r *http.Request) { + ctx := context.New(r) if !ctx.IsAdminUser() { - response.JSON().Forbidden() + json.Forbidden(w) return } - userID, err := request.IntegerParam("userID") + userID, err := request.IntParam(r, "userID") if err != nil { - response.JSON().BadRequest(err) + json.BadRequest(w, err) return } user, err := c.store.UserByID(userID) if err != nil { - response.JSON().ServerError(errors.New("Unable to fetch this user from the database")) + json.ServerError(w, errors.New("Unable to fetch this user from the database")) return } if user == nil { - response.JSON().NotFound(errors.New("User not found")) + json.NotFound(w, errors.New("User not found")) return } if err := c.store.RemoveUser(user.ID); err != nil { - response.JSON().BadRequest(errors.New("Unable to remove this user from the database")) + json.BadRequest(w, errors.New("Unable to remove this user from the database")) return } - response.JSON().NoContent() + json.NoContent(w) } -- cgit v1.2.3