replace errors package with fmt.Errorf
https://gist.github.com/Peltoche/60b8b81dfbf70164d0e2b88988003229 was used for it, thanks to @Peltoche for publishing it.
This commit is contained in:
committed by
Umputun
parent
21d0339d3d
commit
ba86db1263
@@ -7,8 +7,9 @@
|
||||
package accessor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/store/admin"
|
||||
)
|
||||
@@ -43,7 +44,7 @@ func (m *MemAdmin) Key(_ string) (key string, err error) {
|
||||
func (m *MemAdmin) Admins(siteID string) (ids []string, err error) {
|
||||
resp, ok := m.data[siteID]
|
||||
if !ok {
|
||||
return nil, errors.Errorf("site %s not found", siteID)
|
||||
return nil, fmt.Errorf("site %s not found", siteID)
|
||||
}
|
||||
log.Printf("[DEBUG] admins for %s, %+v", siteID, resp.IDs)
|
||||
return resp.IDs, nil
|
||||
@@ -53,7 +54,7 @@ func (m *MemAdmin) Admins(siteID string) (ids []string, err error) {
|
||||
func (m *MemAdmin) Email(siteID string) (email string, err error) {
|
||||
resp, ok := m.data[siteID]
|
||||
if !ok {
|
||||
return "", errors.Errorf("site %s not found", siteID)
|
||||
return "", fmt.Errorf("site %s not found", siteID)
|
||||
}
|
||||
|
||||
return resp.Email, nil
|
||||
@@ -63,7 +64,7 @@ func (m *MemAdmin) Email(siteID string) (email string, err error) {
|
||||
func (m *MemAdmin) Enabled(siteID string) (ok bool, err error) {
|
||||
resp, ok := m.data[siteID]
|
||||
if !ok {
|
||||
return false, errors.Errorf("site %s not found", siteID)
|
||||
return false, fmt.Errorf("site %s not found", siteID)
|
||||
}
|
||||
return resp.Enabled, nil
|
||||
}
|
||||
@@ -72,7 +73,7 @@ func (m *MemAdmin) Enabled(siteID string) (ok bool, err error) {
|
||||
func (m *MemAdmin) OnEvent(siteID string, ev admin.EventType) error {
|
||||
resp, ok := m.data[siteID]
|
||||
if !ok {
|
||||
return errors.Errorf("site %s not found", siteID)
|
||||
return fmt.Errorf("site %s not found", siteID)
|
||||
}
|
||||
if ev == admin.EvCreate {
|
||||
resp.CountCreated++ // not a good idea, just for demo
|
||||
|
||||
@@ -7,13 +7,12 @@
|
||||
package accessor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/store"
|
||||
"github.com/umputun/remark42/backend/app/store/engine"
|
||||
)
|
||||
@@ -58,7 +57,7 @@ func NewMemData() *MemData {
|
||||
func (m *MemData) Create(comment store.Comment) (commentID string, err error) {
|
||||
|
||||
if ro, e := m.Flag(engine.FlagRequest{Flag: engine.ReadOnly, Locator: comment.Locator}); e == nil && ro {
|
||||
return "", errors.Errorf("post %s is read-only", comment.Locator.URL)
|
||||
return "", fmt.Errorf("post %s is read-only", comment.Locator.URL)
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
@@ -66,7 +65,7 @@ func (m *MemData) Create(comment store.Comment) (commentID string, err error) {
|
||||
comments := m.posts[comment.Locator.SiteID]
|
||||
for _, c := range comments { // don't allow duplicated IDs
|
||||
if c.ID == comment.ID {
|
||||
return "", errors.New("dup key")
|
||||
return "", fmt.Errorf("dup key")
|
||||
}
|
||||
}
|
||||
comments = append(comments, comment)
|
||||
@@ -161,7 +160,7 @@ func (m *MemData) Count(req engine.FindRequest) (count int, err error) {
|
||||
})
|
||||
return len(comments), nil
|
||||
default:
|
||||
return 0, errors.Errorf("invalid count request %+v", req)
|
||||
return 0, fmt.Errorf("invalid count request %+v", req)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +175,7 @@ func (m *MemData) Info(req engine.InfoRequest) (res []store.PostInfo, err error)
|
||||
return c.Locator == req.Locator
|
||||
})
|
||||
if len(comments) == 0 {
|
||||
return nil, errors.New("not found")
|
||||
return nil, fmt.Errorf("not found")
|
||||
}
|
||||
info := store.PostInfo{
|
||||
URL: req.Locator.URL,
|
||||
@@ -235,7 +234,7 @@ func (m *MemData) Info(req engine.InfoRequest) (res []store.PostInfo, err error)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
return nil, errors.Errorf("invalid info request %+v", req)
|
||||
return nil, fmt.Errorf("invalid info request %+v", req)
|
||||
}
|
||||
|
||||
// Flag sets and gets flag values
|
||||
@@ -277,7 +276,7 @@ func (m *MemData) ListFlags(req engine.FlagRequest) (res []interface{}, err erro
|
||||
return res, nil
|
||||
}
|
||||
|
||||
return nil, errors.Errorf("flag %s not listable", req.Flag)
|
||||
return nil, fmt.Errorf("flag %s not listable", req.Flag)
|
||||
}
|
||||
|
||||
// UserDetail sets or gets single detail value, or gets all details fo§r requested site.
|
||||
@@ -287,7 +286,7 @@ func (m *MemData) UserDetail(req engine.UserDetailRequest) ([]engine.UserDetailE
|
||||
switch req.Detail {
|
||||
case engine.UserEmail, engine.UserTelegram:
|
||||
if req.UserID == "" {
|
||||
return nil, errors.New("userid cannot be empty in request for single detail")
|
||||
return nil, fmt.Errorf("userid cannot be empty in request for single detail")
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
@@ -306,9 +305,9 @@ func (m *MemData) UserDetail(req engine.UserDetailRequest) ([]engine.UserDetailE
|
||||
defer m.mu.Unlock()
|
||||
return m.listDetails(req.Locator)
|
||||
}
|
||||
return nil, errors.New("unsupported request with userdetail all")
|
||||
return nil, fmt.Errorf("unsupported request with userdetail all")
|
||||
default:
|
||||
return nil, errors.Errorf("unsupported detail %q", req.Detail)
|
||||
return nil, fmt.Errorf("unsupported detail %q", req.Detail)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,13 +336,13 @@ func (m *MemData) Delete(req engine.DeleteRequest) error {
|
||||
|
||||
case req.Locator.SiteID != "" && req.Locator.URL == "" && req.CommentID == "" && req.UserID == "" && req.UserDetail == "": // delete site
|
||||
if _, ok := m.posts[req.Locator.SiteID]; !ok {
|
||||
return errors.New("not found")
|
||||
return fmt.Errorf("not found")
|
||||
}
|
||||
m.posts[req.Locator.SiteID] = []store.Comment{}
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.Errorf("invalid delete request %+v", req)
|
||||
return fmt.Errorf("invalid delete request %+v", req)
|
||||
}
|
||||
|
||||
func (m *MemData) deleteComment(loc store.Locator, id string, mode store.DeleteMode) error {
|
||||
@@ -352,7 +351,7 @@ func (m *MemData) deleteComment(loc store.Locator, id string, mode store.DeleteM
|
||||
return c.Locator == loc && c.ID == id
|
||||
})
|
||||
if len(comments) == 0 {
|
||||
return errors.New("not found")
|
||||
return fmt.Errorf("not found")
|
||||
}
|
||||
|
||||
comments[0].SetDeleted(mode)
|
||||
@@ -430,7 +429,10 @@ func (m *MemData) setFlag(req engine.FlagRequest) (res bool, err error) {
|
||||
info.ReadOnly = status
|
||||
m.metaPosts[req.Locator] = info
|
||||
}
|
||||
return status, errors.Wrapf(err, "failed to set flag %+v", req)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to set flag %+v: %w", req, err)
|
||||
}
|
||||
return status, nil
|
||||
}
|
||||
|
||||
// getUserDetail returns UserDetailEntry with requested userDetail (omitting other details)
|
||||
@@ -535,7 +537,7 @@ func (m *MemData) get(loc store.Locator, commentID string) (store.Comment, error
|
||||
return c.Locator == loc && c.ID == commentID
|
||||
})
|
||||
if len(comments) == 0 {
|
||||
return store.Comment{}, errors.New("not found")
|
||||
return store.Comment{}, fmt.Errorf("not found")
|
||||
}
|
||||
return comments[0], nil
|
||||
}
|
||||
@@ -557,7 +559,7 @@ func (m *MemData) updateComment(comment store.Comment) error {
|
||||
m.posts[comment.Locator.SiteID] = comments
|
||||
return nil
|
||||
}
|
||||
return errors.New("not found")
|
||||
return fmt.Errorf("not found")
|
||||
}
|
||||
|
||||
func (m *MemData) match(comments []store.Comment, fn func(c store.Comment) bool) (res []store.Comment) {
|
||||
|
||||
@@ -8,11 +8,11 @@ package accessor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/store/image"
|
||||
)
|
||||
@@ -53,7 +53,7 @@ func (m *MemImage) ResetCleanupTimer(id string) error {
|
||||
m.insertTime[id] = time.Now()
|
||||
return nil
|
||||
}
|
||||
return errors.Errorf("image %s not found", id)
|
||||
return fmt.Errorf("image %s not found", id)
|
||||
}
|
||||
|
||||
// Load image by ID
|
||||
@@ -65,7 +65,7 @@ func (m *MemImage) Load(id string) ([]byte, error) {
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
if !ok {
|
||||
return nil, errors.Errorf("image %s not found", id)
|
||||
return nil, fmt.Errorf("image %s not found", id)
|
||||
}
|
||||
return img, nil
|
||||
}
|
||||
@@ -76,7 +76,7 @@ func (m *MemImage) Commit(id string) error {
|
||||
img, ok := m.imagesStaging[id]
|
||||
m.mu.RUnlock()
|
||||
if !ok {
|
||||
return errors.Errorf("failed to commit %s, not found in staging", id)
|
||||
return fmt.Errorf("failed to commit %s, not found in staging", id)
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
|
||||
@@ -6,7 +6,6 @@ require (
|
||||
github.com/go-pkgz/jrpc v0.2.0
|
||||
github.com/go-pkgz/lgr v0.10.4
|
||||
github.com/jessevdk/go-flags v1.5.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/umputun/remark42/backend v1.9.0
|
||||
)
|
||||
@@ -29,6 +28,7 @@ require (
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/microcosm-cc/bluemonday v1.0.18 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rs/xid v1.4.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
|
||||
"github.com/go-pkgz/auth/avatar"
|
||||
@@ -39,12 +39,12 @@ func (ac *AvatarCommand) Execute(_ []string) error {
|
||||
|
||||
src, err := ac.makeAvatarStore(ac.AvatarSrc)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "can't make avatart store for %s", ac.AvatarSrc.Type)
|
||||
return fmt.Errorf("can't make avatart store for %s: %w", ac.AvatarSrc.Type, err)
|
||||
}
|
||||
|
||||
dst, err := ac.makeAvatarStore(ac.AvatarDst)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "can't make avatart store for %s", ac.AvatarDst.Type)
|
||||
return fmt.Errorf("can't make avatart store for %s: %w", ac.AvatarDst.Type, err)
|
||||
}
|
||||
|
||||
if ac.migrator == nil {
|
||||
@@ -72,14 +72,14 @@ func (ac *AvatarCommand) makeAvatarStore(gr AvatarGroup) (avatar.Store, error) {
|
||||
switch gr.Type {
|
||||
case "fs":
|
||||
if err := makeDirs(gr.FS.Path); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create avatar store")
|
||||
return nil, fmt.Errorf("failed to create avatar store: %w", err)
|
||||
}
|
||||
return avatar.NewLocalFS(gr.FS.Path), nil
|
||||
case "bolt":
|
||||
if err := makeDirs(path.Dir(gr.Bolt.File)); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create avatar store")
|
||||
return nil, fmt.Errorf("failed to create avatar store: %w", err)
|
||||
}
|
||||
return avatar.NewBoltDB(gr.Bolt.File, bolt.Options{})
|
||||
}
|
||||
return nil, errors.Errorf("unsupported avatar store type %s", gr.Type)
|
||||
return nil, fmt.Errorf("unsupported avatar store type %s", gr.Type)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
@@ -25,7 +25,7 @@ func TestAvatar_Execute(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
// failed
|
||||
cmd = AvatarCommand{migrator: &avatarMigratorMock{retCount: 0, retError: errors.New("failed blah")}}
|
||||
cmd = AvatarCommand{migrator: &avatarMigratorMock{retCount: 0, retError: fmt.Errorf("failed blah")}}
|
||||
cmd.SetCommon(CommonOpts{RemarkURL: "", SharedSecret: "123456"})
|
||||
p = flags.NewParser(&cmd, flags.Default)
|
||||
_, err = p.ParseArgs([]string{"--src.type=fs", "--src.fs.path=/tmp/ava-test", "--dst.type=bolt",
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"time"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// BackupCommand set of flags and command for export
|
||||
@@ -43,14 +42,14 @@ func (ec *BackupCommand) Execute(_ []string) error {
|
||||
exportURL := fmt.Sprintf("%s/api/v1/admin/export?mode=file&site=%s", ec.RemarkURL, ec.Site)
|
||||
req, err := http.NewRequest(http.MethodGet, exportURL, http.NoBody)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "can't make export request for %s", exportURL)
|
||||
return fmt.Errorf("can't make export request for %s: %w", exportURL, err)
|
||||
}
|
||||
req.SetBasicAuth("admin", ec.AdminPasswd)
|
||||
|
||||
// get with timeout
|
||||
resp, err := client.Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "request failed for %s", exportURL)
|
||||
return fmt.Errorf("request failed for %s: %w", exportURL, err)
|
||||
}
|
||||
defer func() {
|
||||
if err = resp.Body.Close(); err != nil {
|
||||
@@ -64,7 +63,7 @@ func (ec *BackupCommand) Execute(_ []string) error {
|
||||
|
||||
fh, err := os.Create(fname) //nolint:gosec // harmless
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "can't create backup file %s", fname)
|
||||
return fmt.Errorf("can't create backup file %s: %w", fname, err)
|
||||
}
|
||||
defer func() { //nolint:gosec // false positive on defer without error check when it's checked here
|
||||
if err = fh.Close(); err != nil {
|
||||
@@ -73,7 +72,7 @@ func (ec *BackupCommand) Execute(_ []string) error {
|
||||
}()
|
||||
|
||||
if _, err = io.Copy(fh, resp.Body); err != nil {
|
||||
return errors.Wrapf(err, "failed to write backup file %s", fname)
|
||||
return fmt.Errorf("failed to write backup file %s: %w", fname, err)
|
||||
}
|
||||
|
||||
log.Printf("[INFO] export completed, file %s", fname)
|
||||
|
||||
+16
-17
@@ -9,7 +9,6 @@ import (
|
||||
"time"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/store"
|
||||
)
|
||||
@@ -39,7 +38,7 @@ func (cc *CleanupCommand) Execute(_ []string) error {
|
||||
|
||||
posts, err := cc.postsInRange(cc.From, cc.To)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "can't get posts")
|
||||
return fmt.Errorf("can't get posts: %w", err)
|
||||
}
|
||||
log.Printf("[DEBUG] got %d posts", len(posts))
|
||||
|
||||
@@ -99,7 +98,7 @@ func (cc *CleanupCommand) procTitles(comments []store.Comment) {
|
||||
func (cc *CleanupCommand) postsInRange(fromS, toS string) ([]store.PostInfo, error) {
|
||||
posts, err := cc.listPosts()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't list posts for %s", cc.Site)
|
||||
return nil, fmt.Errorf("can't list posts for %s: %w", cc.Site, err)
|
||||
}
|
||||
|
||||
from, to := defaultFrom, defaultTo
|
||||
@@ -107,14 +106,14 @@ func (cc *CleanupCommand) postsInRange(fromS, toS string) ([]store.PostInfo, err
|
||||
if fromS != "" {
|
||||
from, err = time.ParseInLocation("20060102", fromS, time.Local)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't parse --from")
|
||||
return nil, fmt.Errorf("can't parse --from: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if toS != "" {
|
||||
to, err = time.ParseInLocation("20060102", toS, time.Local)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't parse --to")
|
||||
return nil, fmt.Errorf("can't parse --to: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,17 +132,17 @@ func (cc *CleanupCommand) listPosts() ([]store.PostInfo, error) {
|
||||
client := http.Client{Timeout: 30 * time.Second}
|
||||
r, err := client.Get(listURL)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "get request failed for list of posts, site %s", cc.Site)
|
||||
return nil, fmt.Errorf("get request failed for list of posts, site %s: %w", cc.Site, err)
|
||||
}
|
||||
defer func() { _ = r.Body.Close() }()
|
||||
|
||||
if r.StatusCode != 200 {
|
||||
return nil, errors.Errorf("request %s failed with status %d", listURL, r.StatusCode)
|
||||
return nil, fmt.Errorf("request %s failed with status %d", listURL, r.StatusCode)
|
||||
}
|
||||
|
||||
list := []store.PostInfo{}
|
||||
if err = json.NewDecoder(r.Body).Decode(&list); err != nil {
|
||||
return nil, errors.Wrapf(err, "can't decode list of posts for site %s", cc.Site)
|
||||
return nil, fmt.Errorf("can't decode list of posts for site %s: %w", cc.Site, err)
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
@@ -160,7 +159,7 @@ func (cc *CleanupCommand) listComments(postURL string) ([]store.Comment, error)
|
||||
client := http.Client{Timeout: 30 * time.Second}
|
||||
r, err = client.Get(commentsURL)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "get request failed for comments, %s", postURL)
|
||||
return nil, fmt.Errorf("get request failed for comments, %s: %w", postURL, err)
|
||||
}
|
||||
if r.StatusCode == http.StatusTooManyRequests {
|
||||
_ = r.Body.Close()
|
||||
@@ -173,7 +172,7 @@ func (cc *CleanupCommand) listComments(postURL string) ([]store.Comment, error)
|
||||
defer func() { _ = r.Body.Close() }()
|
||||
|
||||
if r.StatusCode != http.StatusOK {
|
||||
return nil, errors.Errorf("request %s failed with status %d", commentsURL, r.StatusCode)
|
||||
return nil, fmt.Errorf("request %s failed with status %d", commentsURL, r.StatusCode)
|
||||
}
|
||||
|
||||
commentsWithInfo := struct {
|
||||
@@ -182,7 +181,7 @@ func (cc *CleanupCommand) listComments(postURL string) ([]store.Comment, error)
|
||||
}{}
|
||||
|
||||
if err = json.NewDecoder(r.Body).Decode(&commentsWithInfo); err != nil {
|
||||
return nil, errors.Wrapf(err, "can't decode list of comments for %s", postURL)
|
||||
return nil, fmt.Errorf("can't decode list of comments for %s: %w", postURL, err)
|
||||
}
|
||||
return commentsWithInfo.Comments, nil
|
||||
}
|
||||
@@ -192,18 +191,18 @@ func (cc *CleanupCommand) deleteComment(c store.Comment) error {
|
||||
deleteURL := fmt.Sprintf("%s/api/v1/admin/comment/%s?site=%s&url=%s&format=plain", cc.RemarkURL, c.ID, cc.Site, c.Locator.URL)
|
||||
req, err := http.NewRequest("DELETE", deleteURL, http.NoBody)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to make delete request for comment %s, %s", c.ID, c.Locator.URL)
|
||||
return fmt.Errorf("failed to make delete request for comment %s, %s: %w", c.ID, c.Locator.URL, err)
|
||||
}
|
||||
req.SetBasicAuth("admin", cc.AdminPasswd)
|
||||
|
||||
client := http.Client{}
|
||||
r, err := client.Do(req)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "delete request failed for comment %s, %s", c.ID, c.Locator.URL)
|
||||
return fmt.Errorf("delete request failed for comment %s, %s: %w", c.ID, c.Locator.URL, err)
|
||||
}
|
||||
defer func() { _ = r.Body.Close() }()
|
||||
if r.StatusCode != http.StatusOK {
|
||||
return errors.Errorf("delete request failed with status %s", r.Status)
|
||||
return fmt.Errorf("delete request failed with status %s", r.Status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -213,18 +212,18 @@ func (cc *CleanupCommand) setTitle(c store.Comment) error {
|
||||
titleURL := fmt.Sprintf("%s/api/v1/admin/title/%s?site=%s&url=%s&format=plain", cc.RemarkURL, c.ID, cc.Site, c.Locator.URL)
|
||||
req, err := http.NewRequest("PUT", titleURL, http.NoBody)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to make title request for comment %s, %s", c.ID, c.Locator.URL)
|
||||
return fmt.Errorf("failed to make title request for comment %s, %s: %w", c.ID, c.Locator.URL, err)
|
||||
}
|
||||
req.SetBasicAuth("admin", cc.AdminPasswd)
|
||||
|
||||
client := http.Client{}
|
||||
r, err := client.Do(req)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "title request failed for comment %s, %s", c.ID, c.Locator.URL)
|
||||
return fmt.Errorf("title request failed for comment %s, %s: %w", c.ID, c.Locator.URL, err)
|
||||
}
|
||||
defer func() { _ = r.Body.Close() }()
|
||||
if r.StatusCode != http.StatusOK {
|
||||
return errors.Errorf("title request failed with status %s", r.Status)
|
||||
return fmt.Errorf("title request failed with status %s", r.Status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -13,7 +14,6 @@ import (
|
||||
"time"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// CommonOptionsCommander extends flags.Commander with SetCommon
|
||||
@@ -87,7 +87,7 @@ func (p *fileParser) parse(now time.Time) (string, error) {
|
||||
}
|
||||
|
||||
if err := template.Must(template.New("bb").Parse(fname)).Execute(&bb, fileTemplate); err != nil {
|
||||
return "", errors.Wrapf(err, "failed to parse %q", fname)
|
||||
return "", fmt.Errorf("failed to parse %q: %w", fname, err)
|
||||
}
|
||||
return bb.String(), nil
|
||||
}
|
||||
@@ -107,14 +107,14 @@ func responseError(resp *http.Response) error {
|
||||
if e != nil {
|
||||
body = []byte("")
|
||||
}
|
||||
return errors.Errorf("error response %q, %s", resp.Status, body)
|
||||
return fmt.Errorf("error response %q, %s", resp.Status, body)
|
||||
}
|
||||
|
||||
// mkdir -p for all dirs
|
||||
func makeDirs(dirs ...string) error {
|
||||
for _, dir := range dirs {
|
||||
if err := os.MkdirAll(dir, 0o700); err != nil { // If path is already a directory, MkdirAll does nothing
|
||||
return errors.Wrapf(err, "can't make directory %s", dir)
|
||||
return fmt.Errorf("can't make directory %s: %w", dir, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"time"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ImportCommand set of flags and command for import
|
||||
@@ -31,7 +30,7 @@ func (ic *ImportCommand) Execute(_ []string) error {
|
||||
|
||||
reader, err := ic.reader(ic.InputFile)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "can't open import file %s", ic.InputFile)
|
||||
return fmt.Errorf("can't open import file %s: %w", ic.InputFile, err)
|
||||
}
|
||||
|
||||
client := http.Client{}
|
||||
@@ -40,13 +39,13 @@ func (ic *ImportCommand) Execute(_ []string) error {
|
||||
importURL := fmt.Sprintf("%s/api/v1/admin/import?site=%s&provider=%s", ic.RemarkURL, ic.Site, ic.Provider)
|
||||
req, err := http.NewRequest(http.MethodPost, importURL, reader)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "can't make import request for %s", importURL)
|
||||
return fmt.Errorf("can't make import request for %s: %w", importURL, err)
|
||||
}
|
||||
req.SetBasicAuth("admin", ic.AdminPasswd)
|
||||
|
||||
resp, err := client.Do(req.WithContext(ctx)) // closes request's reader
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "request failed for %s", importURL)
|
||||
return fmt.Errorf("request failed for %s: %w", importURL, err)
|
||||
}
|
||||
defer func() {
|
||||
if err = resp.Body.Close(); err != nil {
|
||||
@@ -59,7 +58,7 @@ func (ic *ImportCommand) Execute(_ []string) error {
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "can't get response from importer")
|
||||
return fmt.Errorf("can't get response from importer: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("[INFO] completed, status=%d, %s", resp.StatusCode, string(body))
|
||||
@@ -70,13 +69,13 @@ func (ic *ImportCommand) Execute(_ []string) error {
|
||||
func (ic *ImportCommand) reader(inp string) (reader io.Reader, err error) {
|
||||
inpFile, err := os.Open(inp) // nolint
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "import failed, can't open %s", inp)
|
||||
return nil, fmt.Errorf("import failed, can't open %s: %w", inp, err)
|
||||
}
|
||||
|
||||
reader = inpFile
|
||||
if strings.HasSuffix(ic.InputFile, ".gz") {
|
||||
if reader, err = gzip.NewReader(inpFile); err != nil {
|
||||
return nil, errors.Wrap(err, "can't make gz reader")
|
||||
return nil, fmt.Errorf("can't make gz reader: %w", err)
|
||||
}
|
||||
}
|
||||
return reader, nil
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"time"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// RemapCommand set of flags and command for change linkage between comments to
|
||||
@@ -29,7 +28,7 @@ func (rc *RemapCommand) Execute(_ []string) error {
|
||||
|
||||
rulesReader, err := os.Open(rc.InputFile)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cant open file %s", rc.InputFile)
|
||||
return fmt.Errorf("cant open file %s: %w", rc.InputFile, err)
|
||||
}
|
||||
|
||||
client := http.Client{}
|
||||
@@ -38,13 +37,13 @@ func (rc *RemapCommand) Execute(_ []string) error {
|
||||
remapURL := fmt.Sprintf("%s/api/v1/admin/remap?site=%s", rc.RemarkURL, rc.Site)
|
||||
req, err := http.NewRequest(http.MethodPost, remapURL, rulesReader)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "can't make remap request for %s", remapURL)
|
||||
return fmt.Errorf("can't make remap request for %s: %w", remapURL, err)
|
||||
}
|
||||
req.SetBasicAuth("admin", rc.AdminPasswd)
|
||||
|
||||
resp, err := client.Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "request failed for %s", remapURL)
|
||||
return fmt.Errorf("request failed for %s: %w", remapURL, err)
|
||||
}
|
||||
defer func() {
|
||||
if err = resp.Body.Close(); err != nil {
|
||||
@@ -57,7 +56,7 @@ func (rc *RemapCommand) Execute(_ []string) error {
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "can't get response")
|
||||
return fmt.Errorf("can't get response: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("[INFO] completed, status=%d, %s", resp.StatusCode, string(body))
|
||||
|
||||
+35
-33
@@ -18,7 +18,6 @@ import (
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/golang-jwt/jwt"
|
||||
"github.com/kyokomi/emoji/v2"
|
||||
"github.com/pkg/errors"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
|
||||
"github.com/go-pkgz/auth"
|
||||
@@ -450,27 +449,27 @@ func contains(s string, a []string) bool {
|
||||
// doesn't start anything
|
||||
func (s *ServerCommand) newServerApp(ctx context.Context) (*serverApp, error) {
|
||||
if err := makeDirs(s.BackupLocation); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create backup store")
|
||||
return nil, fmt.Errorf("failed to create backup store: %w", err)
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(s.RemarkURL, "http://") && !strings.HasPrefix(s.RemarkURL, "https://") {
|
||||
return nil, errors.Errorf("invalid remark42 url %s", s.RemarkURL)
|
||||
return nil, fmt.Errorf("invalid remark42 url %s", s.RemarkURL)
|
||||
}
|
||||
log.Printf("[INFO] root url=%s", s.RemarkURL)
|
||||
|
||||
storeEngine, err := s.makeDataStore()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to make data store engine")
|
||||
return nil, fmt.Errorf("failed to make data store engine: %w", err)
|
||||
}
|
||||
|
||||
adminStore, err := s.makeAdminStore()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to make admin store")
|
||||
return nil, fmt.Errorf("failed to make admin store: %w", err)
|
||||
}
|
||||
|
||||
imageService, err := s.makePicturesStore()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to make pictures store")
|
||||
return nil, fmt.Errorf("failed to make pictures store: %w", err)
|
||||
}
|
||||
log.Printf("[DEBUG] image service for url=%s, EditDuration=%v", imageService.ImageAPI, imageService.EditDuration)
|
||||
|
||||
@@ -492,13 +491,13 @@ func (s *ServerCommand) newServerApp(ctx context.Context) (*serverApp, error) {
|
||||
loadingCache, err := s.makeCache()
|
||||
if err != nil {
|
||||
_ = dataService.Close()
|
||||
return nil, errors.Wrap(err, "failed to make cache")
|
||||
return nil, fmt.Errorf("failed to make cache: %w", err)
|
||||
}
|
||||
|
||||
avatarStore, err := s.makeAvatarStore()
|
||||
if err != nil {
|
||||
_ = dataService.Close()
|
||||
return nil, errors.Wrap(err, "failed to make avatar store")
|
||||
return nil, fmt.Errorf("failed to make avatar store: %w", err)
|
||||
}
|
||||
authRefreshCache := newAuthRefreshCache()
|
||||
authenticator := s.getAuthenticator(dataService, avatarStore, adminStore, authRefreshCache)
|
||||
@@ -509,7 +508,7 @@ func (s *ServerCommand) newServerApp(ctx context.Context) (*serverApp, error) {
|
||||
err = s.addAuthProviders(authenticator)
|
||||
if err != nil {
|
||||
_ = dataService.Close()
|
||||
return nil, errors.Wrap(err, "failed to make authenticator")
|
||||
return nil, fmt.Errorf("failed to make authenticator: %w", err)
|
||||
}
|
||||
|
||||
exporter := &migrator.Native{DataStore: dataService}
|
||||
@@ -548,7 +547,7 @@ func (s *ServerCommand) newServerApp(ctx context.Context) (*serverApp, error) {
|
||||
sslConfig, err := s.makeSSLConfig()
|
||||
if err != nil {
|
||||
_ = dataService.Close()
|
||||
return nil, errors.Wrap(err, "failed to make config of ssl server params")
|
||||
return nil, fmt.Errorf("failed to make config of ssl server params: %w", err)
|
||||
}
|
||||
|
||||
srv := &api.Rest{
|
||||
@@ -587,7 +586,7 @@ func (s *ServerCommand) newServerApp(ctx context.Context) (*serverApp, error) {
|
||||
da, errDevAuth := authenticator.DevAuth()
|
||||
if errDevAuth != nil {
|
||||
_ = dataService.Close()
|
||||
return nil, errors.Wrap(errDevAuth, "can't make dev oauth2 server")
|
||||
return nil, fmt.Errorf("can't make dev oauth2 server: %w", errDevAuth)
|
||||
}
|
||||
devAuth = da
|
||||
}
|
||||
@@ -687,7 +686,7 @@ func (s *ServerCommand) makeDataStore() (result engine.Interface, err error) {
|
||||
switch s.Store.Type {
|
||||
case "bolt":
|
||||
if err = makeDirs(s.Store.Bolt.Path); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create bolt store")
|
||||
return nil, fmt.Errorf("failed to create bolt store: %w", err)
|
||||
}
|
||||
sites := []engine.BoltSite{}
|
||||
for _, site := range s.Sites {
|
||||
@@ -703,9 +702,12 @@ func (s *ServerCommand) makeDataStore() (result engine.Interface, err error) {
|
||||
}}
|
||||
return r, nil
|
||||
default:
|
||||
return nil, errors.Errorf("unsupported store type %s", s.Store.Type)
|
||||
return nil, fmt.Errorf("unsupported store type %s", s.Store.Type)
|
||||
}
|
||||
return result, errors.Wrap(err, "can't initialize data store")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't initialize data store: %w", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *ServerCommand) makeAvatarStore() (avatar.Store, error) {
|
||||
@@ -714,18 +716,18 @@ func (s *ServerCommand) makeAvatarStore() (avatar.Store, error) {
|
||||
switch s.Avatar.Type {
|
||||
case "fs":
|
||||
if err := makeDirs(s.Avatar.FS.Path); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create avatar store")
|
||||
return nil, fmt.Errorf("failed to create avatar store: %w", err)
|
||||
}
|
||||
return avatar.NewLocalFS(s.Avatar.FS.Path), nil
|
||||
case "bolt":
|
||||
if err := makeDirs(path.Dir(s.Avatar.Bolt.File)); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create avatar store")
|
||||
return nil, fmt.Errorf("failed to create avatar store: %w", err)
|
||||
}
|
||||
return avatar.NewBoltDB(s.Avatar.Bolt.File, bolt.Options{})
|
||||
case "uri":
|
||||
return avatar.NewStore(s.Avatar.URI)
|
||||
}
|
||||
return nil, errors.Errorf("unsupported avatar store type %s", s.Avatar.Type)
|
||||
return nil, fmt.Errorf("unsupported avatar store type %s", s.Avatar.Type)
|
||||
}
|
||||
|
||||
func (s *ServerCommand) makePicturesStore() (*image.Service, error) {
|
||||
@@ -746,7 +748,7 @@ func (s *ServerCommand) makePicturesStore() (*image.Service, error) {
|
||||
return image.NewService(boltImageStore, imageServiceParams), nil
|
||||
case "fs":
|
||||
if err := makeDirs(s.Image.FS.Path); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create pictures store")
|
||||
return nil, fmt.Errorf("failed to create pictures store: %w", err)
|
||||
}
|
||||
return image.NewService(&image.FileSystem{
|
||||
Location: s.Image.FS.Path,
|
||||
@@ -762,7 +764,7 @@ func (s *ServerCommand) makePicturesStore() (*image.Service, error) {
|
||||
AuthPasswd: s.Image.RPC.AuthPassword,
|
||||
}}, imageServiceParams), nil
|
||||
}
|
||||
return nil, errors.Errorf("unsupported pictures store type %s", s.Image.Type)
|
||||
return nil, fmt.Errorf("unsupported pictures store type %s", s.Image.Type)
|
||||
}
|
||||
|
||||
func (s *ServerCommand) makeAdminStore() (admin.Store, error) {
|
||||
@@ -788,7 +790,7 @@ func (s *ServerCommand) makeAdminStore() (admin.Store, error) {
|
||||
}}
|
||||
return r, nil
|
||||
default:
|
||||
return nil, errors.Errorf("unsupported admin store type %s", s.Admin.Type)
|
||||
return nil, fmt.Errorf("unsupported admin store type %s", s.Admin.Type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -798,25 +800,25 @@ func (s *ServerCommand) makeCache() (LoadingCache, error) {
|
||||
case "redis_pub_sub":
|
||||
redisPubSub, err := eventbus.NewRedisPubSub(s.Cache.RedisAddr, "remark42-cache")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cache backend initialization, redis PubSub initialisation")
|
||||
return nil, fmt.Errorf("cache backend initialization, redis PubSub initialisation: %w", err)
|
||||
}
|
||||
backend, err := cache.NewLruCache(cache.MaxCacheSize(s.Cache.Max.Size), cache.MaxValSize(s.Cache.Max.Value),
|
||||
cache.MaxKeys(s.Cache.Max.Items), cache.EventBus(redisPubSub))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cache backend initialization")
|
||||
return nil, fmt.Errorf("cache backend initialization: %w", err)
|
||||
}
|
||||
return cache.NewScache(backend), nil
|
||||
case "mem":
|
||||
backend, err := cache.NewLruCache(cache.MaxCacheSize(s.Cache.Max.Size), cache.MaxValSize(s.Cache.Max.Value),
|
||||
cache.MaxKeys(s.Cache.Max.Items))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cache backend initialization")
|
||||
return nil, fmt.Errorf("cache backend initialization: %w", err)
|
||||
}
|
||||
return cache.NewScache(backend), nil
|
||||
case "none":
|
||||
return cache.NewScache(&cache.Nop{}), nil
|
||||
}
|
||||
return nil, errors.Errorf("unsupported cache type %s", s.Cache.Type)
|
||||
return nil, fmt.Errorf("unsupported cache type %s", s.Cache.Type)
|
||||
}
|
||||
|
||||
func (s *ServerCommand) addAuthProviders(authenticator *auth.Service) error {
|
||||
@@ -930,7 +932,7 @@ func (s *ServerCommand) loadEmailTemplate() (string, error) {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to read file %s", s.Auth.Email.MsgTemplate)
|
||||
return "", fmt.Errorf("failed to read file %s: %w", s.Auth.Email.MsgTemplate, err)
|
||||
}
|
||||
|
||||
return string(file), nil
|
||||
@@ -986,7 +988,7 @@ func (s *ServerCommand) makeNotifyDestinations(authenticator *auth.Service) ([]n
|
||||
}
|
||||
webhook, err := notify.NewWebhook(client, whParams)
|
||||
if err != nil {
|
||||
return destinations, errors.Wrap(err, "failed to create webhook notification destination")
|
||||
return destinations, fmt.Errorf("failed to create webhook notification destination: %w", err)
|
||||
}
|
||||
destinations = append(destinations, webhook)
|
||||
}
|
||||
@@ -994,7 +996,7 @@ func (s *ServerCommand) makeNotifyDestinations(authenticator *auth.Service) ([]n
|
||||
if contains("slack", s.Notify.Admins) {
|
||||
slack, err := notify.NewSlack(s.Notify.Slack.Token, s.Notify.Slack.Channel)
|
||||
if err != nil {
|
||||
return destinations, errors.Wrap(err, "failed to create slack notification destination")
|
||||
return destinations, fmt.Errorf("failed to create slack notification destination: %w", err)
|
||||
}
|
||||
destinations = append(destinations, slack)
|
||||
}
|
||||
@@ -1022,7 +1024,7 @@ func (s *ServerCommand) makeNotifyDestinations(authenticator *auth.Service) ([]n
|
||||
}
|
||||
tkn, err := authenticator.TokenService().Token(claims)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to make unsubscription token")
|
||||
return "", fmt.Errorf("failed to make unsubscription token: %w", err)
|
||||
}
|
||||
return tkn, nil
|
||||
},
|
||||
@@ -1040,7 +1042,7 @@ func (s *ServerCommand) makeNotifyDestinations(authenticator *auth.Service) ([]n
|
||||
}
|
||||
emailService, err := notify.NewEmail(emailParams, smtpParams)
|
||||
if err != nil {
|
||||
return destinations, errors.Wrap(err, "failed to create email notification destination")
|
||||
return destinations, fmt.Errorf("failed to create email notification destination: %w", err)
|
||||
}
|
||||
destinations = append(destinations, emailService)
|
||||
}
|
||||
@@ -1051,7 +1053,7 @@ func (s *ServerCommand) makeNotifyDestinations(authenticator *auth.Service) ([]n
|
||||
// constructs Telegram notify service
|
||||
func (s *ServerCommand) makeTelegramNotify() (*notify.Telegram, error) {
|
||||
if contains("telegram", s.Notify.Admins) && s.Notify.Telegram.Channel == "" {
|
||||
return nil, errors.New("--notify.telegram.channel must be set for admin notifications to work")
|
||||
return nil, fmt.Errorf("--notify.telegram.channel must be set for admin notifications to work")
|
||||
}
|
||||
telegramParams := notify.TelegramParams{
|
||||
AdminChannelID: s.Notify.Telegram.Channel,
|
||||
@@ -1062,7 +1064,7 @@ func (s *ServerCommand) makeTelegramNotify() (*notify.Telegram, error) {
|
||||
}
|
||||
tg, err := notify.NewTelegram(telegramParams)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create telegram notification destination")
|
||||
return nil, fmt.Errorf("failed to create telegram notification destination: %w", err)
|
||||
}
|
||||
return tg, nil
|
||||
}
|
||||
@@ -1073,10 +1075,10 @@ func (s *ServerCommand) makeSSLConfig() (config api.SSLConfig, err error) {
|
||||
config.SSLMode = api.None
|
||||
case "static":
|
||||
if s.SSL.Cert == "" {
|
||||
return config, errors.New("path to cert.pem is required")
|
||||
return config, fmt.Errorf("path to cert.pem is required")
|
||||
}
|
||||
if s.SSL.Key == "" {
|
||||
return config, errors.New("path to key.pem is required")
|
||||
return config, fmt.Errorf("path to key.pem is required")
|
||||
}
|
||||
config.SSLMode = api.Static
|
||||
config.Port = s.SSL.Port
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"time"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// AutoBackup struct handles daily backups params for siteID
|
||||
@@ -50,18 +49,18 @@ func (ab AutoBackup) makeBackup() (string, error) {
|
||||
backupFile := fmt.Sprintf("%s/backup-%s-%s.gz", ab.BackupLocation, ab.SiteID, time.Now().Format("20060102"))
|
||||
fh, err := os.Create(backupFile) //nolint:gosec // harmless
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "can't create backup file %s", backupFile)
|
||||
return "", fmt.Errorf("can't create backup file %s: %w", backupFile, err)
|
||||
}
|
||||
gz := gzip.NewWriter(fh)
|
||||
|
||||
if _, err = ab.Exporter.Export(gz, ab.SiteID); err != nil {
|
||||
return "", errors.Wrapf(err, "export failed for %s", ab.SiteID)
|
||||
return "", fmt.Errorf("export failed for %s: %w", ab.SiteID, err)
|
||||
}
|
||||
if err = gz.Close(); err != nil {
|
||||
return "", errors.Wrapf(err, "can't close gz for %s", backupFile)
|
||||
return "", fmt.Errorf("can't close gz for %s: %w", backupFile, err)
|
||||
}
|
||||
if err = fh.Close(); err != nil {
|
||||
return "", errors.Wrapf(err, "can't close file handler for %s", backupFile)
|
||||
return "", fmt.Errorf("can't close file handler for %s: %w", backupFile, err)
|
||||
}
|
||||
log.Printf("[DEBUG] created backup file %s", backupFile)
|
||||
return backupFile, nil
|
||||
|
||||
@@ -2,10 +2,10 @@ package migrator
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/umputun/remark42/backend/app/store"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
@@ -68,9 +68,9 @@ func (d *Commento) Import(r io.Reader, siteID string) (size int, err error) {
|
||||
}
|
||||
|
||||
if failed > 0 {
|
||||
err = errors.Errorf("failed to save %d comments", failed)
|
||||
err = fmt.Errorf("failed to save %d comments", failed)
|
||||
if passed == 0 {
|
||||
err = errors.New("import failed")
|
||||
err = fmt.Errorf("import failed")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/store"
|
||||
"github.com/umputun/remark42/backend/app/store/admin"
|
||||
"github.com/umputun/remark42/backend/app/store/engine"
|
||||
"github.com/umputun/remark42/backend/app/store/service"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
func TestCommento_Import(t *testing.T) {
|
||||
|
||||
@@ -2,12 +2,12 @@ package migrator
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/store"
|
||||
)
|
||||
@@ -68,9 +68,9 @@ func (d *Disqus) Import(r io.Reader, siteID string) (size int, err error) {
|
||||
}
|
||||
|
||||
if failed > 0 {
|
||||
err = errors.Errorf("failed to save %d comments", failed)
|
||||
err = fmt.Errorf("failed to save %d comments", failed)
|
||||
if passed == 0 {
|
||||
err = errors.New("import failed")
|
||||
err = fmt.Errorf("import failed")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
package migrator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/store"
|
||||
"github.com/umputun/remark42/backend/app/store/service"
|
||||
@@ -69,12 +69,12 @@ func ImportComments(p ImportParams) (int, error) {
|
||||
case "native":
|
||||
importer = &Native{DataStore: p.DataStore}
|
||||
default:
|
||||
return 0, errors.Errorf("unsupported import provider %s", p.Provider)
|
||||
return 0, fmt.Errorf("unsupported import provider %s", p.Provider)
|
||||
}
|
||||
|
||||
fh, err := os.Open(p.InputFile)
|
||||
if err != nil {
|
||||
return 0, errors.Wrapf(err, "can't open import file %s", p.InputFile)
|
||||
return 0, fmt.Errorf("can't open import file %s: %w", p.InputFile, err)
|
||||
}
|
||||
|
||||
defer func() { //nolint:gosec // false positive on defer without error check when it's checked here
|
||||
|
||||
@@ -4,12 +4,12 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync/atomic"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/go-pkgz/syncs"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/store"
|
||||
"github.com/umputun/remark42/backend/app/store/service"
|
||||
@@ -36,7 +36,7 @@ type meta struct {
|
||||
// The final file is a valid json
|
||||
func (n *Native) Export(w io.Writer, siteID string) (size int, err error) {
|
||||
if err = n.exportMeta(siteID, w); err != nil {
|
||||
return 0, errors.Wrapf(err, "failed to export meta for site %s", siteID)
|
||||
return 0, fmt.Errorf("failed to export meta for site %s: %w", siteID, err)
|
||||
}
|
||||
|
||||
topics, err := n.DataStore.List(siteID, 0, 0)
|
||||
@@ -59,10 +59,10 @@ func (n *Native) Export(w io.Writer, siteID string) (size int, err error) {
|
||||
enc.SetEscapeHTML(false)
|
||||
|
||||
if err = enc.Encode(comment); err != nil {
|
||||
return commentsCount, errors.Wrapf(err, "can't marshal %v", comments)
|
||||
return commentsCount, fmt.Errorf("can't marshal %v: %w", comments, err)
|
||||
}
|
||||
if _, err = w.Write(buf.Bytes()); err != nil {
|
||||
return commentsCount, errors.Wrap(err, "can't write comment data")
|
||||
return commentsCount, fmt.Errorf("can't write comment data: %w", err)
|
||||
}
|
||||
commentsCount++
|
||||
}
|
||||
@@ -76,11 +76,11 @@ func (n *Native) exportMeta(siteID string, w io.Writer) (err error) {
|
||||
m := meta{Version: nativeVersion}
|
||||
m.Users, m.Posts, err = n.DataStore.Metas(siteID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "can't get meta")
|
||||
return fmt.Errorf("can't get meta: %w", err)
|
||||
}
|
||||
|
||||
if err = json.NewEncoder(w).Encode(m); err != nil {
|
||||
return errors.Wrap(err, "can't encode meta")
|
||||
return fmt.Errorf("can't encode meta: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -131,11 +131,11 @@ func (n *Native) Import(reader io.Reader, siteID string) (size int, err error) {
|
||||
m := meta{}
|
||||
dec := json.NewDecoder(reader)
|
||||
if err = dec.Decode(&m); err != nil {
|
||||
return 0, errors.Wrapf(err, "failed to import meta for site %s", siteID)
|
||||
return 0, fmt.Errorf("failed to import meta for site %s: %w", siteID, err)
|
||||
}
|
||||
|
||||
if m.Version != nativeVersion && m.Version != 0 { // this version allows back compatibility with 0 version
|
||||
return 0, errors.Errorf("unexpected import file version %d", m.Version)
|
||||
return 0, fmt.Errorf("unexpected import file version %d", m.Version)
|
||||
}
|
||||
|
||||
if e := n.DataStore.DeleteAll(siteID); e != nil {
|
||||
@@ -183,7 +183,7 @@ func (n *Native) Import(reader io.Reader, siteID string) (size int, err error) {
|
||||
grp.Wait()
|
||||
|
||||
if failed > 0 {
|
||||
return int(comments), errors.Errorf("failed to save %d comments", failed)
|
||||
return int(comments), fmt.Errorf("failed to save %d comments", failed)
|
||||
}
|
||||
log.Printf("[INFO] imported %d comments from %d records", comments, total)
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@ package migrator
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"html"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/store"
|
||||
)
|
||||
@@ -75,9 +75,9 @@ func (w *WordPress) Import(r io.Reader, siteID string) (size int, err error) {
|
||||
}
|
||||
|
||||
if failed > 0 {
|
||||
err = errors.Errorf("failed to save %d comments", failed)
|
||||
err = fmt.Errorf("failed to save %d comments", failed)
|
||||
if passed == 0 {
|
||||
err = errors.New("import failed")
|
||||
err = fmt.Errorf("import failed")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-16
@@ -129,7 +129,7 @@ func NewEmail(emailParams EmailParams, smtpParams SMTPParams) (*Email, error) {
|
||||
// initialize templates
|
||||
err := res.setTemplates()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't set templates")
|
||||
return nil, fmt.Errorf("can't set templates: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Create new email notifier for server %s with user %s, timeout=%s",
|
||||
@@ -173,7 +173,7 @@ func (e *Email) setTemplates() error {
|
||||
func (e *Email) Send(ctx context.Context, req Request) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return errors.Errorf("sending email messages about comment %q aborted due to canceled context", req.Comment.ID)
|
||||
return fmt.Errorf("sending email messages about comment %q aborted due to canceled context", req.Comment.ID)
|
||||
default:
|
||||
}
|
||||
|
||||
@@ -181,12 +181,16 @@ func (e *Email) Send(ctx context.Context, req Request) error {
|
||||
|
||||
for _, email := range req.Emails {
|
||||
err := e.buildAndSendMessage(ctx, req, email, false)
|
||||
result = multierror.Append(errors.Wrapf(err, "problem sending user email notification to %q", email))
|
||||
if err != nil {
|
||||
result = multierror.Append(fmt.Errorf("problem sending user email notification to %q: %w", email, err))
|
||||
}
|
||||
}
|
||||
|
||||
for _, email := range e.AdminEmails {
|
||||
err := e.buildAndSendMessage(ctx, req, email, true)
|
||||
result = multierror.Append(errors.Wrapf(err, "problem sending admin email notification to %q", email))
|
||||
if err != nil {
|
||||
result = multierror.Append(fmt.Errorf("problem sending admin email notification to %q: %w", email, err))
|
||||
}
|
||||
}
|
||||
|
||||
return result.ErrorOrNil()
|
||||
@@ -215,7 +219,7 @@ func (e *Email) SendVerification(ctx context.Context, req VerificationRequest) e
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return errors.Errorf("sending message to %q aborted due to canceled context", req.User)
|
||||
return fmt.Errorf("sending message to %q aborted due to canceled context", req.User)
|
||||
default:
|
||||
}
|
||||
|
||||
@@ -338,11 +342,11 @@ func (e *Email) buildMessage(subject, body, to, contentType, unsubscribeLink str
|
||||
// Thread safe.
|
||||
func (e *Email) sendMessage(m emailMessage) error {
|
||||
if e.smtp == nil {
|
||||
return errors.New("sendMessage called without client set")
|
||||
return fmt.Errorf("sendMessage called without client set")
|
||||
}
|
||||
client, err := e.smtp.Create(e.SMTPParams)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to make smtp Create")
|
||||
return fmt.Errorf("failed to make smtp Create: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
@@ -355,15 +359,15 @@ func (e *Email) sendMessage(m emailMessage) error {
|
||||
}()
|
||||
|
||||
if err = client.Mail(m.from); err != nil {
|
||||
return errors.Wrapf(err, "bad from address %q", m.from)
|
||||
return fmt.Errorf("bad from address %q: %w", m.from, err)
|
||||
}
|
||||
if err = client.Rcpt(m.to); err != nil {
|
||||
return errors.Wrapf(err, "bad to address %q", m.to)
|
||||
return fmt.Errorf("bad to address %q: %w", m.to, err)
|
||||
}
|
||||
|
||||
writer, err := client.Data()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "can't make email writer")
|
||||
return fmt.Errorf("can't make email writer: %w", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
@@ -374,7 +378,7 @@ func (e *Email) sendMessage(m emailMessage) error {
|
||||
|
||||
buf := bytes.NewBufferString(m.message)
|
||||
if _, err = buf.WriteTo(writer); err != nil {
|
||||
return errors.Wrapf(err, "failed to send email body to %q", m.to)
|
||||
return fmt.Errorf("failed to send email body to %q: %w", m.to, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -394,7 +398,7 @@ func (s *emailClient) Create(params SMTPParams) (smtpClient, error) {
|
||||
}
|
||||
auth := smtp.PlainAuth("", params.Username, params.Password, params.Host)
|
||||
if err := c.Auth(auth); err != nil {
|
||||
return errors.Wrapf(err, "failed to auth to smtp %s:%d", params.Host, params.Port)
|
||||
return fmt.Errorf("failed to auth to smtp %s:%d: %w", params.Host, params.Port, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -409,22 +413,22 @@ func (s *emailClient) Create(params SMTPParams) (smtpClient, error) {
|
||||
}
|
||||
conn, err := tls.Dial("tcp", srvAddress, tlsConf)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to dial smtp tls to %s", srvAddress)
|
||||
return nil, fmt.Errorf("failed to dial smtp tls to %s: %w", srvAddress, err)
|
||||
}
|
||||
if c, err = smtp.NewClient(conn, params.Host); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to make smtp client for %s", srvAddress)
|
||||
return nil, fmt.Errorf("failed to make smtp client for %s: %w", srvAddress, err)
|
||||
}
|
||||
return c, authenticate(c)
|
||||
}
|
||||
|
||||
conn, err := net.DialTimeout("tcp", srvAddress, params.TimeOut)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "timeout connecting to %s", srvAddress)
|
||||
return nil, fmt.Errorf("timeout connecting to %s: %w", srvAddress, err)
|
||||
}
|
||||
|
||||
c, err = smtp.NewClient(conn, params.Host)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to dial")
|
||||
return nil, fmt.Errorf("failed to dial: %w", err)
|
||||
}
|
||||
|
||||
return c, authenticate(c)
|
||||
|
||||
@@ -3,7 +3,7 @@ package notify
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/smtp"
|
||||
"sync"
|
||||
@@ -361,7 +361,7 @@ type fakeTestSMTP struct {
|
||||
|
||||
func (f *fakeTestSMTP) Create(SMTPParams) (smtpClient, error) {
|
||||
if f.fail["create"] {
|
||||
return nil, errors.New("failed to create client")
|
||||
return nil, fmt.Errorf("failed to create client")
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
@@ -373,7 +373,7 @@ func (f *fakeTestSMTP) Mail(m string) error {
|
||||
f.mail = m
|
||||
f.lock.Unlock()
|
||||
if f.fail["mail"] {
|
||||
return errors.New("failed to verify sender")
|
||||
return fmt.Errorf("failed to verify sender")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -383,7 +383,7 @@ func (f *fakeTestSMTP) Rcpt(r string) error {
|
||||
f.rcpt = r
|
||||
f.lock.Unlock()
|
||||
if f.fail["rcpt"] {
|
||||
return errors.New("failed to verify receiver")
|
||||
return fmt.Errorf("failed to verify receiver")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -393,7 +393,7 @@ func (f *fakeTestSMTP) Quit() error {
|
||||
f.quitCount++
|
||||
f.lock.Unlock()
|
||||
if f.fail["quit"] {
|
||||
return errors.New("failed to quit")
|
||||
return fmt.Errorf("failed to quit")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -401,14 +401,14 @@ func (f *fakeTestSMTP) Quit() error {
|
||||
func (f *fakeTestSMTP) Close() error {
|
||||
f.close = true
|
||||
if f.fail["close"] {
|
||||
return errors.New("failed to close")
|
||||
return fmt.Errorf("failed to close")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeTestSMTP) Data() (io.WriteCloser, error) {
|
||||
if f.fail["data"] {
|
||||
return nil, errors.New("failed to send")
|
||||
return nil, fmt.Errorf("failed to send")
|
||||
}
|
||||
return nopCloser{&f.buff}, nil
|
||||
}
|
||||
@@ -433,7 +433,7 @@ func (f *fakeTestSMTP) readQuitCount() int {
|
||||
|
||||
func TokenGenFn(user, _, _ string) (string, error) {
|
||||
if user == "error" {
|
||||
return "", errors.New("token generation error")
|
||||
return "", fmt.Errorf("token generation error")
|
||||
}
|
||||
return "token", nil
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync/atomic"
|
||||
@@ -284,7 +283,7 @@ type mockStore struct {
|
||||
func (m mockStore) getUserDetail(userID string) (string, error) {
|
||||
detail, ok := m.userDetails[userID]
|
||||
if !ok {
|
||||
return "", errors.New("no such user")
|
||||
return "", fmt.Errorf("no such user")
|
||||
}
|
||||
return detail, nil
|
||||
}
|
||||
@@ -292,7 +291,7 @@ func (m mockStore) getUserDetail(userID string) (string, error) {
|
||||
func (m mockStore) Get(_ store.Locator, id string, _ store.User) (store.Comment, error) {
|
||||
res, ok := m.data[id]
|
||||
if !ok {
|
||||
return store.Comment{}, errors.New("no such id")
|
||||
return store.Comment{}, fmt.Errorf("no such id")
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ package notify
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/slack-go/slack"
|
||||
)
|
||||
|
||||
@@ -26,7 +26,7 @@ func NewSlack(token, channelName string, opts ...slack.Option) (*Slack, error) {
|
||||
|
||||
channelID, err := res.findChannelIDByName(channelName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can not find slack channel '"+channelName+"'")
|
||||
return nil, fmt.Errorf("can not find slack channel '"+channelName+"': %w", err)
|
||||
}
|
||||
|
||||
res.channelID = channelID
|
||||
@@ -91,5 +91,5 @@ func (t *Slack) findChannelIDByName(name string) (string, error) {
|
||||
}
|
||||
params.Cursor = next
|
||||
}
|
||||
return "", errors.New("no such channel")
|
||||
return "", fmt.Errorf("no such channel")
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"golang.org/x/net/html"
|
||||
"io"
|
||||
"net/http"
|
||||
neturl "net/url"
|
||||
@@ -15,12 +14,12 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/go-pkgz/repeater"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
// TelegramParams contain settings for telegram notifications
|
||||
@@ -111,7 +110,7 @@ func (t *Telegram) Send(ctx context.Context, req Request) error {
|
||||
|
||||
msg, err := buildMessage(req)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to make telegram message body for comment ID %s", req.Comment.ID)
|
||||
return fmt.Errorf("failed to make telegram message body for comment ID %s: %w", req.Comment.ID, err)
|
||||
}
|
||||
|
||||
if t.AdminChannelID != "" {
|
||||
@@ -269,22 +268,22 @@ func (t *Telegram) CheckToken(token, user string) (telegram, site string, err er
|
||||
t.requests.RUnlock()
|
||||
|
||||
if !ok {
|
||||
return "", "", errors.New("request is not found")
|
||||
return "", "", fmt.Errorf("request is not found")
|
||||
}
|
||||
|
||||
if time.Now().After(authRequest.expires) {
|
||||
t.requests.Lock()
|
||||
delete(t.requests.data, token)
|
||||
t.requests.Unlock()
|
||||
return "", "", errors.New("request expired")
|
||||
return "", "", fmt.Errorf("request expired")
|
||||
}
|
||||
|
||||
if !authRequest.confirmed {
|
||||
return "", "", errors.New("request is not verified yet")
|
||||
return "", "", fmt.Errorf("request is not verified yet")
|
||||
}
|
||||
|
||||
if authRequest.user != user {
|
||||
return "", "", errors.New("user does not match original requester")
|
||||
return "", "", fmt.Errorf("user does not match original requester")
|
||||
}
|
||||
|
||||
// Delete request
|
||||
@@ -333,7 +332,7 @@ func (t *Telegram) Run(ctx context.Context) {
|
||||
// so that caller could get updates and send it not only there but to multiple sources
|
||||
func (t *Telegram) ProcessUpdate(ctx context.Context, textUpdate string) error {
|
||||
if atomic.LoadInt32(&t.run) != 0 {
|
||||
return errors.New("Run goroutine should not be used with ProcessUpdate")
|
||||
return fmt.Errorf("the Run goroutine should not be used with ProcessUpdate")
|
||||
}
|
||||
defer func() {
|
||||
// as Run goroutine is not running, clean up old requests on each update
|
||||
@@ -349,7 +348,7 @@ func (t *Telegram) ProcessUpdate(ctx context.Context, textUpdate string) error {
|
||||
}()
|
||||
var updates TelegramUpdate
|
||||
if err := json.Unmarshal([]byte(textUpdate), &updates); err != nil {
|
||||
return errors.Wrap(err, "failed to decode provided telegram update")
|
||||
return fmt.Errorf("failed to decode provided telegram update: %w", err)
|
||||
}
|
||||
t.processUpdates(ctx, &updates)
|
||||
return nil
|
||||
@@ -377,7 +376,7 @@ func (t *Telegram) getUpdates(ctx context.Context) (*TelegramUpdate, error) {
|
||||
|
||||
err := t.Request(ctx, url, nil, &result)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to fetch updates")
|
||||
return nil, fmt.Errorf("failed to fetch updates: %w", err)
|
||||
}
|
||||
|
||||
for _, u := range result.Result {
|
||||
@@ -445,7 +444,7 @@ func (t *Telegram) botInfo(ctx context.Context) (*TelegramBotInfo, error) {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Result == nil {
|
||||
return nil, errors.New("received empty result")
|
||||
return nil, fmt.Errorf("received empty result")
|
||||
}
|
||||
|
||||
return resp.Result, nil
|
||||
@@ -465,13 +464,13 @@ func (t *Telegram) Request(ctx context.Context, method string, b []byte, data in
|
||||
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create request")
|
||||
return fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
|
||||
client := http.Client{Timeout: t.Timeout}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to send request")
|
||||
return fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
@@ -480,7 +479,7 @@ func (t *Telegram) Request(ctx context.Context, method string, b []byte, data in
|
||||
}
|
||||
|
||||
if err = json.NewDecoder(resp.Body).Decode(data); err != nil {
|
||||
return errors.Wrap(err, "failed to decode json response")
|
||||
return fmt.Errorf("failed to decode json response: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -492,7 +491,7 @@ func (t *Telegram) parseError(r io.Reader, statusCode int) error {
|
||||
Description string `json:"description"`
|
||||
}{}
|
||||
if err := json.NewDecoder(r).Decode(&tgErr); err != nil {
|
||||
return errors.Errorf("unexpected telegram API status code %d", statusCode)
|
||||
return fmt.Errorf("unexpected telegram API status code %d", statusCode)
|
||||
}
|
||||
return errors.Errorf("unexpected telegram API status code %d, error: %q", statusCode, tgErr.Description)
|
||||
return fmt.Errorf("unexpected telegram API status code %d, error: %q", statusCode, tgErr.Description)
|
||||
}
|
||||
|
||||
@@ -453,7 +453,7 @@ func TestTelegram_TokenVerification(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go tb.Run(ctx)
|
||||
assert.Eventually(t, func() bool {
|
||||
return tb.ProcessUpdate(ctx, "").Error() == "Run goroutine should not be used with ProcessUpdate"
|
||||
return tb.ProcessUpdate(ctx, "").Error() == "the Run goroutine should not be used with ProcessUpdate"
|
||||
}, time.Millisecond*100, time.Millisecond*10, "ProcessUpdate should not work same time as Run")
|
||||
tb.AddToken("expired token", "user", "site", time.Now().Add(-time.Minute))
|
||||
tb.requests.RLock()
|
||||
|
||||
@@ -40,7 +40,7 @@ type Webhook struct {
|
||||
func NewWebhook(client WebhookClient, params WebhookParams) (*Webhook, error) {
|
||||
res := &Webhook{WebhookParams: params}
|
||||
if res.WebhookURL == "" {
|
||||
return nil, errors.New("webhook URL is required for webhook notifications")
|
||||
return nil, fmt.Errorf("webhook URL is required for webhook notifications")
|
||||
}
|
||||
|
||||
if res.Template == "" {
|
||||
@@ -49,7 +49,7 @@ func NewWebhook(client WebhookClient, params WebhookParams) (*Webhook, error) {
|
||||
|
||||
payloadTmpl, err := template.New("webhook").Parse(res.Template)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to parse webhook template")
|
||||
return nil, fmt.Errorf("unable to parse webhook template: %w", err)
|
||||
}
|
||||
|
||||
res.webhookClient = client
|
||||
@@ -65,12 +65,12 @@ func (t *Webhook) Send(ctx context.Context, req Request) error {
|
||||
var payload bytes.Buffer
|
||||
err := t.webhookTemplate.Execute(&payload, req.Comment)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to compile webhook template")
|
||||
return fmt.Errorf("unable to compile webhook template: %w", err)
|
||||
}
|
||||
|
||||
httpReq, err := http.NewRequestWithContext(ctx, "POST", t.WebhookURL, &payload)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to create webhook request")
|
||||
return fmt.Errorf("unable to create webhook request: %w", err)
|
||||
}
|
||||
|
||||
for _, h := range t.Headers {
|
||||
@@ -83,7 +83,7 @@ func (t *Webhook) Send(ctx context.Context, req Request) error {
|
||||
|
||||
resp, err := t.webhookClient.Do(httpReq)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "webhook request failed")
|
||||
return fmt.Errorf("webhook request failed: %w", err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
@@ -3,7 +3,7 @@ package notify
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
@@ -31,7 +31,7 @@ type errReader struct {
|
||||
}
|
||||
|
||||
func (errReader) Read(p []byte) (n int, err error) {
|
||||
return 0, errors.New("test error")
|
||||
return 0, fmt.Errorf("test error")
|
||||
}
|
||||
|
||||
func TestWebhook_NewWebhook(t *testing.T) {
|
||||
@@ -104,7 +104,7 @@ func TestWebhook_Send(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "unable to create webhook request")
|
||||
|
||||
wh, err = NewWebhook(funcWebhookClient(func(*http.Request) (*http.Response, error) {
|
||||
return nil, errors.New("request failed")
|
||||
return nil, fmt.Errorf("request failed")
|
||||
}), WebhookParams{WebhookURL: "https://not-existing-url.net"})
|
||||
assert.NoError(t, err)
|
||||
err = wh.Send(context.TODO(), Request{Comment: c})
|
||||
|
||||
@@ -3,7 +3,7 @@ package providers
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -46,7 +46,7 @@ func (m *mockTGRequester) Request(_ context.Context, _ string, _ []byte, data in
|
||||
assert.NoError(m.t, json.Unmarshal([]byte(getUpdatesResp), data))
|
||||
return nil
|
||||
}
|
||||
return errors.New("test error")
|
||||
return fmt.Errorf("test error")
|
||||
}
|
||||
|
||||
type mockTGUpdatesReceiver struct {
|
||||
@@ -68,5 +68,5 @@ func (m *mockTGUpdatesReceiver) ProcessUpdate(_ context.Context, textUpdate stri
|
||||
return nil
|
||||
}
|
||||
assert.Nil(m.t, result.Result)
|
||||
return errors.New("test error")
|
||||
return fmt.Errorf("test error")
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"time"
|
||||
@@ -103,7 +103,7 @@ func (a *admin) deleteMeRequestCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// deleteme set by deleteMeCtrl, this check just to make sure we not trying to delete with leaked token
|
||||
if !claims.User.BoolAttr("delete_me") {
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("forbidden"), "can't use provided token", rest.ErrNoAccess)
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, fmt.Errorf("forbidden"), "can't use provided token", rest.ErrNoAccess)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ func (a *admin) setReadOnlyCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
// don't allow to reset ro for posts turned to ro by ReadOnlyAge
|
||||
if !roStatus {
|
||||
if info, e := a.dataService.Info(locator, a.readOnlyAge); e == nil && isRoByAge(info) {
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"),
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, fmt.Errorf("rejected"),
|
||||
"read-only due the age", rest.ErrActionRejected)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
cache "github.com/go-pkgz/lcw"
|
||||
log "github.com/go-pkgz/lgr"
|
||||
R "github.com/go-pkgz/rest"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/migrator"
|
||||
"github.com/umputun/remark42/backend/app/rest"
|
||||
@@ -47,7 +46,7 @@ func (m *Migrator) importCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
siteID := r.URL.Query().Get("site")
|
||||
|
||||
if m.isBusy(siteID) {
|
||||
rest.SendErrorJSON(w, r, http.StatusConflict, errors.New("already running"),
|
||||
rest.SendErrorJSON(w, r, http.StatusConflict, fmt.Errorf("already running"),
|
||||
"import rejected", rest.ErrActionRejected)
|
||||
return
|
||||
}
|
||||
@@ -70,7 +69,7 @@ func (m *Migrator) importFormCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
siteID := r.URL.Query().Get("site")
|
||||
|
||||
if m.isBusy(siteID) {
|
||||
rest.SendErrorJSON(w, r, http.StatusConflict, errors.New("already running"),
|
||||
rest.SendErrorJSON(w, r, http.StatusConflict, fmt.Errorf("already running"),
|
||||
"import rejected", rest.ErrActionRejected)
|
||||
return
|
||||
}
|
||||
@@ -253,15 +252,15 @@ func (m *Migrator) runImport(siteID, provider, tmpfile string) {
|
||||
func (m *Migrator) saveTemp(r io.Reader) (string, error) {
|
||||
tmpfile, err := ioutil.TempFile("", "remark42_import")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "can't make temp file")
|
||||
return "", fmt.Errorf("can't make temp file: %w", err)
|
||||
}
|
||||
|
||||
if _, err = io.Copy(tmpfile, r); err != nil {
|
||||
return "", errors.Wrap(err, "can't copy to temp file")
|
||||
return "", fmt.Errorf("can't copy to temp file: %w", err)
|
||||
}
|
||||
|
||||
if err = tmpfile.Close(); err != nil {
|
||||
return "", errors.Wrap(err, "can't close temp file")
|
||||
return "", fmt.Errorf("can't close temp file: %w", err)
|
||||
}
|
||||
|
||||
return tmpfile.Name(), nil
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
log "github.com/go-pkgz/lgr"
|
||||
R "github.com/go-pkgz/rest"
|
||||
"github.com/go-pkgz/rest/logger"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rakyll/statik/fs"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/notify"
|
||||
@@ -505,7 +504,7 @@ func encodeJSONWithHTML(v interface{}) ([]byte, error) {
|
||||
enc := json.NewEncoder(buf)
|
||||
enc.SetEscapeHTML(false)
|
||||
if err := enc.Encode(v); err != nil {
|
||||
return nil, errors.Wrap(err, "json encoding failed")
|
||||
return nil, fmt.Errorf("json encoding failed: %w", err)
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
R "github.com/go-pkgz/rest"
|
||||
"github.com/golang-jwt/jwt"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/notify"
|
||||
"github.com/umputun/remark42/backend/app/rest"
|
||||
@@ -142,12 +141,12 @@ func (s *private) createCommentCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// check if user blocked
|
||||
if s.dataService.IsBlocked(comment.Locator.SiteID, comment.User.ID) {
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "user blocked", rest.ErrUserBlocked)
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, fmt.Errorf("rejected"), "user blocked", rest.ErrUserBlocked)
|
||||
return
|
||||
}
|
||||
|
||||
if s.isReadOnly(comment.Locator) {
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "old post, read-only", rest.ErrReadOnly)
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, fmt.Errorf("rejected"), "old post, read-only", rest.ErrReadOnly)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -207,7 +206,7 @@ func (s *private) updateCommentCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if currComment.User.ID != user.ID {
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"),
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, fmt.Errorf("rejected"),
|
||||
"can not edit comments for other users", rest.ErrNoAccess)
|
||||
return
|
||||
}
|
||||
@@ -268,13 +267,13 @@ func (s *private) voteCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
vote := r.URL.Query().Get("vote") == "1"
|
||||
|
||||
if s.isReadOnly(locator) {
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "old post, read-only", rest.ErrReadOnly)
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, fmt.Errorf("rejected"), "old post, read-only", rest.ErrReadOnly)
|
||||
return
|
||||
}
|
||||
|
||||
// check if user blocked
|
||||
if s.dataService.IsBlocked(locator.SiteID, user.ID) {
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "user blocked", rest.ErrUserBlocked)
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, fmt.Errorf("rejected"), "user blocked", rest.ErrUserBlocked)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -317,7 +316,7 @@ func (s *private) sendEmailConfirmationCtrl(w http.ResponseWriter, r *http.Reque
|
||||
siteID := r.URL.Query().Get("site")
|
||||
if address == "" {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest,
|
||||
errors.New("missing parameter"), "address parameter is required", rest.ErrInternal)
|
||||
fmt.Errorf("missing parameter"), "address parameter is required", rest.ErrInternal)
|
||||
return
|
||||
}
|
||||
existingAddress, err := s.dataService.GetUserEmail(siteID, user.ID)
|
||||
@@ -326,7 +325,7 @@ func (s *private) sendEmailConfirmationCtrl(w http.ResponseWriter, r *http.Reque
|
||||
}
|
||||
if address == existingAddress {
|
||||
rest.SendErrorJSON(w, r, http.StatusConflict,
|
||||
errors.New("already verified"), "email address is already verified for this user", rest.ErrInternal)
|
||||
fmt.Errorf("already verified"), "email address is already verified for this user", rest.ErrInternal)
|
||||
return
|
||||
}
|
||||
claims := token.Claims{
|
||||
@@ -364,7 +363,7 @@ func (s *private) telegramSubscribeCtrl(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
if s.telegramService == nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusInternalServerError,
|
||||
errors.New("not enabled"), "telegram notifications are not enabled", rest.ErrActionRejected)
|
||||
fmt.Errorf("not enabled"), "telegram notifications are not enabled", rest.ErrActionRejected)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -373,13 +372,13 @@ func (s *private) telegramSubscribeCtrl(w http.ResponseWriter, r *http.Request)
|
||||
// GET /telegram/subscribe?site=siteID (No token supplied)
|
||||
siteID := r.URL.Query().Get("site")
|
||||
if siteID == "" {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, errors.New("missing parameter"), "site parameter is required", rest.ErrInternal)
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, fmt.Errorf("missing parameter"), "site parameter is required", rest.ErrInternal)
|
||||
return
|
||||
}
|
||||
// we don't care as much if we can't retrieve the current value of that field for the user, so ignore the error
|
||||
if existingAddress, _ := s.dataService.GetUserTelegram(siteID, user.ID); existingAddress != "" {
|
||||
rest.SendErrorJSON(w, r, http.StatusConflict,
|
||||
errors.New("already subscribed"), "telegram subscription is already set for this user, delete if first to re-subscribe", rest.ErrActionRejected)
|
||||
fmt.Errorf("already subscribed"), "telegram subscription is already set for this user, delete if first to re-subscribe", rest.ErrActionRejected)
|
||||
return
|
||||
}
|
||||
// Generate and send token
|
||||
@@ -422,7 +421,7 @@ func (s *private) telegramSubscribeCtrl(w http.ResponseWriter, r *http.Request)
|
||||
func (s *private) setConfirmedEmailCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
tkn := r.URL.Query().Get("tkn")
|
||||
if tkn == "" {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, errors.New("missing parameter"), "token parameter is required", rest.ErrInternal)
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, fmt.Errorf("missing parameter"), "token parameter is required", rest.ErrInternal)
|
||||
return
|
||||
}
|
||||
user := rest.MustGetUserInfo(r)
|
||||
@@ -435,14 +434,14 @@ func (s *private) setConfirmedEmailCtrl(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
if s.authenticator.TokenService().IsExpired(confClaims) {
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, errors.New("expired"), "failed to verify confirmation token", rest.ErrInternal)
|
||||
rest.SendErrorJSON(w, r, http.StatusForbidden, fmt.Errorf("expired"), "failed to verify confirmation token", rest.ErrInternal)
|
||||
return
|
||||
}
|
||||
|
||||
// Handshake.ID is user.ID + "::" + address
|
||||
elems := strings.Split(confClaims.Handshake.ID, "::")
|
||||
if len(elems) != 2 || elems[0] != user.ID {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, errors.New(confClaims.Handshake.ID), "invalid handshake token", rest.ErrInternal)
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, fmt.Errorf("%s", confClaims.Handshake.ID), "invalid handshake token", rest.ErrInternal)
|
||||
return
|
||||
}
|
||||
address := elems[1]
|
||||
@@ -475,7 +474,7 @@ func (s *private) emailUnsubscribeCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
tkn := r.URL.Query().Get("tkn")
|
||||
if tkn == "" {
|
||||
rest.SendErrorHTML(w, r, http.StatusBadRequest,
|
||||
errors.New("missing parameter"), "token parameter is required", rest.ErrInternal, s.templates)
|
||||
fmt.Errorf("missing parameter"), "token parameter is required", rest.ErrInternal, s.templates)
|
||||
return
|
||||
}
|
||||
siteID := r.URL.Query().Get("site")
|
||||
@@ -488,7 +487,7 @@ func (s *private) emailUnsubscribeCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if s.authenticator.TokenService().IsExpired(confClaims) {
|
||||
rest.SendErrorHTML(w, r, http.StatusForbidden,
|
||||
errors.New("expired"), "failed to verify confirmation token", rest.ErrInternal, s.templates)
|
||||
fmt.Errorf("expired"), "failed to verify confirmation token", rest.ErrInternal, s.templates)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -496,7 +495,7 @@ func (s *private) emailUnsubscribeCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
elems := strings.Split(confClaims.Handshake.ID, "::")
|
||||
if len(elems) != 2 {
|
||||
rest.SendErrorHTML(w, r, http.StatusBadRequest,
|
||||
errors.New(confClaims.Handshake.ID), "invalid handshake token", rest.ErrInternal, s.templates)
|
||||
fmt.Errorf("%s", confClaims.Handshake.ID), "invalid handshake token", rest.ErrInternal, s.templates)
|
||||
return
|
||||
}
|
||||
userID := elems[0]
|
||||
@@ -510,12 +509,12 @@ func (s *private) emailUnsubscribeCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
if existingAddress == "" {
|
||||
rest.SendErrorHTML(w, r, http.StatusConflict,
|
||||
errors.New("user is not subscribed"), "user does not have active email subscription", rest.ErrInternal, s.templates)
|
||||
fmt.Errorf("user is not subscribed"), "user does not have active email subscription", rest.ErrInternal, s.templates)
|
||||
return
|
||||
}
|
||||
if address != existingAddress {
|
||||
rest.SendErrorHTML(w, r, http.StatusBadRequest,
|
||||
errors.New("wrong email unsubscription"), "email address in request does not match known for this user",
|
||||
fmt.Errorf("wrong email unsubscription"), "email address in request does not match known for this user",
|
||||
rest.ErrInternal, s.templates)
|
||||
return
|
||||
}
|
||||
@@ -727,11 +726,11 @@ func (s *private) isReadOnly(locator store.Locator) bool {
|
||||
func randToken() (string, error) {
|
||||
b := make([]byte, 32)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return "", errors.Wrap(err, "can't get random")
|
||||
return "", fmt.Errorf("can't get random: %w", err)
|
||||
}
|
||||
s := sha1.New() //nolint:gosec // not used for security
|
||||
if _, err := s.Write(b); err != nil {
|
||||
return "", errors.Wrap(err, "can't write randoms to sha1")
|
||||
return "", fmt.Errorf("can't write randoms to sha1: %w", err)
|
||||
}
|
||||
return fmt.Sprintf("%x", s.Sum(nil)), nil
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
@@ -1287,7 +1286,7 @@ func (m *mockTelegram) GetBotUsername() string {
|
||||
|
||||
func (m *mockTelegram) CheckToken(string, string) (telegram, site string, err error) {
|
||||
if m.notVerified {
|
||||
return "", "", errors.New("not verified")
|
||||
return "", "", fmt.Errorf("not verified")
|
||||
}
|
||||
return "good_telegram", m.site, nil
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"crypto/sha1" // nolint
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -17,7 +18,6 @@ import (
|
||||
cache "github.com/go-pkgz/lcw"
|
||||
log "github.com/go-pkgz/lgr"
|
||||
R "github.com/go-pkgz/rest"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/skip2/go-qrcode"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/rest"
|
||||
@@ -372,12 +372,12 @@ func (s *public) robotsCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *public) telegramQrCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
text := r.URL.Query().Get("url")
|
||||
if text == "" {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, errors.New("missing parameter"), "text parameter is required", rest.ErrInternal)
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, fmt.Errorf("missing parameter"), "text parameter is required", rest.ErrInternal)
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(text, "https://t.me/") {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, errors.New("wrong parameter"), "text parameter should start with https://t.me/", rest.ErrInternal)
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, fmt.Errorf("wrong parameter"), "text parameter should start with https://t.me/", rest.ErrInternal)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -423,7 +423,7 @@ func (s *public) parseSince(r *http.Request) (time.Time, error) {
|
||||
if since := r.URL.Query().Get("since"); since != "" {
|
||||
unixTS, e := strconv.ParseInt(since, 10, 64)
|
||||
if e != nil {
|
||||
return time.Time{}, errors.Wrap(e, "can't translate since parameter")
|
||||
return time.Time{}, fmt.Errorf("can't translate since parameter: %w", e)
|
||||
}
|
||||
sinceTS = time.Unix(unixTS/1000, 1000000*(unixTS%1000)) // since param in msec timestamp
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
@@ -277,13 +276,13 @@ func TestRest_parseError(t *testing.T) {
|
||||
err error
|
||||
res int
|
||||
}{
|
||||
{errors.New("can not vote for his own comment"), rest.ErrVoteSelf},
|
||||
{errors.New("already voted for"), rest.ErrVoteDbl},
|
||||
{errors.New("maximum number of votes exceeded for comment"), rest.ErrVoteMax},
|
||||
{errors.New("minimal score reached for comment"), rest.ErrVoteMinScore},
|
||||
{errors.New("too late to edit"), rest.ErrCommentEditExpired},
|
||||
{errors.New("parent comment with reply can't be edited"), rest.ErrCommentEditChanged},
|
||||
{errors.New("blah blah"), rest.ErrInternal},
|
||||
{fmt.Errorf("can not vote for his own comment"), rest.ErrVoteSelf},
|
||||
{fmt.Errorf("already voted for"), rest.ErrVoteDbl},
|
||||
{fmt.Errorf("maximum number of votes exceeded for comment"), rest.ErrVoteMax},
|
||||
{fmt.Errorf("minimal score reached for comment"), rest.ErrVoteMinScore},
|
||||
{fmt.Errorf("too late to edit"), rest.ErrCommentEditExpired},
|
||||
{fmt.Errorf("parent comment with reply can't be edited"), rest.ErrCommentEditChanged},
|
||||
{fmt.Errorf("blah blah"), rest.ErrInternal},
|
||||
}
|
||||
|
||||
for n, tt := range tbl {
|
||||
@@ -398,7 +397,7 @@ func randomPath(tempDir, basename, suffix string) (string, error) {
|
||||
return fname, nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("cannot create temp file")
|
||||
return "", fmt.Errorf("cannot create temp file in %s", tempDir)
|
||||
}
|
||||
|
||||
// startupT runs fully configured testing server
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
cache "github.com/go-pkgz/lcw"
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/gorilla/feeds"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/rest"
|
||||
"github.com/umputun/remark42/backend/app/store"
|
||||
@@ -104,7 +103,7 @@ func (s *rss) repliesCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
data, err := s.cache.Get(key, func() (res []byte, e error) {
|
||||
replies, userName, e := s.dataService.UserReplies(siteID, userID, maxRssItems, maxReplyDuration)
|
||||
if e != nil {
|
||||
return nil, errors.Wrap(e, "can't get last comments")
|
||||
return nil, fmt.Errorf("can't get last comments: %w", e)
|
||||
}
|
||||
|
||||
feed, e := s.toRssFeed(siteID, replies, "replies to "+userName)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -18,7 +17,7 @@ func TestSendErrorJSON(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/error" {
|
||||
t.Log("http err request", r.URL)
|
||||
SendErrorJSON(w, r, 500, errors.New("error 500"), "error details 123456", 123)
|
||||
SendErrorJSON(w, r, 500, fmt.Errorf("error 500"), "error details 123456", 123)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(404)
|
||||
@@ -48,7 +47,7 @@ func TestSendErrorHTML(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/error" {
|
||||
t.Log("http err request", r.URL)
|
||||
SendErrorHTML(w, r, 500, errors.New("error 500"), "error details 123456", 987, fs)
|
||||
SendErrorHTML(w, r, 500, fmt.Errorf("error 500"), "error details 123456", 987, fs)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(404)
|
||||
@@ -74,7 +73,7 @@ func TestErrorDetailsMsg(t *testing.T) {
|
||||
req, err := http.NewRequest("GET", "https://example.com/test?k1=v1&k2=v2", http.NoBody)
|
||||
require.NoError(t, err)
|
||||
req.RemoteAddr = "1.2.3.4"
|
||||
msg := errDetailsMsg(req, 500, errors.New("error 500"), "error details 123456", 123)
|
||||
msg := errDetailsMsg(req, 500, fmt.Errorf("error 500"), "error details 123456", 123)
|
||||
assert.Contains(t, msg, "error details 123456 - error 500 - 500 (123) - https://example.com/test?k1=v1&k2=v2 - [app/rest/httperrors_test.go:")
|
||||
// error line in the middle of the message is not checked
|
||||
assert.Contains(t, msg, " rest.TestErrorDetailsMsg]")
|
||||
@@ -89,7 +88,7 @@ func TestErrorDetailsMsgWithUser(t *testing.T) {
|
||||
req.RemoteAddr = "127.0.0.1:1234"
|
||||
req = SetUserInfo(req, store.User{Name: "test", ID: "id"})
|
||||
require.NoError(t, err)
|
||||
msg := errDetailsMsg(req, 500, errors.New("error 500"), "error details 123456", 34567)
|
||||
msg := errDetailsMsg(req, 500, fmt.Errorf("error 500"), "error details 123456", 34567)
|
||||
assert.Contains(t, msg, "error details 123456 - error 500 - 500 (34567) - test/id - https://example.com/test?k1=v1&k2=v2 - [app/rest/httperrors_test.go:")
|
||||
// error line in the middle of the message is not checked
|
||||
assert.Contains(t, msg, " rest.TestErrorDetailsMsgWithUser]")
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -12,7 +13,6 @@ import (
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/go-pkgz/repeater"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/rest"
|
||||
"github.com/umputun/remark42/backend/app/store/image"
|
||||
@@ -54,7 +54,7 @@ func (p Image) Convert(commentHTML string) string {
|
||||
func (p Image) extract(commentHTML string, imgSrcPred func(string) bool) ([]string, error) {
|
||||
doc, err := goquery.NewDocumentFromReader(strings.NewReader(commentHTML))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't create document")
|
||||
return nil, fmt.Errorf("can't create document: %w", err)
|
||||
}
|
||||
result := []string{}
|
||||
doc.Find("img").Each(func(i int, s *goquery.Selection) {
|
||||
@@ -150,23 +150,23 @@ func (p Image) downloadImage(ctx context.Context, imgURL string) ([]byte, error)
|
||||
var e error
|
||||
req, e := http.NewRequest("GET", imgURL, http.NoBody)
|
||||
if e != nil {
|
||||
return errors.Wrapf(e, "failed to make request for %s", imgURL)
|
||||
return fmt.Errorf("failed to make request for %s: %w", imgURL, e)
|
||||
}
|
||||
resp, e = client.Do(req.WithContext(ctx)) //nolint:bodyclose // need a refactor to fix that
|
||||
return e
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't download image %s", imgURL)
|
||||
return nil, fmt.Errorf("can't download image %s: %w", imgURL, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, errors.Errorf("got unsuccessful response status %d while fetching %s", resp.StatusCode, imgURL)
|
||||
return nil, fmt.Errorf("got unsuccessful response status %d while fetching %s", resp.StatusCode, imgURL)
|
||||
}
|
||||
|
||||
imgData, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("unable to read image body")
|
||||
return nil, fmt.Errorf("unable to read image body")
|
||||
}
|
||||
return imgData, nil
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-pkgz/auth/token"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/store"
|
||||
)
|
||||
@@ -23,7 +23,7 @@ func MustGetUserInfo(r *http.Request) store.User {
|
||||
func GetUserInfo(r *http.Request) (user store.User, err error) {
|
||||
u, err := token.GetUserInfo(r)
|
||||
if err != nil {
|
||||
return store.User{}, errors.Wrap(err, "can't extract user info from the token")
|
||||
return store.User{}, fmt.Errorf("can't extract user info from the token: %w", err)
|
||||
}
|
||||
|
||||
return store.User{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
@@ -50,7 +50,7 @@ func NewStaticKeyStore(key string) *StaticStore {
|
||||
// Key returns static key, same for all sites
|
||||
func (s *StaticStore) Key(_ string) (key string, err error) {
|
||||
if s.key == "" {
|
||||
return "", errors.New("empty key for static key store")
|
||||
return "", fmt.Errorf("empty key for static key store")
|
||||
}
|
||||
return s.key, nil
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/store"
|
||||
@@ -57,7 +56,7 @@ func NewBoltDB(options bolt.Options, sites ...BoltSite) (*BoltDB, error) {
|
||||
for _, site := range sites {
|
||||
db, err := bolt.Open(site.FileName, 0o600, &options) //nolint:gocritic //octalLiteral is OK as FileMode
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to make boltdb for %s", site.FileName)
|
||||
return nil, fmt.Errorf("failed to make boltdb for %s: %w", site.FileName, err)
|
||||
}
|
||||
|
||||
// make top-level buckets
|
||||
@@ -66,14 +65,14 @@ func NewBoltDB(options bolt.Options, sites ...BoltSite) (*BoltDB, error) {
|
||||
err = db.Update(func(tx *bolt.Tx) error {
|
||||
for _, bktName := range topBuckets {
|
||||
if _, e := tx.CreateBucketIfNotExists([]byte(bktName)); e != nil {
|
||||
return errors.Wrapf(e, "failed to create top level bucket %s", bktName)
|
||||
return fmt.Errorf("failed to create top level bucket %s: %w", bktName, e)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to create top level bucket)")
|
||||
return nil, fmt.Errorf("failed to create top level bucket): %w", err)
|
||||
}
|
||||
|
||||
result.dbs[site.SiteID] = db
|
||||
@@ -90,7 +89,7 @@ func (b *BoltDB) Create(comment store.Comment) (commentID string, err error) {
|
||||
}
|
||||
|
||||
if b.checkFlag(FlagRequest{Locator: comment.Locator, Flag: ReadOnly}) {
|
||||
return "", errors.Errorf("post %s is read-only", comment.Locator.URL)
|
||||
return "", fmt.Errorf("post %s is read-only", comment.Locator.URL)
|
||||
}
|
||||
|
||||
err = bdb.Update(func(tx *bolt.Tx) (err error) {
|
||||
@@ -101,12 +100,12 @@ func (b *BoltDB) Create(comment store.Comment) (commentID string, err error) {
|
||||
}
|
||||
// check if key already in store, reject doubles
|
||||
if postBkt.Get([]byte(comment.ID)) != nil {
|
||||
return errors.Errorf("key %s already in store", comment.ID)
|
||||
return fmt.Errorf("key %s already in store", comment.ID)
|
||||
}
|
||||
|
||||
// serialize comment to json []byte for bolt and save
|
||||
if err = b.save(postBkt, comment.ID, comment); err != nil {
|
||||
return errors.Wrapf(err, "failed to put key %s to bucket %s", comment.ID, comment.Locator.URL)
|
||||
return fmt.Errorf("failed to put key %s to bucket %s: %w", comment.ID, comment.Locator.URL, err)
|
||||
}
|
||||
|
||||
ref := b.makeRef(comment) // reference combines url and comment id
|
||||
@@ -115,21 +114,21 @@ func (b *BoltDB) Create(comment store.Comment) (commentID string, err error) {
|
||||
lastBkt = tx.Bucket([]byte(lastBucketName))
|
||||
commentTS := []byte(comment.Timestamp.Format(tsNano))
|
||||
if err = lastBkt.Put(commentTS, ref); err != nil {
|
||||
return errors.Wrapf(err, "can't put reference %s to %s", ref, lastBucketName)
|
||||
return fmt.Errorf("can't put reference %s to %s: %w", ref, lastBucketName, err)
|
||||
}
|
||||
|
||||
// add reference to commentID to "users" bucket
|
||||
if userBkt, err = b.getUserBucket(tx, comment.User.ID); err != nil {
|
||||
return errors.Wrapf(err, "can't get bucket %s", comment.User.ID)
|
||||
return fmt.Errorf("can't get bucket %s: %w", comment.User.ID, err)
|
||||
}
|
||||
// put into individual user's bucket with ts as a key
|
||||
if err = userBkt.Put(commentTS, ref); err != nil {
|
||||
return errors.Wrapf(err, "failed to put user comment %s for %s", comment.ID, comment.User.ID)
|
||||
return fmt.Errorf("failed to put user comment %s for %s: %w", comment.ID, comment.User.ID, err)
|
||||
}
|
||||
|
||||
// set info with the count for post url
|
||||
if _, err = b.setInfo(tx, comment); err != nil {
|
||||
return errors.Wrapf(err, "failed to set info for %s", comment.Locator)
|
||||
return fmt.Errorf("failed to set info for %s: %w", comment.Locator, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -174,7 +173,7 @@ func (b *BoltDB) Find(req FindRequest) (comments []store.Comment, err error) {
|
||||
return bucket.ForEach(func(k, v []byte) error {
|
||||
comment := store.Comment{}
|
||||
if e = json.Unmarshal(v, &comment); e != nil {
|
||||
return errors.Wrap(e, "failed to unmarshal")
|
||||
return fmt.Errorf("failed to unmarshal: %w", e)
|
||||
}
|
||||
if req.Since.IsZero() || comment.Timestamp.After(req.Since) {
|
||||
comments = append(comments, comment)
|
||||
@@ -211,7 +210,7 @@ func (b *BoltDB) UserDetail(req UserDetailRequest) ([]UserDetailEntry, error) {
|
||||
switch req.Detail {
|
||||
case UserEmail, UserTelegram:
|
||||
if req.UserID == "" {
|
||||
return nil, errors.New("userid cannot be empty in request for single detail")
|
||||
return nil, fmt.Errorf("userid cannot be empty in request for single detail")
|
||||
}
|
||||
|
||||
if req.Update == "" { // read detail value, no update requested
|
||||
@@ -225,9 +224,9 @@ func (b *BoltDB) UserDetail(req UserDetailRequest) ([]UserDetailEntry, error) {
|
||||
if req.Update == "" && req.UserID == "" { // read list of all details
|
||||
return b.listDetails(req.Locator)
|
||||
}
|
||||
return nil, errors.New("unsupported request with userdetail all")
|
||||
return nil, fmt.Errorf("unsupported request with userdetail all")
|
||||
default:
|
||||
return nil, errors.Errorf("unsupported detail %q", req.Detail)
|
||||
return nil, fmt.Errorf("unsupported detail %q", req.Detail)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +276,7 @@ func (b *BoltDB) Count(req FindRequest) (count int, err error) {
|
||||
usersBkt := tx.Bucket([]byte(userBucketName))
|
||||
userIDBkt := usersBkt.Bucket([]byte(req.UserID))
|
||||
if userIDBkt == nil {
|
||||
return errors.Errorf("no comments for user %s in store for %s site", req.UserID, req.Locator.SiteID)
|
||||
return fmt.Errorf("no comments for user %s in store for %s site", req.UserID, req.Locator.SiteID)
|
||||
}
|
||||
stats := userIDBkt.Stats()
|
||||
count = stats.KeyN
|
||||
@@ -286,7 +285,7 @@ func (b *BoltDB) Count(req FindRequest) (count int, err error) {
|
||||
return count, err
|
||||
}
|
||||
|
||||
return 0, errors.Errorf("invalid count request %+v", req)
|
||||
return 0, fmt.Errorf("invalid count request %+v", req)
|
||||
}
|
||||
|
||||
// Info get post(s) meta info
|
||||
@@ -301,7 +300,7 @@ func (b *BoltDB) Info(req InfoRequest) ([]store.PostInfo, error) {
|
||||
err = bdb.View(func(tx *bolt.Tx) error {
|
||||
infoBkt := tx.Bucket([]byte(infoBucketName))
|
||||
if e := b.load(infoBkt, req.Locator.URL, &info); e != nil {
|
||||
return errors.Wrapf(e, "can't load info for %s", req.Locator.URL)
|
||||
return fmt.Errorf("can't load info for %s: %w", req.Locator.URL, e)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -331,7 +330,7 @@ func (b *BoltDB) Info(req InfoRequest) ([]store.PostInfo, error) {
|
||||
infoBkt := tx.Bucket([]byte(infoBucketName))
|
||||
info := store.PostInfo{}
|
||||
if e := b.load(infoBkt, postURL, &info); e != nil {
|
||||
return errors.Wrapf(e, "can't load info for %s", postURL)
|
||||
return fmt.Errorf("can't load info for %s: %w", postURL, e)
|
||||
}
|
||||
list = append(list, info)
|
||||
if req.Limit > 0 && len(list) >= req.Limit {
|
||||
@@ -343,7 +342,7 @@ func (b *BoltDB) Info(req InfoRequest) ([]store.PostInfo, error) {
|
||||
return list, err
|
||||
}
|
||||
|
||||
return nil, errors.Errorf("invalid info request %+v", req)
|
||||
return nil, fmt.Errorf("invalid info request %+v", req)
|
||||
}
|
||||
|
||||
// ListFlags get list of flagged keys, like blocked & verified user
|
||||
@@ -372,7 +371,7 @@ func (b *BoltDB) ListFlags(req FlagRequest) (res []interface{}, err error) {
|
||||
return bucket.ForEach(func(k []byte, v []byte) error {
|
||||
ts, errParse := time.ParseInLocation(tsNano, string(v), time.Local)
|
||||
if errParse != nil {
|
||||
return errors.Wrap(errParse, "can't parse block ts")
|
||||
return fmt.Errorf("can't parse block ts: %w", errParse)
|
||||
}
|
||||
if time.Now().Before(ts) {
|
||||
// get user name from comment user section
|
||||
@@ -389,7 +388,7 @@ func (b *BoltDB) ListFlags(req FlagRequest) (res []interface{}, err error) {
|
||||
})
|
||||
return res, err
|
||||
}
|
||||
return nil, errors.Errorf("flag %s not listable", req.Flag)
|
||||
return nil, fmt.Errorf("flag %s not listable", req.Flag)
|
||||
}
|
||||
|
||||
// Delete post(s), user, comment, user details, or everything
|
||||
@@ -410,15 +409,17 @@ func (b *BoltDB) Delete(req DeleteRequest) error {
|
||||
return b.deleteAll(bdb, req.Locator.SiteID)
|
||||
}
|
||||
|
||||
return errors.Errorf("invalid delete request %+v", req)
|
||||
return fmt.Errorf("invalid delete request %+v", req)
|
||||
}
|
||||
|
||||
// Close boltdb store
|
||||
func (b *BoltDB) Close() error {
|
||||
errs := new(multierror.Error)
|
||||
for site, db := range b.dbs {
|
||||
err := errors.Wrapf(db.Close(), "can't close site %s", site)
|
||||
errs = multierror.Append(errs, err)
|
||||
err := db.Close()
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, fmt.Errorf("can't close site %s: %w", site, err))
|
||||
}
|
||||
}
|
||||
return errs.ErrorOrNil()
|
||||
}
|
||||
@@ -496,7 +497,7 @@ func (b *BoltDB) userComments(siteID, userID string, limit, skip int) (comments
|
||||
usersBkt := tx.Bucket([]byte(userBucketName))
|
||||
userIDBkt := usersBkt.Bucket([]byte(userID))
|
||||
if userIDBkt == nil {
|
||||
return errors.Errorf("no comments for user %s in store", userID)
|
||||
return fmt.Errorf("no comments for user %s in store", userID)
|
||||
}
|
||||
|
||||
c := userIDBkt.Cursor()
|
||||
@@ -522,7 +523,7 @@ func (b *BoltDB) userComments(siteID, userID string, limit, skip int) (comments
|
||||
for _, v := range commentRefs {
|
||||
url, commentID, errParse := b.parseRef([]byte(v))
|
||||
if errParse != nil {
|
||||
return comments, errors.Wrapf(errParse, "can't parse reference %s", v)
|
||||
return comments, fmt.Errorf("can't parse reference %s: %w", v, errParse)
|
||||
}
|
||||
getReq := GetRequest{Locator: store.Locator{SiteID: siteID, URL: url}, CommentID: commentID}
|
||||
if c, errRef := b.Get(getReq); errRef == nil {
|
||||
@@ -600,20 +601,20 @@ func (b *BoltDB) setFlag(req FlagRequest) (res bool, err error) {
|
||||
val = time.Now().Add(req.TTL).Format(tsNano)
|
||||
}
|
||||
if e = bucket.Put([]byte(key), []byte(val)); e != nil {
|
||||
return errors.Wrapf(e, "failed to put blocked to %s", key)
|
||||
return fmt.Errorf("failed to put blocked to %s: %w", key, e)
|
||||
}
|
||||
res = true
|
||||
return nil
|
||||
}
|
||||
|
||||
if e = bucket.Put([]byte(key), []byte(time.Now().Format(tsNano))); e != nil {
|
||||
return errors.Wrapf(e, "failed to set flag %s for %s", req.Flag, req.Locator.URL)
|
||||
return fmt.Errorf("failed to set flag %s for %s: %w", req.Flag, req.Locator.URL, e)
|
||||
}
|
||||
res = true
|
||||
return nil
|
||||
case FlagFalse:
|
||||
if e = bucket.Delete([]byte(key)); e != nil {
|
||||
return errors.Wrapf(e, "failed to clean flag %s for %s", req.Flag, req.Locator.URL)
|
||||
return fmt.Errorf("failed to clean flag %s for %s: %w", req.Flag, req.Locator.URL, e)
|
||||
}
|
||||
res = false
|
||||
}
|
||||
@@ -632,7 +633,7 @@ func (b *BoltDB) flagBucket(tx *bolt.Tx, flag Flag) (bkt *bolt.Bucket, err error
|
||||
case Verified:
|
||||
bkt = tx.Bucket([]byte(verifiedBucketName))
|
||||
default:
|
||||
return nil, errors.Errorf("unsupported flag %v", flag)
|
||||
return nil, fmt.Errorf("unsupported flag %v", flag)
|
||||
}
|
||||
return bkt, nil
|
||||
}
|
||||
@@ -652,7 +653,7 @@ func (b *BoltDB) getUserDetail(req UserDetailRequest) (result []UserDetailEntry,
|
||||
// return no error in case of absent entry
|
||||
if value != nil {
|
||||
if err = json.Unmarshal(value, &entry); err != nil {
|
||||
return errors.Wrap(e, "failed to unmarshal entry")
|
||||
return fmt.Errorf("failed to unmarshal entry: %w", e)
|
||||
}
|
||||
switch req.Detail {
|
||||
case UserEmail:
|
||||
@@ -682,7 +683,7 @@ func (b *BoltDB) setUserDetail(req UserDetailRequest) (result []UserDetailEntry,
|
||||
// return no error in case of absent entry
|
||||
if value != nil {
|
||||
if err = json.Unmarshal(value, &entry); err != nil {
|
||||
return errors.Wrap(e, "failed to unmarshal entry")
|
||||
return fmt.Errorf("failed to unmarshal entry: %w", e)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -705,7 +706,10 @@ func (b *BoltDB) setUserDetail(req UserDetailRequest) (result []UserDetailEntry,
|
||||
|
||||
err = bdb.Update(func(tx *bolt.Tx) error {
|
||||
err = b.save(tx.Bucket([]byte(userDetailsBucketName)), req.UserID, entry)
|
||||
return errors.Wrapf(err, "failed to update detail %s for %s in %s", req.Detail, req.UserID, req.Locator.SiteID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update detail %s for %s in %s: %w", req.Detail, req.UserID, req.Locator.SiteID, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return []UserDetailEntry{entry}, err
|
||||
@@ -723,7 +727,7 @@ func (b *BoltDB) listDetails(loc store.Locator) (result []UserDetailEntry, err e
|
||||
bucket := tx.Bucket([]byte(userDetailsBucketName))
|
||||
return bucket.ForEach(func(userID, value []byte) error {
|
||||
if err = json.Unmarshal(value, &entry); err != nil {
|
||||
return errors.Wrap(e, "failed to unmarshal entry")
|
||||
return fmt.Errorf("failed to unmarshal entry: %w", e)
|
||||
}
|
||||
result = append(result, entry)
|
||||
return nil
|
||||
@@ -741,7 +745,7 @@ func (b *BoltDB) deleteUserDetail(bdb *bolt.DB, userID string, userDetail UserDe
|
||||
// return no error in case of absent entry
|
||||
if value != nil {
|
||||
if err := json.Unmarshal(value, &entry); err != nil {
|
||||
return errors.Wrap(err, "failed to unmarshal entry")
|
||||
return fmt.Errorf("failed to unmarshal entry: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -768,14 +772,20 @@ func (b *BoltDB) deleteUserDetail(bdb *bolt.DB, userID string, userDetail UserDe
|
||||
// if entry doesn't have non-empty details, we should delete it
|
||||
return bdb.Update(func(tx *bolt.Tx) error {
|
||||
err := tx.Bucket([]byte(userDetailsBucketName)).Delete([]byte(userID))
|
||||
return errors.Wrapf(err, "failed to delete user detail %s for %s", userDetail, userID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete user detail %s for %s: %w", userDetail, userID, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return bdb.Update(func(tx *bolt.Tx) error {
|
||||
// updated entry is not empty and we need to store it's updated copy
|
||||
err := b.save(tx.Bucket([]byte(userDetailsBucketName)), userID, entry)
|
||||
return errors.Wrapf(err, "failed to update detail %s for %s", userDetail, userID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update detail %s for %s: %w", userDetail, userID, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -788,13 +798,13 @@ func (b *BoltDB) deleteComment(bdb *bolt.DB, locator store.Locator, commentID st
|
||||
|
||||
comment := store.Comment{}
|
||||
if e = b.load(postBkt, commentID, &comment); e != nil {
|
||||
return errors.Wrapf(e, "can't load key %s from bucket %s", commentID, locator.URL)
|
||||
return fmt.Errorf("can't load key %s from bucket %s: %w", commentID, locator.URL, e)
|
||||
}
|
||||
|
||||
if !comment.Deleted {
|
||||
// decrement comments count for post url
|
||||
if _, e = b.count(tx, comment.Locator.URL, -1); e != nil {
|
||||
return errors.Wrapf(e, "failed to decrement count for %s", comment.Locator)
|
||||
return fmt.Errorf("failed to decrement count for %s: %w", comment.Locator, e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -802,13 +812,13 @@ func (b *BoltDB) deleteComment(bdb *bolt.DB, locator store.Locator, commentID st
|
||||
comment.SetDeleted(mode)
|
||||
|
||||
if e = b.save(postBkt, commentID, comment); e != nil {
|
||||
return errors.Wrapf(e, "can't save deleted comment for key %s from bucket %s", commentID, locator.URL)
|
||||
return fmt.Errorf("can't save deleted comment for key %s from bucket %s: %w", commentID, locator.URL, e)
|
||||
}
|
||||
|
||||
// delete from "last" bucket
|
||||
lastBkt := tx.Bucket([]byte(lastBucketName))
|
||||
if e = lastBkt.Delete([]byte(commentID)); e != nil {
|
||||
return errors.Wrapf(e, "can't delete key %s from bucket %s", commentID, lastBucketName)
|
||||
return fmt.Errorf("can't delete key %s from bucket %s: %w", commentID, lastBucketName, e)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -824,16 +834,19 @@ func (b *BoltDB) deleteAll(bdb *bolt.DB, siteID string) error {
|
||||
err := bdb.Update(func(tx *bolt.Tx) error {
|
||||
for _, bktName := range toDelete {
|
||||
if e := tx.DeleteBucket([]byte(bktName)); e != nil {
|
||||
return errors.Wrapf(e, "failed to delete top level bucket %s", bktName)
|
||||
return fmt.Errorf("failed to delete top level bucket %s: %w", bktName, e)
|
||||
}
|
||||
if _, e := tx.CreateBucketIfNotExists([]byte(bktName)); e != nil {
|
||||
return errors.Wrapf(e, "failed to create top level bucket %s", bktName)
|
||||
return fmt.Errorf("failed to create top level bucket %s: %w", bktName, e)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return errors.Wrapf(err, "failed to delete top level buckets from site %s", siteID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete top level buckets from site %s: %w", siteID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// deleteUser removes all comments and details for given user. Everything will be market as deleted
|
||||
@@ -860,14 +873,17 @@ func (b *BoltDB) deleteUser(bdb *bolt.DB, siteID, userID string, mode store.Dele
|
||||
err = postBkt.ForEach(func(postURL []byte, commentVal []byte) error {
|
||||
comment := store.Comment{}
|
||||
if err = json.Unmarshal(commentVal, &comment); err != nil {
|
||||
return errors.Wrap(err, "failed to unmarshal")
|
||||
return fmt.Errorf("failed to unmarshal: %w", err)
|
||||
}
|
||||
if comment.User.ID == userID {
|
||||
comments = append(comments, commentInfo{locator: comment.Locator, commentID: comment.ID})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return errors.Wrapf(err, "failed to collect list of comments for deletion from %s", postInfo.URL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to collect list of comments for deletion from %s: %w", postInfo.URL, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -879,7 +895,7 @@ func (b *BoltDB) deleteUser(bdb *bolt.DB, siteID, userID string, mode store.Dele
|
||||
// delete collected comments
|
||||
for _, ci := range comments {
|
||||
if e := b.deleteComment(bdb, ci.locator, ci.commentID, mode); e != nil {
|
||||
return errors.Wrapf(err, "failed to delete comment %+v", ci)
|
||||
return fmt.Errorf("failed to delete comment %+v: %w", ci, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -889,19 +905,19 @@ func (b *BoltDB) deleteUser(bdb *bolt.DB, siteID, userID string, mode store.Dele
|
||||
usersBkt := tx.Bucket([]byte(userBucketName))
|
||||
if usersBkt != nil {
|
||||
if e := usersBkt.DeleteBucket([]byte(userID)); e != nil {
|
||||
return errors.Wrapf(err, "failed to delete user bucket for %s", userID)
|
||||
return fmt.Errorf("failed to delete user bucket for %s: %w", userID, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "can't delete user meta")
|
||||
return fmt.Errorf("can't delete user meta: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(comments) == 0 {
|
||||
return errors.Errorf("unknown user %s", userID)
|
||||
return fmt.Errorf("unknown user %s", userID)
|
||||
}
|
||||
|
||||
return b.deleteUserDetail(bdb, userID, AllUserDetails)
|
||||
@@ -911,11 +927,11 @@ func (b *BoltDB) deleteUser(bdb *bolt.DB, siteID, userID string, mode store.Dele
|
||||
func (b *BoltDB) getPostBucket(tx *bolt.Tx, postURL string) (*bolt.Bucket, error) {
|
||||
postsBkt := tx.Bucket([]byte(postsBucketName))
|
||||
if postsBkt == nil {
|
||||
return nil, errors.Errorf("no bucket %s", postsBucketName)
|
||||
return nil, fmt.Errorf("no bucket %s", postsBucketName)
|
||||
}
|
||||
res := postsBkt.Bucket([]byte(postURL))
|
||||
if res == nil {
|
||||
return nil, errors.Errorf("no bucket %s in store", postURL)
|
||||
return nil, fmt.Errorf("no bucket %s in store", postURL)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
@@ -924,11 +940,11 @@ func (b *BoltDB) getPostBucket(tx *bolt.Tx, postURL string) (*bolt.Bucket, error
|
||||
func (b *BoltDB) makePostBucket(tx *bolt.Tx, postURL string) (*bolt.Bucket, error) {
|
||||
postsBkt := tx.Bucket([]byte(postsBucketName))
|
||||
if postsBkt == nil {
|
||||
return nil, errors.Errorf("no bucket %s", postsBucketName)
|
||||
return nil, fmt.Errorf("no bucket %s", postsBucketName)
|
||||
}
|
||||
res, err := postsBkt.CreateBucketIfNotExists([]byte(postURL))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "no bucket %s in store", postURL)
|
||||
return nil, fmt.Errorf("no bucket %s in store: %w", postURL, err)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
@@ -937,7 +953,7 @@ func (b *BoltDB) getUserBucket(tx *bolt.Tx, userID string) (*bolt.Bucket, error)
|
||||
usersBkt := tx.Bucket([]byte(userBucketName))
|
||||
userIDBkt, e := usersBkt.CreateBucketIfNotExists([]byte(userID)) // get bucket for userID
|
||||
if e != nil {
|
||||
return nil, errors.Wrapf(e, "can't get bucket %s", userID)
|
||||
return nil, fmt.Errorf("can't get bucket %s: %w", userID, e)
|
||||
}
|
||||
return userIDBkt, nil
|
||||
}
|
||||
@@ -945,14 +961,14 @@ func (b *BoltDB) getUserBucket(tx *bolt.Tx, userID string) (*bolt.Bucket, error)
|
||||
// save marshaled value to key for bucket. Should run in update tx
|
||||
func (b *BoltDB) save(bkt *bolt.Bucket, key string, value interface{}) (err error) {
|
||||
if value == nil {
|
||||
return errors.Errorf("can't save nil value for %s", key)
|
||||
return fmt.Errorf("can't save nil value for %s", key)
|
||||
}
|
||||
jdata, jerr := json.Marshal(value)
|
||||
if jerr != nil {
|
||||
return errors.Wrap(jerr, "can't marshal comment")
|
||||
return fmt.Errorf("can't marshal comment: %w", jerr)
|
||||
}
|
||||
if err = bkt.Put([]byte(key), jdata); err != nil {
|
||||
return errors.Wrapf(err, "failed to save key %s", key)
|
||||
return fmt.Errorf("failed to save key %s: %w", key, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -961,11 +977,11 @@ func (b *BoltDB) save(bkt *bolt.Bucket, key string, value interface{}) (err erro
|
||||
func (b *BoltDB) load(bkt *bolt.Bucket, key string, res interface{}) error {
|
||||
value := bkt.Get([]byte(key))
|
||||
if value == nil {
|
||||
return errors.Errorf("no value for %s", key)
|
||||
return fmt.Errorf("no value for %s", key)
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(value, &res); err != nil {
|
||||
return errors.Wrap(err, "failed to unmarshal")
|
||||
return fmt.Errorf("failed to unmarshal: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1008,7 +1024,7 @@ func (b *BoltDB) db(siteID string) (*bolt.DB, error) {
|
||||
if res, ok := b.dbs[siteID]; ok {
|
||||
return res, nil
|
||||
}
|
||||
return nil, errors.Errorf("site %q not found", siteID)
|
||||
return nil, fmt.Errorf("site %q not found", siteID)
|
||||
}
|
||||
|
||||
// makeRef creates reference combining url and comment id
|
||||
@@ -1020,7 +1036,7 @@ func (b *BoltDB) makeRef(comment store.Comment) []byte {
|
||||
func (b *BoltDB) parseRef(val []byte) (url, id string, err error) {
|
||||
elems := strings.Split(string(val), "!!")
|
||||
if len(elems) != 2 {
|
||||
return "", "", errors.Errorf("invalid reference value %s", string(val))
|
||||
return "", "", fmt.Errorf("invalid reference value %s", string(val))
|
||||
}
|
||||
return elems[0], elems[1], nil
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
@@ -27,23 +27,23 @@ type Bolt struct {
|
||||
func NewBoltStorage(fileName string, options bolt.Options) (*Bolt, error) {
|
||||
db, err := bolt.Open(fileName, 0o600, &options) //nolint:gocritic //octalLiteral is OK as FileMode
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to make boltdb for %s", fileName)
|
||||
return nil, fmt.Errorf("failed to make boltdb for %s: %w", fileName, err)
|
||||
}
|
||||
|
||||
err = db.Update(func(tx *bolt.Tx) error {
|
||||
if _, e := tx.CreateBucketIfNotExists([]byte(imagesBktName)); e != nil {
|
||||
return errors.Wrapf(e, "failed to create top level bucket %s", imagesBktName)
|
||||
return fmt.Errorf("failed to create top level bucket %s: %w", imagesBktName, e)
|
||||
}
|
||||
if _, e := tx.CreateBucketIfNotExists([]byte(imagesStagedBktName)); e != nil {
|
||||
return errors.Wrapf(e, "failed to create top level bucket %s", imagesStagedBktName)
|
||||
return fmt.Errorf("failed to create top level bucket %s: %w", imagesStagedBktName, e)
|
||||
}
|
||||
if _, e := tx.CreateBucketIfNotExists([]byte(insertTimeBktName)); e != nil {
|
||||
return errors.Wrapf(e, "failed to create top level bucket %s", insertTimeBktName)
|
||||
return fmt.Errorf("failed to create top level bucket %s: %w", insertTimeBktName, e)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to initialize boltdb db %q buckets", fileName)
|
||||
return nil, fmt.Errorf("failed to initialize boltdb db %q buckets: %w", fileName, err)
|
||||
}
|
||||
return &Bolt{
|
||||
db: db,
|
||||
@@ -55,14 +55,14 @@ func NewBoltStorage(fileName string, options bolt.Options) (*Bolt, error) {
|
||||
func (b *Bolt) Save(id string, img []byte) error {
|
||||
return b.db.Update(func(tx *bolt.Tx) error {
|
||||
if err := tx.Bucket([]byte(imagesStagedBktName)).Put([]byte(id), img); err != nil {
|
||||
return errors.Wrapf(err, "can't put to bucket with %s", id)
|
||||
return fmt.Errorf("can't put to bucket with %s: %w", id, err)
|
||||
}
|
||||
tsBuf := &bytes.Buffer{}
|
||||
if err := binary.Write(tsBuf, binary.LittleEndian, time.Now().UnixNano()); err != nil {
|
||||
return errors.Wrapf(err, "can't serialize timestamp for %s", id)
|
||||
return fmt.Errorf("can't serialize timestamp for %s: %w", id, err)
|
||||
}
|
||||
if err := tx.Bucket([]byte(insertTimeBktName)).Put([]byte(id), tsBuf.Bytes()); err != nil {
|
||||
return errors.Wrapf(err, "can't put to bucket with %s", id)
|
||||
return fmt.Errorf("can't put to bucket with %s: %w", id, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -74,10 +74,13 @@ func (b *Bolt) Commit(id string) error {
|
||||
return b.db.Update(func(tx *bolt.Tx) error {
|
||||
data := tx.Bucket([]byte(imagesStagedBktName)).Get([]byte(id))
|
||||
if data == nil {
|
||||
return errors.Errorf("failed to commit %s, not found in staging", id)
|
||||
return fmt.Errorf("failed to commit %s, not found in staging", id)
|
||||
}
|
||||
err := tx.Bucket([]byte(imagesBktName)).Put([]byte(id), data)
|
||||
return errors.Wrapf(err, "can't put to bucket with %s", id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't put to bucket with %s: %w", id, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -86,10 +89,10 @@ func (b *Bolt) ResetCleanupTimer(id string) error {
|
||||
return b.db.Update(func(tx *bolt.Tx) error {
|
||||
tsBuf := &bytes.Buffer{}
|
||||
if err := binary.Write(tsBuf, binary.LittleEndian, time.Now().UnixNano()); err != nil {
|
||||
return errors.Wrapf(err, "can't serialize timestamp for %s", id)
|
||||
return fmt.Errorf("can't serialize timestamp for %s: %w", id, err)
|
||||
}
|
||||
if err := tx.Bucket([]byte(insertTimeBktName)).Put([]byte(id), tsBuf.Bytes()); err != nil {
|
||||
return errors.Wrapf(err, "can't put to bucket with %s", id)
|
||||
return fmt.Errorf("can't put to bucket with %s: %w", id, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -104,7 +107,7 @@ func (b *Bolt) Load(id string) ([]byte, error) {
|
||||
data = tx.Bucket([]byte(imagesStagedBktName)).Get([]byte(id))
|
||||
}
|
||||
if data == nil {
|
||||
return errors.Errorf("can't load image %s", id)
|
||||
return fmt.Errorf("can't load image %s", id)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -126,7 +129,7 @@ func (b *Bolt) Cleanup(_ context.Context, ttl time.Duration) error {
|
||||
var ts int64
|
||||
err := binary.Read(bytes.NewReader(tsData), binary.LittleEndian, &ts)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to deserialize timestamp for %s", id)
|
||||
return fmt.Errorf("failed to deserialize timestamp for %s: %w", id, err)
|
||||
}
|
||||
|
||||
age := time.Since(time.Unix(0, ts))
|
||||
@@ -136,7 +139,7 @@ func (b *Bolt) Cleanup(_ context.Context, ttl time.Duration) error {
|
||||
idsToRemove = append(idsToRemove, id)
|
||||
err := c.Delete()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to remove timestamp for %s", id)
|
||||
return fmt.Errorf("failed to remove timestamp for %s: %w", id, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,7 +147,7 @@ func (b *Bolt) Cleanup(_ context.Context, ttl time.Duration) error {
|
||||
for _, id := range idsToRemove {
|
||||
err := imgBkt.Delete(id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to remove image for %s", id)
|
||||
return fmt.Errorf("failed to remove image for %s: %w", id, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -161,7 +164,7 @@ func (b *Bolt) Info() (StoreInfo, error) {
|
||||
var createdRaw int64
|
||||
err := binary.Read(bytes.NewReader(tsData), binary.LittleEndian, &createdRaw)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to deserialize timestamp for %s", id)
|
||||
return fmt.Errorf("failed to deserialize timestamp for %s: %w", id, err)
|
||||
}
|
||||
|
||||
created := time.Unix(0, createdRaw)
|
||||
@@ -171,5 +174,8 @@ func (b *Bolt) Info() (StoreInfo, error) {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return StoreInfo{FirstStagingImageTS: ts}, errors.Wrapf(err, "problem retrieving first timestamp from staging images")
|
||||
if err != nil {
|
||||
return StoreInfo{}, fmt.Errorf("problem retrieving first timestamp from staging images: %w", err)
|
||||
}
|
||||
return StoreInfo{FirstStagingImageTS: ts}, nil
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"time"
|
||||
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// FileSystem provides image Store for local files. Saves and loads files from Location, restricts max size.
|
||||
@@ -38,11 +37,11 @@ func (f *FileSystem) Save(id string, img []byte) error {
|
||||
dst := f.location(f.Staging, id)
|
||||
|
||||
if err := os.MkdirAll(path.Dir(dst), 0o700); err != nil {
|
||||
return errors.Wrap(err, "can't make image directory")
|
||||
return fmt.Errorf("can't make image directory: %w", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(dst, img, 0o600); err != nil {
|
||||
return errors.Wrapf(err, "can't write image file with id %s", id)
|
||||
return fmt.Errorf("can't write image file with id %s: %w", id, err)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] file %s saved for image %s, size=%d", dst, id, len(img))
|
||||
@@ -55,11 +54,13 @@ func (f *FileSystem) Commit(id string) error {
|
||||
stagingImage, permImage := f.location(f.Staging, id), f.location(f.Location, id)
|
||||
|
||||
if err := os.MkdirAll(path.Dir(permImage), 0o700); err != nil {
|
||||
return errors.Wrap(err, "can't make image directory")
|
||||
return fmt.Errorf("can't make image directory: %w", err)
|
||||
}
|
||||
|
||||
err := os.Rename(stagingImage, permImage)
|
||||
return errors.Wrapf(err, "failed to commit image %s", id)
|
||||
if err := os.Rename(stagingImage, permImage); err != nil {
|
||||
return fmt.Errorf("failed to commit image %s: %w", id, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetCleanupTimer resets cleanup timer for the image
|
||||
@@ -67,13 +68,15 @@ func (f *FileSystem) ResetCleanupTimer(id string) error {
|
||||
file := f.location(f.Staging, id)
|
||||
_, err := os.Stat(file)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "can't get image stats for %s", id)
|
||||
return fmt.Errorf("can't get image stats for %s: %w", id, err)
|
||||
}
|
||||
// we don't need to update access time (second arg),
|
||||
// but reading it is platform-dependent and looks different on darwin and linux,
|
||||
// so it's easier to update it as well
|
||||
err = os.Chtimes(file, time.Now(), time.Now())
|
||||
return errors.Wrapf(err, "problem updating %s modification time", file)
|
||||
if err = os.Chtimes(file, time.Now(), time.Now()); err != nil {
|
||||
return fmt.Errorf("problem updating %s modification time: %w", file, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load image from FS. Uses id to get partition subdirectory.
|
||||
@@ -86,17 +89,20 @@ func (f *FileSystem) Load(id string) ([]byte, error) {
|
||||
file = f.location(f.Staging, id)
|
||||
_, err = os.Stat(file)
|
||||
}
|
||||
return file, errors.Wrapf(err, "can't get image stats for %s", id)
|
||||
if err != nil {
|
||||
return file, fmt.Errorf("can't get image stats for %s: %w", id, err)
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
imgFile, err := img(id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't get image file for %s", id)
|
||||
return nil, fmt.Errorf("can't get image file for %s: %w", id, err)
|
||||
}
|
||||
|
||||
fh, err := os.Open(imgFile) //nolint:gosec // we open file from known location
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't load image %s", id)
|
||||
return nil, fmt.Errorf("can't load image %s: %w", id, err)
|
||||
}
|
||||
return io.ReadAll(fh)
|
||||
}
|
||||
@@ -124,7 +130,10 @@ func (f *FileSystem) Cleanup(_ context.Context, ttl time.Duration) error {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return errors.Wrap(err, "failed to cleanup images")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to cleanup images: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Info returns meta information about storage
|
||||
@@ -149,7 +158,7 @@ func (f *FileSystem) Info() (StoreInfo, error) {
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return StoreInfo{}, errors.Wrapf(err, "problem retrieving first timestamp from staging images on fs")
|
||||
return StoreInfo{}, fmt.Errorf("problem retrieving first timestamp from staging images on fs: %w", err)
|
||||
}
|
||||
return StoreInfo{FirstStagingImageTS: ts}, nil
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/xid"
|
||||
"golang.org/x/image/draw"
|
||||
)
|
||||
@@ -97,7 +96,7 @@ func (s *Service) SubmitAndCommit(idsFn func() []string) error {
|
||||
for _, id := range idsFn() {
|
||||
err := s.store.Commit(id)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, errors.Wrapf(err, "failed to commit image %s", id))
|
||||
errs = multierror.Append(errs, fmt.Errorf("failed to commit image %s: %w", id, err))
|
||||
}
|
||||
}
|
||||
return errs.ErrorOrNil()
|
||||
@@ -269,7 +268,7 @@ func (s *Service) ImgContentType(img []byte) string {
|
||||
func (s *Service) prepareImage(r io.Reader) ([]byte, error) {
|
||||
data, err := readAndValidateImage(r, s.MaxSize)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't load image")
|
||||
return nil, fmt.Errorf("can't load image: %w", err)
|
||||
}
|
||||
|
||||
data = resize(data, s.MaxWidth, s.MaxHeight)
|
||||
@@ -343,12 +342,12 @@ func readAndValidateImage(r io.Reader, maxSize int) ([]byte, error) {
|
||||
}
|
||||
|
||||
if len(data) > maxSize {
|
||||
return nil, errors.Errorf("file is too large (limit=%d)", maxSize)
|
||||
return nil, fmt.Errorf("file is too large (limit=%d)", maxSize)
|
||||
}
|
||||
|
||||
// read header first, needs it to check if data is valid png/gif/jpeg
|
||||
if !isValidImage(data[:512]) {
|
||||
return nil, errors.Errorf("file format not allowed")
|
||||
return nil, fmt.Errorf("file format not allowed")
|
||||
}
|
||||
|
||||
return data, nil
|
||||
@@ -372,7 +371,7 @@ func Sha1Str(s string) string {
|
||||
func CachedImgID(imgURL string) (string, error) {
|
||||
parsedURL, err := url.Parse(imgURL)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "can parse url %s", imgURL)
|
||||
return "", fmt.Errorf("can parse url %s: %w", imgURL, err)
|
||||
}
|
||||
return fmt.Sprintf("cached_images/%s-%s", Sha1Str(parsedURL.Hostname()), Sha1Str(imgURL)), nil
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -13,7 +14,6 @@ import (
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark42/backend/app/store"
|
||||
"github.com/umputun/remark42/backend/app/store/admin"
|
||||
@@ -77,12 +77,12 @@ const UnlimitedVotes = -1
|
||||
var nonAdminUser = store.User{}
|
||||
|
||||
// ErrRestrictedWordsFound returned in case comment text contains restricted words
|
||||
var ErrRestrictedWordsFound = errors.New("comment contains restricted words")
|
||||
var ErrRestrictedWordsFound = fmt.Errorf("comment contains restricted words")
|
||||
|
||||
// Create prepares comment and forward to Interface.Create
|
||||
func (s *DataStore) Create(comment store.Comment) (commentID string, err error) {
|
||||
if comment, err = s.prepareNewComment(comment); err != nil {
|
||||
return "", errors.Wrap(err, "failed to prepare comment")
|
||||
return "", fmt.Errorf("failed to prepare comment: %w", err)
|
||||
}
|
||||
|
||||
if s.RestrictedWordsMatcher != nil && s.RestrictedWordsMatcher.Match(comment.Locator.SiteID, comment.Text) {
|
||||
@@ -250,7 +250,9 @@ func (s *DataStore) ResubmitStagingImages(sites []string) error {
|
||||
for _, site := range sites {
|
||||
locator := store.Locator{SiteID: site}
|
||||
comments, err := s.FindSince(locator, "time", store.User{}, ts)
|
||||
result = multierror.Append(result, errors.Wrapf(err, "problem finding comments for site %s", site))
|
||||
if err != nil {
|
||||
result = multierror.Append(result, fmt.Errorf("problem finding comments for site %s: %w", site, err))
|
||||
}
|
||||
for _, c := range comments {
|
||||
s.submitImages(c)
|
||||
}
|
||||
@@ -303,7 +305,7 @@ func (s *DataStore) prepareNewComment(comment store.Comment) (store.Comment, err
|
||||
|
||||
secret, err := s.getSecret(comment.Locator.SiteID)
|
||||
if err != nil {
|
||||
return store.Comment{}, errors.Wrapf(err, "can't get secret for site %s", comment.Locator.SiteID)
|
||||
return store.Comment{}, fmt.Errorf("can't get secret for site %s: %w", comment.Locator.SiteID, err)
|
||||
}
|
||||
comment.User.HashIP(secret) // replace ip by hash
|
||||
return comment, nil
|
||||
@@ -347,7 +349,7 @@ func (s *DataStore) Vote(req VoteReq) (comment store.Comment, err error) {
|
||||
}
|
||||
|
||||
if comment.User.ID == req.UserID && req.UserID != "dev" {
|
||||
return comment, errors.Errorf("user %s can not vote for his own comment %s", req.UserID, req.CommentID)
|
||||
return comment, fmt.Errorf("user %s can not vote for his own comment %s", req.UserID, req.CommentID)
|
||||
}
|
||||
|
||||
if comment.Votes == nil {
|
||||
@@ -356,16 +358,16 @@ func (s *DataStore) Vote(req VoteReq) (comment store.Comment, err error) {
|
||||
|
||||
v, voted := comment.Votes[req.UserID]
|
||||
if voted && v == req.Val { // voted before and same vote (+/-) again. Change allowed, i.e. +, - or -, + is fine
|
||||
return comment, errors.Errorf("user %s already voted for %s", req.UserID, req.CommentID)
|
||||
return comment, fmt.Errorf("user %s already voted for %s", req.UserID, req.CommentID)
|
||||
}
|
||||
|
||||
secret, err := s.getSecret(comment.Locator.SiteID)
|
||||
if err != nil {
|
||||
return store.Comment{}, errors.Wrapf(err, "can't get secret for site %s", comment.Locator.SiteID)
|
||||
return store.Comment{}, fmt.Errorf("can't get secret for site %s: %w", comment.Locator.SiteID, err)
|
||||
}
|
||||
userIPHash := store.HashValue(req.UserIP, secret)
|
||||
if s.isSameIPVote(req, userIPHash, comment) {
|
||||
return comment, errors.Errorf("the same ip %s already voted for %s", userIPHash, req.CommentID)
|
||||
return comment, fmt.Errorf("the same ip %s already voted for %s", userIPHash, req.CommentID)
|
||||
}
|
||||
|
||||
maxVotes := s.MaxVotes // 0 value allowed and treated as "no comments allowed"
|
||||
@@ -374,11 +376,11 @@ func (s *DataStore) Vote(req VoteReq) (comment store.Comment, err error) {
|
||||
}
|
||||
|
||||
if maxVotes >= 0 && len(comment.Votes) >= maxVotes {
|
||||
return comment, errors.Errorf("maximum number of votes exceeded for comment %s", req.CommentID)
|
||||
return comment, fmt.Errorf("maximum number of votes exceeded for comment %s", req.CommentID)
|
||||
}
|
||||
|
||||
if s.PositiveScore && comment.Score <= 0 && !req.Val {
|
||||
return comment, errors.Errorf("minimal score reached for comment %s", req.CommentID)
|
||||
return comment, fmt.Errorf("minimal score reached for comment %s", req.CommentID)
|
||||
}
|
||||
|
||||
// add ip hash to voted ip map
|
||||
@@ -472,12 +474,12 @@ func (s *DataStore) EditComment(locator store.Locator, commentID string, req Edi
|
||||
|
||||
// edit allowed in editDuration window only
|
||||
if s.EditDuration > 0 && time.Now().After(comment.Timestamp.Add(s.EditDuration)) {
|
||||
return errors.Errorf("too late to edit %s", commentID)
|
||||
return fmt.Errorf("too late to edit %s", commentID)
|
||||
}
|
||||
|
||||
// edit rejected on replayed threads
|
||||
if s.HasReplies(comment) {
|
||||
return errors.Errorf("parent comment with reply can't be edited, %s", commentID)
|
||||
return fmt.Errorf("parent comment with reply can't be edited, %s", commentID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -555,7 +557,7 @@ func (s *DataStore) HasReplies(comment store.Comment) bool {
|
||||
func (s *DataStore) UserReplies(siteID, userID string, limit int, duration time.Duration) ([]store.Comment, string, error) {
|
||||
comments, e := s.Last(siteID, maxLastCommentsReply, time.Time{}, nonAdminUser)
|
||||
if e != nil {
|
||||
return nil, "", errors.Wrap(e, "can't get last comments")
|
||||
return nil, "", fmt.Errorf("can't get last comments: %w", e)
|
||||
}
|
||||
replies := []store.Comment{}
|
||||
|
||||
@@ -574,7 +576,7 @@ func (s *DataStore) UserReplies(siteID, userID string, limit int, duration time.
|
||||
if c.ParentID != "" && !c.Deleted && c.User.ID != userID { // not interested in replies to yourself
|
||||
var pc store.Comment
|
||||
if pc, e = s.Get(c.Locator, c.ParentID, nonAdminUser); e != nil {
|
||||
return nil, "", errors.Wrap(e, "can't get parent comment")
|
||||
return nil, "", fmt.Errorf("can't get parent comment: %w", e)
|
||||
}
|
||||
if pc.User.ID == userID {
|
||||
replies = append(replies, c)
|
||||
@@ -588,7 +590,7 @@ func (s *DataStore) UserReplies(siteID, userID string, limit int, duration time.
|
||||
// SetTitle puts title from the locator.URL page and overwrites any existing title
|
||||
func (s *DataStore) SetTitle(locator store.Locator, commentID string) (comment store.Comment, err error) {
|
||||
if s.TitleExtractor == nil {
|
||||
return comment, errors.New("no title extractor")
|
||||
return comment, fmt.Errorf("no title extractor")
|
||||
}
|
||||
|
||||
comment, err = s.Engine.Get(engine.GetRequest{Locator: locator, CommentID: commentID})
|
||||
@@ -626,13 +628,13 @@ func (s *DataStore) ValidateComment(c *store.Comment) error {
|
||||
maxSize = defaultCommentMaxSize
|
||||
}
|
||||
if c.Orig == "" {
|
||||
return errors.New("empty comment text")
|
||||
return fmt.Errorf("empty comment text")
|
||||
}
|
||||
if len([]rune(c.Orig)) > maxSize {
|
||||
return errors.Errorf("comment text exceeded max allowed size %d (%d)", maxSize, len([]rune(c.Orig)))
|
||||
return fmt.Errorf("comment text exceeded max allowed size %d (%d)", maxSize, len([]rune(c.Orig)))
|
||||
}
|
||||
if c.User.ID == "" || c.User.Name == "" {
|
||||
return errors.Errorf("empty user info")
|
||||
return fmt.Errorf("empty user info")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -711,7 +713,7 @@ func (s *DataStore) SetBlock(siteID, userID string, status bool, ttl time.Durati
|
||||
func (s *DataStore) BlockedUsers(siteID string) (res []store.BlockedUser, err error) {
|
||||
blocked, e := s.Engine.ListFlags(engine.FlagRequest{Locator: store.Locator{SiteID: siteID}, Flag: engine.Blocked})
|
||||
if e != nil {
|
||||
return nil, errors.Wrapf(err, "can't get list of blocked users for %s", siteID)
|
||||
return nil, fmt.Errorf("can't get list of blocked users for %s: %w", siteID, err)
|
||||
}
|
||||
for _, v := range blocked {
|
||||
res = append(res, v.(store.BlockedUser))
|
||||
@@ -727,7 +729,7 @@ func (s *DataStore) Info(locator store.Locator, readonlyAge int) (store.PostInfo
|
||||
return store.PostInfo{}, err
|
||||
}
|
||||
if len(res) == 0 {
|
||||
return store.PostInfo{}, errors.Errorf("post %+v not found", locator)
|
||||
return store.PostInfo{}, fmt.Errorf("post %+v not found", locator)
|
||||
}
|
||||
return res[0], nil
|
||||
}
|
||||
@@ -767,7 +769,7 @@ func (s *DataStore) Metas(siteID string) (umetas []UserMetaData, pmetas []PostMe
|
||||
// set posts meta
|
||||
posts, err := s.Engine.Info(engine.InfoRequest{Locator: store.Locator{SiteID: siteID}})
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "can't get list of posts for %s", siteID)
|
||||
return nil, nil, fmt.Errorf("can't get list of posts for %s: %w", siteID, err)
|
||||
}
|
||||
|
||||
for _, p := range posts {
|
||||
@@ -782,7 +784,7 @@ func (s *DataStore) Metas(siteID string) (umetas []UserMetaData, pmetas []PostMe
|
||||
// process blocked users
|
||||
blocked, err := s.BlockedUsers(siteID)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "can't get list of blocked users for %s", siteID)
|
||||
return nil, nil, fmt.Errorf("can't get list of blocked users for %s: %w", siteID, err)
|
||||
}
|
||||
for _, b := range blocked {
|
||||
val, ok := m[b.ID]
|
||||
@@ -797,7 +799,7 @@ func (s *DataStore) Metas(siteID string) (umetas []UserMetaData, pmetas []PostMe
|
||||
// process verified users
|
||||
verified, err := s.Engine.ListFlags(engine.FlagRequest{Locator: store.Locator{SiteID: siteID}, Flag: engine.Verified})
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "can't get list of verified users for %s", siteID)
|
||||
return nil, nil, fmt.Errorf("can't get list of verified users for %s: %w", siteID, err)
|
||||
}
|
||||
for _, vi := range verified {
|
||||
v := vi.(string)
|
||||
@@ -812,7 +814,7 @@ func (s *DataStore) Metas(siteID string) (umetas []UserMetaData, pmetas []PostMe
|
||||
// process users details
|
||||
usersDetails, err := s.Engine.UserDetail(engine.UserDetailRequest{Locator: store.Locator{SiteID: siteID}, Detail: engine.AllUserDetails})
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "can't get user details for %s", siteID)
|
||||
return nil, nil, fmt.Errorf("can't get user details for %s: %w", siteID, err)
|
||||
}
|
||||
for _, entry := range usersDetails {
|
||||
val, ok := m[entry.UserID]
|
||||
@@ -982,15 +984,15 @@ func (s *DataStore) prepVotes(c store.Comment, user store.User) store.Comment {
|
||||
// Note: secret shared across sites, but some sites can be disabled.
|
||||
func (s *DataStore) getSecret(siteID string) (secret string, err error) {
|
||||
if secret, err = s.AdminStore.Key("any"); err != nil {
|
||||
return "", errors.Wrapf(err, "can't get secret for site %s", siteID)
|
||||
return "", fmt.Errorf("can't get secret for site %s: %w", siteID, err)
|
||||
}
|
||||
|
||||
ok, err := s.AdminStore.Enabled(siteID)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "can't check secret enabled for site %s", siteID)
|
||||
return "", fmt.Errorf("can't check secret enabled for site %s: %w", siteID, err)
|
||||
}
|
||||
if !ok {
|
||||
return "", errors.Errorf("site %s disabled", siteID)
|
||||
return "", fmt.Errorf("site %s disabled", siteID)
|
||||
}
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
@@ -754,10 +753,10 @@ func TestService_ValidateComment(t *testing.T) {
|
||||
inp store.Comment
|
||||
err error
|
||||
}{
|
||||
{inp: store.Comment{}, err: errors.New("empty comment text")},
|
||||
{inp: store.Comment{}, err: fmt.Errorf("empty comment text")},
|
||||
{inp: store.Comment{Orig: "something blah", User: store.User{ID: "myid", Name: "name"}}, err: nil},
|
||||
{inp: store.Comment{Orig: "something blah", User: store.User{ID: "myid"}}, err: errors.New("empty user info")},
|
||||
{inp: store.Comment{Orig: longText, User: store.User{ID: "myid", Name: "name"}}, err: errors.New("comment text exceeded max allowed size 2000 (4000)")},
|
||||
{inp: store.Comment{Orig: "something blah", User: store.User{ID: "myid"}}, err: fmt.Errorf("empty user info")},
|
||||
{inp: store.Comment{Orig: longText, User: store.User{ID: "myid", Name: "name"}}, err: fmt.Errorf("comment text exceeded max allowed size 2000 (4000)")},
|
||||
}
|
||||
|
||||
for n, tt := range tbl {
|
||||
@@ -1439,7 +1438,7 @@ func TestService_ResubmitStagingImages(t *testing.T) {
|
||||
bError := DataStore{Engine: eng, EditDuration: 10 * time.Millisecond, ImageService: imgSvcError}
|
||||
|
||||
// resubmit will receive error from image storage and should return it
|
||||
mockStoreError.On("Info").Once().Return(image.StoreInfo{}, errors.New("mock_err"))
|
||||
mockStoreError.On("Info").Once().Return(image.StoreInfo{}, fmt.Errorf("mock_err"))
|
||||
err = bError.ResubmitStagingImages([]string{"radio-t"})
|
||||
assert.EqualError(t, err, "mock_err")
|
||||
|
||||
@@ -1459,7 +1458,7 @@ func TestService_ResubmitStagingImages_EngineError(t *testing.T) {
|
||||
site1Req := engine.FindRequest{Locator: store.Locator{SiteID: "site1", URL: ""}, Sort: "time", Since: time.Time{}.Add(time.Second)}
|
||||
site2Req := engine.FindRequest{Locator: store.Locator{SiteID: "site2", URL: ""}, Sort: "time", Since: time.Time{}.Add(time.Second)}
|
||||
engineMock.On("Find", site1Req).Return(nil, nil)
|
||||
engineMock.On("Find", site2Req).Return(nil, errors.New("mockError"))
|
||||
engineMock.On("Find", site2Req).Return(nil, fmt.Errorf("mockError"))
|
||||
b := DataStore{Engine: &engineMock, EditDuration: 10 * time.Millisecond, ImageService: imgSvc}
|
||||
|
||||
// One call without error and one with error
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -8,7 +9,6 @@ import (
|
||||
|
||||
"github.com/go-pkgz/lcw"
|
||||
log "github.com/go-pkgz/lgr"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
|
||||
@@ -43,7 +43,7 @@ func (t *TitleExtractor) Get(url string) (string, error) {
|
||||
b, err := t.cache.Get(url, func() (interface{}, error) {
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to load page %s", url)
|
||||
return nil, fmt.Errorf("failed to load page %s: %w", url, err)
|
||||
}
|
||||
defer func() {
|
||||
if err = resp.Body.Close(); err != nil {
|
||||
@@ -51,12 +51,12 @@ func (t *TitleExtractor) Get(url string) (string, error) {
|
||||
}
|
||||
}()
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, errors.Errorf("can't load page %s, code %d", url, resp.StatusCode)
|
||||
return nil, fmt.Errorf("can't load page %s, code %d", url, resp.StatusCode)
|
||||
}
|
||||
|
||||
title, ok := t.getTitle(resp.Body)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("can't get title for %s", url)
|
||||
return nil, fmt.Errorf("can't get title for %s", url)
|
||||
}
|
||||
return title, nil
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ package store
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -63,4 +63,4 @@ func (mock mockHash) Sum(_ []byte) []byte { return nil }
|
||||
func (mock mockHash) Reset() {}
|
||||
func (mock mockHash) Size() int { return 0 }
|
||||
func (mock mockHash) BlockSize() int { return 0 }
|
||||
func (mock mockHash) Write(_ []byte) (n int, err error) { return 0, errors.New("error") }
|
||||
func (mock mockHash) Write(_ []byte) (n int, err error) { return 0, fmt.Errorf("error") }
|
||||
|
||||
Reference in New Issue
Block a user