package main import ( "bytes" "crypto/rand" "fmt" "path/filepath" "regexp" "strconv" "strings" "github.com/lib/pq" ) var ( regexpSpaces = regexp.MustCompile(`[\s]+`) ) // inArray checks if a string is present in a list of strings. func inArray(val string, vals []string) (ok bool) { for _, v := range vals { if v == val { return true } } return false } // makeFilename sanitizes a filename (user supplied upload filenames). func makeFilename(fName string) string { name := strings.TrimSpace(fName) if name == "" { name, _ = generateRandomString(10) } // replace whitespace with "-" name = regexpSpaces.ReplaceAllString(name, "-") return filepath.Base(name) } // Given an error, pqErrMsg will try to return pq error details // if it's a pq error. func pqErrMsg(err error) string { if err, ok := err.(*pq.Error); ok { if err.Detail != "" { return fmt.Sprintf("%s. %s", err, err.Detail) } } return err.Error() } // normalizeTags takes a list of string tags and normalizes them by // lowercasing and removing all special characters except for dashes. func normalizeTags(tags []string) []string { var ( out []string dash = []byte("-") ) for _, t := range tags { rep := regexpSpaces.ReplaceAll(bytes.TrimSpace([]byte(t)), dash) if len(rep) > 0 { out = append(out, string(rep)) } } return out } // makeMsgTpl takes a page title, heading, and message and returns // a msgTpl that can be rendered as a HTML view. This is used for // rendering arbitrary HTML views with error and success messages. func makeMsgTpl(pageTitle, heading, msg string) msgTpl { if heading == "" { heading = pageTitle } err := msgTpl{} err.Title = pageTitle err.MessageTitle = heading err.Message = msg return err } // parseStringIDs takes a slice of numeric string IDs and // parses each number into an int64 and returns a slice of the // resultant values. func parseStringIDs(s []string) ([]int64, error) { vals := make([]int64, 0, len(s)) for _, v := range s { i, err := strconv.ParseInt(v, 10, 64) if err != nil { return nil, err } if i < 1 { return nil, fmt.Errorf("%d is not a valid ID", i) } vals = append(vals, i) } return vals, nil } // generateRandomString generates a cryptographically random, alphanumeric string of length n. func generateRandomString(n int) (string, error) { const dictionary = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" var bytes = make([]byte, n) if _, err := rand.Read(bytes); err != nil { return "", err } for k, v := range bytes { bytes[k] = dictionary[v%byte(len(dictionary))] } return string(bytes), nil } // strHasLen checks if the given string has a length within min-max. func strHasLen(str string, min, max int) bool { return len(str) >= min && len(str) <= max } // strSliceContains checks if a string is present in the string slice. func strSliceContains(str string, sl []string) bool { for _, s := range sl { if s == str { return true } } return false }