extract avatar proxy to separate package
This commit is contained in:
+3
-2
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/umputun/remark/app/rest"
|
||||
"github.com/umputun/remark/app/rest/api"
|
||||
"github.com/umputun/remark/app/rest/auth"
|
||||
"github.com/umputun/remark/app/rest/avatar"
|
||||
"github.com/umputun/remark/app/store"
|
||||
)
|
||||
|
||||
@@ -102,7 +103,7 @@ func main() {
|
||||
}
|
||||
go importSrv.Run(opts.Port + 1)
|
||||
|
||||
avatarProxy := &auth.AvatarProxy{
|
||||
avatarProxy := &avatar.Proxy{
|
||||
StorePath: opts.AvatarStore,
|
||||
RoutePath: "/api/v1/avatar",
|
||||
RemarkURL: strings.TrimSuffix(opts.RemarkURL, "/"),
|
||||
@@ -181,7 +182,7 @@ func makeDirs(dirs ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeAuthProviders(sessionStore sessions.Store, avatarProxy *auth.AvatarProxy) (providers []auth.Provider) {
|
||||
func makeAuthProviders(sessionStore sessions.Store, avatarProxy *avatar.Proxy) (providers []auth.Provider) {
|
||||
|
||||
makeParams := func(cid, secret string) auth.Params {
|
||||
return auth.Params{
|
||||
|
||||
@@ -82,7 +82,7 @@ func (s *Rest) Run(port int) {
|
||||
}
|
||||
})
|
||||
|
||||
router.Mount(s.Authenticator.AvatarProxy.Routes())
|
||||
router.Mount(s.Authenticator.AvatarProxy.Routes()) // mount avatars controller to /api/v1/avatar/{file.img}
|
||||
|
||||
// api routes
|
||||
router.Route("/api/v1", func(rapi chi.Router) {
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/umputun/remark/app/rest/avatar"
|
||||
|
||||
"github.com/umputun/remark/app/migrator"
|
||||
"github.com/umputun/remark/app/rest/auth"
|
||||
@@ -468,7 +469,7 @@ func prep(t *testing.T) (srv *Rest, port int) {
|
||||
SessionStore: sessions.NewFilesystemStore("/tmp", []byte("blah")),
|
||||
DevPasswd: "password",
|
||||
Providers: nil,
|
||||
AvatarProxy: &auth.AvatarProxy{StorePath: "/tmp", RoutePath: "/api/v1/avatar"},
|
||||
AvatarProxy: &avatar.Proxy{StorePath: "/tmp", RoutePath: "/api/v1/avatar"},
|
||||
Admins: []string{"a1", "a2"},
|
||||
},
|
||||
Exporter: &migrator.Remark{DataStore: dataStore},
|
||||
|
||||
@@ -11,13 +11,14 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/umputun/remark/app/rest"
|
||||
"github.com/umputun/remark/app/rest/avatar"
|
||||
"github.com/umputun/remark/app/store"
|
||||
)
|
||||
|
||||
// Authenticator is top level auth object providing middlewares
|
||||
type Authenticator struct {
|
||||
SessionStore sessions.Store
|
||||
AvatarProxy *AvatarProxy
|
||||
AvatarProxy *avatar.Proxy
|
||||
Admins []string
|
||||
Providers []Provider
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/umputun/remark/app/rest/avatar"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/umputun/remark/app/rest"
|
||||
@@ -32,7 +33,7 @@ type Provider struct {
|
||||
Scopes []string
|
||||
MapUser func(userData, []byte) store.User // map info from InfoURL to User
|
||||
|
||||
avatarProxy *AvatarProxy
|
||||
avatarProxy *avatar.Proxy
|
||||
conf *oauth2.Config
|
||||
}
|
||||
|
||||
@@ -42,7 +43,7 @@ type Params struct {
|
||||
Csecret string
|
||||
SessionStore sessions.Store
|
||||
RemarkURL string
|
||||
AvatarProxy *AvatarProxy
|
||||
AvatarProxy *avatar.Proxy
|
||||
}
|
||||
|
||||
type userData map[string]interface{}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
package auth
|
||||
// Package avatar provides file-system store and http handler for avatars
|
||||
// On user login auth will call Put and it will retrieve and save picture locally.
|
||||
package avatar
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -21,8 +23,8 @@ import (
|
||||
"github.com/umputun/remark/app/store"
|
||||
)
|
||||
|
||||
// AvatarProxy provides avatar store and http handler for avatars
|
||||
type AvatarProxy struct {
|
||||
// Proxy is avatar store and http handler for avatars
|
||||
type Proxy struct {
|
||||
StorePath string
|
||||
RoutePath string
|
||||
RemarkURL string
|
||||
@@ -34,7 +36,7 @@ type AvatarProxy struct {
|
||||
const imgSfx = ".image"
|
||||
|
||||
// Put stores retrieved avatar to StorePath. Gets image from user info. Returns proxied url
|
||||
func (p *AvatarProxy) Put(u store.User) (avatarURL string, err error) {
|
||||
func (p *Proxy) Put(u store.User) (avatarURL string, err error) {
|
||||
|
||||
// no picture for user, try default avatar
|
||||
if u.Picture == "" {
|
||||
@@ -83,7 +85,7 @@ func (p *AvatarProxy) Put(u store.User) (avatarURL string, err error) {
|
||||
}
|
||||
|
||||
// Routes returns auth routes for given provider
|
||||
func (p *AvatarProxy) Routes() (string, chi.Router) {
|
||||
func (p *Proxy) Routes() (string, chi.Router) {
|
||||
router := chi.NewRouter()
|
||||
|
||||
// GET /123456789.image
|
||||
@@ -91,7 +93,7 @@ func (p *AvatarProxy) Routes() (string, chi.Router) {
|
||||
|
||||
avatar := chi.URLParam(r, "avatar")
|
||||
|
||||
// client-side caching
|
||||
// enforce client-side caching
|
||||
etag := `"` + avatar + `"`
|
||||
w.Header().Set("Etag", etag)
|
||||
w.Header().Set("Cache-Control", "max-age=2592000") // 30 days
|
||||
@@ -133,10 +135,10 @@ func (p *AvatarProxy) Routes() (string, chi.Router) {
|
||||
return p.RoutePath, router
|
||||
}
|
||||
|
||||
// get location for user id by adding partition to final path in order to keep files
|
||||
// get location (directory) for user id by adding partition to final path in order to keep files
|
||||
// in different subdirectories and avoid too many files in a single place.
|
||||
// the end result is a full path like this - /tmp/avatars.test/92
|
||||
func (p *AvatarProxy) location(id string) string {
|
||||
func (p *Proxy) location(id string) string {
|
||||
p.once.Do(func() { p.ctcTable = crc64.MakeTable(crc64.ECMA) })
|
||||
checksum64 := crc64.Checksum([]byte(id), p.ctcTable)
|
||||
partition := checksum64 % 100
|
||||
@@ -1,4 +1,4 @@
|
||||
package auth
|
||||
package avatar
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -26,7 +26,7 @@ func TestPut(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
p := AvatarProxy{StorePath: "/tmp/avatars.test", RoutePath: "/avatar", RemarkURL: "http://localhost:8080"}
|
||||
p := Proxy{StorePath: "/tmp/avatars.test", RoutePath: "/avatar", RemarkURL: "http://localhost:8080"}
|
||||
os.MkdirAll("/tmp/avatars.test", 0700)
|
||||
defer os.RemoveAll("/tmp/avatars.test")
|
||||
|
||||
@@ -48,7 +48,7 @@ func TestPut(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPutNoAvatar(t *testing.T) {
|
||||
p := AvatarProxy{StorePath: "/tmp/avatars.test", RoutePath: "/avatar"}
|
||||
p := Proxy{StorePath: "/tmp/avatars.test", RoutePath: "/avatar"}
|
||||
u := store.User{ID: "user1", Name: "user1 name"}
|
||||
_, err := p.Put(u)
|
||||
assert.Error(t, err)
|
||||
@@ -66,7 +66,7 @@ func TestRoutes(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
p := AvatarProxy{StorePath: "/tmp/avatars.test", RoutePath: "/avatar"}
|
||||
p := Proxy{StorePath: "/tmp/avatars.test", RoutePath: "/avatar"}
|
||||
os.MkdirAll("/tmp/avatars.test", 0700)
|
||||
defer os.RemoveAll("/tmp/avatars.test")
|
||||
|
||||
@@ -98,7 +98,7 @@ func TestRoutes(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLocation(t *testing.T) {
|
||||
p := AvatarProxy{StorePath: "/tmp/avatars.test"}
|
||||
p := Proxy{StorePath: "/tmp/avatars.test"}
|
||||
|
||||
tbl := []struct {
|
||||
id string
|
||||
Reference in New Issue
Block a user