Make App struct public

This commit is contained in:
Matt Baer 2019-05-12 16:55:30 -04:00
parent 9023d4eb3f
commit d8937e89a8
19 changed files with 140 additions and 139 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2019 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -49,7 +49,7 @@ type (
} }
) )
func NewUserPage(app *app, r *http.Request, u *User, title string, flashes []string) *UserPage { func NewUserPage(app *App, r *http.Request, u *User, title string, flashes []string) *UserPage {
up := &UserPage{ up := &UserPage{
StaticPage: pageForReq(app, r), StaticPage: pageForReq(app, r),
PageTitle: title, PageTitle: title,
@ -73,12 +73,12 @@ const (
var actuallyUsernameReg = regexp.MustCompile("username is actually ([a-z0-9\\-]+)\\. Please try that, instead") var actuallyUsernameReg = regexp.MustCompile("username is actually ([a-z0-9\\-]+)\\. Please try that, instead")
func apiSignup(app *app, w http.ResponseWriter, r *http.Request) error { func apiSignup(app *App, w http.ResponseWriter, r *http.Request) error {
_, err := signup(app, w, r) _, err := signup(app, w, r)
return err return err
} }
func signup(app *app, w http.ResponseWriter, r *http.Request) (*AuthUser, error) { func signup(app *App, w http.ResponseWriter, r *http.Request) (*AuthUser, error) {
reqJSON := IsJSON(r.Header.Get("Content-Type")) reqJSON := IsJSON(r.Header.Get("Content-Type"))
// Get params // Get params
@ -113,7 +113,7 @@ func signup(app *app, w http.ResponseWriter, r *http.Request) (*AuthUser, error)
return signupWithRegistration(app, ur, w, r) return signupWithRegistration(app, ur, w, r)
} }
func signupWithRegistration(app *app, signup userRegistration, w http.ResponseWriter, r *http.Request) (*AuthUser, error) { func signupWithRegistration(app *App, signup userRegistration, w http.ResponseWriter, r *http.Request) (*AuthUser, error) {
reqJSON := IsJSON(r.Header.Get("Content-Type")) reqJSON := IsJSON(r.Header.Get("Content-Type"))
// Validate required params (alias) // Validate required params (alias)
@ -229,7 +229,7 @@ func signupWithRegistration(app *app, signup userRegistration, w http.ResponseWr
return resUser, nil return resUser, nil
} }
func viewLogout(app *app, w http.ResponseWriter, r *http.Request) error { func viewLogout(app *App, w http.ResponseWriter, r *http.Request) error {
session, err := app.sessionStore.Get(r, cookieName) session, err := app.sessionStore.Get(r, cookieName)
if err != nil { if err != nil {
return ErrInternalCookieSession return ErrInternalCookieSession
@ -268,7 +268,7 @@ func viewLogout(app *app, w http.ResponseWriter, r *http.Request) error {
return impart.HTTPError{http.StatusFound, "/"} return impart.HTTPError{http.StatusFound, "/"}
} }
func handleAPILogout(app *app, w http.ResponseWriter, r *http.Request) error { func handleAPILogout(app *App, w http.ResponseWriter, r *http.Request) error {
accessToken := r.Header.Get("Authorization") accessToken := r.Header.Get("Authorization")
if accessToken == "" { if accessToken == "" {
return ErrNoAccessToken return ErrNoAccessToken
@ -284,7 +284,7 @@ func handleAPILogout(app *app, w http.ResponseWriter, r *http.Request) error {
return impart.HTTPError{Status: http.StatusNoContent} return impart.HTTPError{Status: http.StatusNoContent}
} }
func viewLogin(app *app, w http.ResponseWriter, r *http.Request) error { func viewLogin(app *App, w http.ResponseWriter, r *http.Request) error {
var earlyError string var earlyError string
oneTimeToken := r.FormValue("with") oneTimeToken := r.FormValue("with")
if oneTimeToken != "" { if oneTimeToken != "" {
@ -333,7 +333,7 @@ func viewLogin(app *app, w http.ResponseWriter, r *http.Request) error {
return nil return nil
} }
func webLogin(app *app, w http.ResponseWriter, r *http.Request) error { func webLogin(app *App, w http.ResponseWriter, r *http.Request) error {
err := login(app, w, r) err := login(app, w, r)
if err != nil { if err != nil {
username := r.FormValue("alias") username := r.FormValue("alias")
@ -370,7 +370,7 @@ func webLogin(app *app, w http.ResponseWriter, r *http.Request) error {
var loginAttemptUsers = sync.Map{} var loginAttemptUsers = sync.Map{}
func login(app *app, w http.ResponseWriter, r *http.Request) error { func login(app *App, w http.ResponseWriter, r *http.Request) error {
reqJSON := IsJSON(r.Header.Get("Content-Type")) reqJSON := IsJSON(r.Header.Get("Content-Type"))
oneTimeToken := r.FormValue("with") oneTimeToken := r.FormValue("with")
verbose := r.FormValue("all") == "true" || r.FormValue("verbose") == "1" || r.FormValue("verbose") == "true" || (reqJSON && oneTimeToken != "") verbose := r.FormValue("all") == "true" || r.FormValue("verbose") == "1" || r.FormValue("verbose") == "true" || (reqJSON && oneTimeToken != "")
@ -534,7 +534,7 @@ func login(app *app, w http.ResponseWriter, r *http.Request) error {
return nil return nil
} }
func getVerboseAuthUser(app *app, token string, u *User, verbose bool) *AuthUser { func getVerboseAuthUser(app *App, token string, u *User, verbose bool) *AuthUser {
resUser := &AuthUser{ resUser := &AuthUser{
AccessToken: token, AccessToken: token,
User: u, User: u,
@ -563,7 +563,7 @@ func getVerboseAuthUser(app *app, token string, u *User, verbose bool) *AuthUser
return resUser return resUser
} }
func viewExportOptions(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func viewExportOptions(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
// Fetch extra user data // Fetch extra user data
p := NewUserPage(app, r, u, "Export", nil) p := NewUserPage(app, r, u, "Export", nil)
@ -571,7 +571,7 @@ func viewExportOptions(app *app, u *User, w http.ResponseWriter, r *http.Request
return nil return nil
} }
func viewExportPosts(app *app, w http.ResponseWriter, r *http.Request) ([]byte, string, error) { func viewExportPosts(app *App, w http.ResponseWriter, r *http.Request) ([]byte, string, error) {
var filename string var filename string
var u = &User{} var u = &User{}
reqJSON := IsJSON(r.Header.Get("Content-Type")) reqJSON := IsJSON(r.Header.Get("Content-Type"))
@ -635,7 +635,7 @@ func viewExportPosts(app *app, w http.ResponseWriter, r *http.Request) ([]byte,
return data, filename, err return data, filename, err
} }
func viewExportFull(app *app, w http.ResponseWriter, r *http.Request) ([]byte, string, error) { func viewExportFull(app *App, w http.ResponseWriter, r *http.Request) ([]byte, string, error) {
var err error var err error
filename := "" filename := ""
u := getUserSession(app, r) u := getUserSession(app, r)
@ -655,7 +655,7 @@ func viewExportFull(app *app, w http.ResponseWriter, r *http.Request) ([]byte, s
return data, filename, err return data, filename, err
} }
func viewMeAPI(app *app, w http.ResponseWriter, r *http.Request) error { func viewMeAPI(app *App, w http.ResponseWriter, r *http.Request) error {
reqJSON := IsJSON(r.Header.Get("Content-Type")) reqJSON := IsJSON(r.Header.Get("Content-Type"))
uObj := struct { uObj := struct {
ID int64 `json:"id,omitempty"` ID int64 `json:"id,omitempty"`
@ -679,7 +679,7 @@ func viewMeAPI(app *app, w http.ResponseWriter, r *http.Request) error {
return impart.WriteSuccess(w, uObj, http.StatusOK) return impart.WriteSuccess(w, uObj, http.StatusOK)
} }
func viewMyPostsAPI(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func viewMyPostsAPI(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
reqJSON := IsJSON(r.Header.Get("Content-Type")) reqJSON := IsJSON(r.Header.Get("Content-Type"))
if !reqJSON { if !reqJSON {
return ErrBadRequestedType return ErrBadRequestedType
@ -710,7 +710,7 @@ func viewMyPostsAPI(app *app, u *User, w http.ResponseWriter, r *http.Request) e
return impart.WriteSuccess(w, p, http.StatusOK) return impart.WriteSuccess(w, p, http.StatusOK)
} }
func viewMyCollectionsAPI(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func viewMyCollectionsAPI(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
reqJSON := IsJSON(r.Header.Get("Content-Type")) reqJSON := IsJSON(r.Header.Get("Content-Type"))
if !reqJSON { if !reqJSON {
return ErrBadRequestedType return ErrBadRequestedType
@ -724,7 +724,7 @@ func viewMyCollectionsAPI(app *app, u *User, w http.ResponseWriter, r *http.Requ
return impart.WriteSuccess(w, p, http.StatusOK) return impart.WriteSuccess(w, p, http.StatusOK)
} }
func viewArticles(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func viewArticles(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
p, err := app.db.GetAnonymousPosts(u) p, err := app.db.GetAnonymousPosts(u)
if err != nil { if err != nil {
log.Error("unable to fetch anon posts: %v", err) log.Error("unable to fetch anon posts: %v", err)
@ -761,7 +761,7 @@ func viewArticles(app *app, u *User, w http.ResponseWriter, r *http.Request) err
return nil return nil
} }
func viewCollections(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func viewCollections(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
c, err := app.db.GetCollections(u) c, err := app.db.GetCollections(u)
if err != nil { if err != nil {
log.Error("unable to fetch collections: %v", err) log.Error("unable to fetch collections: %v", err)
@ -792,7 +792,7 @@ func viewCollections(app *app, u *User, w http.ResponseWriter, r *http.Request)
return nil return nil
} }
func viewEditCollection(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func viewEditCollection(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
c, err := app.db.GetCollection(vars["collection"]) c, err := app.db.GetCollection(vars["collection"])
if err != nil { if err != nil {
@ -815,7 +815,7 @@ func viewEditCollection(app *app, u *User, w http.ResponseWriter, r *http.Reques
return nil return nil
} }
func updateSettings(app *app, w http.ResponseWriter, r *http.Request) error { func updateSettings(app *App, w http.ResponseWriter, r *http.Request) error {
reqJSON := IsJSON(r.Header.Get("Content-Type")) reqJSON := IsJSON(r.Header.Get("Content-Type"))
var s userSettings var s userSettings
@ -904,7 +904,7 @@ func updateSettings(app *app, w http.ResponseWriter, r *http.Request) error {
return nil return nil
} }
func updatePassphrase(app *app, w http.ResponseWriter, r *http.Request) error { func updatePassphrase(app *App, w http.ResponseWriter, r *http.Request) error {
accessToken := r.Header.Get("Authorization") accessToken := r.Header.Get("Authorization")
if accessToken == "" { if accessToken == "" {
return ErrNoAccessToken return ErrNoAccessToken
@ -943,7 +943,7 @@ func updatePassphrase(app *app, w http.ResponseWriter, r *http.Request) error {
return impart.WriteSuccess(w, struct{}{}, http.StatusOK) return impart.WriteSuccess(w, struct{}{}, http.StatusOK)
} }
func viewStats(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func viewStats(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
var c *Collection var c *Collection
var err error var err error
vars := mux.Vars(r) vars := mux.Vars(r)
@ -994,7 +994,7 @@ func viewStats(app *app, u *User, w http.ResponseWriter, r *http.Request) error
return nil return nil
} }
func viewSettings(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func viewSettings(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
fullUser, err := app.db.GetUserByID(u.ID) fullUser, err := app.db.GetUserByID(u.ID)
if err != nil { if err != nil {
log.Error("Unable to get user for settings: %s", err) log.Error("Unable to get user for settings: %s", err)
@ -1025,7 +1025,7 @@ func viewSettings(app *app, u *User, w http.ResponseWriter, r *http.Request) err
return nil return nil
} }
func saveTempInfo(app *app, key, val string, r *http.Request, w http.ResponseWriter) error { func saveTempInfo(app *App, key, val string, r *http.Request, w http.ResponseWriter) error {
session, err := app.sessionStore.Get(r, "t") session, err := app.sessionStore.Get(r, "t")
if err != nil { if err != nil {
return ErrInternalCookieSession return ErrInternalCookieSession
@ -1039,7 +1039,7 @@ func saveTempInfo(app *app, key, val string, r *http.Request, w http.ResponseWri
return err return err
} }
func getTempInfo(app *app, key string, r *http.Request, w http.ResponseWriter) string { func getTempInfo(app *App, key string, r *http.Request, w http.ResponseWriter) string {
session, err := app.sessionStore.Get(r, "t") session, err := app.sessionStore.Get(r, "t")
if err != nil { if err != nil {
return "" return ""

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2019 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -62,7 +62,7 @@ func (ru *RemoteUser) AsPerson() *activitystreams.Person {
} }
} }
func handleFetchCollectionActivities(app *app, w http.ResponseWriter, r *http.Request) error { func handleFetchCollectionActivities(app *App, w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Server", serverSoftware) w.Header().Set("Server", serverSoftware)
vars := mux.Vars(r) vars := mux.Vars(r)
@ -86,7 +86,7 @@ func handleFetchCollectionActivities(app *app, w http.ResponseWriter, r *http.Re
return impart.RenderActivityJSON(w, p, http.StatusOK) return impart.RenderActivityJSON(w, p, http.StatusOK)
} }
func handleFetchCollectionOutbox(app *app, w http.ResponseWriter, r *http.Request) error { func handleFetchCollectionOutbox(app *App, w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Server", serverSoftware) w.Header().Set("Server", serverSoftware)
vars := mux.Vars(r) vars := mux.Vars(r)
@ -138,7 +138,7 @@ func handleFetchCollectionOutbox(app *app, w http.ResponseWriter, r *http.Reques
return impart.RenderActivityJSON(w, ocp, http.StatusOK) return impart.RenderActivityJSON(w, ocp, http.StatusOK)
} }
func handleFetchCollectionFollowers(app *app, w http.ResponseWriter, r *http.Request) error { func handleFetchCollectionFollowers(app *App, w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Server", serverSoftware) w.Header().Set("Server", serverSoftware)
vars := mux.Vars(r) vars := mux.Vars(r)
@ -183,7 +183,7 @@ func handleFetchCollectionFollowers(app *app, w http.ResponseWriter, r *http.Req
return impart.RenderActivityJSON(w, ocp, http.StatusOK) return impart.RenderActivityJSON(w, ocp, http.StatusOK)
} }
func handleFetchCollectionFollowing(app *app, w http.ResponseWriter, r *http.Request) error { func handleFetchCollectionFollowing(app *App, w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Server", serverSoftware) w.Header().Set("Server", serverSoftware)
vars := mux.Vars(r) vars := mux.Vars(r)
@ -218,7 +218,7 @@ func handleFetchCollectionFollowing(app *app, w http.ResponseWriter, r *http.Req
return impart.RenderActivityJSON(w, ocp, http.StatusOK) return impart.RenderActivityJSON(w, ocp, http.StatusOK)
} }
func handleFetchCollectionInbox(app *app, w http.ResponseWriter, r *http.Request) error { func handleFetchCollectionInbox(app *App, w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Server", serverSoftware) w.Header().Set("Server", serverSoftware)
vars := mux.Vars(r) vars := mux.Vars(r)
@ -531,7 +531,7 @@ func resolveIRI(url string) ([]byte, error) {
return body, nil return body, nil
} }
func deleteFederatedPost(app *app, p *PublicPost, collID int64) error { func deleteFederatedPost(app *App, p *PublicPost, collID int64) error {
if debugging { if debugging {
log.Info("Deleting federated post!") log.Info("Deleting federated post!")
} }
@ -569,7 +569,7 @@ func deleteFederatedPost(app *app, p *PublicPost, collID int64) error {
return nil return nil
} }
func federatePost(app *app, p *PublicPost, collID int64, isUpdate bool) error { func federatePost(app *App, p *PublicPost, collID int64, isUpdate bool) error {
if debugging { if debugging {
if isUpdate { if isUpdate {
log.Info("Federating updated post!") log.Info("Federating updated post!")
@ -619,7 +619,7 @@ func federatePost(app *app, p *PublicPost, collID int64, isUpdate bool) error {
return nil return nil
} }
func getRemoteUser(app *app, actorID string) (*RemoteUser, error) { func getRemoteUser(app *App, actorID string) (*RemoteUser, error) {
u := RemoteUser{ActorID: actorID} u := RemoteUser{ActorID: actorID}
err := app.db.QueryRow("SELECT id, inbox, shared_inbox FROM remoteusers WHERE actor_id = ?", actorID).Scan(&u.ID, &u.Inbox, &u.SharedInbox) err := app.db.QueryRow("SELECT id, inbox, shared_inbox FROM remoteusers WHERE actor_id = ?", actorID).Scan(&u.ID, &u.Inbox, &u.SharedInbox)
switch { switch {
@ -633,7 +633,7 @@ func getRemoteUser(app *app, actorID string) (*RemoteUser, error) {
return &u, nil return &u, nil
} }
func getActor(app *app, actorIRI string) (*activitystreams.Person, *RemoteUser, error) { func getActor(app *App, actorIRI string) (*activitystreams.Person, *RemoteUser, error) {
log.Info("Fetching actor %s locally", actorIRI) log.Info("Fetching actor %s locally", actorIRI)
actor := &activitystreams.Person{} actor := &activitystreams.Person{}
remoteUser, err := getRemoteUser(app, actorIRI) remoteUser, err := getRemoteUser(app, actorIRI)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2019 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -96,7 +96,7 @@ func (c instanceContent) UpdatedFriendly() string {
return c.Updated.Format("January 2, 2006, 3:04 PM") return c.Updated.Format("January 2, 2006, 3:04 PM")
} }
func handleViewAdminDash(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func handleViewAdminDash(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
updateAppStats() updateAppStats()
p := struct { p := struct {
*UserPage *UserPage
@ -117,7 +117,7 @@ func handleViewAdminDash(app *app, u *User, w http.ResponseWriter, r *http.Reque
return nil return nil
} }
func handleViewAdminUsers(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func handleViewAdminUsers(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
p := struct { p := struct {
*UserPage *UserPage
Config config.AppCfg Config config.AppCfg
@ -157,7 +157,7 @@ func handleViewAdminUsers(app *app, u *User, w http.ResponseWriter, r *http.Requ
return nil return nil
} }
func handleViewAdminUser(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func handleViewAdminUser(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
username := vars["username"] username := vars["username"]
if username == "" { if username == "" {
@ -229,7 +229,7 @@ func handleViewAdminUser(app *app, u *User, w http.ResponseWriter, r *http.Reque
return nil return nil
} }
func handleViewAdminPages(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func handleViewAdminPages(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
p := struct { p := struct {
*UserPage *UserPage
Config config.AppCfg Config config.AppCfg
@ -287,7 +287,7 @@ func handleViewAdminPages(app *app, u *User, w http.ResponseWriter, r *http.Requ
return nil return nil
} }
func handleViewAdminPage(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func handleViewAdminPage(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
slug := vars["slug"] slug := vars["slug"]
if slug == "" { if slug == "" {
@ -329,7 +329,7 @@ func handleViewAdminPage(app *app, u *User, w http.ResponseWriter, r *http.Reque
return nil return nil
} }
func handleAdminUpdateSite(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func handleAdminUpdateSite(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
id := vars["page"] id := vars["page"]
@ -347,7 +347,7 @@ func handleAdminUpdateSite(app *app, u *User, w http.ResponseWriter, r *http.Req
return impart.HTTPError{http.StatusFound, "/admin/page/" + id + m} return impart.HTTPError{http.StatusFound, "/admin/page/" + id + m}
} }
func handleAdminUpdateConfig(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func handleAdminUpdateConfig(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
app.cfg.App.SiteName = r.FormValue("site_name") app.cfg.App.SiteName = r.FormValue("site_name")
app.cfg.App.SiteDesc = r.FormValue("site_desc") app.cfg.App.SiteDesc = r.FormValue("site_desc")
app.cfg.App.OpenRegistration = r.FormValue("open_registration") == "on" app.cfg.App.OpenRegistration = r.FormValue("open_registration") == "on"
@ -418,7 +418,7 @@ func updateAppStats() {
sysStatus.NumGC = m.NumGC sysStatus.NumGC = m.NumGC
} }
func adminResetPassword(app *app, u *User, newPass string) error { func adminResetPassword(app *App, u *User, newPass string) error {
hashedPass, err := auth.HashPass([]byte(newPass)) hashedPass, err := auth.HashPass([]byte(newPass))
if err != nil { if err != nil {
return impart.HTTPError{http.StatusInternalServerError, fmt.Sprintf("Could not create password hash: %v", err)} return impart.HTTPError{http.StatusInternalServerError, fmt.Sprintf("Could not create password hash: %v", err)}

39
app.go
View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2019 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -62,7 +62,8 @@ var (
isSingleUser bool isSingleUser bool
) )
type app struct { // App holds data and configuration for an individual WriteFreely instance.
type App struct {
router *mux.Router router *mux.Router
db *datastore db *datastore
cfg *config.Config cfg *config.Config
@ -76,7 +77,7 @@ type app struct {
// handleViewHome shows page at root path. Will be the Pad if logged in and the // handleViewHome shows page at root path. Will be the Pad if logged in and the
// catch-all landing page otherwise. // catch-all landing page otherwise.
func handleViewHome(app *app, w http.ResponseWriter, r *http.Request) error { func handleViewHome(app *App, w http.ResponseWriter, r *http.Request) error {
if app.cfg.App.SingleUser { if app.cfg.App.SingleUser {
// Render blog index // Render blog index
return handleViewCollection(app, w, r) return handleViewCollection(app, w, r)
@ -111,7 +112,7 @@ func handleViewHome(app *app, w http.ResponseWriter, r *http.Request) error {
return renderPage(w, "landing.tmpl", p) return renderPage(w, "landing.tmpl", p)
} }
func handleTemplatedPage(app *app, w http.ResponseWriter, r *http.Request, t *template.Template) error { func handleTemplatedPage(app *App, w http.ResponseWriter, r *http.Request, t *template.Template) error {
p := struct { p := struct {
page.StaticPage page.StaticPage
ContentTitle string ContentTitle string
@ -157,7 +158,7 @@ func handleTemplatedPage(app *app, w http.ResponseWriter, r *http.Request, t *te
return nil return nil
} }
func pageForReq(app *app, r *http.Request) page.StaticPage { func pageForReq(app *App, r *http.Request) page.StaticPage {
p := page.StaticPage{ p := page.StaticPage{
AppCfg: app.cfg.App, AppCfg: app.cfg.App,
Path: r.URL.Path, Path: r.URL.Path,
@ -189,7 +190,7 @@ func pageForReq(app *app, r *http.Request) page.StaticPage {
var shttp = http.NewServeMux() var shttp = http.NewServeMux()
var fileRegex = regexp.MustCompile("/([^/]*\\.[^/]*)$") var fileRegex = regexp.MustCompile("/([^/]*\\.[^/]*)$")
func Serve(app *app, debug bool) { func Serve(app *App, debug bool) {
debugging = debug debugging = debug
log.Info("Initializing...") log.Info("Initializing...")
@ -317,14 +318,14 @@ func OutputVersion() {
} }
// NewApp creates a new app instance. // NewApp creates a new app instance.
func NewApp(cfgFile string) *app { func NewApp(cfgFile string) *App {
return &app{ return &App{
cfgFile: cfgFile, cfgFile: cfgFile,
} }
} }
// CreateConfig creates a default configuration and saves it to the app's cfgFile. // CreateConfig creates a default configuration and saves it to the app's cfgFile.
func CreateConfig(app *app) error { func CreateConfig(app *App) error {
log.Info("Creating configuration...") log.Info("Creating configuration...")
c := config.New() c := config.New()
log.Info("Saving configuration %s...", app.cfgFile) log.Info("Saving configuration %s...", app.cfgFile)
@ -336,7 +337,7 @@ func CreateConfig(app *app) error {
} }
// DoConfig runs the interactive configuration process. // DoConfig runs the interactive configuration process.
func DoConfig(app *app) { func DoConfig(app *App) {
d, err := config.Configure(app.cfgFile) d, err := config.Configure(app.cfgFile)
if err != nil { if err != nil {
log.Error("Unable to configure: %v", err) log.Error("Unable to configure: %v", err)
@ -374,7 +375,7 @@ func DoConfig(app *app) {
} }
// GenerateKeys creates app encryption keys and saves them into the configured KeysParentDir. // GenerateKeys creates app encryption keys and saves them into the configured KeysParentDir.
func GenerateKeys(app *app) error { func GenerateKeys(app *App) error {
// Read keys path from config // Read keys path from config
loadConfig(app) loadConfig(app)
@ -407,7 +408,7 @@ func GenerateKeys(app *app) error {
} }
// CreateSchema creates all database tables needed for the application. // CreateSchema creates all database tables needed for the application.
func CreateSchema(app *app) error { func CreateSchema(app *App) error {
loadConfig(app) loadConfig(app)
connectToDatabase(app) connectToDatabase(app)
defer shutdown(app) defer shutdown(app)
@ -419,7 +420,7 @@ func CreateSchema(app *app) error {
} }
// Migrate runs all necessary database migrations. // Migrate runs all necessary database migrations.
func Migrate(app *app) error { func Migrate(app *App) error {
loadConfig(app) loadConfig(app)
connectToDatabase(app) connectToDatabase(app)
defer shutdown(app) defer shutdown(app)
@ -432,7 +433,7 @@ func Migrate(app *app) error {
} }
// ResetPassword runs the interactive password reset process. // ResetPassword runs the interactive password reset process.
func ResetPassword(app *app, username string) error { func ResetPassword(app *App, username string) error {
// Connect to the database // Connect to the database
loadConfig(app) loadConfig(app)
connectToDatabase(app) connectToDatabase(app)
@ -470,7 +471,7 @@ func ResetPassword(app *app, username string) error {
return nil return nil
} }
func loadConfig(app *app) { func loadConfig(app *App) {
log.Info("Loading %s configuration...", app.cfgFile) log.Info("Loading %s configuration...", app.cfgFile)
cfg, err := config.Load(app.cfgFile) cfg, err := config.Load(app.cfgFile)
if err != nil { if err != nil {
@ -480,7 +481,7 @@ func loadConfig(app *app) {
app.cfg = cfg app.cfg = cfg
} }
func connectToDatabase(app *app) { func connectToDatabase(app *App) {
log.Info("Connecting to %s database...", app.cfg.Database.Type) log.Info("Connecting to %s database...", app.cfg.Database.Type)
var db *sql.DB var db *sql.DB
@ -510,13 +511,13 @@ func connectToDatabase(app *app) {
app.db = &datastore{db, app.cfg.Database.Type} app.db = &datastore{db, app.cfg.Database.Type}
} }
func shutdown(app *app) { func shutdown(app *App) {
log.Info("Closing database connection...") log.Info("Closing database connection...")
app.db.Close() app.db.Close()
} }
// CreateUser creates a new admin or normal user from the given username:password string. // CreateUser creates a new admin or normal user from the given username:password string.
func CreateUser(app *app, credStr string, isAdmin bool) error { func CreateUser(app *App, credStr string, isAdmin bool) error {
// Create an admin user with --create-admin // Create an admin user with --create-admin
creds := strings.Split(credStr, ":") creds := strings.Split(credStr, ":")
if len(creds) != 2 { if len(creds) != 2 {
@ -587,7 +588,7 @@ func CreateUser(app *app, credStr string, isAdmin bool) error {
return nil return nil
} }
func adminInitDatabase(app *app) error { func adminInitDatabase(app *App) error {
schemaFileName := "schema.sql" schemaFileName := "schema.sql"
if app.cfg.Database.Type == driverSQLite { if app.cfg.Database.Type == driverSQLite {
schemaFileName = "sqlite.sql" schemaFileName = "sqlite.sql"

View File

@ -316,7 +316,7 @@ func (c *Collection) RenderMathJax() bool {
return c.db.CollectionHasAttribute(c.ID, "render_mathjax") return c.db.CollectionHasAttribute(c.ID, "render_mathjax")
} }
func newCollection(app *app, w http.ResponseWriter, r *http.Request) error { func newCollection(app *App, w http.ResponseWriter, r *http.Request) error {
reqJSON := IsJSON(r.Header.Get("Content-Type")) reqJSON := IsJSON(r.Header.Get("Content-Type"))
alias := r.FormValue("alias") alias := r.FormValue("alias")
title := r.FormValue("title") title := r.FormValue("title")
@ -399,7 +399,7 @@ func newCollection(app *app, w http.ResponseWriter, r *http.Request) error {
return impart.HTTPError{http.StatusFound, redirectTo} return impart.HTTPError{http.StatusFound, redirectTo}
} }
func apiCheckCollectionPermissions(app *app, r *http.Request, c *Collection) (int64, error) { func apiCheckCollectionPermissions(app *App, r *http.Request, c *Collection) (int64, error) {
accessToken := r.Header.Get("Authorization") accessToken := r.Header.Get("Authorization")
var userID int64 = -1 var userID int64 = -1
if accessToken != "" { if accessToken != "" {
@ -419,7 +419,7 @@ func apiCheckCollectionPermissions(app *app, r *http.Request, c *Collection) (in
} }
// fetchCollection handles the API endpoint for retrieving collection data. // fetchCollection handles the API endpoint for retrieving collection data.
func fetchCollection(app *app, w http.ResponseWriter, r *http.Request) error { func fetchCollection(app *App, w http.ResponseWriter, r *http.Request) error {
accept := r.Header.Get("Accept") accept := r.Header.Get("Accept")
if strings.Contains(accept, "application/activity+json") { if strings.Contains(accept, "application/activity+json") {
return handleFetchCollectionActivities(app, w, r) return handleFetchCollectionActivities(app, w, r)
@ -467,7 +467,7 @@ func fetchCollection(app *app, w http.ResponseWriter, r *http.Request) error {
// fetchCollectionPosts handles an API endpoint for retrieving a collection's // fetchCollectionPosts handles an API endpoint for retrieving a collection's
// posts. // posts.
func fetchCollectionPosts(app *app, w http.ResponseWriter, r *http.Request) error { func fetchCollectionPosts(app *App, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
alias := vars["alias"] alias := vars["alias"]
@ -563,7 +563,7 @@ func processCollectionRequest(cr *collectionReq, vars map[string]string, w http.
// domain that doesn't yet have a collection associated, or if a collection // domain that doesn't yet have a collection associated, or if a collection
// requires a password. In either case, this will return nil, nil -- thus both // requires a password. In either case, this will return nil, nil -- thus both
// values should ALWAYS be checked to determine whether or not to continue. // values should ALWAYS be checked to determine whether or not to continue.
func processCollectionPermissions(app *app, cr *collectionReq, u *User, w http.ResponseWriter, r *http.Request) (*Collection, error) { func processCollectionPermissions(app *App, cr *collectionReq, u *User, w http.ResponseWriter, r *http.Request) (*Collection, error) {
// Display collection if this is a collection // Display collection if this is a collection
var c *Collection var c *Collection
var err error var err error
@ -654,7 +654,7 @@ func processCollectionPermissions(app *app, cr *collectionReq, u *User, w http.R
return c, nil return c, nil
} }
func checkUserForCollection(app *app, cr *collectionReq, r *http.Request, isPostReq bool) (*User, error) { func checkUserForCollection(app *App, cr *collectionReq, r *http.Request, isPostReq bool) (*User, error) {
u := getUserSession(app, r) u := getUserSession(app, r)
return u, nil return u, nil
} }
@ -682,7 +682,7 @@ func getCollectionPage(vars map[string]string) int {
} }
// handleViewCollection displays the requested Collection // handleViewCollection displays the requested Collection
func handleViewCollection(app *app, w http.ResponseWriter, r *http.Request) error { func handleViewCollection(app *App, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
cr := &collectionReq{} cr := &collectionReq{}
@ -788,7 +788,7 @@ func handleViewCollection(app *app, w http.ResponseWriter, r *http.Request) erro
return err return err
} }
func handleViewCollectionTag(app *app, w http.ResponseWriter, r *http.Request) error { func handleViewCollectionTag(app *App, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
tag := vars["tag"] tag := vars["tag"]
@ -867,7 +867,7 @@ func handleViewCollectionTag(app *app, w http.ResponseWriter, r *http.Request) e
return nil return nil
} }
func handleCollectionPostRedirect(app *app, w http.ResponseWriter, r *http.Request) error { func handleCollectionPostRedirect(app *App, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
slug := vars["slug"] slug := vars["slug"]
@ -885,7 +885,7 @@ func handleCollectionPostRedirect(app *app, w http.ResponseWriter, r *http.Reque
return impart.HTTPError{http.StatusFound, loc} return impart.HTTPError{http.StatusFound, loc}
} }
func existingCollection(app *app, w http.ResponseWriter, r *http.Request) error { func existingCollection(app *App, w http.ResponseWriter, r *http.Request) error {
reqJSON := IsJSON(r.Header.Get("Content-Type")) reqJSON := IsJSON(r.Header.Get("Content-Type"))
vars := mux.Vars(r) vars := mux.Vars(r)
collAlias := vars["alias"] collAlias := vars["alias"]
@ -980,7 +980,7 @@ func collectionAliasFromReq(r *http.Request) string {
return alias return alias
} }
func handleWebCollectionUnlock(app *app, w http.ResponseWriter, r *http.Request) error { func handleWebCollectionUnlock(app *App, w http.ResponseWriter, r *http.Request) error {
var readReq struct { var readReq struct {
Alias string `schema:"alias" json:"alias"` Alias string `schema:"alias" json:"alias"`
Pass string `schema:"password" json:"password"` Pass string `schema:"password" json:"password"`
@ -1047,7 +1047,7 @@ func handleWebCollectionUnlock(app *app, w http.ResponseWriter, r *http.Request)
return impart.HTTPError{http.StatusFound, next} return impart.HTTPError{http.StatusFound, next}
} }
func isAuthorizedForCollection(app *app, alias string, r *http.Request) bool { func isAuthorizedForCollection(app *App, alias string, r *http.Request) bool {
authd := false authd := false
session, err := app.sessionStore.Get(r, blogPassCookieName) session, err := app.sessionStore.Get(r, blogPassCookieName)
if err == nil { if err == nil {

View File

@ -60,7 +60,7 @@ type writestore interface {
GetTemporaryAccessToken(userID int64, validSecs int) (string, error) GetTemporaryAccessToken(userID int64, validSecs int) (string, error)
GetTemporaryOneTimeAccessToken(userID int64, validSecs int, oneTime bool) (string, error) GetTemporaryOneTimeAccessToken(userID int64, validSecs int, oneTime bool) (string, error)
DeleteAccount(userID int64) (l *string, err error) DeleteAccount(userID int64) (l *string, err error)
ChangeSettings(app *app, u *User, s *userSettings) error ChangeSettings(app *App, u *User, s *userSettings) error
ChangePassphrase(userID int64, sudo bool, curPass string, hashedPass []byte) error ChangePassphrase(userID int64, sudo bool, curPass string, hashedPass []byte) error
GetCollections(u *User) (*[]Collection, error) GetCollections(u *User) (*[]Collection, error)
@ -1774,7 +1774,7 @@ func (db *datastore) GetUserPostsCount(userID int64) int64 {
// ChangeSettings takes a User and applies the changes in the given // ChangeSettings takes a User and applies the changes in the given
// userSettings, MODIFYING THE USER with successful changes. // userSettings, MODIFYING THE USER with successful changes.
func (db *datastore) ChangeSettings(app *app, u *User, s *userSettings) error { func (db *datastore) ChangeSettings(app *App, u *User, s *userSettings) error {
var errPass error var errPass error
q := query.NewUpdate() q := query.NewUpdate()

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2019 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -92,7 +92,7 @@ func exportPostsZip(u *User, posts *[]PublicPost) []byte {
return b.Bytes() return b.Bytes()
} }
func compileFullExport(app *app, u *User) *ExportUser { func compileFullExport(app *App, u *User) *ExportUser {
exportUser := &ExportUser{ exportUser := &ExportUser{
User: u, User: u,
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2019 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -20,7 +20,7 @@ import (
"time" "time"
) )
func ViewFeed(app *app, w http.ResponseWriter, req *http.Request) error { func ViewFeed(app *App, w http.ResponseWriter, req *http.Request) error {
alias := collectionAliasFromReq(req) alias := collectionAliasFromReq(req)
// Display collection if this is a collection // Display collection if this is a collection

View File

@ -36,16 +36,16 @@ const (
) )
type ( type (
handlerFunc func(app *app, w http.ResponseWriter, r *http.Request) error handlerFunc func(app *App, w http.ResponseWriter, r *http.Request) error
userHandlerFunc func(app *app, u *User, w http.ResponseWriter, r *http.Request) error userHandlerFunc func(app *App, u *User, w http.ResponseWriter, r *http.Request) error
dataHandlerFunc func(app *app, w http.ResponseWriter, r *http.Request) ([]byte, string, error) dataHandlerFunc func(app *App, w http.ResponseWriter, r *http.Request) ([]byte, string, error)
authFunc func(app *app, r *http.Request) (*User, error) authFunc func(app *App, r *http.Request) (*User, error)
) )
type Handler struct { type Handler struct {
errors *ErrorPages errors *ErrorPages
sessionStore *sessions.CookieStore sessionStore *sessions.CookieStore
app *app app *App
} }
// ErrorPages hold template HTML error pages for displaying errors to the user. // ErrorPages hold template HTML error pages for displaying errors to the user.
@ -59,7 +59,7 @@ type ErrorPages struct {
// NewHandler returns a new Handler instance, using the given StaticPage data, // NewHandler returns a new Handler instance, using the given StaticPage data,
// and saving alias to the application's CookieStore. // and saving alias to the application's CookieStore.
func NewHandler(app *app) *Handler { func NewHandler(app *App) *Handler {
h := &Handler{ h := &Handler{
errors: &ErrorPages{ errors: &ErrorPages{
NotFound: template.Must(template.New("").Parse("{{define \"base\"}}<html><head><title>404</title></head><body><p>Not found.</p></body></html>{{end}}")), NotFound: template.Must(template.New("").Parse("{{define \"base\"}}<html><head><title>404</title></head><body><p>Not found.</p></body></html>{{end}}")),
@ -160,7 +160,7 @@ func (h *Handler) Admin(f userHandlerFunc) http.HandlerFunc {
// UserAPI handles requests made in the API by the authenticated user. // UserAPI handles requests made in the API by the authenticated user.
// This provides user-friendly HTML pages and actions that work in the browser. // This provides user-friendly HTML pages and actions that work in the browser.
func (h *Handler) UserAPI(f userHandlerFunc) http.HandlerFunc { func (h *Handler) UserAPI(f userHandlerFunc) http.HandlerFunc {
return h.UserAll(false, f, func(app *app, r *http.Request) (*User, error) { return h.UserAll(false, f, func(app *App, r *http.Request) (*User, error) {
// Authorize user from Authorization header // Authorize user from Authorization header
t := r.Header.Get("Authorization") t := r.Header.Get("Authorization")
if t == "" { if t == "" {
@ -222,7 +222,7 @@ func (h *Handler) UserAll(web bool, f userHandlerFunc, a authFunc) http.HandlerF
} }
func (h *Handler) RedirectOnErr(f handlerFunc, loc string) handlerFunc { func (h *Handler) RedirectOnErr(f handlerFunc, loc string) handlerFunc {
return func(app *app, w http.ResponseWriter, r *http.Request) error { return func(app *App, w http.ResponseWriter, r *http.Request) error {
err := f(app, w, r) err := f(app, w, r)
if err != nil { if err != nil {
if ie, ok := err.(impart.HTTPError); ok { if ie, ok := err.(impart.HTTPError); ok {
@ -239,7 +239,7 @@ func (h *Handler) RedirectOnErr(f handlerFunc, loc string) handlerFunc {
} }
func (h *Handler) Page(n string) http.HandlerFunc { func (h *Handler) Page(n string) http.HandlerFunc {
return h.Web(func(app *app, w http.ResponseWriter, r *http.Request) error { return h.Web(func(app *App, w http.ResponseWriter, r *http.Request) error {
t, ok := pages[n] t, ok := pages[n]
if !ok { if !ok {
return impart.HTTPError{http.StatusNotFound, "Page not found."} return impart.HTTPError{http.StatusNotFound, "Page not found."}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2019 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -15,7 +15,7 @@ import (
"net/http" "net/http"
) )
func handleViewHostMeta(app *app, w http.ResponseWriter, r *http.Request) error { func handleViewHostMeta(app *App, w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Server", serverSoftware) w.Header().Set("Server", serverSoftware)
w.Header().Set("Content-Type", "application/xrd+xml; charset=utf-8") w.Header().Set("Content-Type", "application/xrd+xml; charset=utf-8")

View File

@ -45,7 +45,7 @@ func (i Invite) ExpiresFriendly() string {
return i.Expires.Format("January 2, 2006, 3:04 PM") return i.Expires.Format("January 2, 2006, 3:04 PM")
} }
func handleViewUserInvites(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func handleViewUserInvites(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
// Don't show page if instance doesn't allow it // Don't show page if instance doesn't allow it
if !(app.cfg.App.UserInvites != "" && (u.IsAdmin() || app.cfg.App.UserInvites != "admin")) { if !(app.cfg.App.UserInvites != "" && (u.IsAdmin() || app.cfg.App.UserInvites != "admin")) {
return impart.HTTPError{http.StatusNotFound, ""} return impart.HTTPError{http.StatusNotFound, ""}
@ -73,7 +73,7 @@ func handleViewUserInvites(app *app, u *User, w http.ResponseWriter, r *http.Req
return nil return nil
} }
func handleCreateUserInvite(app *app, u *User, w http.ResponseWriter, r *http.Request) error { func handleCreateUserInvite(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
muVal := r.FormValue("uses") muVal := r.FormValue("uses")
expVal := r.FormValue("expires") expVal := r.FormValue("expires")
@ -106,7 +106,7 @@ func handleCreateUserInvite(app *app, u *User, w http.ResponseWriter, r *http.Re
return impart.HTTPError{http.StatusFound, "/me/invites"} return impart.HTTPError{http.StatusFound, "/me/invites"}
} }
func handleViewInvite(app *app, w http.ResponseWriter, r *http.Request) error { func handleViewInvite(app *App, w http.ResponseWriter, r *http.Request) error {
inviteCode := mux.Vars(r)["code"] inviteCode := mux.Vars(r)["code"]
i, err := app.db.GetUserInvite(inviteCode) i, err := app.db.GetUserInvite(inviteCode)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2019 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -34,13 +34,13 @@ type keychain struct {
emailKey, cookieAuthKey, cookieKey []byte emailKey, cookieAuthKey, cookieKey []byte
} }
func initKeyPaths(app *app) { func initKeyPaths(app *App) {
emailKeyPath = filepath.Join(app.cfg.Server.KeysParentDir, emailKeyPath) emailKeyPath = filepath.Join(app.cfg.Server.KeysParentDir, emailKeyPath)
cookieAuthKeyPath = filepath.Join(app.cfg.Server.KeysParentDir, cookieAuthKeyPath) cookieAuthKeyPath = filepath.Join(app.cfg.Server.KeysParentDir, cookieAuthKeyPath)
cookieKeyPath = filepath.Join(app.cfg.Server.KeysParentDir, cookieKeyPath) cookieKeyPath = filepath.Join(app.cfg.Server.KeysParentDir, cookieKeyPath)
} }
func initKeys(app *app) error { func initKeys(app *App) error {
var err error var err error
app.keys = &keychain{} app.keys = &keychain{}

6
pad.go
View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2019 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -19,7 +19,7 @@ import (
"strings" "strings"
) )
func handleViewPad(app *app, w http.ResponseWriter, r *http.Request) error { func handleViewPad(app *App, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
action := vars["action"] action := vars["action"]
slug := vars["slug"] slug := vars["slug"]
@ -102,7 +102,7 @@ func handleViewPad(app *app, w http.ResponseWriter, r *http.Request) error {
return nil return nil
} }
func handleViewMeta(app *app, w http.ResponseWriter, r *http.Request) error { func handleViewMeta(app *App, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
action := vars["action"] action := vars["action"]
slug := vars["slug"] slug := vars["slug"]

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2019 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -18,7 +18,7 @@ import (
var defaultPageUpdatedTime = time.Date(2018, 11, 8, 12, 0, 0, 0, time.Local) var defaultPageUpdatedTime = time.Date(2018, 11, 8, 12, 0, 0, 0, time.Local)
func getAboutPage(app *app) (*instanceContent, error) { func getAboutPage(app *App) (*instanceContent, error) {
c, err := app.db.GetDynamicContent("about") c, err := app.db.GetDynamicContent("about")
if err != nil { if err != nil {
return nil, err return nil, err
@ -40,7 +40,7 @@ func defaultAboutTitle(cfg *config.Config) sql.NullString {
return sql.NullString{String: "About " + cfg.App.SiteName, Valid: true} return sql.NullString{String: "About " + cfg.App.SiteName, Valid: true}
} }
func getPrivacyPage(app *app) (*instanceContent, error) { func getPrivacyPage(app *App) (*instanceContent, error) {
c, err := app.db.GetDynamicContent("privacy") c, err := app.db.GetDynamicContent("privacy")
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2019 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -260,7 +260,7 @@ func (p *Post) HasTitleLink() bool {
return hasLink return hasLink
} }
func handleViewPost(app *app, w http.ResponseWriter, r *http.Request) error { func handleViewPost(app *App, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
friendlyID := vars["post"] friendlyID := vars["post"]
@ -466,7 +466,7 @@ func handleViewPost(app *app, w http.ResponseWriter, r *http.Request) error {
// /posts // /posts
// /posts?collection={alias} // /posts?collection={alias}
// ? /collections/{alias}/posts // ? /collections/{alias}/posts
func newPost(app *app, w http.ResponseWriter, r *http.Request) error { func newPost(app *App, w http.ResponseWriter, r *http.Request) error {
reqJSON := IsJSON(r.Header.Get("Content-Type")) reqJSON := IsJSON(r.Header.Get("Content-Type"))
vars := mux.Vars(r) vars := mux.Vars(r)
collAlias := vars["alias"] collAlias := vars["alias"]
@ -591,7 +591,7 @@ func newPost(app *app, w http.ResponseWriter, r *http.Request) error {
return response return response
} }
func existingPost(app *app, w http.ResponseWriter, r *http.Request) error { func existingPost(app *App, w http.ResponseWriter, r *http.Request) error {
reqJSON := IsJSON(r.Header.Get("Content-Type")) reqJSON := IsJSON(r.Header.Get("Content-Type"))
vars := mux.Vars(r) vars := mux.Vars(r)
postID := vars["post"] postID := vars["post"]
@ -711,7 +711,7 @@ func existingPost(app *app, w http.ResponseWriter, r *http.Request) error {
return nil return nil
} }
func deletePost(app *app, w http.ResponseWriter, r *http.Request) error { func deletePost(app *App, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
friendlyID := vars["post"] friendlyID := vars["post"]
editToken := r.FormValue("token") editToken := r.FormValue("token")
@ -830,7 +830,7 @@ func deletePost(app *app, w http.ResponseWriter, r *http.Request) error {
} }
// addPost associates a post with the authenticated user. // addPost associates a post with the authenticated user.
func addPost(app *app, w http.ResponseWriter, r *http.Request) error { func addPost(app *App, w http.ResponseWriter, r *http.Request) error {
var ownerID int64 var ownerID int64
// Authenticate user // Authenticate user
@ -879,7 +879,7 @@ func addPost(app *app, w http.ResponseWriter, r *http.Request) error {
return impart.WriteSuccess(w, res, http.StatusOK) return impart.WriteSuccess(w, res, http.StatusOK)
} }
func dispersePost(app *app, w http.ResponseWriter, r *http.Request) error { func dispersePost(app *App, w http.ResponseWriter, r *http.Request) error {
var ownerID int64 var ownerID int64
// Authenticate user // Authenticate user
@ -923,7 +923,7 @@ type (
) )
// pinPost pins a post to a blog // pinPost pins a post to a blog
func pinPost(app *app, w http.ResponseWriter, r *http.Request) error { func pinPost(app *App, w http.ResponseWriter, r *http.Request) error {
var userID int64 var userID int64
// Authenticate user // Authenticate user
@ -981,7 +981,7 @@ func pinPost(app *app, w http.ResponseWriter, r *http.Request) error {
return impart.WriteSuccess(w, res, http.StatusOK) return impart.WriteSuccess(w, res, http.StatusOK)
} }
func fetchPost(app *app, w http.ResponseWriter, r *http.Request) error { func fetchPost(app *App, w http.ResponseWriter, r *http.Request) error {
var collID int64 var collID int64
var coll *Collection var coll *Collection
var err error var err error
@ -1030,7 +1030,7 @@ func fetchPost(app *app, w http.ResponseWriter, r *http.Request) error {
return impart.WriteSuccess(w, p, http.StatusOK) return impart.WriteSuccess(w, p, http.StatusOK)
} }
func fetchPostProperty(app *app, w http.ResponseWriter, r *http.Request) error { func fetchPostProperty(app *App, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
p, err := app.db.GetPostProperty(vars["post"], 0, vars["property"]) p, err := app.db.GetPostProperty(vars["post"], 0, vars["property"])
if err != nil { if err != nil {
@ -1128,7 +1128,7 @@ func (p *SubmittedPost) isFontValid() bool {
return valid return valid
} }
func getRawPost(app *app, friendlyID string) *RawPost { func getRawPost(app *App, friendlyID string) *RawPost {
var content, font, title string var content, font, title string
var isRTL sql.NullBool var isRTL sql.NullBool
var lang sql.NullString var lang sql.NullString
@ -1148,7 +1148,7 @@ func getRawPost(app *app, friendlyID string) *RawPost {
} }
// TODO; return a Post! // TODO; return a Post!
func getRawCollectionPost(app *app, slug, collAlias string) *RawPost { func getRawCollectionPost(app *App, slug, collAlias string) *RawPost {
var id, title, content, font string var id, title, content, font string
var isRTL sql.NullBool var isRTL sql.NullBool
var lang sql.NullString var lang sql.NullString
@ -1185,7 +1185,7 @@ func getRawCollectionPost(app *app, slug, collAlias string) *RawPost {
} }
} }
func viewCollectionPost(app *app, w http.ResponseWriter, r *http.Request) error { func viewCollectionPost(app *App, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
slug := vars["slug"] slug := vars["slug"]

14
read.go
View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2019 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -49,7 +49,7 @@ type readPublication struct {
TotalPages int TotalPages int
} }
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.db.FetchPublicPosts, 10*time.Minute),
@ -108,7 +108,7 @@ func (db *datastore) FetchPublicPosts() (interface{}, error) {
return posts, nil return posts, nil
} }
func viewLocalTimelineAPI(app *app, w http.ResponseWriter, r *http.Request) error { func viewLocalTimelineAPI(app *App, w http.ResponseWriter, r *http.Request) error {
updateTimelineCache(app.timeline) updateTimelineCache(app.timeline)
skip, _ := strconv.Atoi(r.FormValue("skip")) skip, _ := strconv.Atoi(r.FormValue("skip"))
@ -121,7 +121,7 @@ func viewLocalTimelineAPI(app *app, w http.ResponseWriter, r *http.Request) erro
return impart.WriteSuccess(w, posts, http.StatusOK) return impart.WriteSuccess(w, posts, http.StatusOK)
} }
func viewLocalTimeline(app *app, w http.ResponseWriter, r *http.Request) error { func viewLocalTimeline(app *App, w http.ResponseWriter, r *http.Request) error {
if !app.cfg.App.LocalTimeline { if !app.cfg.App.LocalTimeline {
return impart.HTTPError{http.StatusNotFound, "Page doesn't exist."} return impart.HTTPError{http.StatusNotFound, "Page doesn't exist."}
} }
@ -153,7 +153,7 @@ func updateTimelineCache(tl *localTimeline) {
} }
} }
func showLocalTimeline(app *app, w http.ResponseWriter, r *http.Request, page int, author, tag string) error { func showLocalTimeline(app *App, w http.ResponseWriter, r *http.Request, page int, author, tag string) error {
updateTimelineCache(app.timeline) updateTimelineCache(app.timeline)
pl := len(*(app.timeline.posts)) pl := len(*(app.timeline.posts))
@ -226,7 +226,7 @@ func (c *readPublication) PrevPageURL(n int) string {
// handlePostIDRedirect handles a route where a post ID is given and redirects // handlePostIDRedirect handles a route where a post ID is given and redirects
// the user to the canonical post URL. // the user to the canonical post URL.
func handlePostIDRedirect(app *app, w http.ResponseWriter, r *http.Request) error { func handlePostIDRedirect(app *App, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
postID := vars["post"] postID := vars["post"]
p, err := app.db.GetPost(postID, 0) p, err := app.db.GetPost(postID, 0)
@ -249,7 +249,7 @@ func handlePostIDRedirect(app *app, w http.ResponseWriter, r *http.Request) erro
return impart.HTTPError{http.StatusFound, c.CanonicalURL() + p.Slug.String} return impart.HTTPError{http.StatusFound, c.CanonicalURL() + p.Slug.String}
} }
func viewLocalTimelineFeed(app *app, w http.ResponseWriter, req *http.Request) error { func viewLocalTimelineFeed(app *App, w http.ResponseWriter, req *http.Request) error {
if !app.cfg.App.LocalTimeline { if !app.cfg.App.LocalTimeline {
return impart.HTTPError{http.StatusNotFound, "Page doesn't exist."} return impart.HTTPError{http.StatusNotFound, "Page doesn't exist."}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2019 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -29,7 +29,7 @@ const (
// initSession creates the cookie store. It depends on the keychain already // initSession creates the cookie store. It depends on the keychain already
// being loaded. // being loaded.
func initSession(app *app) *sessions.CookieStore { func initSession(app *App) *sessions.CookieStore {
// Register complex data types we'll be storing in cookies // Register complex data types we'll be storing in cookies
gob.Register(&User{}) gob.Register(&User{})
@ -44,7 +44,7 @@ func initSession(app *app) *sessions.CookieStore {
return store return store
} }
func getSessionFlashes(app *app, w http.ResponseWriter, r *http.Request, session *sessions.Session) ([]string, error) { func getSessionFlashes(app *App, w http.ResponseWriter, r *http.Request, session *sessions.Session) ([]string, error) {
var err error var err error
if session == nil { if session == nil {
session, err = app.sessionStore.Get(r, cookieName) session, err = app.sessionStore.Get(r, cookieName)
@ -66,7 +66,7 @@ func getSessionFlashes(app *app, w http.ResponseWriter, r *http.Request, session
return f, nil return f, nil
} }
func addSessionFlash(app *app, w http.ResponseWriter, r *http.Request, m string, session *sessions.Session) error { func addSessionFlash(app *App, w http.ResponseWriter, r *http.Request, m string, session *sessions.Session) error {
var err error var err error
if session == nil { if session == nil {
session, err = app.sessionStore.Get(r, cookieName) session, err = app.sessionStore.Get(r, cookieName)
@ -82,7 +82,7 @@ func addSessionFlash(app *app, w http.ResponseWriter, r *http.Request, m string,
return nil return nil
} }
func getUserAndSession(app *app, r *http.Request) (*User, *sessions.Session) { func getUserAndSession(app *App, r *http.Request) (*User, *sessions.Session) {
session, err := app.sessionStore.Get(r, cookieName) session, err := app.sessionStore.Get(r, cookieName)
if err == nil { if err == nil {
// Got the currently logged-in user // Got the currently logged-in user
@ -97,12 +97,12 @@ func getUserAndSession(app *app, r *http.Request) (*User, *sessions.Session) {
return nil, nil return nil, nil
} }
func getUserSession(app *app, r *http.Request) *User { func getUserSession(app *App, r *http.Request) *User {
u, _ := getUserAndSession(app, r) u, _ := getUserAndSession(app, r)
return u return u
} }
func saveUserSession(app *app, r *http.Request, w http.ResponseWriter) error { func saveUserSession(app *App, r *http.Request, w http.ResponseWriter) error {
session, err := app.sessionStore.Get(r, cookieName) session, err := app.sessionStore.Get(r, cookieName)
if err != nil { if err != nil {
return ErrInternalCookieSession return ErrInternalCookieSession
@ -127,7 +127,7 @@ func saveUserSession(app *app, r *http.Request, w http.ResponseWriter) error {
return err return err
} }
func getFullUserSession(app *app, r *http.Request) *User { func getFullUserSession(app *App, r *http.Request) *User {
u := getUserSession(app, r) u := getUserSession(app, r)
if u == nil { if u == nil {
return nil return nil

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2019 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -34,7 +34,7 @@ func buildSitemap(host, alias string) *stm.Sitemap {
return sm return sm
} }
func handleViewSitemap(app *app, w http.ResponseWriter, r *http.Request) error { func handleViewSitemap(app *App, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r) vars := mux.Vars(r)
// Determine canonical blog URL // Determine canonical blog URL

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2019 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -18,7 +18,7 @@ import (
"net/http" "net/http"
) )
func handleWebSignup(app *app, w http.ResponseWriter, r *http.Request) error { func handleWebSignup(app *App, w http.ResponseWriter, r *http.Request) error {
reqJSON := IsJSON(r.Header.Get("Content-Type")) reqJSON := IsJSON(r.Header.Get("Content-Type"))
// Get params // Get params
@ -67,7 +67,7 @@ func handleWebSignup(app *app, w http.ResponseWriter, r *http.Request) error {
// { "username": "asdf" } // { "username": "asdf" }
// result: { code: 204 } // result: { code: 204 }
func handleUsernameCheck(app *app, w http.ResponseWriter, r *http.Request) error { func handleUsernameCheck(app *App, w http.ResponseWriter, r *http.Request) error {
reqJSON := IsJSON(r.Header.Get("Content-Type")) reqJSON := IsJSON(r.Header.Get("Content-Type"))
// Get params // Get params
@ -112,7 +112,7 @@ func handleUsernameCheck(app *app, w http.ResponseWriter, r *http.Request) error
return impart.HTTPError{http.StatusConflict, "Username is already taken."} return impart.HTTPError{http.StatusConflict, "Username is already taken."}
} }
func getValidUsername(app *app, reqName, prevName string) (string, *impart.HTTPError) { func getValidUsername(app *App, reqName, prevName string) (string, *impart.HTTPError) {
// Check if username is okay // Check if username is okay
finalUsername := getSlug(reqName, "") finalUsername := getSlug(reqName, "")
if finalUsername == "" { if finalUsername == "" {