commit 9efd158b1f17232407884a2a0332e7da06da4523 Author: Nathan Woodburn Date: Sat Jun 22 16:55:03 2024 +1000 Initial commit diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..0f60c40 --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +MESSAGE=Test MESSAGE \ No newline at end of file diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..fe20ab7 --- /dev/null +++ b/.gitea/workflows/build.yml @@ -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 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..912acd9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ + +main +.env \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6da842c --- /dev/null +++ b/Dockerfile @@ -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"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..31e576c --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Go Webserver template \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..0598b50 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module git.woodburn.au/nathanwoodburn/go-webserver-template + +go 1.21.3 + +require github.com/joho/godotenv v1.5.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..d61b19e --- /dev/null +++ b/go.sum @@ -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= diff --git a/main.go b/main.go new file mode 100644 index 0000000..0a3377e --- /dev/null +++ b/main.go @@ -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))) +} diff --git a/templates/about.html b/templates/about.html new file mode 100644 index 0000000..15acde2 --- /dev/null +++ b/templates/about.html @@ -0,0 +1,13 @@ + + + + + + Go HTML Template + + + + +

About page

+ + \ No newline at end of file diff --git a/templates/assets/css/error.css b/templates/assets/css/error.css new file mode 100644 index 0000000..7983fd7 --- /dev/null +++ b/templates/assets/css/error.css @@ -0,0 +1,5 @@ +html { + background-color: black; + color: white; + text-align: center; +} \ No newline at end of file diff --git a/templates/assets/css/index.css b/templates/assets/css/index.css new file mode 100644 index 0000000..5eccafa --- /dev/null +++ b/templates/assets/css/index.css @@ -0,0 +1,4 @@ +html { + background-color: black; + color: white; +} \ No newline at end of file diff --git a/templates/assets/img/favicon.png b/templates/assets/img/favicon.png new file mode 100644 index 0000000..b325464 Binary files /dev/null and b/templates/assets/img/favicon.png differ diff --git a/templates/error.html b/templates/error.html new file mode 100644 index 0000000..ef8e6a7 --- /dev/null +++ b/templates/error.html @@ -0,0 +1,14 @@ + + + + + + Error {{.short}} + + + + +

Error {{.short}}

+

{{.long}}

+ + \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..d9ef1c7 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,24 @@ + + + + + + Go HTML Template + + + + +

Hello, World!

+ {{if .envMessage }} +

{{.envMessage}}

+ {{end}} + + {{if .message}} +

{{.message}}

+ {{end}} +
+ + +
+ + \ No newline at end of file