Compare commits

..

No commits in common. "master" and "EditProjects" have entirely different histories.

60 changed files with 477 additions and 1122 deletions

View File

@ -1,20 +0,0 @@
JWT_SECRET=temp123
ENVIRONMENT=docker
WEB_PORT=4000
API_PORT=4001
# -
# Database
# -
# IP address of database
POSTGRES_HOST=
# Database port
POSTGRES_PORT=
# Database username
POSTGRES_USER=
# The name of the database to connect to
POSTGRES_DB=portfolio
# Database password
POSTGRES_PASSWORD=
# Whether or not to use SSL ("verify-full" or "disable")
SSL_MODE=disable

View File

@ -13,61 +13,43 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: 'Create env file' - name: 'Create env file'
run: | run: |
touch .env touch .env
echo WEB_PORT=4000 >> .env echo POSTGRES_HOST=${{ secrets.POSTGRES_HOST }} >> .env
echo API_PORT=4001 >> .env echo POSTGRES_PORT=${{ secrets.POSTGRES_PORT }} >> .env
echo JWT_SECRET=${{secrets.JWT_SECRET}} >> .env echo POSTGRES_USER=${{ secrets.POSTGRES_USER }} >> .env
echo POSTGRES_HOST=192.168.1.200 >> .env echo POSTGRES_DB=${{ secrets.POSTGRES_DB }} >> .env
echo POSTGRES_PORT=5099 >> .env echo POSTGRES_PASSWORD=${{ secrets.POSTGRES_PASSWORD }} >> .env
echo POSTGRES_USER=postgres >> .env echo SSL_MODE=${{ secrets.SSL_MODE }} >> .env
echo POSTGRES_DB=portfolio >> .env - name: Build the Docker image
echo POSTGRES_PASSWORD=${{secrets.POSTGRES_PASSWORD}} >> .env run: docker compose build
echo SSL_MODE=disable >> .env - name: Docker push
echo ENVIRONMENT=docker >> .env run: |
- name: Build the Docker image docker push docker.dariusklein.nl/portfolio:latest
run: docker compose build docker push docker.dariusklein.nl/portfolio-docs:latest
- name: Docker login
run: docker login gitea.kleinsense.nl -p ${{secrets.docker_password}} -u ${{secrets.docker_username}}
- name: Docker push
run: docker push gitea.kleinsense.nl/dariusklein/portfolio:latest
- name: Docker push
run: docker push gitea.kleinsense.nl/dariusklein/portfolio-docs:latest
publish-docs: publish:
needs: build needs: build
runs-on: ubuntu-latest runs-on: self-hosted
steps: steps:
- name: Docker stop - uses: actions/checkout@v3
run: docker stop darius-portfolio-docs || true with:
- name: Docker remove sparse-checkout: |
run: docker rm darius-portfolio-docs || true docker-compose.yml
- name: Docker login - name: copy file
run: docker login gitea.kleinsense.nl -p ${{secrets.docker_password}} -u ${{secrets.docker_username}} run: mv docker-compose.yml /home/darius/portfolio
- name: Docker pull - name: Docker login
run: docker pull gitea.kleinsense.nl/dariusklein/portfolio-docs:latest run: docker login docker.dariusklein.nl -u Darius -p ${{ secrets.DOCKER_PASSWORD }}
- name: Docker run - name: Docker pull
run: docker run --restart=always -dit -p 4002:80 --name darius-portfolio-docs gitea.kleinsense.nl/dariusklein/portfolio-docs:latest run: |
cd /home/darius/portfolio
publish-portfolio: docker compose pull
- name: Docker run
needs: build run: |
cd /home/darius/portfolio
runs-on: ubuntu-latest docker compose up -d
steps:
- name: Docker stop
run: docker stop darius-portfolio-server || true
- name: Docker remove
run: docker rm darius-portfolio-server || true
- name: Docker login
run: docker login gitea.kleinsense.nl -p ${{secrets.docker_password}} -u ${{secrets.docker_username}}
- name: Docker pull
run: docker pull gitea.kleinsense.nl/dariusklein/portfolio:latest
- name: Docker run
run: docker run --restart=always -dit -p 4000:4000 -p 4001:4001 --name darius-portfolio-server gitea.kleinsense.nl/dariusklein/portfolio:latest

View File

@ -19,8 +19,7 @@ FROM gcr.io/distroless/base-debian12
COPY --from=build /go/portfolio . COPY --from=build /go/portfolio .
COPY .env . ADD .env .
ADD ./web/assets ./web/assets ADD ./web/assets ./web/assets
# Expose port 8080 for incoming traffic # Expose port 8080 for incoming traffic

View File

@ -1 +1,2 @@
Portfolio project backend api Portfolio project backend api
test

View File

@ -1,13 +1,11 @@
package api package api
import ( import (
"log"
"net/http" "net/http"
"portfolio/api/handlers" "portfolio/api/handlers"
) )
func Routes() *http.ServeMux { func ApiRoutes() *http.ServeMux {
log.Println("Setup web routes")
// 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()
@ -30,7 +28,6 @@ func Routes() *http.ServeMux {
mux.HandleFunc("PATCH /projects", handlers.UpdateProjectsHandler) mux.HandleFunc("PATCH /projects", handlers.UpdateProjectsHandler)
mux.HandleFunc("GET /project/{id}", handlers.GetProjectHandler) mux.HandleFunc("GET /project/{id}", handlers.GetProjectHandler)
mux.HandleFunc("GET /projects", handlers.GetProjectsHandler) mux.HandleFunc("GET /projects", handlers.GetProjectsHandler)
mux.HandleFunc("GET /projects/backup", handlers.GetProjectsBackupHandler)
return mux return mux
} }

View File

@ -1,6 +1,6 @@
module openAPI module openAPI
go 1.24.0 go 1.22
require ( require (
github.com/a-h/respond v0.0.2 github.com/a-h/respond v0.0.2
@ -8,19 +8,17 @@ require (
) )
require ( require (
github.com/getkin/kin-openapi v0.132.0 // indirect github.com/getkin/kin-openapi v0.124.0 // indirect
github.com/go-openapi/jsonpointer v0.21.1 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/swag v0.23.1 // indirect github.com/go-openapi/swag v0.23.0 // indirect
github.com/invopop/yaml v0.3.1 // indirect github.com/invopop/yaml v0.3.1 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.9.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect
golang.org/x/mod v0.24.0 // indirect golang.org/x/mod v0.17.0 // indirect
golang.org/x/sync v0.14.0 // indirect golang.org/x/sync v0.7.0 // indirect
golang.org/x/tools v0.33.0 // indirect golang.org/x/tools v0.20.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

View File

@ -6,16 +6,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/getkin/kin-openapi v0.124.0 h1:VSFNMB9C9rTKBnQ/fpyDU8ytMTr4dWI9QovSKj9kz/M= github.com/getkin/kin-openapi v0.124.0 h1:VSFNMB9C9rTKBnQ/fpyDU8ytMTr4dWI9QovSKj9kz/M=
github.com/getkin/kin-openapi v0.124.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM= github.com/getkin/kin-openapi v0.124.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM=
github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk=
github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic=
github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
@ -30,14 +24,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY=
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw=
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c=
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o=
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@ -50,20 +38,12 @@ github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc= golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc=
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@ -4,7 +4,7 @@ import (
"github.com/a-h/respond" "github.com/a-h/respond"
"github.com/a-h/rest" "github.com/a-h/rest"
"net/http" "net/http"
"portfolio/api/types" "portfolio/database/ent"
) )
func RegisterProjectEndpoints() { func RegisterProjectEndpoints() {
@ -21,7 +21,7 @@ func RegisterProjectEndpoints() {
Regexp: `\d+`, Regexp: `\d+`,
}). }).
HasDescription("Update project by id"). HasDescription("Update project by id").
HasRequestModel(rest.ModelOf[types.Project]()). HasRequestModel(rest.ModelOf[ent.Project]()).
HasResponseModel(http.StatusOK, rest.ModelOf[string]()). HasResponseModel(http.StatusOK, rest.ModelOf[string]()).
HasResponseModel(http.StatusBadRequest, rest.ModelOf[string]()). HasResponseModel(http.StatusBadRequest, rest.ModelOf[string]()).
HasResponseModel(http.StatusInternalServerError, rest.ModelOf[respond.Error]()). HasResponseModel(http.StatusInternalServerError, rest.ModelOf[respond.Error]()).
@ -30,7 +30,7 @@ func RegisterProjectEndpoints() {
api.Patch("/projects"). api.Patch("/projects").
HasDescription("Update projects WIP"). HasDescription("Update projects WIP").
HasResponseModel(http.StatusOK, rest.ModelOf[[]types.Project]()). HasResponseModel(http.StatusOK, rest.ModelOf[[]ent.Project]()).
HasResponseModel(http.StatusInternalServerError, rest.ModelOf[respond.Error]()). HasResponseModel(http.StatusInternalServerError, rest.ModelOf[respond.Error]()).
HasResponseModel(http.StatusUnprocessableEntity, rest.ModelOf[respond.Error]()). HasResponseModel(http.StatusUnprocessableEntity, rest.ModelOf[respond.Error]()).
HasResponseModel(http.StatusUnauthorized, rest.ModelOf[string]()) HasResponseModel(http.StatusUnauthorized, rest.ModelOf[string]())
@ -41,12 +41,12 @@ func RegisterProjectEndpoints() {
Regexp: `\d+`, Regexp: `\d+`,
}). }).
HasDescription("Get project by id"). HasDescription("Get project by id").
HasResponseModel(http.StatusOK, rest.ModelOf[types.Project]()). HasResponseModel(http.StatusOK, rest.ModelOf[ent.Project]()).
HasResponseModel(http.StatusBadRequest, rest.ModelOf[string]()). HasResponseModel(http.StatusBadRequest, rest.ModelOf[string]()).
HasResponseModel(http.StatusUnprocessableEntity, rest.ModelOf[respond.Error]()) HasResponseModel(http.StatusUnprocessableEntity, rest.ModelOf[respond.Error]())
api.Get("/projects"). api.Get("/projects").
HasDescription("Get projects"). HasDescription("Get projects").
HasResponseModel(http.StatusOK, rest.ModelOf[[]types.Project]()). HasResponseModel(http.StatusOK, rest.ModelOf[[]ent.Project]()).
HasResponseModel(http.StatusUnprocessableEntity, rest.ModelOf[respond.Error]()) HasResponseModel(http.StatusUnprocessableEntity, rest.ModelOf[respond.Error]())
} }

