Compare commits

..

No commits in common. "cf0d0a164457b2746305ce8ef227e1e3fb8a7dc1" and "9705a8c655ed40e3b16d8ef40709c16f2d051636" have entirely different histories.

12 changed files with 133 additions and 110 deletions

View File

@ -17,9 +17,9 @@ jobs:
- name: Build the Docker image - name: Build the Docker image
run: docker compose build run: docker compose build
- name: Docker push - name: Docker push
run: docker push gitea.kleinsense.nl/dariusklein/portfolio:latest run: docker push docker.dariusklein.nl/portfolio
- name: Docker push - name: Docker push
run: docker push gitea.kleinsense.nl/dariusklein/portfolio-docs:latest run: docker push docker.dariusklein.nl/portfolio-docs
publish-docs: publish-docs:
@ -33,11 +33,11 @@ jobs:
- name: Docker remove - name: Docker remove
run: docker rm darius-portfolio-docs || true run: docker rm darius-portfolio-docs || true
- name: Docker login - name: Docker login
run: docker login gitea.kleinsense.nl -p ${{secrets.docker_password}} -u ${{secrets.docker_username}} run: docker login 192.168.1.200:3000 -p ${{secrets.docker_password}} -u ${{secrets.docker_username}}
- name: Docker pull - name: Docker pull
run: docker pull gitea.kleinsense.nl/dariusklein/portfolio-docs:latest run: docker pull 192.168.1.200:3000/DariusKlein/portfolio-docs:latest
- name: Docker run - name: Docker run
run: docker run --restart=always -dit -p 4002:80 --name darius-portfolio-docs gitea.kleinsense.nl/dariusklein/portfolio-docs:latest run: docker run --restart=always -dit -p 4002:80 --name darius-portfolio-docs 192.168.1.200:3000/DariusKlein/portfolio-docs:latest
publish-portfolio: publish-portfolio:
@ -51,8 +51,8 @@ jobs:
- name: Docker remove - name: Docker remove
run: docker rm darius-portfolio-server || true run: docker rm darius-portfolio-server || true
- name: Docker login - name: Docker login
run: docker login gitea.kleinsense.nl -p ${{secrets.docker_password}} -u ${{secrets.docker_username}} run: docker login 192.168.1.200:3000 -p ${{secrets.docker_password}} -u ${{secrets.docker_username}}
- name: Docker pull - name: Docker pull
run: docker pull gitea.kleinsense.nl/dariusklein/portfolio:latest run: docker pull 192.168.1.200:3000/DariusKlein/portfolio:latest
- name: Docker run - name: Docker run
run: docker run --restart=always -dit -p 4001:4001 -p 4002:4002 --name darius-portfolio-server gitea.kleinsense.nl/dariusklein/portfolio:latest run: docker run --restart=always -dit -p 4001:4001 -p 4002:4002 --name darius-portfolio-server 192.168.1.200:3000/DariusKlein/portfolio:latest

View File

@ -5,7 +5,7 @@ import (
"portfolio/api/handlers" "portfolio/api/handlers"
) )
func Routes() *http.ServeMux { func ApiRoutes() *http.ServeMux {
// Create a new request multiplexer // Create a new request multiplexer
// Take incoming requests and dispatch them to the matching webHandler // Take incoming requests and dispatch them to the matching webHandler
mux := http.NewServeMux() mux := http.NewServeMux()

View File

@ -22,9 +22,9 @@ func Login(w http.ResponseWriter, r *http.Request) {
Password: r.PostFormValue("password"), Password: r.PostFormValue("password"),
} }
} else { } else {
if err := json.NewDecoder(r.Body).Decode(&u); err != nil { err := json.NewDecoder(r.Body).Decode(&u)
if err != nil {
InternalServerErrorHandler(w, err) InternalServerErrorHandler(w, err)
return
} }
} }
@ -60,8 +60,7 @@ func Login(w http.ResponseWriter, r *http.Request) {
} else { } else {
UnauthorizedHandler(w) UnauthorizedHandler(w)
return
println("unauthorized")
} }
} }

View File

