Initial commit

This commit is contained in:
Nathan Woodburn 2024-06-22 16:55:03 +10:00
commit 9efd158b1f
14 changed files with 287 additions and 0 deletions

1
.env.example Normal file
View File

@ -0,0 +1 @@
MESSAGE=Test MESSAGE

View File

@ -0,0 +1,49 @@
name: Build Docker
run-name: Build Docker Image
on:
push:
jobs:
BuildSite:
runs-on: [ubuntu-latest, amd]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install Docker
run : |
apt-get install ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install docker-ce-cli -y
- name: Build Docker image
run : |
echo "${{ secrets.DOCKERGIT_TOKEN }}" | docker login git.woodburn.au -u nathanwoodburn --password-stdin
echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}"
tag=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}
tag=${tag//\//-}
tag_num=${GITHUB_RUN_NUMBER}
echo "tag_num=$tag_num"
if [[ "$tag" == "main" ]]; then
tag="latest"
else
tag_num="${tag}-${tag_num}"
fi
echo "tag=$tag"
echo "tag_num=$tag_num"
repo=$GITHUB_REPOSITORY
# Remove the org name
repo=${repo#*/}
echo "container=$repo"
docker build -t $repo:$tag_num .
docker tag $repo:$tag_num git.woodburn.au/nathanwoodburn/$repo:$tag_num
docker push git.woodburn.au/nathanwoodburn/$repo:$tag_num
docker tag $repo:$tag_num git.woodburn.au/nathanwoodburn/$repo:$tag
docker push git.woodburn.au/nathanwoodburn/$repo:$tag

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
main
.env

16
Dockerfile Normal file
View File

@ -0,0 +1,16 @@
# syntax=docker/dockerfile:1
FROM golang:1.21
# Set destination for COPY
WORKDIR /app
COPY main.go ./
COPY go.mod ./
COPY go.sum ./
COPY templates ./templates/
RUN go get
RUN go build main.go
EXPOSE 3000
# Run
CMD ["./main"]

1
README.md Normal file
View File

@ -0,0 +1 @@
# Go Webserver template

5
go.mod Normal file
View File

@ -0,0 +1,5 @@
module git.woodburn.au/nathanwoodburn/go-webserver-template
go 1.21.3
require github.com/joho/godotenv v1.5.1

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=

150
main.go Normal file
View File

@ -0,0 +1,150 @@
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"os"
"path/filepath"
"github.com/joho/godotenv"
)
func main() {
// Load the .env file
err := godotenv.Load()
if err != nil {
// Try to load the .env.example file
fmt.Println("Error loading .env file, trying .env.example")
err = godotenv.Load(".env.example")
if err != nil {
log.Fatal("Error loading .env.example file")
}
}
http.HandleFunc("/", mainHandler)
http.HandleFunc("/assets/", assetHandler)
fmt.Println("Starting server on :3000 ...")
log.Fatal(http.ListenAndServe(":3000", nil))
}
func mainHandler(w http.ResponseWriter, r *http.Request) {
// Sanitize the path to prevent directory traversal attacks
relPath := r.URL.Path
if relPath == "/" {
relPath = "/index"
}
// Check method
switch r.Method {
case http.MethodGet:
getHandler(relPath, w, r)
case http.MethodPost:
postHandler(relPath, w, r)
default:
errorPage(405, w, r)
}
}
func getHandler(relPath string, w http.ResponseWriter, r *http.Request) {
tmplPath := filepath.Join("templates", filepath.Clean(relPath)+".html")
// Get message from Env
message := os.Getenv("MESSAGE")
// Parse the template
tmpl, err := template.ParseFiles(tmplPath)
if err != nil {
errorPage(404, w, r)
return
}
// Create a map to hold the data
requestData := map[string]interface{}{"envMessage": message}
// Execute the template
err = tmpl.Execute(w, requestData)
if err != nil {
http.Error(w, "Error rendering template", http.StatusInternalServerError)
}
}
func postHandler(relPath string, w http.ResponseWriter, r *http.Request) {
switch relPath {
case "/index":
indexPostHandler(w, r)
default:
errorPage(405, w, r)
}
}
func indexPostHandler(w http.ResponseWriter, r *http.Request) {
// Parse the form data
err := r.ParseForm()
if err != nil {
errorPage(500, w, r)
return
}
// Get the form data
message := r.FormValue("message")
// Print the message to the console
log.Printf("Message: %s", message)
// Create a map to hold the data
requestData := map[string]interface{}{
"message": message,
}
// Return a page with message
tmpl, err := template.ParseFiles("templates/index.html")
if err != nil {
errorPage(500, w, r)
return
}
err = tmpl.Execute(w, requestData)
}
func errorPage(errorCode int, w http.ResponseWriter, r *http.Request) {
w.WriteHeader(errorCode)
tmpl, err := template.ParseFiles("templates/error.html")
if err != nil {
log.Printf("Error loading error page template: %v", err)
http.Error(w, "Error loading error page", http.StatusInternalServerError)
return
}
errorMsgs := map[int]string{
404: "Page not found for " + r.URL.Path,
405: "Method not allowed",
500: "Internal server error",
}
// Check if errorcode isn't in the map
if _, ok := errorMsgs[errorCode]; !ok {
errorCode = 500
}
// Correcting the initialization of the errorData map
errorData := map[string]interface{}{
"short": errorCode,
"long": errorMsgs[errorCode],
}
err = tmpl.Execute(w, errorData)
if err != nil {
log.Printf("Error executing error page template: %v", err)
http.Error(w, "Error rendering error page", http.StatusInternalServerError)
}
}
func assetHandler(w http.ResponseWriter, r *http.Request) {
// Serve static files from templates/assets
http.ServeFile(w, r, filepath.Join("templates", filepath.Clean(r.URL.Path)))
}

13
templates/about.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Go HTML Template</title>
<link rel="stylesheet" href="/assets/css/index.css">
<link rel="icon" href="/assets/img/favicon.png">
</head>
<body>
<h1>About page</h1>
</body>
</html>

View File

@ -0,0 +1,5 @@
html {
background-color: black;
color: white;
text-align: center;
}

View File

@ -0,0 +1,4 @@
html {
background-color: black;
color: white;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

14
templates/error.html Normal file
View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Error {{.short}}</title>
<link rel="stylesheet" href="/assets/css/error.css">
<link rel="icon" href="/assets/img/favicon.png">
</head>
<body>
<h1>Error {{.short}}</h1>
<p>{{.long}}</p>
</body>
</html>

24
templates/index.html Normal file
View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Go HTML Template</title>
<link rel="stylesheet" href="/assets/css/index.css">
<link rel="icon" href="/assets/img/favicon.png">
</head>
<body>
<h1>Hello, World!</h1>
{{if .envMessage }}
<p>{{.envMessage}}</p>
{{end}}
{{if .message}}
<p>{{.message}}</p>
{{end}}
<form action="/" method="post">
<input type="text" name="message" placeholder="Enter your message">
<button type="submit">Submit</button>
</form>
</body>
</html>