From ec1f7a5a9d4c5249c3290d14c780c5adc08b17db Mon Sep 17 00:00:00 2001 From: Atridad Lahiji Date: Thu, 21 Nov 2024 00:48:45 -0600 Subject: [PATCH] Fly time --- .env.example | 11 +- .github/workflows/deploy.yml | 39 ----- .github/workflows/fly-deploy.yml | 18 +++ Dockerfile | 4 +- api/createroom.go | 4 +- api/deleteroom.go | 4 +- api/getroom.go | 2 +- api/getroomlist.go | 2 +- api/register.go | 4 +- api/signin.go | 2 +- api/signout.go | 2 +- fly.toml | 20 +++ go.mod | 35 ++--- go.sum | 262 +++++-------------------------- lib/db.go | 180 ++++++++------------- lib/room.go | 45 +++--- lib/session.go | 30 ++-- lib/user.go | 43 +++-- main.go | 35 ++--- pages/room.go | 2 +- 20 files changed, 251 insertions(+), 493 deletions(-) delete mode 100644 .github/workflows/deploy.yml create mode 100644 .github/workflows/fly-deploy.yml create mode 100644 fly.toml diff --git a/.env.example b/.env.example index f69b4bd..58f36f1 100644 --- a/.env.example +++ b/.env.example @@ -1,12 +1,11 @@ -# This file is used to store environment variables for the application # Database Connection Information -POSTGRES_PASSWORD=password -POSTGRES_USER=username +DB_URL="libsql://your-database-name.turso.io" +DB_TOKEN="your-auth-token" # Security -ENCRYPTION_KEY="hOzXzSwDSuU41PMtMHm9O/nqf1X+jTB3MOgVDSPXC5o=" -SIGNING_KEY="hOzXzSwDSuU41PMtMHm9O/nqf1X+jTB3MOgVDSPXC5o=" -AUTH_SECRET="hOzXzSwDSuU41PMtMHm9O/nqf1X+jTB3MOgVDSPXC5o=" +ENCRYPTION_KEY="" +SIGNING_KEY="" +AUTH_SECRET="" # Feature Flags DEVMODE=true diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index cd6291a..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Build and Push to GitHub Container Registry - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - build-and-push: - runs-on: ubuntu-latest - - permissions: - contents: read - packages: write - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Build the Docker image - run: docker build . --file Dockerfile --tag ${{ github.event.repository.name }}:${{ github.sha }} - - - name: Login to GitHub Container Registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Tag images - run: | - docker tag ${{ github.event.repository.name }}:${{ github.sha }} ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ github.sha }} - docker tag ${{ github.event.repository.name }}:${{ github.sha }} ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:latest - - - name: Push images to GitHub Container Registry - run: | - docker push ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ github.sha }} - docker push ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:latest diff --git a/.github/workflows/fly-deploy.yml b/.github/workflows/fly-deploy.yml new file mode 100644 index 0000000..b0c246e --- /dev/null +++ b/.github/workflows/fly-deploy.yml @@ -0,0 +1,18 @@ +# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/ + +name: Fly Deploy +on: + push: + branches: + - main +jobs: + deploy: + name: Deploy app + runs-on: ubuntu-latest + concurrency: deploy-group # optional: ensure only one action runs at a time + steps: + - uses: actions/checkout@v4 + - uses: superfly/flyctl-actions/setup-flyctl@master + - run: flyctl deploy --remote-only + env: + FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} diff --git a/Dockerfile b/Dockerfile index c76a442..c2971b9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22.3 as build +FROM golang:1.23.1 as build WORKDIR /app @@ -11,4 +11,4 @@ FROM gcr.io/distroless/base-debian12 COPY --from=build /go/bin/app / -CMD [ "/app" ] \ No newline at end of file +CMD [ "/app" ] diff --git a/api/createroom.go b/api/createroom.go index 649737d..5cea3b2 100644 --- a/api/createroom.go +++ b/api/createroom.go @@ -20,14 +20,14 @@ func CreateRoomHandler(c echo.Context) error { return c.JSON(http.StatusBadRequest, map[string]string{"error": "room name is required"}) } - _, err = lib.CreateRoom(lib.GetDBPool(), currentSession.UserID, roomName) + _, err = lib.CreateRoom(lib.GetDB(), currentSession.UserID, roomName) if err != nil { println("Error creating room: ", err.Error()) return c.JSON(http.StatusInternalServerError, map[string]string{"error": "failed to create room"}) } // Retrieve the updated list of rooms for the user - rooms, err := lib.GetRoomsByUserID(lib.GetDBPool(), currentSession.UserID) + rooms, err := lib.GetRoomsByUserID(lib.GetDB(), currentSession.UserID) if err != nil { println("Error retrieving rooms: ", err.Error()) return c.JSON(http.StatusInternalServerError, map[string]string{"error": "failed to retrieve rooms"}) diff --git a/api/deleteroom.go b/api/deleteroom.go index 95dcf4c..43c7938 100644 --- a/api/deleteroom.go +++ b/api/deleteroom.go @@ -21,13 +21,13 @@ func DeleteRoomHandler(c echo.Context) error { return c.JSON(http.StatusBadRequest, map[string]string{"error": "room ID is required"}) } - deletionError := lib.DeleteRoom(lib.GetDBPool(), roomID) + deletionError := lib.DeleteRoom(lib.GetDB(), roomID) if deletionError != nil { return c.JSON(http.StatusInternalServerError, map[string]string{"error": "failed to delete room"}) } // Retrieve the updated list of rooms for the user - rooms, fetchError := lib.GetRoomsByUserID(lib.GetDBPool(), currentSession.UserID) + rooms, fetchError := lib.GetRoomsByUserID(lib.GetDB(), currentSession.UserID) if fetchError != nil { println("Error retrieving rooms: ", fetchError.Error()) return c.JSON(http.StatusInternalServerError, map[string]string{"error": "failed to retrieve rooms"}) diff --git a/api/getroom.go b/api/getroom.go index 1d5561e..edf8ccb 100644 --- a/api/getroom.go +++ b/api/getroom.go @@ -11,7 +11,7 @@ import ( // GetRoomHandler handles the request to get a room by ID. func GetRoomHandler(c echo.Context) error { roomID := c.Param("id") - room, err := lib.GetRoomById(lib.GetDBPool(), roomID) + room, err := lib.GetRoomById(lib.GetDB(), roomID) if err != nil { // Log the error println("Error retrieving room: ", err.Error()) diff --git a/api/getroomlist.go b/api/getroomlist.go index b827d19..a6a7d03 100644 --- a/api/getroomlist.go +++ b/api/getroomlist.go @@ -15,7 +15,7 @@ func GetAllRoomsHandler(c echo.Context) error { return c.JSON(http.StatusUnauthorized, map[string]string{"error": "unauthorized"}) } - rooms, err := lib.GetRoomsByUserID(lib.GetDBPool(), currentSession.UserID) + rooms, err := lib.GetRoomsByUserID(lib.GetDB(), currentSession.UserID) if err != nil { // Log the error and return an internal server error response println("Error retrieving rooms: ", err.Error()) diff --git a/api/register.go b/api/register.go index a208bc4..5ea840d 100644 --- a/api/register.go +++ b/api/register.go @@ -13,7 +13,7 @@ func RegisterUserHandler(c echo.Context) error { password := c.FormValue("password") // Check if the email already exists - existingUser, err := lib.GetUserByEmail(lib.GetDBPool(), email) + existingUser, err := lib.GetUserByEmail(lib.GetDB(), email) if err == nil && existingUser != nil { // User with the given email already exists errorMessage := `
An account with this email already exists!
` @@ -28,7 +28,7 @@ func RegisterUserHandler(c echo.Context) error { user := lib.User{Name: name, Email: email, Password: hashedPassword} println("User: ", user.Name, user.Email, user.Password) - if err := lib.SaveUser(lib.GetDBPool(), &user); err != nil { + if err := lib.SaveUser(lib.GetDB(), &user); err != nil { println("Error saving user: ", err.Error()) return c.JSON(http.StatusInternalServerError, "Failed to save user") } diff --git a/api/signin.go b/api/signin.go index 13458c5..a78826b 100644 --- a/api/signin.go +++ b/api/signin.go @@ -12,7 +12,7 @@ func SignInUserHandler(c echo.Context) error { password := c.FormValue("password") // Example validation logic - user, err := lib.GetUserByEmail(lib.GetDBPool(), email) + user, err := lib.GetUserByEmail(lib.GetDB(), email) if err != nil || !lib.CheckPasswordHash(password, user.Password) { errorMessage := `
Incorrect email or password
` return c.HTML(http.StatusUnauthorized, errorMessage) diff --git a/api/signout.go b/api/signout.go index c556aa2..af4f5dc 100644 --- a/api/signout.go +++ b/api/signout.go @@ -12,7 +12,7 @@ func SignOutUserHandler(c echo.Context) error { sessionData, err := lib.GetSessionCookie(c.Request(), "session") if err == nil && sessionData != nil { // Delete the session from the database - err = lib.DeleteSession(lib.GetDBPool(), sessionData.SessionID) + err = lib.DeleteSession(lib.GetDB(), sessionData.SessionID) if err != nil { log.Printf("Error deleting session: %v", err) } diff --git a/fly.toml b/fly.toml new file mode 100644 index 0000000..4209f49 --- /dev/null +++ b/fly.toml @@ -0,0 +1,20 @@ +# fly.toml app configuration file generated for polloapp on 2024-11-21T00:41:17-06:00 +# +# See https://fly.io/docs/reference/configuration/ for information about how to use this file. +# + +app = 'polloapp' +primary_region = 'ord' + +[build] + +[http_service] +internal_port = 3000 +force_https = true +auto_stop_machines = 'stop' +auto_start_machines = true +min_machines_running = 0 +processes = ['app'] + +[[vm]] +size = 'shared-cpu-1x' diff --git a/go.mod b/go.mod index ce44485..1db17cd 100644 --- a/go.mod +++ b/go.mod @@ -1,39 +1,34 @@ module pollo -go 1.22.0 +go 1.23 + +require github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d require ( + github.com/antlr4-go/antlr/v4 v4.13.1 // indirect + github.com/coder/websocket v1.8.12 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect - github.com/google/go-cmp v0.6.0 // indirect github.com/gorilla/context v1.1.2 // indirect github.com/gorilla/securecookie v1.1.2 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.14.3 // indirect - github.com/jackc/pgio v1.0.0 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.3 // indirect - github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect - github.com/jackc/pgtype v1.14.3 // indirect - github.com/jackc/puddle v1.3.0 // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - golang.org/x/net v0.27.0 // indirect - golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/text v0.16.0 // indirect - golang.org/x/time v0.5.0 // indirect + golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect + golang.org/x/net v0.31.0 // indirect + golang.org/x/text v0.20.0 // indirect + golang.org/x/time v0.8.0 // indirect + gopkg.in/validator.v2 v2.0.1 // indirect ) require ( - github.com/fatih/color v1.17.0 - github.com/gorilla/sessions v1.3.0 - github.com/jackc/pgx/v4 v4.18.3 + github.com/fatih/color v1.18.0 + github.com/gorilla/sessions v1.4.0 github.com/joho/godotenv v1.5.1 github.com/labstack/echo-contrib v0.17.1 github.com/labstack/echo/v4 v4.12.0 github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/svix/svix-webhooks v1.24.0 - golang.org/x/crypto v0.25.0 - golang.org/x/sys v0.22.0 // indirect + github.com/svix/svix-webhooks v1.41.0 + golang.org/x/crypto v0.29.0 + golang.org/x/sys v0.27.0 // indirect ) diff --git a/go.sum b/go.sum index 3f9e81e..9fa7422 100644 --- a/go.sum +++ b/go.sum @@ -1,95 +1,28 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= +github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= +github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= +github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= +github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= 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/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= -github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -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/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o= github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= -github.com/gorilla/sessions v1.3.0 h1:XYlkq7KcpOB2ZhHBPv5WpjMIxrQosiZanfoy1HLZFzg= -github.com/gorilla/sessions v1.3.0/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= -github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= -github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= -github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= -github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgtype v1.14.3 h1:h6W9cPuHsRWQFTWUZMAKMgG5jSwQI0Zurzdvlx3Plus= -github.com/jackc/pgtype v1.14.3/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= -github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA= -github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= +github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/labstack/echo-contrib v0.17.1 h1:7I/he7ylVKsDUieaGRZ9XxxTYOjfQwVzHzUYrNykfCU= github.com/labstack/echo-contrib v0.17.1/go.mod h1:SnsCZtwHBAZm5uBSAtQtXQHI3wqEA73hvTn0bYMKnZA= @@ -97,167 +30,42 @@ github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+k github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= -github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/svix/svix-webhooks v1.24.0 h1:NL8WVC+GpXXJdt0JJ4jfUsCK0CjYxZiU2bM2nRvXaW0= -github.com/svix/svix-webhooks v1.24.0/go.mod h1:MPOB9jpp6jPh652WuKeuKIV5m2APqXXOjLxxOe4mDmM= +github.com/svix/svix-webhooks v1.41.0 h1:zyVY9eF1L+f1Q3iqXIagzThw4KYoNxAwBD3Q6hojUxc= +github.com/svix/svix-webhooks v1.41.0/go.mod h1:MHZT9p7h83h+yuSsBBqZjK7YUOJtv/gukZpmvDDtGQg= +github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d h1:dOMI4+zEbDI37KGb0TI44GUAwxHF9cMsIoDTJ7UmgfU= +github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d/go.mod h1:l8xTsYB90uaVdMHXMCxKKLSgw5wLYBwBKKefNIUnm9s= 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/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= +golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= +golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= +golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +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/validator.v2 v2.0.1 h1:xF0KWyGWXm/LM2G1TrEjqOu4pa6coO9AlWSf3msVfDY= +gopkg.in/validator.v2 v2.0.1/go.mod h1:lIUZBlB3Im4s/eYp39Ry/wkR02yOPhZ9IwIRBjuPuG8= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/lib/db.go b/lib/db.go index 5296754..f8f04f3 100644 --- a/lib/db.go +++ b/lib/db.go @@ -1,139 +1,85 @@ package lib import ( - "context" "crypto/rand" + "database/sql" "encoding/hex" "fmt" - "github.com/jackc/pgx/v4/pgxpool" + _ "github.com/tursodatabase/libsql-client-go/libsql" ) -var dbPool *pgxpool.Pool - -// Migration represents a database migration. -type Migration struct { - Version string - SQL string -} +var db *sql.DB // GenerateNewID generates a DB with the format "prefix_randomstring". func GenerateNewID(prefix string) string { - randomBytes := make([]byte, 16) - if _, err := rand.Read(randomBytes); err != nil { - panic(err) - } - return fmt.Sprintf("%s_%s", prefix, hex.EncodeToString(randomBytes)) + randomBytes := make([]byte, 16) + if _, err := rand.Read(randomBytes); err != nil { + panic(err) + } + return fmt.Sprintf("%s_%s", prefix, hex.EncodeToString(randomBytes)) } -// Initializes the global database connection pool. -func InitializeDBPool(host, user, password, dbname string, port int) error { - connString := fmt.Sprintf("postgres://%s:%s@%s:%d/%s", user, password, host, port, dbname) - var err error - dbPool, err = pgxpool.Connect(context.Background(), connString) - if err != nil { - return err - } - return nil +// Initialize the database connection +func InitializeDB(url, authToken string) error { + var err error + connectionString := fmt.Sprintf("%s?authToken=%s", url, authToken) + db, err = sql.Open("libsql", connectionString) + if err != nil { + return fmt.Errorf("error opening database: %v", err) + } + + // Test the connection + err = db.Ping() + if err != nil { + return fmt.Errorf("error connecting to the database: %v", err) + } + + return nil } -func InitializeSchema(dbPool *pgxpool.Pool) error { - migrations := []Migration{ - { - Version: "1_create_users_table", - SQL: ` - CREATE TABLE IF NOT EXISTS users ( - id TEXT NOT NULL PRIMARY KEY, - name VARCHAR(255) NOT NULL, - email VARCHAR(255) UNIQUE NOT NULL, - password VARCHAR(255) NOT NULL - );`, - }, - { - Version: "2_create_rooms_table", - SQL: ` - CREATE TABLE IF NOT EXISTS rooms ( - id TEXT NOT NULL PRIMARY KEY, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - userId TEXT NOT NULL, - roomName TEXT, - topicName TEXT, - visible BOOLEAN NOT NULL DEFAULT false, - scale TEXT NOT NULL DEFAULT '0.5,1,2,3,5' - );`, - }, - { - Version: "3_add_foreign_key_to_rooms", - SQL: ` - ALTER TABLE rooms - ADD CONSTRAINT fk_user_id - FOREIGN KEY (userId) REFERENCES users(id);`, - }, - { - Version: "4_create_index_on_users_email", - SQL: ` - CREATE INDEX IF NOT EXISTS idx_users_email ON users(email); - `, - }, - { - Version: "5_create_index_on_rooms_userid", - SQL: ` - CREATE INDEX IF NOT EXISTS idx_rooms_userid ON rooms(userId); - `, - }, - { - Version: "6_create_sessions_table", - SQL: ` - CREATE TABLE IF NOT EXISTS sessions ( - id TEXT PRIMARY KEY, - user_id TEXT NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - expires_at TIMESTAMP NOT NULL, - FOREIGN KEY (user_id) REFERENCES users(id) - ); - CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id); - `, - }, - } +func InitializeSchema() error { + if db == nil { + return fmt.Errorf("database not initialized") + } - // Ensure the migrations table exists - _, err := dbPool.Exec(context.Background(), ` - CREATE TABLE IF NOT EXISTS migrations ( - version VARCHAR(255) PRIMARY KEY - ); - `) - if err != nil { - return err - } + migrations := []string{ + `CREATE TABLE IF NOT EXISTS users ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + email TEXT UNIQUE NOT NULL, + password TEXT NOT NULL + )`, + `CREATE TABLE IF NOT EXISTS rooms ( + id TEXT PRIMARY KEY, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + userId TEXT NOT NULL, + roomName TEXT, + topicName TEXT, + visible BOOLEAN DEFAULT false, + scale TEXT DEFAULT '0.5,1,2,3,5', + FOREIGN KEY (userId) REFERENCES users(id) + )`, + `CREATE TABLE IF NOT EXISTS sessions ( + id TEXT PRIMARY KEY, + user_id TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + expires_at TIMESTAMP NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) + )`, + } - // Apply each migration - for _, migration := range migrations { - // Check if this migration has already been applied - var exists bool - err := dbPool.QueryRow(context.Background(), "SELECT EXISTS(SELECT 1 FROM migrations WHERE version = $1)", migration.Version).Scan(&exists) - if err != nil { - return err - } + for _, migration := range migrations { + _, err := db.Exec(migration) + if err != nil { + return fmt.Errorf("error executing migration: %v", err) + } + } - if !exists { - // Apply the migration - _, err = dbPool.Exec(context.Background(), migration.SQL) - if err != nil { - return err - } - - // Mark this migration as applied - _, err = dbPool.Exec(context.Background(), "INSERT INTO migrations (version) VALUES ($1)", migration.Version) - if err != nil { - return err - } - } - } - - return nil + return nil } -// Returns the initialized database connection pool. -func GetDBPool() *pgxpool.Pool { - return dbPool +// GetDB returns the database connection +func GetDB() *sql.DB { + return db } diff --git a/lib/room.go b/lib/room.go index 6dd1a2c..eba479e 100644 --- a/lib/room.go +++ b/lib/room.go @@ -1,13 +1,10 @@ package lib import ( - "context" "database/sql" "errors" "fmt" "time" - - "github.com/jackc/pgx/v4/pgxpool" ) type Room struct { @@ -21,16 +18,18 @@ type Room struct { } // CreateRoom creates a new room in the database. -func CreateRoom(dbPool *pgxpool.Pool, userID, roomName string) (*Room, error) { - if dbPool == nil { - return nil, errors.New("database connection pool is not initialized") +func CreateRoom(db *sql.DB, userID, roomName string) (*Room, error) { + if db == nil { + return nil, errors.New("database is not initialized") } // Generate a new ID for the room newRoomID := GenerateNewID("room") // Insert the new room into the database - _, err := dbPool.Exec(context.Background(), "INSERT INTO rooms (id, userid, roomname, topicname, visible, scale) VALUES ($1, $2, $3, $4, $5, $6)", newRoomID, userID, roomName, "My First Topic", false, "0.5,1,2,3,5") + _, err := db.Exec( + "INSERT INTO rooms (id, userid, roomname, topicname, visible, scale) VALUES (?, ?, ?, ?, ?, ?)", + newRoomID, userID, roomName, "My First Topic", false, "0.5,1,2,3,5") if err != nil { return nil, err } @@ -46,12 +45,14 @@ func CreateRoom(dbPool *pgxpool.Pool, userID, roomName string) (*Room, error) { } // DeleteRoom deletes a room from the database by its ID. -func DeleteRoom(dbPool *pgxpool.Pool, roomID string) error { - if dbPool == nil { - return errors.New("database connection pool is not initialized") +func DeleteRoom(db *sql.DB, roomID string) error { + if db == nil { + return errors.New("database is not initialized") } - _, err := dbPool.Exec(context.Background(), "DELETE FROM rooms WHERE id = $1", roomID) + _, err := db.Exec( + "DELETE FROM rooms WHERE id = ?", + roomID) if err != nil { return err } @@ -60,13 +61,15 @@ func DeleteRoom(dbPool *pgxpool.Pool, roomID string) error { } // GetRoomsByUserID retrieves all rooms for a given userID. -func GetRoomsByUserID(dbPool *pgxpool.Pool, userID string) ([]Room, error) { - if dbPool == nil { - return nil, errors.New("database connection pool is not initialized") +func GetRoomsByUserID(db *sql.DB, userID string) ([]Room, error) { + if db == nil { + return nil, errors.New("database is not initialized") } var rooms []Room - rows, err := dbPool.Query(context.Background(), "SELECT id, created_at, userid, roomname, topicname, visible, scale FROM rooms WHERE userid = $1", userID) + rows, err := db.Query( + "SELECT id, created_at, userid, roomname, topicname, visible, scale FROM rooms WHERE userid = ?", + userID) if err != nil { return nil, err } @@ -89,11 +92,15 @@ func GetRoomsByUserID(dbPool *pgxpool.Pool, userID string) ([]Room, error) { } // GetRoomById retrieves a room by its ID from the database. -func GetRoomById(dbPool *pgxpool.Pool, roomId string) (*Room, error) { - var room Room +func GetRoomById(db *sql.DB, roomId string) (*Room, error) { + if db == nil { + return nil, errors.New("database is not initialized") + } - query := "SELECT id, created_at, userid, roomname, topicname, visible, scale FROM rooms WHERE id = $1" - err := dbPool.QueryRow(context.Background(), query, roomId).Scan(&room.ID, &room.CreatedAt, &room.UserID, &room.RoomName, &room.TopicName, &room.Visible, &room.Scale) + var room Room + err := db.QueryRow( + "SELECT id, created_at, userid, roomname, topicname, visible, scale FROM rooms WHERE id = ?", + roomId).Scan(&room.ID, &room.CreatedAt, &room.UserID, &room.RoomName, &room.TopicName, &room.Visible, &room.Scale) if err != nil { if err == sql.ErrNoRows { return nil, fmt.Errorf("no room found with ID %s", roomId) diff --git a/lib/session.go b/lib/session.go index 3699bce..d5b04eb 100644 --- a/lib/session.go +++ b/lib/session.go @@ -1,7 +1,7 @@ package lib import ( - "context" + "database/sql" "encoding/hex" "encoding/json" "log" @@ -10,7 +10,6 @@ import ( "time" "github.com/gorilla/sessions" - "github.com/jackc/pgx/v4/pgxpool" "github.com/labstack/echo-contrib/session" "github.com/labstack/echo/v4" ) @@ -36,8 +35,8 @@ func InitSessionMiddleware() echo.MiddlewareFunc { // Adjusted SetSessionCookie to include more user info func SetSessionCookie(w http.ResponseWriter, name string, sessionData SessionData) error { // Create session in database - expiresAt := time.Now().Add(48 * time.Hour) // Set expiration to 1 hour from now - sessionID, err := CreateSession(GetDBPool(), sessionData.UserID, expiresAt) + expiresAt := time.Now().Add(48 * time.Hour) // Set expiration to 48 hours from now + sessionID, err := CreateSession(GetDB(), sessionData.UserID, expiresAt) if err != nil { return err } @@ -115,7 +114,7 @@ func IsSignedIn(c echo.Context) bool { } // Validate the session in the database - validSessionData, err := ValidateSession(GetDBPool(), sessionData.SessionID) + validSessionData, err := ValidateSession(GetDB(), sessionData.SessionID) if err != nil || validSessionData == nil { log.Printf("Invalid session: %v", err) ClearSessionCookie(c.Response().Writer, "session") @@ -134,10 +133,10 @@ func GenerateSessionID() (string, error) { return hex.EncodeToString(bytes), nil } -func CreateSession(dbPool *pgxpool.Pool, userID string, expiresAt time.Time) (string, error) { +func CreateSession(db *sql.DB, userID string, expiresAt time.Time) (string, error) { sessionID := GenerateNewID("session") - _, err := dbPool.Exec(context.Background(), - "INSERT INTO sessions (id, user_id, expires_at) VALUES ($1, $2, $3)", + _, err := db.Exec( + "INSERT INTO sessions (id, user_id, expires_at) VALUES (?, ?, ?)", sessionID, userID, expiresAt) if err != nil { return "", err @@ -145,17 +144,17 @@ func CreateSession(dbPool *pgxpool.Pool, userID string, expiresAt time.Time) (st return sessionID, nil } -func ValidateSession(dbPool *pgxpool.Pool, sessionID string) (*SessionData, error) { +func ValidateSession(db *sql.DB, sessionID string) (*SessionData, error) { var userID string var expiresAt time.Time - err := dbPool.QueryRow(context.Background(), - "SELECT user_id, expires_at FROM sessions WHERE id = $1 AND expires_at > NOW()", + err := db.QueryRow( + "SELECT user_id, expires_at FROM sessions WHERE id = ? AND expires_at > datetime('now')", sessionID).Scan(&userID, &expiresAt) if err != nil { return nil, err } - user, err := GetUserByID(dbPool, userID) + user, err := GetUserByID(db, userID) if err != nil { return nil, err } @@ -169,8 +168,9 @@ func ValidateSession(dbPool *pgxpool.Pool, sessionID string) (*SessionData, erro }, nil } -func DeleteSession(dbPool *pgxpool.Pool, sessionID string) error { - _, err := dbPool.Exec(context.Background(), - "DELETE FROM sessions WHERE id = $1", sessionID) +func DeleteSession(db *sql.DB, sessionID string) error { + _, err := db.Exec( + "DELETE FROM sessions WHERE id = ?", + sessionID) return err } diff --git a/lib/user.go b/lib/user.go index 6fa49a5..cc99afc 100644 --- a/lib/user.go +++ b/lib/user.go @@ -1,11 +1,10 @@ package lib import ( - "context" + "database/sql" "errors" "net/http" - "github.com/jackc/pgx/v4/pgxpool" "github.com/labstack/echo/v4" "golang.org/x/crypto/bcrypt" ) @@ -30,14 +29,17 @@ func CheckPasswordHash(password, hash string) bool { } // GetUserByEmail fetches a user by email from the database. -func GetUserByEmail(dbPool *pgxpool.Pool, email string) (*User, error) { - if dbPool == nil { - return nil, errors.New("database connection pool is not initialized") +func GetUserByEmail(db *sql.DB, email string) (*User, error) { + if db == nil { + return nil, errors.New("database client is not initialized") } var user User - // Ensure the ID is being scanned as a string. - err := dbPool.QueryRow(context.Background(), "SELECT id::text, name, email, password FROM users WHERE email = $1", email).Scan(&user.ID, &user.Name, &user.Email, &user.Password) + row := db.QueryRow( + "SELECT id, name, email, password FROM users WHERE email = ?", + email) + + err := row.Scan(&user.ID, &user.Name, &user.Email, &user.Password) if err != nil { return nil, err } @@ -45,14 +47,17 @@ func GetUserByEmail(dbPool *pgxpool.Pool, email string) (*User, error) { } // GetUserByID fetches a user by ID from the database. -func GetUserByID(dbPool *pgxpool.Pool, id string) (*User, error) { - if dbPool == nil { - return nil, errors.New("database connection pool is not initialized") +func GetUserByID(db *sql.DB, id string) (*User, error) { + if db == nil { + return nil, errors.New("database client is not initialized") } var user User - // Ensure the ID is being scanned as a string. - err := dbPool.QueryRow(context.Background(), "SELECT id::text, name, email, password FROM users WHERE id = $1", id).Scan(&user.ID, &user.Name, &user.Email, &user.Password) + row := db.QueryRow( + "SELECT id, name, email, password FROM users WHERE id = ?", + id) + + err := row.Scan(&user.ID, &user.Name, &user.Email, &user.Password) if err != nil { return nil, err } @@ -60,16 +65,20 @@ func GetUserByID(dbPool *pgxpool.Pool, id string) (*User, error) { } // SaveUser saves a new user to the database. -func SaveUser(dbPool *pgxpool.Pool, user *User) error { - if dbPool == nil { - return errors.New("database connection pool is not initialized") +func SaveUser(db *sql.DB, user *User) error { + if db == nil { + return errors.New("database client is not initialized") } - commandTag, err := dbPool.Exec(context.Background(), "INSERT INTO users (id, name, email, password) VALUES ($1, $2, $3, $4)", GenerateNewID("user"), user.Name, user.Email, user.Password) + result, err := db.Exec( + "INSERT INTO users (id, name, email, password) VALUES (?, ?, ?, ?)", + GenerateNewID("user"), user.Name, user.Email, user.Password) if err != nil { return err } - if commandTag.RowsAffected() != 1 { + + rowsAffected, _ := result.RowsAffected() + if rowsAffected != 1 { return errors.New("expected one row to be affected") } return nil diff --git a/main.go b/main.go index 8763e27..48c9780 100755 --- a/main.go +++ b/main.go @@ -7,7 +7,6 @@ import ( "log" "net/http" "os" - "strconv" "pollo/api" "pollo/api/webhooks" @@ -24,30 +23,26 @@ var PublicFS embed.FS func main() { // Load environment variables - godotenv.Load(".env") - - // Initialize the database connection pool - postgresHost := os.Getenv("POSTGRES_HOST") - postgresPort := os.Getenv("POSTGRES_PORT") - postgresUser := os.Getenv("POSTGRES_USER") - postgresPassword := os.Getenv("POSTGRES_PASSWORD") - postgresDB := os.Getenv("POSTGRES_DB") - if postgresHost == "" || postgresPort == "" || postgresUser == "" || postgresPassword == "" || postgresDB == "" { - log.Fatal("DB environment variables not set") - } - - portNumber, err := strconv.Atoi(postgresPort) + err := godotenv.Load() if err != nil { - log.Fatalf("Invalid database port: %v", err) + log.Printf("Warning: Error loading .env file: %v", err) } - if err := lib.InitializeDBPool(postgresHost, postgresUser, postgresPassword, postgresDB, portNumber); err != nil { - log.Fatalf("Failed to initialize DB pool: %v", err) + // Initialize database connection + dbUrl := os.Getenv("DB_URL") + dbToken := os.Getenv("DB_TOKEN") + + if dbUrl == "" || dbToken == "" { + log.Fatal("DB_URL and DB_TOKEN environment variables must be set") } - // Initialize the database schema - dbPool := lib.GetDBPool() - if err := lib.InitializeSchema(dbPool); err != nil { + // Initialize the database + if err := lib.InitializeDB(dbUrl, dbToken); err != nil { + log.Fatalf("Failed to initialize DB: %v", err) + } + + // Initialize schema + if err := lib.InitializeSchema(); err != nil { log.Fatalf("Failed to initialize schema: %v", err) } diff --git a/pages/room.go b/pages/room.go index 3666a6d..a0b2390 100644 --- a/pages/room.go +++ b/pages/room.go @@ -18,7 +18,7 @@ func Room(c echo.Context) error { pageError := lib.Error{} // Get the room from the database - room, err := lib.GetRoomById(lib.GetDBPool(), roomID) + room, err := lib.GetRoomById(lib.GetDB(), roomID) if err != nil { pageError = lib.Error{ Code: 404,