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

convert to regular app #3

Merged
merged 26 commits into from
Nov 26, 2023
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
46 changes: 0 additions & 46 deletions .github/workflows/comment-test.yml

This file was deleted.

40 changes: 18 additions & 22 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ on:
[push]

jobs:
build:
runs-on: ubuntu-latest
build-and-push:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3

Expand All @@ -20,26 +20,22 @@ jobs:
- name: Build
run: make build

- name: what gblic?
run: ldd --version ldd

- name: Test
run: go test ./...

push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup
run: mkdir -p bin/linux && cp bin/webapp bib/linux_amd64/webapp

- name: Get shortsha
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT

- name: Push to GCR
uses: RafikFarhad/[email protected]
with:
gcloud_service_key: ${{ secrets.GCP_SERVICE_ACCOUNT }}
registry: gcr.io
project_id: ian-rose
image_name: us-central1-docker.pkg.dev/ian-rose/docker-1/webapp
image_tag: latest,${{ steps.vars.outputs.sha_short }}
- name: Get shortsha
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT

- name: Push to GCR
uses: RafikFarhad/[email protected]
with:
gcloud_service_key: ${{ secrets.GCP_SERVICE_ACCOUNT }}
registry: us-central1-docker.pkg.dev
project_id: ian-rose/docker-1
image_name: webapp
image_tag: latest,${{ steps.vars.outputs.sha_short }}
build_args: BIN=bin/webapp
27 changes: 25 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,25 @@
*.pyc
secrets.go
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

# Custom stuff from here down:
bin
*.sqlite
.idea
secrets.yaml
var

# from docs here: https://github.com/google-github-actions/auth#prerequisites
gha-creds-*.json
9 changes: 9 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM ubuntu:22.04
ARG BIN
WORKDIR /root/
RUN apt-get update
RUN apt-get install -y ca-certificates

# make cgo happy, see https://github.com/mattn/go-sqlite3/issues/855#issuecomment-1496136603
RUN apt-get install -y build-essential
COPY $BIN /root
18 changes: 18 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.PHONY: build webapp init

build: webapp

webapp:
@mkdir -p bin
go build -o bin/ ./cmd/webapp

webapp-linux:
@mkdir -p bin/linux_amd64/
GOOS=linux GOARCH=amd64 go build -o bin/linux_amd64/ ./cmd/webapp

sql:
./bin/sqlc -f internal/storage/sqlc.yaml generate

# to set things up initially
init:
GOBIN=`pwd`/bin go install github.com/kyleconroy/sqlc/cmd/sqlc@latest
171 changes: 171 additions & 0 deletions cmd/webapp/handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package main

import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"html/template"
"io"
"io/ioutil"
"log"
"net/http"
"net/url"
"strings"

"github.com/ianrose14/website/internal"
)

const (
AlbumsConfigUrl = "https://www.dropbox.com/s/kr8ewc68husts57/albums.json?dl=1"
)

var (
albumsTemplate = template.Must(template.ParseFS(templatesFS, "templates/albums.html"))
)

type album struct {
Name string `json:"name"`
Url string `json:"url"`
CoverPath string `json:"cover_path"`
CoverUrl string
}

// albumsHandler serves a page that lists all available photo albums.
func (svr *server) albumsHandler(w http.ResponseWriter, _ *http.Request) {
rsp, err := http.Get(AlbumsConfigUrl)
if err != nil {
internal.HttpError(w, http.StatusInternalServerError, "failed to fetch albums config from dropbox: %s", err)
return
}
defer internal.DrainAndClose(rsp.Body)

if err := internal.CheckResponse(rsp); err != nil {
internal.HttpError(w, http.StatusInternalServerError, "failed to fetch albums config from dropbox: %s", err)
return
}

var results struct {
Albums []*album `json:"albums"`
}

if err := json.NewDecoder(rsp.Body).Decode(&results); err != nil {
internal.HttpError(w, http.StatusInternalServerError, "failed to json-decode response: %s", err)
return
}

for _, album := range results.Albums {
album.CoverUrl = fmt.Sprintf("/albums/thumbnail?path=%s", url.QueryEscape(album.CoverPath))
}

if err := albumsTemplate.Execute(w, results.Albums); err != nil {
internal.HttpError(w, http.StatusInternalServerError, "failed to render template: %s", err)
return
}
}

func (svr *server) dumpHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")

writeIt := func(s string, args ...interface{}) {
log.Printf(s, args...)
fmt.Fprintf(w, s+"\n", args...)
}

writeIt("URL: %s", r.URL)
writeIt("Method: %s", r.Method)
writeIt("Proto: %s", r.Proto)
writeIt("RemoteAddr: %s", r.RemoteAddr)

var buf bytes.Buffer
buf.WriteString("Headers:\n")
for k, v := range r.Header {
fmt.Fprintf(&buf, "%s: %v\n", k, v)
}
writeIt("%s", buf.String())
fmt.Fprintln(w, "") // write blank line to response body

buf.Reset()
buf.WriteString("Cookies:\n")
for _, c := range r.Cookies() {
fmt.Fprintf(&buf, "%s\n", c)
}
writeIt("%s", buf.String())
fmt.Fprintln(w, "") // write blank line to response body

b, err := ioutil.ReadAll(r.Body)
if err != nil {
writeIt("error: failed to read body: %s", err)
} else {
buf.Reset()
if _, err := base64.NewEncoder(base64.StdEncoding, &buf).Write(b); err != nil {
writeIt("error: failed to base64-encode body: %s", err)
} else {
writeIt("Body (base64):\n%s\n", buf.String())
}
fmt.Fprintln(w, "") // write blank line to response body

writeIt("Body (raw):\n%s", string(b))
fmt.Fprintln(w, "") // write blank line to response body
}
}

func (svr *server) thumbnailHandler(w http.ResponseWriter, r *http.Request) {
path := r.URL.Query().Get("path")
if path == "" {
internal.HttpError(w, http.StatusBadRequest, "no path query")
return
}

if !strings.HasPrefix(path, "/photos/") {
internal.HttpError(w, http.StatusBadRequest, "rejecting forbidden path %s", path)
return
}

params := struct {
Path string `json:"path"`
Format string `json:"format"`
Size string `json:"size"`
}{
Path: path,
Format: "jpeg",
Size: "w640h480",
}

jstr, err := json.Marshal(&params)
if err != nil {
internal.HttpError(w, http.StatusInternalServerError, "failed to json-encode params: %s", err)
return
}

qs := make(url.Values)
qs.Add("arg", string(jstr))

urls := "https://api-content.dropbox.com/2/files/get_thumbnail?" + qs.Encode()
log.Printf("fetching %s", urls)

req, err := http.NewRequest("GET", urls, nil)
if err != nil {
internal.HttpError(w, http.StatusInternalServerError, "failed to make new http request")
return
}

req.Header.Set("Authorization", "Bearer "+svr.secrets.Dropbox.AccessToken)

rsp, err := http.DefaultClient.Do(req)
if err != nil {
internal.HttpError(w, http.StatusInternalServerError, "failed to fetch thumbnail from dropbox: %s", err)
return
}
defer internal.DrainAndClose(rsp.Body)

if err := internal.CheckResponse(rsp); err != nil {
internal.HttpError(w, http.StatusInternalServerError, "failed to fetch thumbnail from dropbox: %s", err)
return
}

w.Header().Set("Content-Type", rsp.Header.Get("Content-Type"))
if _, err := io.Copy(w, rsp.Body); err != nil {
log.Printf("failed to copy thumbnail body to response stream: %s", err)
}
}
Loading