diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index e6e478d..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Build - -on: - push: - branches: - - main - pull_request: - types: [opened, synchronize, reopened] - -jobs: - build: - name: Build and analyze - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - uses: SonarSource/sonarqube-scan-action@v5 - env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} - # If you wish to fail your job when the Quality Gate is red, uncomment the - # following lines. This would typically be used to fail a deployment. - # We do not recommend to use this in a pull request. Prefer using pull request - # decoration instead. - # - uses: SonarSource/sonarqube-quality-gate-action@v1 - # timeout-minutes: 5 - # env: - # SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml index b0eff9b..14784d3 100644 --- a/.github/workflows/sonarqube.yml +++ b/.github/workflows/sonarqube.yml @@ -5,7 +5,7 @@ on: branches: - main pull_request: - + types: [opened, synchronize, reopened] jobs: build: @@ -15,8 +15,16 @@ jobs: steps: - uses: actions/checkout@v4 with: - fetch-depth: 0 + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - uses: SonarSource/sonarqube-scan-action@v6 env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} \ No newline at end of file + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + # If you wish to fail your job when the Quality Gate is red, uncomment the + # following lines. This would typically be used to fail a deployment. + # We do not recommend to use this in a pull request. Prefer using pull request + # decoration instead. + # - uses: SonarSource/sonarqube-quality-gate-action@v1 + # timeout-minutes: 5 + # env: + # SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/README.md b/README.md index 48fa055..2925e45 100644 --- a/README.md +++ b/README.md @@ -3,21 +3,22 @@ A simple interface for logging and displaying time since a certain event has occured, allowing for CSHer's to track how long its been since a prior event. Heavily inspired off the "Days since last..." meme format. -This project uses Golang, [Gin](https://fastapi.tiangolo.com/), HTML/CSS, and Javascript. +This project uses Golang, [Gin](https://gin-gonic.com/en/), HTML/CSS, and Javascript. This project ALSO uses a modified version of bootstrap 5! Check it out [here!](https://github.com/ComputerScienceHouse/csh-material-bootstrap/tree/bootstrap-5) -## Installing +## Local Development +### Installing 1. Clone and cd into the repo: git clone https://github.com/WeatherGod3218/counters >> (OPTIONAL): Make another branch if your working on a large thing! -## Setup +### Setup 1. Make sure you have docker installed >> (OPTIONAL): You can use docker compose as well!! 2. Copy the .env.template file, rename it to .env and place it in the root folder 3. Ask an RTP for counters secrets, add them to the .env accordingly -## Run +### Run Counters is containerized through a docker file. @@ -30,7 +31,7 @@ Counters is containerized through a docker file. docker run -p 8080:80 Counters ``` -## Docker Compose +### Docker Compose Counters also has support for Docker Compose, a extended version of docker that simplifies the steps. @@ -38,3 +39,8 @@ Counters also has support for Docker Compose, a extended version of docker that ``` docker compose up ``` + +## TODO +- [] Add API Integration +- [] Add Logging (similar to Votes "Actions") +- [] Time Zone support diff --git a/api.go b/api.go index cb23620..5491f03 100644 --- a/api.go +++ b/api.go @@ -11,8 +11,6 @@ import ( "go.mongodb.org/mongo-driver/v2/bson" ) -const tempName string = "A Person!" - func translateTime(inputTime string) time.Time { timeZone, _ := time.LoadLocation("America/New_York") @@ -26,13 +24,11 @@ func translateTime(inputTime string) time.Time { if timeConverted.After(currentTime) { timeConverted = currentTime } - return timeConverted } func GetHomePage(c *gin.Context) { - // This is intentionally left unprotected - // A user may be unable to vote but should still be able to see a list of polls + user := GetUserData(c) counters, err := database.GetAllCounters(c) @@ -47,51 +43,76 @@ func GetHomePage(c *gin.Context) { c.HTML(http.StatusOK, "index.html", gin.H{ "Counters": counters, + "Username": user.Username, + "FullName": user.FullName, + "EBoard": IsEboard(user), + "RTP": IsActiveRTP(user), }) } func GetCreatePage(c *gin.Context) { - c.HTML(http.StatusOK, "create.tmpl", gin.H{}) + user := GetUserData(c) + + c.HTML(http.StatusOK, "create.tmpl", gin.H{ + "Username": user.Username, + "FullName": user.FullName, + "EBoard": IsEboard(user), + "RTP": IsActiveRTP(user), + }) } func GetResetPage(c *gin.Context) { + user := GetUserData(c) + idToUse := c.Param("id") c.HTML(http.StatusOK, "reset.tmpl", gin.H{ - "Id": idToUse, + "Id": idToUse, + "Username": user.Username, + "FullName": user.FullName, + "EBoard": IsEboard(user), + "RTP": IsActiveRTP(user), }) } func LoadCounter(c *gin.Context) { idToUse := c.Param("id") + user := GetUserData(c) - counter, cError := database.GetCounterFromId(c, idToUse) - if cError != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": cError.Error()}) + counter, err := database.GetCounterFromId(c, idToUse) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } - history, hError := database.GetHistoryFromId(c, idToUse) - if hError != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": hError.Error()}) + history, err := database.GetHistoryFromId(c, idToUse) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.HTML(200, "counter.tmpl", gin.H{ "Id": counter.Id.Hex(), + "CounterID": counter.UserID, "Title": counter.Title, "Description": counter.Description, "Timestamp": counter.LastReset.Timestamp, "History": history.History, + "Username": user.Username, + "FullName": user.FullName, + "UserID": user.Uuid, + "EBoard": IsEboard(user), + "RTP": IsActiveRTP(user), }) } func ResetCounter(c *gin.Context) { resetTime := translateTime(c.PostForm("reset-time")) + user := GetUserData(c) reset := &database.Reset{ Id: bson.NewObjectID(), - Reporter: tempName, - Instigator: c.PostForm("reset-user"), + UserID: user.Uuid, + Reporter: user.Username, Description: c.PostForm("reset-description"), Timestamp: resetTime, } @@ -108,18 +129,20 @@ func ResetCounter(c *gin.Context) { func CreateCounter(c *gin.Context) { resetTime := translateTime(c.PostForm("reset-time")) + user := GetUserData(c) reset := &database.Reset{ Id: bson.NewObjectID(), - Reporter: tempName, - Instigator: c.PostForm("reset-user"), + UserID: user.Uuid, + Reporter: user.Username, Description: c.PostForm("reset-description"), Timestamp: resetTime, } counter := &database.Counter{ Id: bson.NewObjectID(), - CreatedBy: tempName, + UserID: user.Uuid, + CreatedBy: user.Username, Title: c.PostForm("title"), Description: c.PostForm("description"), LastReset: *reset, @@ -133,3 +156,34 @@ func CreateCounter(c *gin.Context) { c.Redirect(http.StatusFound, "/counters/"+counter.IDHex()) } + +func DeleteReset(c *gin.Context) { + counterIdString := c.PostForm("counterId") + resetId, _ := bson.ObjectIDFromHex(c.PostForm("resetId")) + counterId, _ := bson.ObjectIDFromHex(counterIdString) + + exists, err := database.DeleteReset(c, counterId, resetId) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + if exists { + c.Redirect(http.StatusFound, "/counters/"+counterIdString) + return + } + + c.Redirect(http.StatusFound, "/") +} + +func DeleteCounter(c *gin.Context) { + counterId, _ := bson.ObjectIDFromHex(c.PostForm("counterId")) + + err := database.DeleteCounter(c, counterId) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.Redirect(http.StatusFound, "/") +} diff --git a/database/counter.go b/database/counter.go index 242ec48..54ffc31 100644 --- a/database/counter.go +++ b/database/counter.go @@ -2,14 +2,18 @@ package database import ( "context" - "sort" "time" "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo/options" + + "github.com/WeatherGod3218/counters/logging" + "github.com/sirupsen/logrus" ) type Counter struct { Id bson.ObjectID `bson:"_id,omitempty"` + UserID string `bson:"uuid"` CreatedBy string `bson:"createdBy"` Title string `bson:"title"` Description string `bson:"description"` @@ -81,7 +85,19 @@ func GetAllCounters(ctx context.Context) ([]*Counter, error) { return counters, nil } -func (counter *Counter) Reset(ctx context.Context, reset *Reset) error { +func DeleteCounter(ctx context.Context, counterId bson.ObjectID) error { + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + counter, err := GetCounterFromId(context.Background(), counterId.Hex()) + if err != nil { + logging.Logger.WithFields(logrus.Fields{"error": err, "module": "reset", "method": "DeleteReset"}).Fatal("error deleting the counter!") + } + + return counter.Delete(ctx) +} + +func (counter *Counter) Delete(ctx context.Context) error { ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() @@ -92,22 +108,66 @@ func (counter *Counter) Reset(ctx context.Context, reset *Reset) error { defer session.EndSession(context.Background()) _, err = session.WithTransaction(ctx, func(sessCtx context.Context) (any, error) { + _, err = Client.Database(db).Collection("history").DeleteOne( + sessCtx, + bson.M{"_id": counter.Id}, + ) - var history History + if err != nil { + return nil, err + } + + _, err = Client.Database(db).Collection("counters").DeleteOne( + sessCtx, + bson.M{"_id": counter.Id}, + ) - err := Client.Database(db).Collection("history").FindOne(sessCtx, bson.M{"_id": counter.Id}).Decode(&history) if err != nil { return nil, err } - resetHistory := history.History - resetHistory = append(resetHistory, *reset) - sort.Slice(resetHistory, func(i, j int) bool { - return resetHistory[i].Timestamp.After(resetHistory[j].Timestamp) - }) + return nil, nil + }) + + if err != nil { + logging.Logger.WithFields(logrus.Fields{"error": err, "module": "counter", "method": "Delete", "counter": counter.Id}).Warn("error deleting the counter!") + return err + } + + return nil +} + +func (counter *Counter) Update(ctx context.Context) (bool, error) { + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + session, err := Client.StartSession() + if err != nil { + return false, err + } + defer session.EndSession(context.Background()) + + counterEmpty := false - lastReset := resetHistory[0] + _, err = session.WithTransaction(ctx, func(sessCtx context.Context) (any, error) { + var history History + + err = Client.Database(db).Collection("history").FindOne( + sessCtx, + bson.M{"_id": counter.Id}, + options.FindOne().SetProjection(bson.M{"history": bson.M{"$slice": 1}}), + ).Decode(&history) + if err != nil { + return nil, err + } + + if len(history.History) == 0 { + counterEmpty = true + return nil, nil + } + + lastReset := history.History[0] _, err = Client.Database(db).Collection("counters").UpdateOne( sessCtx, bson.M{"_id": counter.Id}, @@ -117,6 +177,33 @@ func (counter *Counter) Reset(ctx context.Context, reset *Reset) error { return nil, err } + counter.LastReset = lastReset + return nil, nil + }) + + if err != nil { + logging.Logger.WithFields(logrus.Fields{"error": err, "module": "counter", "method": "Update", "counter": counter.Id}).Warn("error updating the counter!") + return false, err + } + + if counterEmpty { + return false, counter.Delete(context.Background()) + } + + return true, nil +} + +func (counter *Counter) Reset(ctx context.Context, reset *Reset) (any, error) { + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + + session, err := Client.StartSession() + if err != nil { + return true, err + } + defer session.EndSession(context.Background()) + + _, err = session.WithTransaction(ctx, func(sessCtx context.Context) (any, error) { _, err = Client.Database(db).Collection("history").UpdateOne( sessCtx, bson.M{"_id": counter.Id}, @@ -131,12 +218,14 @@ func (counter *Counter) Reset(ctx context.Context, reset *Reset) error { return nil, err } - counter.LastReset = lastReset - return nil, nil }) - return err + if err != nil { + logging.Logger.WithFields(logrus.Fields{"error": err, "module": "counter", "method": "Reset", "counter": counter.Id}).Fatal("error updating counters history!") + } + + return counter.Update(context.Background()) } func (c *Counter) IDHex() string { diff --git a/database/database.go b/database/database.go index 3e398c9..ff90694 100644 --- a/database/database.go +++ b/database/database.go @@ -1,3 +1,4 @@ +// Package database contains modules for each struct in the database package database import ( @@ -13,18 +14,10 @@ import ( "go.mongodb.org/mongo-driver/v2/mongo/readpref" ) -type UpsertResult int - -const ( - New UpsertResult = 0 - Updated UpsertResult = 1 -) - var Client *mongo.Client var db = "" -var logger *logrus.Logger = logrus.New() - +// Connects to the MongoDB database func Connect() *mongo.Client { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() @@ -46,6 +39,7 @@ func Connect() *mongo.Client { return client } +// Disconnects from the MongoDB database func Disconnect() { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() diff --git a/database/reset.go b/database/reset.go index 61f55d1..0ba59d5 100644 --- a/database/reset.go +++ b/database/reset.go @@ -1,15 +1,47 @@ package database import ( + "context" "time" + "github.com/WeatherGod3218/counters/logging" + "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/v2/bson" ) type Reset struct { Id bson.ObjectID `bson:"_id,omitempty"` - Instigator string `bson:"instigator"` + UserID string `bson:"uuid"` Reporter string `bson:"reporter"` Description string `bson:"description"` Timestamp time.Time `bson:"timestamp"` } + +func (r *Reset) IDHex() string { + return r.Id.Hex() +} + +func DeleteReset(ctx context.Context, counterId bson.ObjectID, resetId bson.ObjectID) (bool, error) { + ctx, cancel := context.WithTimeout(ctx, 15*time.Second) + defer cancel() + + _, err := Client.Database(db).Collection("history").UpdateOne( + ctx, + bson.M{"_id": counterId}, + bson.M{"$pull": bson.M{ + "history": bson.M{"_id": resetId}, + }}, + ) + + if err != nil { + return false, err + } + + counter, err := GetCounterFromId(ctx, counterId.Hex()) + if err != nil { + logging.Logger.WithFields(logrus.Fields{"error": err, "module": "reset", "method": "DeleteReset"}).Warn("error deleting the counter!") + return false, err + } + + return counter.Update(ctx) +} diff --git a/go.mod b/go.mod index c6a3df9..4496206 100644 --- a/go.mod +++ b/go.mod @@ -3,34 +3,36 @@ module github.com/WeatherGod3218/counters go 1.25.7 require ( - github.com/computersciencehouse/csh-auth/v2 v2.0.0 + github.com/computersciencehouse/csh-auth/v2 v2.0.1 github.com/gin-gonic/gin v1.12.0 github.com/sirupsen/logrus v1.9.4 go.mongodb.org/mongo-driver/v2 v2.6.0 ) require ( - github.com/bytedance/gopkg v0.1.3 // indirect - github.com/bytedance/sonic v1.15.0 // indirect - github.com/bytedance/sonic/loader v0.5.0 // indirect - github.com/cloudwego/base64x v0.1.6 // indirect + github.com/bytedance/gopkg v0.1.4 // indirect + github.com/bytedance/sonic v1.15.1 // indirect + github.com/bytedance/sonic/loader v0.5.1 // indirect + github.com/cloudwego/base64x v0.1.7 // indirect github.com/coreos/go-oidc v2.5.0+incompatible // indirect - github.com/gabriel-vasile/mimetype v1.4.12 // indirect - github.com/gin-contrib/sse v1.1.0 // indirect + github.com/coreos/go-oidc/v3 v3.18.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.13 // indirect + github.com/gin-contrib/sse v1.1.1 // indirect + github.com/go-jose/go-jose/v4 v4.1.4 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.30.1 // indirect - github.com/goccy/go-json v0.10.5 // indirect + github.com/go-playground/validator/v10 v10.30.2 // indirect + github.com/goccy/go-json v0.10.6 // indirect github.com/goccy/go-yaml v1.19.2 // indirect github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.6 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/pelletier/go-toml/v2 v2.3.1 // indirect github.com/pquerna/cachecontrol v0.2.0 // indirect github.com/quic-go/qpack v0.6.0 // indirect github.com/quic-go/quic-go v0.59.0 // indirect @@ -40,13 +42,13 @@ require ( github.com/xdg-go/scram v1.2.0 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect - golang.org/x/arch v0.22.0 // indirect - golang.org/x/crypto v0.50.0 // indirect - golang.org/x/net v0.52.0 // indirect + golang.org/x/arch v0.27.0 // indirect + golang.org/x/crypto v0.51.0 // indirect + golang.org/x/net v0.54.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sync v0.20.0 // indirect - golang.org/x/sys v0.43.0 // indirect - golang.org/x/text v0.36.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + golang.org/x/sys v0.44.0 // indirect + golang.org/x/text v0.37.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect ) diff --git a/go.sum b/go.sum index 17c6386..454c9e7 100644 --- a/go.sum +++ b/go.sum @@ -1,24 +1,42 @@ github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= +github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM= +github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4= github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE= github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k= +github.com/bytedance/sonic v1.15.1 h1:nJD5PmM0vY7J8CT6MxoqbVAAMhkSmV2HgRAUrrpLoOw= +github.com/bytedance/sonic v1.15.1/go.mod h1:mT2NbXunuaEbnZ+mRIX/vYqKISmgEuHFDI4UzmKx2SA= github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE= github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= +github.com/bytedance/sonic/loader v0.5.1 h1:Ygpfa9zwRCCKSlrp5bBP/b/Xzc3VxsAW+5NIYXrOOpI= +github.com/bytedance/sonic/loader v0.5.1/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= +github.com/cloudwego/base64x v0.1.7 h1:NppS+Fgzg5ovhn4NkUXaDT3x9jldgH5ToMCqzBSi2zI= +github.com/cloudwego/base64x v0.1.7/go.mod h1:Cu1PV9zfrSf7ET2tIbWbbEy7jO7HHJ13q4X2SQ8aWYg= github.com/computersciencehouse/csh-auth/v2 v2.0.0 h1:uRP8Ti/pb1SaSSBvhk3dLVpHagGdGIj216fQXkYhT9E= github.com/computersciencehouse/csh-auth/v2 v2.0.0/go.mod h1:JelmcPFBLpo8wnmErF4Zoa4UJKi0psgUDpcuTq6pWbY= +github.com/computersciencehouse/csh-auth/v2 v2.0.1 h1:rtGa9cBDZJZZJ8aeGefwAM/rzPMxWNAGDwuVDZI80ro= +github.com/computersciencehouse/csh-auth/v2 v2.0.1/go.mod h1:uL/2UDr9GJlAQORsn+rmFc18YkBsZPymYJbwb+uTRig= github.com/coreos/go-oidc v2.5.0+incompatible h1:6W0vGJR3Tu0r0PwfmjOrRZSlfxeEln8dsejt3ZWIvwo= github.com/coreos/go-oidc v2.5.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-oidc/v3 v3.18.0 h1:V9orjXynvu5wiC9SemFTWnG4F45v403aIcjWo0d41+A= +github.com/coreos/go-oidc/v3 v3.18.0/go.mod h1:DYCf24+ncYi+XkIH97GY1+dqoRlbaSI26KVTCI9SrY4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM= +github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= +github.com/gin-contrib/sse v1.1.1 h1:uGYpNwTacv5R68bSGMapo62iLTRa9l5zxGCps4hK6ko= +github.com/gin-contrib/sse v1.1.1/go.mod h1:QXzuVkA0YO7o/gun03UI1Q+FTI8ZV/n5t03kIQAI89s= github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8= github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc= +github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= +github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -27,8 +45,12 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w= github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= +github.com/go-playground/validator/v10 v10.30.2 h1:JiFIMtSSHb2/XBUbWM4i/MpeQm9ZK2xqPNk8vgvu5JQ= +github.com/go-playground/validator/v10 v10.30.2/go.mod h1:mAf2pIOVXjTEBrwUMGKkCWKKPs9NheYGabeB04txQSc= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= +github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= @@ -48,6 +70,8 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= 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/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 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= @@ -55,6 +79,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc= +github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= 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/pquerna/cachecontrol v0.2.0 h1:vBXSNuE5MYP9IJ5kjsdo8uq+w41jSPgvba2DEnkRx9k= @@ -96,16 +122,22 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= +golang.org/x/arch v0.27.0 h1:0WNVcR8u9yFz8j5FvdHpgwNp3FS5U4guYdzHwEiGjoU= +golang.org/x/arch v0.27.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/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.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= +golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -120,6 +152,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= +golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= 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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -128,12 +162,16 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= diff --git a/main.go b/main.go index 03f8cd6..e1ec033 100644 --- a/main.go +++ b/main.go @@ -8,12 +8,15 @@ import ( "github.com/gin-gonic/gin" "github.com/WeatherGod3218/counters/logging" - cshAuth "github.com/computersciencehouse/csh-auth/v2" "github.com/sirupsen/logrus" + + cshAuth "github.com/computersciencehouse/csh-auth/v2" ) var DEV_FORCE_IS_EBOARD bool = os.Getenv("DEV_FORCE_IS_EBOARD") == "true" +var oidcClient = OIDCClient{} + func main() { database.Client = database.Connect() @@ -42,13 +45,16 @@ func main() { router.Use(auth.CookieMiddleware()) router.GET("/", GetHomePage) - router.GET("counters/:id", LoadCounter) + router.GET("/counters/:id", LoadCounter) router.GET("/create", GetCreatePage) router.POST("/create", CreateCounter) - router.GET("reset/:id", GetResetPage) - router.POST("reset/:id", ResetCounter) + router.GET("/reset/:id", GetResetPage) + router.POST("/reset/:id", ResetCounter) + + router.DELETE("/delete/counter", DeleteCounter) + router.DELETE("/delete/reset", DeleteReset) router.Run(":8080") } diff --git a/templates/counter.tmpl b/templates/counter.tmpl index 6a2fc03..51931af 100644 --- a/templates/counter.tmpl +++ b/templates/counter.tmpl @@ -1,6 +1,48 @@ {{ define "counter.tmpl"}} {{ template "header.tmpl" . }} + + + +

