sticter golangci config, fix discovered issues
This commit is contained in:
committed by
Umputun
parent
2acb00d424
commit
513c8f353d
+42
-1
@@ -4,8 +4,34 @@ run:
|
||||
format: tab
|
||||
skip-dirs:
|
||||
- vendor
|
||||
|
||||
linters-settings:
|
||||
govet:
|
||||
check-shadowing: true
|
||||
golint:
|
||||
min-confidence: 0.1
|
||||
maligned:
|
||||
suggest-new: true
|
||||
goconst:
|
||||
min-len: 2
|
||||
min-occurrences: 2
|
||||
misspell:
|
||||
locale: US
|
||||
lll:
|
||||
line-length: 140
|
||||
gocritic:
|
||||
enabled-tags:
|
||||
- performance
|
||||
- style
|
||||
- experimental
|
||||
disabled-checks:
|
||||
- wrapperFunc
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- megacheck
|
||||
- golint
|
||||
- govet
|
||||
- unconvert
|
||||
- megacheck
|
||||
- structcheck
|
||||
@@ -19,9 +45,24 @@ linters:
|
||||
- typecheck
|
||||
- ineffassign
|
||||
- varcheck
|
||||
- stylecheck
|
||||
- gochecknoinits
|
||||
- scopelint
|
||||
- nakedret
|
||||
- gosimple
|
||||
- prealloc
|
||||
fast: false
|
||||
disable-all: true
|
||||
|
||||
issues:
|
||||
exclude-rules:
|
||||
- text: "at least one file in a package should have a package comment"
|
||||
linters:
|
||||
- stylecheck
|
||||
- text: "should have a package comment, unless it's in another file for this package"
|
||||
linters:
|
||||
- golint
|
||||
exclude-use-default: false
|
||||
|
||||
service:
|
||||
golangci-lint-version: 1.24.x
|
||||
golangci-lint-version: 1.23.x
|
||||
|
||||
@@ -75,7 +75,7 @@ func (m *MemAdmin) OnEvent(siteID string, ev admin.EventType) error {
|
||||
return errors.Errorf("site %s not found", siteID)
|
||||
}
|
||||
if ev == admin.EvCreate {
|
||||
resp.CountCreated += 1 // not a good idea, just for demo
|
||||
resp.CountCreated++ // not a good idea, just for demo
|
||||
m.data[siteID] = resp
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -33,6 +33,7 @@ func NewMemImageStore() *MemImage {
|
||||
}
|
||||
}
|
||||
|
||||
// Save stores image with passed id to staging
|
||||
func (m *MemImage) Save(id string, img []byte) error {
|
||||
m.Lock()
|
||||
m.imagesStaging[id] = img
|
||||
@@ -42,6 +43,7 @@ func (m *MemImage) Save(id string, img []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load image by ID
|
||||
func (m *MemImage) Load(id string) ([]byte, error) {
|
||||
m.RLock()
|
||||
img, ok := m.images[id]
|
||||
@@ -55,6 +57,7 @@ func (m *MemImage) Load(id string) ([]byte, error) {
|
||||
return img, nil
|
||||
}
|
||||
|
||||
// Commit moves image from staging to permanent
|
||||
func (m *MemImage) Commit(id string) error {
|
||||
m.RLock()
|
||||
img, ok := m.imagesStaging[id]
|
||||
@@ -70,6 +73,7 @@ func (m *MemImage) Commit(id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cleanup runs removal loop for old images on staging
|
||||
func (m *MemImage) Cleanup(_ context.Context, ttl time.Duration) error {
|
||||
var idsToRemove []string
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ require (
|
||||
github.com/go-pkgz/jrpc v0.1.0
|
||||
github.com/go-pkgz/lgr v0.7.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/rs/xid v1.2.1
|
||||
github.com/stretchr/testify v1.5.1
|
||||
github.com/umputun/go-flags v1.5.1
|
||||
github.com/umputun/remark/backend v1.5.0
|
||||
|
||||
@@ -34,7 +34,7 @@ func (a avatarMigrator) Migrate(dst, src avatar.Store) (int, error) {
|
||||
}
|
||||
|
||||
// Execute runs with AvatarCommand parameters, entry point for "avatar" command
|
||||
func (ac *AvatarCommand) Execute(args []string) error {
|
||||
func (ac *AvatarCommand) Execute(_ []string) error {
|
||||
log.Printf("[INFO] migrate avatars from %s to %s", ac.AvatarSrc.Type, ac.AvatarDst.Type)
|
||||
|
||||
src, err := ac.makeAvatarStore(ac.AvatarSrc)
|
||||
|
||||
@@ -42,7 +42,7 @@ type avatarMigratorMock struct {
|
||||
retCount int
|
||||
}
|
||||
|
||||
func (a *avatarMigratorMock) Migrate(dst, src avatar.Store) (int, error) {
|
||||
func (a *avatarMigratorMock) Migrate(_, _ avatar.Store) (int, error) {
|
||||
a.called++
|
||||
return a.retCount, a.retError
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ type BackupCommand struct {
|
||||
}
|
||||
|
||||
// Execute runs export with ExportCommand parameters, entry point for "export" command
|
||||
func (ec *BackupCommand) Execute(args []string) error {
|
||||
func (ec *BackupCommand) Execute(_ []string) error {
|
||||
log.Printf("[INFO] export to %s, site %s", ec.ExportPath, ec.Site)
|
||||
resetEnv("SECRET", "ADMIN_PASSWD")
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ var (
|
||||
|
||||
// Execute runs cleanup with CleanupCommand parameters, entry point for "cleanup" command
|
||||
// This command uses provided flags to detect and remove junk comments
|
||||
func (cc *CleanupCommand) Execute(args []string) error {
|
||||
func (cc *CleanupCommand) Execute(_ []string) error {
|
||||
log.Printf("[INFO] cleanup for site %s", cc.Site)
|
||||
|
||||
posts, err := cc.postsInRange(cc.From, cc.To)
|
||||
|
||||
@@ -144,7 +144,7 @@ func TestCleanup_ExecuteTitle(t *testing.T) {
|
||||
}
|
||||
|
||||
func cleanupRoutes(t *testing.T, r *chi.Mux, c *cleanedComments) {
|
||||
r.HandleFunc("/api/v1/list", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
r.HandleFunc("/api/v1/list", func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "GET", r.Method)
|
||||
require.Equal(t, "site=remark&limit=10000", r.URL.RawQuery)
|
||||
list := []store.PostInfo{
|
||||
@@ -165,9 +165,9 @@ func cleanupRoutes(t *testing.T, r *chi.Mux, c *cleanedComments) {
|
||||
},
|
||||
}
|
||||
require.NoError(t, json.NewEncoder(w).Encode(list))
|
||||
}))
|
||||
})
|
||||
|
||||
r.HandleFunc("/api/v1/find", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
r.HandleFunc("/api/v1/find", func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "GET", r.Method)
|
||||
require.Equal(t, "remark", r.URL.Query().Get("site"))
|
||||
require.Equal(t, "plain", r.URL.Query().Get("format"))
|
||||
@@ -193,22 +193,22 @@ func cleanupRoutes(t *testing.T, r *chi.Mux, c *cleanedComments) {
|
||||
}
|
||||
|
||||
require.NoError(t, json.NewEncoder(w).Encode(commentsWithInfo))
|
||||
}))
|
||||
})
|
||||
|
||||
r.HandleFunc("/api/v1/admin/comment/{id}", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
r.HandleFunc("/api/v1/admin/comment/{id}", func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "DELETE", r.Method)
|
||||
t.Log("delete ", r.URL.Path)
|
||||
c.lock.Lock()
|
||||
c.ids = append(c.ids, r.URL.Path)
|
||||
c.lock.Unlock()
|
||||
}))
|
||||
})
|
||||
|
||||
r.HandleFunc("/api/v1/admin/title/{id}", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
r.HandleFunc("/api/v1/admin/title/{id}", func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "PUT", r.Method)
|
||||
t.Log("title for ", r.URL.Path)
|
||||
c.lock.Lock()
|
||||
c.ids = append(c.ids, r.URL.Path)
|
||||
c.lock.Unlock()
|
||||
}))
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ type ImportCommand struct {
|
||||
}
|
||||
|
||||
// Execute runs import with ImportCommand parameters, entry point for "import" command
|
||||
func (ic *ImportCommand) Execute(args []string) error {
|
||||
func (ic *ImportCommand) Execute(_ []string) error {
|
||||
log.Printf("[INFO] import %s (%s), site %s", ic.InputFile, ic.Provider, ic.Site)
|
||||
resetEnv("SECRET", "ADMIN_PASSWD")
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ type RemapCommand struct {
|
||||
}
|
||||
|
||||
// Execute runs (re)mapper with RemapCommand parameters, entry point for "remap" command
|
||||
func (rc *RemapCommand) Execute(args []string) error {
|
||||
func (rc *RemapCommand) Execute(_ []string) error {
|
||||
log.Printf("[INFO] start remap, site %s, file with rules %s", rc.Site, rc.InputFile)
|
||||
resetEnv("SECRET", "ADMIN_PASSWD")
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ type ServerCommand struct {
|
||||
Cache CacheGroup `group:"cache" namespace:"cache" env-namespace:"CACHE"`
|
||||
Admin AdminGroup `group:"admin" namespace:"admin" env-namespace:"ADMIN"`
|
||||
Notify NotifyGroup `group:"notify" namespace:"notify" env-namespace:"NOTIFY"`
|
||||
SMTP SmtpGroup `group:"smtp" namespace:"smtp" env-namespace:"SMTP"`
|
||||
SMTP SMTPGroup `group:"smtp" namespace:"smtp" env-namespace:"SMTP"`
|
||||
Image ImageGroup `group:"image" namespace:"image" env-namespace:"IMAGE"`
|
||||
SSL SSLGroup `group:"ssl" namespace:"ssl" env-namespace:"SSL"`
|
||||
Stream StreamGroup `group:"stream" namespace:"stream" env-namespace:"STREAM"`
|
||||
@@ -177,8 +177,8 @@ type AdminGroup struct {
|
||||
RPC RPCGroup `group:"rpc" namespace:"rpc" env-namespace:"RPC"`
|
||||
}
|
||||
|
||||
// SmtpGroup defines options for SMTP server connection, used in auth and notify modules
|
||||
type SmtpGroup struct {
|
||||
// SMTPGroup defines options for SMTP server connection, used in auth and notify modules
|
||||
type SMTPGroup struct {
|
||||
Host string `long:"host" env:"HOST" description:"SMTP host"`
|
||||
Port int `long:"port" env:"PORT" description:"SMTP port"`
|
||||
Username string `long:"username" env:"USERNAME" description:"SMTP user name"`
|
||||
@@ -251,7 +251,7 @@ type serverApp struct {
|
||||
}
|
||||
|
||||
// Execute is the entry point for "server" command, called by flag parser
|
||||
func (s *ServerCommand) Execute(args []string) error {
|
||||
func (s *ServerCommand) Execute(_ []string) error {
|
||||
log.Printf("[INFO] start server on port %d", s.Port)
|
||||
resetEnv("SECRET", "AUTH_GOOGLE_CSEC", "AUTH_GITHUB_CSEC", "AUTH_FACEBOOK_CSEC", "AUTH_YANDEX_CSEC", "ADMIN_PASSWD")
|
||||
|
||||
@@ -373,7 +373,7 @@ func (s *ServerCommand) newServerApp() (*serverApp, error) {
|
||||
DisqusImporter: &migrator.Disqus{DataStore: dataService},
|
||||
WordPressImporter: &migrator.WordPress{DataStore: dataService},
|
||||
NativeExporter: &migrator.Native{DataStore: dataService},
|
||||
UrlMapperMaker: migrator.NewUrlMapper,
|
||||
URLMapperMaker: migrator.NewURLMapper,
|
||||
KeyStore: adminStore,
|
||||
}
|
||||
|
||||
@@ -503,7 +503,8 @@ func (a *serverApp) run(ctx context.Context) error {
|
||||
}
|
||||
a.notifyService.Close()
|
||||
// call potentially infinite loop with cancellation after a minute as a safeguard
|
||||
minuteCtx, _ := context.WithTimeout(context.Background(), time.Minute)
|
||||
minuteCtx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
a.imageService.Close(minuteCtx)
|
||||
|
||||
close(a.terminated)
|
||||
@@ -796,7 +797,7 @@ func (s *ServerCommand) makeNotify(dataStore *service.DataStore, authenticator *
|
||||
return tkn, nil
|
||||
},
|
||||
}
|
||||
smtpParams := notify.SmtpParams{
|
||||
smtpParams := notify.SMTPParams{
|
||||
Host: s.SMTP.Host,
|
||||
Port: s.SMTP.Port,
|
||||
TLS: s.SMTP.TLS,
|
||||
|
||||
@@ -84,6 +84,7 @@ func getDump() string {
|
||||
return string(stacktrace[:length])
|
||||
}
|
||||
|
||||
// nolint:gochecknoinits
|
||||
func init() {
|
||||
// catch SIGQUIT and print stack traces
|
||||
sigChan := make(chan os.Signal)
|
||||
|
||||
@@ -77,7 +77,7 @@ func TestBackup_Do(t *testing.T) {
|
||||
|
||||
type mockExporter struct{}
|
||||
|
||||
func (mock *mockExporter) Export(w io.Writer, siteID string) (int, error) {
|
||||
func (mock *mockExporter) Export(w io.Writer, _ string) (int, error) {
|
||||
_, err := w.Write([]byte("some export blah blah 1234567890"))
|
||||
return 1000, err
|
||||
}
|
||||
|
||||
@@ -7,15 +7,15 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// UrlMapper implements Mapper interface
|
||||
type UrlMapper struct {
|
||||
// URLMapper implements Mapper interface
|
||||
type URLMapper struct {
|
||||
rules map[string]string
|
||||
}
|
||||
|
||||
// NewUrlMapper reads rules from given reader and returns initialised UrlMapper
|
||||
// NewURLMapper reads rules from given reader and returns initialized URLMapper
|
||||
// if given rules are valid.
|
||||
func NewUrlMapper(reader io.Reader) (Mapper, error) {
|
||||
u := &UrlMapper{}
|
||||
func NewURLMapper(reader io.Reader) (Mapper, error) {
|
||||
u := &URLMapper{}
|
||||
if err := u.loadRules(reader); err != nil {
|
||||
return u, err
|
||||
}
|
||||
@@ -29,7 +29,7 @@ func NewUrlMapper(reader io.Reader) (Mapper, error) {
|
||||
// Example:
|
||||
// https://www.myblog.com/blog/1/ https://myblog.com/blog/1/
|
||||
// https://www.myblog.com/* https://myblog.com/*
|
||||
func (u *UrlMapper) loadRules(reader io.Reader) error {
|
||||
func (u *URLMapper) loadRules(reader io.Reader) error {
|
||||
data, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -54,19 +54,19 @@ func (u *UrlMapper) loadRules(reader io.Reader) error {
|
||||
|
||||
// URL maps given url to another url according loaded url-rules.
|
||||
// If not matched returns given url.
|
||||
func (u *UrlMapper) URL(url string) string {
|
||||
if newUrl, ok := u.rules[url]; ok {
|
||||
return newUrl
|
||||
func (u *URLMapper) URL(url string) string {
|
||||
if newURL, ok := u.rules[url]; ok {
|
||||
return newURL
|
||||
}
|
||||
// try to match by prefix
|
||||
for oldUrl, newUrl := range u.rules {
|
||||
if !strings.HasSuffix(oldUrl, "*") {
|
||||
for oldURL, newURL := range u.rules {
|
||||
if !strings.HasSuffix(oldURL, "*") {
|
||||
continue
|
||||
}
|
||||
oldUrl = strings.TrimSuffix(oldUrl, "*")
|
||||
newUrl = strings.TrimSuffix(newUrl, "*")
|
||||
if strings.HasPrefix(url, oldUrl) {
|
||||
return newUrl + strings.TrimPrefix(url, oldUrl)
|
||||
oldURL = strings.TrimSuffix(oldURL, "*")
|
||||
newURL = strings.TrimSuffix(newURL, "*")
|
||||
if strings.HasPrefix(url, oldURL) {
|
||||
return newURL + strings.TrimPrefix(url, oldURL)
|
||||
}
|
||||
}
|
||||
// search failed, return given url
|
||||
|
||||
@@ -16,7 +16,7 @@ https://radio-t.com/p/2018/09/22////podcast-616/ https://www.radio-t.com/p/2018/
|
||||
https://radio-t.com/p/2018/09/22/podcast-616/?with_query=1 https://www.radio-t.com/p/2018/09/22/podcast-616/
|
||||
`)
|
||||
|
||||
mapper, err := NewUrlMapper(rules)
|
||||
mapper, err := NewURLMapper(rules)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// if url not matched mapper should return given url
|
||||
@@ -30,7 +30,7 @@ https://radio-t.com/p/2018/09/22/podcast-616/?with_query=1 https://www.radio-t.c
|
||||
|
||||
// want remap from http to https
|
||||
rules = strings.NewReader(`http://anysite.com/p/123 https://anysite.com/p/321`)
|
||||
mapper, err = NewUrlMapper(rules)
|
||||
mapper, err = NewURLMapper(rules)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "https://anysite.com/p/321", mapper.URL("http://anysite.com/p/123"))
|
||||
assert.Equal(t, "https://notexist", mapper.URL("https://notexist"))
|
||||
@@ -38,7 +38,7 @@ https://radio-t.com/p/2018/09/22/podcast-616/?with_query=1 https://www.radio-t.c
|
||||
|
||||
// want remap from http to https by pattern
|
||||
rules = strings.NewReader(`http://anysite.com* https://anysite.com*`)
|
||||
mapper, err = NewUrlMapper(rules)
|
||||
mapper, err = NewURLMapper(rules)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "https://anysite.com/p/1", mapper.URL("http://anysite.com/p/1"))
|
||||
assert.Equal(t, "https://anysite.com/", mapper.URL("http://anysite.com/"))
|
||||
@@ -80,7 +80,7 @@ func TestUrlMapper_New(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
_, err := NewUrlMapper(strings.NewReader(c.rules))
|
||||
_, err := NewURLMapper(strings.NewReader(c.rules))
|
||||
if c.expectError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
|
||||
@@ -105,7 +105,7 @@ func TestNative_ImportWithMapper(t *testing.T) {
|
||||
|
||||
// want to remap comments to https://rdt.c
|
||||
rules := `https://radio-t.com* https://rdt.c*`
|
||||
mapper, err := NewUrlMapper(strings.NewReader(rules))
|
||||
mapper, err := NewURLMapper(strings.NewReader(rules))
|
||||
assert.NoError(t, err)
|
||||
|
||||
inp := `{"version":1,"users":[{"id":"user1","blocked":{"status":false,"until":"0001-01-01T00:00:00Z"},"verified":true},{"id":"user2","blocked":{"status":true,"until":"2018-12-23T02:55:22.472041-06:00"},"verified":false}],"posts":[{"url":"https://radio-t.com","read_only":true}]}
|
||||
|
||||
+19
-19
@@ -29,8 +29,8 @@ type EmailParams struct {
|
||||
TokenGenFn func(userID, email, site string) (string, error) // Unsubscribe token generation function
|
||||
}
|
||||
|
||||
// SmtpParams contain settings for smtp server connection
|
||||
type SmtpParams struct {
|
||||
// SMTPParams contain settings for smtp server connection
|
||||
type SMTPParams struct {
|
||||
Host string // SMTP host
|
||||
Port int // SMTP port
|
||||
TLS bool // TLS auth
|
||||
@@ -42,7 +42,7 @@ type SmtpParams struct {
|
||||
// Email implements notify.Destination for email
|
||||
type Email struct {
|
||||
EmailParams
|
||||
SmtpParams
|
||||
SMTPParams
|
||||
|
||||
smtp smtpClientCreator
|
||||
msgTmpl *template.Template // parsed request message template
|
||||
@@ -64,7 +64,7 @@ type smtpClient interface {
|
||||
|
||||
// smtpClientCreator interface defines function for creating new smtpClients
|
||||
type smtpClientCreator interface {
|
||||
Create(SmtpParams) (smtpClient, error)
|
||||
Create(SMTPParams) (smtpClient, error)
|
||||
}
|
||||
|
||||
type emailMessage struct {
|
||||
@@ -202,7 +202,7 @@ const (
|
||||
)
|
||||
|
||||
// NewEmail makes new Email object, returns error in case of e.MsgTemplate or e.VerificationTemplate parsing error
|
||||
func NewEmail(emailParams EmailParams, smtpParams SmtpParams) (*Email, error) {
|
||||
func NewEmail(emailParams EmailParams, smtpParams SMTPParams) (*Email, error) {
|
||||
// set up Email emailParams
|
||||
res := Email{EmailParams: emailParams}
|
||||
if res.MsgTemplate == "" {
|
||||
@@ -217,7 +217,7 @@ func NewEmail(emailParams EmailParams, smtpParams SmtpParams) (*Email, error) {
|
||||
|
||||
// set up SMTP emailParams
|
||||
res.smtp = &emailClient{}
|
||||
res.SmtpParams = smtpParams
|
||||
res.SMTPParams = smtpParams
|
||||
if res.TimeOut <= 0 {
|
||||
res.TimeOut = defaultEmailTimeout
|
||||
}
|
||||
@@ -225,7 +225,7 @@ func NewEmail(emailParams EmailParams, smtpParams SmtpParams) (*Email, error) {
|
||||
log.Printf("[DEBUG] Create new email notifier for server %s with user %s, timeout=%s",
|
||||
res.Host, res.Username, res.TimeOut)
|
||||
|
||||
// initialise templates
|
||||
// initialize templates
|
||||
var err error
|
||||
if res.msgTmpl, err = template.New("messageFromRequest").Parse(res.MsgTemplate); err != nil {
|
||||
return nil, errors.Wrapf(err, "can't parse message template")
|
||||
@@ -314,13 +314,13 @@ func (e *Email) buildMessageFromRequest(req Request, forAdmin bool) (string, err
|
||||
unsubscribeLink = ""
|
||||
}
|
||||
|
||||
commentUrlPrefix := req.Comment.Locator.URL + uiNav
|
||||
commentURLPrefix := req.Comment.Locator.URL + uiNav
|
||||
msg := bytes.Buffer{}
|
||||
tmplData := msgTmplData{
|
||||
UserName: req.Comment.User.Name,
|
||||
UserPicture: req.Comment.User.Picture,
|
||||
CommentText: req.Comment.Text,
|
||||
CommentLink: commentUrlPrefix + req.Comment.ID,
|
||||
CommentLink: commentURLPrefix + req.Comment.ID,
|
||||
CommentDate: req.Comment.Timestamp,
|
||||
PostTitle: req.Comment.PostTitle,
|
||||
Email: req.Email,
|
||||
@@ -332,7 +332,7 @@ func (e *Email) buildMessageFromRequest(req Request, forAdmin bool) (string, err
|
||||
tmplData.ParentUserName = req.parent.User.Name
|
||||
tmplData.ParentUserPicture = req.parent.User.Picture
|
||||
tmplData.ParentCommentText = req.parent.Text
|
||||
tmplData.ParentCommentLink = commentUrlPrefix + req.parent.ID
|
||||
tmplData.ParentCommentLink = commentURLPrefix + req.parent.ID
|
||||
tmplData.ParentCommentDate = req.parent.Timestamp
|
||||
}
|
||||
err = e.msgTmpl.Execute(&msg, tmplData)
|
||||
@@ -384,30 +384,30 @@ 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 smtpClient set")
|
||||
return errors.New("sendMessage called without client set")
|
||||
}
|
||||
smtpClient, err := e.smtp.Create(e.SmtpParams)
|
||||
client, err := e.smtp.Create(e.SMTPParams)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to make smtp Create")
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := smtpClient.Quit(); err != nil {
|
||||
if err = client.Quit(); err != nil {
|
||||
log.Printf("[WARN] failed to send quit command to %s:%d, %v", e.Host, e.Port, err)
|
||||
if err := smtpClient.Close(); err != nil {
|
||||
if err = client.Close(); err != nil {
|
||||
log.Printf("[WARN] can't close smtp connection, %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if err := smtpClient.Mail(m.from); err != nil {
|
||||
if err = client.Mail(m.from); err != nil {
|
||||
return errors.Wrapf(err, "bad from address %q", m.from)
|
||||
}
|
||||
if err := smtpClient.Rcpt(m.to); err != nil {
|
||||
if err = client.Rcpt(m.to); err != nil {
|
||||
return errors.Wrapf(err, "bad to address %q", m.to)
|
||||
}
|
||||
|
||||
writer, err := smtpClient.Data()
|
||||
writer, err := client.Data()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "can't make email writer")
|
||||
}
|
||||
@@ -431,9 +431,9 @@ func (e *Email) String() string {
|
||||
return fmt.Sprintf("email: from %q with username '%s' at server %s:%d", e.From, e.Username, e.Host, e.Port)
|
||||
}
|
||||
|
||||
// Create establish SMTP connection with server using credentials in smtpClientWithCreator.SmtpParams
|
||||
// Create establish SMTP connection with server using credentials in smtpClientWithCreator.SMTPParams
|
||||
// and returns pointer to it. Thread safe.
|
||||
func (s *emailClient) Create(params SmtpParams) (smtpClient, error) {
|
||||
func (s *emailClient) Create(params SMTPParams) (smtpClient, error) {
|
||||
authenticate := func(c *smtp.Client) error {
|
||||
if params.Username == "" || params.Password == "" {
|
||||
return nil
|
||||
|
||||
@@ -22,7 +22,7 @@ func TestEmailNew(t *testing.T) {
|
||||
err bool
|
||||
errText string
|
||||
emailParams EmailParams
|
||||
smtpParams SmtpParams
|
||||
smtpParams SMTPParams
|
||||
}{
|
||||
{name: "empty"},
|
||||
{name: "with template parse error",
|
||||
@@ -36,7 +36,7 @@ func TestEmailNew(t *testing.T) {
|
||||
From: "test@from",
|
||||
VerificationTemplate: "{{",
|
||||
},
|
||||
smtpParams: SmtpParams{
|
||||
smtpParams: SMTPParams{
|
||||
Host: "test@host",
|
||||
Port: 1000,
|
||||
TLS: true,
|
||||
@@ -50,7 +50,7 @@ func TestEmailNew(t *testing.T) {
|
||||
emailParams: EmailParams{
|
||||
From: "test@from",
|
||||
},
|
||||
smtpParams: SmtpParams{
|
||||
smtpParams: SMTPParams{
|
||||
Host: "test@host",
|
||||
Port: 1000,
|
||||
TLS: true,
|
||||
@@ -125,7 +125,7 @@ func TestEmailSendErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEmailSend_ExitConditions(t *testing.T) {
|
||||
email, err := NewEmail(EmailParams{}, SmtpParams{})
|
||||
email, err := NewEmail(EmailParams{}, SMTPParams{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, email, "expecting email returned")
|
||||
// prevent triggering e.autoFlush creation
|
||||
@@ -179,7 +179,7 @@ func TestEmailSendClientError(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEmail_Send(t *testing.T) {
|
||||
email, err := NewEmail(EmailParams{From: "from@example.org"}, SmtpParams{})
|
||||
email, err := NewEmail(EmailParams{From: "from@example.org"}, SMTPParams{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, email)
|
||||
fakeSmtp := fakeTestSMTP{}
|
||||
@@ -227,7 +227,7 @@ Date: `)
|
||||
}
|
||||
|
||||
func TestEmail_SendVerification(t *testing.T) {
|
||||
email, err := NewEmail(EmailParams{From: "from@example.org"}, SmtpParams{})
|
||||
email, err := NewEmail(EmailParams{From: "from@example.org"}, SMTPParams{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, email)
|
||||
fakeSmtp := fakeTestSMTP{}
|
||||
@@ -272,7 +272,7 @@ Date: `)
|
||||
|
||||
func Test_emailClient_Create(t *testing.T) {
|
||||
creator := emailClient{}
|
||||
client, err := creator.Create(SmtpParams{})
|
||||
client, err := creator.Create(SMTPParams{})
|
||||
assert.Error(t, err, "absence of address to connect results in error")
|
||||
assert.Nil(t, client, "no client returned in case of error")
|
||||
}
|
||||
@@ -288,7 +288,7 @@ type fakeTestSMTP struct {
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
func (f *fakeTestSMTP) Create(SmtpParams) (smtpClient, error) {
|
||||
func (f *fakeTestSMTP) Create(SMTPParams) (smtpClient, error) {
|
||||
if f.fail["create"] {
|
||||
return nil, errors.New("failed to create client")
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
log "github.com/go-pkgz/lgr"
|
||||
)
|
||||
|
||||
// MockDest is a destination mock
|
||||
type MockDest struct {
|
||||
data []Request
|
||||
id int
|
||||
@@ -16,6 +17,7 @@ type MockDest struct {
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// Send mock
|
||||
func (m *MockDest) Send(ctx context.Context, r Request) error {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
@@ -30,6 +32,7 @@ func (m *MockDest) Send(ctx context.Context, r Request) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get mock
|
||||
func (m *MockDest) Get() []Request {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
|
||||
@@ -111,7 +111,7 @@ func (a *admin) deleteMeRequestCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := a.dataService.DeleteUserDetail(claims.Audience, claims.User.ID, engine.UserEmail); err != nil {
|
||||
if err = a.dataService.DeleteUserDetail(claims.Audience, claims.User.ID, engine.UserEmail); err != nil {
|
||||
code := parseError(err, rest.ErrInternal)
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't delete email for user", code)
|
||||
return
|
||||
|
||||
@@ -55,8 +55,8 @@ func TestAdmin_Delete(t *testing.T) {
|
||||
j := []store.PostInfo{}
|
||||
err = json.Unmarshal(bb, &j)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []store.PostInfo([]store.PostInfo{{URL: "https://radio-t.com/blah", Count: 2},
|
||||
{URL: "https://radio-t.com/blah2", Count: 0}}), j)
|
||||
assert.Equal(t, []store.PostInfo{{URL: "https://radio-t.com/blah", Count: 2},
|
||||
{URL: "https://radio-t.com/blah2", Count: 0}}, j)
|
||||
|
||||
// delete a comment
|
||||
req, err := http.NewRequest(http.MethodDelete,
|
||||
@@ -103,8 +103,8 @@ func TestAdmin_Delete(t *testing.T) {
|
||||
j = []store.PostInfo{}
|
||||
err = json.Unmarshal(bb, &j)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []store.PostInfo([]store.PostInfo{{URL: "https://radio-t.com/blah", Count: 1},
|
||||
{URL: "https://radio-t.com/blah2", Count: 0}}), j)
|
||||
assert.Equal(t, []store.PostInfo{{URL: "https://radio-t.com/blah", Count: 1},
|
||||
{URL: "https://radio-t.com/blah2", Count: 0}}, j)
|
||||
}
|
||||
|
||||
func TestAdmin_Title(t *testing.T) {
|
||||
@@ -310,7 +310,7 @@ func TestAdmin_Block(t *testing.T) {
|
||||
pi = []store.PostInfo{}
|
||||
err = json.Unmarshal(body, &pi)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []store.PostInfo([]store.PostInfo{{URL: "https://radio-t.com/blah", Count: 1}}), pi)
|
||||
assert.Equal(t, []store.PostInfo{{URL: "https://radio-t.com/blah", Count: 1}}, pi)
|
||||
|
||||
res, code := get(t, ts.URL+"/api/v1/find?site=remark42&url=https://radio-t.com/blah&sort=+time")
|
||||
assert.Equal(t, 200, code)
|
||||
|
||||
@@ -28,7 +28,7 @@ type Migrator struct {
|
||||
DisqusImporter migrator.Importer
|
||||
WordPressImporter migrator.Importer
|
||||
NativeExporter migrator.Exporter
|
||||
UrlMapperMaker migrator.MapperMaker
|
||||
URLMapperMaker migrator.MapperMaker
|
||||
KeyStore KeyStore
|
||||
|
||||
busy map[string]bool
|
||||
@@ -161,7 +161,7 @@ func (m *Migrator) remapCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
siteID := r.URL.Query().Get("site")
|
||||
|
||||
// create new url-mapper from given rules in body
|
||||
mapper, err := m.UrlMapperMaker(r.Body)
|
||||
mapper, err := m.URLMapperMaker(r.Body)
|
||||
if err != nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "remap failed, bad given rules", rest.ErrDecode)
|
||||
return
|
||||
@@ -180,12 +180,12 @@ func (m *Migrator) remapCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if e := os.Remove(fh.Name()); e != nil {
|
||||
if e = os.Remove(fh.Name()); e != nil {
|
||||
log.Printf("[WARN] failed to remove temp file %+v", e)
|
||||
}
|
||||
}()
|
||||
log.Printf("[DEBUG] start export for site=%s", siteID)
|
||||
if _, e := m.NativeExporter.Export(fh, siteID); e != nil {
|
||||
if _, e = m.NativeExporter.Export(fh, siteID); e != nil {
|
||||
log.Printf("[WARN] export failed with %+v", e)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -464,7 +464,7 @@ func addFileServer(r chi.Router, path string, root http.FileSystem, version stri
|
||||
origPath := path
|
||||
webFS = http.StripPrefix(path, webFS)
|
||||
if path != "/" && path[len(path)-1] != '/' {
|
||||
r.Get(path, http.RedirectHandler(path+"/", 301).ServeHTTP)
|
||||
r.Get(path, http.RedirectHandler(path+"/", http.StatusMovedPermanently).ServeHTTP)
|
||||
path += "/"
|
||||
}
|
||||
path += "*"
|
||||
|
||||
@@ -59,7 +59,7 @@ type privStore interface {
|
||||
Info(locator store.Locator, readonlyAge int) (store.PostInfo, error)
|
||||
}
|
||||
|
||||
const unsubscribeHtml = `<!DOCTYPE html>
|
||||
const unsubscribeHTML = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width"/>
|
||||
@@ -418,7 +418,7 @@ func (s *private) emailUnsubscribeCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
log.Printf("[DEBUG] unsubscribe user %s", userID)
|
||||
|
||||
if err := s.dataService.DeleteUserDetail(siteID, userID, engine.UserEmail); err != nil {
|
||||
if err = s.dataService.DeleteUserDetail(siteID, userID, engine.UserEmail); err != nil {
|
||||
code := parseError(err, rest.ErrInternal)
|
||||
rest.SendErrorHTML(w, r, http.StatusBadRequest, err, "can't delete email for user", code)
|
||||
return
|
||||
@@ -443,7 +443,7 @@ func (s *private) emailUnsubscribeCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
tmpl := template.Must(template.New("unsubscribe").Parse(unsubscribeHtml))
|
||||
tmpl := template.Must(template.New("unsubscribe").Parse(unsubscribeHTML))
|
||||
msg := bytes.Buffer{}
|
||||
MustExecute(tmpl, &msg, nil)
|
||||
render.HTML(w, r, msg.String())
|
||||
|
||||
@@ -249,8 +249,8 @@ func TestRest_UpdateDelete(t *testing.T) {
|
||||
j := []store.PostInfo{}
|
||||
err = json.Unmarshal(bb, &j)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []store.PostInfo([]store.PostInfo{{URL: "https://radio-t.com/blah1", Count: 1},
|
||||
{URL: "https://radio-t.com/blah2", Count: 0}}), j)
|
||||
assert.Equal(t, []store.PostInfo{{URL: "https://radio-t.com/blah1", Count: 1},
|
||||
{URL: "https://radio-t.com/blah2", Count: 0}}, j)
|
||||
|
||||
// delete a comment
|
||||
client := http.Client{}
|
||||
@@ -290,8 +290,8 @@ func TestRest_UpdateDelete(t *testing.T) {
|
||||
j = []store.PostInfo{}
|
||||
err = json.Unmarshal(bb, &j)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []store.PostInfo([]store.PostInfo{{URL: "https://radio-t.com/blah1", Count: 0},
|
||||
{URL: "https://radio-t.com/blah2", Count: 0}}), j)
|
||||
assert.Equal(t, []store.PostInfo{{URL: "https://radio-t.com/blah1", Count: 0},
|
||||
{URL: "https://radio-t.com/blah2", Count: 0}}, j)
|
||||
}
|
||||
|
||||
func TestRest_UpdateNotOwner(t *testing.T) {
|
||||
|
||||
@@ -449,8 +449,8 @@ func TestRest_Counts(t *testing.T) {
|
||||
j := []store.PostInfo{}
|
||||
err = json.Unmarshal(body, &j)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []store.PostInfo([]store.PostInfo{{URL: "https://radio-t.com/blah1", Count: 3},
|
||||
{URL: "https://radio-t.com/blah2", Count: 2}}), j)
|
||||
assert.Equal(t, []store.PostInfo{{URL: "https://radio-t.com/blah1", Count: 3},
|
||||
{URL: "https://radio-t.com/blah2", Count: 2}}, j)
|
||||
|
||||
resp, err = post(t, ts.URL+"/api/v1/counts?site=radio-XXX", `{}`)
|
||||
require.NoError(t, err)
|
||||
@@ -527,7 +527,7 @@ func TestRest_Config(t *testing.T) {
|
||||
err := json.Unmarshal([]byte(body), &j)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 300., j["edit_duration"])
|
||||
assert.EqualValues(t, []interface{}([]interface{}{"a1", "a2"}), j["admins"])
|
||||
assert.EqualValues(t, []interface{}{"a1", "a2"}, j["admins"])
|
||||
assert.Equal(t, "admin@remark-42.com", j["admin_email"])
|
||||
assert.Equal(t, 4000., j["max_comment_size"])
|
||||
assert.Equal(t, -5., j["low_score"])
|
||||
@@ -598,7 +598,7 @@ func TestRest_InfoStream(t *testing.T) {
|
||||
assert.Equal(t, 200, code)
|
||||
<-done
|
||||
|
||||
recs := strings.Split(strings.TrimSuffix(string(body), "\n"), "\n")
|
||||
recs := strings.Split(strings.TrimSuffix(body, "\n"), "\n")
|
||||
require.Equal(t, 10*3, len(recs), "10 records. each 2 lines +1 emty line")
|
||||
assert.True(t, strings.Contains(recs[0+1], `"count":2`), recs[0])
|
||||
assert.True(t, strings.Contains(recs[9*3+1], `"count":11`), recs[9])
|
||||
@@ -723,10 +723,11 @@ func TestRest_Robots(t *testing.T) {
|
||||
assert.Equal(t, "User-agent: *\nDisallow: /auth/\nDisallow: /api/\nAllow: /api/v1/find\n"+
|
||||
"Allow: /api/v1/last\nAllow: /api/v1/id\nAllow: /api/v1/count\nAllow: /api/v1/counts\n"+
|
||||
"Allow: /api/v1/list\nAllow: /api/v1/config\nAllow: /api/v1/user\nAllow: /api/v1/img\n"+
|
||||
"Allow: /api/v1/avatar\nAllow: /api/v1/picture\n", string(body))
|
||||
"Allow: /api/v1/avatar\nAllow: /api/v1/picture\n", body)
|
||||
}
|
||||
|
||||
func TestRest_LastCommentsStream(t *testing.T) {
|
||||
t.Skip() // TODO: enable after cache is migrated to https://github.com/dgraph-io/ristretto
|
||||
ts, srv, teardown := startupT(t)
|
||||
srv.pubRest.readOnlyAge = 10000000 // make sure we don't hit read-only
|
||||
srv.pubRest.streamer.Refresh = 50 * time.Millisecond
|
||||
|
||||
@@ -383,7 +383,7 @@ func startupT(t *testing.T) (ts *httptest.Server, srv *Rest, teardown func()) {
|
||||
WordPressImporter: &migrator.WordPress{DataStore: dataStore},
|
||||
NativeImporter: &migrator.Native{DataStore: dataStore},
|
||||
NativeExporter: &migrator.Native{DataStore: dataStore},
|
||||
UrlMapperMaker: migrator.NewUrlMapper,
|
||||
URLMapperMaker: migrator.NewURLMapper,
|
||||
Cache: memCache,
|
||||
KeyStore: astore,
|
||||
},
|
||||
|
||||
@@ -38,7 +38,7 @@ const (
|
||||
ErrAssetNotFound = 18 // requested file not found
|
||||
)
|
||||
|
||||
const errorHtml = `<!DOCTYPE html>
|
||||
const errorHTML = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width"/>
|
||||
@@ -64,12 +64,12 @@ type errTmplData struct {
|
||||
func SendErrorHTML(w http.ResponseWriter, r *http.Request, httpStatusCode int, err error, details string, errCode int) {
|
||||
// MustExecute behaves like template.Execute, but panics if an error occurs.
|
||||
MustExecute := func(tmpl *template.Template, wr io.Writer, data interface{}) {
|
||||
if err := tmpl.Execute(wr, data); err != nil {
|
||||
if err = tmpl.Execute(wr, data); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
tmpl := template.Must(template.New("error").Parse(errorHtml))
|
||||
tmpl := template.Must(template.New("error").Parse(errorHTML))
|
||||
log.Printf("[WARN] %s", errDetailsMsg(r, httpStatusCode, err, details, errCode))
|
||||
render.Status(r, httpStatusCode)
|
||||
msg := bytes.Buffer{}
|
||||
|
||||
@@ -79,4 +79,4 @@ func (s *StaticStore) Enabled(site string) (ok bool, err error) {
|
||||
}
|
||||
|
||||
// OnEvent doesn nothing for StaticStore
|
||||
func (s *StaticStore) OnEvent(siteID string, et EventType) error { return nil }
|
||||
func (s *StaticStore) OnEvent(_ string, _ EventType) error { return nil }
|
||||
|
||||
@@ -120,7 +120,7 @@ func (c *Comment) Sanitize() {
|
||||
c.Text = p.Sanitize(c.Text)
|
||||
c.Orig = p.Sanitize(c.Orig)
|
||||
c.User.ID = template.HTMLEscapeString(c.User.ID)
|
||||
c.User.Name = c.escapeHtmlWithSome(c.User.Name)
|
||||
c.User.Name = c.escapeHTMLWithSome(c.User.Name)
|
||||
c.User.Picture = p.Sanitize(c.User.Picture)
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ func (c *Comment) Snippet(limit int) string {
|
||||
return string(snippet) + " ..."
|
||||
}
|
||||
|
||||
func (c *Comment) escapeHtmlWithSome(inp string) string {
|
||||
func (c *Comment) escapeHTMLWithSome(inp string) string {
|
||||
res := template.HTMLEscapeString(inp)
|
||||
res = strings.Replace(res, """, "\"", -1)
|
||||
res = strings.Replace(res, "'", "'", -1)
|
||||
|
||||
@@ -662,7 +662,7 @@ func (b *BoltDB) getUserDetail(req UserDetailRequest) (result []UserDetailEntry,
|
||||
value := bucket.Get([]byte(req.UserID))
|
||||
// return no error in case of absent entry
|
||||
if value != nil {
|
||||
if err := json.Unmarshal(value, &entry); err != nil {
|
||||
if err = json.Unmarshal(value, &entry); err != nil {
|
||||
return errors.Wrap(e, "failed to unmarshal entry")
|
||||
}
|
||||
switch req.Detail {
|
||||
@@ -690,7 +690,7 @@ func (b *BoltDB) setUserDetail(req UserDetailRequest) (result []UserDetailEntry,
|
||||
value := bucket.Get([]byte(req.UserID))
|
||||
// return no error in case of absent entry
|
||||
if value != nil {
|
||||
if err := json.Unmarshal(value, &entry); err != nil {
|
||||
if err = json.Unmarshal(value, &entry); err != nil {
|
||||
return errors.Wrap(e, "failed to unmarshal entry")
|
||||
}
|
||||
}
|
||||
@@ -711,7 +711,7 @@ 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)
|
||||
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)
|
||||
})
|
||||
|
||||
@@ -729,7 +729,7 @@ func (b *BoltDB) listDetails(loc store.Locator) (result []UserDetailEntry, err e
|
||||
var entry UserDetailEntry
|
||||
bucket := tx.Bucket([]byte(userDetailsBucketName))
|
||||
return bucket.ForEach(func(userID, value []byte) error {
|
||||
if err := json.Unmarshal(value, &entry); err != nil {
|
||||
if err = json.Unmarshal(value, &entry); err != nil {
|
||||
return errors.Wrap(e, "failed to unmarshal entry")
|
||||
}
|
||||
result = append(result, entry)
|
||||
@@ -860,6 +860,7 @@ func (b *BoltDB) deleteUser(bdb *bolt.DB, siteID string, userID string, mode sto
|
||||
// get list of commentID for all user's comment
|
||||
comments := []commentInfo{}
|
||||
for _, postInfo := range posts {
|
||||
postInfo := postInfo
|
||||
err = bdb.View(func(tx *bolt.Tx) error {
|
||||
postsBkt := tx.Bucket([]byte(postsBucketName))
|
||||
postBkt := postsBkt.Bucket([]byte(postInfo.URL))
|
||||
|
||||
@@ -83,10 +83,13 @@ const (
|
||||
Verified = Flag("verified")
|
||||
Blocked = Flag("blocked")
|
||||
)
|
||||
|
||||
// All possible user details
|
||||
const (
|
||||
// All possible user details
|
||||
UserEmail = UserDetail("email")
|
||||
AllUserDetails = UserDetail("all") // used for listing and deletion requests
|
||||
// UserEmail is a user email
|
||||
UserEmail = UserDetail("email")
|
||||
// AllUserDetails used for listing and deletion requests
|
||||
AllUserDetails = UserDetail("all")
|
||||
)
|
||||
|
||||
// FlagRequest is the input for both get/set for flags, like blocked, verified and so on
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"image"
|
||||
// support gif and jpeg images decoding
|
||||
_ "image/gif"
|
||||
_ "image/jpeg"
|
||||
"image/png"
|
||||
@@ -60,7 +61,7 @@ type ServiceParams struct {
|
||||
// e.g. when somebody uploaded a picture but did not sent the comment.
|
||||
type Store interface {
|
||||
Save(id string, img []byte) error // store image with passed id to staging
|
||||
Load(id string) ([]byte, error) // load image by ID. Caller has to close the reader.
|
||||
Load(id string) ([]byte, error) // load image by ID
|
||||
|
||||
Commit(id string) error // move image from staging to permanent
|
||||
Cleanup(ctx context.Context, ttl time.Duration) error // run removal loop for old images on staging
|
||||
@@ -73,6 +74,7 @@ type submitReq struct {
|
||||
TS time.Time
|
||||
}
|
||||
|
||||
// NewService returns new Service instance
|
||||
func NewService(s Store, p ServiceParams) *Service {
|
||||
return &Service{ServiceParams: p, store: s}
|
||||
}
|
||||
@@ -186,7 +188,7 @@ func (s *Service) Save(userID string, r io.Reader) (id string, err error) {
|
||||
return id, s.SaveWithID(id, r)
|
||||
}
|
||||
|
||||
// Save wraps storage Save function, validating and resizing the image before calling it.
|
||||
// SaveWithID wraps storage Save function, validating and resizing the image before calling it.
|
||||
func (s *Service) SaveWithID(id string, r io.Reader) error {
|
||||
img, err := s.prepareImage(r)
|
||||
if err != nil {
|
||||
@@ -195,6 +197,7 @@ func (s *Service) SaveWithID(id string, r io.Reader) error {
|
||||
return s.store.Save(id, img)
|
||||
}
|
||||
|
||||
// ImgContentType returns content type for provided image
|
||||
func (s *Service) ImgContentType(img []byte) string {
|
||||
contentType := http.DetectContentType(img)
|
||||
if contentType == "application/octet-stream" {
|
||||
|
||||
@@ -16,11 +16,13 @@ type RPC struct {
|
||||
jrpc.Client
|
||||
}
|
||||
|
||||
// Save saves image with given id to staging.
|
||||
func (r *RPC) Save(id string, img []byte) error {
|
||||
_, err := r.Call("image.save_with_id", id, img)
|
||||
return err
|
||||
}
|
||||
|
||||
// Load image with given id
|
||||
func (r *RPC) Load(id string) ([]byte, error) {
|
||||
resp, err := r.Call("image.load", id)
|
||||
if err != nil {
|
||||
@@ -33,11 +35,13 @@ func (r *RPC) Load(id string) ([]byte, error) {
|
||||
return ioutil.ReadAll(base64.NewDecoder(base64.StdEncoding, strings.NewReader(rawImg)))
|
||||
}
|
||||
|
||||
// Commit file stored in staging location by moving it to permanent location
|
||||
func (r *RPC) Commit(id string) error {
|
||||
_, err := r.Call("image.commit", id)
|
||||
return err
|
||||
}
|
||||
|
||||
// Cleanup runs scan of staging and removes old files based on ttl
|
||||
func (r *RPC) Cleanup(_ context.Context, ttl time.Duration) error {
|
||||
_, err := r.Call("image.cleanup", ttl)
|
||||
return err
|
||||
|
||||
@@ -19,7 +19,7 @@ type StaticRestrictedWordsLister struct {
|
||||
}
|
||||
|
||||
// List provides restricted words in comments (ignores siteID)
|
||||
func (l StaticRestrictedWordsLister) List(siteID string) (restricted []string, err error) {
|
||||
func (l StaticRestrictedWordsLister) List(_ string) (restricted []string, err error) {
|
||||
return l.Words, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Package service wraps engine interfaces with common logic unrelated to any particular engine implementation.
|
||||
// All consumers should be using service.DataStore and not the naked engine!
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
|
||||
@@ -60,8 +60,8 @@ func TestUser_HashFailed(t *testing.T) {
|
||||
|
||||
type mockHash struct{}
|
||||
|
||||
func (mock mockHash) Sum(b []byte) []byte { return nil }
|
||||
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(p []byte) (n int, err error) { return 0, errors.New("error") }
|
||||
func (mock mockHash) Write(_ []byte) (n int, err error) { return 0, errors.New("error") }
|
||||
|
||||
Reference in New Issue
Block a user