summaryrefslogtreecommitdiffstats
path: root/hugolib/author.go
diff options
context:
space:
mode:
authorDerek Perkins <derek@derekperkins.com>2016-09-15 20:28:13 -0600
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2016-09-17 00:49:24 +0200
commitcf978c06496d99e76b08418422dda5797d90fed6 (patch)
tree301a0eb848539cef0ae7226d0816f37767d69acc /hugolib/author.go
parent44bf76d0f28cc88a1dc185d1c587e0977652edf2 (diff)
Add First Class Author Support
Closes #1850
Diffstat (limited to 'hugolib/author.go')
-rw-r--r--hugolib/author.go157
1 files changed, 145 insertions, 12 deletions
diff --git a/hugolib/author.go b/hugolib/author.go
index 0f4327097..2fbbfe793 100644
--- a/hugolib/author.go
+++ b/hugolib/author.go
@@ -13,23 +13,57 @@
package hugolib
-// AuthorList is a list of all authors and their metadata.
-type AuthorList map[string]Author
+import (
+ "fmt"
+ "regexp"
+ "sort"
+ "strings"
+
+ "github.com/spf13/cast"
+)
+
+var (
+ onlyNumbersRegExp = regexp.MustCompile("^[0-9]*$")
+)
+
+// Authors is a list of all authors and their metadata.
+type Authors []Author
+
+// Get returns an author from an ID
+func (a Authors) Get(id string) Author {
+ for _, author := range a {
+ if author.ID == id {
+ return author
+ }
+ }
+ return Author{}
+}
+
+// Sort sorts the authors by weight
+func (a Authors) Sort() Authors {
+ sort.Stable(a)
+ return a
+}
// Author contains details about the author of a page.
type Author struct {
- GivenName string
- FamilyName string
- DisplayName string
- Thumbnail string
- Image string
- ShortBio string
- LongBio string
- Email string
- Social AuthorSocial
+ ID string
+ GivenName string // givenName OR firstName
+ FirstName string // alias for GivenName
+ FamilyName string // familyName OR lastName
+ LastName string // alias for FamilyName
+ DisplayName string // displayName
+ Thumbnail string // thumbnail
+ Image string // image
+ ShortBio string // shortBio
+ Bio string // bio
+ Email string // email
+ Social AuthorSocial // social
+ Params map[string]string // params
+ Weight int
}
-// AuthorSocial is a place to put social details per author. These are the
+// AuthorSocial is a place to put social usernames per author. These are the
// standard keys that themes will expect to have available, but can be
// expanded to any others on a per site basis
// - website
@@ -43,3 +77,102 @@ type Author struct {
// - linkedin
// - skype
type AuthorSocial map[string]string
+
+// URL is a convenience function that provides the correct canonical URL
+// for a specific social network given a username. If an unsupported network
+// is requested, only the username is returned
+func (as AuthorSocial) URL(key string) string {
+ switch key {
+ case "github":
+ return fmt.Sprintf("https://github.com/%s", as[key])
+ case "facebook":
+ return fmt.Sprintf("https://www.facebook.com/%s", as[key])
+ case "twitter":
+ return fmt.Sprintf("https://twitter.com/%s", as[key])
+ case "googleplus":
+ isNumeric := onlyNumbersRegExp.Match([]byte(as[key]))
+ if isNumeric {
+ return fmt.Sprintf("https://plus.google.com/%s", as[key])
+ }
+ return fmt.Sprintf("https://plus.google.com/+%s", as[key])
+ case "pinterest":
+ return fmt.Sprintf("https://www.pinterest.com/%s/", as[key])
+ case "instagram":
+ return fmt.Sprintf("https://www.instagram.com/%s/", as[key])
+ case "youtube":
+ return fmt.Sprintf("https://www.youtube.com/user/%s", as[key])
+ case "linkedin":
+ return fmt.Sprintf("https://www.linkedin.com/in/%s", as[key])
+ default:
+ return as[key]
+ }
+}
+
+func mapToAuthors(m map[string]interface{}) Authors {
+ authors := make(Authors, len(m))
+ for authorID, data := range m {
+ authorMap, ok := data.(map[string]interface{})
+ if !ok {
+ continue
+ }
+ authors = append(authors, mapToAuthor(authorID, authorMap))
+ }
+ sort.Stable(authors)
+ return authors
+}
+
+func mapToAuthor(id string, m map[string]interface{}) Author {
+ author := Author{ID: id}
+ for k, data := range m {
+ switch k {
+ case "givenName", "firstName":
+ author.GivenName = cast.ToString(data)
+ author.FirstName = author.GivenName
+ case "familyName", "lastName":
+ author.FamilyName = cast.ToString(data)
+ author.LastName = author.FamilyName
+ case "displayName":
+ author.DisplayName = cast.ToString(data)
+ case "thumbnail":
+ author.Thumbnail = cast.ToString(data)
+ case "image":
+ author.Image = cast.ToString(data)
+ case "shortBio":
+ author.ShortBio = cast.ToString(data)
+ case "bio":
+ author.Bio = cast.ToString(data)
+ case "email":
+ author.Email = cast.ToString(data)
+ case "social":
+ author.Social = normalizeSocial(cast.ToStringMapString(data))
+ case "params":
+ author.Params = cast.ToStringMapString(data)
+ }
+ }
+
+ // set a reasonable default for DisplayName
+ if author.DisplayName == "" {
+ author.DisplayName = author.GivenName + " " + author.FamilyName
+ }
+
+ return author
+}
+
+// normalizeSocial makes a naive attempt to normalize social media usernames
+// and strips out extraneous characters or url info
+func normalizeSocial(m map[string]string) map[string]string {
+ for network, username := range m {
+ username = strings.TrimSpace(username)
+ username = strings.TrimSuffix(username, "/")
+ strs := strings.Split(username, "/")
+ username = strs[len(strs)-1]
+ username = strings.TrimPrefix(username, "@")
+ username = strings.TrimPrefix(username, "+")
+ m[network] = username
+ }
+ return m
+}
+
+func (a Authors) Len() int { return len(a) }
+func (a Authors) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a Authors) Less(i, j int) bool { return a[i].Weight < a[j].Weight }