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