diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | cmd/start.go | 2 | ||||
-rw-r--r-- | components/auth.html | 7 | ||||
-rw-r--r-- | go.mod | 20 | ||||
-rw-r--r-- | go.sum | 52 | ||||
-rw-r--r-- | internal/database/migrations/001_init.up.sql | 11 | ||||
-rw-r--r-- | internal/database/repos/action.go | 10 | ||||
-rw-r--r-- | internal/database/repos/userscore.go | 4 | ||||
-rw-r--r-- | internal/database/sql/main.go | 69 | ||||
-rw-r--r-- | internal/handlers/auth.go | 56 | ||||
-rw-r--r-- | internal/handlers/main.go | 46 | ||||
-rw-r--r-- | internal/models/models.go | 1 | ||||
-rw-r--r-- | internal/server/router.go | 2 | ||||
-rw-r--r-- | pkg/cache/main.go | 2 |
14 files changed, 120 insertions, 163 deletions
@@ -3,3 +3,4 @@ config.yml apjournal tags store.json +apj.db diff --git a/cmd/start.go b/cmd/start.go index c75f0f8..6bb16a3 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -30,7 +30,7 @@ var startCmd = &cobra.Command{ "path", viper.ConfigFileUsed()) } cfg := config.LoadConfig(viper.GetViper()) - db, err := database.InitWithMigrate(cfg.DBURI, true) + db, err := database.Init(cfg.DBURI) if err != nil { log.Error("failed to connect to db", "error", err) return diff --git a/components/auth.html b/components/auth.html index 78ad338..5122919 100644 --- a/components/auth.html +++ b/components/auth.html @@ -1,6 +1,6 @@ {{define "auth"}} <div id="logindiv"> - <form class="space-y-6" hx-post="/login" hx-target="#ancestor" hx-swap="outerHTML"> + <form class="space-y-6" hx-target="#ancestor" hx-swap="outerHTML"> <div> <label For="username" class="block text-sm font-medium leading-6 text-white-900">username</label> <div class="mt-2"> @@ -8,13 +8,14 @@ </div> </div> <div> - <label For="room_pass" class="block text-sm font-medium leading-6 text-white-900">password</label> + <label For="password" class="block text-sm font-medium leading-6 text-white-900">password</label> <div class="mt-2"> <input id="password" name="password" type="password" required class="rounded-md text-center text-black" /> </div> </div> <div> - <button type="submit" class="justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Sign in</button> + <button type="submit" hx-post="/login" class="justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Log in</button> + <button type="submit" hx-post="/signup" class="justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Sign up</button> </div> </form> </div> @@ -3,32 +3,21 @@ module apjournal go 1.22.1 require ( - github.com/golang-migrate/migrate v3.5.4+incompatible - github.com/jackc/pgx/v5 v5.5.5 github.com/jmoiron/sqlx v1.3.5 + github.com/mattn/go-sqlite3 v1.14.6 github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 + golang.org/x/crypto v0.16.0 ) require ( - github.com/distribution/reference v0.6.0 // indirect - github.com/docker/docker v26.0.0+incompatible // indirect - github.com/docker/go-connections v0.5.0 // indirect - github.com/docker/go-units v0.5.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/puddle/v2 v2.2.1 // indirect - github.com/lib/pq v1.2.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moby/docker-image-spec v1.3.1 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -38,15 +27,12 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/testify v1.9.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 // indirect - go.opentelemetry.io/otel/trace v1.25.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect - golang.org/x/crypto v0.17.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/sync v0.5.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) @@ -1,52 +1,27 @@ -github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= -github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v26.0.0+incompatible h1:Ng2qi+gdKADUa/VM+6b6YaY2nlZhk/lVJiKR/2bMudU= -github.com/docker/docker v26.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= -github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= -github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-migrate/migrate v3.5.4+incompatible h1:R7OzwvCJTCgwapPCiX6DyBiu2czIUMDCB118gFTKTUA= -github.com/golang-migrate/migrate v3.5.4+incompatible/go.mod h1:IsVUlFN5puWOmXrqjgGUfIRIbU7mr8oNBE2tyERd9Wk= 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/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -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/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= -github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= @@ -57,12 +32,6 @@ github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRU github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 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/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= -github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= -github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -93,7 +62,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ 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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -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.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= @@ -101,24 +69,14 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 h1:cEPbyTSEHlQR89XVlyo78gqluF8Y3oMeBkXGWzQsfXY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8= -go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k= -go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= -go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA= -go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= -go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= -go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= diff --git a/internal/database/migrations/001_init.up.sql b/internal/database/migrations/001_init.up.sql index 80ebcad..f7e41c1 100644 --- a/internal/database/migrations/001_init.up.sql +++ b/internal/database/migrations/001_init.up.sql @@ -1,21 +1,22 @@ BEGIN; CREATE TABLE user_score ( - id INT GENERATED BY DEFAULT AS IDENTITY, + id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, - burn_time TIMESTAMP NOT NULL DEFAULT NOW() + interval '1 day', + password TEXT NOT NULL, + burn_time TIMESTAMP NOT NULL, score SMALLINT NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT NOW() + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE action ( - id INT GENERATED BY DEFAULT AS IDENTITY, + id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, magnitude SMALLINT NOT NULL DEFAULT 1, repeatable BOOLEAN NOT NULL DEFAULT FALSE, type TEXT NOT NULL, done BOOLEAN NOT NULL DEFAULT FALSE, username TEXT NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT NOW(), + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE(username, name), CONSTRAINT fk_user_score FOREIGN KEY(username) diff --git a/internal/database/repos/action.go b/internal/database/repos/action.go index 6024dd5..49ad95e 100644 --- a/internal/database/repos/action.go +++ b/internal/database/repos/action.go @@ -5,6 +5,7 @@ import "apjournal/internal/models" type ActionRepo interface { DBActionCreate(req *models.Action) error DBActionList(username string) ([]models.Action, error) + DBActionGetByName(name string) (*models.Action, error) DBActionDone(name string) error DBActionsToReset() error } @@ -25,6 +26,15 @@ func (p *Provider) DBActionList(username string) ([]models.Action, error) { return resp, nil } +func (p *Provider) DBActionGetByName(name string) (*models.Action, error) { + resp := models.Action{} + query := "SELECT * FROM action WHERE name=$1;" + if err := p.db.Get(&resp, query, name); err != nil { + return nil, err + } + return &resp, nil +} + func (p *Provider) DBActionDone(name string) error { // should reset at burn time stmt := "UPDATE action SET done=true WHERE name=$1;" diff --git a/internal/database/repos/userscore.go b/internal/database/repos/userscore.go index 5c09004..2baf99f 100644 --- a/internal/database/repos/userscore.go +++ b/internal/database/repos/userscore.go @@ -10,8 +10,8 @@ type UserScoreRepo interface { func (p *Provider) DBUserScoreCreate(req *models.UserScore) error { _, err := p.db.NamedExec(` - INSERT INTO user_score(username, burn_time, score) - VALUES (:username, :burn_time, :score);`, req) + INSERT INTO user_score(username, burn_time, score, password) + VALUES (:username, :burn_time, :score, :password);`, req) return err } diff --git a/internal/database/sql/main.go b/internal/database/sql/main.go index 80d5f5c..5a523f6 100644 --- a/internal/database/sql/main.go +++ b/internal/database/sql/main.go @@ -1,23 +1,20 @@ package database import ( - "apjournal/internal/database/migrations" "os" "time" - "github.com/jmoiron/sqlx" - - // driver postgres for migrations "log/slog" - "github.com/golang-migrate/migrate" - _ "github.com/golang-migrate/migrate/database/postgres" - bindata "github.com/golang-migrate/migrate/source/go_bindata" - _ "github.com/jackc/pgx/v5/stdlib" // register pgx driver + "github.com/jmoiron/sqlx" + _ "github.com/mattn/go-sqlite3" "github.com/pkg/errors" ) -var log = slog.New(slog.NewJSONHandler(os.Stdout, nil)) +var ( + log = slog.New(slog.NewJSONHandler(os.Stdout, nil)) + dbDriver = "sqlite3" +) type DB struct { Conn *sqlx.DB @@ -40,38 +37,17 @@ func closeConn(conn *sqlx.DB) error { func Init(DBURI string) (*DB, error) { var result DB var err error - result.Conn, err = openDBConnection(DBURI, "pgx") + result.Conn, err = openDBConnection(DBURI, dbDriver) if err != nil { return nil, err } result.URI = DBURI - if err := testConnection(result.Conn); err != nil { return nil, err } return &result, nil } -func InitWithMigrate(DBURI string, up bool) (*DB, error) { - var ( - result DB - err error - ) - result.Conn, err = openDBConnection(DBURI, "pgx") - if err != nil { - return nil, err - } - result.URI = DBURI - - if err = testConnection(result.Conn); err != nil { - return nil, err - } - if err = result.Migrate(DBURI, up); err != nil { - return nil, err - } - return &result, nil -} - func openDBConnection(dbURI, driver string) (*sqlx.DB, error) { conn, err := sqlx.Open(driver, dbURI) if err != nil { @@ -88,38 +64,9 @@ func testConnection(conn *sqlx.DB) error { return nil } -func (db *DB) Migrate(url string, up bool) error { - source := bindata.Resource(migrations.AssetNames(), migrations.Asset) - driver, err := bindata.WithInstance(source) - if err != nil { - return errors.WithStack(errors.WithMessage(err, - "unable to instantiate driver from bindata")) - } - migration, err := migrate.NewWithSourceInstance("go-bindata", - driver, url) - if err != nil { - return errors.WithStack(errors.WithMessage(err, - "unable to start migration")) - } - if up { - if err = migration.Up(); err != nil && err.Error() != "no change" { - return errors.WithStack(errors.WithMessage(err, - "unable to migrate up")) - } - } else { - if err = migration.Down(); err != nil && - err.Error() != "no change" { - return errors.WithStack(errors.WithMessage(err, - "unable to migrate down")) - } - } - return nil -} - func (d *DB) PingRoutine(interval time.Duration) { ticker := time.NewTicker(interval) done := make(chan bool) - for { select { case <-done: @@ -131,7 +78,7 @@ func (d *DB) PingRoutine(interval time.Duration) { if err := closeConn(d.Conn); err != nil { log.Error("failed to close db connection", "error", err, "ping_at", t) } - d.Conn, err = openDBConnection(d.URI, "pgx") + d.Conn, err = openDBConnection(d.URI, dbDriver) if err != nil { log.Error("failed to reconnect", "error", err, "ping_at", t) } diff --git a/internal/handlers/auth.go b/internal/handlers/auth.go index e7eca50..0287960 100644 --- a/internal/handlers/auth.go +++ b/internal/handlers/auth.go @@ -11,6 +11,8 @@ import ( "net/http" "strings" "time" + + "golang.org/x/crypto/bcrypt" ) func abortWithError(w http.ResponseWriter, msg string) { @@ -18,7 +20,7 @@ func abortWithError(w http.ResponseWriter, msg string) { tmpl.ExecuteTemplate(w, "error", msg) } -func (h *Handlers) HandleLogin(w http.ResponseWriter, r *http.Request) { +func (h *Handlers) HandleSignup(w http.ResponseWriter, r *http.Request) { r.ParseForm() username := r.PostFormValue("username") if username == "" { @@ -34,7 +36,24 @@ func (h *Handlers) HandleLogin(w http.ResponseWriter, r *http.Request) { abortWithError(w, msg) return } + // TODO: make sure username does not exists cleanName := utils.RemoveSpacesFromStr(username) + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), 8) + // create user in db + now := time.Now() + nextMidnight := time.Date(now.Year(), now.Month(), now.Day(), + 0, 0, 0, 0, time.UTC).Add(time.Hour * 24) + newUser := &models.UserScore{ + Username: cleanName, Password: string(hashedPassword), + BurnTime: nextMidnight, CreatedAt: now, + } + if err := h.repo.DBUserScoreCreate(newUser); err != nil { + msg := "failed to create user" + h.log.Error(msg, "user", newUser) + abortWithError(w, msg) + return + } + // TODO: login user cookie, err := h.makeCookie(cleanName, r.RemoteAddr) if err != nil { h.log.Error("failed to login", "error", err) @@ -47,12 +66,33 @@ func (h *Handlers) HandleLogin(w http.ResponseWriter, r *http.Request) { if err != nil { panic(err) } + tmpl.ExecuteTemplate(w, "main", newUser) +} + +func (h *Handlers) HandleLogin(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + username := r.PostFormValue("username") + if username == "" { + msg := "username not provided" + h.log.Error(msg) + abortWithError(w, msg) + return + } + password := r.PostFormValue("password") + if password == "" { + msg := "password not provided" + h.log.Error(msg) + abortWithError(w, msg) + return + } + cleanName := utils.RemoveSpacesFromStr(username) + tmpl, err := template.ParseGlob("components/*.html") + if err != nil { + panic(err) + } userScore, err := h.repo.DBUserScoreGet(cleanName) if err != nil { h.log.Warn("got db err", "err", err) - if err := h.repo.DBUserScoreCreate(&us); err != nil { - panic(err) - } tmpl.ExecuteTemplate(w, "main", nil) return } @@ -60,6 +100,14 @@ func (h *Handlers) HandleLogin(w http.ResponseWriter, r *http.Request) { if err != nil { panic(err) } + cookie, err := h.makeCookie(cleanName, r.RemoteAddr) + if err != nil { + h.log.Error("failed to login", "error", err) + abortWithError(w, err.Error()) + return + } + http.SetCookie(w, cookie) + // http.Redirect(w, r, "/", 302) tmpl.ExecuteTemplate(w, "main", userScore) } diff --git a/internal/handlers/main.go b/internal/handlers/main.go index aa9db4f..e87c74f 100644 --- a/internal/handlers/main.go +++ b/internal/handlers/main.go @@ -39,13 +39,6 @@ func NewHandlers( return h } -// FIXME: global userscore for test -var us = models.UserScore{ - Username: "test", - BurnTime: time.Now().Add(time.Duration(24) * time.Hour), - CreatedAt: time.Now(), -} - func (h *Handlers) Ping(w http.ResponseWriter, r *http.Request) { h.log.Info("got ping request") w.Write([]byte("pong")) @@ -70,10 +63,7 @@ func (h *Handlers) MainPage(w http.ResponseWriter, r *http.Request) { userScore, err := h.repo.DBUserScoreGet(username) if err != nil { h.log.Warn("got db err", "err", err) - if err := h.repo.DBUserScoreCreate(&us); err != nil { - panic(err) - } - tmpl.ExecuteTemplate(w, "main", us) + tmpl.ExecuteTemplate(w, "main", nil) return } userScore.Actions, err = h.repo.DBActionList(username) @@ -120,8 +110,10 @@ func (h *Handlers) HandleForm(w http.ResponseWriter, r *http.Request) { Repeatable: repeat, CreatedAt: time.Now(), } - // TODO: get username from ctx - userScore, err := h.repo.DBUserScoreGet("test") + // get username from ctx + username := r.Context().Value("username").(string) + h.log.Info("got username from ctx", "username", username) + userScore, err := h.repo.DBUserScoreGet(username) if err != nil { panic(err) } @@ -135,11 +127,11 @@ func (h *Handlers) HandleForm(w http.ResponseWriter, r *http.Request) { func (h *Handlers) UserScoreWithActionsByUsername( username string, ) (*models.UserScore, error) { - userScore, err := h.repo.DBUserScoreGet("test") + userScore, err := h.repo.DBUserScoreGet(username) if err != nil { return nil, err } - list, err := h.repo.DBActionList("test") + list, err := h.repo.DBActionList(username) if err != nil { return nil, err } @@ -149,18 +141,30 @@ func (h *Handlers) UserScoreWithActionsByUsername( func (h *Handlers) HandleDoneAction(w http.ResponseWriter, r *http.Request) { r.ParseForm() - h.log.Info("got done request", "payload", r.PostForm) actionName := r.PostFormValue("name") - h.log.Info("got postform request", "name", actionName) + username := r.Context().Value("username").(string) + h.log.Info("got postform request", "name", actionName, + "username", username) + userScore, err := h.UserScoreWithActionsByUsername(username) + if err != nil { + panic(err) + } + // get action by name + action, err := h.repo.DBActionGetByName(actionName) + magnitude := int8(action.Magnitude) + if action.Type == models.ActionTypeMinus { + magnitude *= -1 + } + // change counter of user score + userScore.Score += magnitude + // disable action if repetable if err := h.repo.DBActionDone(actionName); err != nil { panic(err) } - userScore, err := h.UserScoreWithActionsByUsername("test") - if err != nil { + // update score in db + if err := h.repo.DBUserScoreUpdate(userScore); err != nil { panic(err) } - // change counter of user score - // get action by name tmpl := template.Must(template.ParseGlob("components/*.html")) tmpl.ExecuteTemplate(w, "main", userScore) } diff --git a/internal/models/models.go b/internal/models/models.go index bd38eaf..71fb358 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -13,6 +13,7 @@ type ( UserScore struct { ID uint32 `db:"id"` Username string `db:"username"` + Password string `db:"password"` Actions []Action BurnTime time.Time `db:"burn_time"` Score int8 `db:"score"` diff --git a/internal/server/router.go b/internal/server/router.go index 3e8785f..ae68418 100644 --- a/internal/server/router.go +++ b/internal/server/router.go @@ -24,7 +24,7 @@ func (srv *server) ListenToRequests() { mux.HandleFunc("POST /", h.HandleForm) mux.HandleFunc("POST /done", h.HandleDoneAction) mux.HandleFunc("POST /login", h.HandleLogin) - // mux.HandleFunc("POST /signup", h.HandleLogin) + mux.HandleFunc("POST /signup", h.HandleSignup) // ====== elements ====== mux.HandleFunc("GET /showform", h.ServeShowForm) diff --git a/pkg/cache/main.go b/pkg/cache/main.go index d617f49..2aac109 100644 --- a/pkg/cache/main.go +++ b/pkg/cache/main.go @@ -42,7 +42,7 @@ func init() { timeMap: make(map[string]time.Time), lock: &sync.RWMutex{}, } - MemCache.StartExpiryRoutine(time.Minute) + MemCache.StartExpiryRoutine(time.Hour * 24 * 30) MemCache.StartBackupRoutine(time.Minute) } |