@ -1,38 +1,55 @@
package handlers package handlers
import ( import "net/http"
"log"
"net/http"
)
func InternalServerErrorHandler(w http.ResponseWriter, err error) { func InternalServerErrorHandler(w http.ResponseWriter, err error) {
setError(w, http.StatusInternalServerError, err.Error()) w.WriteHeader(http.StatusInternalServerError) //set http status
} _, err = w.Write([]byte(err.Error())) //set response message
if err != nil {
func NotFoundHandler(w http.ResponseWriter) { return
setError(w, http.StatusNotFound, "404 Not Found") }
} return
}
func BadRequestHandler(w http.ResponseWriter) {
setError(w, http.StatusBadRequest, "404 Not Found") func NotFoundHandler(w http.ResponseWriter) {
} w.WriteHeader(http.StatusNotFound)
_, err := w.Write([]byte("404 Not Found"))
func UnprocessableEntityHandler(w http.ResponseWriter, err error) { if err != nil {
setError(w, http.StatusUnprocessableEntity, err.Error()) return
} }
}
func UnauthorizedHandler(w http.ResponseWriter) {
setError(w, http.StatusUnauthorized, "Unauthorized") func BadRequestHandler(w http.ResponseWriter) {
} w.WriteHeader(http.StatusBadRequest)
_, err := w.Write([]byte("400 Bad Request"))
func NotImplementedHandler(w http.ResponseWriter) { if err != nil {
setError(w, http.StatusNotImplemented, "WORK IN PROGRESS") return
} }
}
func setError(w http.ResponseWriter, httpStatus int, errorMessage string) {
w.WriteHeader(httpStatus) func UnprocessableEntityHandler(w http.ResponseWriter, err error) {
if _, err := w.Write([]byte(errorMessage)); err != nil { w.WriteHeader(http.StatusUnprocessableEntity) //set http status
log.Println(err) _, err = w.Write([]byte(err.Error())) //set response message
if err != nil {
return
}
return
}
func UnauthorizedHandler(w http.ResponseWriter) {
w.WriteHeader(http.StatusUnauthorized) //set http status
_, err := w.Write([]byte("Unauthorized")) //set response message
if err != nil {
return
}
return
}
func NotImplementedHandler(w http.ResponseWriter) {
w.WriteHeader(http.StatusNotImplemented) //set http status
_, err := w.Write([]byte("WORK IN PROGRESS"))
if err != nil {
return
} }
return return
} }

View File

