mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 23:12:25 -05:00 
			
		
		
		
	[feature] Add opt-in RSS feed for account's latest Public posts (#897)
* start adding rss functionality * add gorilla/feeds dependency * first bash at building rss feed still needs work, this is an interim commit * tidy up a bit * add publicOnly option to GetAccountLastPosted * implement rss endpoint * fix test * add initial user docs for rss * update rss logo * docs update * add rssFeed to frontend * feed -> feed.rss * enableRSS * increase rss logo size a lil bit * add rss toggle * move emojify to text package * fiddle with rss feed formatting * add Text field to test statuses * move status to rss item to typeconverter * update bun schema for enablerss * simplify 304 checking * assume account not rss * update tests * update swagger docs * allow more characters in title, trim nicer * update last posted to be more consistent
This commit is contained in:
		
					parent
					
						
							
								aa07750bdb
							
						
					
				
			
			
				commit
				
					
						80663061d8
					
				
			
		
					 58 changed files with 2282 additions and 211 deletions
				
			
		
							
								
								
									
										169
									
								
								vendor/github.com/gorilla/feeds/atom.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								vendor/github.com/gorilla/feeds/atom.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,169 @@ | |||
| package feeds | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/xml" | ||||
| 	"fmt" | ||||
| 	"net/url" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| // Generates Atom feed as XML | ||||
| 
 | ||||
| const ns = "http://www.w3.org/2005/Atom" | ||||
| 
 | ||||
| type AtomPerson struct { | ||||
| 	Name  string `xml:"name,omitempty"` | ||||
| 	Uri   string `xml:"uri,omitempty"` | ||||
| 	Email string `xml:"email,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type AtomSummary struct { | ||||
| 	XMLName xml.Name `xml:"summary"` | ||||
| 	Content string   `xml:",chardata"` | ||||
| 	Type    string   `xml:"type,attr"` | ||||
| } | ||||
| 
 | ||||
| type AtomContent struct { | ||||
| 	XMLName xml.Name `xml:"content"` | ||||
| 	Content string   `xml:",chardata"` | ||||
| 	Type    string   `xml:"type,attr"` | ||||
| } | ||||
| 
 | ||||
| type AtomAuthor struct { | ||||
| 	XMLName xml.Name `xml:"author"` | ||||
| 	AtomPerson | ||||
| } | ||||
| 
 | ||||
| type AtomContributor struct { | ||||
| 	XMLName xml.Name `xml:"contributor"` | ||||
| 	AtomPerson | ||||
| } | ||||
| 
 | ||||
| type AtomEntry struct { | ||||
| 	XMLName     xml.Name `xml:"entry"` | ||||
| 	Xmlns       string   `xml:"xmlns,attr,omitempty"` | ||||
| 	Title       string   `xml:"title"`   // required | ||||
| 	Updated     string   `xml:"updated"` // required | ||||
| 	Id          string   `xml:"id"`      // required | ||||
| 	Category    string   `xml:"category,omitempty"` | ||||
| 	Content     *AtomContent | ||||
| 	Rights      string `xml:"rights,omitempty"` | ||||
| 	Source      string `xml:"source,omitempty"` | ||||
| 	Published   string `xml:"published,omitempty"` | ||||
| 	Contributor *AtomContributor | ||||
| 	Links       []AtomLink   // required if no child 'content' elements | ||||
| 	Summary     *AtomSummary // required if content has src or content is base64 | ||||
| 	Author      *AtomAuthor  // required if feed lacks an author | ||||
| } | ||||
| 
 | ||||
| // Multiple links with different rel can coexist | ||||
| type AtomLink struct { | ||||
| 	//Atom 1.0 <link rel="enclosure" type="audio/mpeg" title="MP3" href="http://www.example.org/myaudiofile.mp3" length="1234" /> | ||||
| 	XMLName xml.Name `xml:"link"` | ||||
| 	Href    string   `xml:"href,attr"` | ||||
| 	Rel     string   `xml:"rel,attr,omitempty"` | ||||
| 	Type    string   `xml:"type,attr,omitempty"` | ||||
| 	Length  string   `xml:"length,attr,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type AtomFeed struct { | ||||
| 	XMLName     xml.Name `xml:"feed"` | ||||
| 	Xmlns       string   `xml:"xmlns,attr"` | ||||
| 	Title       string   `xml:"title"`   // required | ||||
| 	Id          string   `xml:"id"`      // required | ||||
| 	Updated     string   `xml:"updated"` // required | ||||
| 	Category    string   `xml:"category,omitempty"` | ||||
| 	Icon        string   `xml:"icon,omitempty"` | ||||
| 	Logo        string   `xml:"logo,omitempty"` | ||||
| 	Rights      string   `xml:"rights,omitempty"` // copyright used | ||||
| 	Subtitle    string   `xml:"subtitle,omitempty"` | ||||
| 	Link        *AtomLink | ||||
| 	Author      *AtomAuthor `xml:"author,omitempty"` | ||||
| 	Contributor *AtomContributor | ||||
| 	Entries     []*AtomEntry `xml:"entry"` | ||||
| } | ||||
| 
 | ||||