Days Since {{.Title}}

{{.Description}}
@@ -8,37 +50,65 @@
+ + {{if or .Eboard .RTP (eq .UserID .CounterID)}} + + {{end}}

@@ -48,6 +118,17 @@ (() => { 'use strict' + document.getElementById("deleteReset").addEventListener("show.bs.modal", function(event) { + let button = event.relatedTarget + document.getElementById("reset-modal-reset-id").value = button.getAttribute("data-reset-id") + document.getElementById("reset-modal-counter-id").value = button.getAttribute("data-counter-id") + }) + + document.getElementById("deleteCounter").addEventListener("show.bs.modal", function(event) { + let button = event.relatedTarget + document.getElementById("counter-modal-counter-id").value = button.getAttribute("data-counter-id") + }) + document.querySelectorAll(".days-since").forEach(el => { const days = Math.floor((Date.now() - new Date(el.dataset.timestamp)) / 86400000); el.textContent = days; diff --git a/templates/create.tmpl b/templates/create.tmpl index c88671b..374a944 100644 --- a/templates/create.tmpl +++ b/templates/create.tmpl @@ -10,7 +10,7 @@ type="text" class="form-control" name="title" - placeholder="What are we counting?" + placeholder="Days Since Last ..." required >
@@ -26,16 +26,6 @@
First Reset
-
- - -
Days Since Last...

- +
-