From bb8e61c7c5d9f297bde207c6de07a5d4b67dcd29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Guillot?= Date: Mon, 27 Nov 2017 21:30:04 -0800 Subject: [PATCH] Make sure golint pass on the code base --- .travis.yml | 2 ++ Makefile | 14 ++++++---- locale/locale.go | 4 +-- locale/translations.go | 2 +- model/theme.go | 6 ++-- model/user.go | 12 ++------ reader/feed/handler.go | 2 +- reader/opml/handler.go | 6 ++-- reader/processor/processor.go | 1 + reader/rewrite/rewriter.go | 1 + server/api/controller/category.go | 3 +- server/api/controller/feed.go | 6 ++-- server/api/controller/user.go | 9 +++--- server/api/payload/payload.go | 7 +++++ server/core/context.go | 15 +++++----- server/core/handler.go | 4 +-- server/middleware/basic_auth.go | 16 +++++++---- server/middleware/context_keys.go | 26 ++++++++++++++++++ server/middleware/csrf.go | 6 ++-- server/middleware/middleware.go | 15 ++++++---- server/middleware/session.go | 11 +++++--- server/route/route.go | 3 +- server/routes.go | 4 +-- server/static/bin.go | 2 +- server/static/css.go | 2 +- server/static/js.go | 2 +- server/template/common.go | 2 +- server/template/template.go | 2 +- server/template/views.go | 2 +- server/ui/controller/about.go | 1 + server/ui/controller/category.go | 8 +++--- server/ui/controller/feed.go | 8 +++--- server/ui/controller/history.go | 2 +- server/ui/controller/icon.go | 6 ++-- server/ui/controller/oauth2.go | 2 +- server/ui/controller/opml.go | 3 ++ server/ui/controller/pagination.go | 16 +++++------ server/ui/controller/session.go | 7 +++-- server/ui/controller/settings.go | 11 +++++--- server/ui/controller/static.go | 8 ++++-- server/ui/controller/subscription.go | 2 +- server/ui/controller/unread.go | 2 +- server/ui/controller/user.go | 13 +++++++-- server/ui/filter/image_proxy_filter.go | 5 ++-- server/ui/form/auth.go | 8 ++++-- server/ui/form/category.go | 10 +++++-- server/ui/form/feed.go | 8 ++++-- server/ui/form/settings.go | 15 ++++++---- server/ui/form/subscription.go | 8 ++++-- server/ui/form/user.go | 23 ++++++++++------ server/ui/payload/payload.go | 4 ++- sql/sql.go | 2 +- storage/category.go | 38 ++++++++++++++++---------- storage/feed.go | 15 +++++++--- storage/icon.go | 15 ++++++---- storage/session.go | 13 +++++++-- storage/storage.go | 8 ++++-- storage/timezone.go | 8 ++++-- storage/user.go | 37 +++++++++++++++++-------- 59 files changed, 322 insertions(+), 171 deletions(-) create mode 100644 server/middleware/context_keys.go diff --git a/.travis.yml b/.travis.yml index 8a3c51f4..c872700a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,9 @@ go: - 1.9 before_install: - npm install -g jshint + - go get -u github.com/golang/lint/golint script: - jshint server/static/js/app.js + - make lint - make test - make integration-test diff --git a/Makefile b/Makefile index 61ec8c2c..0b4be229 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,10 @@ -APP = miniflux -VERSION = $(shell git rev-parse --short HEAD) -BUILD_DATE = `date +%FT%T%z` -DB_URL = postgres://postgres:postgres@localhost/miniflux_test?sslmode=disable +APP := miniflux +VERSION := $(shell git rev-parse --short HEAD) +BUILD_DATE := `date +%FT%T%z` +PKG_LIST := $(shell go list ./... | grep -v /vendor/) +DB_URL := postgres://postgres:postgres@localhost/miniflux_test?sslmode=disable -.PHONY: build-linux build-darwin build run clean test integration-test clean-integration-test +.PHONY: build-linux build-darwin build run clean test lint integration-test clean-integration-test build-linux: @ go generate @@ -25,6 +26,9 @@ clean: test: go test -cover -race ./... +lint: + @ golint -set_exit_status ${PKG_LIST} + integration-test: psql -U postgres -c 'drop database if exists miniflux_test;' psql -U postgres -c 'create database miniflux_test;' diff --git a/locale/locale.go b/locale/locale.go index 257ec2be..c62d6b6d 100644 --- a/locale/locale.go +++ b/locale/locale.go @@ -24,8 +24,8 @@ func Load() *Translator { return translator } -// GetAvailableLanguages returns the list of available languages. -func GetAvailableLanguages() map[string]string { +// AvailableLanguages returns the list of available languages. +func AvailableLanguages() map[string]string { return map[string]string{ "en_US": "English", "fr_FR": "Français", diff --git a/locale/translations.go b/locale/translations.go index 766f8add..b9164fa1 100644 --- a/locale/translations.go +++ b/locale/translations.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2017-11-25 15:50:52.572283626 -0800 PST m=+0.030941705 +// 2017-11-27 21:07:53.23444885 -0800 PST m=+0.028635078 package locale diff --git a/model/theme.go b/model/theme.go index c9bbc05d..85307ce4 100644 --- a/model/theme.go +++ b/model/theme.go @@ -6,8 +6,8 @@ package model import "github.com/miniflux/miniflux2/errors" -// GetThemes returns the list of available themes. -func GetThemes() map[string]string { +// Themes returns the list of available themes. +func Themes() map[string]string { return map[string]string{ "default": "Default", "black": "Black", @@ -16,7 +16,7 @@ func GetThemes() map[string]string { // ValidateTheme validates theme value. func ValidateTheme(theme string) error { - for key := range GetThemes() { + for key := range Themes() { if key == theme { return nil } diff --git a/model/user.go b/model/user.go index b756f1b8..c030d524 100644 --- a/model/user.go +++ b/model/user.go @@ -33,11 +33,7 @@ func (u User) ValidateUserCreation() error { return err } - if err := u.ValidatePassword(); err != nil { - return err - } - - return nil + return u.ValidatePassword() } // ValidateUserModification validates user for modification. @@ -54,11 +50,7 @@ func (u User) ValidateUserModification() error { return err } - if err := ValidateTheme(u.Theme); err != nil { - return err - } - - return nil + return ValidateTheme(u.Theme) } // ValidateUserLogin validates user credential requirements. diff --git a/reader/feed/handler.go b/reader/feed/handler.go index c6dc4487..f406c139 100644 --- a/reader/feed/handler.go +++ b/reader/feed/handler.go @@ -92,7 +92,7 @@ func (h *Handler) CreateFeed(userID, categoryID int64, url string) (*model.Feed, func (h *Handler) RefreshFeed(userID, feedID int64) error { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Handler:RefreshFeed] feedID=%d", feedID)) - originalFeed, err := h.store.GetFeedById(userID, feedID) + originalFeed, err := h.store.FeedByID(userID, feedID) if err != nil { return err } diff --git a/reader/opml/handler.go b/reader/opml/handler.go index 8ba27368..9d5fb0fd 100644 --- a/reader/opml/handler.go +++ b/reader/opml/handler.go @@ -21,7 +21,7 @@ type Handler struct { // Export exports user feeds to OPML. func (h *Handler) Export(userID int64) (string, error) { - feeds, err := h.store.GetFeeds(userID) + feeds, err := h.store.Feeds(userID) if err != nil { log.Println(err) return "", errors.New("unable to fetch feeds") @@ -52,13 +52,13 @@ func (h *Handler) Import(userID int64, data io.Reader) (err error) { var category *model.Category if subscription.CategoryName == "" { - category, err = h.store.GetFirstCategory(userID) + category, err = h.store.FirstCategory(userID) if err != nil { log.Println(err) return errors.New("unable to find first category") } } else { - category, err = h.store.GetCategoryByTitle(userID, subscription.CategoryName) + category, err = h.store.CategoryByTitle(userID, subscription.CategoryName) if err != nil { log.Println(err) return errors.New("unable to search category by title") diff --git a/reader/processor/processor.go b/reader/processor/processor.go index a4f4de13..ef93b9a0 100644 --- a/reader/processor/processor.go +++ b/reader/processor/processor.go @@ -9,6 +9,7 @@ import ( "github.com/miniflux/miniflux2/reader/sanitizer" ) +// ItemContentProcessor executes a set of functions to sanitize and alter item contents. func ItemContentProcessor(url, content string) string { content = sanitizer.Sanitize(url, content) return rewrite.Rewriter(url, content) diff --git a/reader/rewrite/rewriter.go b/reader/rewrite/rewriter.go index f23c0af7..d76feeee 100644 --- a/reader/rewrite/rewriter.go +++ b/reader/rewrite/rewriter.go @@ -38,6 +38,7 @@ var rewriteRules = []func(string, string) string{ }, } +// Rewriter modify item contents with a set of rewriting rules. func Rewriter(url, content string) string { for _, rewriteRule := range rewriteRules { content = rewriteRule(url, content) diff --git a/server/api/controller/category.go b/server/api/controller/category.go index bf894111..5cf88bdc 100644 --- a/server/api/controller/category.go +++ b/server/api/controller/category.go @@ -6,6 +6,7 @@ package api import ( "errors" + "github.com/miniflux/miniflux2/server/api/payload" "github.com/miniflux/miniflux2/server/core" ) @@ -65,7 +66,7 @@ func (c *Controller) UpdateCategory(ctx *core.Context, request *core.Request, re // GetCategories is the API handler to get a list of categories for a given user. func (c *Controller) GetCategories(ctx *core.Context, request *core.Request, response *core.Response) { - categories, err := c.store.GetCategories(ctx.UserID()) + categories, err := c.store.Categories(ctx.UserID()) if err != nil { response.JSON().ServerError(errors.New("Unable to fetch categories")) return diff --git a/server/api/controller/feed.go b/server/api/controller/feed.go index 282e81c1..73bf241e 100644 --- a/server/api/controller/feed.go +++ b/server/api/controller/feed.go @@ -66,7 +66,7 @@ func (c *Controller) UpdateFeed(ctx *core.Context, request *core.Request, respon return } - originalFeed, err := c.store.GetFeedById(userID, feedID) + originalFeed, err := c.store.FeedByID(userID, feedID) if err != nil { response.JSON().NotFound(errors.New("Unable to find this feed")) return @@ -88,7 +88,7 @@ func (c *Controller) UpdateFeed(ctx *core.Context, request *core.Request, respon // GetFeeds is the API handler that get all feeds that belongs to the given user. func (c *Controller) GetFeeds(ctx *core.Context, request *core.Request, response *core.Response) { - feeds, err := c.store.GetFeeds(ctx.UserID()) + feeds, err := c.store.Feeds(ctx.UserID()) if err != nil { response.JSON().ServerError(errors.New("Unable to fetch feeds from the database")) return @@ -106,7 +106,7 @@ func (c *Controller) GetFeed(ctx *core.Context, request *core.Request, response return } - feed, err := c.store.GetFeedById(userID, feedID) + feed, err := c.store.FeedByID(userID, feedID) if err != nil { response.JSON().ServerError(errors.New("Unable to fetch this feed")) return diff --git a/server/api/controller/user.go b/server/api/controller/user.go index 3ea66508..fcf24b62 100644 --- a/server/api/controller/user.go +++ b/server/api/controller/user.go @@ -6,6 +6,7 @@ package api import ( "errors" + "github.com/miniflux/miniflux2/server/api/payload" "github.com/miniflux/miniflux2/server/core" ) @@ -67,7 +68,7 @@ func (c *Controller) UpdateUser(ctx *core.Context, request *core.Request, respon return } - originalUser, err := c.store.GetUserById(userID) + originalUser, err := c.store.UserByID(userID) if err != nil { response.JSON().BadRequest(errors.New("Unable to fetch this user from the database")) return @@ -94,7 +95,7 @@ func (c *Controller) GetUsers(ctx *core.Context, request *core.Request, response return } - users, err := c.store.GetUsers() + users, err := c.store.Users() if err != nil { response.JSON().ServerError(errors.New("Unable to fetch the list of users")) return @@ -116,7 +117,7 @@ func (c *Controller) GetUser(ctx *core.Context, request *core.Request, response return } - user, err := c.store.GetUserById(userID) + user, err := c.store.UserByID(userID) if err != nil { response.JSON().BadRequest(errors.New("Unable to fetch this user from the database")) return @@ -143,7 +144,7 @@ func (c *Controller) RemoveUser(ctx *core.Context, request *core.Request, respon return } - user, err := c.store.GetUserById(userID) + user, err := c.store.UserByID(userID) if err != nil { response.JSON().ServerError(errors.New("Unable to fetch this user from the database")) return diff --git a/server/api/payload/payload.go b/server/api/payload/payload.go index 4fbc16e0..310ba050 100644 --- a/server/api/payload/payload.go +++ b/server/api/payload/payload.go @@ -12,11 +12,13 @@ import ( "github.com/miniflux/miniflux2/model" ) +// EntriesResponse represents the response sent when fetching entries. type EntriesResponse struct { Total int `json:"total"` Entries model.Entries `json:"entries"` } +// DecodeUserPayload unserialize JSON user object. func DecodeUserPayload(data io.Reader) (*model.User, error) { var user model.User @@ -28,6 +30,7 @@ func DecodeUserPayload(data io.Reader) (*model.User, error) { return &user, nil } +// DecodeURLPayload unserialize JSON subscription object. func DecodeURLPayload(data io.Reader) (string, error) { type payload struct { URL string `json:"url"` @@ -42,6 +45,7 @@ func DecodeURLPayload(data io.Reader) (string, error) { return p.URL, nil } +// DecodeEntryStatusPayload unserialize JSON entry statuses object. func DecodeEntryStatusPayload(data io.Reader) ([]int64, string, error) { type payload struct { EntryIDs []int64 `json:"entry_ids"` @@ -57,6 +61,7 @@ func DecodeEntryStatusPayload(data io.Reader) ([]int64, string, error) { return p.EntryIDs, p.Status, nil } +// DecodeFeedCreationPayload unserialize JSON feed creation object. func DecodeFeedCreationPayload(data io.Reader) (string, int64, error) { type payload struct { FeedURL string `json:"feed_url"` @@ -72,6 +77,7 @@ func DecodeFeedCreationPayload(data io.Reader) (string, int64, error) { return p.FeedURL, p.CategoryID, nil } +// DecodeFeedModificationPayload unserialize JSON feed object. func DecodeFeedModificationPayload(data io.Reader) (*model.Feed, error) { var feed model.Feed @@ -83,6 +89,7 @@ func DecodeFeedModificationPayload(data io.Reader) (*model.Feed, error) { return &feed, nil } +// DecodeCategoryPayload unserialize JSON category object. func DecodeCategoryPayload(data io.Reader) (*model.Category, error) { var category model.Category diff --git a/server/core/context.go b/server/core/context.go index 90c46594..217e4d46 100644 --- a/server/core/context.go +++ b/server/core/context.go @@ -9,6 +9,7 @@ import ( "net/http" "github.com/miniflux/miniflux2/model" + "github.com/miniflux/miniflux2/server/middleware" "github.com/miniflux/miniflux2/server/route" "github.com/miniflux/miniflux2/storage" @@ -26,7 +27,7 @@ type Context struct { // IsAdminUser checks if the logged user is administrator. func (c *Context) IsAdminUser() bool { - if v := c.request.Context().Value("IsAdminUser"); v != nil { + if v := c.request.Context().Value(middleware.IsAdminUserContextKey); v != nil { return v.(bool) } return false @@ -34,7 +35,7 @@ func (c *Context) IsAdminUser() bool { // UserTimezone returns the timezone used by the logged user. func (c *Context) UserTimezone() string { - if v := c.request.Context().Value("UserTimezone"); v != nil { + if v := c.request.Context().Value(middleware.UserTimezoneContextKey); v != nil { return v.(string) } return "UTC" @@ -42,7 +43,7 @@ func (c *Context) UserTimezone() string { // IsAuthenticated returns a boolean if the user is authenticated. func (c *Context) IsAuthenticated() bool { - if v := c.request.Context().Value("IsAuthenticated"); v != nil { + if v := c.request.Context().Value(middleware.IsAuthenticatedContextKey); v != nil { return v.(bool) } return false @@ -50,7 +51,7 @@ func (c *Context) IsAuthenticated() bool { // UserID returns the UserID of the logged user. func (c *Context) UserID() int64 { - if v := c.request.Context().Value("UserId"); v != nil { + if v := c.request.Context().Value(middleware.UserIDContextKey); v != nil { return v.(int64) } return 0 @@ -60,7 +61,7 @@ func (c *Context) UserID() int64 { func (c *Context) LoggedUser() *model.User { if c.user == nil { var err error - c.user, err = c.store.GetUserById(c.UserID()) + c.user, err = c.store.UserByID(c.UserID()) if err != nil { log.Fatalln(err) } @@ -81,7 +82,7 @@ func (c *Context) UserLanguage() string { // CsrfToken returns the current CSRF token. func (c *Context) CsrfToken() string { - if v := c.request.Context().Value("CsrfToken"); v != nil { + if v := c.request.Context().Value(middleware.CsrfContextKey); v != nil { return v.(string) } @@ -91,7 +92,7 @@ func (c *Context) CsrfToken() string { // Route returns the path for the given arguments. func (c *Context) Route(name string, args ...interface{}) string { - return route.GetRoute(c.router, name, args...) + return route.Path(c.router, name, args...) } // NewContext creates a new Context. diff --git a/server/core/handler.go b/server/core/handler.go index df7e0be7..db6204a9 100644 --- a/server/core/handler.go +++ b/server/core/handler.go @@ -27,7 +27,7 @@ type Handler struct { translator *locale.Translator template *template.Engine router *mux.Router - middleware *middleware.MiddlewareChain + middleware *middleware.Chain } // Use is a wrapper around an HTTP handler. @@ -51,7 +51,7 @@ func (h *Handler) Use(f HandlerFunc) http.Handler { } // NewHandler returns a new Handler. -func NewHandler(store *storage.Storage, router *mux.Router, template *template.Engine, translator *locale.Translator, middleware *middleware.MiddlewareChain) *Handler { +func NewHandler(store *storage.Storage, router *mux.Router, template *template.Engine, translator *locale.Translator, middleware *middleware.Chain) *Handler { return &Handler{ store: store, translator: translator, diff --git a/server/middleware/basic_auth.go b/server/middleware/basic_auth.go index 73dfb98c..3ad53181 100644 --- a/server/middleware/basic_auth.go +++ b/server/middleware/basic_auth.go @@ -6,15 +6,18 @@ package middleware import ( "context" - "github.com/miniflux/miniflux2/storage" "log" "net/http" + + "github.com/miniflux/miniflux2/storage" ) +// BasicAuthMiddleware is the middleware for HTTP Basic authentication. type BasicAuthMiddleware struct { store *storage.Storage } +// Handler executes the middleware. func (b *BasicAuthMiddleware) Handler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`) @@ -35,7 +38,7 @@ func (b *BasicAuthMiddleware) Handler(next http.Handler) http.Handler { return } - user, err := b.store.GetUserByUsername(username) + user, err := b.store.UserByUsername(username) if err != nil || user == nil { log.Println("[Middleware:BasicAuth] User not found:", username) w.WriteHeader(http.StatusUnauthorized) @@ -47,15 +50,16 @@ func (b *BasicAuthMiddleware) Handler(next http.Handler) http.Handler { b.store.SetLastLogin(user.ID) ctx := r.Context() - ctx = context.WithValue(ctx, "UserId", user.ID) - ctx = context.WithValue(ctx, "UserTimezone", user.Timezone) - ctx = context.WithValue(ctx, "IsAdminUser", user.IsAdmin) - ctx = context.WithValue(ctx, "IsAuthenticated", true) + ctx = context.WithValue(ctx, UserIDContextKey, user.ID) + ctx = context.WithValue(ctx, UserTimezoneContextKey, user.Timezone) + ctx = context.WithValue(ctx, IsAdminUserContextKey, user.IsAdmin) + ctx = context.WithValue(ctx, IsAuthenticatedContextKey, true) next.ServeHTTP(w, r.WithContext(ctx)) }) } +// NewBasicAuthMiddleware returns a new BasicAuthMiddleware. func NewBasicAuthMiddleware(s *storage.Storage) *BasicAuthMiddleware { return &BasicAuthMiddleware{store: s} } diff --git a/server/middleware/context_keys.go b/server/middleware/context_keys.go new file mode 100644 index 00000000..c011fbb6 --- /dev/null +++ b/server/middleware/context_keys.go @@ -0,0 +1,26 @@ +// Copyright 2017 Frédéric Guillot. All rights reserved. +// Use of this source code is governed by the Apache 2.0 +// license that can be found in the LICENSE file. + +package middleware + +type contextKey struct { + name string +} + +var ( + // UserIDContextKey is the context key used to store the user ID. + UserIDContextKey = &contextKey{"UserID"} + + // UserTimezoneContextKey is the context key used to store the user timezone. + UserTimezoneContextKey = &contextKey{"UserTimezone"} + + // IsAdminUserContextKey is the context key used to store the user role. + IsAdminUserContextKey = &contextKey{"IsAdminUser"} + + // IsAuthenticatedContextKey is the context key used to store the authentication flag. + IsAuthenticatedContextKey = &contextKey{"IsAuthenticated"} + + // CsrfContextKey is the context key used to store CSRF token. + CsrfContextKey = &contextKey{"CSRF"} +) diff --git a/server/middleware/csrf.go b/server/middleware/csrf.go index 74736b57..0c07e428 100644 --- a/server/middleware/csrf.go +++ b/server/middleware/csrf.go @@ -6,11 +6,13 @@ package middleware import ( "context" - "github.com/miniflux/miniflux2/helper" "log" "net/http" + + "github.com/miniflux/miniflux2/helper" ) +// Csrf is a middleware that handle CSRF tokens. func Csrf(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var csrfToken string @@ -32,7 +34,7 @@ func Csrf(next http.Handler) http.Handler { } ctx := r.Context() - ctx = context.WithValue(ctx, "CsrfToken", csrfToken) + ctx = context.WithValue(ctx, CsrfContextKey, csrfToken) w.Header().Add("Vary", "Cookie") isTokenValid := csrfToken == r.FormValue("csrf") || csrfToken == r.Header.Get("X-Csrf-Token") diff --git a/server/middleware/middleware.go b/server/middleware/middleware.go index cab01c86..9853bc36 100644 --- a/server/middleware/middleware.go +++ b/server/middleware/middleware.go @@ -8,13 +8,16 @@ import ( "net/http" ) +// Middleware represents a HTTP middleware. type Middleware func(http.Handler) http.Handler -type MiddlewareChain struct { +// Chain handles a list of middlewares. +type Chain struct { middlewares []Middleware } -func (m *MiddlewareChain) Wrap(h http.Handler) http.Handler { +// Wrap adds a HTTP handler into the chain. +func (m *Chain) Wrap(h http.Handler) http.Handler { for i := range m.middlewares { h = m.middlewares[len(m.middlewares)-1-i](h) } @@ -22,10 +25,12 @@ func (m *MiddlewareChain) Wrap(h http.Handler) http.Handler { return h } -func (m *MiddlewareChain) WrapFunc(fn http.HandlerFunc) http.Handler { +// WrapFunc adds a HTTP handler function into the chain. +func (m *Chain) WrapFunc(fn http.HandlerFunc) http.Handler { return m.Wrap(fn) } -func NewMiddlewareChain(middlewares ...Middleware) *MiddlewareChain { - return &MiddlewareChain{append(([]Middleware)(nil), middlewares...)} +// NewChain returns a new Chain. +func NewChain(middlewares ...Middleware) *Chain { + return &Chain{append(([]Middleware)(nil), middlewares...)} } diff --git a/server/middleware/session.go b/server/middleware/session.go index 1ab0d0a7..e857c1fc 100644 --- a/server/middleware/session.go +++ b/server/middleware/session.go @@ -16,11 +16,13 @@ import ( "github.com/gorilla/mux" ) +// SessionMiddleware represents a session middleware. type SessionMiddleware struct { store *storage.Storage router *mux.Router } +// Handler execute the middleware. func (s *SessionMiddleware) Handler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { session := s.getSessionFromCookie(r) @@ -30,13 +32,13 @@ func (s *SessionMiddleware) Handler(next http.Handler) http.Handler { if s.isPublicRoute(r) { next.ServeHTTP(w, r) } else { - http.Redirect(w, r, route.GetRoute(s.router, "login"), http.StatusFound) + http.Redirect(w, r, route.Path(s.router, "login"), http.StatusFound) } } else { log.Println("[Middleware:Session]", session) ctx := r.Context() - ctx = context.WithValue(ctx, "UserId", session.UserID) - ctx = context.WithValue(ctx, "IsAuthenticated", true) + ctx = context.WithValue(ctx, UserIDContextKey, session.UserID) + ctx = context.WithValue(ctx, IsAuthenticatedContextKey, true) next.ServeHTTP(w, r.WithContext(ctx)) } @@ -59,7 +61,7 @@ func (s *SessionMiddleware) getSessionFromCookie(r *http.Request) *model.Session return nil } - session, err := s.store.GetSessionByToken(sessionCookie.Value) + session, err := s.store.SessionByToken(sessionCookie.Value) if err != nil { log.Println(err) return nil @@ -68,6 +70,7 @@ func (s *SessionMiddleware) getSessionFromCookie(r *http.Request) *model.Session return session } +// NewSessionMiddleware returns a new SessionMiddleware. func NewSessionMiddleware(s *storage.Storage, r *mux.Router) *SessionMiddleware { return &SessionMiddleware{store: s, router: r} } diff --git a/server/route/route.go b/server/route/route.go index 885f0bc4..06d095aa 100644 --- a/server/route/route.go +++ b/server/route/route.go @@ -11,7 +11,8 @@ import ( "github.com/gorilla/mux" ) -func GetRoute(router *mux.Router, name string, args ...interface{}) string { +// Path returns the defined route based on given arguments. +func Path(router *mux.Router, name string, args ...interface{}) string { route := router.Get(name) if route == nil { log.Fatalln("Route not found:", name) diff --git a/server/routes.go b/server/routes.go index 8d5a5c51..8c584fa6 100644 --- a/server/routes.go +++ b/server/routes.go @@ -31,11 +31,11 @@ func getRoutes(cfg *config.Config, store *storage.Storage, feedHandler *feed.Han apiController := api_controller.NewController(store, feedHandler) uiController := ui_controller.NewController(cfg, store, pool, feedHandler, opml.NewHandler(store)) - apiHandler := core.NewHandler(store, router, templateEngine, translator, middleware.NewMiddlewareChain( + apiHandler := core.NewHandler(store, router, templateEngine, translator, middleware.NewChain( middleware.NewBasicAuthMiddleware(store).Handler, )) - uiHandler := core.NewHandler(store, router, templateEngine, translator, middleware.NewMiddlewareChain( + uiHandler := core.NewHandler(store, router, templateEngine, translator, middleware.NewChain( middleware.NewSessionMiddleware(store, router).Handler, middleware.Csrf, )) diff --git a/server/static/bin.go b/server/static/bin.go index 3a5ca069..9987f8aa 100644 --- a/server/static/bin.go +++ b/server/static/bin.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2017-11-25 10:47:30.351686806 -0800 PST m=+0.007814912 +// 2017-11-27 21:07:53.21170439 -0800 PST m=+0.005890618 package static diff --git a/server/static/css.go b/server/static/css.go index 39da75c7..2bb2f39c 100644 --- a/server/static/css.go +++ b/server/static/css.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2017-11-25 10:47:30.352812144 -0800 PST m=+0.008940250 +// 2017-11-27 21:07:53.213299146 -0800 PST m=+0.007485374 package static diff --git a/server/static/js.go b/server/static/js.go index 5076159c..9f7c717e 100644 --- a/server/static/js.go +++ b/server/static/js.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2017-11-25 10:47:30.357950671 -0800 PST m=+0.014078777 +// 2017-11-27 21:07:53.215205872 -0800 PST m=+0.009392100 package static diff --git a/server/template/common.go b/server/template/common.go index 21f91aa4..0a803b28 100644 --- a/server/template/common.go +++ b/server/template/common.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2017-11-25 10:47:30.370347794 -0800 PST m=+0.026475900 +// 2017-11-27 21:07:53.233262137 -0800 PST m=+0.027448365 package template diff --git a/server/template/template.go b/server/template/template.go index cf778b30..63a1df87 100644 --- a/server/template/template.go +++ b/server/template/template.go @@ -49,7 +49,7 @@ func (e *Engine) parseAll() { return false }, "route": func(name string, args ...interface{}) string { - return route.GetRoute(e.router, name, args...) + return route.Path(e.router, name, args...) }, "noescape": func(str string) template.HTML { return template.HTML(str) diff --git a/server/template/views.go b/server/template/views.go index 9a429a97..8254f8ca 100644 --- a/server/template/views.go +++ b/server/template/views.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2017-11-25 17:05:58.40092186 -0800 PST m=+0.019242510 +// 2017-11-27 21:07:53.218349526 -0800 PST m=+0.012535754 package template diff --git a/server/ui/controller/about.go b/server/ui/controller/about.go index 5d9a2427..0b1e4e48 100644 --- a/server/ui/controller/about.go +++ b/server/ui/controller/about.go @@ -9,6 +9,7 @@ import ( "github.com/miniflux/miniflux2/version" ) +// AboutPage shows the about page. func (c *Controller) AboutPage(ctx *core.Context, request *core.Request, response *core.Response) { args, err := c.getCommonTemplateArgs(ctx) if err != nil { diff --git a/server/ui/controller/category.go b/server/ui/controller/category.go index e8ebb032..b718d0d7 100644 --- a/server/ui/controller/category.go +++ b/server/ui/controller/category.go @@ -22,7 +22,7 @@ func (c *Controller) ShowCategories(ctx *core.Context, request *core.Request, re } user := ctx.LoggedUser() - categories, err := c.store.GetCategoriesWithFeedCount(user.ID) + categories, err := c.store.CategoriesWithFeedCount(user.ID) if err != nil { response.HTML().ServerError(err) return @@ -57,7 +57,7 @@ func (c *Controller) ShowCategoryEntries(ctx *core.Context, request *core.Reques builder.WithDirection(model.DefaultSortingDirection) builder.WithoutStatus(model.EntryStatusRemoved) builder.WithOffset(offset) - builder.WithLimit(NbItemsPerPage) + builder.WithLimit(nbItemsPerPage) entries, err := builder.GetEntries() if err != nil { @@ -110,7 +110,7 @@ func (c *Controller) SaveCategory(ctx *core.Context, request *core.Request, resp return } - duplicateCategory, err := c.store.GetCategoryByTitle(user.ID, categoryForm.Title) + duplicateCategory, err := c.store.CategoryByTitle(user.ID, categoryForm.Title) if err != nil { response.HTML().ServerError(err) return @@ -223,7 +223,7 @@ func (c *Controller) getCategoryFromURL(ctx *core.Context, request *core.Request } user := ctx.LoggedUser() - category, err := c.store.GetCategory(user.ID, categoryID) + category, err := c.store.Category(user.ID, categoryID) if err != nil { response.HTML().ServerError(err) return nil, err diff --git a/server/ui/controller/feed.go b/server/ui/controller/feed.go index 7ed903ed..85a94cf5 100644 --- a/server/ui/controller/feed.go +++ b/server/ui/controller/feed.go @@ -39,7 +39,7 @@ func (c *Controller) ShowFeedsPage(ctx *core.Context, request *core.Request, res return } - feeds, err := c.store.GetFeeds(user.ID) + feeds, err := c.store.Feeds(user.ID) if err != nil { response.HTML().ServerError(err) return @@ -74,7 +74,7 @@ func (c *Controller) ShowFeedEntries(ctx *core.Context, request *core.Request, r builder.WithOrder(model.DefaultSortingOrder) builder.WithDirection(model.DefaultSortingDirection) builder.WithOffset(offset) - builder.WithLimit(NbItemsPerPage) + builder.WithLimit(nbItemsPerPage) entries, err := builder.GetEntries() if err != nil { @@ -190,7 +190,7 @@ func (c *Controller) getFeedFromURL(request *core.Request, response *core.Respon return nil, err } - feed, err := c.store.GetFeedById(user.ID, feedID) + feed, err := c.store.FeedByID(user.ID, feedID) if err != nil { response.HTML().ServerError(err) return nil, err @@ -210,7 +210,7 @@ func (c *Controller) getFeedFormTemplateArgs(ctx *core.Context, user *model.User return nil, err } - categories, err := c.store.GetCategories(user.ID) + categories, err := c.store.Categories(user.ID) if err != nil { return nil, err } diff --git a/server/ui/controller/history.go b/server/ui/controller/history.go index 100b12f5..9b4e3163 100644 --- a/server/ui/controller/history.go +++ b/server/ui/controller/history.go @@ -25,7 +25,7 @@ func (c *Controller) ShowHistoryPage(ctx *core.Context, request *core.Request, r builder.WithOrder(model.DefaultSortingOrder) builder.WithDirection(model.DefaultSortingDirection) builder.WithOffset(offset) - builder.WithLimit(NbItemsPerPage) + builder.WithLimit(nbItemsPerPage) entries, err := builder.GetEntries() if err != nil { diff --git a/server/ui/controller/icon.go b/server/ui/controller/icon.go index 0fd85caf..4f9f2473 100644 --- a/server/ui/controller/icon.go +++ b/server/ui/controller/icon.go @@ -5,10 +5,12 @@ package controller import ( - "github.com/miniflux/miniflux2/server/core" "time" + + "github.com/miniflux/miniflux2/server/core" ) +// ShowIcon shows the feed icon. func (c *Controller) ShowIcon(ctx *core.Context, request *core.Request, response *core.Response) { iconID, err := request.IntegerParam("iconID") if err != nil { @@ -16,7 +18,7 @@ func (c *Controller) ShowIcon(ctx *core.Context, request *core.Request, response return } - icon, err := c.store.GetIconByID(iconID) + icon, err := c.store.IconByID(iconID) if err != nil { response.HTML().ServerError(err) return diff --git a/server/ui/controller/oauth2.go b/server/ui/controller/oauth2.go index c80ec71e..2ed928c6 100644 --- a/server/ui/controller/oauth2.go +++ b/server/ui/controller/oauth2.go @@ -82,7 +82,7 @@ func (c *Controller) OAuth2Callback(ctx *core.Context, request *core.Request, re return } - user, err := c.store.GetUserByExtraField(profile.Key, profile.ID) + user, err := c.store.UserByExtraField(profile.Key, profile.ID) if err != nil { response.HTML().ServerError(err) return diff --git a/server/ui/controller/opml.go b/server/ui/controller/opml.go index d4890322..ebde6226 100644 --- a/server/ui/controller/opml.go +++ b/server/ui/controller/opml.go @@ -10,6 +10,7 @@ import ( "github.com/miniflux/miniflux2/server/core" ) +// Export generates the OPML file. func (c *Controller) Export(ctx *core.Context, request *core.Request, response *core.Response) { user := ctx.LoggedUser() opml, err := c.opmlHandler.Export(user.ID) @@ -21,6 +22,7 @@ func (c *Controller) Export(ctx *core.Context, request *core.Request, response * response.XML().Download("feeds.opml", opml) } +// Import shows the import form. func (c *Controller) Import(ctx *core.Context, request *core.Request, response *core.Response) { args, err := c.getCommonTemplateArgs(ctx) if err != nil { @@ -33,6 +35,7 @@ func (c *Controller) Import(ctx *core.Context, request *core.Request, response * })) } +// UploadOPML handles OPML file importation. func (c *Controller) UploadOPML(ctx *core.Context, request *core.Request, response *core.Response) { file, fileHeader, err := request.File("file") if err != nil { diff --git a/server/ui/controller/pagination.go b/server/ui/controller/pagination.go index b649d900..1d61f74f 100644 --- a/server/ui/controller/pagination.go +++ b/server/ui/controller/pagination.go @@ -5,10 +5,10 @@ package controller const ( - NbItemsPerPage = 100 + nbItemsPerPage = 100 ) -type Pagination struct { +type pagination struct { Route string Total int Offset int @@ -19,25 +19,25 @@ type Pagination struct { PrevOffset int } -func (c *Controller) getPagination(route string, total, offset int) Pagination { +func (c *Controller) getPagination(route string, total, offset int) pagination { nextOffset := 0 prevOffset := 0 - showNext := (total - offset) > NbItemsPerPage + showNext := (total - offset) > nbItemsPerPage showPrev := offset > 0 if showNext { - nextOffset = offset + NbItemsPerPage + nextOffset = offset + nbItemsPerPage } if showPrev { - prevOffset = offset - NbItemsPerPage + prevOffset = offset - nbItemsPerPage } - return Pagination{ + return pagination{ Route: route, Total: total, Offset: offset, - ItemsPerPage: NbItemsPerPage, + ItemsPerPage: nbItemsPerPage, ShowNext: showNext, NextOffset: nextOffset, ShowPrev: showPrev, diff --git a/server/ui/controller/session.go b/server/ui/controller/session.go index fec754b6..ee0c75a9 100644 --- a/server/ui/controller/session.go +++ b/server/ui/controller/session.go @@ -5,10 +5,12 @@ package controller import ( - "github.com/miniflux/miniflux2/server/core" "log" + + "github.com/miniflux/miniflux2/server/core" ) +// ShowSessions shows the list of active sessions. func (c *Controller) ShowSessions(ctx *core.Context, request *core.Request, response *core.Response) { user := ctx.LoggedUser() args, err := c.getCommonTemplateArgs(ctx) @@ -17,7 +19,7 @@ func (c *Controller) ShowSessions(ctx *core.Context, request *core.Request, resp return } - sessions, err := c.store.GetSessions(user.ID) + sessions, err := c.store.Sessions(user.ID) if err != nil { response.HTML().ServerError(err) return @@ -31,6 +33,7 @@ func (c *Controller) ShowSessions(ctx *core.Context, request *core.Request, resp })) } +// RemoveSession remove a session. func (c *Controller) RemoveSession(ctx *core.Context, request *core.Request, response *core.Response) { user := ctx.LoggedUser() diff --git a/server/ui/controller/settings.go b/server/ui/controller/settings.go index 1bd599b6..e8ab20ba 100644 --- a/server/ui/controller/settings.go +++ b/server/ui/controller/settings.go @@ -5,13 +5,15 @@ package controller import ( + "log" + "github.com/miniflux/miniflux2/locale" "github.com/miniflux/miniflux2/model" "github.com/miniflux/miniflux2/server/core" "github.com/miniflux/miniflux2/server/ui/form" - "log" ) +// ShowSettings shows the settings page. func (c *Controller) ShowSettings(ctx *core.Context, request *core.Request, response *core.Response) { user := ctx.LoggedUser() @@ -24,6 +26,7 @@ func (c *Controller) ShowSettings(ctx *core.Context, request *core.Request, resp response.HTML().Render("settings", args) } +// UpdateSettings update the settings. func (c *Controller) UpdateSettings(ctx *core.Context, request *core.Request, response *core.Response) { user := ctx.LoggedUser() @@ -81,9 +84,9 @@ func (c *Controller) getSettingsFormTemplateArgs(ctx *core.Context, user *model. } args["menu"] = "settings" - args["themes"] = model.GetThemes() - args["languages"] = locale.GetAvailableLanguages() - args["timezones"], err = c.store.GetTimezones() + args["themes"] = model.Themes() + args["languages"] = locale.AvailableLanguages() + args["timezones"], err = c.store.Timezones() if err != nil { return args, err } diff --git a/server/ui/controller/static.go b/server/ui/controller/static.go index 822118a3..fba408cd 100644 --- a/server/ui/controller/static.go +++ b/server/ui/controller/static.go @@ -6,12 +6,14 @@ package controller import ( "encoding/base64" - "github.com/miniflux/miniflux2/server/core" - "github.com/miniflux/miniflux2/server/static" "log" "time" + + "github.com/miniflux/miniflux2/server/core" + "github.com/miniflux/miniflux2/server/static" ) +// Stylesheet renders the CSS. func (c *Controller) Stylesheet(ctx *core.Context, request *core.Request, response *core.Response) { stylesheet := request.StringParam("name", "white") body := static.Stylesheets["common"] @@ -25,10 +27,12 @@ func (c *Controller) Stylesheet(ctx *core.Context, request *core.Request, respon response.Cache("text/css", etag, []byte(body), 48*time.Hour) } +// Javascript renders application client side code. func (c *Controller) Javascript(ctx *core.Context, request *core.Request, response *core.Response) { response.Cache("text/javascript", static.JavascriptChecksums["app"], []byte(static.Javascript["app"]), 48*time.Hour) } +// Favicon renders the application favicon. func (c *Controller) Favicon(ctx *core.Context, request *core.Request, response *core.Response) { blob, err := base64.StdEncoding.DecodeString(static.Binaries["favicon.ico"]) if err != nil { diff --git a/server/ui/controller/subscription.go b/server/ui/controller/subscription.go index 342f0c55..8b0caf14 100644 --- a/server/ui/controller/subscription.go +++ b/server/ui/controller/subscription.go @@ -135,7 +135,7 @@ func (c *Controller) getSubscriptionFormTemplateArgs(ctx *core.Context, user *mo return nil, err } - categories, err := c.store.GetCategories(user.ID) + categories, err := c.store.Categories(user.ID) if err != nil { return nil, err } diff --git a/server/ui/controller/unread.go b/server/ui/controller/unread.go index 593ee38f..a114250e 100644 --- a/server/ui/controller/unread.go +++ b/server/ui/controller/unread.go @@ -19,7 +19,7 @@ func (c *Controller) ShowUnreadPage(ctx *core.Context, request *core.Request, re builder.WithOrder(model.DefaultSortingOrder) builder.WithDirection(model.DefaultSortingDirection) builder.WithOffset(offset) - builder.WithLimit(NbItemsPerPage) + builder.WithLimit(nbItemsPerPage) entries, err := builder.GetEntries() if err != nil { diff --git a/server/ui/controller/user.go b/server/ui/controller/user.go index 1590d964..0d1fbb27 100644 --- a/server/ui/controller/user.go +++ b/server/ui/controller/user.go @@ -6,12 +6,14 @@ package controller import ( "errors" + "log" + "github.com/miniflux/miniflux2/model" "github.com/miniflux/miniflux2/server/core" "github.com/miniflux/miniflux2/server/ui/form" - "log" ) +// ShowUsers shows the list of users. func (c *Controller) ShowUsers(ctx *core.Context, request *core.Request, response *core.Response) { user := ctx.LoggedUser() @@ -26,7 +28,7 @@ func (c *Controller) ShowUsers(ctx *core.Context, request *core.Request, respons return } - users, err := c.store.GetUsers() + users, err := c.store.Users() if err != nil { response.HTML().ServerError(err) return @@ -38,6 +40,7 @@ func (c *Controller) ShowUsers(ctx *core.Context, request *core.Request, respons })) } +// CreateUser shows the user creation form. func (c *Controller) CreateUser(ctx *core.Context, request *core.Request, response *core.Response) { user := ctx.LoggedUser() @@ -58,6 +61,7 @@ func (c *Controller) CreateUser(ctx *core.Context, request *core.Request, respon })) } +// SaveUser validate and save the new user into the database. func (c *Controller) SaveUser(ctx *core.Context, request *core.Request, response *core.Response) { user := ctx.LoggedUser() @@ -105,6 +109,7 @@ func (c *Controller) SaveUser(ctx *core.Context, request *core.Request, response response.Redirect(ctx.Route("users")) } +// EditUser shows the form to edit a user. func (c *Controller) EditUser(ctx *core.Context, request *core.Request, response *core.Response) { user := ctx.LoggedUser() @@ -134,6 +139,7 @@ func (c *Controller) EditUser(ctx *core.Context, request *core.Request, response })) } +// UpdateUser validate and update a user. func (c *Controller) UpdateUser(ctx *core.Context, request *core.Request, response *core.Response) { user := ctx.LoggedUser() @@ -189,6 +195,7 @@ func (c *Controller) UpdateUser(ctx *core.Context, request *core.Request, respon response.Redirect(ctx.Route("users")) } +// RemoveUser deletes a user from the database. func (c *Controller) RemoveUser(ctx *core.Context, request *core.Request, response *core.Response) { user := ctx.LoggedUser() if !user.IsAdmin { @@ -216,7 +223,7 @@ func (c *Controller) getUserFromURL(ctx *core.Context, request *core.Request, re return nil, err } - user, err := c.store.GetUserById(userID) + user, err := c.store.UserByID(userID) if err != nil { response.HTML().ServerError(err) return nil, err diff --git a/server/ui/filter/image_proxy_filter.go b/server/ui/filter/image_proxy_filter.go index 71da8691..8a775fee 100644 --- a/server/ui/filter/image_proxy_filter.go +++ b/server/ui/filter/image_proxy_filter.go @@ -6,9 +6,10 @@ package filter import ( "encoding/base64" + "strings" + "github.com/miniflux/miniflux2/reader/url" "github.com/miniflux/miniflux2/server/route" - "strings" "github.com/PuerkitoBio/goquery" "github.com/gorilla/mux" @@ -24,7 +25,7 @@ func ImageProxyFilter(r *mux.Router, data string) string { doc.Find("img").Each(func(i int, img *goquery.Selection) { if srcAttr, ok := img.Attr("src"); ok { if !url.IsHTTPS(srcAttr) { - path := route.GetRoute(r, "proxy", "encodedURL", base64.StdEncoding.EncodeToString([]byte(srcAttr))) + path := route.Path(r, "proxy", "encodedURL", base64.StdEncoding.EncodeToString([]byte(srcAttr))) img.SetAttr("src", path) } } diff --git a/server/ui/form/auth.go b/server/ui/form/auth.go index 3cfc2171..68493399 100644 --- a/server/ui/form/auth.go +++ b/server/ui/form/auth.go @@ -5,23 +5,27 @@ package form import ( - "errors" "net/http" + + "github.com/miniflux/miniflux2/errors" ) +// AuthForm represents the authentication form. type AuthForm struct { Username string Password string } +// Validate makes sure the form values are valid. func (a AuthForm) Validate() error { if a.Username == "" || a.Password == "" { - return errors.New("All fields are mandatory.") + return errors.NewLocalizedError("All fields are mandatory.") } return nil } +// NewAuthForm returns a new AuthForm. func NewAuthForm(r *http.Request) *AuthForm { return &AuthForm{ Username: r.FormValue("username"), diff --git a/server/ui/form/category.go b/server/ui/form/category.go index 510d1b43..f977b7a3 100644 --- a/server/ui/form/category.go +++ b/server/ui/form/category.go @@ -5,9 +5,10 @@ package form import ( - "errors" - "github.com/miniflux/miniflux2/model" "net/http" + + "github.com/miniflux/miniflux2/errors" + "github.com/miniflux/miniflux2/model" ) // CategoryForm represents a feed form in the UI @@ -15,18 +16,21 @@ type CategoryForm struct { Title string } +// Validate makes sure the form values are valid. func (c CategoryForm) Validate() error { if c.Title == "" { - return errors.New("The title is mandatory.") + return errors.NewLocalizedError("The title is mandatory.") } return nil } +// Merge update the given category fields. func (c CategoryForm) Merge(category *model.Category) *model.Category { category.Title = c.Title return category } +// NewCategoryForm returns a new CategoryForm. func NewCategoryForm(r *http.Request) *CategoryForm { return &CategoryForm{ Title: r.FormValue("title"), diff --git a/server/ui/form/feed.go b/server/ui/form/feed.go index e21e6ca0..8a8cf201 100644 --- a/server/ui/form/feed.go +++ b/server/ui/form/feed.go @@ -5,10 +5,11 @@ package form import ( - "errors" - "github.com/miniflux/miniflux2/model" "net/http" "strconv" + + "github.com/miniflux/miniflux2/errors" + "github.com/miniflux/miniflux2/model" ) // FeedForm represents a feed form in the UI @@ -22,11 +23,12 @@ type FeedForm struct { // ValidateModification validates FeedForm fields func (f FeedForm) ValidateModification() error { if f.FeedURL == "" || f.SiteURL == "" || f.Title == "" || f.CategoryID == 0 { - return errors.New("All fields are mandatory.") + return errors.NewLocalizedError("All fields are mandatory.") } return nil } +// Merge updates the fields of the given feed. func (f FeedForm) Merge(feed *model.Feed) *model.Feed { feed.Category.ID = f.CategoryID feed.Title = f.Title diff --git a/server/ui/form/settings.go b/server/ui/form/settings.go index 1e40b97d..3d37a0fc 100644 --- a/server/ui/form/settings.go +++ b/server/ui/form/settings.go @@ -5,11 +5,13 @@ package form import ( - "errors" - "github.com/miniflux/miniflux2/model" "net/http" + + "github.com/miniflux/miniflux2/errors" + "github.com/miniflux/miniflux2/model" ) +// SettingsForm represents the settings form. type SettingsForm struct { Username string Password string @@ -19,6 +21,7 @@ type SettingsForm struct { Timezone string } +// Merge updates the fields of the given user. func (s *SettingsForm) Merge(user *model.User) *model.User { user.Username = s.Username user.Theme = s.Theme @@ -32,24 +35,26 @@ func (s *SettingsForm) Merge(user *model.User) *model.User { return user } +// Validate makes sure the form values are valid. func (s *SettingsForm) Validate() error { if s.Username == "" || s.Theme == "" || s.Language == "" || s.Timezone == "" { - return errors.New("The username, theme, language and timezone fields are mandatory.") + return errors.NewLocalizedError("The username, theme, language and timezone fields are mandatory.") } if s.Password != "" { if s.Password != s.Confirmation { - return errors.New("Passwords are not the same.") + return errors.NewLocalizedError("Passwords are not the same.") } if len(s.Password) < 6 { - return errors.New("You must use at least 6 characters") + return errors.NewLocalizedError("You must use at least 6 characters") } } return nil } +// NewSettingsForm returns a new SettingsForm. func NewSettingsForm(r *http.Request) *SettingsForm { return &SettingsForm{ Username: r.FormValue("username"), diff --git a/server/ui/form/subscription.go b/server/ui/form/subscription.go index 6696b22f..ca1c6055 100644 --- a/server/ui/form/subscription.go +++ b/server/ui/form/subscription.go @@ -5,24 +5,28 @@ package form import ( - "errors" "net/http" "strconv" + + "github.com/miniflux/miniflux2/errors" ) +// SubscriptionForm represents the subscription form. type SubscriptionForm struct { URL string CategoryID int64 } +// Validate makes sure the form values are valid. func (s *SubscriptionForm) Validate() error { if s.URL == "" || s.CategoryID == 0 { - return errors.New("The URL and the category are mandatory.") + return errors.NewLocalizedError("The URL and the category are mandatory.") } return nil } +// NewSubscriptionForm returns a new SubscriptionForm. func NewSubscriptionForm(r *http.Request) *SubscriptionForm { categoryID, err := strconv.Atoi(r.FormValue("category_id")) if err != nil { diff --git a/server/ui/form/user.go b/server/ui/form/user.go index 1197b484..5319cb87 100644 --- a/server/ui/form/user.go +++ b/server/ui/form/user.go @@ -5,11 +5,13 @@ package form import ( - "errors" - "github.com/miniflux/miniflux2/model" "net/http" + + "github.com/miniflux/miniflux2/errors" + "github.com/miniflux/miniflux2/model" ) +// UserForm represents the user form. type UserForm struct { Username string Password string @@ -17,40 +19,43 @@ type UserForm struct { IsAdmin bool } +// ValidateCreation validates user creation. func (u UserForm) ValidateCreation() error { if u.Username == "" || u.Password == "" || u.Confirmation == "" { - return errors.New("All fields are mandatory.") + return errors.NewLocalizedError("All fields are mandatory.") } if u.Password != u.Confirmation { - return errors.New("Passwords are not the same.") + return errors.NewLocalizedError("Passwords are not the same.") } if len(u.Password) < 6 { - return errors.New("You must use at least 6 characters.") + return errors.NewLocalizedError("You must use at least 6 characters.") } return nil } +// ValidateModification validates user modification. func (u UserForm) ValidateModification() error { if u.Username == "" { - return errors.New("The username is mandatory.") + return errors.NewLocalizedError("The username is mandatory.") } if u.Password != "" { if u.Password != u.Confirmation { - return errors.New("Passwords are not the same.") + return errors.NewLocalizedError("Passwords are not the same.") } if len(u.Password) < 6 { - return errors.New("You must use at least 6 characters.") + return errors.NewLocalizedError("You must use at least 6 characters.") } } return nil } +// ToUser returns a User from the form values. func (u UserForm) ToUser() *model.User { return &model.User{ Username: u.Username, @@ -59,6 +64,7 @@ func (u UserForm) ToUser() *model.User { } } +// Merge updates the fields of the given user. func (u UserForm) Merge(user *model.User) *model.User { user.Username = u.Username user.IsAdmin = u.IsAdmin @@ -70,6 +76,7 @@ func (u UserForm) Merge(user *model.User) *model.User { return user } +// NewUserForm returns a new UserForm. func NewUserForm(r *http.Request) *UserForm { return &UserForm{ Username: r.FormValue("username"), diff --git a/server/ui/payload/payload.go b/server/ui/payload/payload.go index b2fef954..7312fb23 100644 --- a/server/ui/payload/payload.go +++ b/server/ui/payload/payload.go @@ -7,10 +7,12 @@ package payload import ( "encoding/json" "fmt" - "github.com/miniflux/miniflux2/model" "io" + + "github.com/miniflux/miniflux2/model" ) +// DecodeEntryStatusPayload unserialize JSON request to update entry statuses. func DecodeEntryStatusPayload(data io.Reader) (entryIDs []int64, status string, err error) { type payload struct { EntryIDs []int64 `json:"entry_ids"` diff --git a/sql/sql.go b/sql/sql.go index 1a3febd1..14457c08 100644 --- a/sql/sql.go +++ b/sql/sql.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2017-11-25 10:47:30.347837046 -0800 PST m=+0.003965152 +// 2017-11-27 21:07:53.208711992 -0800 PST m=+0.002898220 package sql diff --git a/storage/category.go b/storage/category.go index e1986b7f..5591a898 100644 --- a/storage/category.go +++ b/storage/category.go @@ -14,6 +14,7 @@ import ( "github.com/miniflux/miniflux2/model" ) +// AnotherCategoryExists checks if another category exists with the same title. func (s *Storage) AnotherCategoryExists(userID, categoryID int64, title string) bool { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:AnotherCategoryExists] userID=%d, categoryID=%d, title=%s", userID, categoryID, title)) @@ -23,6 +24,7 @@ func (s *Storage) AnotherCategoryExists(userID, categoryID int64, title string) return result >= 1 } +// CategoryExists checks if the given category exists into the database. func (s *Storage) CategoryExists(userID, categoryID int64) bool { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:CategoryExists] userID=%d, categoryID=%d", userID, categoryID)) @@ -32,8 +34,9 @@ func (s *Storage) CategoryExists(userID, categoryID int64) bool { return result >= 1 } -func (s *Storage) GetCategory(userID, categoryID int64) (*model.Category, error) { - defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:GetCategory] userID=%d, getCategory=%d", userID, categoryID)) +// Category returns a category from the database. +func (s *Storage) Category(userID, categoryID int64) (*model.Category, error) { + defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:Category] userID=%d, getCategory=%d", userID, categoryID)) var category model.Category query := `SELECT id, user_id, title FROM categories WHERE user_id=$1 AND id=$2` @@ -41,29 +44,31 @@ func (s *Storage) GetCategory(userID, categoryID int64) (*model.Category, error) if err == sql.ErrNoRows { return nil, nil } else if err != nil { - return nil, fmt.Errorf("Unable to fetch category: %v", err) + return nil, fmt.Errorf("unable to fetch category: %v", err) } return &category, nil } -func (s *Storage) GetFirstCategory(userID int64) (*model.Category, error) { - defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:GetFirstCategory] userID=%d", userID)) +// FirstCategory returns the first category for the given user. +func (s *Storage) FirstCategory(userID int64) (*model.Category, error) { + defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:FirstCategory] userID=%d", userID)) var category model.Category - query := `SELECT id, user_id, title FROM categories WHERE user_id=$1 ORDER BY title ASC` + query := `SELECT id, user_id, title FROM categories WHERE user_id=$1 ORDER BY title ASC LIMIT 1` err := s.db.QueryRow(query, userID).Scan(&category.ID, &category.UserID, &category.Title) if err == sql.ErrNoRows { return nil, nil } else if err != nil { - return nil, fmt.Errorf("Unable to fetch category: %v", err) + return nil, fmt.Errorf("unable to fetch category: %v", err) } return &category, nil } -func (s *Storage) GetCategoryByTitle(userID int64, title string) (*model.Category, error) { - defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:GetCategoryByTitle] userID=%d, title=%s", userID, title)) +// CategoryByTitle finds a category by the title. +func (s *Storage) CategoryByTitle(userID int64, title string) (*model.Category, error) { + defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:CategoryByTitle] userID=%d, title=%s", userID, title)) var category model.Category query := `SELECT id, user_id, title FROM categories WHERE user_id=$1 AND title=$2` @@ -77,10 +82,11 @@ func (s *Storage) GetCategoryByTitle(userID int64, title string) (*model.Categor return &category, nil } -func (s *Storage) GetCategories(userID int64) (model.Categories, error) { - defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:GetCategories] userID=%d", userID)) +// Categories returns all categories that belongs to the given user. +func (s *Storage) Categories(userID int64) (model.Categories, error) { + defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:Categories] userID=%d", userID)) - query := `SELECT id, user_id, title FROM categories WHERE user_id=$1` + query := `SELECT id, user_id, title FROM categories WHERE user_id=$1 ORDER BY title ASC` rows, err := s.db.Query(query, userID) if err != nil { return nil, fmt.Errorf("Unable to fetch categories: %v", err) @@ -100,8 +106,9 @@ func (s *Storage) GetCategories(userID int64) (model.Categories, error) { return categories, nil } -func (s *Storage) GetCategoriesWithFeedCount(userID int64) (model.Categories, error) { - defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:GetCategoriesWithFeedCount] userID=%d", userID)) +// CategoriesWithFeedCount returns all categories with the number of feeds. +func (s *Storage) CategoriesWithFeedCount(userID int64) (model.Categories, error) { + defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:CategoriesWithFeedCount] userID=%d", userID)) query := `SELECT c.id, c.user_id, c.title, (SELECT count(*) FROM feeds WHERE feeds.category_id=c.id) AS count @@ -126,6 +133,7 @@ func (s *Storage) GetCategoriesWithFeedCount(userID int64) (model.Categories, er return categories, nil } +// CreateCategory creates a new category. func (s *Storage) CreateCategory(category *model.Category) error { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:CreateCategory] title=%s", category.Title)) @@ -149,6 +157,7 @@ func (s *Storage) CreateCategory(category *model.Category) error { return nil } +// UpdateCategory updates an existing category. func (s *Storage) UpdateCategory(category *model.Category) error { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UpdateCategory] categoryID=%d", category.ID)) @@ -167,6 +176,7 @@ func (s *Storage) UpdateCategory(category *model.Category) error { return nil } +// RemoveCategory deletes a category. func (s *Storage) RemoveCategory(userID, categoryID int64) error { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:RemoveCategory] userID=%d, categoryID=%d", userID, categoryID)) diff --git a/storage/feed.go b/storage/feed.go index 4c581608..9d42664d 100644 --- a/storage/feed.go +++ b/storage/feed.go @@ -14,6 +14,7 @@ import ( "github.com/miniflux/miniflux2/model" ) +// FeedExists checks if the given feed exists. func (s *Storage) FeedExists(userID, feedID int64) bool { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:FeedExists] userID=%d, feedID=%d", userID, feedID)) @@ -23,6 +24,7 @@ func (s *Storage) FeedExists(userID, feedID int64) bool { return result >= 1 } +// FeedURLExists checks if feed URL already exists. func (s *Storage) FeedURLExists(userID int64, feedURL string) bool { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:FeedURLExists] userID=%d, feedURL=%s", userID, feedURL)) @@ -43,8 +45,9 @@ func (s *Storage) CountFeeds(userID int64) int { return result } -func (s *Storage) GetFeeds(userID int64) (model.Feeds, error) { - defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:GetFeeds] userID=%d", userID)) +// Feeds returns all feeds of the given user. +func (s *Storage) Feeds(userID int64) (model.Feeds, error) { + defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:Feeds] userID=%d", userID)) feeds := make(model.Feeds, 0) query := `SELECT @@ -109,8 +112,9 @@ func (s *Storage) GetFeeds(userID int64) (model.Feeds, error) { return feeds, nil } -func (s *Storage) GetFeedById(userID, feedID int64) (*model.Feed, error) { - defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:GetFeedById] feedID=%d", feedID)) +// FeedByID returns a feed by the ID. +func (s *Storage) FeedByID(userID, feedID int64) (*model.Feed, error) { + defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:FeedByID] feedID=%d", feedID)) var feed model.Feed feed.Category = &model.Category{UserID: userID} @@ -149,6 +153,7 @@ func (s *Storage) GetFeedById(userID, feedID int64) (*model.Feed, error) { return &feed, nil } +// CreateFeed creates a new feed. func (s *Storage) CreateFeed(feed *model.Feed) error { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:CreateFeed] feedURL=%s", feed.FeedURL)) sql := ` @@ -184,6 +189,7 @@ func (s *Storage) CreateFeed(feed *model.Feed) error { return nil } +// UpdateFeed updates an existing feed. func (s *Storage) UpdateFeed(feed *model.Feed) (err error) { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UpdateFeed] feedURL=%s", feed.FeedURL)) @@ -213,6 +219,7 @@ func (s *Storage) UpdateFeed(feed *model.Feed) (err error) { return nil } +// RemoveFeed removes a feed. func (s *Storage) RemoveFeed(userID, feedID int64) error { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:RemoveFeed] userID=%d, feedID=%d", userID, feedID)) diff --git a/storage/icon.go b/storage/icon.go index 69f96536..e021d291 100644 --- a/storage/icon.go +++ b/storage/icon.go @@ -14,6 +14,7 @@ import ( "github.com/miniflux/miniflux2/model" ) +// HasIcon checks if the given feed has an icon. func (s *Storage) HasIcon(feedID int64) bool { var result int query := `SELECT count(*) as c FROM feed_icons WHERE feed_id=$1` @@ -21,8 +22,9 @@ func (s *Storage) HasIcon(feedID int64) bool { return result == 1 } -func (s *Storage) GetIconByID(iconID int64) (*model.Icon, error) { - defer helper.ExecutionTime(time.Now(), "[Storage:GetIconByID]") +// IconByID returns an icon by the ID. +func (s *Storage) IconByID(iconID int64) (*model.Icon, error) { + defer helper.ExecutionTime(time.Now(), "[Storage:IconByID]") var icon model.Icon query := `SELECT id, hash, mime_type, content FROM icons WHERE id=$1` @@ -36,8 +38,9 @@ func (s *Storage) GetIconByID(iconID int64) (*model.Icon, error) { return &icon, nil } -func (s *Storage) GetIconByHash(icon *model.Icon) error { - defer helper.ExecutionTime(time.Now(), "[Storage:GetIconByHash]") +// IconByHash returns an icon by the hash (checksum). +func (s *Storage) IconByHash(icon *model.Icon) error { + defer helper.ExecutionTime(time.Now(), "[Storage:IconByHash]") err := s.db.QueryRow(`SELECT id FROM icons WHERE hash=$1`, icon.Hash).Scan(&icon.ID) if err == sql.ErrNoRows { @@ -49,6 +52,7 @@ func (s *Storage) GetIconByHash(icon *model.Icon) error { return nil } +// CreateIcon creates a new icon. func (s *Storage) CreateIcon(icon *model.Icon) error { defer helper.ExecutionTime(time.Now(), "[Storage:CreateIcon]") @@ -73,10 +77,11 @@ func (s *Storage) CreateIcon(icon *model.Icon) error { return nil } +// CreateFeedIcon creates an icon and associate the icon to the given feed. func (s *Storage) CreateFeedIcon(feed *model.Feed, icon *model.Icon) error { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:CreateFeedIcon] feedID=%d", feed.ID)) - err := s.GetIconByHash(icon) + err := s.IconByHash(icon) if err != nil { return err } diff --git a/storage/session.go b/storage/session.go index 296711de..719fcffd 100644 --- a/storage/session.go +++ b/storage/session.go @@ -7,11 +7,13 @@ package storage import ( "database/sql" "fmt" + "github.com/miniflux/miniflux2/helper" "github.com/miniflux/miniflux2/model" ) -func (s *Storage) GetSessions(userID int64) (model.Sessions, error) { +// Sessions returns the list of sessions for the given user. +func (s *Storage) Sessions(userID int64) (model.Sessions, error) { query := `SELECT id, user_id, token, created_at, user_agent, ip FROM sessions WHERE user_id=$1 ORDER BY id DESC` rows, err := s.db.Query(query, userID) if err != nil { @@ -41,6 +43,7 @@ func (s *Storage) GetSessions(userID int64) (model.Sessions, error) { return sessions, nil } +// CreateSession creates a new sessions. func (s *Storage) CreateSession(username, userAgent, ip string) (sessionID string, err error) { var userID int64 @@ -61,7 +64,8 @@ func (s *Storage) CreateSession(username, userAgent, ip string) (sessionID strin return token, nil } -func (s *Storage) GetSessionByToken(token string) (*model.Session, error) { +// SessionByToken finds a session by the token. +func (s *Storage) SessionByToken(token string) (*model.Session, error) { var session model.Session query := "SELECT id, user_id, token, created_at, user_agent, ip FROM sessions WHERE token = $1" @@ -83,6 +87,7 @@ func (s *Storage) GetSessionByToken(token string) (*model.Session, error) { return &session, nil } +// RemoveSessionByToken remove a session by using the token. func (s *Storage) RemoveSessionByToken(userID int64, token string) error { result, err := s.db.Exec(`DELETE FROM sessions WHERE user_id=$1 AND token=$2`, userID, token) if err != nil { @@ -101,6 +106,7 @@ func (s *Storage) RemoveSessionByToken(userID int64, token string) error { return nil } +// RemoveSessionByID remove a session by using the ID. func (s *Storage) RemoveSessionByID(userID, sessionID int64) error { result, err := s.db.Exec(`DELETE FROM sessions WHERE user_id=$1 AND id=$2`, userID, sessionID) if err != nil { @@ -119,7 +125,8 @@ func (s *Storage) RemoveSessionByID(userID, sessionID int64) error { return nil } +// FlushAllSessions removes all sessions from the database. func (s *Storage) FlushAllSessions() (err error) { - _, err = s.db.Exec(`delete from sessions`) + _, err = s.db.Exec(`DELETE FROM sessions`) return } diff --git a/storage/storage.go b/storage/storage.go index ebefe912..c815a067 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -8,19 +8,23 @@ import ( "database/sql" "log" + // Postgresql driver import _ "github.com/lib/pq" ) +// Storage handles all operations related to the database. type Storage struct { db *sql.DB } +// Close closes all database connections. func (s *Storage) Close() { s.db.Close() } -func NewStorage(databaseUrl string, maxOpenConns int) *Storage { - db, err := sql.Open("postgres", databaseUrl) +// NewStorage returns a new Storage. +func NewStorage(databaseURL string, maxOpenConns int) *Storage { + db, err := sql.Open("postgres", databaseURL) if err != nil { log.Fatalf("Unable to connect to the database: %v", err) } diff --git a/storage/timezone.go b/storage/timezone.go index 8edfc1cc..257f44fc 100644 --- a/storage/timezone.go +++ b/storage/timezone.go @@ -6,12 +6,14 @@ package storage import ( "fmt" - "github.com/miniflux/miniflux2/helper" "time" + + "github.com/miniflux/miniflux2/helper" ) -func (s *Storage) GetTimezones() (map[string]string, error) { - defer helper.ExecutionTime(time.Now(), "[Storage:GetTimezones]") +// Timezones returns all timezones supported by the database. +func (s *Storage) Timezones() (map[string]string, error) { + defer helper.ExecutionTime(time.Now(), "[Storage:Timezones]") timezones := make(map[string]string) query := `select name from pg_timezone_names() order by name asc` diff --git a/storage/user.go b/storage/user.go index d02418ed..fdbbfda5 100644 --- a/storage/user.go +++ b/storage/user.go @@ -19,6 +19,7 @@ import ( "golang.org/x/crypto/bcrypt" ) +// SetLastLogin updates the last login date of a user. func (s *Storage) SetLastLogin(userID int64) error { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:SetLastLogin] userID=%d", userID)) query := "UPDATE users SET last_login_at=now() WHERE id=$1" @@ -30,6 +31,7 @@ func (s *Storage) SetLastLogin(userID int64) error { return nil } +// UserExists checks if a user exists by using the given username. func (s *Storage) UserExists(username string) bool { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UserExists] username=%s", username)) @@ -38,6 +40,7 @@ func (s *Storage) UserExists(username string) bool { return result >= 1 } +// AnotherUserExists checks if another user exists with the given username. func (s *Storage) AnotherUserExists(userID int64, username string) bool { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:AnotherUserExists] userID=%d, username=%s", userID, username)) @@ -46,6 +49,7 @@ func (s *Storage) AnotherUserExists(userID int64, username string) bool { return result >= 1 } +// CreateUser creates a new user. func (s *Storage) CreateUser(user *model.User) (err error) { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:CreateUser] username=%s", user.Username)) password := "" @@ -84,6 +88,7 @@ func (s *Storage) CreateUser(user *model.User) (err error) { return nil } +// UpdateExtraField updates an extra field of the given user. func (s *Storage) UpdateExtraField(userID int64, field, value string) error { query := fmt.Sprintf(`UPDATE users SET extra = hstore('%s', $1) WHERE id=$2`, field) _, err := s.db.Exec(query, value, userID) @@ -93,6 +98,7 @@ func (s *Storage) UpdateExtraField(userID int64, field, value string) error { return nil } +// RemoveExtraField deletes an extra field for the given user. func (s *Storage) RemoveExtraField(userID int64, field string) error { query := `UPDATE users SET extra = delete(extra, $1) WHERE id=$2` _, err := s.db.Exec(query, field, userID) @@ -102,6 +108,7 @@ func (s *Storage) RemoveExtraField(userID int64, field string) error { return nil } +// UpdateUser updates a user. func (s *Storage) UpdateUser(user *model.User) error { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UpdateUser] username=%s", user.Username)) user.Username = strings.ToLower(user.Username) @@ -128,8 +135,9 @@ func (s *Storage) UpdateUser(user *model.User) error { return nil } -func (s *Storage) GetUserById(userID int64) (*model.User, error) { - defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:GetUserById] userID=%d", userID)) +// UserByID finds a user by the ID. +func (s *Storage) UserByID(userID int64) (*model.User, error) { + defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UserByID] userID=%d", userID)) var user model.User var extra hstore.Hstore @@ -151,8 +159,9 @@ func (s *Storage) GetUserById(userID int64) (*model.User, error) { return &user, nil } -func (s *Storage) GetUserByUsername(username string) (*model.User, error) { - defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:GetUserByUsername] username=%s", username)) +// UserByUsername finds a user by the username. +func (s *Storage) UserByUsername(username string) (*model.User, error) { + defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UserByUsername] username=%s", username)) var user model.User row := s.db.QueryRow("SELECT id, username, is_admin, theme, language, timezone FROM users WHERE username=$1", username) @@ -166,8 +175,9 @@ func (s *Storage) GetUserByUsername(username string) (*model.User, error) { return &user, nil } -func (s *Storage) GetUserByExtraField(field, value string) (*model.User, error) { - defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:GetUserByExtraField] field=%s", field)) +// UserByExtraField finds a user by an extra field value. +func (s *Storage) UserByExtraField(field, value string) (*model.User, error) { + defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UserByExtraField] field=%s", field)) var user model.User query := `SELECT id, username, is_admin, theme, language, timezone FROM users WHERE extra->$1=$2` row := s.db.QueryRow(query, field, value) @@ -181,6 +191,7 @@ func (s *Storage) GetUserByExtraField(field, value string) (*model.User, error) return &user, nil } +// RemoveUser deletes a user. func (s *Storage) RemoveUser(userID int64) error { defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:RemoveUser] userID=%d", userID)) @@ -195,14 +206,15 @@ func (s *Storage) RemoveUser(userID int64) error { } if count == 0 { - return errors.New("nothing has been removed.") + return errors.New("nothing has been removed") } return nil } -func (s *Storage) GetUsers() (model.Users, error) { - defer helper.ExecutionTime(time.Now(), "[Storage:GetUsers]") +// Users returns all users. +func (s *Storage) Users() (model.Users, error) { + defer helper.ExecutionTime(time.Now(), "[Storage:Users]") var users model.Users rows, err := s.db.Query("SELECT id, username, is_admin, theme, language, timezone, last_login_at FROM users ORDER BY username ASC") @@ -233,6 +245,7 @@ func (s *Storage) GetUsers() (model.Users, error) { return users, nil } +// CheckPassword validate the hashed password. func (s *Storage) CheckPassword(username, password string) error { defer helper.ExecutionTime(time.Now(), "[Storage:CheckPassword]") @@ -241,13 +254,13 @@ func (s *Storage) CheckPassword(username, password string) error { err := s.db.QueryRow("SELECT password FROM users WHERE username=$1", username).Scan(&hash) if err == sql.ErrNoRows { - return fmt.Errorf("Unable to find this user: %s\n", username) + return fmt.Errorf("unable to find this user: %s", username) } else if err != nil { - return fmt.Errorf("Unable to fetch user: %v\n", err) + return fmt.Errorf("unable to fetch user: %v", err) } if err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)); err != nil { - return fmt.Errorf("Invalid password for %s\n", username) + return fmt.Errorf("invalid password for %s", username) } return nil