diff --git a/account.go b/account.go index f6fca31..9afb8a5 100644 --- a/account.go +++ b/account.go @@ -1059,17 +1059,20 @@ func viewStats(app *App, u *User, w http.ResponseWriter, r *http.Request) error } obj := struct { *UserPage - VisitsBlog string - Collection *Collection - TopPosts *[]PublicPost - APFollowers int - Silenced bool + VisitsBlog string + Collection *Collection + TopPosts *[]PublicPost + APFollowers int + EmailEnabled bool + EmailSubscribers int + Silenced bool }{ - UserPage: NewUserPage(app, r, u, titleStats+"Stats", flashes), - VisitsBlog: alias, - Collection: c, - TopPosts: topPosts, - Silenced: silenced, + UserPage: NewUserPage(app, r, u, titleStats+"Stats", flashes), + VisitsBlog: alias, + Collection: c, + TopPosts: topPosts, + EmailEnabled: app.cfg.Email.Enabled(), + Silenced: silenced, } obj.UserPage.CollAlias = c.Alias if app.cfg.App.Federation { @@ -1079,11 +1082,73 @@ func viewStats(app *App, u *User, w http.ResponseWriter, r *http.Request) error } obj.APFollowers = len(*folls) } + if obj.EmailEnabled { + subs, err := app.db.GetEmailSubscribers(c.ID, true) + if err != nil { + return err + } + obj.EmailSubscribers = len(subs) + } showUserPage(w, "stats", obj) return nil } +func handleViewSubscribers(app *App, u *User, w http.ResponseWriter, r *http.Request) error { + vars := mux.Vars(r) + c, err := app.db.GetCollection(vars["collection"]) + if err != nil { + return err + } + + filter := r.FormValue("filter") + + flashes, _ := getSessionFlashes(app, w, r, nil) + obj := struct { + *UserPage + Collection CollectionNav + EmailSubs []*EmailSubscriber + Followers *[]RemoteUser + Silenced bool + + Filter string + FederationEnabled bool + CanEmailSub bool + CanAddSubs bool + EmailSubsEnabled bool + }{ + UserPage: NewUserPage(app, r, u, c.DisplayTitle()+" Subscribers", flashes), + Collection: CollectionNav{ + Collection: c, + Path: r.URL.Path, + SingleUser: app.cfg.App.SingleUser, + }, + Silenced: u.IsSilenced(), + Filter: filter, + FederationEnabled: app.cfg.App.Federation, + CanEmailSub: app.cfg.Email.Enabled(), + EmailSubsEnabled: c.EmailSubsEnabled(), + } + + obj.Followers, err = app.db.GetAPFollowers(c) + if err != nil { + return err + } + + obj.EmailSubs, err = app.db.GetEmailSubscribers(c.ID, true) + if err != nil { + return err + } + + if obj.Filter == "" { + // Set permission to add email subscribers + //obj.CanAddSubs = app.db.GetUserAttribute(c.OwnerID, userAttrCanAddEmailSubs) == "1" + } + + showUserPage(w, "subscribers", obj) + return nil +} + func viewSettings(app *App, u *User, w http.ResponseWriter, r *http.Request) error { fullUser, err := app.db.GetUserByID(u.ID) if err != nil { diff --git a/collections.go b/collections.go index b95c20d..8368447 100644 --- a/collections.go +++ b/collections.go @@ -84,6 +84,14 @@ type ( TotalPages int Silenced bool } + + CollectionNav struct { + *Collection + Path string + SingleUser bool + CanPost bool + } + SubmittedCollection struct { // Data used for updating a given collection ID int64 diff --git a/less/admin.less b/less/admin.less index 86dc9ff..673a03b 100644 --- a/less/admin.less +++ b/less/admin.less @@ -60,6 +60,35 @@ nav#admin { background: #ccc; } } + + &.sub { + margin: 1em 0 2em; + a:not(.toggle) { + border: 0; + border-bottom: 2px transparent solid; + .rounded(0); + padding: 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + + &:hover { + color: @primary; + background: transparent; + } + &.selected { + color: @primary; + background: transparent; + border-bottom-color: @primary; + } + &+a { + margin-left: 1em; + } + } + a.toggle { + margin-top: -0.5em; + float: right; + } + } } .admin-actions { diff --git a/routes.go b/routes.go index 0a44821..dc2a3c1 100644 --- a/routes.go +++ b/routes.go @@ -99,6 +99,7 @@ func InitRoutes(apper Apper, r *mux.Router) *mux.Router { me.HandleFunc("/c/", handler.User(viewCollections)).Methods("GET") me.HandleFunc("/c/{collection}", handler.User(viewEditCollection)).Methods("GET") me.HandleFunc("/c/{collection}/stats", handler.User(viewStats)).Methods("GET") + me.HandleFunc("/c/{collection}/subscribers", handler.User(handleViewSubscribers)).Methods("GET") me.Path("/delete").Handler(csrf.Protect(apper.App().keys.CSRFKey)(handler.User(handleUserDelete))).Methods("POST") me.HandleFunc("/posts", handler.Redirect("/me/posts/", UserLevelUser)).Methods("GET") me.HandleFunc("/posts/", handler.User(viewArticles)).Methods("GET") diff --git a/templates/collection.tmpl b/templates/collection.tmpl index 8380910..93a01c5 100644 --- a/templates/collection.tmpl +++ b/templates/collection.tmpl @@ -54,6 +54,7 @@ {{if .SimpleNav}}
  • New Post
  • {{end}}
  • Customize
  • Stats
  • +
  • Subscribers

  • {{if not .SingleUser}}
  • View Blogs
  • {{end}}
  • View Drafts
  • diff --git a/templates/user/include/header.tmpl b/templates/user/include/header.tmpl index 66a2a84..9b6912b 100644 --- a/templates/user/include/header.tmpl +++ b/templates/user/include/header.tmpl @@ -18,6 +18,7 @@ diff --git a/templates/user/include/nav.tmpl b/templates/user/include/nav.tmpl index 057fc3c..735019d 100644 --- a/templates/user/include/nav.tmpl +++ b/templates/user/include/nav.tmpl @@ -9,6 +9,7 @@ {{if .CanPost}}New Post{{end}} Customize Stats + Subscribers View Blog → diff --git a/templates/user/stats.tmpl b/templates/user/stats.tmpl index 0791f77..b7f3322 100644 --- a/templates/user/stats.tmpl +++ b/templates/user/stats.tmpl @@ -30,15 +30,17 @@ td.none { {{end}}

    Stats for all time.

    - - {{if .Federation}} -

    Fediverse stats

    + + {{if or .Federation .EmailEnabled}} +

    Subscribers

    - + {{if .Federation}}{{end}} + {{if .EmailEnabled}}{{end}} - + {{if .Federation}}{{end}} + {{if .EmailEnabled}}{{end}}
    FollowersFediverse FollowersEmail Subscribers
    {{.APFollowers}}{{.APFollowers}}{{.EmailSubscribers}}
    {{end}} diff --git a/templates/user/subscribers.tmpl b/templates/user/subscribers.tmpl new file mode 100644 index 0000000..1e79ddb --- /dev/null +++ b/templates/user/subscribers.tmpl @@ -0,0 +1,98 @@ +{{define "subscribers"}} +{{template "header" .}} + + + +
    + {{if .Silenced}} + {{template "user-silenced"}} + {{end}} + + {{if .Collection.Collection}}{{template "collection-breadcrumbs" .}}{{end}} + +

    Subscribers

    + {{if .Collection.Collection}} + {{template "collection-nav" .Collection}} + + + {{end}} + + {{if .Flashes -}} + + {{- end}} + + {{ if eq .Filter "fediverse" }} + + + + + + + {{if and (gt (len .Followers) 0) (not .FederationEnabled)}} +
    +

    Federation is disabled on this server, so followers won't receive any new posts.

    +
    + {{end}} + {{ if gt (len .Followers) 0 }} + {{range $el := .Followers}} + + + + + {{end}} + {{ else }} + + + + {{ end }} +
    UsernameSince
    @{{.EstimatedHandle}}{{.CreatedFriendly}}
    No followers yet.
    + {{ else }} + {{if or .CanEmailSub .EmailSubs}} + {{if not .CanEmailSub}} +
    +

    Email subscriptions are disabled on this server, so no new emails will be sent out.

    +
    + {{end}} + {{if not .EmailSubsEnabled}} +
    +

    Email subscriptions are disabled. {{if .EmailSubs}}No new emails will be sent out.{{end}} To enable email subscriptions, turn the option on from your blog's Customize page.

    +
    + {{end}} + + + + + + + {{ if .EmailSubs }} + {{range $el := .EmailSubs}} + + + + + {{end}} + {{ else }} + + + + {{ end }} +
    Email AddressSince
    {{.Email.String}}{{.SubscribedFriendly}}
    No subscribers yet.
    + {{end}} + {{ end }} + +
    + +{{template "foot" .}} + +{{template "body-end" .}} +{{end}}