diff --git a/config/database.go b/config/database.go index bb5a8dd..ca7536b 100644 --- a/config/database.go +++ b/config/database.go @@ -47,6 +47,9 @@ func MigrateDB() { &schemas.Team{}, &schemas.Role{}, &schemas.Member{}, + &schemas.Subject{}, + &schemas.StudyMaterial{}, + &schemas.SubjectCategory{}, } { if err := db.AutoMigrate(&schema); err != nil { panic(err) diff --git a/controllers/app_controller.go b/controllers/app_controller.go index 2f99e31..312bce9 100644 --- a/controllers/app_controller.go +++ b/controllers/app_controller.go @@ -8,9 +8,10 @@ import ( ) type AppController struct { - User interface{ UserController } - Team interface{ TeamController } - Seed interface{ SeedController } + User interface{ UserController } + Team interface{ TeamController } + Seed interface{ SeedController } + StudyMaterial interface{ StudyMaterialController } } type seedController struct { @@ -41,6 +42,11 @@ func (s *seedController) SeedDB() error { log.Panic(err) return err } - log.Println(color.GreenString("Seeded Successfully")) + err = s.seed.StudyMaterialSeeder() + if err != nil { + log.Panic(err) + return err + } + log.Println(color.GreenString(" Seeded Successfully")) return nil } diff --git a/controllers/resource_controller.go b/controllers/resource_controller.go new file mode 100644 index 0000000..d397344 --- /dev/null +++ b/controllers/resource_controller.go @@ -0,0 +1,277 @@ +package controllers + +import ( + "log" + "net/http" + + "github.com/ecea-nitt/ecea-server/middlewares" + "github.com/ecea-nitt/ecea-server/models" + "github.com/ecea-nitt/ecea-server/services" + "github.com/fatih/color" + "github.com/labstack/echo/v4" +) + +type studyMaterialController struct { + rs services.StudyMaterialService +} + +type StudyMaterialController interface { + AddStudyMaterial(c echo.Context) error + GetCategoryStudyMaterials(c echo.Context) error + GetAllMaterials(c echo.Context) error + GetStudyMaterial(c echo.Context) error + AddSubject(c echo.Context) error + // UpdateStudyMaterialSubject(c echo.Context) error + UpdateStudyMaterialURL(c echo.Context) error + DeleteStudyMaterial(c echo.Context) error +} + +func NewStudyMaterialController(rs services.StudyMaterialService) StudyMaterialController { + return &studyMaterialController{rs} +} + +// AddStudyMaterial godoc +// +// @Summary Add a study material +// @Description Creates a new study material and adds to Database +// @Tags StudyMaterial +// @Accept multipart/form-data +// @Produce json +// @Param name formData string true "Enter material name" +// @Param code formData string true "Enter subject code" +// @Param document formData file true "Upload Document" +// @Success 200 {object} string +// @Failure 400 {object} models.Error +// +// @Security ApiKeyAuth +// @Router /v1/studymaterial/addMaterial [post] +func (rc *studyMaterialController) AddStudyMaterial(c echo.Context) error { + request := new(models.StudyMaterialRequest) + if err := c.Bind(request); err != nil { + log.Println(err) + return err + } + file, err := c.FormFile("document") + if err != nil { + log.Println(err) + return err + } + log.Println(request) + err = rc.rs.CreateNewStudyMaterial(*request, file) + if err != nil { + log.Println(err) + return middlewares.Responder(c, http.StatusConflict, "Conflict") + } + return middlewares.Responder(c, http.StatusOK, "Success") +} + +// GetStudyMaterial godoc +// +// @Summary Get a study material +// @Description Fetches a study material and removes form database +// @Tags StudyMaterial +// @Accept json +// @Produce json +// @Param name path string true "Get study material" +// @Success 200 {object} models.StudyMaterials +// @Failure 400 {object} models.Error +// +// @Security ApiKeyAuth +// @Router /v1/studymaterial/get/{name} [get] +func (rc *studyMaterialController) GetStudyMaterial(c echo.Context) error { + rname := c.Param("name") + res, err := rc.rs.GetStudyMaterial(rname) + if err != nil { + log.Println(color.RedString(err.Error())) + return middlewares.Responder(c, http.StatusConflict, "Error Occurred") + } + + return middlewares.Responder(c, http.StatusOK, &res) +} + +// GetCategoryStudyMaterials godoc +// +// @Summary Get study materials from a category +// @Description Fetches all study materials belonging to a category from Database +// @Tags StudyMaterial +// @Accept json +// @Produce json +// @Param category path models.SubjectCategory true "Get study material from category" +// @Success 200 {object} []models.StudyMaterials +// @Failure 400 {object} models.Error +// +// @Security ApiKeyAuth +// @Router /v1/studymaterial/getcat/{category} [get] +func (rc *studyMaterialController) GetCategoryStudyMaterials(c echo.Context) error { + /* + request := new(models.StudyMaterialRequest) + if err := c.Bind(request); err != nil { + return err + } + */ + res, err := rc.rs.GetCategoryStudyMaterials(c.Param("category")) + log.Println(c.Param("category")) + if err != nil { + log.Println(color.RedString(err.Error())) + return middlewares.Responder(c, http.StatusConflict, "Conflict") + } + return middlewares.Responder(c, http.StatusOK, res) +} + +// UpdateStudyMaterialSubject godoc +// +// @Summary Updates a studymaterial's subject name +// @Description Updates a subject name and updates to Database +// @Tags StudyMaterial +// @Accept multipart/form-data +// @Produce json +// @Param subject formData string true "Edit name" +// @Param subjectCode formData string true "Enter subject code" +// @Success 200 {object} string +// @Failure 400 {object} models.Error +// +// @Security ApiKeyAuth +// @Router /v1/studymaterial/edit/subject [put] + +/* +func (rc *studyMaterialController) UpdateStudyMaterialSubject(c echo.Context) error { + + request := new(models.StudyMaterialRequest) + if err := c.Bind(request); err != nil { + log.Println(err) + return middlewares.Responder(c, http.StatusBadRequest, "Bad Request") + } + subject := c.Param("subject") + subjectCode := c.Param("subjectCode") + if err := c.Bind(request); err != nil { + log.Println(err) + return middlewares.Responder(c, http.StatusBadRequest, "Bad Request") + } + log.Println(request.Subject, request.SubjectCode) + err := rc.rs.EditStudyMaterialSubject(request.Subject, request.SubjectCode) + if err != nil { + log.Println(color.RedString(err.Error())) + return middlewares.Responder(c, http.StatusConflict, err) + } + return middlewares.Responder(c, http.StatusOK, "Success") +} +*/ + +// UpdateStudyMaterialURL godoc +// +// @Summary Update a study material's document +// @Description Update a document and update it on Database +// @Tags StudyMaterial +// @Accept multipart/form-data +// @Produce json +// @Param name formData string true "Enter the name of material" +// @Param document formData file true "Edit Document" +// @Success 200 {object} string +// @Failure 400 {object} models.Error +// +// @Security ApiKeyAuth +// @Router /v1/studymaterial/edit/document [put] +func (rc *studyMaterialController) UpdateStudyMaterialURL(c echo.Context) error { + + request := new(models.StudyMaterialRequest) + if err := c.Bind(request); err != nil { + log.Println(err) + return middlewares.Responder(c, http.StatusBadRequest, "Bad Request") + } + /* + name := c.Param("name") + request := new(models.StudyMaterialRequest) + if err := c.Bind(request); err != nil { + log.Println(err) + return middlewares.Responder(c, http.StatusBadRequest, "Bad Request") + } + */ + file, err := c.FormFile("document") + if err != nil { + log.Println(err) + return err + } + + err = rc.rs.EditStudyMaterialURL(request.Name, file) + if err != nil { + log.Println(color.RedString(err.Error())) + return middlewares.Responder(c, http.StatusConflict, err) + } + return middlewares.Responder(c, http.StatusOK, "Success") +} + +// DeleteStudyMaterial godoc +// +// @Summary Deletes a study material +// @Description Deletes a study material along with its document and remove form Database +// @Tags StudyMaterial +// @Accept json +// @Produce json +// @Param name path string true "Delete study material" +// @Success 200 {object} string +// @Failure 400 {object} models.Error +// +// @Security ApiKeyAuth +// @Router /v1/studymaterial/delete/{name} [delete] +func (rc *studyMaterialController) DeleteStudyMaterial(c echo.Context) error { + rname := c.Param("name") + + err := rc.rs.RemoveStudyMaterial(rname) + log.Println(rname) + if err != nil { + log.Println(color.RedString(err.Error())) + return middlewares.Responder(c, http.StatusConflict, "Error Occurred") + } + + return middlewares.Responder(c, http.StatusOK, "Success") +} + +// AddSubject godoc +// +// @Summary Add a subject +// @Description Creates a new subject and adds to Database +// @Tags StudyMaterial +// @Accept multipart/form-data +// @Produce json +// @Param subject formData string true "Enter subject name" +// @Param code formData string true "Enter subject code" +// @Param category formData models.SubjectCategory true "Enter subject category" +// @Success 200 {object} string +// @Failure 400 {object} models.Error +// +// @Security ApiKeyAuth +// @Router /v1/studymaterial/addSubject [post] +func (rc *studyMaterialController) AddSubject(c echo.Context) error { + response := new(models.StudyMaterialRequest) + if err := c.Bind(response); err != nil { + return err + } + err := rc.rs.AddSubject(response) + if err != nil { + log.Println(color.RedString(err.Error())) + return middlewares.Responder(c, http.StatusConflict, "Error Occurred") + } + + return middlewares.Responder(c, http.StatusOK, "Success") +} + +// GetAllStudyMaterials godoc +// +// @Summary Get all study materials from each category +// @Description Fetches all study materials belonging to every category from Database +// @Tags StudyMaterial +// @Accept json +// @Produce json +// @Success 200 {object} []models.CategoryMaterials +// @Failure 400 {object} models.Error +// +// @Security ApiKeyAuth +// @Router /v1/studymaterial/getall [get] +func (rc *studyMaterialController) GetAllMaterials(c echo.Context) error { + res, err := rc.rs.GetAllMaterials() + if err != nil { + log.Println(color.RedString(err.Error())) + return middlewares.Responder(c, http.StatusConflict, "Conflict") + } + return middlewares.Responder(c, http.StatusOK, res) +} diff --git a/controllers/team_controller.go b/controllers/team_controller.go index 6cbde60..bb98f9f 100644 --- a/controllers/team_controller.go +++ b/controllers/team_controller.go @@ -108,6 +108,8 @@ func (tc *teamController) AddMember(c echo.Context) error { log.Println(err) return middlewares.Responder(c, http.StatusBadRequest, "Bad Request") } + log.Println(request.Team) + log.Println(request.Role) file, err := c.FormFile("image") if err != nil { log.Println(err) diff --git a/docker-compose.yml b/docker-compose.yml index 1c09ed0..a43e35b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,10 +29,12 @@ services: ports: - ${POSTGRES_PORT}:${POSTGRES_PORT} command: -p ${POSTGRES_PORT} - volumes: - - ./database:/data/postgres +# volumes: +# - database:/data/postgres +#volumes: +# database: -networks: - default: - external: - name: thirumathikart_network +# networks: +# default: +# external: +# name: thirumathikart_network \ No newline at end of file diff --git a/docs/docs.go b/docs/docs.go index 2f0243d..1e28705 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -24,6 +24,359 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/v1/studymaterial/addMaterial": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Creates a new study material and adds to Database", + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "StudyMaterial" + ], + "summary": "Add a study material", + "parameters": [ + { + "type": "string", + "description": "Enter material name", + "name": "name", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "Enter subject code", + "name": "code", + "in": "formData", + "required": true + }, + { + "type": "file", + "description": "Upload Document", + "name": "document", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/v1/studymaterial/addSubject": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Creates a new subject and adds to Database", + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "StudyMaterial" + ], + "summary": "Add a subject", + "parameters": [ + { + "type": "string", + "description": "Enter subject name", + "name": "subject", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "Enter subject code", + "name": "code", + "in": "formData", + "required": true + }, + { + "enum": [ + "DIGITAL ELECTRONICS", + "ANALOG ELECTRONICS", + "TELECOMMUNICATION", + "COMMUNICATION CHANNELING", + "SYSTEM DESIGN AND ARCHITECTURE", + "BASIC ENGINEERING", + "MATHEMATICS", + "OTHERS" + ], + "type": "string", + "description": "Enter subject category", + "name": "category", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/v1/studymaterial/delete/{name}": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Deletes a study material along with its document and remove form Database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "StudyMaterial" + ], + "summary": "Deletes a study material", + "parameters": [ + { + "type": "string", + "description": "Delete study material", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/v1/studymaterial/edit/document": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Update a document and update it on Database", + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "StudyMaterial" + ], + "summary": "Update a study material's document", + "parameters": [ + { + "type": "string", + "description": "Enter the name of material", + "name": "name", + "in": "formData", + "required": true + }, + { + "type": "file", + "description": "Edit Document", + "name": "document", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/v1/studymaterial/get/{name}": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Fetches a study material and removes form database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "StudyMaterial" + ], + "summary": "Get a study material", + "parameters": [ + { + "type": "string", + "description": "Get study material", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.StudyMaterials" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/v1/studymaterial/getall": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Fetches all study materials belonging to every category from Database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "StudyMaterial" + ], + "summary": "Get all study materials from each category", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.CategoryMaterials" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/v1/studymaterial/getcat/{category}": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Fetches all study materials belonging to a category from Database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "StudyMaterial" + ], + "summary": "Get study materials from a category", + "parameters": [ + { + "enum": [ + "DIGITAL ELECTRONICS", + "ANALOG ELECTRONICS", + "TELECOMMUNICATION", + "COMMUNICATION CHANNELING", + "SYSTEM DESIGN AND ARCHITECTURE", + "BASIC ENGINEERING", + "MATHEMATICS", + "OTHERS" + ], + "type": "string", + "description": "Get study material from category", + "name": "category", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.StudyMaterials" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, "/v1/team/add": { "post": { "security": [ @@ -516,6 +869,20 @@ const docTemplate = `{ } }, "definitions": { + "models.CategoryMaterials": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "subjects": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SubjectMaterial" + } + } + } + }, "models.Error": { "type": "object", "properties": { @@ -529,6 +896,17 @@ const docTemplate = `{ } } }, + "models.Links": { + "type": "object", + "properties": { + "document_url": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, "models.MemberRoles": { "type": "string", "enum": [ @@ -604,6 +982,43 @@ const docTemplate = `{ "type": "string" } } + }, + "models.StudyMaterials": { + "type": "object", + "properties": { + "document_url": { + "type": "string" + }, + "name": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "subjectCode": { + "type": "string" + }, + "subject_category": { + "type": "string" + } + } + }, + "models.SubjectMaterial": { + "type": "object", + "properties": { + "materials": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Links" + } + }, + "name": { + "type": "string" + }, + "subject_code": { + "type": "string" + } + } } }, "securityDefinitions": { diff --git a/docs/swagger.json b/docs/swagger.json index b74456a..aa81155 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -15,6 +15,359 @@ "version": "1.0" }, "paths": { + "/v1/studymaterial/addMaterial": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Creates a new study material and adds to Database", + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "StudyMaterial" + ], + "summary": "Add a study material", + "parameters": [ + { + "type": "string", + "description": "Enter material name", + "name": "name", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "Enter subject code", + "name": "code", + "in": "formData", + "required": true + }, + { + "type": "file", + "description": "Upload Document", + "name": "document", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/v1/studymaterial/addSubject": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Creates a new subject and adds to Database", + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "StudyMaterial" + ], + "summary": "Add a subject", + "parameters": [ + { + "type": "string", + "description": "Enter subject name", + "name": "subject", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "Enter subject code", + "name": "code", + "in": "formData", + "required": true + }, + { + "enum": [ + "DIGITAL ELECTRONICS", + "ANALOG ELECTRONICS", + "TELECOMMUNICATION", + "COMMUNICATION CHANNELING", + "SYSTEM DESIGN AND ARCHITECTURE", + "BASIC ENGINEERING", + "MATHEMATICS", + "OTHERS" + ], + "type": "string", + "description": "Enter subject category", + "name": "category", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/v1/studymaterial/delete/{name}": { + "delete": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Deletes a study material along with its document and remove form Database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "StudyMaterial" + ], + "summary": "Deletes a study material", + "parameters": [ + { + "type": "string", + "description": "Delete study material", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/v1/studymaterial/edit/document": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Update a document and update it on Database", + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "StudyMaterial" + ], + "summary": "Update a study material's document", + "parameters": [ + { + "type": "string", + "description": "Enter the name of material", + "name": "name", + "in": "formData", + "required": true + }, + { + "type": "file", + "description": "Edit Document", + "name": "document", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/v1/studymaterial/get/{name}": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Fetches a study material and removes form database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "StudyMaterial" + ], + "summary": "Get a study material", + "parameters": [ + { + "type": "string", + "description": "Get study material", + "name": "name", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.StudyMaterials" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/v1/studymaterial/getall": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Fetches all study materials belonging to every category from Database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "StudyMaterial" + ], + "summary": "Get all study materials from each category", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.CategoryMaterials" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/v1/studymaterial/getcat/{category}": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "Fetches all study materials belonging to a category from Database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "StudyMaterial" + ], + "summary": "Get study materials from a category", + "parameters": [ + { + "enum": [ + "DIGITAL ELECTRONICS", + "ANALOG ELECTRONICS", + "TELECOMMUNICATION", + "COMMUNICATION CHANNELING", + "SYSTEM DESIGN AND ARCHITECTURE", + "BASIC ENGINEERING", + "MATHEMATICS", + "OTHERS" + ], + "type": "string", + "description": "Get study material from category", + "name": "category", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.StudyMaterials" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.Error" + } + } + } + } + }, "/v1/team/add": { "post": { "security": [ @@ -507,6 +860,20 @@ } }, "definitions": { + "models.CategoryMaterials": { + "type": "object", + "properties": { + "category": { + "type": "string" + }, + "subjects": { + "type": "array", + "items": { + "$ref": "#/definitions/models.SubjectMaterial" + } + } + } + }, "models.Error": { "type": "object", "properties": { @@ -520,6 +887,17 @@ } } }, + "models.Links": { + "type": "object", + "properties": { + "document_url": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, "models.MemberRoles": { "type": "string", "enum": [ @@ -595,6 +973,43 @@ "type": "string" } } + }, + "models.StudyMaterials": { + "type": "object", + "properties": { + "document_url": { + "type": "string" + }, + "name": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "subjectCode": { + "type": "string" + }, + "subject_category": { + "type": "string" + } + } + }, + "models.SubjectMaterial": { + "type": "object", + "properties": { + "materials": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Links" + } + }, + "name": { + "type": "string" + }, + "subject_code": { + "type": "string" + } + } } }, "securityDefinitions": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 4f5429a..21e97ff 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,4 +1,13 @@ definitions: + models.CategoryMaterials: + properties: + category: + type: string + subjects: + items: + $ref: '#/definitions/models.SubjectMaterial' + type: array + type: object models.Error: properties: code: @@ -8,6 +17,13 @@ definitions: example: status type: string type: object + models.Links: + properties: + document_url: + type: string + name: + type: string + type: object models.MemberRoles: enum: - Chairperson @@ -63,6 +79,30 @@ definitions: message: type: string type: object + models.StudyMaterials: + properties: + document_url: + type: string + name: + type: string + subject: + type: string + subject_category: + type: string + subjectCode: + type: string + type: object + models.SubjectMaterial: + properties: + materials: + items: + $ref: '#/definitions/models.Links' + type: array + name: + type: string + subject_code: + type: string + type: object info: contact: email: probe.eceanitt@gmail.com @@ -75,6 +115,237 @@ info: title: Probe Admin version: "1.0" paths: + /v1/studymaterial/addMaterial: + post: + consumes: + - multipart/form-data + description: Creates a new study material and adds to Database + parameters: + - description: Enter material name + in: formData + name: name + required: true + type: string + - description: Enter subject code + in: formData + name: code + required: true + type: string + - description: Upload Document + in: formData + name: document + required: true + type: file + produces: + - application/json + responses: + "200": + description: OK + schema: + type: string + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + security: + - ApiKeyAuth: [] + summary: Add a study material + tags: + - StudyMaterial + /v1/studymaterial/addSubject: + post: + consumes: + - multipart/form-data + description: Creates a new subject and adds to Database + parameters: + - description: Enter subject name + in: formData + name: subject + required: true + type: string + - description: Enter subject code + in: formData + name: code + required: true + type: string + - description: Enter subject category + enum: + - DIGITAL ELECTRONICS + - ANALOG ELECTRONICS + - TELECOMMUNICATION + - COMMUNICATION CHANNELING + - SYSTEM DESIGN AND ARCHITECTURE + - BASIC ENGINEERING + - MATHEMATICS + - OTHERS + in: formData + name: category + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + type: string + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + security: + - ApiKeyAuth: [] + summary: Add a subject + tags: + - StudyMaterial + /v1/studymaterial/delete/{name}: + delete: + consumes: + - application/json + description: Deletes a study material along with its document and remove form + Database + parameters: + - description: Delete study material + in: path + name: name + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + type: string + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + security: + - ApiKeyAuth: [] + summary: Deletes a study material + tags: + - StudyMaterial + /v1/studymaterial/edit/document: + put: + consumes: + - multipart/form-data + description: Update a document and update it on Database + parameters: + - description: Enter the name of material + in: formData + name: name + required: true + type: string + - description: Edit Document + in: formData + name: document + required: true + type: file + produces: + - application/json + responses: + "200": + description: OK + schema: + type: string + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + security: + - ApiKeyAuth: [] + summary: Update a study material's document + tags: + - StudyMaterial + /v1/studymaterial/get/{name}: + get: + consumes: + - application/json + description: Fetches a study material and removes form database + parameters: + - description: Get study material + in: path + name: name + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.StudyMaterials' + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + security: + - ApiKeyAuth: [] + summary: Get a study material + tags: + - StudyMaterial + /v1/studymaterial/getall: + get: + consumes: + - application/json + description: Fetches all study materials belonging to every category from Database + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.CategoryMaterials' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + security: + - ApiKeyAuth: [] + summary: Get all study materials from each category + tags: + - StudyMaterial + /v1/studymaterial/getcat/{category}: + get: + consumes: + - application/json + description: Fetches all study materials belonging to a category from Database + parameters: + - description: Get study material from category + enum: + - DIGITAL ELECTRONICS + - ANALOG ELECTRONICS + - TELECOMMUNICATION + - COMMUNICATION CHANNELING + - SYSTEM DESIGN AND ARCHITECTURE + - BASIC ENGINEERING + - MATHEMATICS + - OTHERS + in: path + name: category + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.StudyMaterials' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + security: + - ApiKeyAuth: [] + summary: Get study materials from a category + tags: + - StudyMaterial /v1/team/add: post: consumes: diff --git a/go.sum b/go.sum index adf54a6..a4d5512 100644 --- a/go.sum +++ b/go.sum @@ -163,7 +163,7 @@ github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXY github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIDttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/helpers/resource.go b/helpers/resource.go new file mode 100644 index 0000000..9a6eebf --- /dev/null +++ b/helpers/resource.go @@ -0,0 +1,75 @@ +package helpers + +import ( + "log" + "mime/multipart" + + "github.com/ecea-nitt/ecea-server/repositories" + "github.com/ecea-nitt/ecea-server/utils" +) + +func FetchSubjectID(channel chan int, code string, repo repositories.StudyMaterialRepository) { + subID, err := repo.GetSubjectID(code) + if err != nil { + return + } + channel <- int(subID) + +} + +func FetchSubjectCategoryID(channel chan int, subjectCode string, repo repositories.StudyMaterialRepository) { + id, err := repo.GetSubjectCategoryIDByCode(subjectCode) + if err != nil { + log.Println("hehehaha") + channel <- -1 + return + } + channel <- int(id) + +} + +func UploadFileAndFetchAssetID(channel chan int, file *multipart.FileHeader, repo repositories.StudyMaterialRepository) { + + fileName, err := utils.UploadDocument(file) + if err != nil { + log.Println(err) + channel <- -1 + return + } + id, err := repo.InsertAsset(fileName) + if err != nil { + log.Println(err) + channel <- -1 + return + } + channel <- int(id) +} + +func UpdateFileAndFetchAssetID(dbID uint, dbName string, document *multipart.FileHeader, repo repositories.StudyMaterialRepository) int { + + if dbName == document.Filename { + return int(dbID) + } + + err := utils.DeleteDocument(dbName) + + if err != nil { + log.Println(err) + return -1 + } + + fileName, err := utils.UploadDocument(document) + if err != nil { + log.Println(err) + return -1 + } + + err = repo.UpdateAsset(dbID, fileName) + + if err != nil { + log.Println(err) + return -1 + } + + return int(dbID) +} diff --git a/main.go b/main.go index bcb207a..92acc95 100644 --- a/main.go +++ b/main.go @@ -36,7 +36,7 @@ func main() { appController := reg.NewAppController() // Seed database - // appController.Seed.SeedDB() + //appController.Seed.SeedDB() // Create and Setup Echo Server server := echo.New() diff --git a/models/resource.go b/models/resource.go new file mode 100644 index 0000000..58631a3 --- /dev/null +++ b/models/resource.go @@ -0,0 +1,43 @@ +package models + +type StudyMaterialRequest struct { + Name string `json:"name" form:"name"` + Subject string `json:"subject" form:"subject"` + SubjectCategory string `json:"subject_category" form:"category"` + SubjectCode string `json:"subject_code" form:"code"` +} +type StudyMaterials struct { + Name string `json:"name"` + Subject string `json:"subject"` + SubjectCategory string `json:"subject_category"` + SubjectCode string `hson:"subject_code"` + DocumentURL string `json:"document_url"` +} + +type CategoryMaterials struct { + Category string `json:"category"` + SubjectMaterial []SubjectMaterial `json:"subjects"` +} +type SubjectMaterial struct { + Name string `json:"name"` + SubjectCode string `json:"subject_code"` + Links []Links `json:"materials"` +} + +type Links struct { + Name string `json:"name"` + DocumentURL string `json:"document_url"` +} + +type SubjectCategory string + +const ( + DigitalElectronics SubjectCategory = "DIGITAL ELECTRONICS" + AnalogElectronics SubjectCategory = "ANALOG ELECTRONICS" + Telecommunication SubjectCategory = "TELECOMMUNICATION" + CommunicationChanneling SubjectCategory = "COMMUNICATION CHANNELING" + SystemDesignAndArchitechture SubjectCategory = "SYSTEM DESIGN AND ARCHITECTURE" + BasicEngineering SubjectCategory = "BASIC ENGINEERING" + Mathematics SubjectCategory = "MATHEMATICS" + Others SubjectCategory = "OTHERS" +) diff --git a/registry/registry.go b/registry/registry.go index 1142ec8..32c4dc7 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -19,8 +19,9 @@ func NewRegistry(db *gorm.DB) Registry { func (r *registry) NewAppController() controllers.AppController { return controllers.AppController{ - User: r.NewUserController(), - Team: r.NewTeamController(), - Seed: r.NewSeedController(), + User: r.NewUserController(), + Team: r.NewTeamController(), + Seed: r.NewSeedController(), + StudyMaterial: r.NewStudyMaterialController(), } } diff --git a/registry/resource_registry.go b/registry/resource_registry.go new file mode 100644 index 0000000..3dc3b73 --- /dev/null +++ b/registry/resource_registry.go @@ -0,0 +1,19 @@ +package registry + +import ( + "github.com/ecea-nitt/ecea-server/controllers" + "github.com/ecea-nitt/ecea-server/repositories" + "github.com/ecea-nitt/ecea-server/services" +) + +func (r *registry) NewStudyMaterialController() controllers.StudyMaterialController { + return controllers.NewStudyMaterialController(r.NewStudyMaterialService()) +} + +func (r *registry) NewStudyMaterialService() services.StudyMaterialService { + return services.NewStudyMaterialService(r.NewStudyMaterialRepository()) +} + +func (r *registry) NewStudyMaterialRepository() repositories.StudyMaterialRepository { + return repositories.NewStudyMaterialRepository(r.db) +} diff --git a/repositories/resource_repository.go b/repositories/resource_repository.go new file mode 100644 index 0000000..6245eb0 --- /dev/null +++ b/repositories/resource_repository.go @@ -0,0 +1,257 @@ +package repositories + +import ( + "github.com/ecea-nitt/ecea-server/config" + "github.com/ecea-nitt/ecea-server/models" + "github.com/ecea-nitt/ecea-server/schemas" + "gorm.io/gorm" + "gorm.io/gorm/clause" +) + +type studyMaterialRepository struct { + db *gorm.DB +} + +type StudyMaterialRepository interface { + GetDocumentLinks(subID uint) ([]models.Links, error) + GetSubjectsByCategory(category string) ([]string, error) + GetSubjectStudyMaterial(subject string) (models.SubjectMaterial, error) + GetCategoryStudyMaterials(name string) ([]models.StudyMaterials, error) + GetAllCategories() ([]string, error) + FindStudyMaterialByName(name string) (models.StudyMaterials, error) + FindStudyMaterialByNameReturnSchema(name string) (schemas.StudyMaterial, error) + GetSubjectID(code string) (uint, error) + GetSubjectCategoryID(name string) (uint, error) + GetSubjectCategory(subject string) (string, error) + GetSubjectCategoryIDByCode(code string) (uint, error) + GetSubjectIDByName(name string) (uint, error) + GetAssetIDByName(name string) (uint, error) + InsertAsset(name string) (uint, error) + UpdateAsset(id uint, name string) error + CreateSubject(name string, code string, id uint) error + CreateStudyMaterial(studyMaterial *schemas.StudyMaterial) error + UpdateStudyMaterialSubject(editrequest *schemas.Subject, name string, code string) error + UpdateStudyMaterial(studyMaterial *schemas.StudyMaterial) error + DeleteStudyMaterial(name string, subjectID uint, assetID uint) error +} + +func NewStudyMaterialRepository(db *gorm.DB) StudyMaterialRepository { + return &studyMaterialRepository{db} +} + +func (rr *studyMaterialRepository) UpdateStudyMaterialSubject(editrequest *schemas.Subject, name string, code string) error { + /* + return rr.db.Table("subjects").Where("subjects.subject_code = ?", code).Update("subjects.name", name).Error + return rr.db.Model(&schemas.Subject{}).Where("subjects.subject_code = ?", code).Update("name", name).Error + */ + return rr.db.Model(&editrequest).Where("subject_code = ?", code).Updates(&editrequest).Error +} + +func (rr *studyMaterialRepository) CreateStudyMaterial(studyMaterial *schemas.StudyMaterial) error { + return rr.db.Create(&studyMaterial).Error +} + +func (rr *studyMaterialRepository) GetSubjectIDByName(name string) (uint, error) { + var studyMaterial schemas.StudyMaterial + res := rr.db.Where("name = ?", name).First(&studyMaterial) + if res.Error != nil { + return 0, res.Error + } + return studyMaterial.SubjectID, nil +} +func (rr *studyMaterialRepository) DeleteStudyMaterial(name string, subjectID uint, assetID uint) error { + err := rr.db.Unscoped().Where("id = ?", subjectID).Delete(&schemas.Subject{}).Error + if err != nil { + return err + } + err = rr.db.Unscoped().Where("id = ?", assetID).Delete(&schemas.Asset{}).Error + if err != nil { + return err + } + return rr.db.Unscoped().Where("name = ?", name).Delete(&schemas.StudyMaterial{}).Error +} + +func (rr *studyMaterialRepository) GetSubjectID(code string) (uint, error) { + var subject schemas.Subject + res := rr.db.Where("subject_code = ?", code).First(&subject) + if res.Error != nil { + return 0, res.Error + } + return subject.ID, nil +} + +func (rr *studyMaterialRepository) GetSubjectCategoryID(name string) (uint, error) { + var subjectCategory schemas.SubjectCategory + res := rr.db.Where("name = ?", name).First(&subjectCategory) + if res.Error != nil { + return 0, res.Error + } + return subjectCategory.ID, nil +} + +func (rr *studyMaterialRepository) GetAssetIDByName(name string) (uint, error) { + var studyMaterial schemas.StudyMaterial + res := rr.db.Where("name = ?", name).First(&studyMaterial) + if res.Error != nil { + return 0, res.Error + } + return studyMaterial.AssetID, nil +} + +func (rr *studyMaterialRepository) InsertAsset(name string) (uint, error) { + var assetType schemas.AssetType + if err := rr.db.Where("name = ?", schemas.Document).First(&assetType).Error; err != nil { + return 0, err + } + asset := schemas.Asset{ + Name: name, + AssetTypeID: assetType.ID, + } + if err := rr.db.Create(&asset).Error; err != nil { + return 0, err + } + return asset.ID, nil +} + +func (rr *studyMaterialRepository) FindStudyMaterialByName(name string) (models.StudyMaterials, error) { + /* + var studyMaterial schemas.StudyMaterial + + err := rr.db.Preload(clause.Associations).Where("name = ?", name).First(&studyMaterial).Error + return studyMaterial, err + */ + var studyMaterials models.StudyMaterials + err := rr.db.Table("study_materials").Select( + `study_materials.name as name,subjects.name as subject,subjects.subject_code as subject_code,CONCAT(?::text,'/static/documents','/',assets.name) as document_url`, config.Origin, + ).Joins( + "JOIN assets on assets.id = study_materials.asset_id").Joins( + "JOIN subjects on subjects.id = study_materials.subject_id").Where( + "study_materials.name = ?", name).First( + &studyMaterials).Error + if err != nil { + return models.StudyMaterials{}, err + } + return studyMaterials, nil +} + +func (rr *studyMaterialRepository) UpdateStudyMaterial(studyMaterial *schemas.StudyMaterial) error { + return rr.db.Model(&studyMaterial).Where("id = ?", studyMaterial.ID).Updates(&studyMaterial).Error +} + +func (rr *studyMaterialRepository) GetCategoryStudyMaterials(name string) ([]models.StudyMaterials, error) { + var studyMaterials []models.StudyMaterials + if err := rr.db.Table("study_materials").Select( + `study_materials.name as name,subjects.name as subject,subject_categories.name as subject_category,subjects.subject_code as subject_code, CONCAT(?::text,'/static/documents','/',assets.name) as document_url`, config.Origin, + ).Joins( + "JOIN assets on assets.id = study_materials.asset_id").Joins( + "JOIN subjects on subjects.id = study_materials.subject_id").Joins("JOIN subject_categories on subject_categories.id = subjects.subject_category_id").Where("subject_categories.name = ?", name).Scan( + &studyMaterials).Error; err != nil { + return nil, err + } + + return studyMaterials, nil +} + +func (rr *studyMaterialRepository) UpdateAsset(id uint, name string) error { + return rr.db.Model(&schemas.Asset{}).Where("id = ?", id).Update("name", name).Error +} + +func (rr *studyMaterialRepository) CreateSubject(name string, code string, id uint) error { + subject := schemas.Subject{ + Name: name, + SubjectCategoryID: id, + SubjectCode: code, + } + res := rr.db.Create(&subject) + if res.Error != nil { + return res.Error + } + return nil +} + +func (rr *studyMaterialRepository) GetSubjectCategory(subject string) (string, error) { + var category string + if err := rr.db.Table("subject_categories").Select( + `subject_categories.name`, + ).Joins( + "JOIN subjects on subjects.subject_category_id = subject_categories.id").Where("subjects.name = ?", subject).Scan( + &category).Error; err != nil { + return "", err + } + return category, nil +} + +func (rr *studyMaterialRepository) FindStudyMaterialByNameReturnSchema(name string) (schemas.StudyMaterial, error) { + var studyMaterial schemas.StudyMaterial + + err := rr.db.Preload(clause.Associations).Where("name = ?", name).First(&studyMaterial).Error + return studyMaterial, err +} + +func (rr *studyMaterialRepository) GetSubjectCategoryIDByCode(code string) (uint, error) { + var id uint + if err := rr.db.Table("subjects").Select(`subjects.subject_category_id`).Where("subjects.subject_code = ?", code).Scan( + &id).Error; err != nil { + return 0, err + } + return id, nil +} + +/* + func (rr *studyMaterialRepository) GetAllMaterials(categories []string) ([]models.AllMaterials,error) { + var allMaterials []models.AllMaterials + var categoryMaterials models.AllMaterials + for _,category := range categories { + categoryMaterials.Category = category + + } + } +*/ +func (rr *studyMaterialRepository) GetAllCategories() ([]string, error) { + var allCategories []string + if err := rr.db.Table("subject_categories").Select(`subject_categories.name`).Scan( + &allCategories).Error; err != nil { + return nil, err + } + return allCategories, nil +} + +func (rr *studyMaterialRepository) GetSubjectsByCategory(category string) ([]string, error) { + var categorySubjects []string + id, err := rr.GetSubjectCategoryID(category) + if err != nil { + return nil, err + } + if err := rr.db.Table("subjects").Select("subjects.name").Joins("JOIN subject_categories on subject_categories.name = ?", category).Where("subjects.subject_category_id = ?", id).Scan(&categorySubjects).Error; err != nil { + return nil, err + } + return categorySubjects, nil +} + +func (rr *studyMaterialRepository) GetSubjectStudyMaterial(subject string) (models.SubjectMaterial, error) { + var subMaterial models.SubjectMaterial + var subjectCode string + if err := rr.db.Table("subjects").Select("subjects.subject_code").Where("subjects.name = ?", subject).Scan(&subjectCode).Error; err != nil { + return subMaterial, err + } + subMaterial.Name = subject + subMaterial.SubjectCode = subjectCode + subID, err := rr.GetSubjectID(subjectCode) + if err != nil { + return subMaterial, err + } + links, err1 := rr.GetDocumentLinks(subID) + if err1 != nil { + return subMaterial, err + } + subMaterial.Links = links + return subMaterial, nil +} + +func (rr *studyMaterialRepository) GetDocumentLinks(subID uint) ([]models.Links, error) { + var links []models.Links + if err := rr.db.Table("study_materials").Select(`study_materials.name as name,CONCAT(?::text,'/static/documents','/',assets.name) as document_url`, config.Origin).Joins("JOIN assets on assets.id = study_materials.asset_id").Where("study_materials.subject_id = ?", subID).Scan(&links).Error; err != nil { + return nil, err + } + return links, nil +} diff --git a/repositories/seeder_repository.go b/repositories/seeder_repository.go index f71db45..71f79d5 100644 --- a/repositories/seeder_repository.go +++ b/repositories/seeder_repository.go @@ -13,6 +13,7 @@ type SeedRepository interface { InsertTeams(teams []schemas.Team) error InsertRoles(roles []schemas.Role) error InsertAssetTypes(types []schemas.AssetType) error + InsertSubjectCategory(sc []schemas.SubjectCategory) error } func NewSeedRepository(db *gorm.DB) SeedRepository { @@ -31,3 +32,7 @@ func (sr *seedRepository) InsertRoles(roles []schemas.Role) error { func (sr *seedRepository) InsertAssetTypes(types []schemas.AssetType) error { return sr.db.Create(&types).Error } + +func (sr *seedRepository) InsertSubjectCategory(sc []schemas.SubjectCategory) error { + return sr.db.Create(&sc).Error +} diff --git a/router/resource.go b/router/resource.go new file mode 100644 index 0000000..c46d16f --- /dev/null +++ b/router/resource.go @@ -0,0 +1,22 @@ +package router + +import ( + "github.com/ecea-nitt/ecea-server/controllers" + "github.com/ecea-nitt/ecea-server/middlewares" + "github.com/labstack/echo/v4" +) + +func StudyMaterialRoutes(e *echo.Group, c controllers.StudyMaterialController) { + studyMaterial := e.Group("/studymaterial") + + studyMaterial.POST("/addMaterial", middlewares.Authorizer(c.AddStudyMaterial)) + studyMaterial.PUT("/edit/document", middlewares.Authorizer(c.UpdateStudyMaterialURL)) + // studyMaterial.PUT("/edit/name", middlewares.Authorizer(c.EditRessourceName)) + // studyMaterial.PUT("/edit/bookid", middlewares.Authorizer(c.EditMemberRole)) + studyMaterial.POST("/addSubject", middlewares.Authorizer(c.AddSubject)) + studyMaterial.GET("/getcat/:category", c.GetCategoryStudyMaterials) + studyMaterial.GET("/get/:name", c.GetStudyMaterial) + studyMaterial.GET("/getall", c.GetAllMaterials) + studyMaterial.DELETE("/delete/:name", middlewares.Authorizer(c.DeleteStudyMaterial)) + +} diff --git a/router/router.go b/router/router.go index 20a3ac4..48d3897 100644 --- a/router/router.go +++ b/router/router.go @@ -16,5 +16,6 @@ func NewRouter(e *echo.Echo, c controllers.AppController) { UserRoutes(api, c.User) TeamRoutes(api, c.Team) + StudyMaterialRoutes(api, c.StudyMaterial) SwaggerRoutes(api) } diff --git a/schemas/Schemas.md b/schemas/Schemas.md new file mode 100644 index 0000000..70537a3 --- /dev/null +++ b/schemas/Schemas.md @@ -0,0 +1,3 @@ +# Schemas + +![eceadb](https://user-images.githubusercontent.com/63253383/210140288-b791f989-0729-4a8d-ac4d-e501347bc7ad.jpg) \ No newline at end of file diff --git a/schemas/asset.go b/schemas/asset.go index 7ab5f23..c63c7e4 100644 --- a/schemas/asset.go +++ b/schemas/asset.go @@ -11,7 +11,7 @@ type Asset struct { type AssetType struct { gorm.Model - Name string `gorm:"not null;unique"` + Name string `gorm:"not null;"` } type AssetTypes string diff --git a/schemas/resource.go b/schemas/resource.go new file mode 100644 index 0000000..aef7d2a --- /dev/null +++ b/schemas/resource.go @@ -0,0 +1,25 @@ +package schemas + +import "gorm.io/gorm" + +type StudyMaterial struct { + gorm.Model + Name string `gorm:"not null; unique"` + AssetID uint `gorm:"default: null"` + Asset Asset `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` + SubjectID uint `gorm:"default: null"` + Subject Subject `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` +} + +type Subject struct { + gorm.Model + SubjectCode string `gorm:"not null; unique"` + Name string `gorm:"not null"` + SubjectCategoryID uint `gorm:"default: null"` + SubjectCategory SubjectCategory `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"` +} + +type SubjectCategory struct { + gorm.Model + Name string `gorm:"not null; unique"` +} diff --git a/services/resource_service.go b/services/resource_service.go new file mode 100644 index 0000000..b74528c --- /dev/null +++ b/services/resource_service.go @@ -0,0 +1,179 @@ +package services + +import ( + "errors" + "log" + "mime/multipart" + + "github.com/ecea-nitt/ecea-server/helpers" + "github.com/ecea-nitt/ecea-server/models" + "github.com/ecea-nitt/ecea-server/repositories" + "github.com/ecea-nitt/ecea-server/schemas" +) + +type studyMaterialService struct { + repo repositories.StudyMaterialRepository +} + +type StudyMaterialService interface { + CreateNewStudyMaterial(studyMaterialDetails models.StudyMaterialRequest, studyMaterialFile *multipart.FileHeader) error + // EditStudyMaterialSubject(subject string, code string) error + EditStudyMaterialURL(name string, file *multipart.FileHeader) error + GetStudyMaterial(name string) (models.StudyMaterials, error) + GetCategoryStudyMaterials(name string) ([]models.StudyMaterials, error) + RemoveStudyMaterial(name string) error + GetAllMaterials() ([]models.CategoryMaterials, error) + AddSubject(studyMaterialDetails *models.StudyMaterialRequest) error +} + +func NewStudyMaterialService(repo repositories.StudyMaterialRepository) StudyMaterialService { + return &studyMaterialService{repo} +} + +func (rs *studyMaterialService) CreateNewStudyMaterial(studyMaterialDetails models.StudyMaterialRequest, studyMaterialFile *multipart.FileHeader) error { + assetChannel := make(chan int) + subjectChannel := make(chan int) + subjectCategoryChannel := make(chan int) + /* + subjectCategoryID, err := rs.repo.GetSubjectCategoryID(studyMaterialDetails.SubjectCategory) + if err != nil { + return err + } + */ + go helpers.FetchSubjectCategoryID(subjectCategoryChannel, studyMaterialDetails.SubjectCode, rs.repo) + subjectCategoryID := <-subjectCategoryChannel + go helpers.FetchSubjectID(subjectChannel, studyMaterialDetails.SubjectCode, rs.repo) + go helpers.UploadFileAndFetchAssetID(assetChannel, studyMaterialFile, rs.repo) + subjectID := <-subjectChannel + assetID := <-assetChannel + if subjectID == -1 || assetID == -1 || subjectCategoryID == -1 { + return errors.New("could not fetch data") + } + studyMaterial := schemas.StudyMaterial{ + Name: studyMaterialDetails.Name, + SubjectID: uint(subjectID), + AssetID: uint(assetID), + } + log.Println(subjectCategoryID, studyMaterialDetails.SubjectCategory) + return rs.repo.CreateStudyMaterial(&studyMaterial) +} + +/* +func (rs *studyMaterialService) EditStudyMaterialSubject(subject string, code string) error { + editrequest := schemas.Subject{ + Name: subject, + SubjectCode: code, + } + subjectID, err := rs.repo.GetSubjectIDByCode(code) + if err != nil { + return err + } + return rs.repo.UpdateStudyMaterialSubject(&editrequest, subject, code) +} +*/ + +func (rs *studyMaterialService) EditStudyMaterialURL(name string, file *multipart.FileHeader) error { + dbStudyMaterial, err := rs.repo.FindStudyMaterialByNameReturnSchema(name) + if err != nil { + return err + } + + assetID := helpers.UpdateFileAndFetchAssetID(dbStudyMaterial.AssetID, dbStudyMaterial.Asset.Name, file, rs.repo) + + if assetID == -1 { + return errors.New(" Error Occurred") + } + + studyMaterial := schemas.StudyMaterial{ + AssetID: uint(assetID), + } + studyMaterial.ID = dbStudyMaterial.ID + + return rs.repo.UpdateStudyMaterial(&studyMaterial) +} + +func (rs *studyMaterialService) RemoveStudyMaterial(name string) error { + subjectID, err1 := rs.repo.GetSubjectIDByName(name) + if err1 != nil { + return err1 + } + assetID, err2 := rs.repo.GetAssetIDByName(name) + if err2 != nil { + return err2 + } + return rs.repo.DeleteStudyMaterial(name, subjectID, assetID) +} + +func (rs *studyMaterialService) GetStudyMaterial(name string) (models.StudyMaterials, error) { + studyMaterial, err := rs.repo.FindStudyMaterialByName(name) + if err != nil { + return models.StudyMaterials{}, err + } + subjectCategory, err1 := rs.repo.GetSubjectCategory(studyMaterial.Subject) + if err1 != nil { + return models.StudyMaterials{}, err1 + } + result := models.StudyMaterials{ + Name: studyMaterial.Name, + Subject: studyMaterial.Subject, + SubjectCategory: subjectCategory, + SubjectCode: studyMaterial.SubjectCode, + DocumentURL: studyMaterial.DocumentURL, + } + log.Println(studyMaterial) + log.Println(result) + return result, err +} + +func (rs *studyMaterialService) GetCategoryStudyMaterials(name string) ([]models.StudyMaterials, error) { + return rs.repo.GetCategoryStudyMaterials(name) +} + +func (rs *studyMaterialService) AddSubject(studyMaterialDetails *models.StudyMaterialRequest) error { + subjectName := studyMaterialDetails.Subject + subjectCode := studyMaterialDetails.SubjectCode + subjectCategory := studyMaterialDetails.SubjectCategory + id, err := rs.repo.GetSubjectCategoryID(subjectCategory) + if err != nil { + return err + } + return rs.repo.CreateSubject(subjectName, subjectCode, id) +} + +func (rs *studyMaterialService) GetAllMaterials() ([]models.CategoryMaterials, error) { + allCategories, err := rs.repo.GetAllCategories() + if err != nil { + return nil, err + } + var allMaterials []models.CategoryMaterials + var categoryMaterials models.CategoryMaterials + /* + for _, category := range allCategories { + categoryMaterials.Category = category + temp, err := rs.repo.GetCategoryStudyMaterials(category) + if err != nil { + return nil, err + } + categoryMaterials.Material = temp + allMaterials = append(allMaterials, categoryMaterials) + } + */ + for _, category := range allCategories { + subjects, err := rs.repo.GetSubjectsByCategory(category) + if err != nil { + return nil, err + } + var subjectMaterialList []models.SubjectMaterial + for _, subject := range subjects { + materials, err := rs.repo.GetSubjectStudyMaterial(subject) + if err != nil { + return nil, err + } + subjectMaterialList = append(subjectMaterialList, materials) + } + categoryMaterials.Category = category + categoryMaterials.SubjectMaterial = subjectMaterialList + allMaterials = append(allMaterials, categoryMaterials) + } + return allMaterials, nil +} diff --git a/services/seeder_service.go b/services/seeder_service.go index 9837b41..125cea4 100644 --- a/services/seeder_service.go +++ b/services/seeder_service.go @@ -14,6 +14,7 @@ type SeederService interface { AssetTypesSeeder() error TeamsSeeder() error RolesSeeder() error + StudyMaterialSeeder() error } var teams = []schemas.Team{ @@ -60,6 +61,32 @@ var assetTypes = []schemas.AssetType{ Name: string(schemas.Document), }, } +var subjectCategory = []schemas.SubjectCategory{ + { + Name: string(models.AnalogElectronics), + }, + { + Name: string(models.CommunicationChanneling), + }, + { + Name: string(models.DigitalElectronics), + }, + { + Name: string(models.SystemDesignAndArchitechture), + }, + { + Name: string(models.BasicEngineering), + }, + { + Name: string(models.Mathematics), + }, + { + Name: string(models.Telecommunication), + }, + { + Name: string(models.Others), + }, +} func NewSeeder(repo repositories.SeedRepository) SeederService { return &seederService{repo} @@ -76,3 +103,7 @@ func (s *seederService) RolesSeeder() error { func (s *seederService) AssetTypesSeeder() error { return s.repo.InsertAssetTypes(assetTypes) } + +func (s *seederService) StudyMaterialSeeder() error { + return s.repo.InsertSubjectCategory(subjectCategory) +} diff --git a/utils/document.go b/utils/document.go new file mode 100644 index 0000000..cec54ba --- /dev/null +++ b/utils/document.go @@ -0,0 +1,51 @@ +package utils + +import ( + "io" + "log" + "mime/multipart" + "os" + "time" + + "github.com/fatih/color" +) + +var DocumentPath = "static/documents/" + +func UploadDocument(file *multipart.FileHeader) (string, error) { + + src, err := file.Open() + if err != nil { + return "", err + } + defer src.Close() + + // Destination + timeStamp := time.Now() + + if _, err := os.Stat(DocumentPath); os.IsNotExist(err) { + _ = os.Mkdir(DocumentPath, 0777) + } + fileName := timeStamp.Format(time.RFC3339) + ".pdf" + path := DocumentPath + fileName + dst, err := os.Create(path) + if err != nil { + return "", err + } + defer dst.Close() + // Copy + if _, err = io.Copy(dst, src); err != nil { + return "", err + } + return fileName, nil +} + +func DeleteDocument(fileName string) error { + path := DocumentPath + fileName + log.Println(color.MagentaString("Deleting: " + path)) + e := os.Remove(path) + if e != nil { + return e + } + return nil +} diff --git a/utils/validator.go b/utils/validator.go index f033495..5941c78 100644 --- a/utils/validator.go +++ b/utils/validator.go @@ -37,7 +37,7 @@ func NumericValidator(s string) (string, error) { func EmailValidator(s string) (string, error) { var IsValid = regexp.MustCompile(`^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$`).MatchString if !IsValid(s) { - return s, errors.New("Invalid Email format") + return s, errors.New(" Invalid Email format") } return s, nil }