This moves `hostName` to the `Collection` struct, where it's needed. The field is populated after successful `GetCollection...()` calls. This isn't the cleanest way to do things, but it accomplishes the goal. Eventually, we should accept the AppCfg to `GetCollection...()` calls, or make them `App` methods, instead of `datastore` methods. Ref T613pull/102/head
@@ -80,6 +80,7 @@ func handleFetchCollectionActivities(app *App, w http.ResponseWriter, r *http.Re | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
c.hostName = app.cfg.App.Host | |||||
p := c.PersonObject() | p := c.PersonObject() | ||||
@@ -104,6 +105,7 @@ func handleFetchCollectionOutbox(app *App, w http.ResponseWriter, r *http.Reques | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
c.hostName = app.cfg.App.Host | |||||
if app.cfg.App.SingleUser { | if app.cfg.App.SingleUser { | ||||
if alias != c.Alias { | if alias != c.Alias { | ||||
@@ -156,6 +158,7 @@ func handleFetchCollectionFollowers(app *App, w http.ResponseWriter, r *http.Req | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
c.hostName = app.cfg.App.Host | |||||
accountRoot := c.FederatedAccount() | accountRoot := c.FederatedAccount() | ||||
@@ -201,6 +204,7 @@ func handleFetchCollectionFollowing(app *App, w http.ResponseWriter, r *http.Req | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
c.hostName = app.cfg.App.Host | |||||
accountRoot := c.FederatedAccount() | accountRoot := c.FederatedAccount() | ||||
@@ -234,6 +238,7 @@ func handleFetchCollectionInbox(app *App, w http.ResponseWriter, r *http.Request | |||||
// TODO: return Reject? | // TODO: return Reject? | ||||
return err | return err | ||||
} | } | ||||
c.hostName = app.cfg.App.Host | |||||
if debugging { | if debugging { | ||||
dump, err := httputil.DumpRequest(r, true) | dump, err := httputil.DumpRequest(r, true) | ||||
@@ -349,7 +354,7 @@ func handleFetchCollectionInbox(app *App, w http.ResponseWriter, r *http.Request | |||||
log.Error("No to! %v", err) | log.Error("No to! %v", err) | ||||
return | return | ||||
} | } | ||||
err = makeActivityPost(p, fullActor.Inbox, am) | |||||
err = makeActivityPost(app.cfg.App.Host, p, fullActor.Inbox, am) | |||||
if err != nil { | if err != nil { | ||||
log.Error("Unable to make activity POST: %v", err) | log.Error("Unable to make activity POST: %v", err) | ||||
return | return | ||||
@@ -423,7 +428,7 @@ func handleFetchCollectionInbox(app *App, w http.ResponseWriter, r *http.Request | |||||
return nil | return nil | ||||
} | } | ||||
func makeActivityPost(p *activitystreams.Person, url string, m interface{}) error { | |||||
func makeActivityPost(hostName string, p *activitystreams.Person, url string, m interface{}) error { | |||||
log.Info("POST %s", url) | log.Info("POST %s", url) | ||||
b, err := json.Marshal(m) | b, err := json.Marshal(m) | ||||
if err != nil { | if err != nil { | ||||
@@ -477,7 +482,7 @@ func makeActivityPost(p *activitystreams.Person, url string, m interface{}) erro | |||||
return nil | return nil | ||||
} | } | ||||
func resolveIRI(url string) ([]byte, error) { | |||||
func resolveIRI(hostName, url string) ([]byte, error) { | |||||
log.Info("GET %s", url) | log.Info("GET %s", url) | ||||
r, _ := http.NewRequest("GET", url, nil) | r, _ := http.NewRequest("GET", url, nil) | ||||
@@ -547,7 +552,7 @@ func deleteFederatedPost(app *App, p *PublicPost, collID int64) error { | |||||
na.CC = append(na.CC, f) | na.CC = append(na.CC, f) | ||||
} | } | ||||
err = makeActivityPost(actor, si, activitystreams.NewDeleteActivity(na)) | |||||
err = makeActivityPost(app.cfg.App.Host, actor, si, activitystreams.NewDeleteActivity(na)) | |||||
if err != nil { | if err != nil { | ||||
log.Error("Couldn't delete post! %v", err) | log.Error("Couldn't delete post! %v", err) | ||||
} | } | ||||
@@ -601,7 +606,7 @@ func federatePost(app *App, p *PublicPost, collID int64, isUpdate bool) error { | |||||
activity.To = na.To | activity.To = na.To | ||||
activity.CC = na.CC | activity.CC = na.CC | ||||
} | } | ||||
err = makeActivityPost(actor, si, activity) | |||||
err = makeActivityPost(app.cfg.App.Host, actor, si, activity) | |||||
if err != nil { | if err != nil { | ||||
log.Error("Couldn't post! %v", err) | log.Error("Couldn't post! %v", err) | ||||
} | } | ||||
@@ -632,7 +637,7 @@ func getActor(app *App, actorIRI string) (*activitystreams.Person, *RemoteUser, | |||||
if iErr.Status == http.StatusNotFound { | if iErr.Status == http.StatusNotFound { | ||||
// Fetch remote actor | // Fetch remote actor | ||||
log.Info("Not found; fetching actor %s remotely", actorIRI) | log.Info("Not found; fetching actor %s remotely", actorIRI) | ||||
actorResp, err := resolveIRI(actorIRI) | |||||
actorResp, err := resolveIRI(app.cfg.App.Host, actorIRI) | |||||
if err != nil { | if err != nil { | ||||
log.Error("Unable to get actor! %v", err) | log.Error("Unable to get actor! %v", err) | ||||
return nil, nil, impart.HTTPError{http.StatusInternalServerError, "Couldn't fetch actor."} | return nil, nil, impart.HTTPError{http.StatusInternalServerError, "Couldn't fetch actor."} | ||||
@@ -57,9 +57,6 @@ var ( | |||||
softwareVer = "0.9.0" | softwareVer = "0.9.0" | ||||
// DEPRECATED VARS | // DEPRECATED VARS | ||||
// TODO: pass app.cfg into GetCollection* calls so we can get these values | |||||
// from Collection methods and we no longer need these. | |||||
hostName string | |||||
isSingleUser bool | isSingleUser bool | ||||
) | ) | ||||
@@ -338,7 +335,6 @@ func Initialize(apper Apper, debug bool) (*App, error) { | |||||
func Serve(app *App, r *mux.Router) { | func Serve(app *App, r *mux.Router) { | ||||
log.Info("Going to serve...") | log.Info("Going to serve...") | ||||
hostName = app.cfg.App.Host | |||||
isSingleUser = app.cfg.App.SingleUser | isSingleUser = app.cfg.App.SingleUser | ||||
app.cfg.Server.Dev = debugging | app.cfg.Server.Dev = debugging | ||||
@@ -54,7 +54,8 @@ type ( | |||||
PublicOwner bool `datastore:"public_owner" json:"-"` | PublicOwner bool `datastore:"public_owner" json:"-"` | ||||
URL string `json:"url,omitempty"` | URL string `json:"url,omitempty"` | ||||
db *datastore | |||||
db *datastore | |||||
hostName string | |||||
} | } | ||||
CollectionObj struct { | CollectionObj struct { | ||||
Collection | Collection | ||||
@@ -211,10 +212,10 @@ func (c *Collection) DisplayCanonicalURL() string { | |||||
func (c *Collection) RedirectingCanonicalURL(isRedir bool) string { | func (c *Collection) RedirectingCanonicalURL(isRedir bool) string { | ||||
if isSingleUser { | if isSingleUser { | ||||
return hostName + "/" | |||||
return c.hostName + "/" | |||||
} | } | ||||
return fmt.Sprintf("%s/%s/", hostName, c.Alias) | |||||
return fmt.Sprintf("%s/%s/", c.hostName, c.Alias) | |||||
} | } | ||||
// PrevPageURL provides a full URL for the previous page of collection posts, | // PrevPageURL provides a full URL for the previous page of collection posts, | ||||
@@ -300,11 +301,11 @@ func (c *Collection) AvatarURL() string { | |||||
if !isAvatarChar(fl) { | if !isAvatarChar(fl) { | ||||
return "" | return "" | ||||
} | } | ||||
return hostName + "/img/avatars/" + fl + ".png" | |||||
return c.hostName + "/img/avatars/" + fl + ".png" | |||||
} | } | ||||
func (c *Collection) FederatedAPIBase() string { | func (c *Collection) FederatedAPIBase() string { | ||||
return hostName + "/" | |||||
return c.hostName + "/" | |||||
} | } | ||||
func (c *Collection) FederatedAccount() string { | func (c *Collection) FederatedAccount() string { | ||||
@@ -434,6 +435,8 @@ func fetchCollection(app *App, w http.ResponseWriter, r *http.Request) error { | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
c.hostName = app.cfg.App.Host | |||||
// Redirect users who aren't requesting JSON | // Redirect users who aren't requesting JSON | ||||
reqJSON := IsJSON(r.Header.Get("Content-Type")) | reqJSON := IsJSON(r.Header.Get("Content-Type")) | ||||
if !reqJSON { | if !reqJSON { | ||||
@@ -475,6 +478,7 @@ func fetchCollectionPosts(app *App, w http.ResponseWriter, r *http.Request) erro | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
c.hostName = app.cfg.App.Host | |||||
// Check permissions | // Check permissions | ||||
userID, err := apiCheckCollectionPermissions(app, r, c) | userID, err := apiCheckCollectionPermissions(app, r, c) | ||||
@@ -600,6 +604,7 @@ func processCollectionPermissions(app *App, cr *collectionReq, u *User, w http.R | |||||
} | } | ||||
return nil, err | return nil, err | ||||
} | } | ||||
c.hostName = app.cfg.App.Host | |||||
// Update CollectionRequest to reflect owner status | // Update CollectionRequest to reflect owner status | ||||
cr.isCollOwner = u != nil && u.ID == c.OwnerID | cr.isCollOwner = u != nil && u.ID == c.OwnerID | ||||
@@ -34,6 +34,7 @@ func ViewFeed(app *App, w http.ResponseWriter, req *http.Request) error { | |||||
if err != nil { | if err != nil { | ||||
return nil | return nil | ||||
} | } | ||||
c.hostName = app.cfg.App.Host | |||||
if c.IsPrivate() || c.IsProtected() { | if c.IsPrivate() || c.IsProtected() { | ||||
return ErrCollectionNotFound | return ErrCollectionNotFound | ||||
@@ -996,6 +996,7 @@ func fetchPost(app *App, w http.ResponseWriter, r *http.Request) error { | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
coll.hostName = app.cfg.App.Host | |||||
_, err = apiCheckCollectionPermissions(app, r, coll) | _, err = apiCheckCollectionPermissions(app, r, coll) | ||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
@@ -1056,7 +1057,7 @@ func (p *Post) processPost() PublicPost { | |||||
func (p *PublicPost) CanonicalURL() string { | func (p *PublicPost) CanonicalURL() string { | ||||
if p.Collection == nil || p.Collection.Alias == "" { | if p.Collection == nil || p.Collection.Alias == "" { | ||||
return hostName + "/" + p.ID | |||||
return p.Collection.hostName + "/" + p.ID | |||||
} | } | ||||
return p.Collection.CanonicalURL() + p.Slug.String | return p.Collection.CanonicalURL() + p.Slug.String | ||||
} | } | ||||
@@ -1087,7 +1088,7 @@ func (p *PublicPost) ActivityObject() *activitystreams.Object { | |||||
if isSingleUser { | if isSingleUser { | ||||
tagBaseURL = p.Collection.CanonicalURL() + "tag:" | tagBaseURL = p.Collection.CanonicalURL() + "tag:" | ||||
} else { | } else { | ||||
tagBaseURL = fmt.Sprintf("%s/%s/tag:", hostName, p.Collection.Alias) | |||||
tagBaseURL = fmt.Sprintf("%s/%s/tag:", p.Collection.hostName, p.Collection.Alias) | |||||
} | } | ||||
for _, t := range p.Tags { | for _, t := range p.Tags { | ||||
o.Tag = append(o.Tag, activitystreams.Tag{ | o.Tag = append(o.Tag, activitystreams.Tag{ | ||||
@@ -1244,6 +1245,7 @@ func viewCollectionPost(app *App, w http.ResponseWriter, r *http.Request) error | |||||
} | } | ||||
return err | return err | ||||
} | } | ||||
c.hostName = app.cfg.App.Host | |||||
// Check collection permissions | // Check collection permissions | ||||
if c.IsPrivate() && (u == nil || u.ID != c.OwnerID) { | if c.IsPrivate() && (u == nil || u.ID != c.OwnerID) { | ||||
@@ -52,17 +52,17 @@ type readPublication struct { | |||||
func initLocalTimeline(app *App) { | func initLocalTimeline(app *App) { | ||||
app.timeline = &localTimeline{ | app.timeline = &localTimeline{ | ||||
postsPerPage: tlPostsPerPage, | postsPerPage: tlPostsPerPage, | ||||
m: memo.New(app.db.FetchPublicPosts, 10*time.Minute), | |||||
m: memo.New(app.FetchPublicPosts, 10*time.Minute), | |||||
} | } | ||||
} | } | ||||
// satisfies memo.Func | // satisfies memo.Func | ||||
func (db *datastore) FetchPublicPosts() (interface{}, error) { | |||||
func (app *App) FetchPublicPosts() (interface{}, error) { | |||||
// Finds all public posts and posts in a public collection published during the owner's active subscription period and within the last 3 months | // Finds all public posts and posts in a public collection published during the owner's active subscription period and within the last 3 months | ||||
rows, err := db.Query(`SELECT p.id, alias, c.title, p.slug, p.title, p.content, p.text_appearance, p.language, p.rtl, p.created, p.updated | |||||
rows, err := app.db.Query(`SELECT p.id, alias, c.title, p.slug, p.title, p.content, p.text_appearance, p.language, p.rtl, p.created, p.updated | |||||
FROM collections c | FROM collections c | ||||
LEFT JOIN posts p ON p.collection_id = c.id | LEFT JOIN posts p ON p.collection_id = c.id | ||||
WHERE c.privacy = 1 AND (p.created >= ` + db.dateSub(3, "month") + ` AND p.created <= ` + db.now() + ` AND pinned_position IS NULL) | |||||
WHERE c.privacy = 1 AND (p.created >= ` + app.db.dateSub(3, "month") + ` AND p.created <= ` + app.db.now() + ` AND pinned_position IS NULL) | |||||
ORDER BY p.created DESC`) | ORDER BY p.created DESC`) | ||||
if err != nil { | if err != nil { | ||||
log.Error("Failed selecting from posts: %v", err) | log.Error("Failed selecting from posts: %v", err) | ||||
@@ -82,6 +82,8 @@ func (db *datastore) FetchPublicPosts() (interface{}, error) { | |||||
log.Error("[READ] Unable to scan row, skipping: %v", err) | log.Error("[READ] Unable to scan row, skipping: %v", err) | ||||
continue | continue | ||||
} | } | ||||
c.hostName = app.cfg.App.Host | |||||
isCollectionPost := alias.Valid | isCollectionPost := alias.Valid | ||||
if isCollectionPost { | if isCollectionPost { | ||||
c.Alias = alias.String | c.Alias = alias.String | ||||
@@ -244,6 +246,7 @@ func handlePostIDRedirect(app *App, w http.ResponseWriter, r *http.Request) erro | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
c.hostName = app.cfg.App.Host | |||||
// Retrieve collection information and send user to canonical URL | // Retrieve collection information and send user to canonical URL | ||||
return impart.HTTPError{http.StatusFound, c.CanonicalURL() + p.Slug.String} | return impart.HTTPError{http.StatusFound, c.CanonicalURL() + p.Slug.String} | ||||
@@ -57,6 +57,7 @@ func handleViewSitemap(app *App, w http.ResponseWriter, r *http.Request) error { | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
c.hostName = app.cfg.App.Host | |||||
if !isSubdomain { | if !isSubdomain { | ||||
pre += alias + "/" | pre += alias + "/" | ||||
@@ -37,6 +37,7 @@ func (wfr wfResolver) FindUser(username string, host, requestHost string, r []we | |||||
log.Error("Unable to get blog: %v", err) | log.Error("Unable to get blog: %v", err) | ||||
return nil, err | return nil, err | ||||
} | } | ||||
c.hostName = wfr.cfg.App.Host | |||||
if wfr.cfg.App.SingleUser { | if wfr.cfg.App.SingleUser { | ||||
// Ensure handle matches user-chosen one on single-user blogs | // Ensure handle matches user-chosen one on single-user blogs | ||||
if username != c.Alias { | if username != c.Alias { | ||||