View File

@ -5,6 +5,7 @@ import (
"github.com/a-h/rest" "github.com/a-h/rest"
"net/http" "net/http"
"portfolio/api/types" "portfolio/api/types"
"portfolio/database/ent"
) )
func RegisterUserEndpoints() { func RegisterUserEndpoints() {
@ -14,14 +15,14 @@ func RegisterUserEndpoints() {
Regexp: `\d+`, Regexp: `\d+`,
}). }).
HasDescription("Get user by uid."). HasDescription("Get user by uid.").
HasResponseModel(http.StatusOK, rest.ModelOf[types.User]()). HasResponseModel(http.StatusOK, rest.ModelOf[ent.User]()).
HasResponseModel(http.StatusBadRequest, rest.ModelOf[string]()). HasResponseModel(http.StatusBadRequest, rest.ModelOf[string]()).
HasResponseModel(http.StatusInternalServerError, rest.ModelOf[respond.Error]()). HasResponseModel(http.StatusInternalServerError, rest.ModelOf[respond.Error]()).
HasResponseModel(http.StatusUnprocessableEntity, rest.ModelOf[respond.Error]()) HasResponseModel(http.StatusUnprocessableEntity, rest.ModelOf[respond.Error]())
api.Post("/register"). api.Post("/register").
HasDescription("Register."). HasDescription("Register.").
HasRequestModel(rest.ModelOf[types.User]()). HasRequestModel(rest.ModelOf[ent.User]()).
HasResponseModel(http.StatusCreated, rest.ModelOf[string]()). HasResponseModel(http.StatusCreated, rest.ModelOf[string]()).
HasResponseModel(http.StatusBadRequest, rest.ModelOf[string]()). HasResponseModel(http.StatusBadRequest, rest.ModelOf[string]()).
HasResponseModel(http.StatusInternalServerError, rest.ModelOf[respond.Error]()). HasResponseModel(http.StatusInternalServerError, rest.ModelOf[respond.Error]()).

View File

@ -6,22 +6,26 @@ import (
"net/http" "net/http"
"portfolio/api/service/bcrypt" "portfolio/api/service/bcrypt"
"portfolio/api/service/jwt" "portfolio/api/service/jwt"
"portfolio/api/types" "portfolio/database/ent"
"portfolio/database/query" "portfolio/database/query"
"time" "time"
) )
func Login(w http.ResponseWriter, r *http.Request) { func Login(w http.ResponseWriter, r *http.Request) {
var u *types.LoginUser var u *ent.User
if r.Header.Get("HX-Request") == "true" { isHtmx := r.Header.Get("HX-Request")
u = handleHtmxLogin(r)
if isHtmx == "true" {
u = &ent.User{
Email: r.PostFormValue("email"),
Password: r.PostFormValue("password"),
}
} else { } else {
u = handleHttpLogin(w, r, u) err := json.NewDecoder(r.Body).Decode(&u)
} if err != nil {
InternalServerErrorHandler(w, err)
if u == nil { }
return
} }
User, err := query.GetLogin(context.Background(), u) User, err := query.GetLogin(context.Background(), u)
@ -30,41 +34,34 @@ func Login(w http.ResponseWriter, r *http.Request) {
return return
} }
if !bcrypt.CheckPasswordHash(u.Password, User.Password) { if bcrypt.CheckPasswordHash(u.Password, User.Password) {
jwtToken := jwt.CreateUserJWT(User.Name, User.ID, string(User.Role))
if jwtToken != "" {
cookie := &http.Cookie{Name: "jwt",
Value: jwtToken,
//HttpOnly: true,
//Secure: true,
SameSite: http.SameSiteLaxMode,
Expires: time.Now().Add(24 * time.Hour),
}
http.SetCookie(w, cookie)
w.WriteHeader(http.StatusOK)
_, err = w.Write([]byte("login success"))
return
} else {
InternalServerErrorHandler(w, err)
return
}
} else {
UnauthorizedHandler(w) UnauthorizedHandler(w)
return return
} }
jwtToken := jwt.CreateUserJWT(User.Name, User.ID, string(User.Role))
cookie := &http.Cookie{
Name: "jwt",
Value: jwtToken,
HttpOnly: true,
Secure: true,
SameSite: http.SameSiteLaxMode,
Expires: time.Now().Add(24 * time.Hour),
}
http.SetCookie(w, cookie)
w.WriteHeader(http.StatusOK)
_, err = w.Write([]byte("login success"))
}
func handleHtmxLogin(r *http.Request) *types.LoginUser {
return &types.LoginUser{
Email: r.PostFormValue("email"),
Password: r.PostFormValue("password"),
}
}
func handleHttpLogin(w http.ResponseWriter, r *http.Request, u *types.LoginUser) *types.LoginUser {
if err := json.NewDecoder(r.Body).Decode(&u); err != nil {
InternalServerErrorHandler(w, err)
return nil
}
return u
} }
func CanEdit(w http.ResponseWriter, r *http.Request) { func CanEdit(w http.ResponseWriter, r *http.Request) {
@ -73,12 +70,14 @@ func CanEdit(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write([]byte("")) w.Write([]byte(""))
return
} }
if audience == "owner" || audience == "admin" { if audience == "owner" || audience == "visitor" {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write([]byte("<button class=\"button is-link\">Edit</button>")) w.Write([]byte("<button class=\"button is-link\">Edit</button>"))
} else { } else {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write([]byte("")) w.Write([]byte(""))
} }
return
} }

View File

@ -1,39 +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) {
log.Println("unauthorized") func BadRequestHandler(w http.ResponseWriter) {
setError(w, http.StatusUnauthorized, "Unauthorized") w.WriteHeader(http.StatusBadRequest)
} _, err := w.Write([]byte("400 Bad Request"))
if err != nil {
func NotImplementedHandler(w http.ResponseWriter) { return
setError(w, http.StatusNotImplemented, "WORK IN PROGRESS") }
} }
func setError(w http.ResponseWriter, httpStatus int, errorMessage string) { func UnprocessableEntityHandler(w http.ResponseWriter, err error) {
w.WriteHeader(httpStatus) w.WriteHeader(http.StatusUnprocessableEntity) //set http status
if _, err := w.Write([]byte(errorMessage)); err != nil { _, err = w.Write([]byte(err.Error())) //set response message
log.Println(err) 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

@ -4,13 +4,11 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"net/http" "net/http"
"os"
"portfolio/api/service/jwt" "portfolio/api/service/jwt"
"portfolio/api/service/parse" "portfolio/api/service/parse"
"portfolio/database/ent" "portfolio/database/ent"
"portfolio/database/query" "portfolio/database/query"
"strconv" "strconv"
"time"
) )
func CreateProjectHandler(w http.ResponseWriter, r *http.Request) { func CreateProjectHandler(w http.ResponseWriter, r *http.Request) {
@ -23,12 +21,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 +36,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 +47,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 +55,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 +70,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 +107,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 +131,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,34 +147,8 @@ 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)
return
}
}
func GetProjectsBackupHandler(w http.ResponseWriter, r *http.Request) {
p, err := query.GetProjects(context.Background())
if err != nil { if err != nil {
UnprocessableEntityHandler(w, err)
return
}
w.Header().Set("Content-Type", "application/json")
backup, _ := json.Marshal(p)
if err = os.WriteFile(
"/web/assets/json/backup-"+strconv.Itoa(int(time.Now().Unix()))+".json",
backup,
0644,
); err != nil {
UnprocessableEntityHandler(w, err)
return
}
if err = json.NewEncoder(w).Encode(p); err != nil {
InternalServerErrorHandler(w, err)
return return
} }
} }

