Skip to content

Commit

Permalink
my request refactor
Browse files Browse the repository at this point in the history
Signed-off-by: Ismael Ibuan <[email protected]>
iibuan committed Oct 7, 2024

Verified

This commit was signed with the committer’s verified signature.
agnesLeroy Agnès Leroy
1 parent 00a18ae commit c5607be
Showing 26 changed files with 337 additions and 130 deletions.
3 changes: 2 additions & 1 deletion .bicep/webapp/parameters.json
Original file line number Diff line number Diff line change
@@ -41,7 +41,8 @@
"EMAIL_CLIENT_SECRET" : "",
"EMAIL_USER_ID" : "",
"LINK_FOOTERS": "",
"ORGANIZATION_NAME": ""
"ORGANIZATION_NAME": "",
"COMMUNITY_PORTAL_APP_ID": ""
}
}
}
1 change: 1 addition & 0 deletions .github/workflows/setup-appservice-resource.yml
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@ jobs:
parameters.appServiceSettings.value.DOCKER_REGISTRY_SERVER_USERNAME : ${{ secrets.CONTAINER_REGISTRY_SERVER_USERNAME }}
parameters.appServiceSettings.value.DOCKER_REGISTRY_SERVER_PASSWORD : ${{ secrets.CONTAINER_REGISTRY_SERVER_PASSWORD }}
parameters.appServiceSettings.value.APPROVALSYSTEMDB_CONNECTION_STRING : ${{ secrets.DATABASE_CONNECTION_STRING }}
parameters.appServiceSettings.value.COMMUNITY_PORTAL_APP_ID : ${{ vars.COMMUNITY_PORTAL_APP_ID }}

