Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.

Commit f243811

Browse files
author
Noah Hanjun Lee
authored
Fix to block requesting the approval to the deployer. (#150)
* Fix to block request the approval to the deployer * Fix not to display the deployer in candidates of approval
1 parent 023cf3d commit f243811

File tree

10 files changed

+122
-11
lines changed

10 files changed

+122
-11
lines changed

internal/server/api/v1/repos/approval.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,15 +153,21 @@ func (r *Repo) CreateApproval(c *gin.Context) {
153153
}
154154

155155
if _, err := r.i.FindPermOfRepo(ctx, re, user); ent.IsNotFound(err) {
156-
r.log.Warn("The permission is not found.", zap.Error(err))
157-
gb.ErrorResponse(c, http.StatusUnprocessableEntity, "There is no permssion for the repository.")
156+
r.log.Warn("The approver has no permission for the repository.", zap.Error(err))
157+
gb.ErrorResponse(c, http.StatusUnprocessableEntity, "The approver has no permission for the repository.")
158158
return
159159
} else if err != nil {
160160
r.log.Error("It has failed to get the perm.", zap.Error(err))
161161
gb.ErrorResponse(c, http.StatusInternalServerError, "It has failed to get the perm.")
162162
return
163163
}
164164

165+
if d.Edges.User != nil && user.ID == d.Edges.User.ID {
166+
r.log.Warn("The deployer can not be the approver.", zap.Error(err))
167+
gb.ErrorResponse(c, http.StatusUnprocessableEntity, "The deployer can not be the approver.")
168+
return
169+
}
170+
165171
ap, err := r.i.CreateApproval(ctx, &ent.Approval{
166172
UserID: user.ID,
167173
DeploymentID: d.ID,
@@ -192,7 +198,7 @@ func (r *Repo) CreateApproval(c *gin.Context) {
192198
gb.Response(c, http.StatusCreated, ap)
193199
}
194200

195-
func (r *Repo) UpdateApproval(c *gin.Context) {
201+
func (r *Repo) UpdateMyApproval(c *gin.Context) {
196202
ctx := c.Request.Context()
197203

198204
var (

internal/server/api/v1/repos/approval_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,66 @@ var (
2121
)
2222

2323
func TestRepo_CreateApproval(t *testing.T) {
24+
t.Run("Validate to request the approval to the deployer.", func(t *testing.T) {
25+
input := struct {
26+
number int
27+
payload *approvalPostPayload
28+
}{
29+
number: 7,
30+
payload: &approvalPostPayload{
31+
UserID: 4,
32+
},
33+
}
34+
35+
ctrl := gomock.NewController(t)
36+
m := mock.NewMockInteractor(ctrl)
37+
38+
t.Log("MOCK - Find the deployment by ID.")
39+
m.
40+
EXPECT().
41+
FindDeploymentOfRepoByNumber(ctx, any, input.number).
42+
Return(&ent.Deployment{
43+
ID: input.number,
44+
Edges: ent.DeploymentEdges{
45+
User: &ent.User{
46+
ID: input.payload.UserID,
47+
},
48+
},
49+
}, nil)
50+
51+
t.Log("MOCK - Find the user, and check the permission.")
52+
m.
53+
EXPECT().
54+
FindUserByID(ctx, input.payload.UserID).
55+
Return(&ent.User{
56+
ID: input.payload.UserID,
57+
}, nil)
58+
59+
m.
60+
EXPECT().
61+
FindPermOfRepo(ctx, any, &ent.User{
62+
ID: input.payload.UserID,
63+
}).
64+
Return(&ent.Perm{}, nil)
65+
66+
gin.SetMode(gin.ReleaseMode)
67+
68+
r := NewRepo(RepoConfig{}, m)
69+
router := gin.New()
70+
router.POST("/deployments/:number/approvals", func(c *gin.Context) {
71+
c.Set(KeyRepo, &ent.Repo{})
72+
}, r.CreateApproval)
73+
74+
body, _ := json.Marshal(input.payload)
75+
req, _ := http.NewRequest("POST", fmt.Sprintf("/deployments/%d/approvals", input.number), bytes.NewBuffer(body))
76+
77+
w := httptest.NewRecorder()
78+
router.ServeHTTP(w, req)
79+
80+
if w.Code != http.StatusUnprocessableEntity {
81+
t.Fatalf("Code != %d, wanted %d", w.Code, http.StatusOK)
82+
}
83+
})
2484

2585
t.Run("Create a new approval.", func(t *testing.T) {
2686
input := struct {

internal/server/router.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ func NewRouter(c *RouterConfig) *gin.Engine {
141141
repov1.GET("/:namespace/:name/deployments/:number/approvals", rm.RepoReadPerm(), r.ListApprovals)
142142
repov1.POST("/:namespace/:name/deployments/:number/approvals", rm.RepoReadPerm(), r.CreateApproval)
143143
repov1.GET("/:namespace/:name/deployments/:number/approval", rm.RepoReadPerm(), r.GetMyApproval)
144-
repov1.PATCH("/:namespace/:name/deployments/:number/approval", rm.RepoReadPerm(), r.UpdateApproval)
144+
repov1.PATCH("/:namespace/:name/deployments/:number/approval", rm.RepoReadPerm(), r.UpdateMyApproval)
145145
repov1.GET("/:namespace/:name/approvals/:aid", rm.RepoReadPerm(), r.GetApproval)
146146
repov1.DELETE("/:namespace/:name/approvals/:aid", rm.RepoReadPerm(), r.DeleteApproval)
147147
repov1.GET("/:namespace/:name/locks", rm.RepoReadPerm(), r.ListLocks)

ui/public/logo192.png

5.13 KB
Loading

ui/src/redux/deployment.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ export const deploymentSlice = createSlice({
268268
state.candidates = []
269269
})
270270
.addCase(searchCandidates.fulfilled, (state, action) => {
271-
state.candidates = action.payload
271+
state.candidates = action.payload.filter(candidate => candidate.id !== state.deployment?.deployer?.id)
272272
})
273273
.addCase(createApproval.fulfilled, (state, action) => {
274274
state.approvals.push(action.payload)

ui/src/redux/repoDeploy.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
getTag,
3131
createDeployment,
3232
createApproval,
33+
getMe,
3334
} from '../apis'
3435

3536
// fetch all at the first page.
@@ -61,6 +62,7 @@ interface RepoDeployState {
6162
*/
6263
approvers: User[]
6364
candidates: User[]
65+
user?: User
6466
deploying: RequestStatus
6567
deployId: string
6668
}
@@ -253,6 +255,18 @@ export const searchCandidates = createAsyncThunk<User[], string, { state: {repoD
253255
}
254256
)
255257

258+
export const fetchUser = createAsyncThunk<User, void, { state: {repoDeploy: RepoDeployState }}>(
259+
"repoDeploy/fetchUser",
260+
async (_, { rejectWithValue }) => {
261+
try {
262+
const user = await getMe()
263+
return user
264+
} catch(e) {
265+
return rejectWithValue(e)
266+
}
267+
}
268+
)
269+
256270
export const deploy = createAsyncThunk<void, void, { state: {repoDeploy: RepoDeployState}}> (
257271
"repoDeploy/deploy",
258272
async (_ , { getState, rejectWithValue, requestId }) => {
@@ -400,7 +414,10 @@ export const repoDeploySlice = createSlice({
400414
state.candidates = []
401415
})
402416
.addCase(searchCandidates.fulfilled, (state, action) => {
403-
state.candidates = action.payload
417+
state.candidates = action.payload.filter(candidate => (candidate.id !== state.user?.id))
418+
})
419+
.addCase(fetchUser.fulfilled, (state, action) => {
420+
state.user = action.payload
404421
})
405422
.addCase(deploy.pending, (state, action) => {
406423
if (state.deploying === RequestStatus.Idle) {

ui/src/redux/repoRollback.tsx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import {
66
listDeployments,
77
rollbackDeployment,
88
createApproval,
9-
listPerms
9+
listPerms,
10+
getMe
1011
} from "../apis"
1112
import {
1213
User,
@@ -39,6 +40,7 @@ interface RepoRollbackState {
3940
*/
4041
approvers: User[]
4142
candidates: User[]
43+
user?: User
4244
deployId: string
4345
deploying: RequestStatus
4446
}
@@ -100,6 +102,18 @@ export const searchCandidates = createAsyncThunk<User[], string, { state: {repoR
100102
}
101103
)
102104

105+
export const fetchUser = createAsyncThunk<User, void, { state: {repoRollback: RepoRollbackState }}>(
106+
"repoRollback/fetchUser",
107+
async (_, { rejectWithValue }) => {
108+
try {
109+
const user = await getMe()
110+
return user
111+
} catch(e) {
112+
return rejectWithValue(e)
113+
}
114+
}
115+
)
116+
103117
export const rollback = createAsyncThunk<void, void, { state: {repoRollback: RepoRollbackState}}> (
104118
"repoRollback/deploy",
105119
async (_ , { getState, rejectWithValue, requestId }) => {
@@ -196,7 +210,10 @@ export const repoRollbackSlice = createSlice({
196210
state.candidates = []
197211
})
198212
.addCase(searchCandidates.fulfilled, (state, action) => {
199-
state.candidates = action.payload
213+
state.candidates = action.payload.filter(candidate => (candidate.id !== state.user?.id))
214+
})
215+
.addCase(fetchUser.fulfilled, (state, action) => {
216+
state.user = action.payload
200217
})
201218
.addCase(rollback.pending, (state, action) => {
202219
if (state.deploying === RequestStatus.Idle) {

ui/src/views/Deployment.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,11 @@ export default function DeploymentView(): JSX.Element {
5656
const f = async () => {
5757
await dispatch(slice.actions.init({namespace, name, number: parseInt(number, 10)}))
5858
await dispatch(fetchDeployment())
59-
await dispatch(slice.actions.setDisplay(true))
60-
await dispatch(fetchDeploymentChanges())
6159
await dispatch(fetchApprovals())
6260
await dispatch(fetchMyApproval())
61+
await dispatch(slice.actions.setDisplay(true))
62+
await dispatch(fetchDeploymentChanges())
63+
await dispatch(searchCandidates(""))
6364
}
6465
f()
6566

ui/src/views/RepoDeploy.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
checkTag,
2020
addTagManually,
2121
searchCandidates,
22+
fetchUser,
2223
deploy} from "../redux/repoDeploy"
2324

2425
import DeployForm, {Option} from "../components/DeployForm"
@@ -55,6 +56,7 @@ export default function RepoDeploy(): JSX.Element {
5556
await dispatch(actions.setDisplay(true))
5657
await dispatch(fetchBranches())
5758
await dispatch(fetchTags())
59+
await dispatch(fetchUser())
5860
await dispatch(searchCandidates(""))
5961
}
6062
f()

ui/src/views/RepoRollback.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@ import { PageHeader, Result, Button } from 'antd'
44
import { shallowEqual } from "react-redux";
55

66
import { useAppDispatch, useAppSelector } from "../redux/hooks"
7-
import { repoRollbackSlice, fetchConfig, fetchDeployments, searchCandidates, rollback } from "../redux/repoRollback"
7+
import {
8+
repoRollbackSlice,
9+
fetchConfig,
10+
fetchDeployments,
11+
searchCandidates,
12+
fetchUser,
13+
rollback,
14+
} from "../redux/repoRollback"
815

916
import { User, Deployment, RequestStatus, Env } from '../models'
1017
import RollbackForm from "../components/RollbackForm";
@@ -33,6 +40,7 @@ export default function RepoHome(): JSX.Element {
3340
await dispatch(actions.init({namespace, name}))
3441
await dispatch(fetchConfig())
3542
await dispatch(actions.setDisplay(true))
43+
await dispatch(fetchUser())
3644
await dispatch(searchCandidates(""))
3745
}
3846
f()

0 commit comments

Comments
 (0)