View File

@ -6,28 +6,30 @@ import (
"net/http" "net/http"
"portfolio/api/service/bcrypt" "portfolio/api/service/bcrypt"
"portfolio/api/service/validate" "portfolio/api/service/validate"
"portfolio/api/types" "portfolio/database/ent"
"portfolio/database/ent/user"
"portfolio/database/query" "portfolio/database/query"
"strconv" "strconv"
) )
func CreateUserHandler(w http.ResponseWriter, r *http.Request) { func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
var u *types.RegisterUser var u *ent.User
if r.Header.Get("HX-Request") == "true" { isHtmx := r.Header.Get("HX-Request")
u = &types.RegisterUser{
Name: r.PostFormValue("name"), if isHtmx == "true" {
Password: r.PostFormValue("password"), u = &ent.User{
Email: r.PostFormValue("email"), Name: r.PostFormValue("name"),
//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
} }
} }
if !validate.UserIsValid(u) { if !validate.UserIsValid(u) {
BadRequestHandler(w) BadRequestHandler(w)
return return
@ -36,13 +38,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) {
@ -60,7 +63,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,10 +1,10 @@
package validate package validate
import ( import (
"portfolio/api/types" "portfolio/database/ent"
) )
func UserIsValid(u *types.RegisterUser) bool { func UserIsValid(u *ent.User) bool {
if len(u.Name) > 0 && if len(u.Name) > 0 &&
len(u.Email) > 0 && len(u.Email) > 0 &&
len(u.Password) > 0 { len(u.Password) > 0 {

View File

@ -1,10 +0,0 @@
package types
type Project struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
URL string `json:"url,omitempty"`
ImageURL string `json:"image_url,omitempty"`
DocURL string `json:"doc_url,omitempty"`
}

View File

@ -1,28 +1,10 @@
package types package types
import (
"portfolio/database/ent/user"
)
type Username struct { type Username struct {
Name string Name string
} }
type LoginUser struct { type LoginUser struct {
Email string `json:"email,omitempty"` Email string
Password string `json:"password,omitempty"` Password string
}
type RegisterUser struct {
Name string `json:"name,omitempty"`
Email string `json:"email,omitempty"`
Password string `json:"password,omitempty"`
}
type User struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Email string `json:"email,omitempty"`
Password string `json:"-"`
Role user.Role `json:"role,omitempty"`
} }

View File

@ -2,12 +2,6 @@ FROM golang:latest as openApiGen
ADD . . ADD . .
# Download and install any required dependencies
RUN go mod download
# Build the Go app
RUN go build .
RUN go run ./api/docs/openAPI RUN go run ./api/docs/openAPI
FROM registry.jetbrains.team/p/writerside/builder/writerside-builder:241.15989 as build FROM registry.jetbrains.team/p/writerside/builder/writerside-builder:241.15989 as build

View File

@ -1,539 +1,19 @@
{ {
"components": { "components": {},
"schemas": {
"Error": {
"properties": {
"message": {
"type": "string"
},
"statusCode": {
"type": "integer"
}
},
"required": [
"message",
"statusCode"
],
"type": "object"
},
"portfolio_api_types_LoginUser": {
"properties": {
"email": {
"type": "string"
},
"password": {
"type": "string"
}
},
"type": "object"
},
"portfolio_api_types_Project": {
"properties": {
"description": {
"type": "string"
},
"doc_url": {
"type": "string"
},
"id": {
"type": "integer"
},
"image_url": {
"type": "string"
},
"name": {
"type": "string"
},
"url": {
"type": "string"
}
},
"type": "object"
},
"portfolio_api_types_User": {
"properties": {
"-": {
"type": "string"
},
"email": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"role": {
"type": "string"
}
},
"required": [
"-"
],
"type": "object"
}
}
},
"info": { "info": {
"title": "portfolio", "title": "portfolio",
"version": "0.0.0" "version": "0.0.0"
}, },
"openapi": "3.0.0", "openapi": "3.0.0",
"paths": { "paths": {
"/check": { "/nfc/{uid}": {
"get": { "get": {
"description": "check for user jwt cookie", "description": "Get nfc data by uid.",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"default": {
"description": ""
}
}
}
},
"/htmx/canEdit": {
"get": {
"description": "check if user is allowed to edit",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
},
"default": {
"description": ""
}
}
}
},
"/login": {
"post": {
"description": "Login.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/portfolio_api_types_LoginUser"
}
}
}
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
},
"401": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"default": {
"description": ""
}
}
}
},
"/project": {
"post": {
"description": "Create project",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
},
"401": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"default": {
"description": ""
}
}
}
},
"/project/{id}": {
"get": {
"description": "Get project by id",
"parameters": [
{
"description": "id of the project",
"in": "path",
"name": "id",
"required": true,
"schema": {
"pattern": "\\d+",
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/portfolio_api_types_Project"
}
}
},
"description": ""
},
"400": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"default": {
"description": ""
}
}
},
"patch": {
"description": "Update project by id",
"parameters": [
{
"description": "id of the project",
"in": "path",
"name": "id",
"required": true,
"schema": {
"pattern": "\\d+",
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/portfolio_api_types_Project"
}
}
}
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
},
"400": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
},
"401": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"default": {
"description": ""
}
}
}
},
"/projects": {
"get": {
"description": "Get projects",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/portfolio_api_types_Project"
},
"nullable": true,
"type": "array"
}
}
},
"description": ""
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"default": {
"description": ""
}
}
},
"patch": {
"description": "Update projects WIP",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/portfolio_api_types_Project"
},
"nullable": true,
"type": "array"
}
}
},
"description": ""
},
"401": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"default": {
"description": ""
}
}
}
},
"/register": {
"post": {
"description": "Register.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/portfolio_api_types_User"
}
}
}
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
},
"400": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"description": ""
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"default": {
"description": ""
}
}
}
},
"/user/{uid}": {
"get": {
"description": "Get user by uid.",
"parameters": [ "parameters": [
{ {
"description": "id of the user", "description": "id of the user",
"in": "path", "in": "path",
"name": "id", "name": "uid",
"required": true, "required": true,
"schema": { "schema": {
"pattern": "\\d+", "pattern": "\\d+",
@ -543,16 +23,6 @@
], ],
"responses": { "responses": {
"200": { "200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/portfolio_api_types_User"
}
}
},
"description": ""
},
"400": {
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
@ -562,26 +32,6 @@
}, },
"description": "" "description": ""
}, },
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"500": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": ""
},
"default": { "default": {
"description": "" "description": ""
} }
@ -590,11 +40,3 @@
} }
} }
} }
: {
"description": ""
}
}
}
}
}
}

View File

@ -7,16 +7,8 @@
start-page="test.md"> start-page="test.md">
<toc-element topic="test.md"/> <toc-element topic="test.md"/>
<toc-element topic="API_Reference.topic"> <toc-element topic="API_Reference.md">
<toc-element topic="user_uid_GET.topic"/> <toc-element topic="Schemas.md"/>
<toc-element topic="register_POST.topic"/> <toc-element topic="nfc_uid_GET.md"/>
<toc-element topic="projects_PATCH.topic"/>
<toc-element topic="projects_GET.topic"/>
<toc-element topic="project_id_PATCH.topic"/>
<toc-element topic="project_id_GET.topic"/>
<toc-element topic="project_POST.topic"/>
<toc-element topic="login_POST.topic"/>
<toc-element topic="htmx_canEdit_GET.topic"/>
<toc-element topic="check_GET.topic"/>
</toc-element> </toc-element>
</instance-profile> </instance-profile>

View File

