sticter golangci config, fix discovered issues

This commit is contained in:
Dmitry Verkhoturov
2020-04-19 16:21:09 -05:00
committed by Umputun
parent 2acb00d424
commit 513c8f353d
38 changed files with 175 additions and 115 deletions
+42 -1
View File
@@ -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
-1
View File
@@ -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
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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
}
+1 -1
View File
@@ -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")
+1 -1
View File
@@ -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)
+8 -8
View File
@@ -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()
}))
})
}
+1 -1
View File
@@ -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")
+1 -1
View File
@@ -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")
+8 -7
View File
@@ -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,
+1
View File
@@ -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)
+1 -1
View File
@@ -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
}
+15 -15
View File
@@ -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
+4 -4
View File
@@ -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 {
+1 -1
View File
@@ -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
View File
@@ -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
+8 -8
View File
@@ -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")
}
+3
View File
@@ -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()
+1 -1
View File
@@ -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
+5 -5
View File
@@ -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)
+4 -4
View File
@@ -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
}
+1 -1
View File
@@ -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 += "*"
+3 -3
View File
@@ -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())
+4 -4
View File
@@ -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) {
+6 -5
View File
@@ -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
+1 -1
View File
@@ -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,
},
+3 -3
View File
@@ -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{}
+1 -1
View File
@@ -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 }
+2 -2
View File
@@ -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, "&#34;", "\"", -1)
res = strings.Replace(res, "&#39;", "'", -1)
+5 -4
View File
@@ -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))
+6 -3
View File
@@ -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
+5 -2
View File
@@ -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" {
+4
View File
@@ -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
View File
@@ -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 (
+2 -2
View File
@@ -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") }