chore: minor refactors based on static checks

- unchecked returns fixed (most)
- remove unused constants
- remove unsed structs
- function parameters unused or incorrectly used
- removed if else chains for error checks
- use regex MustCompile instead of compile
- spell checks
- preallocate slice cap when size known
- scope issues inside range
This commit is contained in:
Rohan Verma 2019-10-25 11:11:47 +05:30
parent 2c18d6356b
commit 712ad2d517
15 changed files with 67 additions and 49 deletions

View File

@ -38,7 +38,7 @@ func handleGetConfigScript(c echo.Context) error {
) )
b.Write([]byte(`var CONFIG = `)) b.Write([]byte(`var CONFIG = `))
j.Encode(out) _ = j.Encode(out)
return c.Blob(http.StatusOK, "application/javascript", b.Bytes()) return c.Blob(http.StatusOK, "application/javascript", b.Bytes())
} }

View File

@ -85,9 +85,11 @@ func handleGetCampaigns(c echo.Context) error {
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, return echo.NewHTTPError(http.StatusInternalServerError,
fmt.Sprintf("Error fetching campaigns: %s", pqErrMsg(err))) fmt.Sprintf("Error fetching campaigns: %s", pqErrMsg(err)))
} else if single && len(out.Results) == 0 { }
if single && len(out.Results) == 0 {
return echo.NewHTTPError(http.StatusBadRequest, "Campaign not found.") return echo.NewHTTPError(http.StatusBadRequest, "Campaign not found.")
} else if len(out.Results) == 0 { }
if len(out.Results) == 0 {
out.Results = make([]models.Campaign, 0) out.Results = make([]models.Campaign, 0)
return c.JSON(http.StatusOK, out) return c.JSON(http.StatusOK, out)
} }
@ -492,7 +494,8 @@ func handleTestCampaign(c echo.Context) error {
// Send the test messages. // Send the test messages.
for _, s := range subs { for _, s := range subs {
if err := sendTestMessage(&s, &camp, app); err != nil { sub := s
if err := sendTestMessage(&sub, &camp, app); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error sending test: %v", err)) return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Error sending test: %v", err))
} }
} }
@ -500,7 +503,7 @@ func handleTestCampaign(c echo.Context) error {
return c.JSON(http.StatusOK, okResp{true}) return c.JSON(http.StatusOK, okResp{true})
} }
// sendTestMessage takes a campaign and a subsriber and sends out a sample campain message. // sendTestMessage takes a campaign and a subsriber and sends out a sample campaign message.
func sendTestMessage(sub *models.Subscriber, camp *models.Campaign, app *App) error { func sendTestMessage(sub *models.Subscriber, camp *models.Campaign, app *App) error {
if err := camp.CompileTemplate(app.Manager.TemplateFuncs(camp)); err != nil { if err := camp.CompileTemplate(app.Manager.TemplateFuncs(camp)); err != nil {
return fmt.Errorf("Error compiling template: %v", err) return fmt.Errorf("Error compiling template: %v", err)

View File

@ -13,9 +13,6 @@ const (
// stdInputMaxLen is the maximum allowed length for a standard input field. // stdInputMaxLen is the maximum allowed length for a standard input field.
stdInputMaxLen = 200 stdInputMaxLen = 200
// bodyMaxLen is the maximum allowed length for e-mail bodies.
bodyMaxLen = 1000000
// defaultPerPage is the default number of results returned in an GET call. // defaultPerPage is the default number of results returned in an GET call.
defaultPerPage = 20 defaultPerPage = 20

View File

@ -141,6 +141,5 @@ func newConfigFile() error {
return fmt.Errorf("error reading sample config (is binary stuffed?): %v", err) return fmt.Errorf("error reading sample config (is binary stuffed?): %v", err)
} }
ioutil.WriteFile("config.toml", b, 0644) return ioutil.WriteFile("config.toml", b, 0644)
return nil
} }

View File

@ -41,9 +41,11 @@ func handleGetLists(c echo.Context) error {
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, return echo.NewHTTPError(http.StatusInternalServerError,
fmt.Sprintf("Error fetching lists: %s", pqErrMsg(err))) fmt.Sprintf("Error fetching lists: %s", pqErrMsg(err)))
} else if single && len(out.Results) == 0 { }
if single && len(out.Results) == 0 {
return echo.NewHTTPError(http.StatusBadRequest, "List not found.") return echo.NewHTTPError(http.StatusBadRequest, "List not found.")
} else if len(out.Results) == 0 { }
if len(out.Results) == 0 {
return c.JSON(http.StatusOK, okResp{[]struct{}{}}) return c.JSON(http.StatusOK, okResp{[]struct{}{}})
} }
@ -141,7 +143,9 @@ func handleDeleteLists(c echo.Context) error {
) )
// Read the list IDs if they were sent in the body. // Read the list IDs if they were sent in the body.
c.Bind(&ids) if err := c.Bind(&ids); err != nil {
return err
}
if id < 1 && len(ids) == 0 { if id < 1 && len(ids) == 0 {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid ID.") return echo.NewHTTPError(http.StatusBadRequest, "Invalid ID.")

34
main.go
View File

@ -84,7 +84,9 @@ func init() {
f.Bool("new-config", false, "Generate sample config file") f.Bool("new-config", false, "Generate sample config file")
// Process flags. // Process flags.
f.Parse(os.Args[1:]) if err := f.Parse(os.Args[1:]); err != nil {
logger.Fatalf("error loading flags: %v", err)
}
// Display version. // Display version.
if v, _ := f.GetBool("version"); v { if v, _ := f.GetBool("version"); v {
@ -120,13 +122,15 @@ func init() {
}), nil); err != nil { }), nil); err != nil {
logger.Fatalf("error loading config from env: %v", err) logger.Fatalf("error loading config from env: %v", err)
} }
ko.Load(posflag.Provider(f, ".", ko), nil) if err := ko.Load(posflag.Provider(f, ".", ko), nil); err != nil {
logger.Fatalf("error loading config: %v", err)
}
} }
// initFileSystem initializes the stuffbin FileSystem to provide // initFileSystem initializes the stuffbin FileSystem to provide
// access to bunded static assets to the app. // access to bunded static assets to the app.
func initFileSystem(binPath string) (stuffbin.FileSystem, error) { func initFileSystem(binPath string) (stuffbin.FileSystem, error) {
fs, err := stuffbin.UnStuff(os.Args[0]) fs, err := stuffbin.UnStuff(binPath)
if err == nil { if err == nil {
return fs, nil return fs, nil
} }
@ -158,17 +162,23 @@ func initFileSystem(binPath string) (stuffbin.FileSystem, error) {
// initMessengers initializes various messaging backends. // initMessengers initializes various messaging backends.
func initMessengers(r *manager.Manager) messenger.Messenger { func initMessengers(r *manager.Manager) messenger.Messenger {
// Load SMTP configurations for the default e-mail Messenger. // Load SMTP configurations for the default e-mail Messenger.
var srv []messenger.Server var (
for _, name := range ko.MapKeys("smtp") { mapKeys = ko.MapKeys("smtp")
srv = make([]messenger.Server, 0, len(mapKeys))
)
for _, name := range mapKeys {
if !ko.Bool(fmt.Sprintf("smtp.%s.enabled", name)) { if !ko.Bool(fmt.Sprintf("smtp.%s.enabled", name)) {
logger.Printf("skipped SMTP: %s", name) logger.Printf("skipped SMTP: %s", name)
continue continue
} }
var s messenger.Server var s messenger.Server
ko.Unmarshal("smtp."+name, &s) if err := ko.Unmarshal("smtp."+name, &s); err != nil {
logger.Fatalf("error loading SMTP: %v", err)
}
s.Name = name s.Name = name
s.SendTimeout = s.SendTimeout * time.Millisecond s.SendTimeout *= time.Millisecond
srv = append(srv, s) srv = append(srv, s)
logger.Printf("loaded SMTP: %s (%s@%s)", s.Name, s.Username, s.Host) logger.Printf("loaded SMTP: %s (%s@%s)", s.Name, s.Username, s.Host)
@ -199,8 +209,12 @@ func main() {
defer db.Close() defer db.Close()
var c constants var c constants
ko.Unmarshal("app", &c) if err := ko.Unmarshal("app", &c); err != nil {
ko.Unmarshal("privacy", &c.Privacy) log.Fatalf("error loading app config: %v", err)
}
if err := ko.Unmarshal("privacy", &c.Privacy); err != nil {
log.Fatalf("error loading app config: %v", err)
}
c.RootURL = strings.TrimRight(c.RootURL, "/") c.RootURL = strings.TrimRight(c.RootURL, "/")
c.UploadURI = filepath.Clean(c.UploadURI) c.UploadURI = filepath.Clean(c.UploadURI)
c.UploadPath = filepath.Clean(c.UploadPath) c.UploadPath = filepath.Clean(c.UploadPath)
@ -286,7 +300,7 @@ func main() {
app.Messenger = initMessengers(app.Manager) app.Messenger = initMessengers(app.Manager)
// Initialize the workers that push out messages. // Initialize the workers that push out messages.
go m.Run(time.Duration(time.Second * 5)) go m.Run(time.Second * 5)
m.SpawnWorkers() m.SpawnWorkers()
// Initialize the HTTP server. // Initialize the HTTP server.

View File

@ -91,8 +91,8 @@ func New(cfg Config, src DataSource, notifCB models.AdminNotifCallback, l *log.L
notifCB: notifCB, notifCB: notifCB,
logger: l, logger: l,
messengers: make(map[string]messenger.Messenger), messengers: make(map[string]messenger.Messenger),
camps: make(map[int]*models.Campaign, 0), camps: make(map[int]*models.Campaign),
links: make(map[string]string, 0), links: make(map[string]string),
subFetchQueue: make(chan *models.Campaign, cfg.Concurrency), subFetchQueue: make(chan *models.Campaign, cfg.Concurrency),
msgQueue: make(chan *Message, cfg.Concurrency), msgQueue: make(chan *Message, cfg.Concurrency),
msgErrorQueue: make(chan msgError, cfg.MaxSendErrors), msgErrorQueue: make(chan msgError, cfg.MaxSendErrors),
@ -125,7 +125,7 @@ func (m *Manager) AddMessenger(msg messenger.Messenger) error {
// GetMessengerNames returns the list of registered messengers. // GetMessengerNames returns the list of registered messengers.
func (m *Manager) GetMessengerNames() []string { func (m *Manager) GetMessengerNames() []string {
var names []string names := make([]string, 0, len(m.messengers))
for n := range m.messengers { for n := range m.messengers {
names = append(names, n) names = append(names, n)
} }

View File

@ -16,9 +16,8 @@ import (
var imageMimes = []string{"image/jpg", "image/jpeg", "image/png", "image/svg", "image/gif"} var imageMimes = []string{"image/jpg", "image/jpeg", "image/png", "image/svg", "image/gif"}
const ( const (
thumbPrefix = "thumb_" thumbPrefix = "thumb_"
thumbWidth = 90 thumbnailSize = 90
thumbHeight = 90
) )
// handleUploadMedia handles media file uploads. // handleUploadMedia handles media file uploads.
@ -52,7 +51,7 @@ func handleUploadMedia(c echo.Context) error {
fmt.Sprintf("Error opening image for resizing: %s", err)) fmt.Sprintf("Error opening image for resizing: %s", err))
} }
t := imaging.Resize(src, thumbWidth, 0, imaging.Lanczos) t := imaging.Resize(src, thumbnailSize, 0, imaging.Lanczos)
if err := imaging.Save(t, fmt.Sprintf("%s/%s%s", app.Constants.UploadPath, thumbPrefix, fName)); err != nil { if err := imaging.Save(t, fmt.Sprintf("%s/%s%s", app.Constants.UploadPath, thumbPrefix, fName)); err != nil {
cleanUp = true cleanUp = true
return echo.NewHTTPError(http.StatusInternalServerError, return echo.NewHTTPError(http.StatusInternalServerError,

View File

@ -38,7 +38,8 @@ func NewEmailer(srv ...Server) (Messenger, error) {
servers: make(map[string]*Server), servers: make(map[string]*Server),
} }
for _, s := range srv { for _, server := range srv {
s := server
var auth smtp.Auth var auth smtp.Auth
if s.AuthProtocol == "cram" { if s.AuthProtocol == "cram" {
auth = smtp.CRAMMD5Auth(s.Username, s.Password) auth = smtp.CRAMMD5Auth(s.Username, s.Password)

View File

@ -29,6 +29,6 @@ func MakeAttachmentHeader(filename, encoding string) textproto.MIMEHeader {
h := textproto.MIMEHeader{} h := textproto.MIMEHeader{}
h.Set("Content-Disposition", "attachment; filename="+filename) h.Set("Content-Disposition", "attachment; filename="+filename)
h.Set("Content-Type", "application/json; name=\""+filename+"\"") h.Set("Content-Type", "application/json; name=\""+filename+"\"")
h.Set("Content-Transfer-Encoding", "base64") h.Set("Content-Transfer-Encoding", encoding)
return h return h
} }

View File

@ -232,6 +232,6 @@ func drawTransparentImage(h, w int) []byte {
img = image.NewRGBA(image.Rect(0, 0, w, h)) img = image.NewRGBA(image.Rect(0, 0, w, h))
out = &bytes.Buffer{} out = &bytes.Buffer{}
) )
png.Encode(out, img) _ = png.Encode(out, img)
return out.Bytes() return out.Bytes()
} }

View File

@ -335,7 +335,7 @@ func (s *Session) ExtractZIP(srcPath string, maxCSVs int) (string, []string, err
return "", nil, err return "", nil, err
} }
var files []string files := make([]string, 0, len(z.File))
for _, f := range z.File { for _, f := range z.File {
fName := f.FileInfo().Name() fName := f.FileInfo().Name()
@ -421,7 +421,7 @@ func (s *Session) LoadCSV(srcPath string, delim rune) error {
s.im.Unlock() s.im.Unlock()
// Rewind, now that we've done a linecount on the same handler. // Rewind, now that we've done a linecount on the same handler.
f.Seek(0, 0) _, _ = f.Seek(0, 0)
rd := csv.NewReader(f) rd := csv.NewReader(f)
rd.Comma = delim rd.Comma = delim

View File

@ -69,10 +69,13 @@ func handleGetSubscriber(c echo.Context) error {
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, return echo.NewHTTPError(http.StatusInternalServerError,
fmt.Sprintf("Error fetching subscriber: %s", pqErrMsg(err))) fmt.Sprintf("Error fetching subscriber: %s", pqErrMsg(err)))
} else if len(out) == 0 { }
if len(out) == 0 {
return echo.NewHTTPError(http.StatusBadRequest, "Subscriber not found.") return echo.NewHTTPError(http.StatusBadRequest, "Subscriber not found.")
} }
out.LoadLists(app.Queries.GetSubscriberLists) if err := out.LoadLists(app.Queries.GetSubscriberLists); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Error loading lists for subscriber.")
}
return c.JSON(http.StatusOK, okResp{out[0]}) return c.JSON(http.StatusOK, okResp{out[0]})
} }

View File

@ -28,10 +28,6 @@ const (
<p>Here is a link to <a href="https://listmonk.app" target="_blank">listmonk</a>.</p>` <p>Here is a link to <a href="https://listmonk.app" target="_blank">listmonk</a>.</p>`
) )
type dummyMessage struct {
UnsubscribeURL string
}
var ( var (
regexpTplTag = regexp.MustCompile(`{{(\s+)?template\s+?"content"(\s+)?\.(\s+)?}}`) regexpTplTag = regexp.MustCompile(`{{(\s+)?template\s+?"content"(\s+)?\.(\s+)?}}`)
) )
@ -56,12 +52,14 @@ func handleGetTemplates(c echo.Context) error {
if err != nil { if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, return echo.NewHTTPError(http.StatusInternalServerError,
fmt.Sprintf("Error fetching templates: %s", pqErrMsg(err))) fmt.Sprintf("Error fetching templates: %s", pqErrMsg(err)))
} else if single && len(out) == 0 { }
if single && len(out) == 0 {
return echo.NewHTTPError(http.StatusBadRequest, "Template not found.") return echo.NewHTTPError(http.StatusBadRequest, "Template not found.")
} else if len(out) == 0 {
return c.JSON(http.StatusOK, okResp{[]struct{}{}})
} }
if len(out) == 0 {
return c.JSON(http.StatusOK, okResp{[]struct{}{}})
}
if single { if single {
return c.JSON(http.StatusOK, okResp{out[0]}) return c.JSON(http.StatusOK, okResp{out[0]})
} }

View File

@ -27,11 +27,11 @@ var (
// filename_(number). The number is incremented in case // filename_(number). The number is incremented in case
// new file uploads conflict with existing filenames // new file uploads conflict with existing filenames
// on the filesystem. // on the filesystem.
fnameRegexp, _ = regexp.Compile(`(.+?)_([0-9]+)$`) fnameRegexp = regexp.MustCompile(`(.+?)_([0-9]+)$`)
// This replaces all special characters // This replaces all special characters
tagRegexp, _ = regexp.Compile(`[^a-z0-9\-\s]`) tagRegexp = regexp.MustCompile(`[^a-z0-9\-\s]`)
tagRegexpSpaces, _ = regexp.Compile(`[\s]+`) tagRegexpSpaces = regexp.MustCompile(`[\s]+`)
) )
// ScanToStruct prepares a given set of Queries and assigns the resulting // ScanToStruct prepares a given set of Queries and assigns the resulting
@ -248,7 +248,7 @@ func normalizeTags(tags []string) []string {
// makeMsgTpl takes a page title, heading, and message and returns // makeMsgTpl takes a page title, heading, and message and returns
// a msgTpl that can be rendered as a HTML view. This is used for // a msgTpl that can be rendered as a HTML view. This is used for
// rendering aribtrary HTML views with error and success messages. // rendering arbitrary HTML views with error and success messages.
func makeMsgTpl(pageTitle, heading, msg string) msgTpl { func makeMsgTpl(pageTitle, heading, msg string) msgTpl {
if heading == "" { if heading == "" {
heading = pageTitle heading = pageTitle
@ -265,7 +265,7 @@ func makeMsgTpl(pageTitle, heading, msg string) msgTpl {
// parses each number into an int64 and returns a slice of the // parses each number into an int64 and returns a slice of the
// resultant values. // resultant values.
func parseStringIDs(s []string) ([]int64, error) { func parseStringIDs(s []string) ([]int64, error) {
var vals []int64 vals := make([]int64, 0, len(s))
for _, v := range s { for _, v := range s {
i, err := strconv.ParseInt(v, 10, 64) i, err := strconv.ParseInt(v, 10, 64)