Skip to content

Commit 56ca74d

Browse files
authored
Merge pull request #168 from Avanade/167-approve-multiple-requests
167 approve multiple requests
2 parents d63d343 + 813bf10 commit 56ca74d

File tree

15 files changed

+1212
-0
lines changed

15 files changed

+1212
-0
lines changed

src/goapp/controller/item/item-controller-dto.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,27 @@ type RespondePageData struct {
2424
ApproveText string
2525
RejectText string
2626
}
27+
28+
type GetItemsByApproverResponse struct {
29+
Data []Item `json:"data"`
30+
Page int `json:"page"`
31+
Filter int `json:"filter"`
32+
Total int `json:"total"`
33+
}
34+
35+
type PostProcessMultipleResponseRequest struct {
36+
Requests []model.ProcessResponseRequest `json:"request"`
37+
}
38+
39+
type Item struct {
40+
Id string `json:"id"`
41+
Subject string `json:"subject"`
42+
Application string `json:"application"`
43+
ApplicationId string `json:"applicationId"`
44+
Module string `json:"module"`
45+
ModuleId string `json:"moduleId"`
46+
RequestedBy string `json:"requestedBy"`
47+
RequestedOn string `json:"requestedOn"`
48+
Approvers []string `json:"approvers"`
49+
Body string `json:"body"`
50+
}

src/goapp/controller/item/item-controller-interface.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@ import "net/http"
44

55
type ItemController interface {
66
GetItems(w http.ResponseWriter, r *http.Request)
7+
GetItemsByApprover(w http.ResponseWriter, r *http.Request)
78
CreateItem(w http.ResponseWriter, r *http.Request)
89
ProcessResponse(w http.ResponseWriter, r *http.Request)
10+
ProcessMultipleResponse(w http.ResponseWriter, r *http.Request)
911
ReassignItem(w http.ResponseWriter, r *http.Request)
1012
}
1113

1214
type ItemPageController interface {
1315
MyRequests(w http.ResponseWriter, r *http.Request)
1416
MyApprovals(w http.ResponseWriter, r *http.Request)
17+
MultipleApprovals(w http.ResponseWriter, r *http.Request)
1518
RespondToItem(w http.ResponseWriter, r *http.Request)
1619
ReassignApproval(w http.ResponseWriter, r *http.Request)
1720
}

src/goapp/controller/item/item-controller.go

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"main/service"
99
"net/http"
1010
"strconv"
11+
"sync"
1112
"time"
1213

1314
"github.com/gorilla/mux"
@@ -102,6 +103,84 @@ func (c *itemController) GetItems(w http.ResponseWriter, r *http.Request) {
102103
json.NewEncoder(w).Encode(result)
103104
}
104105

106+
func (c *itemController) GetItemsByApprover(w http.ResponseWriter, r *http.Request) {
107+
// Get all items
108+
var filterOptions model.FilterOptions
109+
110+
user, err := c.Authenticator.GetAuthenticatedUser(r)
111+
if err != nil {
112+
http.Error(w, err.Error(), http.StatusInternalServerError)
113+
return
114+
}
115+
116+
params := r.URL.Query()
117+
118+
var requestType string
119+
if params.Has("requestType") {
120+
requestType = params["requestType"][0]
121+
}
122+
123+
var organization string
124+
if params.Has("organization") {
125+
organization = params["organization"][0]
126+
}
127+
128+
filterOptions.Page = 0 // Default page is 1 which is 0 in the database
129+
if params.Has("page") {
130+
filterOptions.Page, err = strconv.Atoi(params["page"][0])
131+
if err != nil {
132+
http.Error(w, err.Error(), http.StatusInternalServerError)
133+
return
134+
}
135+
filterOptions.Page = filterOptions.Page - 1
136+
}
137+
138+
if params.Has("filter") {
139+
filterOptions.Filter, err = strconv.Atoi(params["filter"][0])
140+
if err != nil {
141+
http.Error(w, err.Error(), http.StatusInternalServerError)
142+
return
143+
}
144+
} else {
145+
filterOptions.Filter = 50
146+
}
147+
148+
result, total, err := c.Service.Item.GetByApprover(user.Email, requestType, organization, filterOptions)
149+
if err != nil {
150+
http.Error(w, err.Error(), http.StatusInternalServerError)
151+
return
152+
}
153+
154+
var response GetItemsByApproverResponse
155+
for _, item := range result {
156+
itemResponse := Item{
157+
Id: item.Id,
158+
Subject: item.Subject,
159+
Application: item.Application,
160+
ApplicationId: item.ApplicationId,
161+
Module: item.Module,
162+
ModuleId: item.ModuleId,
163+
RequestedBy: item.RequestedBy,
164+
RequestedOn: item.Created,
165+
Approvers: item.Approvers,
166+
Body: item.Body,
167+
}
168+
169+
response.Data = append(response.Data, itemResponse)
170+
}
171+
if len(response.Data) == 0 {
172+
response.Data = []Item{}
173+
}
174+
response.Page = filterOptions.Page + 1
175+
response.Filter = filterOptions.Filter
176+
response.Total = total
177+
178+
// Return the result
179+
w.Header().Set("Content-Type", "application/json")
180+
w.WriteHeader(http.StatusOK)
181+
json.NewEncoder(w).Encode(response)
182+
}
183+
105184
func (c *itemController) CreateItem(w http.ResponseWriter, r *http.Request) {
106185
// Decode payload
107186
var req model.ItemInsertRequest
@@ -204,6 +283,78 @@ func (c *itemController) ProcessResponse(w http.ResponseWriter, r *http.Request)
204283
w.WriteHeader(http.StatusOK)
205284
}
206285

