Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HTML presenter for access component #12

Merged
merged 1 commit into from
Jul 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.22.5
require (
github.com/Masterminds/squirrel v1.5.4
github.com/golang-migrate/migrate/v4 v4.17.1
github.com/labstack/echo/v4 v4.12.0
github.com/lib/pq v1.10.9
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.9.0
Expand All @@ -30,6 +31,7 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
Expand All @@ -40,8 +42,11 @@ require (
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgtype v1.14.0 // indirect
github.com/jackc/pgx/v4 v4.18.3 // indirect
github.com/labstack/gommon v0.4.2 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/sys/mountinfo v0.7.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
Expand All @@ -51,6 +56,8 @@ require (
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/teran/go-random v0.0.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 // indirect
go.opentelemetry.io/otel v1.26.0 // indirect
go.opentelemetry.io/otel/metric v1.26.0 // indirect
Expand All @@ -59,8 +66,10 @@ require (
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect
golang.org/x/mod v0.11.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.10.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
17 changes: 17 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPh
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4=
github.com/golang-migrate/migrate/v4 v4.17.1/go.mod h1:m8hinFyWBn0SA4QKHuKh175Pm9wjmxj3S2Mia7dbXzM=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
Expand Down Expand Up @@ -126,6 +128,10 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
Expand All @@ -138,9 +144,14 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g=
Expand Down Expand Up @@ -196,6 +207,10 @@ github.com/teran/go-random v0.0.1 h1:WQ3cF7UUQb/Q0oGAKcYeLeUIcMzD4vSs18oU1pkU/Mo
github.com/teran/go-random v0.0.1/go.mod h1:t6Ns4GZsg/L9whg4u4EVXAj9k2lJiRHmJ7p1intLO0g=
github.com/teran/go-time v0.0.2 h1:9g/+j3gAeMwtFETEh8ggWm1GFj8EFWwL/UqoM3ZYuiA=
github.com/teran/go-time v0.0.2/go.mod h1:fsTuk1e6n6eukMXxmyqY7kG6n5PJUMjUjHA4Ved/enE=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
Expand Down Expand Up @@ -279,6 +294,8 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
Expand Down
102 changes: 102 additions & 0 deletions presenter/access/html/handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package html

import (
"html/template"
"net/http"
"path"

echo "github.com/labstack/echo/v4"

"github.com/teran/archived/service"
)

type Handlers interface {
ContainerIndex(c echo.Context) error
VersionIndex(c echo.Context) error

Register(e *echo.Echo)
}

type handlers struct {
svc service.AccessService
templateDir string
}

func New(svc service.AccessService, templateDir string) Handlers {
return &handlers{
svc: svc,
templateDir: templateDir,
}
}

func (h *handlers) ContainerIndex(c echo.Context) error {
containers, err := h.svc.ListContainers(c.Request().Context())
if err != nil {
return err
}

return c.Render(http.StatusOK, "container-list.html", containers)
}

func (h *handlers) VersionIndex(c echo.Context) error {
container := c.Param("container")
versions, err := h.svc.ListVersions(c.Request().Context(), container)
if err != nil {
return err
}

type data struct {
Container string
Versions []string
}

return c.Render(http.StatusOK, "version-list.html", &data{
Container: container,
Versions: versions,
})
}

func (h *handlers) ObjectIndex(c echo.Context) error {
container := c.Param("container")
version := c.Param("version")

objects, err := h.svc.ListObjects(c.Request().Context(), container, version)
if err != nil {
return err
}

type data struct {
Container string
Version string
Objects []string
}
return c.Render(http.StatusOK, "object-list.html", &data{
Container: container,
Version: version,
Objects: objects,
})
}

func (h *handlers) GetObject(c echo.Context) error {
container := c.Param("container")
version := c.Param("version")
object := c.Param("object")

url, err := h.svc.GetObjectURL(c.Request().Context(), container, version, object)
if err != nil {
return err
}

return c.Redirect(http.StatusFound, url)
}

func (h *handlers) Register(e *echo.Echo) {
e.Renderer = &renderer{
templates: template.Must(template.ParseGlob(path.Join(h.templateDir, "*.html"))),
}

e.GET("/", h.ContainerIndex)
e.GET("/:container/", h.VersionIndex)
e.GET("/:container/:version/", h.ObjectIndex)
e.GET("/:container/:version/:object", h.GetObject)
}
100 changes: 100 additions & 0 deletions presenter/access/html/handlers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package html

import (
"io"
"net/http"
"net/http/httptest"
"os"
"testing"

echo "github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/stretchr/testify/suite"
"github.com/teran/archived/service"
)

func (s *handlersTestSuite) TestContainerIndex() {
s.serviceMock.On("ListContainers").Return([]string{"test-container-1"}, nil).Once()

s.compareHTMLResponse(s.srv.URL, "testdata/index.html.sample")
}

func (s *handlersTestSuite) TestVersionIndex() {
s.serviceMock.On("ListVersions", "test-container-1").Return([]string{"20241011121314"}, nil).Once()

s.compareHTMLResponse(s.srv.URL+"/test-container-1/", "testdata/versions.html.sample")
}

func (s *handlersTestSuite) TestObjectIndex() {
s.serviceMock.On("ListObjects", "test-container-1", "20241011121314").Return([]string{"test-object-dir/file.txt"}, nil).Once()

s.compareHTMLResponse(s.srv.URL+"/test-container-1/20241011121314/", "testdata/objects.html.sample")
}

func (s *handlersTestSuite) TestGetObject() {
s.serviceMock.On("GetObjectURL", "test-container-1", "20241011121314", "test-dir/filename.txt").Return("https://example.com/some-addr", nil).Once()

req, err := http.NewRequest(http.MethodGet, s.srv.URL+"/test-container-1/20241011121314/test-dir/filename.txt", nil)
s.Require().NoError(err)

client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}

resp, err := client.Do(req)
s.Require().NoError(err)

v := resp.Header.Get("Location")
s.Require().Equal("https://example.com/some-addr", v)
}

// Definitions ...
type handlersTestSuite struct {
suite.Suite

srv *httptest.Server

serviceMock *service.Mock
handlers Handlers
}

func (s *handlersTestSuite) SetupTest() {
e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.Recover())

s.serviceMock = service.NewMock()

s.handlers = New(s.serviceMock, "templates")
s.handlers.Register(e)

s.srv = httptest.NewServer(e)
}

func (s *handlersTestSuite) TearDownTest() {
s.serviceMock.AssertExpectations(s.T())

s.srv.Close()
}

func TestHandlersTestSuite(t *testing.T) {
suite.Run(t, &handlersTestSuite{})
}

func (s *handlersTestSuite) compareHTMLResponse(url, responseSamplePath string) {
req, err := http.NewRequest(http.MethodGet, url, nil)
s.Require().NoError(err)

resp, err := http.DefaultClient.Do(req)
s.Require().NoError(err)

sampleData, err := os.ReadFile(responseSamplePath)
s.Require().NoError(err)

data, err := io.ReadAll(resp.Body)
s.Require().NoError(err)

s.Require().Equal(sampleData, data)
}
16 changes: 16 additions & 0 deletions presenter/access/html/renderer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package html

import (
"html/template"
"io"

echo "github.com/labstack/echo/v4"
)

type renderer struct {
templates *template.Template
}

func (r *renderer) Render(w io.Writer, name string, data any, c echo.Context) error {
return r.templates.ExecuteTemplate(w, name, data)
}
14 changes: 14 additions & 0 deletions presenter/access/html/templates/container-list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<html>
<head>
<title>Container Index</title>
</head>
<body>
<h1>Container index</h1>
<hr>
{{- range $container := . }}
<a href="/{{ $container }}/">{{ $container }}</a><br>
{{- end }}
<hr>
Powered by <a href="https://github.com/teran/archived" target="_blank">archived</a>
</body>
</html>
17 changes: 17 additions & 0 deletions presenter/access/html/templates/object-list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{{ $container := .Container }}
{{ $version := .Version }}
<html>
<head>
<title>Object Index ({{ $container }}/{{ $version }})</title>
</head>
<body>
<h1>Object Index ({{ $container }}/{{ $version }})</h1>
<hr>
<a href="..">..</a><br>
{{- range $object := .Objects }}
<a href="/{{ $container }}/{{ $version }}/{{ $object }}">{{ $object }}</a><br>
{{- end }}
<hr>
Powered by <a href="https://github.com/teran/archived" target="_blank">archived</a>
</body>
</html>
16 changes: 16 additions & 0 deletions presenter/access/html/templates/version-list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{{ $container := .Container }}
<html>
<head>
<title>Version Index ({{ $container }})</title>
</head>
<body>
<h1>Version Index ({{ $container }})</h1>
<hr>
<a href="..">..</a><br>
{{- range $version := .Versions }}
<a href="/{{ $container }}/{{ $version }}/">{{ $version }}</a><br>
{{- end }}
<hr>
Powered by <a href="https://github.com/teran/archived" target="_blank">archived</a>
</body>
</html>
12 changes: 12 additions & 0 deletions presenter/access/html/testdata/index.html.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<html>
<head>
<title>Container Index</title>
</head>
<body>
<h1>Container index</h1>
<hr>
<a href="/test-container-1/">test-container-1</a><br>
<hr>
Powered by <a href="https://github.com/teran/archived" target="_blank">archived</a>
</body>
</html>
Loading
Loading