@ -18,16 +18,4 @@
<description>Created after removal of "About portfolio" from portfolio</description> <description>Created after removal of "About portfolio" from portfolio</description>
<accepts>starter-topic.html</accepts> <accepts>starter-topic.html</accepts>
</rule> </rule>
<rule id="197e2e0d">
<description>Created after removal of "Schemas" from portfolio</description>
<accepts>Schemas.html</accepts>
</rule>
<rule id="32e9b651">
<description>Created after removal of "/nfc/{uid} GET" from portfolio</description>
<accepts>nfc_uid_GET.html</accepts>
</rule>
<rule id="2eac3350">
<description>Created after removal of "API Reference" from portfolio</description>
<accepts>API_Reference.html</accepts>
</rule>
</rules> </rules>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
title="API Reference" id="API_Reference">
<p>Start typing here...</p>
</topic>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
title="/check GET" id="check_GET">
<api-endpoint openapi-path="../../openApi.json" method="GET" endpoint="/check"/>
</topic>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
title="/htmx/canEdit GET" id="htmx_canEdit_GET">
<api-endpoint openapi-path="../../openApi.json" method="GET" endpoint="/htmx/canEdit"/>
</topic>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
title="/login POST" id="login_POST">
<api-endpoint openapi-path="../../openApi.json" method="POST" endpoint="/login"/>
</topic>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
title="/project POST" id="project_POST">
<api-endpoint openapi-path="../../openApi.json" method="POST" endpoint="/project"/>
</topic>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
title="/project/{id} GET" id="project_id_GET">
<api-endpoint openapi-path="../../openApi.json" method="GET" endpoint="/project/{id}"/>
</topic>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
title="/project/{id} PATCH" id="project_id_PATCH">
<api-endpoint openapi-path="../../openApi.json" method="PATCH" endpoint="/project/{id}"/>
</topic>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
title="/projects GET" id="projects_GET">
<api-endpoint openapi-path="../../openApi.json" method="GET" endpoint="/projects"/>
</topic>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
title="/projects PATCH" id="projects_PATCH">
<api-endpoint openapi-path="../../openApi.json" method="PATCH" endpoint="/projects"/>
</topic>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
title="/register POST" id="register_POST">
<api-endpoint openapi-path="../../openApi.json" method="POST" endpoint="/register"/>
</topic>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE topic
SYSTEM "https://resources.jetbrains.com/writerside/1.0/xhtml-entities.dtd">
<topic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd"
title="/user/{uid} GET" id="user_uid_GET">
<api-endpoint openapi-path="../../openApi.json" method="GET" endpoint="/user/{uid}"/>
</topic>

View File