286+
func (c *itemController) ProcessMultipleResponse(w http.ResponseWriter, r *http.Request) {
287+
// Decode payload
288+
var req PostProcessMultipleResponseRequest
289+
err := json.NewDecoder(r.Body).Decode(&req)
290+
if err != nil {
291+
http.Error(w, err.Error(), http.StatusBadRequest)
292+
return
293+
}
294+
295+
user, err := c.Authenticator.GetAuthenticatedUser(r)
296+
if err != nil {
297+
http.Error(w, err.Error(), http.StatusInternalServerError)
298+
return
299+
}
300+
301+
vars := mux.Vars(r)
302+
response := vars["response"]
303+
304+
var isApproved string
305+
if response == "approve" {
306+
isApproved = "true"
307+
} else if response == "reject" {
308+
isApproved = "false"
309+
} else {
310+
http.Error(w, "Invalid response", http.StatusBadRequest)
311+
return
312+
}
313+
314+
for index, _ := range req.Requests {
315+
req.Requests[index].ApproverEmail = user.Email
316+
req.Requests[index].IsApproved = isApproved
317+
}
318+
319+
var wg sync.WaitGroup
320+
concurrencyLimit := make(chan struct{}, 50) // Limit to 50 concurrent goroutines
321+
322+
// Validate All Requests
323+
for _, request := range req.Requests {
324+
wg.Add(1)
325+
concurrencyLimit <- struct{}{} // Acquire a slot
326+
327+
go func() {
328+
defer wg.Done()
329+
defer func() { <-concurrencyLimit }() // Release the slot
330+
331+
// Validate payload
332+
valid, err := c.Service.Item.ValidateItem(request)
333+
if err != nil {
334+
http.Error(w, err.Error(), http.StatusInternalServerError)
335+
return
336+
}
337+
338+
if !valid {
339+
http.Error(w, "Invalid request", http.StatusBadRequest)
340+
return
341+
}
342+
343+
// Update item response
344+
err = c.Service.Item.UpdateItemResponse(request)
345+
if err != nil {
346+
http.Error(w, err.Error(), http.StatusInternalServerError)
347+
return
348+
}
349+
350+
// Post callback
351+
c.postCallback(request.ItemId)
352+
}()
353+
}
354+
355+
w.WriteHeader(http.StatusOK)
356+
}
357+
207358
func (c *itemController) ReassignItem(w http.ResponseWriter, r *http.Request) {
208359
// Get user info
209360
user, err := c.Authenticator.GetAuthenticatedUser(r)

src/goapp/controller/item/item-page-controller.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,30 @@ func (c *itemPageController) ReassignApproval(w http.ResponseWriter, r *http.Req
214214
}
215215
}
216216
}
217+
218+
func (c *itemPageController) MultipleApprovals(w http.ResponseWriter, r *http.Request) {
219+
user, err := c.Service.Authenticator.GetAuthenticatedUser(r)
220+
if err != nil {
221+
http.Error(w, err.Error(), http.StatusInternalServerError)
222+
return
223+
}
224+
225+
application, err := c.Service.Application.GetApplicationById(c.CommunityPortalAppId)
226+
if err != nil {
227+
http.Error(w, err.Error(), http.StatusInternalServerError)
228+
return
229+
}
230+
231+
b, err := json.Marshal(application)
232+
if err != nil {
233+
fmt.Println(err)
234+
return
235+
}
236+
237+
t, d := c.Service.Template.UseTemplate("multiple-approvals", r.URL.Path, *user, string(b))
238+
239+
err = t.Execute(w, d)
240+
if err != nil {
241+
http.Error(w, err.Error(), http.StatusInternalServerError)
242+
}
243+
}

src/goapp/model/common.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package model
2+
3+
type FilterOptions struct {
4+
Filter int
5+
Page int
6+
Search string
7+
Orderby string
8+
Ordertype string
9+
}

src/goapp/model/item.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ package model
33
type Item struct {
44
Id string `json:"id"`
55
Application string `json:"application"`
6+
ApplicationId string `json:"applicationId"`
67
ApproverRemarks string `json:"approverRemarks"`
78
Body string `json:"body"`
89
Created string `json:"created"`
910
DateResponded string `json:"dateResponded"`
1011
DateSent string `json:"dateSent"`
1112
IsApproved bool `json:"isApproved"`
1213
Module string `json:"module"`
14+
ModuleId string `json:"moduleId"`
1315
Subject string `json:"subject"`
1416
ApproveText string `json:"approveText"`
1517
CallbackUrl string `json:"callbackUrl"`

0 commit comments

Comments
 (0)