From fbfbab12c3dffacceadf822640c83ad0c7b38414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20PAILHAREY?= <rpailharey@grandlyon.com> Date: Fri, 10 Sep 2021 12:55:13 +0000 Subject: [PATCH] feat: updated monthly news + add monthly info --- docker-compose.yml | 1 + docs/docs.go | 266 +++++++++++++++++------- docs/swagger.json | 252 +++++++++++++++------- docs/swagger.yaml | 188 +++++++++++------ go.mod | 14 +- go.sum | 57 +++-- internal/common/common.go | 24 +++ internal/database/database.go | 106 ---------- internal/models/models.go | 45 ++++ internal/models/monthlyInfo.go | 140 +++++++++++++ internal/models/monthlyNews.go | 153 ++++++++++++++ internal/models/monthlyReport.go | 94 +++++++++ internal/models/poll.go | 150 +++++++++++++ internal/monthlyNews/monthlyNews.go | 244 ---------------------- internal/monthlyReport/monthlyReport.go | 106 ---------- internal/poll/poll.go | 244 ---------------------- internal/rootmux/rootmux.go | 37 ++-- internal/rootmux/rootmux_test.go | 111 +++++----- main.go | 17 +- template.env | 1 + 20 files changed, 1233 insertions(+), 1017 deletions(-) delete mode 100644 internal/database/database.go create mode 100644 internal/models/models.go create mode 100644 internal/models/monthlyInfo.go create mode 100644 internal/models/monthlyNews.go create mode 100644 internal/models/monthlyReport.go create mode 100644 internal/models/poll.go delete mode 100644 internal/monthlyNews/monthlyNews.go delete mode 100644 internal/monthlyReport/monthlyReport.go delete mode 100644 internal/poll/poll.go diff --git a/docker-compose.yml b/docker-compose.yml index 2dae102..02ddcce 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -49,6 +49,7 @@ services: - TOKEN_URL=${TOKEN_URL} - USERINFO_URL=${USERINFO_URL} - DEBUG_MODE=${DEBUG_MODE} + - MOCK_OAUTH2=${MOCK_OAUTH2} - DATABASE_USER=${DATABASE_USER} - DATABASE_NAME=${DATABASE_NAME} - DATABASE_PASSWORD=${DATABASE_PASSWORD} diff --git a/docs/docs.go b/docs/docs.go index df6adff..5bd2306 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1,14 +1,13 @@ -// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// Package docs GENERATED BY THE COMMAND ABOVE; DO NOT EDIT // This file was generated by swaggo/swag - package docs import ( "bytes" "encoding/json" "strings" + "text/template" - "github.com/alecthomas/template" "github.com/swaggo/swag" ) @@ -16,7 +15,7 @@ var doc = `{ "schemes": {{ marshal .Schemes }}, "swagger": "2.0", "info": { - "description": "{{.Description}}", + "description": "{{escape .Description}}", "title": "{{.Title}}", "termsOfService": "http://swagger.io/terms/", "contact": { @@ -28,30 +27,30 @@ var doc = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { - "/api/admin/monthlyNews": { + "/api/admin/monthlyInfo": { "get": { - "description": "Get details of all monthlyNews", + "description": "Get details of all monthlyInfo", "produces": [ "application/json" ], "tags": [ - "monthlyNews" + "monthlyInfo" ], - "summary": "List all monthlyNews", + "summary": "List all monthlyInfo", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { - "$ref": "#/definitions/monthlyNews.MonthlyNews" + "$ref": "#/definitions/models.MonthlyInfo" } } } } }, "put": { - "description": "Create/update a specific monthlyNews' content", + "description": "Create/update a specific monthlyInfo' content", "consumes": [ "application/json" ], @@ -59,17 +58,17 @@ var doc = `{ "application/json" ], "tags": [ - "monthlyNews" + "monthlyInfo" ], - "summary": "Create/update a specific monthlyNews' content", + "summary": "Create/update a specific monthlyInfo' content", "parameters": [ { - "description": "MonthlyNews to create/update with new content", - "name": "monthlyNews", + "description": "MonthlyInfo to create/update with new content", + "name": "monthlyInfo", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/monthlyNews.MonthlyNews" + "$ref": "#/definitions/models.MonthlyInfo" } } ], @@ -77,13 +76,13 @@ var doc = `{ "200": { "description": "Updated successfully", "schema": { - "$ref": "#/definitions/monthlyNews.MonthlyNews" + "$ref": "#/definitions/models.MonthlyInfo" } }, "201": { "description": "Created successfully", "schema": { - "$ref": "#/definitions/monthlyNews.MonthlyNews" + "$ref": "#/definitions/models.MonthlyInfo" } }, "400": { @@ -99,9 +98,114 @@ var doc = `{ } } } + } + }, + "/api/admin/monthlyInfo/{year}/{month}": { + "get": { + "description": "Get details of a specific monthlyInfo", + "produces": [ + "application/json" + ], + "tags": [ + "monthlyInfo" + ], + "summary": "Get details of a specific monthlyInfo", + "parameters": [ + { + "type": "integer", + "description": "Year of the monthlyInfo", + "name": "year", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Month of the monthlyInfo", + "name": "month", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.MonthlyInfo" + } + }, + "404": { + "description": "Not found", + "schema": { + "type": "string" + } + } + } + }, + "delete": { + "description": "Delete a specific monthlyInfo", + "produces": [ + "application/json" + ], + "tags": [ + "monthlyInfo" + ], + "summary": "Delete a specific monthlyInfo", + "parameters": [ + { + "type": "integer", + "description": "Year of the monthlyInfo", + "name": "year", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Month of the monthlyInfo", + "name": "month", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "successful delete", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Not found", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/admin/monthlyNews": { + "get": { + "description": "Get details of all monthlyNews", + "produces": [ + "application/json" + ], + "tags": [ + "monthlyNews" + ], + "summary": "List all monthlyNews", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.MonthlyNews" + } + } + } + } }, - "post": { - "description": "Create a new monthlyNews", + "put": { + "description": "Create/update a specific monthlyNews' content", "consumes": [ "application/json" ], @@ -111,23 +215,41 @@ var doc = `{ "tags": [ "monthlyNews" ], - "summary": "Create a new monthlyNews", + "summary": "Create/update a specific monthlyNews' content", "parameters": [ { - "description": "MonthlyNews to create", + "description": "MonthlyNews to create/update with new content", "name": "monthlyNews", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/monthlyNews.MonthlyNews" + "$ref": "#/definitions/models.MonthlyNews" } } ], "responses": { + "200": { + "description": "Updated successfully", + "schema": { + "$ref": "#/definitions/models.MonthlyNews" + } + }, "201": { - "description": "Created", + "description": "Created successfully", "schema": { - "$ref": "#/definitions/monthlyNews.MonthlyNews" + "$ref": "#/definitions/models.MonthlyNews" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "type": "string" } } } @@ -163,7 +285,7 @@ var doc = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/monthlyNews.MonthlyNews" + "$ref": "#/definitions/models.MonthlyNews" } }, "404": { @@ -231,7 +353,7 @@ var doc = `{ "schema": { "type": "array", "items": { - "$ref": "#/definitions/poll.Poll" + "$ref": "#/definitions/models.Poll" } } } @@ -256,7 +378,7 @@ var doc = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/poll.Poll" + "$ref": "#/definitions/models.Poll" } } ], @@ -264,13 +386,13 @@ var doc = `{ "200": { "description": "Updated successfully", "schema": { - "$ref": "#/definitions/poll.Poll" + "$ref": "#/definitions/models.Poll" } }, "201": { "description": "Created successfully", "schema": { - "$ref": "#/definitions/poll.Poll" + "$ref": "#/definitions/models.Poll" } }, "400": { @@ -286,38 +408,6 @@ var doc = `{ } } } - }, - "post": { - "description": "Create a new poll", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "poll" - ], - "summary": "Create a new poll", - "parameters": [ - { - "description": "Poll to create", - "name": "poll", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/poll.Poll" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/poll.Poll" - } - } - } } }, "/api/admin/poll/{year}/{month}": { @@ -350,7 +440,7 @@ var doc = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/poll.Poll" + "$ref": "#/definitions/models.Poll" } }, "404": { @@ -404,23 +494,23 @@ var doc = `{ }, "/api/common/monthlyReport": { "get": { - "description": "Find the most recent MonthlyNews and try to find the corresponding poll if it exists", + "description": "Find the MonthlyInfo of the current month and try to find the corresponding monthlyNews and poll", "produces": [ "application/json" ], "tags": [ "monthlyReport" ], - "summary": "Get details of the most recent monthlyReport", + "summary": "Get details of the current monthlyReport", "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/monthlyReport.MonthlyReport" + "$ref": "#/definitions/models.MonthlyReport" } }, "404": { - "description": "Not Found", + "description": "Not found", "schema": { "type": "string" } @@ -458,11 +548,11 @@ var doc = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/monthlyReport.MonthlyReport" + "$ref": "#/definitions/models.MonthlyReport" } }, "404": { - "description": "Not Found", + "description": "Not found", "schema": { "type": "string" } @@ -472,16 +562,30 @@ var doc = `{ } }, "definitions": { - "monthlyNews.MonthlyNews": { + "models.MonthlyInfo": { "type": "object", "properties": { - "header": { + "info": { "type": "string" }, "month": { "type": "integer" }, - "quote": { + "year": { + "type": "integer" + } + } + }, + "models.MonthlyNews": { + "type": "object", + "properties": { + "content": { + "type": "string" + }, + "month": { + "type": "integer" + }, + "title": { "type": "string" }, "year": { @@ -489,10 +593,10 @@ var doc = `{ } } }, - "monthlyReport.MonthlyReport": { + "models.MonthlyReport": { "type": "object", "properties": { - "header": { + "info": { "type": "string" }, "link": { @@ -501,10 +605,13 @@ var doc = `{ "month": { "type": "integer" }, - "question": { + "newsContent": { "type": "string" }, - "quote": { + "newsTitle": { + "type": "string" + }, + "question": { "type": "string" }, "year": { @@ -512,7 +619,7 @@ var doc = `{ } } }, - "poll.Poll": { + "models.Poll": { "type": "object", "properties": { "link": { @@ -562,6 +669,13 @@ func (s *s) ReadDoc() string { a, _ := json.Marshal(v) return string(a) }, + "escape": func(v interface{}) string { + // escape tabs + str := strings.Replace(v.(string), "\t", "\\t", -1) + // replace " with \", and if that results in \\", replace that with \\\" + str = strings.Replace(str, "\"", "\\\"", -1) + return strings.Replace(str, "\\\\\"", "\\\\\\\"", -1) + }, }).Parse(doc) if err != nil { return doc diff --git a/docs/swagger.json b/docs/swagger.json index d179c02..e7aa192 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -13,30 +13,30 @@ "host": "localhost:1443", "basePath": "/", "paths": { - "/api/admin/monthlyNews": { + "/api/admin/monthlyInfo": { "get": { - "description": "Get details of all monthlyNews", + "description": "Get details of all monthlyInfo", "produces": [ "application/json" ], "tags": [ - "monthlyNews" + "monthlyInfo" ], - "summary": "List all monthlyNews", + "summary": "List all monthlyInfo", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { - "$ref": "#/definitions/monthlyNews.MonthlyNews" + "$ref": "#/definitions/models.MonthlyInfo" } } } } }, "put": { - "description": "Create/update a specific monthlyNews' content", + "description": "Create/update a specific monthlyInfo' content", "consumes": [ "application/json" ], @@ -44,17 +44,17 @@ "application/json" ], "tags": [ - "monthlyNews" + "monthlyInfo" ], - "summary": "Create/update a specific monthlyNews' content", + "summary": "Create/update a specific monthlyInfo' content", "parameters": [ { - "description": "MonthlyNews to create/update with new content", - "name": "monthlyNews", + "description": "MonthlyInfo to create/update with new content", + "name": "monthlyInfo", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/monthlyNews.MonthlyNews" + "$ref": "#/definitions/models.MonthlyInfo" } } ], @@ -62,13 +62,13 @@ "200": { "description": "Updated successfully", "schema": { - "$ref": "#/definitions/monthlyNews.MonthlyNews" + "$ref": "#/definitions/models.MonthlyInfo" } }, "201": { "description": "Created successfully", "schema": { - "$ref": "#/definitions/monthlyNews.MonthlyNews" + "$ref": "#/definitions/models.MonthlyInfo" } }, "400": { @@ -84,9 +84,114 @@ } } } + } + }, + "/api/admin/monthlyInfo/{year}/{month}": { + "get": { + "description": "Get details of a specific monthlyInfo", + "produces": [ + "application/json" + ], + "tags": [ + "monthlyInfo" + ], + "summary": "Get details of a specific monthlyInfo", + "parameters": [ + { + "type": "integer", + "description": "Year of the monthlyInfo", + "name": "year", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Month of the monthlyInfo", + "name": "month", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.MonthlyInfo" + } + }, + "404": { + "description": "Not found", + "schema": { + "type": "string" + } + } + } + }, + "delete": { + "description": "Delete a specific monthlyInfo", + "produces": [ + "application/json" + ], + "tags": [ + "monthlyInfo" + ], + "summary": "Delete a specific monthlyInfo", + "parameters": [ + { + "type": "integer", + "description": "Year of the monthlyInfo", + "name": "year", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Month of the monthlyInfo", + "name": "month", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "successful delete", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Not found", + "schema": { + "type": "string" + } + } + } + } + }, + "/api/admin/monthlyNews": { + "get": { + "description": "Get details of all monthlyNews", + "produces": [ + "application/json" + ], + "tags": [ + "monthlyNews" + ], + "summary": "List all monthlyNews", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.MonthlyNews" + } + } + } + } }, - "post": { - "description": "Create a new monthlyNews", + "put": { + "description": "Create/update a specific monthlyNews' content", "consumes": [ "application/json" ], @@ -96,23 +201,41 @@ "tags": [ "monthlyNews" ], - "summary": "Create a new monthlyNews", + "summary": "Create/update a specific monthlyNews' content", "parameters": [ { - "description": "MonthlyNews to create", + "description": "MonthlyNews to create/update with new content", "name": "monthlyNews", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/monthlyNews.MonthlyNews" + "$ref": "#/definitions/models.MonthlyNews" } } ], "responses": { + "200": { + "description": "Updated successfully", + "schema": { + "$ref": "#/definitions/models.MonthlyNews" + } + }, "201": { - "description": "Created", + "description": "Created successfully", "schema": { - "$ref": "#/definitions/monthlyNews.MonthlyNews" + "$ref": "#/definitions/models.MonthlyNews" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "type": "string" } } } @@ -148,7 +271,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/monthlyNews.MonthlyNews" + "$ref": "#/definitions/models.MonthlyNews" } }, "404": { @@ -216,7 +339,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/poll.Poll" + "$ref": "#/definitions/models.Poll" } } } @@ -241,7 +364,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/poll.Poll" + "$ref": "#/definitions/models.Poll" } } ], @@ -249,13 +372,13 @@ "200": { "description": "Updated successfully", "schema": { - "$ref": "#/definitions/poll.Poll" + "$ref": "#/definitions/models.Poll" } }, "201": { "description": "Created successfully", "schema": { - "$ref": "#/definitions/poll.Poll" + "$ref": "#/definitions/models.Poll" } }, "400": { @@ -271,38 +394,6 @@ } } } - }, - "post": { - "description": "Create a new poll", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "poll" - ], - "summary": "Create a new poll", - "parameters": [ - { - "description": "Poll to create", - "name": "poll", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/poll.Poll" - } - } - ], - "responses": { - "201": { - "description": "Created", - "schema": { - "$ref": "#/definitions/poll.Poll" - } - } - } } }, "/api/admin/poll/{year}/{month}": { @@ -335,7 +426,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/poll.Poll" + "$ref": "#/definitions/models.Poll" } }, "404": { @@ -389,23 +480,23 @@ }, "/api/common/monthlyReport": { "get": { - "description": "Find the most recent MonthlyNews and try to find the corresponding poll if it exists", + "description": "Find the MonthlyInfo of the current month and try to find the corresponding monthlyNews and poll", "produces": [ "application/json" ], "tags": [ "monthlyReport" ], - "summary": "Get details of the most recent monthlyReport", + "summary": "Get details of the current monthlyReport", "responses": { "200": { "description": "OK", "schema": { - "$ref": "#/definitions/monthlyReport.MonthlyReport" + "$ref": "#/definitions/models.MonthlyReport" } }, "404": { - "description": "Not Found", + "description": "Not found", "schema": { "type": "string" } @@ -443,11 +534,11 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/monthlyReport.MonthlyReport" + "$ref": "#/definitions/models.MonthlyReport" } }, "404": { - "description": "Not Found", + "description": "Not found", "schema": { "type": "string" } @@ -457,16 +548,30 @@ } }, "definitions": { - "monthlyNews.MonthlyNews": { + "models.MonthlyInfo": { + "type": "object", + "properties": { + "info": { + "type": "string" + }, + "month": { + "type": "integer" + }, + "year": { + "type": "integer" + } + } + }, + "models.MonthlyNews": { "type": "object", "properties": { - "header": { + "content": { "type": "string" }, "month": { "type": "integer" }, - "quote": { + "title": { "type": "string" }, "year": { @@ -474,10 +579,10 @@ } } }, - "monthlyReport.MonthlyReport": { + "models.MonthlyReport": { "type": "object", "properties": { - "header": { + "info": { "type": "string" }, "link": { @@ -486,10 +591,13 @@ "month": { "type": "integer" }, - "question": { + "newsContent": { "type": "string" }, - "quote": { + "newsTitle": { + "type": "string" + }, + "question": { "type": "string" }, "year": { @@ -497,7 +605,7 @@ } } }, - "poll.Poll": { + "models.Poll": { "type": "object", "properties": { "link": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 9f1922d..5edbca6 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,32 +1,43 @@ basePath: / definitions: - monthlyNews.MonthlyNews: + models.MonthlyInfo: properties: - header: + info: type: string month: type: integer - quote: + year: + type: integer + type: object + models.MonthlyNews: + properties: + content: + type: string + month: + type: integer + title: type: string year: type: integer type: object - monthlyReport.MonthlyReport: + models.MonthlyReport: properties: - header: + info: type: string link: type: string month: type: integer - question: + newsContent: + type: string + newsTitle: type: string - quote: + question: type: string year: type: integer type: object - poll.Poll: + models.Poll: properties: link: type: string @@ -47,9 +58,9 @@ info: title: Backoffice API version: "1.0" paths: - /api/admin/monthlyNews: + /api/admin/monthlyInfo: get: - description: Get details of all monthlyNews + description: Get details of all monthlyInfo produces: - application/json responses: @@ -57,30 +68,112 @@ paths: description: OK schema: items: - $ref: '#/definitions/monthlyNews.MonthlyNews' + $ref: '#/definitions/models.MonthlyInfo' type: array - summary: List all monthlyNews + summary: List all monthlyInfo tags: - - monthlyNews - post: + - monthlyInfo + put: consumes: - application/json - description: Create a new monthlyNews + description: Create/update a specific monthlyInfo' content parameters: - - description: MonthlyNews to create + - description: MonthlyInfo to create/update with new content in: body - name: monthlyNews + name: monthlyInfo required: true schema: - $ref: '#/definitions/monthlyNews.MonthlyNews' + $ref: '#/definitions/models.MonthlyInfo' produces: - application/json responses: + "200": + description: Updated successfully + schema: + $ref: '#/definitions/models.MonthlyInfo' "201": - description: Created + description: Created successfully + schema: + $ref: '#/definitions/models.MonthlyInfo' + "400": + description: Bad Request + schema: + type: string + "500": + description: Internal server error + schema: + type: string + summary: Create/update a specific monthlyInfo' content + tags: + - monthlyInfo + /api/admin/monthlyInfo/{year}/{month}: + delete: + description: Delete a specific monthlyInfo + parameters: + - description: Year of the monthlyInfo + in: path + name: year + required: true + type: integer + - description: Month of the monthlyInfo + in: path + name: month + required: true + type: integer + produces: + - application/json + responses: + "200": + description: successful delete + schema: + type: string + "404": + description: Not found + schema: + type: string + summary: Delete a specific monthlyInfo + tags: + - monthlyInfo + get: + description: Get details of a specific monthlyInfo + parameters: + - description: Year of the monthlyInfo + in: path + name: year + required: true + type: integer + - description: Month of the monthlyInfo + in: path + name: month + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.MonthlyInfo' + "404": + description: Not found + schema: + type: string + summary: Get details of a specific monthlyInfo + tags: + - monthlyInfo + /api/admin/monthlyNews: + get: + description: Get details of all monthlyNews + produces: + - application/json + responses: + "200": + description: OK schema: - $ref: '#/definitions/monthlyNews.MonthlyNews' - summary: Create a new monthlyNews + items: + $ref: '#/definitions/models.MonthlyNews' + type: array + summary: List all monthlyNews tags: - monthlyNews put: @@ -93,18 +186,18 @@ paths: name: monthlyNews required: true schema: - $ref: '#/definitions/monthlyNews.MonthlyNews' + $ref: '#/definitions/models.MonthlyNews' produces: - application/json responses: "200": description: Updated successfully schema: - $ref: '#/definitions/monthlyNews.MonthlyNews' + $ref: '#/definitions/models.MonthlyNews' "201": description: Created successfully schema: - $ref: '#/definitions/monthlyNews.MonthlyNews' + $ref: '#/definitions/models.MonthlyNews' "400": description: Bad Request schema: @@ -163,7 +256,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/monthlyNews.MonthlyNews' + $ref: '#/definitions/models.MonthlyNews' "404": description: Not found schema: @@ -181,32 +274,11 @@ paths: description: OK schema: items: - $ref: '#/definitions/poll.Poll' + $ref: '#/definitions/models.Poll' type: array summary: List all polls tags: - poll - post: - consumes: - - application/json - description: Create a new poll - parameters: - - description: Poll to create - in: body - name: poll - required: true - schema: - $ref: '#/definitions/poll.Poll' - produces: - - application/json - responses: - "201": - description: Created - schema: - $ref: '#/definitions/poll.Poll' - summary: Create a new poll - tags: - - poll put: consumes: - application/json @@ -217,18 +289,18 @@ paths: name: poll required: true schema: - $ref: '#/definitions/poll.Poll' + $ref: '#/definitions/models.Poll' produces: - application/json responses: "200": description: Updated successfully schema: - $ref: '#/definitions/poll.Poll' + $ref: '#/definitions/models.Poll' "201": description: Created successfully schema: - $ref: '#/definitions/poll.Poll' + $ref: '#/definitions/models.Poll' "400": description: Bad Request schema: @@ -287,7 +359,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/poll.Poll' + $ref: '#/definitions/models.Poll' "404": description: Not found schema: @@ -297,20 +369,20 @@ paths: - poll /api/common/monthlyReport: get: - description: Find the most recent MonthlyNews and try to find the corresponding - poll if it exists + description: Find the MonthlyInfo of the current month and try to find the corresponding + monthlyNews and poll produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/monthlyReport.MonthlyReport' + $ref: '#/definitions/models.MonthlyReport' "404": - description: Not Found + description: Not found schema: type: string - summary: Get details of the most recent monthlyReport + summary: Get details of the current monthlyReport tags: - monthlyReport /api/common/monthlyReport/{year}/{month}: @@ -333,9 +405,9 @@ paths: "200": description: OK schema: - $ref: '#/definitions/monthlyReport.MonthlyReport' + $ref: '#/definitions/models.MonthlyReport' "404": - description: Not Found + description: Not found schema: type: string summary: Get details of a specific monthlyReport diff --git a/go.mod b/go.mod index 002b1e8..985e21b 100644 --- a/go.mod +++ b/go.mod @@ -3,15 +3,11 @@ module forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server go 1.15 require ( - github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 - github.com/golang/protobuf v1.5.2 // indirect github.com/gorilla/mux v1.8.0 - github.com/swaggo/http-swagger v1.0.0 - github.com/swaggo/swag v1.7.0 - golang.org/x/net v0.0.0-20210525063256-abc453219eb5 // indirect - golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 - google.golang.org/appengine v1.6.7 // indirect - gorm.io/driver/mysql v1.1.1 + github.com/swaggo/http-swagger v1.1.1 + github.com/swaggo/swag v1.7.1 + golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f + gorm.io/driver/mysql v1.1.2 gorm.io/driver/sqlite v1.1.4 - gorm.io/gorm v1.21.12 + gorm.io/gorm v1.21.14 ) diff --git a/go.sum b/go.sum index c9047ca..91f942d 100644 --- a/go.sum +++ b/go.sum @@ -39,7 +39,6 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN 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/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -69,12 +68,14 @@ github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/spec v0.19.14/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA= -github.com/go-openapi/spec v0.20.0 h1:HGLc8AJ7ynOxwv0Lq4TsnwLsWMawHAYiJIFzbcML86I= github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= +github.com/go-openapi/spec v0.20.3 h1:uH9RQ6vdyPSs2pSy9fL8QPspDF2AMIMPtmK5coSSjtQ= +github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY= -github.com/go-openapi/swag v0.19.12 h1:Bc0bnY2c3AoF7Gc+IMIAQQsD8fLHjHpc19wXvYuayQI= github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -100,10 +101,8 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -112,9 +111,8 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -165,14 +163,16 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 h1:PyYN9JH5jY9j6av01SpfRMb+1DWg/i3MbGOKPxJ2wjM= github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= -github.com/swaggo/http-swagger v1.0.0 h1:ksYgVBCYmAaxFsGVGojlPROgYfiQQSllETTWMtHJHTo= -github.com/swaggo/http-swagger v1.0.0/go.mod h1:cKIcshBU9yEAnfWv6ZzVKSsEf8h5ozxB8/zHQWyOQ/8= -github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E= +github.com/swaggo/http-swagger v1.1.1 h1:7cBYOcF/TS0Nx5uA6oOP9DfFV5RYogpazzK1IUmQUII= +github.com/swaggo/http-swagger v1.1.1/go.mod h1:cKIcshBU9yEAnfWv6ZzVKSsEf8h5ozxB8/zHQWyOQ/8= github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo= +github.com/swaggo/swag v1.7.1 h1:gY9ZakXlNWg/i/v5bQBic7VMZ4teq4m89lpiao74p/s= +github.com/swaggo/swag v1.7.1/go.mod h1:gAiHxNTb9cIpNmA/VEGUP+CyZMCP/EW7mdtc8Bny+p8= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -249,15 +249,15 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201207224615-747e23833adb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -294,7 +294,8 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -302,8 +303,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -348,8 +349,9 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208062317-e652b2f42cc7 h1:2OSu5vYyX4LVqZAtqZXnFEcN26SDKIJYlEVIRl1tj8U= golang.org/x/tools v0.0.0-20201208062317-e652b2f42cc7/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -376,9 +378,8 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -429,10 +430,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 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 h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= @@ -446,14 +445,14 @@ 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 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/mysql v1.1.1 h1:yr1bpyqiwuSPJ4aGGUX9nu46RHXlF8RASQVb1QQNcvo= -gorm.io/driver/mysql v1.1.1/go.mod h1:KdrTanmfLPPyAOeYGyG+UpDys7/7eeWT1zCq+oekYnU= +gorm.io/driver/mysql v1.1.2 h1:OofcyE2lga734MxwcCW9uB4mWNXMr50uaGRVwQL2B0M= +gorm.io/driver/mysql v1.1.2/go.mod h1:4P/X9vSc3WTrhTLZ259cpFd6xKNYiSSdSZngkSBGIMM= gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM= gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw= gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.21.9/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= -gorm.io/gorm v1.21.12 h1:3fQM0Eiz7jcJEhPggHEpoYnsGZqynMzverL77DV40RM= gorm.io/gorm v1.21.12/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= +gorm.io/gorm v1.21.14 h1:NAR9A/3SoyiPVHouW/rlpMUZvuQZ6Z6UYGz+2tosSQo= +gorm.io/gorm v1.21.14/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/common/common.go b/internal/common/common.go index e7c055e..708ba1c 100644 --- a/internal/common/common.go +++ b/internal/common/common.go @@ -5,6 +5,7 @@ import ( "crypto/rand" "encoding/base64" "encoding/json" + "errors" "io" "net/http" "os" @@ -13,6 +14,8 @@ import ( "sync" "log" + + "github.com/gorilla/mux" ) var ( @@ -147,3 +150,24 @@ func BoolValueFromEnv(ev string, def bool) bool { } return v } + +func YearMonthFromRequest(r *http.Request) (year int, month int, err error) { + vars := mux.Vars(r) + yearStr := vars["year"] + monthStr := vars["month"] + + if yearStr == "" || monthStr == "" { + return 0, 0, errors.New("missing query element") + } + + year, err = strconv.Atoi(yearStr) + if err != nil { + return 0, 0, errors.New("year is not an integer") + } + month, err = strconv.Atoi(monthStr) + if err != nil { + return 0, 0, errors.New("month is not an integer") + } + + return year, month, nil +} diff --git a/internal/database/database.go b/internal/database/database.go deleted file mode 100644 index f8d2b00..0000000 --- a/internal/database/database.go +++ /dev/null @@ -1,106 +0,0 @@ -package database - -import ( - "fmt" - - "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/common" - "gorm.io/driver/mysql" - "gorm.io/driver/sqlite" - "gorm.io/gorm" -) - -type MonthlyContent struct { - gorm.Model - Year int - Month int - ContentType string - Content string -} - -var ( - db *gorm.DB - dbUser = common.StringValueFromEnv("DATABASE_USER", "") - dbPassword = common.StringValueFromEnv("DATABASE_PASSWORD", "") - dbName = common.StringValueFromEnv("DATABASE_NAME", "") - dbHost = common.StringValueFromEnv("DATABASE_HOST", "") -) - -func init() { - var err error - // If database crendential missing, use SQL Lite (used for testing purposes) - - if dbUser == "" || dbPassword == "" || dbName == "" { - db, err = gorm.Open(sqlite.Open("backoffice.db"), &gorm.Config{}) - if err != nil { - panic("failed to connect database") - } - } else { - dsn := fmt.Sprintf("%v:%v@tcp(%v:3306)/%v?charset=utf8mb4&parseTime=True&loc=Local", dbUser, dbPassword, dbHost, dbName) - db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) - if err != nil { - panic("failed to connect database") - } - } - // Migrate the schema - db.AutoMigrate(&MonthlyContent{}) -} - -func Exists(year int, month int, contentType string) bool { - var monthlyContent MonthlyContent - if err := db.Where("year = ? AND month = ? AND content_type = ?", year, month, contentType).First(&monthlyContent).Error; err != nil { - return false - } - return true -} - -func Get(year int, month int, contentType string) (MonthlyContent, error) { - var monthlyContent MonthlyContent - if err := db.Where("year = ? AND month = ? AND content_type = ?", year, month, contentType).First(&monthlyContent).Error; err != nil { - return MonthlyContent{}, err - } - return monthlyContent, nil -} - -func GetMostRecent(contentType string) (MonthlyContent, error) { - var monthlyContent MonthlyContent - - if err := db.Where("content_type = ?", contentType).Order("year desc, month desc").First(&monthlyContent).Error; err != nil { - return MonthlyContent{}, err - } - return monthlyContent, nil -} - -func GetAll(contentType string) []MonthlyContent { - var monthlyContents []MonthlyContent - db.Where("content_type = ?", contentType).Find(&monthlyContents) - return monthlyContents -} - -func Create(year int, month int, contentType string, content string) error { - if err := db.Create(&MonthlyContent{Year: year, Month: month, ContentType: contentType, Content: content}).Error; err != nil { - return err - } - return nil -} - -func Delete(year int, month int, contentType string) error { - - if err := db.Where("year = ? AND month = ? AND content_type = ?", year, month, contentType).Delete(&MonthlyContent{}).Error; err != nil { - return err - } - return nil -} - -func Update(year int, month int, contentType string, newContent string) error { - var monthlyContent MonthlyContent - if err := db.Where("year = ? AND month = ? AND content_type = ?", year, month, contentType).First(&monthlyContent).Error; err != nil { - return err - } - - monthlyContent.Content = newContent - - if err := db.Save(&monthlyContent).Error; err != nil { - return err - } - return nil -} diff --git a/internal/models/models.go b/internal/models/models.go new file mode 100644 index 0000000..fc72cf8 --- /dev/null +++ b/internal/models/models.go @@ -0,0 +1,45 @@ +package models + +import ( + "fmt" + + "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/common" + "gorm.io/driver/mysql" + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +type DataHandler struct { + db *gorm.DB +} + +var ( + dbUser = common.StringValueFromEnv("DATABASE_USER", "") + dbPassword = common.StringValueFromEnv("DATABASE_PASSWORD", "") + dbName = common.StringValueFromEnv("DATABASE_NAME", "") + dbHost = common.StringValueFromEnv("DATABASE_HOST", "") +) + +// NewDataHandler init a DataHandler and returns a pointer to it +func NewDataHandler() *DataHandler { + var db *gorm.DB + var err error + if dbUser == "" || dbPassword == "" || dbName == "" { + db, err = gorm.Open(sqlite.Open("backoffice.db"), &gorm.Config{}) + if err != nil { + panic("failed to connect database") + } + } else { + dsn := fmt.Sprintf("%v:%v@tcp(%v:3306)/%v?charset=utf8mb4&parseTime=True&loc=Local", dbUser, dbPassword, dbHost, dbName) + db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) + if err != nil { + panic("failed to connect database") + } + } + + // Migrate the schema + db.AutoMigrate(&MonthlyInfo{}) + db.AutoMigrate(&MonthlyNews{}) + db.AutoMigrate(&Poll{}) + return &DataHandler{db: db} +} diff --git a/internal/models/monthlyInfo.go b/internal/models/monthlyInfo.go new file mode 100644 index 0000000..d55b7f2 --- /dev/null +++ b/internal/models/monthlyInfo.go @@ -0,0 +1,140 @@ +package models + +import ( + "encoding/json" + "log" + "net/http" + + "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/common" +) + +type MonthlyInfo struct { + Year int `json:"year"` + Month int `json:"month"` + Info string `json:"info"` +} + +// GetAllMonthlyInfo godoc +// @Summary List all monthlyInfo +// @Description Get details of all monthlyInfo +// @Tags monthlyInfo +// @Produce json +// @Success 200 {array} MonthlyInfo +// @Router /api/admin/monthlyInfo [get] +func (dh *DataHandler) GetAllMonthlyInfo(w http.ResponseWriter, r *http.Request) { + var monthlyInfo []MonthlyInfo + dh.db.Find(&monthlyInfo) + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(monthlyInfo) + log.Printf("| get all monthlyInfo | %v", r.RemoteAddr) +} + +// GetSingleMonthlyInfo godoc +// @Summary Get details of a specific monthlyInfo +// @Description Get details of a specific monthlyInfo +// @Tags monthlyInfo +// @Produce json +// @Success 200 {object} MonthlyInfo +// @Failure 404 {string} string "Not found" +// @Param year path int true "Year of the monthlyInfo" +// @Param month path int true "Month of the monthlyInfo" +// @Router /api/admin/monthlyInfo/{year}/{month} [get] +func (dh *DataHandler) GetSingleMonthlyInfo(w http.ResponseWriter, r *http.Request) { + year, month, err := common.YearMonthFromRequest(r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + } + + w.Header().Set("Content-Type", "application/json") + + var monthlyInfo MonthlyInfo + err = dh.db.Where("year = ? AND month = ?", year, month).First(&monthlyInfo).Error + if err != nil { + // If not found, answer "not found" + w.WriteHeader(http.StatusNotFound) + return + } + json.NewEncoder(w).Encode(monthlyInfo) +} + +// SaveMonthlyInfo godoc +// @Summary Create/update a specific monthlyInfo' content +// @Description Create/update a specific monthlyInfo' content +// @Tags monthlyInfo +// @Accept json +// @Produce json +// @Success 200 {object} MonthlyInfo "Updated successfully" +// @Success 201 {object} MonthlyInfo "Created successfully" +// @Failure 400 {string} string "Bad Request" +// @Failure 500 {string} string "Internal server error" +// @Param monthlyInfo body MonthlyInfo true "MonthlyInfo to create/update with new content" +// @Router /api/admin/monthlyInfo [put] +func (dh *DataHandler) SaveMonthlyInfo(w http.ResponseWriter, r *http.Request) { + if r.Body == http.NoBody { + http.Error(w, "request body is empty", http.StatusBadRequest) + return + } + + decoder := json.NewDecoder(r.Body) + var monthlyInfo MonthlyInfo + err := decoder.Decode(&monthlyInfo) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + // Check if this monthlyInfo exists + err = dh.db.Where("year = ? AND month = ?", monthlyInfo.Year, monthlyInfo.Month).First(&MonthlyInfo{}).Error + + if err != nil { + // Create a monthlyInfo + err = dh.db.Create(&MonthlyInfo{Year: monthlyInfo.Year, Month: monthlyInfo.Month, Info: monthlyInfo.Info}).Error + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(monthlyInfo) + + log.Printf("| new monthlyInfo | year : %d month : %d | %v", monthlyInfo.Year, monthlyInfo.Month, r.RemoteAddr) + return + + } else { + // Update info + err = dh.db.Model(&MonthlyInfo{}).Where("year = ? AND month = ?", monthlyInfo.Year, monthlyInfo.Month).Update("info", monthlyInfo.Info).Error + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + json.NewEncoder(w).Encode(monthlyInfo) + log.Printf("| updated monthlyInfo | year : %d month : %d | %v", monthlyInfo.Year, monthlyInfo.Month, r.RemoteAddr) + } +} + +// DeleteMonthlyInfo godoc +// @Summary Delete a specific monthlyInfo +// @Description Delete a specific monthlyInfo +// @Tags monthlyInfo +// @Produce json +// @Success 200 {string} string "successful delete" +// @Failure 404 {string} string "Not found" +// @Param year path int true "Year of the monthlyInfo" +// @Param month path int true "Month of the monthlyInfo" +// @Router /api/admin/monthlyInfo/{year}/{month} [delete] +func (dh *DataHandler) DeleteMonthlyInfo(w http.ResponseWriter, r *http.Request) { + year, month, err := common.YearMonthFromRequest(r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + } + + err = dh.db.Where("year = ? AND month = ?", year, month).Delete(&MonthlyInfo{}).Error + if err != nil { + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + w.WriteHeader(http.StatusOK) + w.Write([]byte("successful delete")) +} diff --git a/internal/models/monthlyNews.go b/internal/models/monthlyNews.go new file mode 100644 index 0000000..aba3db0 --- /dev/null +++ b/internal/models/monthlyNews.go @@ -0,0 +1,153 @@ +package models + +import ( + "encoding/json" + "log" + "net/http" + + "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/common" +) + +type MonthlyNews struct { + Year int `json:"year"` + Month int `json:"month"` + Title string `json:"title"` + Content string `json:"content"` +} + +// GetAllMonthlyNews godoc +// @Summary List all monthlyNews +// @Description Get details of all monthlyNews +// @Tags monthlyNews +// @Produce json +// @Success 200 {array} MonthlyNews +// @Router /api/admin/monthlyNews [get] +func (dh *DataHandler) GetAllMonthlyNews(w http.ResponseWriter, r *http.Request) { + var monthlyNews []MonthlyNews + dh.db.Find(&monthlyNews) + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(monthlyNews) + log.Printf("| get all monthlyNews | %v", r.RemoteAddr) +} + +// GetSingleMonthlyNews godoc +// @Summary Get details of a specific monthlyNews +// @Description Get details of a specific monthlyNews +// @Tags monthlyNews +// @Produce json +// @Success 200 {object} MonthlyNews +// @Failure 404 {string} string "Not found" +// @Param year path int true "Year of the monthlyNews" +// @Param month path int true "Month of the monthlyNews" +// @Router /api/admin/monthlyNews/{year}/{month} [get] +func (dh *DataHandler) GetSingleMonthlyNews(w http.ResponseWriter, r *http.Request) { + year, month, err := common.YearMonthFromRequest(r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + } + + w.Header().Set("Content-Type", "application/json") + + var monthlyNews MonthlyNews + err = dh.db.Where("year = ? AND month = ?", year, month).First(&monthlyNews).Error + if err != nil { + // If not found, answer "not found" + w.WriteHeader(http.StatusNotFound) + return + } + json.NewEncoder(w).Encode(monthlyNews) +} + +// SaveMonthlyNews godoc +// @Summary Create/update a specific monthlyNews' content +// @Description Create/update a specific monthlyNews' content +// @Tags monthlyNews +// @Accept json +// @Produce json +// @Success 200 {object} MonthlyNews "Updated successfully" +// @Success 201 {object} MonthlyNews "Created successfully" +// @Failure 400 {string} string "Bad Request" +// @Failure 500 {string} string "Internal server error" +// @Param monthlyNews body MonthlyNews true "MonthlyNews to create/update with new content" +// @Router /api/admin/monthlyNews [put] +func (dh *DataHandler) SaveMonthlyNews(w http.ResponseWriter, r *http.Request) { + if r.Body == http.NoBody { + http.Error(w, "request body is empty", http.StatusBadRequest) + return + } + + decoder := json.NewDecoder(r.Body) + var monthlyNews MonthlyNews + err := decoder.Decode(&monthlyNews) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + // Check if this monthlyNews exists + err = dh.db.Where("year = ? AND month = ?", monthlyNews.Year, monthlyNews.Month).First(&MonthlyNews{}).Error + + // Default title + if monthlyNews.Title == "" { + monthlyNews.Title = "Les nouveautés du service" + } + + if err != nil { + + // Create a monthlyNews + err = dh.db.Create(&MonthlyNews{Year: monthlyNews.Year, Month: monthlyNews.Month, Title: monthlyNews.Title, Content: monthlyNews.Content}).Error + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(monthlyNews) + + log.Printf("| new monthlyNews | year : %d month : %d title : %v| %v", monthlyNews.Year, monthlyNews.Month, monthlyNews.Title, r.RemoteAddr) + return + + } else { + // Update title + err = dh.db.Model(&MonthlyNews{}).Where("year = ? AND month = ?", monthlyNews.Year, monthlyNews.Month).Update("title", monthlyNews.Title).Error + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + // Update content + err = dh.db.Model(&MonthlyNews{}).Where("year = ? AND month = ?", monthlyNews.Year, monthlyNews.Month).Update("content", monthlyNews.Content).Error + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + json.NewEncoder(w).Encode(monthlyNews) + log.Printf("| updated monthlyNews | year : %d month : %d title : %v| %v", monthlyNews.Year, monthlyNews.Month, monthlyNews.Title, r.RemoteAddr) + } +} + +// DeleteMonthlyNews godoc +// @Summary Delete a specific monthlyNews +// @Description Delete a specific monthlyNews +// @Tags monthlyNews +// @Produce json +// @Success 200 {string} string "successful delete" +// @Failure 404 {string} string "Not found" +// @Param year path int true "Year of the monthlyNews" +// @Param month path int true "Month of the monthlyNews" +// @Router /api/admin/monthlyNews/{year}/{month} [delete] +func (dh *DataHandler) DeleteMonthlyNews(w http.ResponseWriter, r *http.Request) { + year, month, err := common.YearMonthFromRequest(r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + } + + err = dh.db.Where("year = ? AND month = ?", year, month).Delete(&MonthlyNews{}).Error + if err != nil { + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + w.WriteHeader(http.StatusOK) + w.Write([]byte("successful delete")) +} diff --git a/internal/models/monthlyReport.go b/internal/models/monthlyReport.go new file mode 100644 index 0000000..03b2110 --- /dev/null +++ b/internal/models/monthlyReport.go @@ -0,0 +1,94 @@ +package models + +import ( + "encoding/json" + "net/http" + "time" + + "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/common" +) + +type MonthlyReport struct { + Year int `json:"year"` + Month int `json:"month"` + Info string `json:"info"` + NewsTitle string `json:"newsTitle"` + NewsContent string `json:"newsContent"` + Question string `json:"question"` + Link string `json:"link"` +} + +// GetMonthlyReport godoc +// @Summary Get details of a specific monthlyReport +// @Description Get details of a specific monthlyReport +// @Tags monthlyReport +// @Produce json +// @Success 200 {object} MonthlyReport +// @Failure 404 {string} string "Not found" +// @Param year path int true "Year of the monthlyReport" +// @Param month path int true "Month of the monthlyReport" +// @Router /api/common/monthlyReport/{year}/{month} [get] +func (dh *DataHandler) GetMonthlyReport(w http.ResponseWriter, r *http.Request) { + year, month, err := common.YearMonthFromRequest(r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + monthlyReport, err := dh.getMonthlyReport(year, month) + if err != nil { + w.WriteHeader(http.StatusNotFound) + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(monthlyReport) +} + +// GetCurrentMonthlyReport godoc +// @Summary Get details of the current monthlyReport +// @Description Find the MonthlyInfo of the current month and try to find the corresponding monthlyNews and poll +// @Tags monthlyReport +// @Produce json +// @Success 200 {object} MonthlyReport +// @Failure 404 {string} string "Not found" +// @Router /api/common/monthlyReport [get] +func (dh *DataHandler) GetCurrentMonthlyReport(w http.ResponseWriter, r *http.Request) { + + year, month, _ := time.Now().Date() + + monthlyReport, err := dh.getMonthlyReport(year, int(month)-1) + if err != nil { + w.WriteHeader(http.StatusNotFound) + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(monthlyReport) +} + +func (dh *DataHandler) getMonthlyReport(year int, month int) (monthlyReport MonthlyReport, err error) { + var monthlyInfo MonthlyInfo + err = dh.db.Where("year = ? AND month = ?", year, month).First(&monthlyInfo).Error + if err != nil { + return MonthlyReport{}, err + } + + var monthlyNews MonthlyNews + dh.db.Where("year = ? AND month = ?", year, month).First(&monthlyNews) + + var poll Poll + dh.db.Where("year = ? AND month = ?", year, month).First(&poll) + + monthlyReport = MonthlyReport{ + Year: year, + Month: month, + Info: monthlyInfo.Info, + NewsTitle: monthlyNews.Title, + NewsContent: monthlyNews.Content, + Question: poll.Question, + Link: poll.Link, + } + + return monthlyReport, nil +} diff --git a/internal/models/poll.go b/internal/models/poll.go new file mode 100644 index 0000000..aea9836 --- /dev/null +++ b/internal/models/poll.go @@ -0,0 +1,150 @@ +package models + +import ( + "encoding/json" + "log" + "net/http" + + "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/common" +) + +type Poll struct { + Year int `json:"year"` + Month int `json:"month"` + Question string `json:"question"` + Link string `json:"link"` +} + +// GetAllPolls godoc +// @Summary List all polls +// @Description Get details of all polls +// @Tags poll +// @Produce json +// @Success 200 {array} Poll +// @Router /api/admin/poll [get] +func (dh *DataHandler) GetAllPolls(w http.ResponseWriter, r *http.Request) { + var polls []Poll + err := dh.db.Find(&polls).Error + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(polls) + log.Printf("| get all polls | %v", r.RemoteAddr) +} + +// GetSinglePoll godoc +// @Summary Get details of a specific poll +// @Description Get details of a specific poll +// @Tags poll +// @Produce json +// @Success 200 {object} Poll +// @Failure 404 {string} string "Not found" +// @Param year path int true "Year of the poll" +// @Param month path int true "Month of the poll" +// @Router /api/admin/poll/{year}/{month} [get] +func (dh *DataHandler) GetSinglePoll(w http.ResponseWriter, r *http.Request) { + year, month, err := common.YearMonthFromRequest(r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + } + + w.Header().Set("Content-Type", "application/json") + + var poll Poll + err = dh.db.Where("year = ? AND month = ?", year, month).First(&poll).Error + if err != nil { + // If not found, answer "not found" + w.WriteHeader(http.StatusNotFound) + return + } + json.NewEncoder(w).Encode(poll) +} + +// SavePoll godoc +// @Summary Update a specific poll' content +// @Description Update a specific poll' content +// @Tags poll +// @Accept json +// @Produce json +// @Success 200 {object} Poll "Updated successfully" +// @Success 201 {object} Poll "Created successfully" +// @Failure 400 {string} string "Bad Request" +// @Failure 500 {string} string "Internal server error" +// @Param poll body Poll true "Poll to update with new content" +// @Router /api/admin/poll [put] +func (dh *DataHandler) SavePoll(w http.ResponseWriter, r *http.Request) { + if r.Body == http.NoBody { + http.Error(w, "request body is empty", http.StatusBadRequest) + return + } + + decoder := json.NewDecoder(r.Body) + var poll Poll + err := decoder.Decode(&poll) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + // Check if this poll exists + err = dh.db.Where("year = ? AND month = ?", poll.Year, poll.Month).First(&Poll{}).Error + + if err != nil { + // Create a poll + err = dh.db.Create(&Poll{Year: poll.Year, Month: poll.Month, Question: poll.Question, Link: poll.Link}).Error + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(poll) + log.Printf("| new poll | year : %d month : %d | %v", poll.Year, poll.Month, r.RemoteAddr) + return + + } else { + // Update question + err = dh.db.Model(&Poll{}).Where("year = ? AND month = ?", poll.Year, poll.Month).Update("question", poll.Question).Error + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + // Update link + err = dh.db.Model(&Poll{}).Where("year = ? AND month = ?", poll.Year, poll.Month).Update("link", poll.Link).Error + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + json.NewEncoder(w).Encode(poll) + log.Printf("| updated poll year : %d month : %d | %v", poll.Year, poll.Month, r.RemoteAddr) + } +} + +// DeletePoll godoc +// @Summary Delete a specific poll +// @Description Delete a specific poll +// @Tags poll +// @Produce json +// @Success 200 {string} string "successful delete" +// @Failure 404 {string} string "Not found" +// @Param year path int true "Year of the poll" +// @Param month path int true "Month of the poll" +// @Router /api/admin/poll/{year}/{month} [delete] +func (dh *DataHandler) DeletePoll(w http.ResponseWriter, r *http.Request) { + year, month, err := common.YearMonthFromRequest(r) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + } + + err = dh.db.Where("year = ? AND month = ?", year, month).Delete(&Poll{}).Error + if err != nil { + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + w.WriteHeader(http.StatusOK) + w.Write([]byte("successful delete")) +} diff --git a/internal/monthlyNews/monthlyNews.go b/internal/monthlyNews/monthlyNews.go deleted file mode 100644 index cff7ac5..0000000 --- a/internal/monthlyNews/monthlyNews.go +++ /dev/null @@ -1,244 +0,0 @@ -package monthlyNews - -import ( - "encoding/json" - "fmt" - "log" - "net/http" - "strconv" - - "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/database" - "github.com/gorilla/mux" -) - -type MonthlyNews struct { - Year int `json:"year"` - Month int `json:"month"` - Header string `json:"header"` - Quote string `json:"quote"` -} - -// GetAllMonthlyNews godoc -// @Summary List all monthlyNews -// @Description Get details of all monthlyNews -// @Tags monthlyNews -// @Produce json -// @Success 200 {array} MonthlyNews -// @Router /api/admin/monthlyNews [get] -func GetAllMonthlyNews(w http.ResponseWriter, r *http.Request) { - monthlyHeaders := database.GetAll("header") - monthlyQuotes := database.GetAll("quote") - - var monthlyNews []MonthlyNews - - for _, header := range monthlyHeaders { - quoteExists := false - for _, quote := range monthlyQuotes { - if header.Year == quote.Year && header.Month == quote.Month { - monthlyNews = append(monthlyNews, MonthlyNews{header.Year, header.Month, header.Content, quote.Content}) - quoteExists = true - break - } - } - if !quoteExists { - monthlyNews = append(monthlyNews, MonthlyNews{header.Year, header.Month, header.Content, ""}) - } - } - - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(monthlyNews) - log.Printf("| get all monthly news | %v", r.RemoteAddr) -} - -// GetSingleMonthlyNews godoc -// @Summary Get details of a specific monthlyNews -// @Description Get details of a specific monthlyNews -// @Tags monthlyNews -// @Produce json -// @Success 200 {object} MonthlyNews -// @Failure 404 {string} string "Not found" -// @Param year path int true "Year of the monthlyNews" -// @Param month path int true "Month of the monthlyNews" -// @Router /api/admin/monthlyNews/{year}/{month} [get] -func GetSingleMonthlyNews(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - yearStr := vars["year"] - monthStr := vars["month"] - - if yearStr == "" || monthStr == "" { - http.Error(w, "missing query element", http.StatusBadRequest) - return - } - - year, err := strconv.Atoi(yearStr) - if err != nil { - http.Error(w, "year is not an integer", http.StatusBadRequest) - return - } - month, err := strconv.Atoi(monthStr) - if err != nil { - http.Error(w, "month is not an integer", http.StatusBadRequest) - return - } - - w.Header().Set("Content-Type", "application/json") - header, errH := database.Get(year, month, "header") - quote, errQ := database.Get(year, month, "quote") - if errH != nil || errQ != nil { - // If not found, answer "not found" - w.WriteHeader(http.StatusNotFound) - return - } - monthlyNews := MonthlyNews{Year: year, Month: month, Header: header.Content, Quote: quote.Content} - json.NewEncoder(w).Encode(monthlyNews) -} - -// AddMonthlyNews godoc -// @Summary Create a new monthlyNews -// @Description Create a new monthlyNews -// @Tags monthlyNews -// @Accept json -// @Produce json -// @Success 201 {object} MonthlyNews -// @Param monthlyNews body MonthlyNews true "MonthlyNews to create" -// @Router /api/admin/monthlyNews [post] -func AddMonthlyNews(w http.ResponseWriter, r *http.Request) { - if r.Body == http.NoBody { - http.Error(w, "request body is empty", http.StatusBadRequest) - return - } - - decoder := json.NewDecoder(r.Body) - var monthlyNews MonthlyNews - err := decoder.Decode(&monthlyNews) - if err != nil { - fmt.Println(err) - } - - err = database.Create(monthlyNews.Year, monthlyNews.Month, "header", monthlyNews.Header) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - err = database.Create(monthlyNews.Year, monthlyNews.Month, "quote", monthlyNews.Quote) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - w.WriteHeader(http.StatusCreated) - json.NewEncoder(w).Encode(monthlyNews) - - log.Printf("| new monthly news | year : %d month : %d | %v", monthlyNews.Year, monthlyNews.Month, r.RemoteAddr) -} - -// UpdateMonthlyNews godoc -// @Summary Create/update a specific monthlyNews' content -// @Description Create/update a specific monthlyNews' content -// @Tags monthlyNews -// @Accept json -// @Produce json -// @Success 200 {object} MonthlyNews "Updated successfully" -// @Success 201 {object} MonthlyNews "Created successfully" -// @Failure 400 {string} string "Bad Request" -// @Failure 500 {string} string "Internal server error" -// @Param monthlyNews body MonthlyNews true "MonthlyNews to create/update with new content" -// @Router /api/admin/monthlyNews [put] -func UpdateMonthlyNews(w http.ResponseWriter, r *http.Request) { - if r.Body == http.NoBody { - http.Error(w, "request body is empty", http.StatusBadRequest) - return - } - - decoder := json.NewDecoder(r.Body) - var monthlyNews MonthlyNews - err := decoder.Decode(&monthlyNews) - if err != nil { - fmt.Println(err) - } - - // Check if this monthly news exists - _, errH := database.Get(monthlyNews.Year, monthlyNews.Month, "header") - _, errQ := database.Get(monthlyNews.Year, monthlyNews.Month, "quote") - - if errH != nil || errQ != nil { - err = database.Create(monthlyNews.Year, monthlyNews.Month, "header", monthlyNews.Header) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - err = database.Create(monthlyNews.Year, monthlyNews.Month, "quote", monthlyNews.Quote) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusCreated) - json.NewEncoder(w).Encode(monthlyNews) - log.Printf("| new monthly news | year : %d month : %d | %v", monthlyNews.Year, monthlyNews.Month, r.RemoteAddr) - return - - } else { - err = database.Update(monthlyNews.Year, monthlyNews.Month, "header", monthlyNews.Header) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - err = database.Update(monthlyNews.Year, monthlyNews.Month, "quote", monthlyNews.Quote) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - json.NewEncoder(w).Encode(monthlyNews) - log.Printf("| updated monthly news | year : %d month : %d | %v", monthlyNews.Year, monthlyNews.Month, r.RemoteAddr) - } -} - -// DeleteMonthlyNews godoc -// @Summary Delete a specific monthlyNews -// @Description Delete a specific monthlyNews -// @Tags monthlyNews -// @Produce json -// @Success 200 {string} string "successful delete" -// @Failure 404 {string} string "Not found" -// @Param year path int true "Year of the monthlyNews" -// @Param month path int true "Month of the monthlyNews" -// @Router /api/admin/monthlyNews/{year}/{month} [delete] -func DeleteMonthlyNews(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - yearStr := vars["year"] - monthStr := vars["month"] - - if yearStr == "" || monthStr == "" { - http.Error(w, "missing query element", http.StatusBadRequest) - return - } - - year, err := strconv.Atoi(yearStr) - if err != nil { - http.Error(w, "year is not an integer", http.StatusBadRequest) - return - } - month, err := strconv.Atoi(monthStr) - if err != nil { - http.Error(w, "month is not an integer", http.StatusBadRequest) - return - } - - err = database.Delete(year, month, "header") - if err != nil { - http.Error(w, err.Error(), http.StatusNotFound) - return - } - err = database.Delete(year, month, "quote") - if err != nil { - http.Error(w, err.Error(), http.StatusNotFound) - return - } - - w.WriteHeader(http.StatusOK) - w.Write([]byte("successful delete")) -} diff --git a/internal/monthlyReport/monthlyReport.go b/internal/monthlyReport/monthlyReport.go deleted file mode 100644 index 821ebd0..0000000 --- a/internal/monthlyReport/monthlyReport.go +++ /dev/null @@ -1,106 +0,0 @@ -package monthlyReport - -import ( - "encoding/json" - "net/http" - "strconv" - - "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/database" - "github.com/gorilla/mux" -) - -type MonthlyReport struct { - Year int `json:"year"` - Month int `json:"month"` - Header string `json:"header"` - Quote string `json:"quote"` - Question string `json:"question"` - Link string `json:"link"` -} - -// GetSingleMonthlyReport godoc -// @Summary Get details of a specific monthlyReport -// @Description Get details of a specific monthlyReport -// @Tags monthlyReport -// @Produce json -// @Success 200 {object} MonthlyReport -// @Failure 404 {string} string "Not found" -// @Param year path int true "Year of the monthlyReport" -// @Param month path int true "Month of the monthlyReport" -// @Router /api/common/monthlyReport/{year}/{month} [get] -func GetSingleMonthlyReport(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - yearStr := vars["year"] - monthStr := vars["month"] - - if yearStr == "" || monthStr == "" { - http.Error(w, "missing query element", http.StatusBadRequest) - return - } - - year, err := strconv.Atoi(yearStr) - if err != nil { - http.Error(w, "year is not an integer", http.StatusBadRequest) - return - } - month, err := strconv.Atoi(monthStr) - if err != nil { - http.Error(w, "month is not an integer", http.StatusBadRequest) - return - } - - header, errH := database.Get(year, month, "header") - quote, errQuo := database.Get(year, month, "quote") - question, errQue := database.Get(year, month, "question") - link, errL := database.Get(year, month, "link") - - if errH != nil || errQuo != nil || errQue != nil || errL != nil { - // If not found, answer empty json - w.WriteHeader(http.StatusNotFound) - return - } - - w.Header().Set("Content-Type", "application/json") - monthlyReport := MonthlyReport{ - Year: year, - Month: month, - Header: header.Content, - Quote: quote.Content, - Question: question.Content, - Link: link.Content, - } - json.NewEncoder(w).Encode(monthlyReport) -} - -// GetMostRecentMonthlyReport godoc -// @Summary Get details of the most recent monthlyReport -// @Description Find the most recent MonthlyNews and try to find the corresponding poll if it exists -// @Tags monthlyReport -// @Produce json -// @Success 200 {object} MonthlyReport -// @Failure 404 {string} string "Not found" -// @Router /api/common/monthlyReport [get] -func GetMostRecentMonthlyReport(w http.ResponseWriter, r *http.Request) { - - header, errH := database.GetMostRecent("header") - quote, _ := database.Get(header.Year, header.Month, "quote") - question, _ := database.Get(header.Year, header.Month, "question") - link, _ := database.Get(header.Year, header.Month, "link") - - if errH != nil { - // If not found, answer "not found" - w.WriteHeader(http.StatusNotFound) - return - } - - w.Header().Set("Content-Type", "application/json") - monthlyReport := MonthlyReport{ - Year: header.Year, - Month: header.Month, - Header: header.Content, - Quote: quote.Content, - Question: question.Content, - Link: link.Content, - } - json.NewEncoder(w).Encode(monthlyReport) -} diff --git a/internal/poll/poll.go b/internal/poll/poll.go deleted file mode 100644 index dc31b45..0000000 --- a/internal/poll/poll.go +++ /dev/null @@ -1,244 +0,0 @@ -package poll - -import ( - "encoding/json" - "fmt" - "log" - "net/http" - "strconv" - - "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/database" - "github.com/gorilla/mux" -) - -type Poll struct { - Year int `json:"year"` - Month int `json:"month"` - Question string `json:"question"` - Link string `json:"link"` -} - -// GetAllPolls godoc -// @Summary List all polls -// @Description Get details of all polls -// @Tags poll -// @Produce json -// @Success 200 {array} Poll -// @Router /api/admin/poll [get] -func GetAllPolls(w http.ResponseWriter, r *http.Request) { - Questions := database.GetAll("question") - Links := database.GetAll("link") - - var poll []Poll - - for _, question := range Questions { - linkExists := false - for _, link := range Links { - if question.Year == link.Year && question.Month == link.Month { - poll = append(poll, Poll{question.Year, question.Month, question.Content, link.Content}) - linkExists = true - break - } - } - if !linkExists { - poll = append(poll, Poll{question.Year, question.Month, question.Content, ""}) - } - } - - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(poll) - log.Printf("| get all polls | %v", r.RemoteAddr) -} - -// GetSinglePoll godoc -// @Summary Get details of a specific poll -// @Description Get details of a specific poll -// @Tags poll -// @Produce json -// @Success 200 {object} Poll -// @Failure 404 {string} string "Not found" -// @Param year path int true "Year of the poll" -// @Param month path int true "Month of the poll" -// @Router /api/admin/poll/{year}/{month} [get] -func GetSinglePoll(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - yearStr := vars["year"] - monthStr := vars["month"] - - if yearStr == "" || monthStr == "" { - http.Error(w, "missing query element", http.StatusBadRequest) - return - } - - year, err := strconv.Atoi(yearStr) - if err != nil { - http.Error(w, "year is not an integer", http.StatusBadRequest) - return - } - month, err := strconv.Atoi(monthStr) - if err != nil { - http.Error(w, "month is not an integer", http.StatusBadRequest) - return - } - - w.Header().Set("Content-Type", "application/json") - question, errQ := database.Get(year, month, "question") - link, errL := database.Get(year, month, "link") - if errQ != nil || errL != nil { - // If not found, answer "not found" - w.WriteHeader(http.StatusNotFound) - return - } - poll := Poll{Year: year, Month: month, Question: question.Content, Link: link.Content} - json.NewEncoder(w).Encode(poll) -} - -// AddPoll godoc -// @Summary Create a new poll -// @Description Create a new poll -// @Tags poll -// @Accept json -// @Produce json -// @Success 201 {object} Poll -// @Param poll body Poll true "Poll to create" -// @Router /api/admin/poll [post] -func AddPoll(w http.ResponseWriter, r *http.Request) { - if r.Body == http.NoBody { - http.Error(w, "request body is empty", http.StatusBadRequest) - return - } - - decoder := json.NewDecoder(r.Body) - var poll Poll - err := decoder.Decode(&poll) - if err != nil { - fmt.Println(err) - } - - err = database.Create(poll.Year, poll.Month, "question", poll.Question) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - err = database.Create(poll.Year, poll.Month, "link", poll.Link) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - w.WriteHeader(http.StatusCreated) - json.NewEncoder(w).Encode(poll) - - log.Printf("| new poll | %v", r.RemoteAddr) -} - -// UpdatePoll godoc -// @Summary Update a specific poll' content -// @Description Update a specific poll' content -// @Tags poll -// @Accept json -// @Produce json -// @Success 200 {object} Poll "Updated successfully" -// @Success 201 {object} Poll "Created successfully" -// @Failure 400 {string} string "Bad Request" -// @Failure 500 {string} string "Internal server error" -// @Param poll body Poll true "Poll to update with new content" -// @Router /api/admin/poll [put] -func UpdatePoll(w http.ResponseWriter, r *http.Request) { - if r.Body == http.NoBody { - http.Error(w, "request body is empty", http.StatusBadRequest) - return - } - - decoder := json.NewDecoder(r.Body) - var poll Poll - err := decoder.Decode(&poll) - if err != nil { - fmt.Println(err) - } - - // Check if this monthly news exists - _, errQ := database.Get(poll.Year, poll.Month, "question") - _, errL := database.Get(poll.Year, poll.Month, "link") - - if errQ != nil || errL != nil { - err = database.Create(poll.Year, poll.Month, "question", poll.Question) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - err = database.Create(poll.Year, poll.Month, "link", poll.Link) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusCreated) - json.NewEncoder(w).Encode(poll) - log.Printf("| new monthly news | year : %d month : %d | %v", poll.Year, poll.Month, r.RemoteAddr) - return - - } else { - err = database.Update(poll.Year, poll.Month, "question", poll.Question) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - err = database.Update(poll.Year, poll.Month, "link", poll.Link) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - json.NewEncoder(w).Encode(poll) - log.Printf("| updated poll year : %d month : %d | %v", poll.Year, poll.Month, r.RemoteAddr) - } -} - -// DeletePoll godoc -// @Summary Delete a specific poll -// @Description Delete a specific poll -// @Tags poll -// @Produce json -// @Success 200 {string} string "successful delete" -// @Failure 404 {string} string "Not found" -// @Param year path int true "Year of the poll" -// @Param month path int true "Month of the poll" -// @Router /api/admin/poll/{year}/{month} [delete] -func DeletePoll(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - yearStr := vars["year"] - monthStr := vars["month"] - - if yearStr == "" || monthStr == "" { - http.Error(w, "missing query element", http.StatusBadRequest) - return - } - - year, err := strconv.Atoi(yearStr) - if err != nil { - http.Error(w, "year is not an integer", http.StatusBadRequest) - return - } - month, err := strconv.Atoi(monthStr) - if err != nil { - http.Error(w, "month is not an integer", http.StatusBadRequest) - return - } - - err = database.Delete(year, month, "question") - if err != nil { - http.Error(w, err.Error(), http.StatusNotFound) - return - } - err = database.Delete(year, month, "link") - if err != nil { - http.Error(w, err.Error(), http.StatusNotFound) - return - } - - w.WriteHeader(http.StatusOK) - w.Write([]byte("successful delete")) -} diff --git a/internal/rootmux/rootmux.go b/internal/rootmux/rootmux.go index 7a79a68..aca639a 100644 --- a/internal/rootmux/rootmux.go +++ b/internal/rootmux/rootmux.go @@ -5,9 +5,7 @@ import ( _ "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/docs" "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/auth" - "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/monthlyNews" - "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/monthlyReport" - "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/poll" + "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/models" "github.com/gorilla/mux" httpSwagger "github.com/swaggo/http-swagger" ) @@ -26,32 +24,37 @@ type RootMux struct { // @host localhost:1443 // @BasePath / -func CreateRootMux(staticDir string) RootMux { +func CreateRootMux() RootMux { r := mux.NewRouter() m := auth.NewManager() + dh := models.NewDataHandler() r.HandleFunc("/OAuth2Login", m.HandleOAuth2Login) r.Handle("/OAuth2Callback", m.HandleOAuth2Callback()) r.HandleFunc("/Logout", m.HandleLogout) r.Handle("/api/common/WhoAmI", auth.ValidateAuthMiddleware(auth.WhoAmI(), []string{"*"}, false)) - r.HandleFunc("/api/common/monthlyReport", monthlyReport.GetMostRecentMonthlyReport).Methods(http.MethodGet) - r.HandleFunc("/api/common/monthlyReport/{year}/{month}", monthlyReport.GetSingleMonthlyReport).Methods(http.MethodGet) + r.HandleFunc("/api/common/monthlyReport", dh.GetCurrentMonthlyReport).Methods(http.MethodGet) + r.HandleFunc("/api/common/monthlyReport/{year}/{month}", dh.GetMonthlyReport).Methods(http.MethodGet) apiAdmin := r.PathPrefix("/api/admin").Subrouter() apiAdmin.Use(auth.AdminAuthMiddleware) - apiAdmin.HandleFunc("/monthlyNews", monthlyNews.GetAllMonthlyNews).Methods(http.MethodGet) - apiAdmin.HandleFunc("/monthlyNews/{year}/{month}", monthlyNews.GetSingleMonthlyNews).Methods(http.MethodGet) - apiAdmin.HandleFunc("/monthlyNews", monthlyNews.AddMonthlyNews).Methods(http.MethodPost) - apiAdmin.HandleFunc("/monthlyNews", monthlyNews.UpdateMonthlyNews).Methods(http.MethodPut) - apiAdmin.HandleFunc("/monthlyNews/{year}/{month}", monthlyNews.DeleteMonthlyNews).Methods(http.MethodDelete) - - apiAdmin.HandleFunc("/poll", poll.GetAllPolls).Methods(http.MethodGet) - apiAdmin.HandleFunc("/poll/{year}/{month}", poll.GetSinglePoll).Methods(http.MethodGet) - apiAdmin.HandleFunc("/poll", poll.AddPoll).Methods(http.MethodPost) - apiAdmin.HandleFunc("/poll", poll.UpdatePoll).Methods(http.MethodPut) - apiAdmin.HandleFunc("/poll/{year}/{month}", poll.DeletePoll).Methods(http.MethodDelete) + + apiAdmin.HandleFunc("/monthlyNews", dh.GetAllMonthlyNews).Methods(http.MethodGet) + apiAdmin.HandleFunc("/monthlyNews/{year}/{month}", dh.GetSingleMonthlyNews).Methods(http.MethodGet) + apiAdmin.HandleFunc("/monthlyNews", dh.SaveMonthlyNews).Methods(http.MethodPut) + apiAdmin.HandleFunc("/monthlyNews/{year}/{month}", dh.DeleteMonthlyNews).Methods(http.MethodDelete) + + apiAdmin.HandleFunc("/monthlyInfo", dh.GetAllMonthlyInfo).Methods(http.MethodGet) + apiAdmin.HandleFunc("/monthlyInfo/{year}/{month}", dh.GetSingleMonthlyInfo).Methods(http.MethodGet) + apiAdmin.HandleFunc("/monthlyInfo", dh.SaveMonthlyInfo).Methods(http.MethodPut) + apiAdmin.HandleFunc("/monthlyInfo/{year}/{month}", dh.DeleteMonthlyInfo).Methods(http.MethodDelete) + + apiAdmin.HandleFunc("/poll", dh.GetAllPolls).Methods(http.MethodGet) + apiAdmin.HandleFunc("/poll/{year}/{month}", dh.GetSinglePoll).Methods(http.MethodGet) + apiAdmin.HandleFunc("/poll", dh.SavePoll).Methods(http.MethodPut) + apiAdmin.HandleFunc("/poll/{year}/{month}", dh.DeletePoll).Methods(http.MethodDelete) // Swagger r.PathPrefix("/swagger").Handler(httpSwagger.WrapHandler) diff --git a/internal/rootmux/rootmux_test.go b/internal/rootmux/rootmux_test.go index 44ee1eb..5e6a66f 100644 --- a/internal/rootmux/rootmux_test.go +++ b/internal/rootmux/rootmux_test.go @@ -11,21 +11,20 @@ import ( "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/auth" "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/mocks" - "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/monthlyNews" - "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/poll" + "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/models" "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/tester" "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/tokens" ) var ( - oAuth2Server *httptest.Server - newMonthlyNews = monthlyNews.MonthlyNews{Year: 2020, Month: 0, Header: "newsHeader", Quote: "newsQuote"} - newMonthlyNewsStr string - recentMonthlyNews = monthlyNews.MonthlyNews{Year: 2021, Month: 0, Header: "recentNewsHeader", Quote: "recentNewsQuote"} - recentMonthlyNewsStr string - newPoll = poll.Poll{Year: 2020, Month: 0, Question: "pollQuestion", Link: "pollLink"} - newPollStr string - noH map[string]string + oAuth2Server *httptest.Server + monthlyInfo = models.MonthlyInfo{Year: 2021, Month: 0, Info: "Informations du mois"} + monthlyInfoStr string + monthlyNews = models.MonthlyNews{Year: 2021, Month: 0, Title: "", Content: "Nouvelles fonctionnalités"} + monthlyNewsStr string + newPoll = models.Poll{Year: 2021, Month: 0, Question: "pollQuestion", Link: "pollLink"} + newPollStr string + noH map[string]string ) func TestMain(m *testing.M) { @@ -48,10 +47,10 @@ func TestMain(m *testing.M) { tokens.Init("../configs/tokenskey.json", true) // Convert example objects to string - newMonthlyNewsBytes, _ := json.Marshal(newMonthlyNews) - newMonthlyNewsStr = string(newMonthlyNewsBytes) - recentMonthlyNewsBytes, _ := json.Marshal(recentMonthlyNews) - recentMonthlyNewsStr = string(recentMonthlyNewsBytes) + monthlyNewsBytes, _ := json.Marshal(monthlyNews) + monthlyNewsStr = string(monthlyNewsBytes) + monthlyInfoBytes, _ := json.Marshal(monthlyInfo) + monthlyInfoStr = string(monthlyInfoBytes) newPollBytes, _ := json.Marshal(newPoll) newPollStr = string(newPollBytes) @@ -94,7 +93,7 @@ func unloggedTests(t *testing.T) { defer ts.Close() // Close the tester // Try to create a monthlyNews (must fail) - do("POST", "/api/admin/monthlyNews", noH, newMonthlyNewsStr, http.StatusUnauthorized, "error extracting token") + do("PUT", "/api/admin/monthlyNews", noH, monthlyNewsStr, http.StatusUnauthorized, "error extracting token") // Try to get the most recent monthlyReport (must fail because not found) do("GET", "/api/common/monthlyReport", noH, "", http.StatusNotFound, "") } @@ -112,49 +111,63 @@ func adminTests(t *testing.T) { token := auth.TokenData{} json.Unmarshal([]byte(response), &token) xsrfHeader := map[string]string{"XSRF-TOKEN": token.XSRFToken} - // Try to create a monthly news without the XSRF-TOKEN (must fail) - do("POST", "/api/admin/monthlyNews", noH, newMonthlyNewsStr, http.StatusUnauthorized, "XSRF protection triggered") - // Try to create a monthly news without body (must fail) - do("POST", "/api/admin/monthlyNews", xsrfHeader, "", http.StatusBadRequest, "request body is empty") - // Try to get a monthly news before it is created (must fail because not found) - do("GET", "/api/admin/monthlyNews/2020/0", xsrfHeader, "", http.StatusNotFound, "") - // Try to create a monthly news (must pass) - do("PUT", "/api/admin/monthlyNews", xsrfHeader, newMonthlyNewsStr, http.StatusCreated, newMonthlyNewsStr) - // Try to update a monthly news (must pass) - do("PUT", "/api/admin/monthlyNews", xsrfHeader, newMonthlyNewsStr, http.StatusOK, newMonthlyNewsStr) - // Try to get the monthly news created (must pass) - do("GET", "/api/admin/monthlyNews/2020/0", xsrfHeader, "", http.StatusOK, newMonthlyNewsStr) - // Try to get the most recent monthlyReport (must pass) - do("GET", "/api/common/monthlyReport", noH, "", http.StatusOK, `{"year":2020,"month":0,"header":"newsHeader","quote":"newsQuote","question":"","link":""`) + // Try to create a monthlyNews without the XSRF-TOKEN (must fail) + do("PUT", "/api/admin/monthlyNews", noH, monthlyNewsStr, http.StatusUnauthorized, "XSRF protection triggered") + // Try to create a monthlyNews without body (must fail) + do("PUT", "/api/admin/monthlyNews", xsrfHeader, "", http.StatusBadRequest, "request body is empty") + // Try to get a monthlyNews before it is created (must fail because not found) + do("GET", "/api/admin/monthlyNews/2021/0", xsrfHeader, "", http.StatusNotFound, "") + // Try to create a monthlyNews (must pass) + do("PUT", "/api/admin/monthlyNews", xsrfHeader, monthlyNewsStr, http.StatusCreated, `{"year":2021,"month":0,"title":"Les nouveautés du service","content":"Nouvelles fonctionnalités"`) + // Try to update a monthlyNews (must pass) + do("PUT", "/api/admin/monthlyNews", xsrfHeader, monthlyNewsStr, http.StatusOK, `{"year":2021,"month":0,"title":"Les nouveautés du service","content":"Nouvelles fonctionnalités"`) + // Try to get the monthlyNews created (must pass) + do("GET", "/api/admin/monthlyNews/2021/0", xsrfHeader, "", http.StatusOK, `{"year":2021,"month":0,"title":"Les nouveautés du service","content":"Nouvelles fonctionnalités"`) + // Try to get the monthlyReport (must fail because monthlyInfo not found) + do("GET", "/api/common/monthlyReport/2021/0", noH, "", http.StatusNotFound, "") // Try to create a poll without the XSRF-TOKEN (must fail) - do("POST", "/api/admin/poll", noH, newPollStr, http.StatusUnauthorized, "XSRF protection triggered") + do("PUT", "/api/admin/poll", noH, newPollStr, http.StatusUnauthorized, "XSRF protection triggered") // Try to create a poll without body (must fail) - do("POST", "/api/admin/poll", xsrfHeader, "", http.StatusBadRequest, "request body is empty") + do("PUT", "/api/admin/poll", xsrfHeader, "", http.StatusBadRequest, "request body is empty") // Try to get a poll before it is created (must fail because not found') - do("GET", "/api/admin/poll/2020/0", xsrfHeader, "", http.StatusNotFound, "") + do("GET", "/api/admin/poll/2021/0", xsrfHeader, "", http.StatusNotFound, "") // Try to create a poll (must pass) do("PUT", "/api/admin/poll", xsrfHeader, newPollStr, http.StatusCreated, newPollStr) // Try to update a poll (must pass) do("PUT", "/api/admin/poll", xsrfHeader, newPollStr, http.StatusOK, newPollStr) // Try to get the poll created (must pass) - do("GET", "/api/admin/poll/2020/0", xsrfHeader, "", http.StatusOK, newPollStr) - // Try to get the most recent monthlyReport (must pass) - do("GET", "/api/common/monthlyReport", noH, "", http.StatusOK, `{"year":2020,"month":0,"header":"newsHeader","quote":"newsQuote","question":"pollQuestion","link":"pollLink"`) - - // Try to create a monthly news (must pass) - do("POST", "/api/admin/monthlyNews", xsrfHeader, recentMonthlyNewsStr, http.StatusCreated, recentMonthlyNewsStr) - // Try to get the most recent monthlyReport (must pass) - do("GET", "/api/common/monthlyReport", noH, "", http.StatusOK, `{"year":2021,"month":0,"header":"recentNewsHeader","quote":"recentNewsQuote","question":"","link":""`) - - // Try to delete the monthly news created (must pass) - do("DELETE", "/api/admin/monthlyNews/2020/0", xsrfHeader, "", http.StatusOK, "successful delete") - // Try to get a monthly news after it is deleted (must fail because not found) - do("GET", "/api/admin/monthlyNews/2020/0", xsrfHeader, "", http.StatusNotFound, "") + do("GET", "/api/admin/poll/2021/0", xsrfHeader, "", http.StatusOK, newPollStr) + // Try to get the monthlyReport (must fail because monthlyInfo not found) + do("GET", "/api/common/monthlyReport/2021/0", noH, "", http.StatusNotFound, "") + + // Try to create a monthlyInfo without the XSRF-TOKEN (must fail) + do("PUT", "/api/admin/monthlyInfo", noH, monthlyInfoStr, http.StatusUnauthorized, "XSRF protection triggered") + // Try to create a monthlyInfo without body (must fail) + do("PUT", "/api/admin/monthlyInfo", xsrfHeader, "", http.StatusBadRequest, "request body is empty") + // Try to get a monthlyInfo before it is created (must fail because not found) + do("GET", "/api/admin/monthlyInfo/2021/0", xsrfHeader, "", http.StatusNotFound, "") + // Try to create a monthlyInfo (must pass) + do("PUT", "/api/admin/monthlyInfo", xsrfHeader, monthlyInfoStr, http.StatusCreated, monthlyInfoStr) + // Try to update a monthlyInfo (must pass) + do("PUT", "/api/admin/monthlyInfo", xsrfHeader, monthlyInfoStr, http.StatusOK, monthlyInfoStr) + // Try to get the monthlyInfo created (must pass) + do("GET", "/api/admin/monthlyInfo/2021/0", xsrfHeader, "", http.StatusOK, monthlyInfoStr) + // Try to get the monthlyReport (must pass) + do("GET", "/api/common/monthlyReport/2021/0", noH, "", http.StatusOK, `{"year":2021,"month":0,"info":"Informations du mois","newsTitle":"Les nouveautés du service","newsContent":"Nouvelles fonctionnalités","question":"pollQuestion","link":"pollLink"`) + + // Try to delete the monthlyNews created (must pass) + do("DELETE", "/api/admin/monthlyNews/2021/0", xsrfHeader, "", http.StatusOK, "successful delete") + // Try to get a monthlyNews after it is deleted (must fail because not found) + do("GET", "/api/admin/monthlyNews/2021/0", xsrfHeader, "", http.StatusNotFound, "") + // Try to get the monthlyReport (must pass) + do("GET", "/api/common/monthlyReport/2021/0", noH, "", http.StatusOK, `{"year":2021,"month":0,"info":"Informations du mois","newsTitle":"","newsContent":"","question":"pollQuestion","link":"pollLink"`) // Try to delete the poll created (must pass) - do("DELETE", "/api/admin/poll/2020/0", xsrfHeader, "", http.StatusOK, "successful delete") + do("DELETE", "/api/admin/poll/2021/0", xsrfHeader, "", http.StatusOK, "successful delete") // Try to get a poll after it is deleted (must fail because not found) - do("GET", "/api/admin/poll/2020/0", xsrfHeader, "", http.StatusNotFound, "") + do("GET", "/api/admin/poll/2021/0", xsrfHeader, "", http.StatusNotFound, "") + // Try to get the monthlyReport (must pass) + do("GET", "/api/common/monthlyReport/2021/0", noH, "", http.StatusOK, `{"year":2021,"month":0,"info":"Informations du mois","newsTitle":"","newsContent":"","question":"","link":""`) } // Try to login (must pass) do("GET", "/OAuth2Login", noH, "", http.StatusOK, "") @@ -162,7 +175,7 @@ func adminTests(t *testing.T) { tests() // Try to logout (must pass) do("GET", "/Logout", noH, "", http.StatusOK, "") - // Try to get a monthly news again (must fail) + // Try to get a monthlyNews again (must fail) do("GET", "/api/admin/monthlyNews", noH, "", http.StatusUnauthorized, "error extracting token") // Try to get a poll again (must fail) do("GET", "/api/admin/poll", noH, "", http.StatusUnauthorized, "error extracting token") @@ -170,7 +183,7 @@ func adminTests(t *testing.T) { func createTester(t *testing.T) (*httptest.Server, tester.DoFn, tester.DoFn) { // Create the server - mux := CreateRootMux("../../web") + mux := CreateRootMux() ts := httptest.NewServer(mux.Router) url, _ := url.Parse(ts.URL) port := url.Port() diff --git a/main.go b/main.go index 1458db1..2876f92 100644 --- a/main.go +++ b/main.go @@ -14,8 +14,9 @@ import ( ) var ( - httpsPort = common.IntValueFromEnv("HTTPS_PORT", 443) // HTTPS port to serve on - debugMode = common.BoolValueFromEnv("DEBUG_MODE", false) // Debug mode, disable Let's Encrypt, enable CORS and more logging + httpsPort = common.IntValueFromEnv("HTTPS_PORT", 443) // HTTPS port to serve on + debugMode = common.BoolValueFromEnv("DEBUG_MODE", false) // Debug mode, disable Secure attribute for cookies + mockOAuth2 = common.BoolValueFromEnv("MOCK_OAUTH2", false) // Enable mock OAuth2 login ) func main() { @@ -26,16 +27,18 @@ func main() { tokens.Init("./configs/tokenskey.json", debugMode) // Create the server - rootMux := rootmux.CreateRootMux("/web/") + rootMux := rootmux.CreateRootMux() // Init the hostname mocks.Init(httpsPort) // Start a mock oauth2 server if debug mode is on - mockOAuth2Port := ":8090" - go http.ListenAndServe(mockOAuth2Port, mocks.CreateMockOAuth2()) - fmt.Println("Mock OAuth2 server Listening on: http://localhost" + mockOAuth2Port) + if mockOAuth2 { + mockOAuth2Port := ":8090" + go http.ListenAndServe(mockOAuth2Port, mocks.CreateMockOAuth2()) + fmt.Println("Mock OAuth2 server Listening on: http://localhost" + mockOAuth2Port) + } - // Serve locally with https on debug mode or with let's encrypt on production mode + // Serve locally with https log.Fatal(http.ListenAndServeTLS(":"+strconv.Itoa(httpsPort), "./dev_certificates/localhost.crt", "./dev_certificates/localhost.key", rootMux.Router)) } diff --git a/template.env b/template.env index f563ef7..efe3ecf 100644 --- a/template.env +++ b/template.env @@ -2,6 +2,7 @@ HOSTNAME= ADMIN_ROLE= DEBUG_MODE= +MOCK_OAUTH2= HTTPS_PORT= # Needed to user OAuth2 authentication : -- GitLab