From 95e13dd1f26576f129e984ede90dccf2ab31325f Mon Sep 17 00:00:00 2001 From: Ismael Ibuan <102030576+iibuan@users.noreply.github.com> Date: Thu, 12 Sep 2024 22:11:01 +0800 Subject: [PATCH] refactor: implement clean arch on get items Signed-off-by: Ismael Ibuan <102030576+iibuan@users.noreply.github.com> --- src/goapp/config/config.go | 11 ++ src/goapp/config/env-config.go | 26 +++ src/goapp/controller/item/implement.go | 55 ++++++ src/goapp/controller/item/interface.go | 7 + src/goapp/init.go | 24 +++ src/goapp/{models => model}/approvals.go | 2 +- src/goapp/{models => model}/data.go | 2 +- src/goapp/model/item.go | 45 +++++ src/goapp/pkg/template/template.go | 16 +- src/goapp/repository/database.go | 184 ++++++++++++++++++ src/goapp/repository/item/implement.go | 155 ++++++++++++++++ src/goapp/repository/item/interface.go | 10 + src/goapp/{http => router}/mux-router.go | 8 + src/goapp/{http => router}/router.go | 2 + src/goapp/routes.go | 7 +- src/goapp/routes/apis/item.go | 185 ------------------- src/goapp/routes/pages/approvals/request.go | 4 +- src/goapp/routes/pages/approvals/response.go | 4 +- src/goapp/service/item/implement.go | 67 +++++++ src/goapp/service/item/interface.go | 10 + 20 files changed, 619 insertions(+), 205 deletions(-) create mode 100644 src/goapp/config/config.go create mode 100644 src/goapp/config/env-config.go create mode 100644 src/goapp/controller/item/implement.go create mode 100644 src/goapp/controller/item/interface.go create mode 100644 src/goapp/init.go rename src/goapp/{models => model}/approvals.go (97%) rename src/goapp/{models => model}/data.go (97%) create mode 100644 src/goapp/model/item.go create mode 100644 src/goapp/repository/database.go create mode 100644 src/goapp/repository/item/implement.go create mode 100644 src/goapp/repository/item/interface.go rename src/goapp/{http => router}/mux-router.go (87%) rename src/goapp/{http => router}/router.go (60%) create mode 100644 src/goapp/service/item/implement.go create mode 100644 src/goapp/service/item/interface.go diff --git a/src/goapp/config/config.go b/src/goapp/config/config.go new file mode 100644 index 0000000..2dc61f2 --- /dev/null +++ b/src/goapp/config/config.go @@ -0,0 +1,11 @@ +package config + +type Key string + +type Config struct { + DatabaseConnectionString string +} + +type ConfigManager interface { + GetDatabaseConnectionString() string +} diff --git a/src/goapp/config/env-config.go b/src/goapp/config/env-config.go new file mode 100644 index 0000000..f0a09e5 --- /dev/null +++ b/src/goapp/config/env-config.go @@ -0,0 +1,26 @@ +package config + +import ( + "log" + "os" + + "github.com/joho/godotenv" +) + +type envConfigManager struct { + *Config +} + +func NewEnvConfigManager() *envConfigManager { + // Set environment variables + err := godotenv.Load() + if err != nil { + log.Fatal(err.Error()) + } + + return &envConfigManager{} +} + +func (ecm *envConfigManager) GetDatabaseConnectionString() string { + return os.Getenv("APPROVALSYSTEMDB_CONNECTION_STRING") +} diff --git a/src/goapp/controller/item/implement.go b/src/goapp/controller/item/implement.go new file mode 100644 index 0000000..f43b3f4 --- /dev/null +++ b/src/goapp/controller/item/implement.go @@ -0,0 +1,55 @@ +package item + +import ( + "encoding/json" + "fmt" + "main/pkg/session" + service "main/service/item" + "net/http" + + "github.com/gorilla/mux" +) + +type itemController struct { + itemService service.ItemService +} + +func NewItemController(itemService service.ItemService) ItemController { + return &itemController{ + itemService: itemService, + } +} + +// GetItems is a function to get all items +func (c *itemController) GetItems(w http.ResponseWriter, r *http.Request) { + // Get all items + vars := mux.Vars(r) + + params := r.URL.Query() + + session, err := session.Store.Get(r, "auth-session") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + var profile map[string]interface{} + u := session.Values["profile"] + profile, ok := u.(map[string]interface{}) + if !ok { + http.Error(w, "Failed to get user info", http.StatusInternalServerError) + return + } + user := fmt.Sprintf("%s", profile["preferred_username"]) + + result, err := c.itemService.GetAll(vars, params, user) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Return the result + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(result) +} diff --git a/src/goapp/controller/item/interface.go b/src/goapp/controller/item/interface.go new file mode 100644 index 0000000..343128c --- /dev/null +++ b/src/goapp/controller/item/interface.go @@ -0,0 +1,7 @@ +package item + +import "net/http" + +type ItemController interface { + GetItems(w http.ResponseWriter, r *http.Request) +} diff --git a/src/goapp/init.go b/src/goapp/init.go new file mode 100644 index 0000000..c061447 --- /dev/null +++ b/src/goapp/init.go @@ -0,0 +1,24 @@ +package main + +import ( + "main/config" + "main/repository" + "main/router" + + repositoryItem "main/repository/item" + + serviceItem "main/service/item" + + controllerItem "main/controller/item" +) + +var ( + configManager config.ConfigManager = config.NewEnvConfigManager() + database repository.Database = repository.NewDatabase(configManager) + + itemRepository repositoryItem.ItemRepository = repositoryItem.NewItemRepository(database) + itemService serviceItem.ItemService = serviceItem.NewItemService(itemRepository) + itemController controllerItem.ItemController = controllerItem.NewItemController(itemService) + + httpRouter router.Router = router.NewMuxRouter() +) diff --git a/src/goapp/models/approvals.go b/src/goapp/model/approvals.go similarity index 97% rename from src/goapp/models/approvals.go rename to src/goapp/model/approvals.go index d392713..5de917b 100644 --- a/src/goapp/models/approvals.go +++ b/src/goapp/model/approvals.go @@ -1,4 +1,4 @@ -package models +package model type TypRequestApproval struct { ApplicationId string `json:"applicationId"` diff --git a/src/goapp/models/data.go b/src/goapp/model/data.go similarity index 97% rename from src/goapp/models/data.go rename to src/goapp/model/data.go index 3dab167..0731578 100644 --- a/src/goapp/models/data.go +++ b/src/goapp/model/data.go @@ -1,4 +1,4 @@ -package models +package model type TypPageData struct { Header interface{} diff --git a/src/goapp/model/item.go b/src/goapp/model/item.go new file mode 100644 index 0000000..ecf7ec8 --- /dev/null +++ b/src/goapp/model/item.go @@ -0,0 +1,45 @@ +package model + +type Item struct { + Application string `json:"application"` + ApproverRemarks string `json:"approverRemarks"` + Body string `json:"body"` + Created string `json:"created"` + DateResponded string `json:"dateResponded"` + DateSent string `json:"dateSent"` + IsApproved bool `json:"isApproved"` + Module string `json:"module"` + Subject string `json:"subject"` + ApproveText string `json:"approveText"` + RejectText string `json:"rejectText"` + ApproveUrl string `json:"approveUrl"` + RejectUrl string `json:"rejectUrl"` + AllowReassign bool `json:"allowReassign"` + AllowReassignUrl string `json:"allowReassignUrl"` + RespondedBy string `json:"respondedBy"` + Approvers []string `json:"approvers"` + RequestedBy string `json:"requestedBy"` +} + +type Response struct { + Data []Item `json:"data"` + Total int `json:"total"` +} + +type ItemType int8 + +const ( + RequestItem ItemType = iota + ApprovalItem + AllType +) + +type ItemStatus int8 + +const ( + Pending ItemStatus = iota + Approved + Rejected + Closed // Disapproved, Approved + All // Disapproved, Approved, Pending +) diff --git a/src/goapp/pkg/template/template.go b/src/goapp/pkg/template/template.go index 08dfeb7..c10c394 100644 --- a/src/goapp/pkg/template/template.go +++ b/src/goapp/pkg/template/template.go @@ -3,7 +3,7 @@ package template import ( "fmt" "html/template" - "main/models" + "main/model" session "main/pkg/session" "net/http" "os" @@ -28,21 +28,21 @@ func UseTemplate(w *http.ResponseWriter, r *http.Request, page string, pageData } // Data on master page - var menu []models.TypMenu - menu = append(menu, models.TypMenu{Name: "My Requests", Url: "/", IconPath: "/public/icons/projects.svg"}) - menu = append(menu, models.TypMenu{Name: "My Approvals", Url: "/myapprovals", IconPath: "/public/icons/approvals.svg"}) - masterPageData := models.TypHeaders{Menu: menu, Page: getUrlPath(r.URL.Path)} + var menu []model.TypMenu + menu = append(menu, model.TypMenu{Name: "My Requests", Url: "/", IconPath: "/public/icons/projects.svg"}) + menu = append(menu, model.TypMenu{Name: "My Approvals", Url: "/myapprovals", IconPath: "/public/icons/approvals.svg"}) + masterPageData := model.TypHeaders{Menu: menu, Page: getUrlPath(r.URL.Path)} //Footers - var footers []models.Footer + var footers []model.Footer footerString := os.Getenv("LINK_FOOTERS") res := strings.Split(footerString, ";") for _, footer := range res { f := strings.Split(footer, ">") - footers = append(footers, models.Footer{Text: f[0], Url: f[1]}) + footers = append(footers, model.Footer{Text: f[0], Url: f[1]}) } - data := models.TypPageData{ + data := model.TypPageData{ Header: masterPageData, Profile: profile, Content: pageData, diff --git a/src/goapp/repository/database.go b/src/goapp/repository/database.go new file mode 100644 index 0000000..9e1c92f --- /dev/null +++ b/src/goapp/repository/database.go @@ -0,0 +1,184 @@ +package repository + +import ( + "context" + "database/sql" + "fmt" + "main/config" + + _ "github.com/microsoft/go-mssqldb" +) + +type Database struct { + connString string + db *sql.DB +} + +func NewDatabase(config config.ConfigManager) Database { + fmt.Println("ConnectDb New") + connectionString := config.GetDatabaseConnectionString() + return Database{ + connString: connectionString, + } +} + +func (d *Database) Connect() error { + conn, err := sql.Open("sqlserver", d.connString) + if err != nil { + return err + } + + d.db = conn + return nil +} + +func (d *Database) Disconnect() error { + if d.db != nil { + return d.db.Close() + } + return nil +} + +func (d *Database) Query(query string, args ...any) (*sql.Rows, error) { + err := d.Connect() + if err != nil { + return nil, err + } + defer d.Disconnect() + + ctx := context.Background() + rows, err := d.db.QueryContext(ctx, query, args...) + if err != nil { + return nil, err + } + return rows, nil +} + +func (d *Database) QueryRow(query string, args ...any) (*sql.Row, error) { + err := d.Connect() + if err != nil { + return nil, err + } + defer d.Disconnect() + + ctx := context.Background() + row := d.db.QueryRowContext(ctx, query, args...) + if row == nil { + err = fmt.Errorf("QueryRowContext returned nil") + } + return row, nil +} + +func (d *Database) Execute(query string, args ...any) error { + err := d.Connect() + if err != nil { + return err + } + defer d.Disconnect() + + ctx := context.Background() + _, err = d.db.ExecContext(ctx, query, args...) + if err != nil { + return err + } + return nil +} + +// helper function to convert rows.Scan() to map[string]interface{} +func (d *Database) RowsToMap(rows *sql.Rows) ([]map[string]interface{}, error) { + columns, err := rows.Columns() + if err != nil { + return nil, err + } + + var results []map[string]interface{} + + for rows.Next() { + values := make([]interface{}, len(columns)) + pointers := make([]interface{}, len(columns)) + for i := range values { + pointers[i] = &values[i] + } + err := rows.Scan(pointers...) + if err != nil { + return nil, err + } + result := make(map[string]interface{}) + for i, val := range values { + result[columns[i]] = val + } + results = append(results, result) + } + + return results, nil +} + +// OLD +func (d *Database) Close() error { + if d.db != nil { + return d.db.Close() + } + return nil +} + +// OLD +func (d *Database) ExecuteStoredProcedure(procedure string, params map[string]interface{}) (sql.Result, error) { + var args []interface{} + + for i, v := range params { + args = append(args, sql.Named(i, v)) + } + + ctx := context.Background() + result, err := d.db.ExecContext(ctx, procedure, args...) + + if err != nil { + return nil, err + } + + return result, nil +} + +// OLD +func (d *Database) ExecuteStoredProcedureWithResult(procedure string, params map[string]interface{}) ([]map[string]interface{}, error) { + var args []interface{} + + ctx := context.Background() + + for i, v := range params { + args = append(args, sql.Named(i, v)) + } + + rows, err := d.db.QueryContext(ctx, procedure, args...) + if err != nil { + return nil, err + } + + defer rows.Close() + + columns, err := rows.Columns() + if err != nil { + return nil, err + } + + var results []map[string]interface{} + + for rows.Next() { + values := make([]interface{}, len(columns)) + pointers := make([]interface{}, len(columns)) + for i := range values { + pointers[i] = &values[i] + } + err := rows.Scan(pointers...) + if err != nil { + return nil, err + } + result := make(map[string]interface{}) + for i, val := range values { + result[columns[i]] = val + } + results = append(results, result) + } + + return results, nil +} diff --git a/src/goapp/repository/item/implement.go b/src/goapp/repository/item/implement.go new file mode 100644 index 0000000..b35c313 --- /dev/null +++ b/src/goapp/repository/item/implement.go @@ -0,0 +1,155 @@ +package item + +import ( + "database/sql" + "fmt" + "main/model" + "main/repository" + "strconv" + "time" +) + +type itemRepository struct { + repository.Database +} + +func NewItemRepository(db repository.Database) ItemRepository { + return &itemRepository{ + Database: db, + } +} + +func (r *itemRepository) GetItemsBy(itemType model.ItemType, itemStatus model.ItemStatus, requestType, organization, user, search string, offset, filter int) ([]model.Item, error) { + var params []interface{} + + if itemType != model.AllType { + params = append(params, sql.Named("ItemType", itemType)) + params = append(params, sql.Named("User", user)) + } + + if requestType != "" { + params = append(params, sql.Named("RequestType", requestType)) + } + + if organization != "" { + params = append(params, sql.Named("Organization", organization)) + } + + params = append(params, sql.Named("IsApproved", itemStatus)) + params = append(params, sql.Named("Search", search)) + params = append(params, sql.Named("Offset", offset)) + params = append(params, sql.Named("Filter", filter)) + + resList, err := r.Query("PR_Items_Select", params...) + if err != nil { + return []model.Item{}, err + } + + result, err := r.RowsToMap(resList) + if err != nil { + return []model.Item{}, err + } + + var items []model.Item + + for _, v := range result { + + item := model.Item{ + Application: v["Application"].(string), + Created: v["Created"].(time.Time).String(), + Module: v["Module"].(string), + ApproveText: v["ApproveText"].(string), + RejectText: v["RejectText"].(string), + AllowReassign: v["AllowReassign"].(bool), + RequestedBy: v["RequestedBy"].(string), + } + + if v["ApproverRemarks"] != nil { + item.ApproverRemarks = v["ApproverRemarks"].(string) + } + + if v["Body"] != nil { + item.Body = v["Body"].(string) + } + + if v["DateResponded"] != nil { + item.DateResponded = v["DateResponded"].(time.Time).String() + } + + if v["DateSent"] != nil { + item.DateSent = v["DateSent"].(time.Time).String() + } + + if v["IsApproved"] != nil { + item.IsApproved = v["IsApproved"].(bool) + } else { + item.ApproveUrl = fmt.Sprintf("/response/%s/%s/%s/1", v["ApplicationId"], v["ApplicationModuleId"], v["ItemId"]) + item.RejectUrl = fmt.Sprintf("/response/%s/%s/%s/0", v["ApplicationId"], v["ApplicationModuleId"], v["ItemId"]) + item.AllowReassignUrl = fmt.Sprintf("/responsereassigned/%s/%s/%s/1/%s/%s", v["ApplicationId"], v["ApplicationModuleId"], v["ItemId"], v["ApproveText"].(string), v["RejectText"].(string)) + + } + + if v["Subject"] != nil { + item.Subject = v["Subject"].(string) + } + + if v["RespondedBy"] != nil { + item.RespondedBy = v["RespondedBy"].(string) + } + + rowApprovers, err := r.Query("PR_ApprovalRequestApprovers_Select_ByItemId", sql.Named("ItemId", v["ItemId"].(string))) + if err != nil { + return []model.Item{}, err + } + + approvers, err := r.RowsToMap(rowApprovers) + if err != nil { + return []model.Item{}, err + } + + for _, approver := range approvers { + item.Approvers = append(item.Approvers, approver["ApproverEmail"].(string)) + } + + items = append(items, item) + } + + return items, nil +} + +func (r *itemRepository) GetTotalItemsBy(itemType model.ItemType, itemStatus model.ItemStatus, requestType, organization, user, search string) (int, error) { + var params []interface{} + + if itemType != model.AllType { + params = append(params, sql.Named("ItemType", itemType)) + params = append(params, sql.Named("User", user)) + } + + if requestType != "" { + params = append(params, sql.Named("RequestType", requestType)) + } + + if organization != "" { + params = append(params, sql.Named("Organization", organization)) + } + + params = append(params, sql.Named("IsApproved", itemStatus)) + params = append(params, sql.Named("Search", search)) + + rowTotal, err := r.Query("PR_Items_Total", params...) + if err != nil { + return 0, err + } + + resultTotal, err := r.RowsToMap(rowTotal) + if err != nil { + return 0, err + } + + total, err := strconv.Atoi(fmt.Sprint(resultTotal[0]["Total"])) + if err != nil { + return 0, err + } + + return total, nil +} diff --git a/src/goapp/repository/item/interface.go b/src/goapp/repository/item/interface.go new file mode 100644 index 0000000..3e3dea7 --- /dev/null +++ b/src/goapp/repository/item/interface.go @@ -0,0 +1,10 @@ +package item + +import ( + "main/model" +) + +type ItemRepository interface { + GetItemsBy(itemType model.ItemType, itemStatus model.ItemStatus, requestType, organization, user, search string, offset, filter int) ([]model.Item, error) + GetTotalItemsBy(itemType model.ItemType, itemStatus model.ItemStatus, requestType, organization, user, search string) (int, error) +} diff --git a/src/goapp/http/mux-router.go b/src/goapp/router/mux-router.go similarity index 87% rename from src/goapp/http/mux-router.go rename to src/goapp/router/mux-router.go index f91ed0d..9f24c6a 100644 --- a/src/goapp/http/mux-router.go +++ b/src/goapp/router/mux-router.go @@ -29,6 +29,14 @@ func (*muxRouter) POST(uri string, f func(resp http.ResponseWriter, req *http.Re muxDispatcher.HandleFunc(uri, f).Methods("POST") } +func (*muxRouter) PUT(uri string, f func(resp http.ResponseWriter, req *http.Request)) { + muxDispatcher.HandleFunc(uri, f).Methods("PUT") +} + +func (*muxRouter) DELETE(uri string, f func(resp http.ResponseWriter, req *http.Request)) { + muxDispatcher.HandleFunc(uri, f).Methods("DELETE") +} + func (*muxRouter) SERVE(port string) { secureOptions := secure.Options{ SSLRedirect: true, // Strict-Transport-Security diff --git a/src/goapp/http/router.go b/src/goapp/router/router.go similarity index 60% rename from src/goapp/http/router.go rename to src/goapp/router/router.go index ec37ee3..8b23e7b 100644 --- a/src/goapp/http/router.go +++ b/src/goapp/router/router.go @@ -5,5 +5,7 @@ import "net/http" type Router interface { GET(uri string, f func(resp http.ResponseWriter, req *http.Request)) POST(uri string, f func(resp http.ResponseWriter, req *http.Request)) + PUT(uri string, f func(resp http.ResponseWriter, req *http.Request)) + DELETE(uri string, f func(resp http.ResponseWriter, req *http.Request)) SERVE(port string) } diff --git a/src/goapp/routes.go b/src/goapp/routes.go index c6233c7..8f17d79 100644 --- a/src/goapp/routes.go +++ b/src/goapp/routes.go @@ -1,7 +1,6 @@ package main import ( - router "main/http" m "main/middleware" ev "main/pkg/envvar" rtApi "main/routes/apis" @@ -10,10 +9,6 @@ import ( rtApprovals "main/routes/pages/approvals" ) -var ( - httpRouter router.Router = router.NewMuxRouter() -) - func setPageRoutes() { httpRouter.GET("/", m.Chain(rtApprovals.MyRequestsHandler, m.AzureAuth())) httpRouter.GET("/myapprovals", m.Chain(rtApprovals.MyApprovalsHandler, m.AzureAuth())) @@ -30,7 +25,7 @@ func setApiRoutes() { httpRouter.GET("/api/request/types", m.Chain(rtApi.GetRequestTypes, m.AzureAuth())) httpRouter.POST("/api/request", rtApprovals.ApprovalRequestHandler) httpRouter.POST("/api/process", rtApprovals.ProcessResponseHandler) - httpRouter.GET("/api/items/type/{type:[0-2]+}/status/{status:[0-3]+}", m.Chain(rtApi.GetItems, m.AzureAuth())) + httpRouter.GET("/api/items/type/{type:[0-2]+}/status/{status:[0-3]+}", m.Chain(itemController.GetItems, m.AzureAuth())) httpRouter.GET("/api/search/users/{search}", m.Chain(rtApi.SearchUserFromActiveDirectory, m.AzureAuth())) httpRouter.GET("/api/responsereassignedapi/{itemGuid}/{approver}/{ApplicationId}/{ApplicationModuleId}/{itemId}/{ApproveText}/{RejectText}", m.Chain(rtApprovals.ReAssignApproverHandler, m.AzureAuth())) } diff --git a/src/goapp/routes/apis/item.go b/src/goapp/routes/apis/item.go index 3cef060..34dd846 100644 --- a/src/goapp/routes/apis/item.go +++ b/src/goapp/routes/apis/item.go @@ -3,14 +3,9 @@ package routes import ( "encoding/json" "fmt" - "main/pkg/session" "main/pkg/sql" "net/http" "os" - "strconv" - "time" - - "github.com/gorilla/mux" ) type ItemType int8 @@ -57,186 +52,6 @@ type Response struct { Total int `json:"total"` } -func GetItems(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - - params := r.URL.Query() - - session, errAuth := session.Store.Get(r, "auth-session") - if errAuth != nil { - http.Error(w, errAuth.Error(), http.StatusInternalServerError) - return - } - - var profile map[string]interface{} - u := session.Values["profile"] - profile, ok := u.(map[string]interface{}) - if !ok { - http.Error(w, errAuth.Error(), http.StatusInternalServerError) - return - } - user := fmt.Sprintf("%s", profile["preferred_username"]) - - itemType, errItemType := strconv.ParseInt(vars["type"], 10, 8) - if errItemType != nil { - http.Error(w, errItemType.Error(), http.StatusInternalServerError) - return - } - - itemStatus, errItemStatus := strconv.ParseInt(vars["status"], 10, 8) - if errItemStatus != nil { - http.Error(w, errItemStatus.Error(), http.StatusInternalServerError) - return - } - - var result Response - - if params.Has("offset") && params.Has("filter") { - filter, _ := strconv.Atoi(params["filter"][0]) - offset, _ := strconv.Atoi(params["offset"][0]) - search := params["search"][0] - requestType := "" - if params["requestType"] != nil { - if params["requestType"][0] != "" { - requestType = params["requestType"][0] - } - } - - organization := "" - if params["organization"] != nil { - if params["organization"][0] != "" { - organization = params["organization"][0] - } - } - - data, total, err := GetItemsBy(ItemType(itemType), ItemStatus(itemStatus), requestType, organization, user, search, offset, filter) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - result = Response{ - Data: data, - Total: total, - } - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(result) -} - -func GetItemsBy(itemType ItemType, itemStatus ItemStatus, requestType, organization, user, search string, offset, filter int) ([]Item, int, error) { - dbConnectionParam := sql.ConnectionParam{ - ConnectionString: os.Getenv("APPROVALSYSTEMDB_CONNECTION_STRING"), - } - - db, errInit := sql.Init(dbConnectionParam) - if errInit != nil { - return []Item{}, 0, errInit - } - defer db.Close() - - params := make(map[string]interface{}) - - if itemType != AllType { - params["ItemType"] = itemType - params["User"] = user - } - - if requestType != "" { - params["RequestType"] = requestType - } - - if organization != "" { - params["Organization"] = organization - } - - params["IsApproved"] = itemStatus - params["Search"] = search - - resultTotal, errResultTotal := db.ExecuteStoredProcedureWithResult("PR_Items_Total", params) - if errResultTotal != nil { - return []Item{}, 0, errResultTotal - } - - params["Offset"] = offset - params["Filter"] = filter - - total, errTotal := strconv.Atoi(fmt.Sprint(resultTotal[0]["Total"])) - if errTotal != nil { - return []Item{}, 0, errTotal - } - - result, errResult := db.ExecuteStoredProcedureWithResult("PR_Items_Select", params) - if errResult != nil { - return []Item{}, 0, errResult - } - - var items []Item - - for _, v := range result { - - item := Item{ - Application: v["Application"].(string), - Created: v["Created"].(time.Time).String(), - Module: v["Module"].(string), - ApproveText: v["ApproveText"].(string), - RejectText: v["RejectText"].(string), - AllowReassign: v["AllowReassign"].(bool), - RequestedBy: v["RequestedBy"].(string), - } - - if v["ApproverRemarks"] != nil { - item.ApproverRemarks = v["ApproverRemarks"].(string) - } - - if v["Body"] != nil { - item.Body = v["Body"].(string) - } - - if v["DateResponded"] != nil { - item.DateResponded = v["DateResponded"].(time.Time).String() - } - - if v["DateSent"] != nil { - item.DateSent = v["DateSent"].(time.Time).String() - } - - if v["IsApproved"] != nil { - item.IsApproved = v["IsApproved"].(bool) - } else { - item.ApproveUrl = fmt.Sprintf("/response/%s/%s/%s/1", v["ApplicationId"], v["ApplicationModuleId"], v["ItemId"]) - item.RejectUrl = fmt.Sprintf("/response/%s/%s/%s/0", v["ApplicationId"], v["ApplicationModuleId"], v["ItemId"]) - item.AllowReassignUrl = fmt.Sprintf("/responsereassigned/%s/%s/%s/1/%s/%s", v["ApplicationId"], v["ApplicationModuleId"], v["ItemId"], v["ApproveText"].(string), v["RejectText"].(string)) - - } - - if v["Subject"] != nil { - item.Subject = v["Subject"].(string) - } - - if v["RespondedBy"] != nil { - item.RespondedBy = v["RespondedBy"].(string) - } - - ApproverRequestApproversParams := make(map[string]interface{}) - ApproverRequestApproversParams["ItemId"] = v["ItemId"].(string) - approvers, errApprovers := db.ExecuteStoredProcedureWithResult("PR_ApprovalRequestApprovers_Select_ByItemId", ApproverRequestApproversParams) - if errApprovers != nil { - return []Item{}, 0, errApprovers - } - - for _, approver := range approvers { - item.Approvers = append(item.Approvers, approver["ApproverEmail"].(string)) - } - - items = append(items, item) - } - - return items, total, nil -} - type RequestType struct { Id string `json:"id"` Name string `json:"name"` diff --git a/src/goapp/routes/pages/approvals/request.go b/src/goapp/routes/pages/approvals/request.go index 06311cb..d6229d1 100644 --- a/src/goapp/routes/pages/approvals/request.go +++ b/src/goapp/routes/pages/approvals/request.go @@ -3,7 +3,7 @@ package route import ( "encoding/json" "fmt" - "main/models" + "main/model" "main/pkg/email" "main/pkg/sql" "net/http" @@ -15,7 +15,7 @@ import ( func ApprovalRequestHandler(w http.ResponseWriter, r *http.Request) { // Decode payload - var req models.TypRequestApproval + var req model.TypRequestApproval err := json.NewDecoder(r.Body).Decode(&req) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) diff --git a/src/goapp/routes/pages/approvals/response.go b/src/goapp/routes/pages/approvals/response.go index 4172d5d..7a66c4c 100644 --- a/src/goapp/routes/pages/approvals/response.go +++ b/src/goapp/routes/pages/approvals/response.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/json" "fmt" - "main/models" + "main/model" session "main/pkg/session" "main/pkg/sql" template "main/pkg/template" @@ -185,7 +185,7 @@ func ProcessResponseHandler(w http.ResponseWriter, r *http.Request) { switch r.Method { case "POST": // Decode payload - var req models.TypRequestProcess + var req model.TypRequestProcess err := json.NewDecoder(r.Body).Decode(&req) if err != nil { diff --git a/src/goapp/service/item/implement.go b/src/goapp/service/item/implement.go new file mode 100644 index 0000000..4ccd4e4 --- /dev/null +++ b/src/goapp/service/item/implement.go @@ -0,0 +1,67 @@ +package item + +import ( + "main/model" + repositoryItem "main/repository/item" + "net/url" + "strconv" +) + +type itemService struct { + repositoryItem repositoryItem.ItemRepository +} + +func NewItemService(repositoryItem repositoryItem.ItemRepository) ItemService { + return &itemService{ + repositoryItem: repositoryItem, + } +} + +func (s *itemService) GetAll(routeVars map[string]string, params url.Values, user string) (model.Response, error) { + itemType, err := strconv.ParseInt(routeVars["type"], 10, 8) + if err != nil { + return model.Response{}, err + } + + itemStatus, err := strconv.ParseInt(routeVars["status"], 10, 8) + if err != nil { + return model.Response{}, err + } + + var result model.Response + + if params.Has("offset") && params.Has("filter") { + filter, _ := strconv.Atoi(params["filter"][0]) + offset, _ := strconv.Atoi(params["offset"][0]) + search := params["search"][0] + requestType := "" + if params["requestType"] != nil { + if params["requestType"][0] != "" { + requestType = params["requestType"][0] + } + } + + organization := "" + if params["organization"] != nil { + if params["organization"][0] != "" { + organization = params["organization"][0] + } + } + + total, err := s.repositoryItem.GetTotalItemsBy(model.ItemType(itemType), model.ItemStatus(itemStatus), requestType, organization, user, search) + if err != nil { + return model.Response{}, err + } + + data, err := s.repositoryItem.GetItemsBy(model.ItemType(itemType), model.ItemStatus(itemStatus), requestType, organization, user, search, offset, filter) + if err != nil { + return model.Response{}, err + } + + result = model.Response{ + Data: data, + Total: total, + } + } + return result, nil +} diff --git a/src/goapp/service/item/interface.go b/src/goapp/service/item/interface.go new file mode 100644 index 0000000..223fef4 --- /dev/null +++ b/src/goapp/service/item/interface.go @@ -0,0 +1,10 @@ +package item + +import ( + "main/model" + "net/url" +) + +type ItemService interface { + GetAll(routeVars map[string]string, params url.Values, user string) (model.Response, error) +}