@ -14,7 +14,6 @@ import (
var Client *ent.Client var Client *ent.Client
func DB() { func DB() {
log.Println("Connecting to database")
err := *new(error) err := *new(error)
port, parseError := strconv.ParseInt(os.Getenv("POSTGRES_PORT"), 10, 32) port, parseError := strconv.ParseInt(os.Getenv("POSTGRES_PORT"), 10, 32)

View File

@ -71,7 +71,7 @@ var (
columnCheck sql.ColumnCheck columnCheck sql.ColumnCheck
) )
// checkColumn checks if the column exists in the given table. // columnChecker checks if the column exists in the given table.
func checkColumn(table, column string) error { func checkColumn(table, column string) error {
initCheck.Do(func() { initCheck.Do(func() {
columnCheck = sql.NewColumnCheck(map[string]func(string) bool{ columnCheck = sql.NewColumnCheck(map[string]func(string) bool{

View File

@ -4,7 +4,6 @@ package enttest
import ( import (
"context" "context"
"portfolio/database/ent" "portfolio/database/ent"
// required by schema hooks. // required by schema hooks.
_ "portfolio/database/ent/runtime" _ "portfolio/database/ent/runtime"

View File

@ -12,7 +12,6 @@ import (
"portfolio/database/ent/team" "portfolio/database/ent/team"
"portfolio/database/ent/user" "portfolio/database/ent/user"
"entgo.io/ent"
"entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field" "entgo.io/ent/schema/field"
@ -110,7 +109,7 @@ func (pq *ProjectQuery) QueryTeams() *TeamQuery {
// First returns the first Project entity from the query. // First returns the first Project entity from the query.
// Returns a *NotFoundError when no Project was found. // Returns a *NotFoundError when no Project was found.
func (pq *ProjectQuery) First(ctx context.Context) (*Project, error) { func (pq *ProjectQuery) First(ctx context.Context) (*Project, error) {
nodes, err := pq.Limit(1).All(setContextOp(ctx, pq.ctx, ent.OpQueryFirst)) nodes, err := pq.Limit(1).All(setContextOp(ctx, pq.ctx, "First"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -133,7 +132,7 @@ func (pq *ProjectQuery) FirstX(ctx context.Context) *Project {
// Returns a *NotFoundError when no Project ID was found. // Returns a *NotFoundError when no Project ID was found.
func (pq *ProjectQuery) FirstID(ctx context.Context) (id int, err error) { func (pq *ProjectQuery) FirstID(ctx context.Context) (id int, err error) {
var ids []int var ids []int
if ids, err = pq.Limit(1).IDs(setContextOp(ctx, pq.ctx, ent.OpQueryFirstID)); err != nil { if ids, err = pq.Limit(1).IDs(setContextOp(ctx, pq.ctx, "FirstID")); err != nil {
return return
} }
if len(ids) == 0 { if len(ids) == 0 {
@ -156,7 +155,7 @@ func (pq *ProjectQuery) FirstIDX(ctx context.Context) int {
// Returns a *NotSingularError when more than one Project entity is found. // Returns a *NotSingularError when more than one Project entity is found.
// Returns a *NotFoundError when no Project entities are found. // Returns a *NotFoundError when no Project entities are found.
func (pq *ProjectQuery) Only(ctx context.Context) (*Project, error) { func (pq *ProjectQuery) Only(ctx context.Context) (*Project, error) {
nodes, err := pq.Limit(2).All(setContextOp(ctx, pq.ctx, ent.OpQueryOnly)) nodes, err := pq.Limit(2).All(setContextOp(ctx, pq.ctx, "Only"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -184,7 +183,7 @@ func (pq *ProjectQuery) OnlyX(ctx context.Context) *Project {
// Returns a *NotFoundError when no entities are found. // Returns a *NotFoundError when no entities are found.
func (pq *ProjectQuery) OnlyID(ctx context.Context) (id int, err error) { func (pq *ProjectQuery) OnlyID(ctx context.Context) (id int, err error) {
var ids []int var ids []int
if ids, err = pq.Limit(2).IDs(setContextOp(ctx, pq.ctx, ent.OpQueryOnlyID)); err != nil { if ids, err = pq.Limit(2).IDs(setContextOp(ctx, pq.ctx, "OnlyID")); err != nil {
return return
} }
switch len(ids) { switch len(ids) {
@ -209,7 +208,7 @@ func (pq *ProjectQuery) OnlyIDX(ctx context.Context) int {
// All executes the query and returns a list of Projects. // All executes the query and returns a list of Projects.
func (pq *ProjectQuery) All(ctx context.Context) ([]*Project, error) { func (pq *ProjectQuery) All(ctx context.Context) ([]*Project, error) {
ctx = setContextOp(ctx, pq.ctx, ent.OpQueryAll) ctx = setContextOp(ctx, pq.ctx, "All")
if err := pq.prepareQuery(ctx); err != nil { if err := pq.prepareQuery(ctx); err != nil {
return nil, err return nil, err
} }
@ -231,7 +230,7 @@ func (pq *ProjectQuery) IDs(ctx context.Context) (ids []int, err error) {
if pq.ctx.Unique == nil && pq.path != nil { if pq.ctx.Unique == nil && pq.path != nil {
pq.Unique(true) pq.Unique(true)
} }
ctx = setContextOp(ctx, pq.ctx, ent.OpQueryIDs) ctx = setContextOp(ctx, pq.ctx, "IDs")
if err = pq.Select(project.FieldID).Scan(ctx, &ids); err != nil { if err = pq.Select(project.FieldID).Scan(ctx, &ids); err != nil {
return nil, err return nil, err
} }
@ -249,7 +248,7 @@ func (pq *ProjectQuery) IDsX(ctx context.Context) []int {
// Count returns the count of the given query. // Count returns the count of the given query.
func (pq *ProjectQuery) Count(ctx context.Context) (int, error) { func (pq *ProjectQuery) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, pq.ctx, ent.OpQueryCount) ctx = setContextOp(ctx, pq.ctx, "Count")
if err := pq.prepareQuery(ctx); err != nil { if err := pq.prepareQuery(ctx); err != nil {
return 0, err return 0, err
} }
@ -267,7 +266,7 @@ func (pq *ProjectQuery) CountX(ctx context.Context) int {
// Exist returns true if the query has elements in the graph. // Exist returns true if the query has elements in the graph.
func (pq *ProjectQuery) Exist(ctx context.Context) (bool, error) { func (pq *ProjectQuery) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, pq.ctx, ent.OpQueryExist) ctx = setContextOp(ctx, pq.ctx, "Exist")
switch _, err := pq.FirstID(ctx); { switch _, err := pq.FirstID(ctx); {
case IsNotFound(err): case IsNotFound(err):
return false, nil return false, nil
@ -665,7 +664,7 @@ func (pgb *ProjectGroupBy) Aggregate(fns ...AggregateFunc) *ProjectGroupBy {
// Scan applies the selector query and scans the result into the given value. // Scan applies the selector query and scans the result into the given value.
func (pgb *ProjectGroupBy) Scan(ctx context.Context, v any) error { func (pgb *ProjectGroupBy) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, pgb.build.ctx, ent.OpQueryGroupBy) ctx = setContextOp(ctx, pgb.build.ctx, "GroupBy")
if err := pgb.build.prepareQuery(ctx); err != nil { if err := pgb.build.prepareQuery(ctx); err != nil {
return err return err
} }
@ -713,7 +712,7 @@ func (ps *ProjectSelect) Aggregate(fns ...AggregateFunc) *ProjectSelect {
// Scan applies the selector query and scans the result into the given value. // Scan applies the selector query and scans the result into the given value.
func (ps *ProjectSelect) Scan(ctx context.Context, v any) error { func (ps *ProjectSelect) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, ps.ctx, ent.OpQuerySelect) ctx = setContextOp(ctx, ps.ctx, "Select")
if err := ps.prepareQuery(ctx); err != nil { if err := ps.prepareQuery(ctx); err != nil {
return err return err
} }

View File

@ -5,6 +5,6 @@ package runtime
// The schema-stitching logic is generated in portfolio/database/ent/runtime.go // The schema-stitching logic is generated in portfolio/database/ent/runtime.go
const ( const (
Version = "v0.14.4" // Version of ent codegen. Version = "v0.13.1" // Version of ent codegen.
Sum = "h1:/DhDraSLXIkBhyiVoJeSshr4ZYi7femzhj6/TckzZuI=" // Sum of ent codegen. Sum = "h1:uD8QwN1h6SNphdCCzmkMN3feSUzNnVvV/WIkHKMbzOE=" // Sum of ent codegen.
) )

View File

@ -12,7 +12,6 @@ import (
"portfolio/database/ent/team" "portfolio/database/ent/team"
"portfolio/database/ent/user" "portfolio/database/ent/user"
"entgo.io/ent"
"entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field" "entgo.io/ent/schema/field"
@ -110,7 +109,7 @@ func (tq *TeamQuery) QueryUsers() *UserQuery {
// First returns the first Team entity from the query. // First returns the first Team entity from the query.
// Returns a *NotFoundError when no Team was found. // Returns a *NotFoundError when no Team was found.
func (tq *TeamQuery) First(ctx context.Context) (*Team, error) { func (tq *TeamQuery) First(ctx context.Context) (*Team, error) {
nodes, err := tq.Limit(1).All(setContextOp(ctx, tq.ctx, ent.OpQueryFirst)) nodes, err := tq.Limit(1).All(setContextOp(ctx, tq.ctx, "First"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -133,7 +132,7 @@ func (tq *TeamQuery) FirstX(ctx context.Context) *Team {
// Returns a *NotFoundError when no Team ID was found. // Returns a *NotFoundError when no Team ID was found.
func (tq *TeamQuery) FirstID(ctx context.Context) (id int, err error) { func (tq *TeamQuery) FirstID(ctx context.Context) (id int, err error) {
var ids []int var ids []int
if ids, err = tq.Limit(1).IDs(setContextOp(ctx, tq.ctx, ent.OpQueryFirstID)); err != nil { if ids, err = tq.Limit(1).IDs(setContextOp(ctx, tq.ctx, "FirstID")); err != nil {
return return
} }
if len(ids) == 0 { if len(ids) == 0 {
@ -156,7 +155,7 @@ func (tq *TeamQuery) FirstIDX(ctx context.Context) int {
// Returns a *NotSingularError when more than one Team entity is found. // Returns a *NotSingularError when more than one Team entity is found.
// Returns a *NotFoundError when no Team entities are found. // Returns a *NotFoundError when no Team entities are found.
func (tq *TeamQuery) Only(ctx context.Context) (*Team, error) { func (tq *TeamQuery) Only(ctx context.Context) (*Team, error) {
nodes, err := tq.Limit(2).All(setContextOp(ctx, tq.ctx, ent.OpQueryOnly)) nodes, err := tq.Limit(2).All(setContextOp(ctx, tq.ctx, "Only"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -184,7 +183,7 @@ func (tq *TeamQuery) OnlyX(ctx context.Context) *Team {
// Returns a *NotFoundError when no entities are found. // Returns a *NotFoundError when no entities are found.
func (tq *TeamQuery) OnlyID(ctx context.Context) (id int, err error) { func (tq *TeamQuery) OnlyID(ctx context.Context) (id int, err error) {
var ids []int var ids []int
if ids, err = tq.Limit(2).IDs(setContextOp(ctx, tq.ctx, ent.OpQueryOnlyID)); err != nil { if ids, err = tq.Limit(2).IDs(setContextOp(ctx, tq.ctx, "OnlyID")); err != nil {
return return
} }
switch len(ids) { switch len(ids) {
@ -209,7 +208,7 @@ func (tq *TeamQuery) OnlyIDX(ctx context.Context) int {
// All executes the query and returns a list of Teams. // All executes the query and returns a list of Teams.
func (tq *TeamQuery) All(ctx context.Context) ([]*Team, error) { func (tq *TeamQuery) All(ctx context.Context) ([]*Team, error) {
ctx = setContextOp(ctx, tq.ctx, ent.OpQueryAll) ctx = setContextOp(ctx, tq.ctx, "All")
if err := tq.prepareQuery(ctx); err != nil { if err := tq.prepareQuery(ctx); err != nil {
return nil, err return nil, err
} }
@ -231,7 +230,7 @@ func (tq *TeamQuery) IDs(ctx context.Context) (ids []int, err error) {
if tq.ctx.Unique == nil && tq.path != nil { if tq.ctx.Unique == nil && tq.path != nil {
tq.Unique(true) tq.Unique(true)
} }
ctx = setContextOp(ctx, tq.ctx, ent.OpQueryIDs) ctx = setContextOp(ctx, tq.ctx, "IDs")
if err = tq.Select(team.FieldID).Scan(ctx, &ids); err != nil { if err = tq.Select(team.FieldID).Scan(ctx, &ids); err != nil {
return nil, err return nil, err
} }
@ -249,7 +248,7 @@ func (tq *TeamQuery) IDsX(ctx context.Context) []int {
// Count returns the count of the given query. // Count returns the count of the given query.
func (tq *TeamQuery) Count(ctx context.Context) (int, error) { func (tq *TeamQuery) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, tq.ctx, ent.OpQueryCount) ctx = setContextOp(ctx, tq.ctx, "Count")
if err := tq.prepareQuery(ctx); err != nil { if err := tq.prepareQuery(ctx); err != nil {
return 0, err return 0, err
} }
@ -267,7 +266,7 @@ func (tq *TeamQuery) CountX(ctx context.Context) int {
// Exist returns true if the query has elements in the graph. // Exist returns true if the query has elements in the graph.
func (tq *TeamQuery) Exist(ctx context.Context) (bool, error) { func (tq *TeamQuery) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, tq.ctx, ent.OpQueryExist) ctx = setContextOp(ctx, tq.ctx, "Exist")
switch _, err := tq.FirstID(ctx); { switch _, err := tq.FirstID(ctx); {
case IsNotFound(err): case IsNotFound(err):
return false, nil return false, nil
@ -665,7 +664,7 @@ func (tgb *TeamGroupBy) Aggregate(fns ...AggregateFunc) *TeamGroupBy {
// Scan applies the selector query and scans the result into the given value. // Scan applies the selector query and scans the result into the given value.
func (tgb *TeamGroupBy) Scan(ctx context.Context, v any) error { func (tgb *TeamGroupBy) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, tgb.build.ctx, ent.OpQueryGroupBy) ctx = setContextOp(ctx, tgb.build.ctx, "GroupBy")
if err := tgb.build.prepareQuery(ctx); err != nil { if err := tgb.build.prepareQuery(ctx); err != nil {
return err return err
} }
@ -713,7 +712,7 @@ func (ts *TeamSelect) Aggregate(fns ...AggregateFunc) *TeamSelect {
// Scan applies the selector query and scans the result into the given value. // Scan applies the selector query and scans the result into the given value.
func (ts *TeamSelect) Scan(ctx context.Context, v any) error { func (ts *TeamSelect) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, ts.ctx, ent.OpQuerySelect) ctx = setContextOp(ctx, ts.ctx, "Select")
if err := ts.prepareQuery(ctx); err != nil { if err := ts.prepareQuery(ctx); err != nil {
return err return err
} }

View File

@ -12,7 +12,6 @@ import (
"portfolio/database/ent/team" "portfolio/database/ent/team"
"portfolio/database/ent/user" "portfolio/database/ent/user"
"entgo.io/ent"
"entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field" "entgo.io/ent/schema/field"
@ -110,7 +109,7 @@ func (uq *UserQuery) QueryProjects() *ProjectQuery {
// First returns the first User entity from the query. // First returns the first User entity from the query.
// Returns a *NotFoundError when no User was found. // Returns a *NotFoundError when no User was found.
func (uq *UserQuery) First(ctx context.Context) (*User, error) { func (uq *UserQuery) First(ctx context.Context) (*User, error) {
nodes, err := uq.Limit(1).All(setContextOp(ctx, uq.ctx, ent.OpQueryFirst)) nodes, err := uq.Limit(1).All(setContextOp(ctx, uq.ctx, "First"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -133,7 +132,7 @@ func (uq *UserQuery) FirstX(ctx context.Context) *User {
// Returns a *NotFoundError when no User ID was found. // Returns a *NotFoundError when no User ID was found.
func (uq *UserQuery) FirstID(ctx context.Context) (id int, err error) { func (uq *UserQuery) FirstID(ctx context.Context) (id int, err error) {
var ids []int var ids []int
if ids, err = uq.Limit(1).IDs(setContextOp(ctx, uq.ctx, ent.OpQueryFirstID)); err != nil { if ids, err = uq.Limit(1).IDs(setContextOp(ctx, uq.ctx, "FirstID")); err != nil {
return return
} }
if len(ids) == 0 { if len(ids) == 0 {
@ -156,7 +155,7 @@ func (uq *UserQuery) FirstIDX(ctx context.Context) int {
// Returns a *NotSingularError when more than one User entity is found. // Returns a *NotSingularError when more than one User entity is found.
// Returns a *NotFoundError when no User entities are found. // Returns a *NotFoundError when no User entities are found.
func (uq *UserQuery) Only(ctx context.Context) (*User, error) { func (uq *UserQuery) Only(ctx context.Context) (*User, error) {
nodes, err := uq.Limit(2).All(setContextOp(ctx, uq.ctx, ent.OpQueryOnly)) nodes, err := uq.Limit(2).All(setContextOp(ctx, uq.ctx, "Only"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -184,7 +183,7 @@ func (uq *UserQuery) OnlyX(ctx context.Context) *User {
// Returns a *NotFoundError when no entities are found. // Returns a *NotFoundError when no entities are found.
func (uq *UserQuery) OnlyID(ctx context.Context) (id int, err error) { func (uq *UserQuery) OnlyID(ctx context.Context) (id int, err error) {
var ids []int var ids []int
if ids, err = uq.Limit(2).IDs(setContextOp(ctx, uq.ctx, ent.OpQueryOnlyID)); err != nil { if ids, err = uq.Limit(2).IDs(setContextOp(ctx, uq.ctx, "OnlyID")); err != nil {
return return
} }
switch len(ids) { switch len(ids) {
@ -209,7 +208,7 @@ func (uq *UserQuery) OnlyIDX(ctx context.Context) int {
// All executes the query and returns a list of Users. // All executes the query and returns a list of Users.
func (uq *UserQuery) All(ctx context.Context) ([]*User, error) { func (uq *UserQuery) All(ctx context.Context) ([]*User, error) {
ctx = setContextOp(ctx, uq.ctx, ent.OpQueryAll) ctx = setContextOp(ctx, uq.ctx, "All")
if err := uq.prepareQuery(ctx); err != nil { if err := uq.prepareQuery(ctx); err != nil {
return nil, err return nil, err
} }
@ -231,7 +230,7 @@ func (uq *UserQuery) IDs(ctx context.Context) (ids []int, err error) {
if uq.ctx.Unique == nil && uq.path != nil { if uq.ctx.Unique == nil && uq.path != nil {
uq.Unique(true) uq.Unique(true)
} }
ctx = setContextOp(ctx, uq.ctx, ent.OpQueryIDs) ctx = setContextOp(ctx, uq.ctx, "IDs")
if err = uq.Select(user.FieldID).Scan(ctx, &ids); err != nil { if err = uq.Select(user.FieldID).Scan(ctx, &ids); err != nil {
return nil, err return nil, err
} }
@ -249,7 +248,7 @@ func (uq *UserQuery) IDsX(ctx context.Context) []int {
// Count returns the count of the given query. // Count returns the count of the given query.
func (uq *UserQuery) Count(ctx context.Context) (int, error) { func (uq *UserQuery) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, uq.ctx, ent.OpQueryCount) ctx = setContextOp(ctx, uq.ctx, "Count")
if err := uq.prepareQuery(ctx); err != nil { if err := uq.prepareQuery(ctx); err != nil {
return 0, err return 0, err
} }
@ -267,7 +266,7 @@ func (uq *UserQuery) CountX(ctx context.Context) int {
// Exist returns true if the query has elements in the graph. // Exist returns true if the query has elements in the graph.
func (uq *UserQuery) Exist(ctx context.Context) (bool, error) { func (uq *UserQuery) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, uq.ctx, ent.OpQueryExist) ctx = setContextOp(ctx, uq.ctx, "Exist")
switch _, err := uq.FirstID(ctx); { switch _, err := uq.FirstID(ctx); {
case IsNotFound(err): case IsNotFound(err):
return false, nil return false, nil
@ -665,7 +664,7 @@ func (ugb *UserGroupBy) Aggregate(fns ...AggregateFunc) *UserGroupBy {
// Scan applies the selector query and scans the result into the given value. // Scan applies the selector query and scans the result into the given value.
func (ugb *UserGroupBy) Scan(ctx context.Context, v any) error { func (ugb *UserGroupBy) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, ugb.build.ctx, ent.OpQueryGroupBy) ctx = setContextOp(ctx, ugb.build.ctx, "GroupBy")
if err := ugb.build.prepareQuery(ctx); err != nil { if err := ugb.build.prepareQuery(ctx); err != nil {
return err return err
} }
@ -713,7 +712,7 @@ func (us *UserSelect) Aggregate(fns ...AggregateFunc) *UserSelect {
// Scan applies the selector query and scans the result into the given value. // Scan applies the selector query and scans the result into the given value.
func (us *UserSelect) Scan(ctx context.Context, v any) error { func (us *UserSelect) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, us.ctx, ent.OpQuerySelect) ctx = setContextOp(ctx, us.ctx, "Select")
if err := us.prepareQuery(ctx); err != nil { if err := us.prepareQuery(ctx); err != nil {
return err return err
} }

View File

@ -4,13 +4,12 @@ import (
"context" "context"
"fmt" "fmt"
"log" "log"
"portfolio/api/types"
"portfolio/database" "portfolio/database"
"portfolio/database/ent" "portfolio/database/ent"
"portfolio/database/ent/user" "portfolio/database/ent/user"
) )
func GetLogin(ctx context.Context, U *types.LoginUser) (*ent.User, error) { func GetLogin(ctx context.Context, U *ent.User) (*ent.User, error) {
u, err := database.Client.User. u, err := database.Client.User.
Query(). Query().
Where(user.Email(U.Email)). Where(user.Email(U.Email)).

View File

@ -85,7 +85,6 @@ func GetFullProjects(ctx context.Context) ([]*ent.Project, error) {
func GetProjects(ctx context.Context) (ent.Projects, error) { func GetProjects(ctx context.Context) (ent.Projects, error) {
p, err := database.Client.Project.Query(). p, err := database.Client.Project.Query().
Order(ent.Asc(project.FieldID)).
All(ctx) All(ctx)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get projects: %w", err) return nil, fmt.Errorf("failed to get projects: %w", err)

View File

@ -4,7 +4,6 @@ import (
"context" "context"
"fmt" "fmt"
"log" "log"
"portfolio/api/types"
"portfolio/database" "portfolio/database"
"portfolio/database/ent" "portfolio/database/ent"
"portfolio/database/ent/user" "portfolio/database/ent/user"
@ -23,7 +22,7 @@ func GetUser(ctx context.Context, id int) (*ent.User, error) {
return u, nil return u, nil
} }
func CreateUser(ctx context.Context, user types.RegisterUser) error { func CreateUser(ctx context.Context, user ent.User) error {
_, err := database.Client.User. _, err := database.Client.User.
Create(). Create().

View File

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

38
go.mod
View File

@ -1,35 +1,31 @@
module portfolio module portfolio
go 1.24.0 go 1.22.2
require ( require (
entgo.io/ent v0.14.4 entgo.io/ent v0.13.1
github.com/delaneyj/gomponents-iconify v0.0.20241016 github.com/delaneyj/gomponents-iconify v0.0.20231025
github.com/golang-jwt/jwt/v5 v5.2.2 github.com/golang-jwt/jwt/v5 v5.2.1
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/lib/pq v1.10.9 github.com/lib/pq v1.10.9
github.com/rs/cors v1.11.1 github.com/maragudk/gomponents v0.20.2
github.com/willoma/bulma-gomponents v0.13.0 github.com/maragudk/gomponents-htmx v0.5.0
github.com/willoma/gomplements v0.8.0 github.com/rs/cors v1.11.0
golang.org/x/crypto v0.38.0 github.com/willoma/bulma-gomponents v0.11.1
maragu.dev/gomponents v1.1.0 github.com/willoma/gomplements v0.6.1
maragu.dev/gomponents-htmx v0.6.1 golang.org/x/crypto v0.23.0
) )
require ( require (
ariga.io/atlas v0.32.1 // indirect ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43 // indirect
github.com/agext/levenshtein v1.2.3 // indirect github.com/agext/levenshtein v1.2.3 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/bmatcuk/doublestar v1.3.4 // indirect github.com/go-openapi/inflect v0.19.0 // indirect
github.com/go-openapi/inflect v0.21.2 // indirect github.com/google/go-cmp v0.6.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.19.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.14.2 // indirect
github.com/zclconf/go-cty-yaml v1.1.0 // indirect golang.org/x/mod v0.17.0 // indirect
golang.org/x/mod v0.24.0 // indirect golang.org/x/text v0.15.0 // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/text v0.25.0 // indirect
golang.org/x/tools v0.33.0 // indirect
) )

66
go.sum Normal file
View File

@ -0,0 +1,66 @@
ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43 h1:GwdJbXydHCYPedeeLt4x/lrlIISQ4JTH1mRWuE5ZZ14=
ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43/go.mod h1:uj3pm+hUTVN/X5yfdBexHlZv+1Xu5u5ZbZx7+CDavNU=
entgo.io/ent v0.13.1 h1:uD8QwN1h6SNphdCCzmkMN3feSUzNnVvV/WIkHKMbzOE=
entgo.io/ent v0.13.1/go.mod h1:qCEmo+biw3ccBn9OyL4ZK5dfpwg++l1Gxwac5B1206A=
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/delaneyj/gomponents-iconify v0.0.20231025 h1:GJU/KtZGoQ7CwIumei/fNITpMk0f0p7yYz4q/AVllss=
github.com/delaneyj/gomponents-iconify v0.0.20231025/go.mod h1:ZjIP4npWKmVuJbvSjBTpzSl1QMimELl77gP/leg1bnI=
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5RPI=
github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/maragudk/gomponents v0.20.2 h1:39FhnBNNCJzqNcD9Hmvp/5xj0otweFoyvVgFG6kXoy0=
github.com/maragudk/gomponents v0.20.2/go.mod h1:nHkNnZL6ODgMBeJhrZjkMHVvNdoYsfmpKB2/hjdQ0Hg=
github.com/maragudk/gomponents-htmx v0.5.0 h1:sWtiRa72YmymgxccjTNZW3h0akKsZvnhYke9RQiS9dk=
github.com/maragudk/gomponents-htmx v0.5.0/go.mod h1:XgI7WE6ECWlyeVQ9Ix3R6aoKS4HtCSYtuQ4iH27GVDE=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po=
github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/willoma/bulma-gomponents v0.11.1 h1:l5lPRGgxkv0SCMle5SNaF7YsVODoud9hXLGsyFo9IRc=
github.com/willoma/bulma-gomponents v0.11.1/go.mod h1:1hkVH4/pPHtlPH5aIkS1pHMaerOV3SI1SDe8QXShHqA=
github.com/willoma/gomplements v0.6.1 h1:JtOVIHFnMXqloflQHafVmsvtqlpf5b+d0Uj18KqrP1k=
github.com/willoma/gomplements v0.6.1/go.mod h1:G/9prZq6jA7EZwIu0AF27HtULgAbUbOVp9oRhsunpkg=
github.com/zclconf/go-cty v1.14.2 h1:kTG7lqmBou0Zkx35r6HJHUQTvaRPr5bIAf3AoHS0izI=
github.com/zclconf/go-cty v1.14.2/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,6 +1,6 @@
go 1.24.0 go 1.22.2
use ( use (
.
api/docs/openAPI api/docs/openAPI
.
) )

86
go.work.sum Normal file
View File

@ -0,0 +1,86 @@
github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3 h1:ZSTrOEhiM5J5RFxEaFvMZVEAM1KvT1YzbEOwB2EAGjA=
github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/delaneyj/toolbelt v0.0.0-20230611200251-2df076bd1579 h1:lj+zHpYT5Xv69ZsEB6eTm1nZ/5S0NmwPip5zG8kO234=
github.com/delaneyj/toolbelt v0.0.0-20230611200251-2df076bd1579/go.mod h1:XPp3P/k7PF1+gU3tFzemCcoIlJl45pRP2uIQ96pxBDQ=
github.com/divan/num2words v0.0.0-20170904212200-57dba452f942 h1:fJ8/Lid8fF4i7Bwl7vWKvG2KeZzr3yU4qG6h/DPdXLU=
github.com/divan/num2words v0.0.0-20170904212200-57dba452f942/go.mod h1:K88GQWK1aAiPMo9q2LZwyKBfEGnge7kmVVTUcZ61HSc=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/maragudk/is v0.1.0 h1:obq9anZNmOYcaNbeT0LMyjIexdNeYTw/TLAPD/BnZHA=
github.com/maragudk/is v0.1.0/go.mod h1:W/r6+TpnISu+a88OLXQy5JQGCOhXQXXLD2e5b4xMn5c=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/smartystreets/goconvey v1.8.0 h1:Oi49ha/2MURE0WexF052Z0m+BNSGirfjg5RL+JXWq3w=
github.com/smartystreets/goconvey v1.8.0/go.mod h1:EdX8jtrTIj26jmjCOVNMVSIYAtgexqXKHOXW2Dx9JLg=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg=
k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
modernc.org/libc v1.22.3 h1:D/g6O5ftAfavceqlLOFwaZuA5KYafKwmr30A6iSqoyY=
modernc.org/libc v1.22.3/go.mod h1:MQrloYP209xa2zHome2a8HLiLm6k0UT8CoHpV74tOFw=
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/sqlite v1.21.1 h1:GyDFqNnESLOhwwDRaHGdp2jKLDzpyT/rNLglX3ZkMSU=
modernc.org/sqlite v1.21.1/go.mod h1:XwQ0wZPIh1iKb5mkvCJ3szzbhk+tykC8ZWqTRTgYRwI=
zombiezen.com/go/sqlite v0.13.0 h1:iEeyVqcm3fk5PCA8OQBhBxPnqrP4yYuVJBF+XZpSnOE=
zombiezen.com/go/sqlite v0.13.0/go.mod h1:Ht/5Rg3Ae2hoyh1I7gbWtWAl89CNocfqeb/aAMTkJr4=

39
main.go
View File

@ -1,50 +1,30 @@
package main package main
import ( import (
"fmt"
"github.com/joho/godotenv" "github.com/joho/godotenv"
"github.com/rs/cors" "github.com/rs/cors"
"log" "log"
"net/http" "net/http"
"os"
"os/signal"
"portfolio/api" "portfolio/api"
"portfolio/database" "portfolio/database"
"portfolio/web" "portfolio/web"
"syscall"
) )
func main() { func main() {
log.Println("Starting application") // 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
} }
// Catch interrupt
cmd := make(chan os.Signal, 1)
signal.Notify(cmd, os.Interrupt, syscall.SIGTERM)
go func() {
<-cmd
log.Println("Shutting down application")
os.Exit(0)
}()
//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
webPort := os.Getenv("WEB_PORT") go http.ListenAndServe(":4000", cors.AllowAll().Handler(webMux))
log.Printf("Starting API port [%s]", webPort)
go func() {
err := http.ListenAndServe(fmt.Sprintf(":%s", webPort), 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"},
@ -56,18 +36,13 @@ func main() {
http.MethodPatch, http.MethodPatch,
http.MethodDelete, http.MethodDelete,
}, },
AllowedHeaders: []string{"Authorization", "Content-Type", "*"}, AllowedHeaders: []string{"*"},
AllowCredentials: true, AllowCredentials: true,
Debug: true,
}) })
//init api routes //init api routes
apiMux := api.Routes() apiMux := api.ApiRoutes()
//run api server //run api server
apiPort := os.Getenv("API_PORT") http.ListenAndServe(":4001", c.Handler(apiMux))
log.Printf("Starting API port [%s]", apiPort)
err = http.ListenAndServe(fmt.Sprintf(":%s", apiPort), c.Handler(apiMux))
if err != nil {
log.Fatal(err)
}
} }

Binary file not shown.

View File

@ -1,10 +1,10 @@
package components package components
import ( import (
g "github.com/maragudk/gomponents"
hx "github.com/maragudk/gomponents-htmx"
. "github.com/maragudk/gomponents/html"
b "github.com/willoma/bulma-gomponents" b "github.com/willoma/bulma-gomponents"
g "maragu.dev/gomponents"
hx "maragu.dev/gomponents-htmx"
. "maragu.dev/gomponents/html"
) )
func Edit() g.Node { func Edit() g.Node {

View File

@ -2,9 +2,9 @@ package components
import ( import (
"github.com/delaneyj/gomponents-iconify/iconify/mdi" "github.com/delaneyj/gomponents-iconify/iconify/mdi"
g "github.com/maragudk/gomponents"
b "github.com/willoma/bulma-gomponents" b "github.com/willoma/bulma-gomponents"
e "github.com/willoma/gomplements" e "github.com/willoma/gomplements"
g "maragu.dev/gomponents"
) )
func Email(valid bool, invalid bool, color e.Element) e.Element { func Email(valid bool, invalid bool, color e.Element) e.Element {

View File

@ -1,10 +1,10 @@
package components package components
import ( import (
g "github.com/maragudk/gomponents"
hx "github.com/maragudk/gomponents-htmx"
. "github.com/maragudk/gomponents/html"
b "github.com/willoma/bulma-gomponents" b "github.com/willoma/bulma-gomponents"
g "maragu.dev/gomponents"
hx "maragu.dev/gomponents-htmx"
. "maragu.dev/gomponents/html"
) )
var BaseUrl = "https://api.portfolio.dariusklein.nl" var BaseUrl = "https://api.portfolio.dariusklein.nl"
@ -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

@ -1,9 +1,9 @@
package components package components
import ( import (
g "github.com/maragudk/gomponents"
b "github.com/willoma/bulma-gomponents" b "github.com/willoma/bulma-gomponents"
e "github.com/willoma/gomplements" e "github.com/willoma/gomplements"
g "maragu.dev/gomponents"
) )
func Navbar() g.Node { func Navbar() g.Node {
@ -22,6 +22,15 @@ func Navbar() g.Node {
b.NavbarAHref("/", "Home"), b.NavbarAHref("/", "Home"),
b.NavbarAHref("/about", "Wie ben ik"), b.NavbarAHref("/about", "Wie ben ik"),
b.NavbarAHref("/projects", "projecten"), b.NavbarAHref("/projects", "projecten"),
b.NavbarDropdown(
"placeholder",
b.Hoverable,
b.NavbarAHref("#1", "item 1"),
b.NavbarAHref("#2", "item 2"),
b.NavbarAHref("#3", "item 3"),
b.NavbarDivider(),
b.NavbarAHref("#4", "divided item"),
),
), ),
b.NavbarEnd( b.NavbarEnd(
b.NavbarItem( b.NavbarItem(

View File

@ -2,10 +2,10 @@ package components
import ( import (
"github.com/delaneyj/gomponents-iconify/iconify/mdi" "github.com/delaneyj/gomponents-iconify/iconify/mdi"
g "github.com/maragudk/gomponents"
. "github.com/maragudk/gomponents/html"
b "github.com/willoma/bulma-gomponents" b "github.com/willoma/bulma-gomponents"
e "github.com/willoma/gomplements" e "github.com/willoma/gomplements"
g "maragu.dev/gomponents"
. "maragu.dev/gomponents/html"
"portfolio/database/ent" "portfolio/database/ent"
"strconv" "strconv"
) )
@ -56,18 +56,23 @@ func EditProject(project *ent.Project) g.Node {
b.ImgSq64, b.ImgSq64,
), ),
), ),
b.Textarea(strconv.Itoa(project.ID), b.Rows(1), e.Name("project_id"), e.ReadOnly(true)), Input(Type("hidden"), Value(strconv.Itoa(project.ID)), Name("project_id")),
//b.Label("ID: "+strconv.Itoa(project.ID), Name("project_id")),
b.Label("Name"), b.Label("Name"),
b.Textarea(project.Name, b.Rows(1), e.Name("project_name")), b.Textarea(project.Name, b.Rows(1), Name("project_name")),
b.Subtitle( b.Subtitle(
6, 6,
b.Label("Repo"), b.Label("Repo"),
b.Textarea(project.URL, b.Rows(1), e.Name("project_repo")), b.Textarea(project.URL, b.Rows(1), Name("project_repo")),
b.Label("Docs"), b.Label("Docs"),
b.Textarea(project.DocURL, b.Rows(1), e.Name("project_docs"))), b.Textarea(project.DocURL, b.Rows(1), Name("project_docs"))),
), ),
b.Content( b.Content(
b.Textarea(project.Description, e.Name("project_description")), b.Textarea(project.Description, Name("project_description")),
), ),
//b.CardFooter(
//Save(),
//),
) )
} }

View File

@ -1,8 +1,8 @@
package handlers package handlers
import ( import (
g "maragu.dev/gomponents" g "github.com/maragudk/gomponents"
. "maragu.dev/gomponents/html" . "github.com/maragudk/gomponents/html"
"net/http" "net/http"
) )
@ -17,10 +17,5 @@ func AboutPageHandler(w http.ResponseWriter, r *http.Request) {
func createAboutBody(w http.ResponseWriter, r *http.Request) g.Node { func createAboutBody(w http.ResponseWriter, r *http.Request) g.Node {
return Body( return Body()
IFrame(
Src("/assets/pdf/cv.pdf"),
Class("h-screen w-screen"),
),
)
} }

View File

@ -1,10 +1,10 @@
package handlers package handlers
import ( import (
g "github.com/maragudk/gomponents"
. "github.com/maragudk/gomponents/html"
b "github.com/willoma/bulma-gomponents" b "github.com/willoma/bulma-gomponents"
e "github.com/willoma/gomplements" e "github.com/willoma/gomplements"
g "maragu.dev/gomponents"
. "maragu.dev/gomponents/html"
"net/http" "net/http"
) )
@ -26,7 +26,7 @@ func createHomeBody(w http.ResponseWriter, r *http.Request) g.Node {
b.MediaLeft( b.MediaLeft(
Figure, Figure,
b.ImageImg("assets/images/darius_circle_noEdge_crop_upscayl_1x_realesrgan-x4plus-anime.png", b.ImageImg("assets/images/darius_circle_noEdge_crop_upscayl_1x_realesrgan-x4plus-anime.png",
b.OnImg(e.Class("object-scale-down grayscale "+ b.OnImg(Class("object-scale-down grayscale "+
"max-h-[calc(25vh_-_3.75rem)] "+ "max-h-[calc(25vh_-_3.75rem)] "+
"sm:max-h-[calc(40vh_-_3.75rem)] "+ "sm:max-h-[calc(40vh_-_3.75rem)] "+
"md:max-h-[calc(60vh_-_3.75rem)] "+ "md:max-h-[calc(60vh_-_3.75rem)] "+
@ -37,7 +37,7 @@ func createHomeBody(w http.ResponseWriter, r *http.Request) g.Node {
b.Section( b.Section(
b.Margin(100), b.Margin(100),
e.H1("Darius Klein", e.H1("Darius Klein",
e.Class("title backdrop-blur "+ Class("title backdrop-blur "+
"text-2xl "+ "text-2xl "+
"sm:text-4xl "+ "sm:text-4xl "+
"md:text-6xl "+ "md:text-6xl "+
@ -45,7 +45,7 @@ func createHomeBody(w http.ResponseWriter, r *http.Request) g.Node {
), ),
e.H2( e.H2(
"Backend developer die zelf zijn servers kan opzetten.", "Backend developer die zelf zijn servers kan opzetten.",
e.Class("subtitle backdrop-blur"), Class("subtitle backdrop-blur"),
), ),
b.ButtonAHref("/projects", "Mijn projecten.", b.Primary, b.Centered, b.Large), b.ButtonAHref("/projects", "Mijn projecten.", b.Primary, b.Centered, b.Large),

View File

@ -1,8 +1,8 @@
package handlers package handlers
import ( import (
g "maragu.dev/gomponents" g "github.com/maragudk/gomponents"
. "maragu.dev/gomponents/html" . "github.com/maragudk/gomponents/html"
"net/http" "net/http"
"portfolio/web/components" "portfolio/web/components"
) )

View File

@ -1,9 +1,9 @@
package handlers package handlers
import ( import (
g "maragu.dev/gomponents" g "github.com/maragudk/gomponents"
c "maragu.dev/gomponents/components" c "github.com/maragudk/gomponents/components"
. "maragu.dev/gomponents/html" . "github.com/maragudk/gomponents/html"
"portfolio/web/components" "portfolio/web/components"
) )

View File

@ -2,8 +2,8 @@ package handlers
import ( import (
"context" "context"
g "maragu.dev/gomponents" g "github.com/maragudk/gomponents"
. "maragu.dev/gomponents/html" . "github.com/maragudk/gomponents/html"
"net/http" "net/http"
"portfolio/database/query" "portfolio/database/query"
"portfolio/web/components" "portfolio/web/components"

View File

@ -1,13 +1,11 @@
package web package web
import ( import (
"log"
"net/http" "net/http"
"portfolio/web/handlers" "portfolio/web/handlers"
) )
func Routes() *http.ServeMux { func WebRoutes() *http.ServeMux {
log.Println("Setup web routes")
// 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()