- name: Deploy App Service Plan and Web App
uses: azure/arm-deploy@v1
3 changes: 2 additions & 1 deletion src/goapp/.env.template
Original file line number Diff line number Diff line change
@@ -16,4 +16,5 @@ EMAIL_CLIENT_SECRET=<Client Secret>
EMAIL_ENABLED=<Email enabled. default: false>
EMAIL_USER_ID=<Email user id>
LINK_FOOTERS=""
ORGANIZATION_NAME=""
ORGANIZATION_NAME=""
COMMUNITY_PORTAL_APP_ID=""
3 changes: 3 additions & 0 deletions src/goapp/config/config.go
Original file line number Diff line number Diff line change
@@ -17,4 +17,7 @@ type ConfigManager interface {
GetTenantID() string
GetClientID() string
GetClientSecret() string
GetLinkFooters() string
GetOrganizationName() string
GetCommunityPortalAppId() string
}
12 changes: 12 additions & 0 deletions src/goapp/config/env-config.go
Original file line number Diff line number Diff line change
@@ -66,3 +66,15 @@ func (ecm *envConfigManager) GetClientID() string {
func (ecm *envConfigManager) GetClientSecret() string {
return os.Getenv("CLIENT_SECRET")
}

func (ecm *envConfigManager) GetLinkFooters() string {
return os.Getenv("LINK_FOOTERS")
}

func (ecm *envConfigManager) GetOrganizationName() string {
return os.Getenv("ORGANIZATION_NAME")
}

func (ecm *envConfigManager) GetCommunityPortalAppId() string {
return os.Getenv("COMMUNITY_PORTAL_APP_ID")
}
10 changes: 10 additions & 0 deletions src/goapp/controller/controller.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package controller

import (
"main/config"
cApplicationModule "main/controller/app-module"
cItem "main/controller/item"
cUser "main/controller/user"
@@ -9,6 +10,7 @@ import (

type Controller struct {
Item cItem.ItemController
ItemPage cItem.ItemPageController
ApplicationModule cApplicationModule.ApplicationModuleController
User cUser.UserController
}
@@ -42,3 +44,11 @@ func NewUserController(svc *service.Service) ControllerOptionFunc {
c.User = cUser.NewUserController(svc)
}
}

// PAGES

func NewItemPageController(svc *service.Service, conf config.ConfigManager) ControllerOptionFunc {
return func(c *Controller) {
c.ItemPage = cItem.NewItemPageController(svc, conf)
}
}
4 changes: 4 additions & 0 deletions src/goapp/controller/item/item-controller-interface.go
Original file line number Diff line number Diff line change
@@ -8,3 +8,7 @@ type ItemController interface {
ProcessResponse(w http.ResponseWriter, r *http.Request)
ReassignItem(w http.ResponseWriter, r *http.Request)
}

type ItemPageController interface {
MyRequests(w http.ResponseWriter, r *http.Request)
}
62 changes: 62 additions & 0 deletions src/goapp/controller/item/item-page-controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package item

import (
"encoding/json"
"fmt"
"main/config"
"main/model"
"main/pkg/session"
"main/service"
"net/http"
)

type itemPageController struct {
*service.Service
CommunityPortalAppId string
}

func NewItemPageController(s *service.Service, conf config.ConfigManager) ItemPageController {
return &itemPageController{
Service: s,
CommunityPortalAppId: conf.GetCommunityPortalAppId(),
}
}

func (c *itemPageController) MyRequests(w http.ResponseWriter, r *http.Request) {
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, "Error getting user data", http.StatusInternalServerError)
return
}
user := model.AzureUser{
Name: profile["name"].(string),
Email: profile["preferred_username"].(string),
}

application, err := c.Service.Application.GetApplicationById(c.CommunityPortalAppId)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

b, err := json.Marshal(application)
if err != nil {
fmt.Println(err)
return
}

t, d := c.Service.Template.UseTemplate("myrequests", r.URL.Path, user, string(b))

err = t.Execute(w, d)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
103 changes: 12 additions & 91 deletions src/goapp/infrastructure/database/database.go
Original file line number Diff line number Diff line change
@@ -11,7 +11,6 @@ import (

type Database struct {
connString string
db *sql.DB
}

func NewDatabase(config config.ConfigManager) Database {
@@ -22,62 +21,54 @@ func NewDatabase(config config.ConfigManager) Database {
}
}

func (d *Database) Connect() error {
func (d *Database) Connect() (*sql.DB, error) {
conn, err := sql.Open("sqlserver", d.connString)
if err != nil {
return err
return nil, err
}

d.db = conn
return nil
}

func (d *Database) Disconnect() error {
if d.db != nil {
return d.db.Close()
}
return nil
return conn, nil
}

func (d *Database) Query(query string, args ...any) (*sql.Rows, error) {
err := d.Connect()
con, err := d.Connect()
if err != nil {
return nil, err
}
defer d.Disconnect()
defer con.Close()

ctx := context.Background()
rows, err := d.db.QueryContext(ctx, query, args...)
rows, err := con.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()
con, err := d.Connect()
if err != nil {
return nil, err
}
defer d.Disconnect()
defer con.Close()

ctx := context.Background()
row := d.db.QueryRowContext(ctx, query, args...)
row := con.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()
con, err := d.Connect()
if err != nil {
return err
}
defer d.Disconnect()
defer con.Close()

ctx := context.Background()
_, err = d.db.ExecContext(ctx, query, args...)
_, err = con.ExecContext(ctx, query, args...)
if err != nil {
return err
}
@@ -112,73 +103,3 @@ func (d *Database) RowsToMap(rows *sql.Rows) ([]map[string]interface{}, error) {

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
}
10 changes: 7 additions & 3 deletions src/goapp/init.go
Original file line number Diff line number Diff line change
@@ -15,23 +15,27 @@ var (
db database.Database = database.NewDatabase(conf)

repo = r.NewRepository(
r.NewApplicationModule(db),
r.NewItem(db),
r.NewApprovalRequestApprover(db),
r.NewApplication(&db),
r.NewApplicationModule(&db),
r.NewItem(&db),
r.NewApprovalRequestApprover(&db),
)

svc = s.NewService(
s.NewApplicationService(repo),
s.NewApplicationModuleService(repo),
s.NewItemService(repo, conf),
s.NewEmailService(conf),
s.NewApprovalRequestApproverService(repo),
s.NewMsGraphService(conf),
s.NewTemplateService(conf),
)

ctrl = c.NewController(
c.NewItemController(svc),
c.NewApplicationModuleController(svc),
c.NewUserController(svc),
c.NewItemPageController(svc, conf),
)

httpRouter router.Router = router.NewMuxRouter()
8 changes: 8 additions & 0 deletions src/goapp/model/application.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package model

type Application struct {
Id string `json:"id"`
Name string `json:"name"`
ExportUrl string `json:"exportUrl"`
OrganizationTypeUrl string `json:"organizationTypeUrl"`
}
16 changes: 8 additions & 8 deletions src/goapp/model/data.go → src/goapp/model/template.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package model

type TypPageData struct {
Header interface{}
Profile interface{}
type MasterPageData struct {
Header Headers
Profile AzureUser
Content interface{}
Footers []Footer
OrganizationName string
@@ -13,20 +13,20 @@ type Footer struct {
Url string
}

type TypHeaders struct {
Menu []TypMenu
ExternalLinks []TypMenu
type Headers struct {
Menu []Menu
ExternalLinks []Menu
Page string
}

type TypMenu struct {
type Menu struct {
Name string
Url string
IconPath string
UrlPath string
}

type TypAzureUser struct {
type AzureUser struct {
Name string `json:"name"`
Email string `json:"preferred_username"`
}
23 changes: 11 additions & 12 deletions src/goapp/pkg/template/template.go
Original file line number Diff line number Diff line change
@@ -20,18 +20,17 @@ func UseTemplate(w *http.ResponseWriter, r *http.Request, page string, pageData
}
profile := sessionaz.Values["profile"]

if profile == nil {
profile = map[string]interface{}{
"name": "",
"preferred_username": "",
}
user := model.AzureUser{}
if profile != nil {
user.Name = profile.(map[string]interface{})["name"].(string)
user.Email = profile.(map[string]interface{})["preferred_username"].(string)
}

// Data on master page
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)}
var menu []model.Menu
menu = append(menu, model.Menu{Name: "My Requests", Url: "/", IconPath: "/public/icons/projects.svg"})
menu = append(menu, model.Menu{Name: "My Approvals", Url: "/myapprovals", IconPath: "/public/icons/approvals.svg"})
masterPageData := model.Headers{Menu: menu, Page: getUrlPath(r.URL.Path)}

//Footers
var footers []model.Footer
@@ -42,9 +41,9 @@ func UseTemplate(w *http.ResponseWriter, r *http.Request, page string, pageData
footers = append(footers, model.Footer{Text: f[0], Url: f[1]})
}

data := model.TypPageData{
data := model.MasterPageData{
Header: masterPageData,
Profile: profile,
Profile: user,
Content: pageData,
Footers: footers,
OrganizationName: os.Getenv("ORGANIZATION_NAME"),
@@ -53,7 +52,7 @@ func UseTemplate(w *http.ResponseWriter, r *http.Request, page string, pageData
tmpl := template.Must(
template.ParseFiles("templates/master.html", "templates/buttons.html",
fmt.Sprintf("templates/%v.html", page)))
(*w).WriteHeader(http.StatusBadRequest)

return tmpl.Execute(*w, data)
}

4 changes: 2 additions & 2 deletions src/goapp/repository/app-module/app-module-repository.go
Original file line number Diff line number Diff line change
@@ -7,10 +7,10 @@ import (
)

type applicationModuleRepository struct {
db.Database
*db.Database
}

func NewApplicationModuleRepository(db db.Database) ApplicationModuleRepository {
func NewApplicationModuleRepository(db *db.Database) ApplicationModuleRepository {
return &applicationModuleRepository{
Database: db,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package application

import (
"main/model"
)

type ApplicationRepository interface {
GetApplicationById(id string) (*model.Application, error)
}
44 changes: 44 additions & 0 deletions src/goapp/repository/application/application-repository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package application

import (
"database/sql"
db "main/infrastructure/database"
"main/model"
)

type applicationRepository struct {
*db.Database
}

func NewApplicationRepository(db *db.Database) ApplicationRepository {
return &applicationRepository{
Database: db,
}
}

func (r *applicationRepository) GetApplicationById(id string) (*model.Application, error) {
var application model.Application
rowApplication, err := r.Query("PR_Applications_Select_ById", sql.Named("Id", id))
if err != nil {
return nil, err
}

applications, err := r.RowsToMap(rowApplication)
if err != nil {
return nil, err
}

if len(applications) == 0 {
return nil, nil
} else {
application.Id = applications[0]["Id"].(string)
application.Name = applications[0]["Name"].(string)
if applications[0]["ExportUrl"] != nil {
application.ExportUrl = applications[0]["ExportUrl"].(string)
}
if applications[0]["OrganizationTypeUrl"] != nil {
application.OrganizationTypeUrl = applications[0]["OrganizationTypeUrl"].(string)
}
}
return &application, nil
}
Original file line number Diff line number Diff line change
@@ -7,10 +7,10 @@ import (
)

type approvalRequestApproverRepository struct {
db.Database
*db.Database
}

func NewApprovalRequestApproverRepository(db db.Database) ApprovalRequestApproverRepository {
func NewApprovalRequestApproverRepository(db *db.Database) ApprovalRequestApproverRepository {
return &approvalRequestApproverRepository{
Database: db,
}
4 changes: 2 additions & 2 deletions src/goapp/repository/item/item-repository.go
Original file line number Diff line number Diff line change
@@ -10,10 +10,10 @@ import (
)

type itemRepository struct {
db.Database
*db.Database
}

func NewItemRepository(db db.Database) ItemRepository {
func NewItemRepository(db *db.Database) ItemRepository {
return &itemRepository{
Database: db,
}
16 changes: 12 additions & 4 deletions src/goapp/repository/repository.go
Original file line number Diff line number Diff line change
@@ -3,14 +3,16 @@ package repository
import (
"main/infrastructure/database"
rAppModule "main/repository/app-module"
rApplication "main/repository/application"
rApprovalRequestApprover "main/repository/approval-request-approver"
rItem "main/repository/item"
)

type Repository struct {
Application rApplication.ApplicationRepository
ApplicationModule rAppModule.ApplicationModuleRepository
Item rItem.ItemRepository
ApprovalRequestApprover rApprovalRequestApprover.ApprovalRequestApproverRepository
Item rItem.ItemRepository
}

type RepositoryOptionFunc func(*Repository)
@@ -25,19 +27,25 @@ func NewRepository(opts ...RepositoryOptionFunc) *Repository {
return repo
}

func NewApplicationModule(db database.Database) RepositoryOptionFunc {
func NewApplication(db *database.Database) RepositoryOptionFunc {
return func(r *Repository) {
r.Application = rApplication.NewApplicationRepository(db)
}
}

func NewApplicationModule(db *database.Database) RepositoryOptionFunc {
return func(r *Repository) {
r.ApplicationModule = rAppModule.NewApplicationModuleRepository(db)
}
}

func NewItem(db database.Database) RepositoryOptionFunc {
func NewItem(db *database.Database) RepositoryOptionFunc {
return func(r *Repository) {
r.Item = rItem.NewItemRepository(db)
}
}

func NewApprovalRequestApprover(db database.Database) RepositoryOptionFunc {
func NewApprovalRequestApprover(db *database.Database) RepositoryOptionFunc {
return func(r *Repository) {
r.ApprovalRequestApprover = rApprovalRequestApprover.NewApprovalRequestApproverRepository(db)
}
2 changes: 1 addition & 1 deletion src/goapp/routes.go
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ import (
)

func setPageRoutes() {
httpRouter.GET("/", m.Chain(rtApprovals.MyRequestsHandler, m.AzureAuth()))
httpRouter.GET("/", m.Chain(ctrl.ItemPage.MyRequests, m.AzureAuth()))
httpRouter.GET("/myapprovals", m.Chain(rtApprovals.MyApprovalsHandler, m.AzureAuth()))
httpRouter.GET("/response/{appGuid}/{appModuleGuid}/{itemGuid}/{isApproved}", m.Chain(rtApprovals.ResponseHandler, m.AzureAuth()))
httpRouter.GET("/responsereassigned/{appGuid}/{appModuleGuid}/{itemGuid}/{isApproved}/{ApproveText}/{RejectText}", m.Chain(rtApprovals.ResponseReassignedeHandler, m.AzureAuth()))
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package application

import (
"main/model"
)

type ApplicationService interface {
GetApplicationById(id string) (*model.Application, error)
}
24 changes: 24 additions & 0 deletions src/goapp/service/application/application-service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package application

import (
"main/model"
"main/repository"
)

type applicationService struct {
Repository *repository.Repository
}

func NewApplicationService(r *repository.Repository) ApplicationService {
return &applicationService{
Repository: r,
}
}

func (s *applicationService) GetApplicationById(id string) (*model.Application, error) {
application, err := s.Repository.Application.GetApplicationById(id)
if err != nil {
return nil, err
}
return application, nil
}
16 changes: 16 additions & 0 deletions src/goapp/service/service.go
Original file line number Diff line number Diff line change
@@ -4,18 +4,22 @@ import (
"main/config"
"main/repository"
sApplicationModule "main/service/app-module"
sApplication "main/service/application"
sApprovalRequestApprover "main/service/approval-request-approver"
sEmail "main/service/email"
sItem "main/service/item"
sMsGraph "main/service/msgraph"
sTemplate "main/service/template"
)

type Service struct {
Application sApplication.ApplicationService
ApplicationModule sApplicationModule.ApplicationModuleService
Item sItem.ItemService
Email sEmail.EmailService
ApprovalRequestApprover sApprovalRequestApprover.ApprovalRequestApproverService
MsGraph sMsGraph.MsGraphService
Template sTemplate.TemplateService
}

type ServiceOptionFunc func(*Service)
@@ -30,6 +34,12 @@ func NewService(opts ...ServiceOptionFunc) *Service {
return service
}

func NewApplicationService(repo *repository.Repository) ServiceOptionFunc {
return func(s *Service) {
s.Application = sApplication.NewApplicationService(repo)
}
}

func NewApplicationModuleService(repo *repository.Repository) ServiceOptionFunc {
return func(s *Service) {
s.ApplicationModule = sApplicationModule.NewApplicationModuleService(repo)
@@ -59,3 +69,9 @@ func NewMsGraphService(conf config.ConfigManager) ServiceOptionFunc {
s.MsGraph = sMsGraph.NewMsGraphService(conf)
}
}

func NewTemplateService(conf config.ConfigManager) ServiceOptionFunc {
return func(s *Service) {
s.Template = sTemplate.NewTemplateService(conf)
}
}
10 changes: 10 additions & 0 deletions src/goapp/service/template/template-service-interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package template

import (
"main/model"
"text/template"
)

type TemplateService interface {
UseTemplate(page, path string, user model.AzureUser, pageData interface{}) (*template.Template, *model.MasterPageData)
}
61 changes: 61 additions & 0 deletions src/goapp/service/template/template-service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package template

import (
"fmt"
"main/config"
"main/model"
"strings"
"text/template"
)

type templateService struct {
LinkFooters string
OrganizationName string
}

func NewTemplateService(config config.ConfigManager) TemplateService {
return &templateService{
LinkFooters: config.GetLinkFooters(),
OrganizationName: config.GetOrganizationName(),
}
}

func (t *templateService) UseTemplate(page, path string, user model.AzureUser, pageData interface{}) (*template.Template, *model.MasterPageData) {
// Data on master page
var menu []model.Menu
menu = append(menu, model.Menu{Name: "My Requests", Url: "/", IconPath: "/public/icons/projects.svg"})
menu = append(menu, model.Menu{Name: "My Approvals", Url: "/myapprovals", IconPath: "/public/icons/approvals.svg"})
masterPageData := model.Headers{Menu: menu, Page: getUrlPath(path)}

//Footers
var footers []model.Footer
footerString := t.LinkFooters
res := strings.Split(footerString, ";")
for _, footer := range res {
f := strings.Split(footer, ">")
footers = append(footers, model.Footer{Text: f[0], Url: f[1]})
}

data := model.MasterPageData{
Header: masterPageData,
Profile: user,
Content: pageData,
Footers: footers,
OrganizationName: t.OrganizationName,
}

tmpl := template.Must(
template.ParseFiles("templates/master.html", "templates/buttons.html",
fmt.Sprintf("templates/%v.html", page)))

return tmpl, &data
}

func getUrlPath(path string) string {
p := strings.Split(path, "/")
if p[1] == "" {
return "/"
} else {
return fmt.Sprintf("/%s", p[1])
}
}
6 changes: 3 additions & 3 deletions src/goapp/templates/master.html
Original file line number Diff line number Diff line change
@@ -158,7 +158,7 @@
<p
class="text-sm font-medium text-gray-700 group-hover:text-gray-900"
>
{{ .Profile.name }}
{{ .Profile.Name }}
</p>
<p
class="text-xs font-medium text-gray-500 group-hover:text-gray-700"
@@ -254,8 +254,8 @@
function masterData(){
return {
profile:{
name:'{{.Profile.name}}',
username:'{{.Profile.preferred_username}}'
name:'{{.Profile.Name}}',
username:'{{.Profile.Email}}'
},
get profileDomain() {
var domain = this.profile.username.split('@')[1]

0 comments on commit c5607be

Please sign in to comment.