@ -3,6 +3,7 @@ package handlers
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"fmt"
"net/http" "net/http"
"os" "os"
"portfolio/api/service/jwt" "portfolio/api/service/jwt"
@ -23,12 +24,14 @@ func CreateProjectHandler(w http.ResponseWriter, r *http.Request) {
var p *ent.Project var p *ent.Project
if err = json.NewDecoder(r.Body).Decode(&p); err != nil { err = json.NewDecoder(r.Body).Decode(&p)
if err != nil {
InternalServerErrorHandler(w, err) InternalServerErrorHandler(w, err)
return return
} }
if err = query.CreateProject(context.Background(), *p, id); err != nil { err = query.CreateProject(context.Background(), *p, id)
if err != nil {
UnprocessableEntityHandler(w, err) UnprocessableEntityHandler(w, err)
return return
} }
@ -36,7 +39,8 @@ func CreateProjectHandler(w http.ResponseWriter, r *http.Request) {
func UpdateProjectHandler(w http.ResponseWriter, r *http.Request) { func UpdateProjectHandler(w http.ResponseWriter, r *http.Request) {
if _, _, err := jwt.VerifyUser(r); err != nil { _, _, err := jwt.VerifyUser(r)
if err != nil {
UnauthorizedHandler(w) UnauthorizedHandler(w)
return return
} }
@ -46,7 +50,6 @@ func UpdateProjectHandler(w http.ResponseWriter, r *http.Request) {
projectID, err := strconv.Atoi(r.PathValue("id")) projectID, err := strconv.Atoi(r.PathValue("id"))
if err != nil { if err != nil {
BadRequestHandler(w) BadRequestHandler(w)
return
} }
p, err = query.GetFullProject(context.Background(), projectID) p, err = query.GetFullProject(context.Background(), projectID)
@ -55,12 +58,14 @@ func UpdateProjectHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
if err = json.NewDecoder(r.Body).Decode(&p); err != nil { err = json.NewDecoder(r.Body).Decode(&p)
if err != nil {
InternalServerErrorHandler(w, err) InternalServerErrorHandler(w, err)
return return
} }
if err = query.UpdateProject(context.Background(), *p, projectID); err != nil { err = query.UpdateProject(context.Background(), *p, projectID)
if err != nil {
UnprocessableEntityHandler(w, err) UnprocessableEntityHandler(w, err)
return return
} }
@ -68,19 +73,19 @@ func UpdateProjectHandler(w http.ResponseWriter, r *http.Request) {
func UpdateProjectsHandler(w http.ResponseWriter, r *http.Request) { func UpdateProjectsHandler(w http.ResponseWriter, r *http.Request) {
var newProjects []*ent.Project
var p []*ent.Project
var err error
isHtmx := r.Header.Get("HX-Request") isHtmx := r.Header.Get("HX-Request")
if _, _, err := jwt.VerifyUser(r); err != nil { _, _, err := jwt.VerifyUser(r)
if err != nil {
UnauthorizedHandler(w) UnauthorizedHandler(w)
return return
} }
var newProjects []*ent.Project
var p []*ent.Project
if isHtmx == "true" { if isHtmx == "true" {
p = parse.ProjectInput(r) p = parse.ParseProjectInput(r)
} else { } else {
p, err = query.GetFullProjects(context.Background()) p, err = query.GetFullProjects(context.Background())
@ -105,7 +110,8 @@ func UpdateProjectsHandler(w http.ResponseWriter, r *http.Request) {
} }
for _, project := range p { for _, project := range p {
if err = query.UpdateProject(context.Background(), *project, project.ID); err != nil { err = query.UpdateProject(context.Background(), *project, project.ID)
if err != nil {
UnprocessableEntityHandler(w, err) UnprocessableEntityHandler(w, err)
return return
} }
@ -128,8 +134,8 @@ func GetProjectHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err = json.NewEncoder(w).Encode(p); err != nil { err = json.NewEncoder(w).Encode(p)
InternalServerErrorHandler(w, err) if err != nil {
return return
} }
} }
@ -144,13 +150,14 @@ func GetProjectsHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err = json.NewEncoder(w).Encode(p); err != nil { err = json.NewEncoder(w).Encode(p)
InternalServerErrorHandler(w, err) if err != nil {
return return
} }
} }
func GetProjectsBackupHandler(w http.ResponseWriter, r *http.Request) { func GetProjectsBackupHandler(w http.ResponseWriter, r *http.Request) {
fmt.Print("test")
p, err := query.GetProjects(context.Background()) p, err := query.GetProjects(context.Background())
if err != nil { if err != nil {
UnprocessableEntityHandler(w, err) UnprocessableEntityHandler(w, err)
@ -161,17 +168,14 @@ func GetProjectsBackupHandler(w http.ResponseWriter, r *http.Request) {
backup, _ := json.Marshal(p) backup, _ := json.Marshal(p)
if err = os.WriteFile( err = os.WriteFile("/web/assets/json/backup-"+strconv.Itoa(int(time.Now().Unix()))+".json", backup, 0644)
"/web/assets/json/backup-"+strconv.Itoa(int(time.Now().Unix()))+".json", if err != nil {
backup,
0644,
); err != nil {
UnprocessableEntityHandler(w, err) UnprocessableEntityHandler(w, err)
return return
} }
if err = json.NewEncoder(w).Encode(p); err != nil { err = json.NewEncoder(w).Encode(p)
InternalServerErrorHandler(w, err) if err != nil {
return return
} }
} }

View File

@ -23,9 +23,9 @@ func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
//Role: user.Role(r.PostFormValue("role")), //Role: user.Role(r.PostFormValue("role")),
} }
} else { } else {
if err := json.NewDecoder(r.Body).Decode(&u); err != nil { err := json.NewDecoder(r.Body).Decode(&u)
if err != nil {
InternalServerErrorHandler(w, err) InternalServerErrorHandler(w, err)
return
} }
} }
u.Password = "123" u.Password = "123"
@ -37,13 +37,14 @@ func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
//hash password //hash password
u.Password, _ = bcrypt.HashPassword(u.Password) u.Password, _ = bcrypt.HashPassword(u.Password)
if err := query.CreateUser(context.Background(), *u); err != nil { err := query.CreateUser(context.Background(), *u)
if err != nil {
UnprocessableEntityHandler(w, err) UnprocessableEntityHandler(w, err)
return return
} }
w.WriteHeader(http.StatusCreated) w.WriteHeader(http.StatusCreated)
w.Write([]byte("user created")) _, err = w.Write([]byte("user created"))
} }
func GetUserHandler(w http.ResponseWriter, r *http.Request) { func GetUserHandler(w http.ResponseWriter, r *http.Request) {
@ -61,7 +62,8 @@ func GetUserHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
if err = json.NewEncoder(w).Encode(User); err != nil { err = json.NewEncoder(w).Encode(User)
if err != nil {
InternalServerErrorHandler(w, err) InternalServerErrorHandler(w, err)
return return
} }

View File

@ -11,7 +11,7 @@ import (
"strconv" "strconv"
) )
func ProjectInput(r *http.Request) []*ent.Project { func ParseProjectInput(r *http.Request) []*ent.Project {
b, err := io.ReadAll(r.Body) b, err := io.ReadAll(r.Body)
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)

View File

@ -1,6 +1,20 @@
version: '3.8' version: '3.8'
services: services:
# database:
# container_name: darius-portfolio-database
# image: postgres:alpine
# restart: always
# env_file:
# - .env
# ports:
# - "5432:5432"
# healthcheck:
# test: [ "CMD-SHELL", "pg_isready -U postgres" ]
# interval: 10s
# timeout: 5s
# retries: 5
portfolio: portfolio:
container_name: darius-portfolio-server container_name: darius-portfolio-server
build: . build: .
@ -10,7 +24,10 @@ services:
- "4000:4000" - "4000:4000"
- "4001:4001" - "4001:4001"
restart: unless-stopped restart: unless-stopped
image: gitea.kleinsense.nl/portfolio:latest image: docker.dariusklein.nl/portfolio:latest
# depends_on:
# database:
# condition: service_healthy
volumes: volumes:
- ./backup:/web/assets/json - ./backup:/web/assets/json
@ -22,5 +39,5 @@ services:
ports: ports:
- "4002:80" - "4002:80"
restart: unless-stopped restart: unless-stopped
image: gitea.kleinsense.nl/portfolio-docs:latest image: docker.dariusklein.nl/portfolio-docs:latest

1
go.mod
View File

@ -24,7 +24,6 @@ require (
github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/hcl/v2 v2.23.0 // indirect github.com/hashicorp/hcl/v2 v2.23.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/zclconf/go-cty v1.16.2 // indirect github.com/zclconf/go-cty v1.16.2 // indirect
github.com/zclconf/go-cty-yaml v1.1.0 // indirect github.com/zclconf/go-cty-yaml v1.1.0 // indirect

35
main.go
View File

@ -1,9 +1,7 @@
package main package main
import ( import (
"github.com/joho/godotenv"
"github.com/rs/cors" "github.com/rs/cors"
"log"
"net/http" "net/http"
"portfolio/api" "portfolio/api"
"portfolio/database" "portfolio/database"
@ -11,26 +9,20 @@ import (
) )
func main() { func main() {
// load .env in runtime environment //// load .env in runtime environment
err := godotenv.Load() //err := godotenv.Load()
if err != nil { //if err != nil {
log.Fatalf(".env not found: %v", err) // log.Fatalf(".env not found: %v", err)
return // return
} //}
//connect to database and migrate //connect to database and migrate
database.DB() database.DB()
//init web routes //init web routes
webMux := web.Routes() webMux := web.WebRoutes()
// Run web server // Run web server
go func() { go http.ListenAndServe(":4000", cors.AllowAll().Handler(webMux))
err = http.ListenAndServe(":4000", cors.AllowAll().Handler(webMux))
if err != nil {
log.Fatal(err)
}
}()
c := cors.New(cors.Options{ c := cors.New(cors.Options{
AllowedOrigins: []string{"http://localhost:4000", "https://*.dariusklein.nl", "https://*.portfolio.dariusklein.nl", "https://dariusklein.nl"}, AllowedOrigins: []string{"http://localhost:4000", "https://*.dariusklein.nl", "https://*.portfolio.dariusklein.nl", "https://dariusklein.nl"},
@ -47,15 +39,8 @@ func main() {
}) })
//init api routes //init api routes
apiMux := api.Routes() apiMux := api.ApiRoutes()
//run api server //run api server
go func() { http.ListenAndServe(":4001", c.Handler(apiMux))
err = http.ListenAndServe(":4001", c.Handler(apiMux))
if err != nil {
log.Fatal(err)
}
}()
// block main thread
select {}
} }

View File

@ -12,7 +12,7 @@ var BaseUrl = "https://api.portfolio.dariusklein.nl"
// todo var BaseUrl = "http://localhost:4001" // todo var BaseUrl = "http://localhost:4001"
func Login() g.Node { func Login() g.Node {
return Form(hx.Post(BaseUrl+"/login"), //https://api.portfolio.dariusklein.nl/login return FormEl(hx.Post(BaseUrl+"/login"), //https://api.portfolio.dariusklein.nl/login
Class("max-w-xl m-auto py-32"), Class("max-w-xl m-auto py-32"),
b.Box( b.Box(
Email(false, false, nil), Email(false, false, nil),

View File

@ -5,7 +5,7 @@ import (
"portfolio/web/handlers" "portfolio/web/handlers"
) )
func Routes() *http.ServeMux { func WebRoutes() *http.ServeMux {
// Create a new request multiplexer // Create a new request multiplexer
// Take incoming requests and dispatch them to the matching webHandler // Take incoming requests and dispatch them to the matching webHandler
mux := http.NewServeMux() mux := http.NewServeMux()