diff --git a/Dockerfile b/Dockerfile
index a5d6f36..2158892 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -10,7 +10,9 @@ COPY .git .
RUN npm ci
COPY web/ .
-RUN npm run build
+
+RUN GIT_DESCRIBE="$(git describe --always --dirty --tags 2>/dev/null || echo unknown)" \
+ npm run build
# go builder
@@ -25,6 +27,9 @@ RUN go mod download
COPY . .
+RUN go install github.com/swaggo/swag/cmd/swag@latest
+RUN swag init --parseDependency
+
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /makedotcsh
diff --git a/database/db.go b/database/db.go
index 6b566af..88918c5 100644
--- a/database/db.go
+++ b/database/db.go
@@ -66,6 +66,19 @@ func (database *DatabaseHelper) GetArea(areaID int) (models.Area, error) {
return area, nil
}
+func (database *DatabaseHelper) DeleteArea(areaID int) error {
+ _, err := database.DB.Exec(
+ "DELETE FROM areas WHERE id = $1",
+ areaID,
+ )
+
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
func (database *DatabaseHelper) GetAllAreas() ([]models.Area, error) {
rows, err := database.DB.Query("SELECT id, name, description, ldapgroup, photourl FROM areas")
if err != nil {
@@ -135,7 +148,7 @@ func (database *DatabaseHelper) GetTraining(trainingID int, includeAnswers bool)
var currentQuestion *models.Question
lastQuestionId := 0
- query := "SELECT id, title, required_correct, description FROM trainings WHERE id = $1"
+ query := "SELECT id, title, required_correct, description, show_answers FROM trainings WHERE id = $1"
row := database.DB.QueryRow(query, trainingID)
@@ -144,6 +157,7 @@ func (database *DatabaseHelper) GetTraining(trainingID int, includeAnswers bool)
&training.Title,
&training.RequiredCorrect,
&training.Description,
+ &training.ShowAnswers,
)
if err != nil {
return models.Training{}, err
@@ -233,10 +247,11 @@ func (database *DatabaseHelper) CreateTraining(training models.CreateTrainingReq
var trainingId int
err = tx.QueryRow(
- "INSERT INTO trainings (title, required_correct, description) VALUES ($1, $2, $3) RETURNING id",
+ "INSERT INTO trainings (title, required_correct, description, showAnswers) VALUES ($1, $2, $3, $4) RETURNING id",
training.Title,
training.RequiredCorrect,
training.Description,
+ training.ShowAnswers,
).Scan(&trainingId)
if err != nil {
@@ -286,10 +301,11 @@ func (database *DatabaseHelper) UpdateTraining(training models.CreateTrainingReq
defer tx.Rollback()
_, err = tx.Exec(
- "UPDATE trainings SET title = $1, required_correct = $2, description = $3 WHERE id = $4",
+ "UPDATE trainings SET title = $1, required_correct = $2, description = $3, show_answers = $4 WHERE id = $5",
training.Title,
training.RequiredCorrect,
training.Description,
+ training.ShowAnswers,
trainingId,
)
@@ -562,3 +578,152 @@ func (database *DatabaseHelper) GetTrainingAnswers(trainingID int) (map[int]stri
return answers, nil
}
+
+func (database *DatabaseHelper) GetResource(rID int) (models.Resource, error) {
+ row := database.DB.QueryRow("SELECT id, name, description, url FROM resources WHERE id = $1", rID)
+
+ var resource models.Resource
+
+ err := row.Scan(
+ &resource.ID,
+ &resource.Name,
+ &resource.Description,
+ &resource.URL,
+ )
+
+ if err != nil {
+ return models.Resource{}, err
+ }
+
+ return resource, nil
+}
+
+func (database *DatabaseHelper) GetAllResources() ([]models.Resource, error) {
+ rows, err := database.DB.Query("SELECT id, name, description, url FROM resources")
+ if err != nil {
+ return []models.Resource{}, nil
+ }
+
+ var resources []models.Resource = []models.Resource{}
+
+ for rows.Next() {
+ var r models.Resource
+
+ err := rows.Scan(
+ &r.ID,
+ &r.Name,
+ &r.Description,
+ &r.URL,
+ )
+
+ if err != nil {
+ return []models.Resource{}, nil
+ }
+
+ resources = append(resources, r)
+ }
+
+ return resources, nil
+}
+
+func (database *DatabaseHelper) GetAreaResources(area int) ([]models.Resource, error) {
+ rows, err := database.DB.Query("SELECT resource_id FROM area_resources WHERE area_id = $1", area)
+ if err != nil {
+ return []models.Resource{}, nil
+ }
+
+ var resources []models.Resource = []models.Resource{}
+
+ for rows.Next() {
+ var resourceID int
+
+ err := rows.Scan(
+ &resourceID,
+ )
+
+ if err != nil {
+ return []models.Resource{}, err
+ }
+
+ // fetch this training, add to array
+ resource, err := database.GetResource(resourceID)
+ if err != nil {
+ return []models.Resource{}, err
+ }
+
+ resources = append(resources, resource)
+ }
+
+ return resources, nil
+}
+
+func (database *DatabaseHelper) CreateResource(r models.Resource) error {
+ _, err := database.DB.Exec(
+ "INSERT INTO resources (name, description, url) VALUES ($1, $2, $3)",
+ r.Name,
+ r.Description,
+ r.URL,
+ )
+
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (database *DatabaseHelper) UpdateResource(r models.Resource, id int) error {
+ _, err := database.DB.Exec(
+ "UPDATE resources SET name = $1, description = $2, url = $3 WHERE id = $4",
+ r.Name,
+ r.Description,
+ r.URL,
+ id,
+ )
+
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (database *DatabaseHelper) DeleteResource(rID int) error {
+ _, err := database.DB.Exec(
+ "DELETE FROM resources WHERE id = $1",
+ rID,
+ )
+
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (database *DatabaseHelper) AddResourceToArea(areaID int, resourceIDs []int) error {
+ for _, resourceID := range resourceIDs {
+ _, err := database.DB.Exec(
+ "INSERT INTO area_resources (area_id, resource_id) VALUES ($1, $2)",
+ areaID, resourceID,
+ )
+
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (database *DatabaseHelper) RemoveResourceFromArea(areaID int, resourceID int) error {
+ _, err := database.DB.Exec(
+ "DELETE FROM area_resources WHERE area_id = $1 AND resource_id = $2",
+ areaID, resourceID,
+ )
+
+ if err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/database/migrations/0003_resources.up.sql b/database/migrations/0003_resources.up.sql
new file mode 100644
index 0000000..c6c78ba
--- /dev/null
+++ b/database/migrations/0003_resources.up.sql
@@ -0,0 +1,14 @@
+CREATE TABLE resources (
+ id SERIAL PRIMARY KEY,
+ name TEXT NOT NULL,
+ description TEXT NOT NULL,
+ url TEXT NOT NULL
+);
+
+CREATE TABLE area_resources (
+ area_id INTEGER NOT NULL,
+ resource_id INTEGER NOT NULL,
+ PRIMARY KEY (area_id, resource_id),
+ FOREIGN KEY (area_id) REFERENCES areas(id) ON DELETE CASCADE,
+ FOREIGN KEY (resource_id) REFERENCES resources(id) ON DELETE CASCADE
+);
\ No newline at end of file
diff --git a/database/migrations/0004_training.up.sql b/database/migrations/0004_training.up.sql
new file mode 100644
index 0000000..2064918
--- /dev/null
+++ b/database/migrations/0004_training.up.sql
@@ -0,0 +1 @@
+ALTER TABLE trainings ADD show_answers BOOLEAN NOT NULL DEFAULT FALSE;
\ No newline at end of file
diff --git a/docs/docs.go b/docs/docs.go
index 4240bef..5dddae9 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -172,6 +172,48 @@ const docTemplate = `{
}
}
}
+ },
+ "delete": {
+ "description": "Deletes an area",
+ "consumes": [
+ "application/json"
+ ],
+ "tags": [
+ "areas"
+ ],
+ "summary": "Deletes an area",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Area ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No Content"
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
}
},
"/me": {
@@ -229,23 +271,23 @@ const docTemplate = `{
}
}
},
- "/trainings": {
+ "/resources": {
"get": {
- "description": "Returns all trainings",
+ "description": "Returns all resources",
"produces": [
"application/json"
],
"tags": [
- "trainings"
+ "resources"
],
- "summary": "Get all trainings",
+ "summary": "Get all resources",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
- "$ref": "#/definitions/models.Training"
+ "$ref": "#/definitions/models.Resource"
}
}
},
@@ -256,18 +298,56 @@ const docTemplate = `{
}
}
}
+ },
+ "post": {
+ "description": "Creates a new resource",
+ "consumes": [
+ "application/json"
+ ],
+ "tags": [
+ "resources"
+ ],
+ "summary": "Create resource",
+ "parameters": [
+ {
+ "description": "Resource",
+ "name": "resource",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/models.Resource"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "Created"
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
}
},
- "/trainings/area/{id}": {
+ "/resources/area/{id}": {
"get": {
- "description": "Returns all trainings required for an area",
+ "description": "Returns all resources associated with an area",
"produces": [
"application/json"
],
"tags": [
- "trainings"
+ "resources"
],
- "summary": "Get area trainings",
+ "summary": "Get area resources",
"parameters": [
{
"type": "integer",
@@ -283,7 +363,7 @@ const docTemplate = `{
"schema": {
"type": "array",
"items": {
- "$ref": "#/definitions/models.Training"
+ "$ref": "#/definitions/models.Resource"
}
}
},
@@ -302,14 +382,17 @@ const docTemplate = `{
}
},
"post": {
- "description": "Associates one or more trainings with an area",
+ "description": "Adds resources to an area",
"consumes": [
"application/json"
],
+ "produces": [
+ "application/json"
+ ],
"tags": [
- "trainings"
+ "resources"
],
- "summary": "Add trainings to area",
+ "summary": "Add resources to area",
"parameters": [
{
"type": "integer",
@@ -319,8 +402,8 @@ const docTemplate = `{
"required": true
},
{
- "description": "Training IDs",
- "name": "trainingIds",
+ "description": "Resource IDs",
+ "name": "request",
"in": "body",
"required": true,
"schema": {
@@ -332,8 +415,8 @@ const docTemplate = `{
}
],
"responses": {
- "201": {
- "description": "Created"
+ "200": {
+ "description": "OK"
},
"400": {
"description": "Bad Request",
@@ -350,14 +433,14 @@ const docTemplate = `{
}
},
"delete": {
- "description": "Removes a training requirement from an area",
+ "description": "Removes a resource from an area",
"consumes": [
"application/json"
],
"tags": [
- "trainings"
+ "resources"
],
- "summary": "Remove training from area",
+ "summary": "Remove resource from area",
"parameters": [
{
"type": "integer",
@@ -367,12 +450,12 @@ const docTemplate = `{
"required": true
},
{
- "description": "Training removal request",
+ "description": "Resource removal request",
"name": "request",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/trainings.RemoveTrainingRequest"
+ "$ref": "#/definitions/resources.RemoveResourceRequest"
}
}
],
@@ -395,7 +478,153 @@ const docTemplate = `{
}
}
},
- "/trainings/create": {
+ "/resources/{id}": {
+ "get": {
+ "description": "Returns a resource by ID",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "resources"
+ ],
+ "summary": "Get resource",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Resource ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/models.Resource"
+ }
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ },
+ "put": {
+ "description": "Updates an existing resource",
+ "consumes": [
+ "application/json"
+ ],
+ "tags": [
+ "resources"
+ ],
+ "summary": "Update resource",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Resource ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "Resource",
+ "name": "resource",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/models.Resource"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "Created"
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ },
+ "delete": {
+ "description": "Deletes a resource by ID",
+ "tags": [
+ "resources"
+ ],
+ "summary": "Delete resource",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Resource ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No Content"
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ }
+ },
+ "/trainings": {
+ "get": {
+ "description": "Returns all trainings",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "trainings"
+ ],
+ "summary": "Get all trainings",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/models.Training"
+ }
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ },
"post": {
"description": "Create a new training",
"consumes": [
@@ -435,6 +664,143 @@ const docTemplate = `{
}
}
},
+ "/trainings/area/{id}": {
+ "get": {
+ "description": "Returns all trainings required for an area",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "trainings"
+ ],
+ "summary": "Get area trainings",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Area ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/models.Training"
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ },
+ "post": {
+ "description": "Associates one or more trainings with an area",
+ "consumes": [
+ "application/json"
+ ],
+ "tags": [
+ "trainings"
+ ],
+ "summary": "Add trainings to area",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Area ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "Training IDs",
+ "name": "trainingIds",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "integer"
+ }
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "Created"
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ },
+ "delete": {
+ "description": "Removes a training requirement from an area",
+ "consumes": [
+ "application/json"
+ ],
+ "tags": [
+ "trainings"
+ ],
+ "summary": "Remove training from area",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Area ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "Training removal request",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/trainings.RemoveTrainingRequest"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "Created"
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ }
+ },
"/trainings/{id}": {
"get": {
"description": "Returns a training by ID",
@@ -594,6 +960,46 @@ const docTemplate = `{
}
}
}
+ },
+ "/trainings/{id}/submissions": {
+ "post": {
+ "description": "Submits and grades a completed training",
+ "consumes": [
+ "application/json"
+ ],
+ "tags": [
+ "trainings"
+ ],
+ "summary": "Submits and grades a completed training",
+ "parameters": [
+ {
+ "description": "Training",
+ "name": "training",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/models.Submission"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "Created"
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ }
}
},
"definitions": {
@@ -623,6 +1029,9 @@ const docTemplate = `{
"ldap.UserWUUID": {
"type": "object",
"properties": {
+ "name": {
+ "type": "string"
+ },
"username": {
"type": "string"
},
@@ -680,6 +1089,12 @@ const docTemplate = `{
"$ref": "#/definitions/models.Question"
}
},
+ "requiredCorrect": {
+ "type": "integer"
+ },
+ "showAnswers": {
+ "type": "boolean"
+ },
"title": {
"type": "string"
}
@@ -717,6 +1132,29 @@ const docTemplate = `{
}
}
},
+ "models.Resource": {
+ "type": "object",
+ "properties": {
+ "description": {
+ "type": "string"
+ },
+ "id": {
+ "type": "integer"
+ },
+ "name": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string"
+ }
+ }
+ },
+ "models.Submission": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
"models.Training": {
"type": "object",
"properties": {
@@ -732,11 +1170,25 @@ const docTemplate = `{
"$ref": "#/definitions/models.Question"
}
},
+ "requiredCorrect": {
+ "type": "integer"
+ },
+ "showAnswers": {
+ "type": "boolean"
+ },
"title": {
"type": "string"
}
}
},
+ "resources.RemoveResourceRequest": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer"
+ }
+ }
+ },
"trainings.RemoveTrainingRequest": {
"type": "object",
"properties": {
diff --git a/docs/swagger.json b/docs/swagger.json
index d770ebc..d8fab55 100644
--- a/docs/swagger.json
+++ b/docs/swagger.json
@@ -164,6 +164,48 @@
}
}
}
+ },
+ "delete": {
+ "description": "Deletes an area",
+ "consumes": [
+ "application/json"
+ ],
+ "tags": [
+ "areas"
+ ],
+ "summary": "Deletes an area",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Area ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No Content"
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
}
},
"/me": {
@@ -221,23 +263,23 @@
}
}
},
- "/trainings": {
+ "/resources": {
"get": {
- "description": "Returns all trainings",
+ "description": "Returns all resources",
"produces": [
"application/json"
],
"tags": [
- "trainings"
+ "resources"
],
- "summary": "Get all trainings",
+ "summary": "Get all resources",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
- "$ref": "#/definitions/models.Training"
+ "$ref": "#/definitions/models.Resource"
}
}
},
@@ -248,18 +290,56 @@
}
}
}
+ },
+ "post": {
+ "description": "Creates a new resource",
+ "consumes": [
+ "application/json"
+ ],
+ "tags": [
+ "resources"
+ ],
+ "summary": "Create resource",
+ "parameters": [
+ {
+ "description": "Resource",
+ "name": "resource",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/models.Resource"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "Created"
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
}
},
- "/trainings/area/{id}": {
+ "/resources/area/{id}": {
"get": {
- "description": "Returns all trainings required for an area",
+ "description": "Returns all resources associated with an area",
"produces": [
"application/json"
],
"tags": [
- "trainings"
+ "resources"
],
- "summary": "Get area trainings",
+ "summary": "Get area resources",
"parameters": [
{
"type": "integer",
@@ -275,7 +355,7 @@
"schema": {
"type": "array",
"items": {
- "$ref": "#/definitions/models.Training"
+ "$ref": "#/definitions/models.Resource"
}
}
},
@@ -294,14 +374,17 @@
}
},
"post": {
- "description": "Associates one or more trainings with an area",
+ "description": "Adds resources to an area",
"consumes": [
"application/json"
],
+ "produces": [
+ "application/json"
+ ],
"tags": [
- "trainings"
+ "resources"
],
- "summary": "Add trainings to area",
+ "summary": "Add resources to area",
"parameters": [
{
"type": "integer",
@@ -311,8 +394,8 @@
"required": true
},
{
- "description": "Training IDs",
- "name": "trainingIds",
+ "description": "Resource IDs",
+ "name": "request",
"in": "body",
"required": true,
"schema": {
@@ -324,8 +407,8 @@
}
],
"responses": {
- "201": {
- "description": "Created"
+ "200": {
+ "description": "OK"
},
"400": {
"description": "Bad Request",
@@ -342,14 +425,14 @@
}
},
"delete": {
- "description": "Removes a training requirement from an area",
+ "description": "Removes a resource from an area",
"consumes": [
"application/json"
],
"tags": [
- "trainings"
+ "resources"
],
- "summary": "Remove training from area",
+ "summary": "Remove resource from area",
"parameters": [
{
"type": "integer",
@@ -359,12 +442,12 @@
"required": true
},
{
- "description": "Training removal request",
+ "description": "Resource removal request",
"name": "request",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/trainings.RemoveTrainingRequest"
+ "$ref": "#/definitions/resources.RemoveResourceRequest"
}
}
],
@@ -387,7 +470,153 @@
}
}
},
- "/trainings/create": {
+ "/resources/{id}": {
+ "get": {
+ "description": "Returns a resource by ID",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "resources"
+ ],
+ "summary": "Get resource",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Resource ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/models.Resource"
+ }
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ },
+ "put": {
+ "description": "Updates an existing resource",
+ "consumes": [
+ "application/json"
+ ],
+ "tags": [
+ "resources"
+ ],
+ "summary": "Update resource",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Resource ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "Resource",
+ "name": "resource",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/models.Resource"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "Created"
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ },
+ "delete": {
+ "description": "Deletes a resource by ID",
+ "tags": [
+ "resources"
+ ],
+ "summary": "Delete resource",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Resource ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "No Content"
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ }
+ },
+ "/trainings": {
+ "get": {
+ "description": "Returns all trainings",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "trainings"
+ ],
+ "summary": "Get all trainings",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/models.Training"
+ }
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ },
"post": {
"description": "Create a new training",
"consumes": [
@@ -427,6 +656,143 @@
}
}
},
+ "/trainings/area/{id}": {
+ "get": {
+ "description": "Returns all trainings required for an area",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "trainings"
+ ],
+ "summary": "Get area trainings",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Area ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/models.Training"
+ }
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ },
+ "post": {
+ "description": "Associates one or more trainings with an area",
+ "consumes": [
+ "application/json"
+ ],
+ "tags": [
+ "trainings"
+ ],
+ "summary": "Add trainings to area",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Area ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "Training IDs",
+ "name": "trainingIds",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "integer"
+ }
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "Created"
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ },
+ "delete": {
+ "description": "Removes a training requirement from an area",
+ "consumes": [
+ "application/json"
+ ],
+ "tags": [
+ "trainings"
+ ],
+ "summary": "Remove training from area",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Area ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ },
+ {
+ "description": "Training removal request",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/trainings.RemoveTrainingRequest"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "Created"
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ }
+ },
"/trainings/{id}": {
"get": {
"description": "Returns a training by ID",
@@ -586,6 +952,46 @@
}
}
}
+ },
+ "/trainings/{id}/submissions": {
+ "post": {
+ "description": "Submits and grades a completed training",
+ "consumes": [
+ "application/json"
+ ],
+ "tags": [
+ "trainings"
+ ],
+ "summary": "Submits and grades a completed training",
+ "parameters": [
+ {
+ "description": "Training",
+ "name": "training",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/models.Submission"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "Created"
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/models.ErrorResponse"
+ }
+ }
+ }
+ }
}
},
"definitions": {
@@ -615,6 +1021,9 @@
"ldap.UserWUUID": {
"type": "object",
"properties": {
+ "name": {
+ "type": "string"
+ },
"username": {
"type": "string"
},
@@ -672,6 +1081,12 @@
"$ref": "#/definitions/models.Question"
}
},
+ "requiredCorrect": {
+ "type": "integer"
+ },
+ "showAnswers": {
+ "type": "boolean"
+ },
"title": {
"type": "string"
}
@@ -709,6 +1124,29 @@
}
}
},
+ "models.Resource": {
+ "type": "object",
+ "properties": {
+ "description": {
+ "type": "string"
+ },
+ "id": {
+ "type": "integer"
+ },
+ "name": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string"
+ }
+ }
+ },
+ "models.Submission": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
"models.Training": {
"type": "object",
"properties": {
@@ -724,11 +1162,25 @@
"$ref": "#/definitions/models.Question"
}
},
+ "requiredCorrect": {
+ "type": "integer"
+ },
+ "showAnswers": {
+ "type": "boolean"
+ },
"title": {
"type": "string"
}
}
},
+ "resources.RemoveResourceRequest": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "integer"
+ }
+ }
+ },
"trainings.RemoveTrainingRequest": {
"type": "object",
"properties": {
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index 229be76..4c0dbbb 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -17,6 +17,8 @@ definitions:
type: object
ldap.UserWUUID:
properties:
+ name:
+ type: string
username:
type: string
uuid:
@@ -54,6 +56,10 @@ definitions:
items:
$ref: '#/definitions/models.Question'
type: array
+ requiredCorrect:
+ type: integer
+ showAnswers:
+ type: boolean
title:
type: string
type: object
@@ -78,6 +84,21 @@ definitions:
type:
type: string
type: object
+ models.Resource:
+ properties:
+ description:
+ type: string
+ id:
+ type: integer
+ name:
+ type: string
+ url:
+ type: string
+ type: object
+ models.Submission:
+ additionalProperties:
+ type: string
+ type: object
models.Training:
properties:
description:
@@ -88,9 +109,18 @@ definitions:
items:
$ref: '#/definitions/models.Question'
type: array
+ requiredCorrect:
+ type: integer
+ showAnswers:
+ type: boolean
title:
type: string
type: object
+ resources.RemoveResourceRequest:
+ properties:
+ id:
+ type: integer
+ type: object
trainings.RemoveTrainingRequest:
properties:
id:
@@ -146,6 +176,34 @@ paths:
tags:
- areas
/areas/{id}:
+ delete:
+ consumes:
+ - application/json
+ description: Deletes an area
+ parameters:
+ - description: Area ID
+ in: path
+ name: id
+ required: true
+ type: integer
+ responses:
+ "204":
+ description: No Content
+ "400":
+ description: Bad Request
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ "404":
+ description: Not Found
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ "500":
+ description: Internal Server Error
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ summary: Deletes an area
+ tags:
+ - areas
get:
description: Returns an area by ID
parameters:
@@ -242,6 +300,222 @@ paths:
summary: Get active CSH members
tags:
- members
+ /resources:
+ get:
+ description: Returns all resources
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ items:
+ $ref: '#/definitions/models.Resource'
+ type: array
+ "500":
+ description: Internal Server Error
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ summary: Get all resources
+ tags:
+ - resources
+ post:
+ consumes:
+ - application/json
+ description: Creates a new resource
+ parameters:
+ - description: Resource
+ in: body
+ name: resource
+ required: true
+ schema:
+ $ref: '#/definitions/models.Resource'
+ responses:
+ "201":
+ description: Created
+ "400":
+ description: Bad Request
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ "500":
+ description: Internal Server Error
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ summary: Create resource
+ tags:
+ - resources
+ /resources/{id}:
+ delete:
+ description: Deletes a resource by ID
+ parameters:
+ - description: Resource ID
+ in: path
+ name: id
+ required: true
+ type: integer
+ responses:
+ "204":
+ description: No Content
+ "400":
+ description: Bad Request
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ "500":
+ description: Internal Server Error
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ summary: Delete resource
+ tags:
+ - resources
+ get:
+ description: Returns a resource by ID
+ parameters:
+ - description: Resource ID
+ in: path
+ name: id
+ required: true
+ type: integer
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/models.Resource'
+ "404":
+ description: Not Found
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ "500":
+ description: Internal Server Error
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ summary: Get resource
+ tags:
+ - resources
+ put:
+ consumes:
+ - application/json
+ description: Updates an existing resource
+ parameters:
+ - description: Resource ID
+ in: path
+ name: id
+ required: true
+ type: integer
+ - description: Resource
+ in: body
+ name: resource
+ required: true
+ schema:
+ $ref: '#/definitions/models.Resource'
+ responses:
+ "201":
+ description: Created
+ "400":
+ description: Bad Request
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ "500":
+ description: Internal Server Error
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ summary: Update resource
+ tags:
+ - resources
+ /resources/area/{id}:
+ delete:
+ consumes:
+ - application/json
+ description: Removes a resource from an area
+ parameters:
+ - description: Area ID
+ in: path
+ name: id
+ required: true
+ type: integer
+ - description: Resource removal request
+ in: body
+ name: request
+ required: true
+ schema:
+ $ref: '#/definitions/resources.RemoveResourceRequest'
+ responses:
+ "201":
+ description: Created
+ "400":
+ description: Bad Request
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ "500":
+ description: Internal Server Error
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ summary: Remove resource from area
+ tags:
+ - resources
+ get:
+ description: Returns all resources associated with an area
+ parameters:
+ - description: Area ID
+ in: path
+ name: id
+ required: true
+ type: integer
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ items:
+ $ref: '#/definitions/models.Resource'
+ type: array
+ "400":
+ description: Bad Request
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ "500":
+ description: Internal Server Error
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ summary: Get area resources
+ tags:
+ - resources
+ post:
+ consumes:
+ - application/json
+ description: Adds resources to an area
+ parameters:
+ - description: Area ID
+ in: path
+ name: id
+ required: true
+ type: integer
+ - description: Resource IDs
+ in: body
+ name: request
+ required: true
+ schema:
+ items:
+ type: integer
+ type: array
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ "400":
+ description: Bad Request
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ "500":
+ description: Internal Server Error
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ summary: Add resources to area
+ tags:
+ - resources
/trainings:
get:
description: Returns all trainings
@@ -261,6 +535,31 @@ paths:
summary: Get all trainings
tags:
- trainings
+ post:
+ consumes:
+ - application/json
+ description: Create a new training
+ parameters:
+ - description: Training
+ in: body
+ name: training
+ required: true
+ schema:
+ $ref: '#/definitions/models.CreateTrainingRequest'
+ responses:
+ "201":
+ description: Created
+ "400":
+ description: Bad Request
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ "500":
+ description: Internal Server Error
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ summary: Create training
+ tags:
+ - trainings
/trainings/{id}:
delete:
description: Deletes a training
@@ -367,6 +666,32 @@ paths:
summary: Get training
tags:
- trainings
+ /trainings/{id}/submissions:
+ post:
+ consumes:
+ - application/json
+ description: Submits and grades a completed training
+ parameters:
+ - description: Training
+ in: body
+ name: training
+ required: true
+ schema:
+ $ref: '#/definitions/models.Submission'
+ responses:
+ "201":
+ description: Created
+ "400":
+ description: Bad Request
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ "500":
+ description: Internal Server Error
+ schema:
+ $ref: '#/definitions/models.ErrorResponse'
+ summary: Submits and grades a completed training
+ tags:
+ - trainings
/trainings/area/{id}:
delete:
consumes:
@@ -458,30 +783,4 @@ paths:
summary: Add trainings to area
tags:
- trainings
- /trainings/create:
- post:
- consumes:
- - application/json
- description: Create a new training
- parameters:
- - description: Training
- in: body
- name: training
- required: true
- schema:
- $ref: '#/definitions/models.CreateTrainingRequest'
- responses:
- "201":
- description: Created
- "400":
- description: Bad Request
- schema:
- $ref: '#/definitions/models.ErrorResponse'
- "500":
- description: Internal Server Error
- schema:
- $ref: '#/definitions/models.ErrorResponse'
- summary: Create training
- tags:
- - trainings
swagger: "2.0"
diff --git a/go.mod b/go.mod
index 42d9430..8aa75c2 100644
--- a/go.mod
+++ b/go.mod
@@ -3,71 +3,73 @@ module makedotcsh
go 1.26.4
require (
- github.com/computersciencehouse/csh-auth/v2 v2.0.2
+ github.com/computersciencehouse/csh-auth/v2 v2.1.0
github.com/gin-contrib/cors v1.7.7
github.com/gin-contrib/gzip v1.2.6
github.com/gin-contrib/logger v1.2.7
github.com/gin-gonic/gin v1.12.0
- github.com/go-ldap/ldap/v3 v3.4.13
+ github.com/go-ldap/ldap/v3 v3.4.14
github.com/golang-migrate/migrate/v4 v4.19.1
github.com/joho/godotenv v1.5.1
- github.com/lib/pq v1.10.9
+ github.com/lib/pq v1.12.3
github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.1
github.com/swaggo/swag v1.16.6
)
require (
- github.com/Azure/go-ntlmssp v0.1.0 // indirect
+ github.com/Azure/go-ntlmssp v0.1.1 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect
- github.com/PuerkitoBio/purell v1.1.1 // indirect
- github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // 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/bytedance/sonic v1.15.2 // indirect
+ github.com/bytedance/sonic/loader v0.5.2 // indirect
github.com/cloudwego/base64x v0.1.7 // indirect
- github.com/coreos/go-oidc/v3 v3.18.0 // indirect
- github.com/gabriel-vasile/mimetype v1.4.13 // indirect
+ github.com/coreos/go-oidc/v3 v3.20.0 // indirect
+ github.com/gabriel-vasile/mimetype v1.4.15 // indirect
github.com/gin-contrib/sse v1.1.1 // indirect
- github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
+ github.com/go-asn1-ber/asn1-ber v1.5.8 // indirect
github.com/go-jose/go-jose/v4 v4.1.4 // indirect
- github.com/go-openapi/jsonpointer v0.19.5 // indirect
- github.com/go-openapi/jsonreference v0.19.6 // indirect
- github.com/go-openapi/spec v0.20.4 // indirect
- github.com/go-openapi/swag v0.19.15 // indirect
+ github.com/go-openapi/jsonpointer v1.0.0 // indirect
+ github.com/go-openapi/jsonreference v1.0.0 // indirect
+ github.com/go-openapi/spec v0.22.9 // indirect
+ github.com/go-openapi/swag/conv v0.28.0 // indirect
+ github.com/go-openapi/swag/jsonutils v0.28.0 // indirect
+ github.com/go-openapi/swag/loading v0.28.0 // indirect
+ github.com/go-openapi/swag/pools v0.28.0 // indirect
+ github.com/go-openapi/swag/stringutils v0.28.0 // indirect
+ github.com/go-openapi/swag/typeutils v0.28.0 // indirect
+ github.com/go-openapi/swag/yamlutils v0.28.0 // 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.2 // indirect
+ github.com/go-playground/validator/v10 v10.30.3 // 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/google/uuid v1.6.0 // indirect
- github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
- github.com/klauspost/cpuid/v2 v2.3.0 // indirect
- github.com/leodido/go-urn v1.4.0 // indirect
- github.com/mailru/easyjson v0.7.6 // indirect
- github.com/mattn/go-colorable v0.1.14 // indirect
- github.com/mattn/go-isatty v0.0.22 // indirect
+ github.com/klauspost/cpuid/v2 v2.4.0 // indirect
+ github.com/leodido/go-urn v1.5.0 // indirect
+ github.com/mattn/go-colorable v0.1.15 // indirect
+ github.com/mattn/go-isatty v0.0.24 // 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.3.1 // indirect
+ github.com/pelletier/go-toml/v2 v2.4.3 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
- github.com/quic-go/quic-go v0.59.0 // indirect
- github.com/rs/zerolog v1.34.0 // indirect
+ github.com/quic-go/quic-go v0.61.0 // indirect
+ github.com/rs/zerolog v1.35.1 // indirect
github.com/sirupsen/logrus v1.9.4 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
- github.com/ugorji/go/codec v1.3.1 // indirect
- go.mongodb.org/mongo-driver/v2 v2.6.0 // indirect
- golang.org/x/arch v0.27.0 // indirect
- golang.org/x/crypto v0.51.0 // indirect
- golang.org/x/mod v0.35.0 // indirect
- golang.org/x/net v0.54.0 // indirect
+ github.com/ugorji/go/codec v1.3.2 // indirect
+ go.mongodb.org/mongo-driver/v2 v2.8.0 // indirect
+ go.yaml.in/yaml/v3 v3.0.4 // indirect
+ golang.org/x/arch v0.30.0 // indirect
+ golang.org/x/crypto v0.54.0 // indirect
+ golang.org/x/mod v0.38.0 // indirect
+ golang.org/x/net v0.57.0 // indirect
golang.org/x/oauth2 v0.36.0 // indirect
- golang.org/x/sync v0.20.0 // indirect
- golang.org/x/sys v0.44.0 // indirect
- golang.org/x/text v0.37.0 // indirect
- golang.org/x/tools v0.44.0 // indirect
+ golang.org/x/sync v0.22.0 // indirect
+ golang.org/x/sys v0.47.0 // indirect
+ golang.org/x/text v0.40.0 // indirect
+ golang.org/x/tools v0.48.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
)
diff --git a/go.sum b/go.sum
index 9ef640b..b73dc39 100644
--- a/go.sum
+++ b/go.sum
@@ -1,35 +1,29 @@
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
-github.com/Azure/go-ntlmssp v0.1.0 h1:DjFo6YtWzNqNvQdrwEyr/e4nhU3vRiwenz5QX7sFz+A=
-github.com/Azure/go-ntlmssp v0.1.0/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9DiVTbhpk=
+github.com/Azure/go-ntlmssp v0.1.1 h1:l+FM/EEMb0U9QZE7mKNEDw5Mu3mFiaa2GKOoTSsNDPw=
+github.com/Azure/go-ntlmssp v0.1.1/go.mod h1:NYqdhxd/8aAct/s4qSYZEerdPuH1liG2/X9DiVTbhpk=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
-github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
-github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
-github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e h1:4dAU9FXIyQktpoUAgOJK3OTFc/xug0PCXYCqU0FgDKI=
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
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.1 h1:nJD5PmM0vY7J8CT6MxoqbVAAMhkSmV2HgRAUrrpLoOw=
-github.com/bytedance/sonic v1.15.1/go.mod h1:mT2NbXunuaEbnZ+mRIX/vYqKISmgEuHFDI4UzmKx2SA=
-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/bytedance/sonic v1.15.2 h1:90H+rcF/FwLXwfB1cudOLq/je83n683Utf4Cbp0xHCo=
+github.com/bytedance/sonic v1.15.2/go.mod h1:mT2NbXunuaEbnZ+mRIX/vYqKISmgEuHFDI4UzmKx2SA=
+github.com/bytedance/sonic/loader v0.5.2 h1:0QtP1gevc1OZ6/H8Lb9BRZiCXd1Ftjd3OKuj1T1lBIo=
+github.com/bytedance/sonic/loader v0.5.2/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
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.2 h1:xlxv2w2cmiWriVNhwA8Io1FWI54sDmv7c12gkVAcK30=
-github.com/computersciencehouse/csh-auth/v2 v2.0.2/go.mod h1:uL/2UDr9GJlAQORsn+rmFc18YkBsZPymYJbwb+uTRig=
+github.com/computersciencehouse/csh-auth/v2 v2.1.0 h1:L00q0la/2vNZgo6rceICruPYtvTbghl7B8xBCAxpvm0=
+github.com/computersciencehouse/csh-auth/v2 v2.1.0/go.mod h1:uL/2UDr9GJlAQORsn+rmFc18YkBsZPymYJbwb+uTRig=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
-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/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/coreos/go-oidc/v3 v3.20.0 h1:EtE0WIBHk03N+DqGkY4+UONzzZHk7amKt6IyNd7OsZE=
+github.com/coreos/go-oidc/v3 v3.20.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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@@ -46,8 +40,8 @@ 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/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
-github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
+github.com/gabriel-vasile/mimetype v1.4.15 h1:05iP/CYtZ/w455R/KZM6rZ5ieAdh99UPtd+d3YzLmaI=
+github.com/gabriel-vasile/mimetype v1.4.15/go.mod h1:azpTcoLcDZRNgFou5j+APrqQx9HqVPWa6ijYQIIVswQ=
github.com/gin-contrib/cors v1.7.7 h1:Oh9joP463x7Mw72vhvJ61YQm8ODh9b04YR7vsOErD0Q=
github.com/gin-contrib/cors v1.7.7/go.mod h1:K5tW0RkzJtWSiOdikXloy8VEZlgdVNpHNw8FpjUPNrE=
github.com/gin-contrib/gzip v1.2.6 h1:OtN8DplD5DNZCSLAnQ5HxRkD2qZ5VU+JhOrcfJrcRvg=
@@ -58,39 +52,55 @@ 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-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
-github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
+github.com/go-asn1-ber/asn1-ber v1.5.8 h1:H9AZkK22UOmfX8J84ubyaZxKJZ3FMHVwn8swoMML7iQ=
+github.com/go-asn1-ber/asn1-ber v1.5.8/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
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-ldap/ldap/v3 v3.4.13 h1:+x1nG9h+MZN7h/lUi5Q3UZ0fJ1GyDQYbPvbuH38baDQ=
-github.com/go-ldap/ldap/v3 v3.4.13/go.mod h1:LxsGZV6vbaK0sIvYfsv47rfh4ca0JXokCoKjZxsszv0=
+github.com/go-ldap/ldap/v3 v3.4.14 h1:D6PYdEgsaVzsXyr6w/yDC06Ria4uUhWm+Rb+er8lfAs=
+github.com/go-ldap/ldap/v3 v3.4.14/go.mod h1:S4eJUMUNjDkE0ZJtIZdybwyb03sGGLW6gxXT1Hs8VKA=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/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-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
-github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
-github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
-github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
-github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
-github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
-github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
-github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxgL3h1H8s=
+github.com/go-openapi/jsonpointer v1.0.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y=
+github.com/go-openapi/jsonreference v1.0.0 h1:jlmTr6torcd1YgDQvSfNmRtKzYDO4FGBkrAdlAVWnpY=
+github.com/go-openapi/jsonreference v1.0.0/go.mod h1:jtwdyGbJk0Xhe5Y+rwtglQP6Sb1WZST4rT32LWB+sv0=
+github.com/go-openapi/spec v0.22.9 h1:/vKIFDcGKp0ktZWGbym/tJEWbk6/XOEmAVU0kqKMH+w=
+github.com/go-openapi/spec v0.22.9/go.mod h1:b/mNUYIOQOyIiUzUzXEE8xzyZqf93KvM9hQGP91yfl0=
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
-github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
+github.com/go-openapi/swag/conv v0.28.0 h1:GtqqbyFe7vR5Y7ehxG9W6/OvrSFdf1OLeTGp40TqxH8=
+github.com/go-openapi/swag/conv v0.28.0/go.mod h1:mbUE+mzctnhxi864m0Q07SpN8OowD9JhxmxuYvZZD/k=
+github.com/go-openapi/swag/jsonutils v0.28.0 h1:YIch6FwO7RXzeAnbO8Tu7dWBZeUEH+4nA0HXltVTnv4=
+github.com/go-openapi/swag/jsonutils v0.28.0/go.mod h1:CYM3WlTUcagR2ZoHdz54di/cbBqt82tuxuXgAjxw+mg=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.28.0 h1:qV+VVUAx5Oro8WjVWpZeql7YReTKhT4smR4zhcOQZr0=
+github.com/go-openapi/swag/jsonutils/fixtures_test v0.28.0/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY=
+github.com/go-openapi/swag/loading v0.28.0 h1:td8QZdZC9MIYGGSnSPKShKiK22I2tU5UQvuUhIBPRLU=
+github.com/go-openapi/swag/loading v0.28.0/go.mod h1:rXB0QiQX5mMveXEA7ouM4KiiM9jVJe4K6BVbwhD1M4k=
+github.com/go-openapi/swag/pools v0.28.0 h1:HPMZWSAfce3rdVTFcjFiCIBtDg9h4x2QlRrHipwhxeU=
+github.com/go-openapi/swag/pools v0.28.0/go.mod h1:kVQefhSK5RWuRe7BXsL8htgBPAMpN7HDGpGEknqugeE=
+github.com/go-openapi/swag/stringutils v0.28.0 h1:ixsc9iYgDPubHL/8nSkbnryEHpD2VRlBMLKpQyPXcDU=
+github.com/go-openapi/swag/stringutils v0.28.0/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM=
+github.com/go-openapi/swag/typeutils v0.28.0 h1:nRBKSBXjDgf01VDPB3fWeD9nQuhCOVeIYAkUx2tbkyY=
+github.com/go-openapi/swag/typeutils v0.28.0/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ=
+github.com/go-openapi/swag/yamlutils v0.28.0 h1:TV3JXH6DS46KUroDtMLAYHGkdWf5VDq3wVWFirmzROY=
+github.com/go-openapi/swag/yamlutils v0.28.0/go.mod h1:x0q/yndZHEgk9Rx3DyDqzFUmHy55KTvIZldvF2dTJXs=
+github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 h1:gGHwAJ0R/5jU8BEGDbfRNR3hL68dAVi84WuOApp29B0=
+github.com/go-openapi/testify/enable/yaml/v2 v2.6.0/go.mod h1:tY+St1SGq4NFl0QIqdTY4aEdbChAHxhyB77XQi9iJCo=
+github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug=
+github.com/go-openapi/testify/v2 v2.6.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
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=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-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/go-playground/validator/v10 v10.30.3 h1:4MU6YkEwx7GbcPJOZxrtbu+QfF3pJLJuaYTeAH0DYy8=
+github.com/go-playground/validator/v10 v10.30.3/go.mod h1:4Axh7oCNGcoGkqLoE4YWt6n20mcEIsPRlB7vPk3lpyc=
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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
@@ -118,34 +128,22 @@ github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZ
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
-github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
-github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
-github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/klauspost/cpuid/v2 v2.4.0 h1:S6Hrbc7+ywsr0r+RLapfGBHfyefhCTwEh3A0tV913Dw=
+github.com/klauspost/cpuid/v2 v2.4.0/go.mod h1:19jmZ9mjzoF//ddRSUsv0zfBTJWh3QJh9FNxZTMrGxU=
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/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/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
-github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
-github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
-github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
-github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.19/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/leodido/go-urn v1.5.0 h1:pLqT2kq1zpHW/1D18QMjMpdtX7cekxqtJJjg5ANyWw0=
+github.com/leodido/go-urn v1.5.0/go.mod h1:9BORnCDhdPBJNDEX+w1bJisa8yOKYi116VeO96s4ifE=
+github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
+github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
+github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY=
+github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
+github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI=
+github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A=
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/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
@@ -157,27 +155,27 @@ 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/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
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.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc=
-github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
+github.com/pelletier/go-toml/v2 v2.4.3 h1:GTRvJQutkOSftxIFD5xw9aepkYNuPWmVJpffdDPYVpY=
+github.com/pelletier/go-toml/v2 v2.4.3/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/quic-go/go-ossfuzz-seeds v0.1.0 h1:APacT+iIaNF6fd8AGEiN3bT/Jtkd2jz4v4TzM7MFjy0=
+github.com/quic-go/go-ossfuzz-seeds v0.1.0/go.mod h1:3IOHRbJIc+L6YKMwfDtJAM9Vj9k0YY4muhuyUYk5tbk=
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
-github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
-github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
+github.com/quic-go/quic-go v0.61.0 h1:ui88A53s8MSVYLC56en0KQ17HARk+9986Dn0SBfKNvA=
+github.com/quic-go/quic-go v0.61.0/go.mod h1:9So2anK4Tp22URSQq00k+Vo2PNkle96ycDPDHL4s9vs=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
-github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
-github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
-github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
+github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI=
+github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -185,7 +183,6 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.6.1/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=
@@ -200,11 +197,11 @@ github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
-github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
-github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
+github.com/ugorji/go/codec v1.3.2 h1:zkEASHHyEClGeURfgNT9PJZVfAbs9oEX9QXggwWNJbc=
+github.com/ugorji/go/codec v1.3.2/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-go.mongodb.org/mongo-driver/v2 v2.6.0 h1:b9sJOYrkmt4l8bY43ZenFBcPlhYIjaOfYHLtbB/5qi8=
-go.mongodb.org/mongo-driver/v2 v2.6.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
+go.mongodb.org/mongo-driver/v2 v2.8.0 h1:CxWDGQYY8QQwNjAl/aq2sfWakdnWZynnqJ9F4DhHbP8=
+go.mongodb.org/mongo-driver/v2 v2.8.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
@@ -217,67 +214,57 @@ go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mx
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
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.27.0 h1:0WNVcR8u9yFz8j5FvdHpgwNp3FS5U4guYdzHwEiGjoU=
-golang.org/x/arch v0.27.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
+go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
+go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
+golang.org/x/arch v0.30.0 h1:sB9h+1gRGa2+LauFSV0tm8bK1J2yo1bx6/Uyi/P6DTU=
+golang.org/x/arch v0.30.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.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
-golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
+golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw=
+golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
-golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
+golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk=
+golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40=
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-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-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/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
+golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
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=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
-golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
+golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/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/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.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-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/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
+golang.org/x/sys v0.47.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/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/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.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
-golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
+golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
+golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
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/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
-golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
+golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE=
+golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/main.go b/main.go
index 7cd3a69..ff7a285 100644
--- a/main.go
+++ b/main.go
@@ -104,6 +104,7 @@ func main() {
// auth
router.GET("/auth/login", auth.HandleLogin) // This endpoint should match the path for loginURL
router.GET("/auth/callback", auth.HandleCallback) // This endpoint should match the path for callbackURL
+ router.POST("/auth/refresh", auth.HandleRefresh)
router.GET("/auth/logout", auth.HandleLogout)
// api
@@ -111,13 +112,13 @@ func main() {
// frontend
if os.Getenv("DEV") == "true" {
- router.NoRoute(auth.CookieMiddleware(), createViteProxy())
+ router.NoRoute(createViteProxy())
} else {
gin.SetMode(gin.ReleaseMode)
router.StaticFS("/assets", http.FS(assetsFS))
- router.NoRoute(auth.CookieMiddleware(), func(c *gin.Context) {
+ router.NoRoute(func(c *gin.Context) {
if strings.HasPrefix(c.Request.URL.Path, "/api") {
c.JSON(404, gin.H{"error": "not found"})
return
diff --git a/models/resources.go b/models/resources.go
new file mode 100644
index 0000000..686333d
--- /dev/null
+++ b/models/resources.go
@@ -0,0 +1,8 @@
+package models
+
+type Resource struct {
+ ID int `json:"id,omitempty"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ URL string `json:"url"`
+}
diff --git a/models/training.go b/models/training.go
index d66daa8..2426c7e 100644
--- a/models/training.go
+++ b/models/training.go
@@ -18,6 +18,7 @@ type Training struct {
Title string `json:"title"`
Description string `json:"description"`
RequiredCorrect int `json:"requiredCorrect"`
+ ShowAnswers bool `json:"showAnswers"`
Questions []Question `json:"questions"`
}
@@ -25,6 +26,7 @@ type CreateTrainingRequest struct {
Title string `json:"title"`
Description string `json:"description"`
RequiredCorrect int `json:"requiredCorrect"`
+ ShowAnswers bool `json:"showAnswers"`
Questions []Question `json:"questions"`
}
@@ -38,8 +40,9 @@ type UserTraining struct {
type Submission = map[int]string
type SubmissionResponse struct {
- Passed bool `json:"passed"`
- NumCorrect int `json:"numCorrect"`
- NumIncorrect int `json:"numIncorrect"`
- Grade int `json:"grade"`
+ Passed bool `json:"passed"`
+ NumCorrect int `json:"numCorrect"`
+ NumIncorrect int `json:"numIncorrect"`
+ Grade int `json:"grade"`
+ GradedResponse map[int]bool `json:"gradedResponse"`
}
diff --git a/routes/api/areas/areas.go b/routes/api/areas/areas.go
index fd9de90..2a4ad01 100644
--- a/routes/api/areas/areas.go
+++ b/routes/api/areas/areas.go
@@ -129,6 +129,35 @@ func updateArea(c *gin.Context) {
c.Status(204)
}
+
+// DeleteArea godoc
+//
+// @Summary Deletes an area
+// @Description Deletes an area
+// @Tags areas
+// @Accept json
+// @Param id path int true "Area ID"
+// @Success 204
+// @Failure 400 {object} models.ErrorResponse
+// @Failure 404 {object} models.ErrorResponse
+// @Failure 500 {object} models.ErrorResponse
+// @Router /areas/{id} [delete]
+func deleteArea(c *gin.Context) {
+ id, err := strconv.Atoi(c.Param("id"))
+ if err != nil {
+ c.Error(err)
+ return
+ }
+
+ err = database.Helper.DeleteArea(id)
+ if err != nil {
+ c.Error(err)
+ return
+ }
+
+ c.Status(201)
+}
+
func Routes(route *gin.RouterGroup) {
areas := route.Group("/areas")
areas.GET("/", getAllAreas)
@@ -136,4 +165,6 @@ func Routes(route *gin.RouterGroup) {
areas.PUT("/:id", middleware.RequireGroup("eboard"), updateArea)
areas.POST("/", middleware.RequireGroup("eboard"), createArea)
+
+ areas.DELETE("/:id", middleware.RequireGroup("eboard"), deleteArea)
}
diff --git a/routes/api/me/me.go b/routes/api/me/me.go
index f135fb0..407b440 100644
--- a/routes/api/me/me.go
+++ b/routes/api/me/me.go
@@ -6,13 +6,22 @@ import (
"github.com/gin-gonic/gin"
)
+// bullshit type that matches csh.auth.UserInfo because swag can't resolve dependencies
+type MeResponse struct {
+ Uuid string `json:"uuid"`
+ Email string `json:"email"`
+ Username string `json:"preferred_username"`
+ FullName string `json:"name"`
+ Groups []string `json:"groups"`
+}
+
// GetAuthUser godoc
//
// @Summary Get authenticated user
// @Description Returns information about the currently authenticated user
// @Tags me
// @Produce json
-// @Success 200 {object} csh_auth.UserInfo
+// @Success 200 {object} MeResponse
// @Failure 500 {object} models.ErrorResponse
// @Router /me [get]
func getAuthUser(c *gin.Context) {
diff --git a/routes/api/resources/resources.go b/routes/api/resources/resources.go
new file mode 100644
index 0000000..f19c891
--- /dev/null
+++ b/routes/api/resources/resources.go
@@ -0,0 +1,270 @@
+package resources
+
+import (
+ "database/sql"
+ "errors"
+ "makedotcsh/database"
+ "makedotcsh/middleware"
+ "makedotcsh/models"
+ "strconv"
+
+ "github.com/gin-gonic/gin"
+)
+
+type RemoveResourceRequest struct {
+ ID int `json:"id"`
+}
+
+// GetAllResources godoc
+//
+// @Summary Get all resources
+// @Description Returns all resources
+// @Tags resources
+// @Produce json
+// @Success 200 {array} models.Resource
+// @Failure 500 {object} models.ErrorResponse
+// @Router /resources [get]
+func getAllResources(c *gin.Context) {
+ rs, err := database.Helper.GetAllResources()
+ if err != nil {
+ c.Error(err)
+ return
+ }
+
+ c.JSON(200, rs)
+}
+
+// GetResource godoc
+//
+// @Summary Get resource
+// @Description Returns a resource by ID
+// @Tags resources
+// @Produce json
+// @Param id path int true "Resource ID"
+// @Success 200 {object} models.Resource
+// @Failure 404 {object} models.ErrorResponse
+// @Failure 500 {object} models.ErrorResponse
+// @Router /resources/{id} [get]
+func getResource(c *gin.Context) {
+ id, err := strconv.Atoi(c.Param("id"))
+
+ r, err := database.Helper.GetResource(id)
+
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ c.JSON(404, gin.H{"error": "resource not found"})
+ return
+ }
+
+ c.Error(err)
+ return
+ }
+
+ c.JSON(200, r)
+}
+
+// CreateResource godoc
+//
+// @Summary Create resource
+// @Description Creates a new resource
+// @Tags resources
+// @Accept json
+// @Param resource body models.Resource true "Resource"
+// @Success 201
+// @Failure 400 {object} models.ErrorResponse
+// @Failure 500 {object} models.ErrorResponse
+// @Router /resources [post]
+func createResource(c *gin.Context) {
+ var req models.Resource
+
+ err := c.ShouldBindBodyWithJSON(&req)
+ if err != nil {
+ c.JSON(400, gin.H{
+ "error": err.Error(),
+ })
+ return
+ }
+
+ err = database.Helper.CreateResource(req)
+ if err != nil {
+ c.Error(err)
+ return
+ }
+
+ c.Status(201)
+}
+
+// UpdateResource godoc
+//
+// @Summary Update resource
+// @Description Updates an existing resource
+// @Tags resources
+// @Accept json
+// @Param id path int true "Resource ID"
+// @Param resource body models.Resource true "Resource"
+// @Success 201
+// @Failure 400 {object} models.ErrorResponse
+// @Failure 500 {object} models.ErrorResponse
+// @Router /resources/{id} [put]
+func updateResource(c *gin.Context) {
+ var req models.Resource
+
+ id, err := strconv.Atoi(c.Param("id"))
+ if err != nil {
+ c.JSON(400, gin.H{
+ "error": err.Error(),
+ })
+ return
+ }
+
+ err = c.ShouldBindBodyWithJSON(&req)
+ if err != nil {
+ c.JSON(400, gin.H{
+ "error": err.Error(),
+ })
+ return
+ }
+
+ err = database.Helper.UpdateResource(req, id)
+ if err != nil {
+ c.Error(err)
+ return
+ }
+
+ c.Status(201)
+}
+
+// DeleteResource godoc
+//
+// @Summary Delete resource
+// @Description Deletes a resource by ID
+// @Tags resources
+// @Param id path int true "Resource ID"
+// @Success 204
+// @Failure 400 {object} models.ErrorResponse
+// @Failure 500 {object} models.ErrorResponse
+// @Router /resources/{id} [delete]
+func deleteResource(c *gin.Context) {
+ id, err := strconv.Atoi(c.Param("id"))
+ if err != nil {
+ c.JSON(400, gin.H{
+ "error": err.Error(),
+ })
+ return
+ }
+
+ err = database.Helper.DeleteResource(id)
+ if err != nil {
+ c.Error(err)
+ return
+ }
+
+ c.Status(204)
+}
+
+// GetAreaResources godoc
+//
+// @Summary Get area resources
+// @Description Returns all resources associated with an area
+// @Tags resources
+// @Produce json
+// @Param id path int true "Area ID"
+// @Success 200 {array} models.Resource
+// @Failure 400 {object} models.ErrorResponse
+// @Failure 500 {object} models.ErrorResponse
+// @Router /resources/area/{id} [get]
+func getAreaResources(c *gin.Context) {
+ id, err := strconv.Atoi(c.Param("id"))
+ if err != nil {
+ c.JSON(400, gin.H{
+ "error": err.Error(),
+ })
+ return
+ }
+
+ resources, err := database.Helper.GetAreaResources(id)
+ if err != nil {
+ c.Error(err)
+ return
+ }
+
+ c.JSON(200, resources)
+}
+
+// AddResourceToArea godoc
+//
+// @Summary Add resources to area
+// @Description Adds resources to an area
+// @Tags resources
+// @Accept json
+// @Produce json
+// @Param id path int true "Area ID"
+// @Param request body []int true "Resource IDs"
+// @Success 200
+// @Failure 400 {object} models.ErrorResponse
+// @Failure 500 {object} models.ErrorResponse
+// @Router /resources/area/{id} [post]
+func addResourceToArea(c *gin.Context) {
+ var req []int
+ id, err := strconv.Atoi(c.Param("id"))
+ err = c.ShouldBindBodyWithJSON(&req)
+ if err != nil {
+ c.JSON(400, gin.H{
+ "error": err.Error(),
+ })
+ return
+ }
+
+ err = database.Helper.AddResourceToArea(id, req)
+ if err != nil {
+ c.Error(err)
+ return
+ }
+}
+
+// RemoveResourceFromArea godoc
+//
+// @Summary Remove resource from area
+// @Description Removes a resource from an area
+// @Tags resources
+// @Accept json
+// @Param id path int true "Area ID"
+// @Param request body resources.RemoveResourceRequest true "Resource removal request"
+// @Success 201
+// @Failure 400 {object} models.ErrorResponse
+// @Failure 500 {object} models.ErrorResponse
+// @Router /resources/area/{id} [delete]
+func removeResourceFromArea(c *gin.Context) {
+ var req RemoveResourceRequest
+ id, err := strconv.Atoi(c.Param("id"))
+ err = c.ShouldBindBodyWithJSON(&req)
+ if err != nil {
+ c.JSON(400, gin.H{
+ "error": err.Error(),
+ })
+ return
+ }
+
+ err = database.Helper.RemoveResourceFromArea(id, req.ID)
+ if err != nil {
+ c.Error(err)
+ return
+ }
+
+ c.Status(201)
+}
+
+func Routes(route *gin.RouterGroup) {
+ resources := route.Group("/resources")
+ resources.GET("/", getAllResources)
+ resources.GET("/:id", getResource)
+ resources.GET("/area/:id", getAreaResources)
+
+ resources.PUT("/:id", middleware.RequireGroup("eboard"), updateResource)
+
+ resources.POST("/", middleware.RequireGroup("eboard"), createResource)
+ resources.POST("/area/:id", middleware.RequireGroup("eboard"), addResourceToArea)
+
+ resources.DELETE("/area/:id", middleware.RequireGroup("eboard"), removeResourceFromArea)
+ resources.DELETE("/:id", middleware.RequireGroup("eboard"), deleteResource)
+}
diff --git a/routes/routes.go b/routes/routes.go
index ba29fb1..0c2dd82 100644
--- a/routes/routes.go
+++ b/routes/routes.go
@@ -4,6 +4,7 @@ import (
"makedotcsh/routes/api/areas"
"makedotcsh/routes/api/me"
"makedotcsh/routes/api/members"
+ "makedotcsh/routes/api/resources"
"makedotcsh/routes/api/trainings"
"makedotcsh/routes/api/user"
@@ -34,5 +35,6 @@ func SetRoutes(router *gin.Engine, auth csh_auth.Auth) {
trainings.Routes(api)
user.Routes(api)
members.Routes(api)
+ resources.Routes(api)
}
diff --git a/utils/util.go b/utils/util.go
index ba0a814..627f0bb 100644
--- a/utils/util.go
+++ b/utils/util.go
@@ -51,6 +51,11 @@ func GradeTraining(trainingId int, userUUID string, submission models.Submission
return models.SubmissionResponse{}, errors.New("invalid submission")
}
+ if len(answers) == 0 {
+ // no submission allowed
+ return models.SubmissionResponse{}, errors.New("invalid submission")
+ }
+
var correct, incorrect int
graded := map[int]bool{}
totalQuestions := len(answers)
@@ -76,6 +81,12 @@ func GradeTraining(trainingId int, userUUID string, submission models.Submission
Grade: int((float64(correct) / float64(totalQuestions)) * 100),
}
+ if training.ShowAnswers {
+ res.GradedResponse = graded
+ } else {
+ res.GradedResponse = map[int]bool{}
+ }
+
if passed {
SubmitTraining(userUUID, training)
diff --git a/web/src/components/AddResourcePopup.vue b/web/src/components/AddResourcePopup.vue
new file mode 100644
index 0000000..570d7fc
--- /dev/null
+++ b/web/src/components/AddResourcePopup.vue
@@ -0,0 +1,111 @@
+
+
+
+
{{ error }}
diff --git a/web/src/components/AppNavbar.vue b/web/src/components/AppNavbar.vue index 0aeae25..5e19320 100644 --- a/web/src/components/AppNavbar.vue +++ b/web/src/components/AppNavbar.vue @@ -29,7 +29,6 @@ function logout() {