| type Atom struct { | ||||
| 	*Feed | ||||
| } | ||||
| 
 | ||||
| func newAtomEntry(i *Item) *AtomEntry { | ||||
| 	id := i.Id | ||||
| 	// assume the description is html | ||||
| 	s := &AtomSummary{Content: i.Description, Type: "html"} | ||||
| 
 | ||||
| 	if len(id) == 0 { | ||||
| 		// if there's no id set, try to create one, either from data or just a uuid | ||||
| 		if len(i.Link.Href) > 0 && (!i.Created.IsZero() || !i.Updated.IsZero()) { | ||||
| 			dateStr := anyTimeFormat("2006-01-02", i.Updated, i.Created) | ||||
| 			host, path := i.Link.Href, "/invalid.html" | ||||
| 			if url, err := url.Parse(i.Link.Href); err == nil { | ||||
| 				host, path = url.Host, url.Path | ||||
| 			} | ||||
| 			id = fmt.Sprintf("tag:%s,%s:%s", host, dateStr, path) | ||||
| 		} else { | ||||
| 			id = "urn:uuid:" + NewUUID().String() | ||||
| 		} | ||||
| 	} | ||||
| 	var name, email string | ||||
| 	if i.Author != nil { | ||||
| 		name, email = i.Author.Name, i.Author.Email | ||||
| 	} | ||||
| 
 | ||||
| 	link_rel := i.Link.Rel | ||||
| 	if link_rel == "" { | ||||
| 		link_rel = "alternate" | ||||
| 	} | ||||
| 	x := &AtomEntry{ | ||||
| 		Title:   i.Title, | ||||
| 		Links:   []AtomLink{{Href: i.Link.Href, Rel: link_rel, Type: i.Link.Type}}, | ||||
| 		Id:      id, | ||||
| 		Updated: anyTimeFormat(time.RFC3339, i.Updated, i.Created), | ||||
| 		Summary: s, | ||||
| 	} | ||||
| 
 | ||||
| 	// if there's a content, assume it's html | ||||
| 	if len(i.Content) > 0 { | ||||
| 		x.Content = &AtomContent{Content: i.Content, Type: "html"} | ||||
| 	} | ||||
| 
 | ||||
| 	if i.Enclosure != nil && link_rel != "enclosure" { | ||||
| 		x.Links = append(x.Links, AtomLink{Href: i.Enclosure.Url, Rel: "enclosure", Type: i.Enclosure.Type, Length: i.Enclosure.Length}) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(name) > 0 || len(email) > 0 { | ||||
| 		x.Author = &AtomAuthor{AtomPerson: AtomPerson{Name: name, Email: email}} | ||||
| 	} | ||||
| 	return x | ||||
| } | ||||
| 
 | ||||
| // create a new AtomFeed with a generic Feed struct's data | ||||
| func (a *Atom) AtomFeed() *AtomFeed { | ||||
| 	updated := anyTimeFormat(time.RFC3339, a.Updated, a.Created) | ||||
| 	feed := &AtomFeed{ | ||||
| 		Xmlns:    ns, | ||||
| 		Title:    a.Title, | ||||
| 		Link:     &AtomLink{Href: a.Link.Href, Rel: a.Link.Rel}, | ||||
| 		Subtitle: a.Description, | ||||
| 		Id:       a.Link.Href, | ||||
| 		Updated:  updated, | ||||
| 		Rights:   a.Copyright, | ||||
| 	} | ||||
| 	if a.Author != nil { | ||||
| 		feed.Author = &AtomAuthor{AtomPerson: AtomPerson{Name: a.Author.Name, Email: a.Author.Email}} | ||||
| 	} | ||||
| 	for _, e := range a.Items { | ||||
| 		feed.Entries = append(feed.Entries, newAtomEntry(e)) | ||||
| 	} | ||||
| 	return feed | ||||
| } | ||||
| 
 | ||||
| // FeedXml returns an XML-Ready object for an Atom object | ||||
| func (a *Atom) FeedXml() interface{} { | ||||
| 	return a.AtomFeed() | ||||
| } | ||||
| 
 | ||||
| // FeedXml returns an XML-ready object for an AtomFeed object | ||||
| func (a *AtomFeed) FeedXml() interface{} { | ||||
| 	return a | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue