Skip to content

Commit

Permalink
[frontend] Restructure Frontend Sources (#634)
Browse files Browse the repository at this point in the history
* 🐸restructure frontend stuff, include admin and future user panel in main repo, properly deduplicate bundles for css+js across uses

* rename bundled to dist, caught by gitignore

* re-include status.css for profile template

* default to localhost

* serve frontend panels

* add todo message for abstraction

* refactor oauth registration flow

* oauth restructure

* update footer template

* change panel routes

* remove superfluous css imports

* write bundle to disk from test server, use forked budo-express

* wrap all page content in container

for robustness with addons etc injection other elements in body

* update documentation, goreleaser, Dockerfile

* update template meta tags

* add AGPL-3.0+ license header everywhere

* only attach update listener on EventEmitter

* cleaner config for various frontend bundles

* fix bundler script paths

* Merge commit 'd191931932b9293ce1be44ed08a1e69b9fcc1e25'

* fix up dockerfile, goreleaser

* go mod tidy

* add uglifyify

* move status hide/show js to frontend bundle

* fix stylesheet color( func regressions

* update contributing docs for new build path

* update goreleaser + docker building

* resolve dependency paths properly

* update package name

* use api errorhandler

Co-authored-by: tsmethurst <[email protected]>
  • Loading branch information
f0x52 and tsmethurst authored Jun 9, 2022
1 parent f30a581 commit b43f9ce
Show file tree
Hide file tree
Showing 47 changed files with 8,061 additions and 1,918 deletions.
5 changes: 3 additions & 2 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
.github
cmd
.vscode
archive
dist
docs
example
internal
scripts
test
testrig
Expand Down
33 changes: 23 additions & 10 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@ project_name: gotosocial
before:
# https://goreleaser.com/customization/hooks/
hooks:
# tidy up and lint
- go mod tidy
- go fmt ./...
# generate the swagger.yaml file using go-swagger and bundle it into the assets directory
- swagger generate spec -o docs/api/swagger.yaml --scan-models
- sed -i "s/REPLACE_ME/{{ incpatch .Version }}/" docs/api/swagger.yaml
- cp docs/api/swagger.yaml web/assets/swagger.yaml
# install and bundle the web assets and styling
- yarn install --cwd web/gotosocial-styling
- node web/gotosocial-styling/index.js --build-dir="web/assets"
- swagger generate spec -o web/assets/swagger.yaml --scan-models
- sed -i "s/REPLACE_ME/{{ incpatch .Version }}/" web/assets/swagger.yaml
# bundle web assets
- yarn install --cwd web/source
- scripts/bundle.sh
builds:
# https://goreleaser.com/customization/build/
-
Expand Down Expand Up @@ -67,6 +63,10 @@ dockers:
- "--label=org.opencontainers.image.version={{.Version}}"
extra_files:
- web
- go.mod
- go.sum
- cmd
- internal
-
use: buildx
goos: linux
Expand All @@ -82,6 +82,10 @@ dockers:
- "--label=org.opencontainers.image.version={{.Version}}"
extra_files:
- web
- go.mod
- go.sum
- cmd
- internal
-
use: buildx
goos: linux
Expand All @@ -98,6 +102,10 @@ dockers:
- "--label=org.opencontainers.image.version={{.Version}}"
extra_files:
- web
- go.mod
- go.sum
- cmd
- internal
-
use: buildx
goos: linux
Expand All @@ -114,6 +122,10 @@ dockers:
- "--label=org.opencontainers.image.version={{.Version}}"
extra_files:
- web
- go.mod
- go.sum
- cmd
- internal
docker_manifests:
- name_template: superseriousbusiness/{{ .ProjectName }}:{{ .Version }}
image_templates:
Expand All @@ -136,7 +148,8 @@ archives:
- README.md
- CHANGELOG*
# web assets
- web
- web/assets
- web/template
# example config files
- example/config.yaml
- example/gotosocial.service
Expand Down
37 changes: 25 additions & 12 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ Check the [issues](https://github.com/superseriousbusiness/gotosocial/issues) to
- [Updating Swagger docs](#updating-swagger-docs)
- [CI/CD configuration](#cicd-configuration)
- [Release Checklist](#release-checklist)
- [Building releases and Docker containers](#building-releases-and-docker-containers)
- [What if something goes wrong?](#what-if-something-goes-wrong)
- [Building Docker containers](#building-docker-containers)
- [With GoReleaser](#with-goreleaser)
- [Manually](#manually)
- [Financial Compensation](#financial-compensation)
Expand Down Expand Up @@ -70,19 +71,21 @@ To work with the stylesheet for templates, you need [Node.js](https://nodejs.org
To install Yarn dependencies:

```bash
yarn install --cwd web/gotosocial-styling
yarn install --cwd web/source
```

To recompile bundles:

```bash
node web/gotosocial-styling/index.js --build-dir="web/assets"
BUDO_BUILD=1 node web/source
```

You can do automatic live-reloads of bundles with:
Or you can run livereloading in development. It will start a webserver (ip/port printed in console, default localhost:8081), while also keeping the bundles
up-to-date on disk. You can access the user/admin panels at localhost:8080/user, localhost:8080/admin, or run in tandem with the GoToSocial testrig, which will also
serve the updated bundles from disk.

``` bash
NODE_ENV=development node web/gotosocial-styling/index.js --build-dir="web/assets"
NODE_ENV=development node web/source
```

### Golang forking quirks
Expand Down Expand Up @@ -185,7 +188,7 @@ Finally, to run tests against both database types one after the other, use:

### CLI Tests

In [./test/cliparsing.sh](./test/cliparsing.sh) there are a bunch of tests for making sure that CLI flags, config, and environment variables get parsed as expected.
In [./test/cliparsing.sh](./test/cliparsing.sh) and [./test/envparsing.sh](./test/envparsing.sh) there are a bunch of tests for making sure that CLI flags, config, and environment variables get parsed as expected.

Although these tests *are* part of the CI/CD testing process, you probably won't need to worry too much about running them yourself. That is, unless you're messing about with code inside the `main` package in `cmd/gotosocial`, or inside the `config` package in `internal/config`.

Expand Down Expand Up @@ -299,7 +302,9 @@ That is: Delete the tag.

Either way, once we've fixed the issue, we just start from the top of this list again. Version numbers are cheap. It's cheap to burn them.

## Building releases and Docker containers
## Building Docker containers

For both of the below methods, you need to have [Docker buildx](https://docs.docker.com/buildx/working-with-buildx/) installed.

### With GoReleaser

Expand All @@ -311,22 +316,30 @@ Normally, these processes are handled by Drone (see CI/CD above). However, you c

To do this, first [install GoReleaser](https://goreleaser.com/install/).

Then, to create snapshot builds, do:
Then install GoSwagger as described in [the Swagger section](#updating-swagger-docs).

Then install Node and Yarn as described in [Stylesheet / Web dev](#stylesheet--web-dev).

Finally, to create a snapshot build, do:

```bash
goreleaser release --rm-dist --snapshot
goreleaser --rm-dist --snapshot
```

If all goes according to plan, you should now have a bunch of multiple-architecture binaries and tars inside the `./dist` folder, and a snapshot Docker image should be built (check your terminal output for version).
If all goes according to plan, you should now have a bunch of multiple-architecture binaries and tars inside the `./dist` folder, and snapshot Docker images should be built (check your terminal output for version).

### Manually

If you prefer a simple approach with fewer dependencies, you can also just build a Docker container manually in the following way:
If you prefer a simple approach to building a Docker container, with fewer dependencies, you can also just build in the following way:

```bash
./scripts/build.sh && docker build -t superseriousbusiness/gotosocial:latest .
./scripts/build.sh && docker buildx build -t superseriousbusiness/gotosocial:latest .
```

The above command first builds the `gotosocial` binary, then invokes Docker buildx to build the container image.

You don't need to install go-swagger, Node, or Yarn to build Docker images this way.

## Financial Compensation

Right now there's no structure in place for financial compensation for pull requests and code. This is simply because there's no money being made on the project apart from the very small weekly Liberapay donations.
Expand Down
35 changes: 20 additions & 15 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
# syntax=docker/dockerfile:1.3
# stage 1: generate up-to-date swagger.yaml to put in the final container
FROM --platform=${BUILDPLATFORM} quay.io/goswagger/swagger:v0.29.0 AS swagger

# bundle the admin webapp
FROM --platform=${BUILDPLATFORM} node:17.6.0-alpine3.15 AS admin_builder
RUN apk update && apk upgrade --no-cache
RUN apk add git
COPY go.mod /go/src/github.com/superseriousbusiness/gotosocial/go.mod
COPY go.sum /go/src/github.com/superseriousbusiness/gotosocial/go.sum
COPY cmd /go/src/github.com/superseriousbusiness/gotosocial/cmd
COPY internal /go/src/github.com/superseriousbusiness/gotosocial/internal
WORKDIR /go/src/github.com/superseriousbusiness/gotosocial
RUN swagger generate spec -o /go/src/github.com/superseriousbusiness/gotosocial/swagger.yaml --scan-models

RUN git clone https://github.com/superseriousbusiness/gotosocial-admin
WORKDIR /gotosocial-admin
# stage 2: generate the web/assets/dist bundles
FROM --platform=${BUILDPLATFORM} node:16.15.1-alpine3.15 AS bundler

RUN npm install
RUN node index.js
COPY web web
RUN yarn install --cwd web/source && \
BUDO_BUILD=1 node web/source && \
rm -r web/source

FROM --platform=${TARGETPLATFORM} alpine:3.15.0 AS executor
# stage 3: build the executor container
FROM --platform=${TARGETPLATFORM} alpine:3.15.4 as executor

# copy over the binary from the first stage
# copy the dist binary created by goreleaser or build.sh
COPY --chown=1000:1000 gotosocial /gotosocial/gotosocial

# copy over the web directory with templates etc
COPY --chown=1000:1000 web /gotosocial/web

# copy over the admin directory
COPY --chown=1000:1000 --from=admin_builder /gotosocial-admin/public /gotosocial/web/assets/admin
# copy over the web directories with templates, assets etc
COPY --chown=1000:1000 --from=bundler web /gotosocial/web
COPY --chown=1000:1000 --from=swagger /go/src/github.com/superseriousbusiness/gotosocial/swagger.yaml web/assets/swagger.yaml

WORKDIR "/gotosocial"
ENTRYPOINT [ "/gotosocial/gotosocial", "server", "start" ]
12 changes: 6 additions & 6 deletions docs/admin/admin_panel.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Admin Control Panel

[gotosocial-admin](https://github.com/superseriousbusiness/gotosocial-admin) is a simple webclient that uses the [admin api routes](https://docs.gotosocial.org/en/latest/api/swagger/#operations-tag-admin) to manage your instance. It uses the same OAUTH mechanism as normal clients (with scope: admin), and as such can be hosted anywhere, separately from your instance, or run locally. A public installation is available here: [https://gts.superseriousbusiness.org/admin](https://gts.superseriousbusiness.org/admin).
The GoToSocial admin panel is a simple webclient that uses the [admin api routes](https://docs.gotosocial.org/en/latest/api/swagger/#operations-tag-admin) to manage your instance. It uses the same OAUTH mechanism as normal clients (with scope: admin), and as such can be hosted anywhere, separately from your instance, or run locally. A public installation is available here: [https://gts.superseriousbusiness.org/admin](https://gts.superseriousbusiness.org/admin).

## Using the panel
To use the Admin API your account has to be promoted as such:
Expand All @@ -16,11 +16,11 @@ any other client.

You can change the instance's settings like the title and descriptions, and add/remove/change domain blocks including a bulk import/export.

## Installing the panel
## Building the panel
Build requirements: some version of [Node.js](https://nodejs.org) and yarn.
```
git clone https://github.com/superseriousbusiness/gotosocial-admin.git && cd gotosocial-admin
yarn install
node index.js
yarn install --cwd web/source
BUDO_BUILD=1 node web/source
```
This will compile a static bundle in `public/`, which can be copied to any webhost, or put into your GoToSocial installation in the `web/admin` directory.

See also: [Contributing.md Stylesheet / Web dev](https://github.com/superseriousbusiness/gotosocial/blob/main/CONTRIBUTING.md#stylesheet--web-dev)
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -663,8 +663,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220524220425-1d687d428aca h1:xTaFYiPROfpPhqrfTIDXj0ri1SpfueYT951s4bAuDO8=
golang.org/x/net v0.0.0-20220524220425-1d687d428aca/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
Expand Down
67 changes: 56 additions & 11 deletions internal/web/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"strings"

"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/superseriousbusiness/gotosocial/internal/api"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
Expand Down Expand Up @@ -104,14 +103,10 @@ func New(processor processing.Processor) (api.ClientModule, error) {
}

func (m *Module) baseHandler(c *gin.Context) {
l := logrus.WithField("func", "BaseGETHandler")
l.Trace("serving index html")

host := config.GetHost()
instance, err := m.processor.InstanceGet(c.Request.Context(), host)
if err != nil {
l.Debugf("error getting instance from processor: %s", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"})
api.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
return
}

Expand All @@ -120,16 +115,66 @@ func (m *Module) baseHandler(c *gin.Context) {
})
}

// TODO: abstract the {admin, user}panel handlers in some way
func (m *Module) AdminPanelHandler(c *gin.Context) {
host := config.GetHost()
instance, err := m.processor.InstanceGet(c.Request.Context(), host)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
return
}

c.HTML(http.StatusOK, "frontend.tmpl", gin.H{
"instance": instance,
"stylesheets": []string{
"/assets/Fork-Awesome/css/fork-awesome.min.css",
"/assets/dist/panels-admin-style.css",
},
"javascript": []string{
"/assets/dist/bundle.js",
"/assets/dist/admin-panel.js",
},
})
}

func (m *Module) UserPanelHandler(c *gin.Context) {
host := config.GetHost()
instance, err := m.processor.InstanceGet(c.Request.Context(), host)
if err != nil {
api.ErrorHandler(c, gtserror.NewErrorInternalError(err), m.processor.InstanceGet)
return
}

c.HTML(http.StatusOK, "frontend.tmpl", gin.H{
"instance": instance,
"stylesheets": []string{
"/assets/Fork-Awesome/css/fork-awesome.min.css",
"/assets/dist/_colors.css",
"/assets/dist/base.css",
"/assets/dist/panels-user-style.css",
},
"javascript": []string{
"/assets/dist/bundle.js",
"/assets/dist/user-panel.js",
},
})
}

// Route satisfies the RESTAPIModule interface
func (m *Module) Route(s router.Router) error {
// serve static files from assets dir at /assets
s.AttachStaticFS("/assets", fileSystem{http.Dir(m.assetsPath)})

// serve admin panel from within assets dir at /admin/
// and redirect /admin to /admin/
s.AttachStaticFS("/admin/", fileSystem{http.Dir(m.adminPath)})
s.AttachHandler(http.MethodGet, "/admin", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "/admin/")
s.AttachHandler(http.MethodGet, "/admin", m.AdminPanelHandler)
// redirect /admin/ to /admin
s.AttachHandler(http.MethodGet, "/admin/", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "/admin")
})

s.AttachHandler(http.MethodGet, "/user", m.UserPanelHandler)
// redirect /settings/ to /settings
s.AttachHandler(http.MethodGet, "/user/", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "/user")
})

// serve front-page
Expand Down
7 changes: 5 additions & 2 deletions internal/web/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,11 @@ func (m *Module) profileGETHandler(c *gin.Context) {
"statuses": statusResp.Items,
"stylesheets": []string{
"/assets/Fork-Awesome/css/fork-awesome.min.css",
"/assets/status.css",
"/assets/profile.css",
"/assets/dist/status.css",
"/assets/dist/profile.css",
},
"javascript": []string{
"/assets/dist/frontend.js",
},
})
}
Expand Down
14 changes: 10 additions & 4 deletions internal/web/thread.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,16 @@ func (m *Module) threadGETHandler(c *gin.Context) {
}

c.HTML(http.StatusOK, "thread.tmpl", gin.H{
"instance": instance,
"status": status,
"context": context,
"stylesheets": []string{"/assets/Fork-Awesome/css/fork-awesome.min.css", "/assets/status.css"},
"instance": instance,
"status": status,
"context": context,
"stylesheets": []string{
"/assets/Fork-Awesome/css/fork-awesome.min.css",
"/assets/dist/status.css",
},
"javascript": []string{
"/assets/dist/frontend.js",
},
})
}

Expand Down
Loading

0 comments on commit b43f9ce

Please sign in to comment.