diff options
author | Derek Perkins <derek@derekperkins.com> | 2016-09-15 20:28:13 -0600 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2016-09-17 00:49:24 +0200 |
commit | cf978c06496d99e76b08418422dda5797d90fed6 (patch) | |
tree | 301a0eb848539cef0ae7226d0816f37767d69acc /hugolib/author.go | |
parent | 44bf76d0f28cc88a1dc185d1c587e0977652edf2 (diff) |
Add First Class Author Support
Closes #1850
Diffstat (limited to 'hugolib/author.go')
-rw-r--r-- | hugolib/author.go | 157 |
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 } |