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

Commit

Permalink
Fix to block requesting the approval to the deployer. (#150)
Browse files Browse the repository at this point in the history
* Fix to block request the approval to the deployer

* Fix not to display the deployer in candidates of approval
  • Loading branch information
Noah Hanjun Lee authored Oct 7, 2021
1 parent 023cf3d commit f243811
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 11 deletions.
12 changes: 9 additions & 3 deletions internal/server/api/v1/repos/approval.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,21 @@ func (r *Repo) CreateApproval(c *gin.Context) {
}

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

if d.Edges.User != nil && user.ID == d.Edges.User.ID {
r.log.Warn("The deployer can not be the approver.", zap.Error(err))
gb.ErrorResponse(c, http.StatusUnprocessableEntity, "The deployer can not be the approver.")
return
}

ap, err := r.i.CreateApproval(ctx, &ent.Approval{
UserID: user.ID,
DeploymentID: d.ID,
Expand Down Expand Up @@ -192,7 +198,7 @@ func (r *Repo) CreateApproval(c *gin.Context) {
gb.Response(c, http.StatusCreated, ap)
}

func (r *Repo) UpdateApproval(c *gin.Context) {
func (r *Repo) UpdateMyApproval(c *gin.Context) {
ctx := c.Request.Context()

var (
Expand Down
60 changes: 60 additions & 0 deletions internal/server/api/v1/repos/approval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,66 @@ var (
)

func TestRepo_CreateApproval(t *testing.T) {
t.Run("Validate to request the approval to the deployer.", func(t *testing.T) {
input := struct {
number int
payload *approvalPostPayload
}{
number: 7,
payload: &approvalPostPayload{
UserID: 4,
},
}

ctrl := gomock.NewController(t)
m := mock.NewMockInteractor(ctrl)

t.Log("MOCK - Find the deployment by ID.")
m.
EXPECT().
FindDeploymentOfRepoByNumber(ctx, any, input.number).
Return(&ent.Deployment{
ID: input.number,
Edges: ent.DeploymentEdges{
User: &ent.User{
ID: input.payload.UserID,
},
},
}, nil)

t.Log("MOCK - Find the user, and check the permission.")
m.
EXPECT().
FindUserByID(ctx, input.payload.UserID).
Return(&ent.User{
ID: input.payload.UserID,
}, nil)

m.
EXPECT().
FindPermOfRepo(ctx, any, &ent.User{
ID: input.payload.UserID,
}).
Return(&ent.Perm{}, nil)

gin.SetMode(gin.ReleaseMode)

r := NewRepo(RepoConfig{}, m)
router := gin.New()
router.POST("/deployments/:number/approvals", func(c *gin.Context) {
c.Set(KeyRepo, &ent.Repo{})
}, r.CreateApproval)

body, _ := json.Marshal(input.payload)
req, _ := http.NewRequest("POST", fmt.Sprintf("/deployments/%d/approvals", input.number), bytes.NewBuffer(body))

w := httptest.NewRecorder()
router.ServeHTTP(w, req)

if w.Code != http.StatusUnprocessableEntity {
t.Fatalf("Code != %d, wanted %d", w.Code, http.StatusOK)
}
})

t.Run("Create a new approval.", func(t *testing.T) {
input := struct {
Expand Down
2 changes: 1 addition & 1 deletion internal/server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func NewRouter(c *RouterConfig) *gin.Engine {
repov1.GET("/:namespace/:name/deployments/:number/approvals", rm.RepoReadPerm(), r.ListApprovals)
repov1.POST("/:namespace/:name/deployments/:number/approvals", rm.RepoReadPerm(), r.CreateApproval)
repov1.GET("/:namespace/:name/deployments/:number/approval", rm.RepoReadPerm(), r.GetMyApproval)
repov1.PATCH("/:namespace/:name/deployments/:number/approval", rm.RepoReadPerm(), r.UpdateApproval)
repov1.PATCH("/:namespace/:name/deployments/:number/approval", rm.RepoReadPerm(), r.UpdateMyApproval)
repov1.GET("/:namespace/:name/approvals/:aid", rm.RepoReadPerm(), r.GetApproval)
repov1.DELETE("/:namespace/:name/approvals/:aid", rm.RepoReadPerm(), r.DeleteApproval)
repov1.GET("/:namespace/:name/locks", rm.RepoReadPerm(), r.ListLocks)
Expand Down
Binary file added ui/public/logo192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion ui/src/redux/deployment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ export const deploymentSlice = createSlice({
state.candidates = []
})
.addCase(searchCandidates.fulfilled, (state, action) => {
state.candidates = action.payload
state.candidates = action.payload.filter(candidate => candidate.id !== state.deployment?.deployer?.id)
})
.addCase(createApproval.fulfilled, (state, action) => {
state.approvals.push(action.payload)
Expand Down
19 changes: 18 additions & 1 deletion ui/src/redux/repoDeploy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
getTag,
createDeployment,
createApproval,
getMe,
} from '../apis'

// fetch all at the first page.
Expand Down Expand Up @@ -61,6 +62,7 @@ interface RepoDeployState {
*/
approvers: User[]
candidates: User[]
user?: User
deploying: RequestStatus
deployId: string
}
Expand Down Expand Up @@ -253,6 +255,18 @@ export const searchCandidates = createAsyncThunk<User[], string, { state: {repoD
}
)

export const fetchUser = createAsyncThunk<User, void, { state: {repoDeploy: RepoDeployState }}>(
"repoDeploy/fetchUser",
async (_, { rejectWithValue }) => {
try {
const user = await getMe()
return user
} catch(e) {
return rejectWithValue(e)
}
}
)

export const deploy = createAsyncThunk<void, void, { state: {repoDeploy: RepoDeployState}}> (
"repoDeploy/deploy",
async (_ , { getState, rejectWithValue, requestId }) => {
Expand Down Expand Up @@ -400,7 +414,10 @@ export const repoDeploySlice = createSlice({
state.candidates = []
})
.addCase(searchCandidates.fulfilled, (state, action) => {
state.candidates = action.payload
state.candidates = action.payload.filter(candidate => (candidate.id !== state.user?.id))
})
.addCase(fetchUser.fulfilled, (state, action) => {
state.user = action.payload
})
.addCase(deploy.pending, (state, action) => {
if (state.deploying === RequestStatus.Idle) {
Expand Down
21 changes: 19 additions & 2 deletions ui/src/redux/repoRollback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
listDeployments,
rollbackDeployment,
createApproval,
listPerms
listPerms,
getMe
} from "../apis"
import {
User,
Expand Down Expand Up @@ -39,6 +40,7 @@ interface RepoRollbackState {
*/
approvers: User[]
candidates: User[]
user?: User
deployId: string
deploying: RequestStatus
}
Expand Down Expand Up @@ -100,6 +102,18 @@ export const searchCandidates = createAsyncThunk<User[], string, { state: {repoR
}
)

export const fetchUser = createAsyncThunk<User, void, { state: {repoRollback: RepoRollbackState }}>(
"repoRollback/fetchUser",
async (_, { rejectWithValue }) => {
try {
const user = await getMe()
return user
} catch(e) {
return rejectWithValue(e)
}
}
)

export const rollback = createAsyncThunk<void, void, { state: {repoRollback: RepoRollbackState}}> (
"repoRollback/deploy",
async (_ , { getState, rejectWithValue, requestId }) => {
Expand Down Expand Up @@ -196,7 +210,10 @@ export const repoRollbackSlice = createSlice({
state.candidates = []
})
.addCase(searchCandidates.fulfilled, (state, action) => {
state.candidates = action.payload
state.candidates = action.payload.filter(candidate => (candidate.id !== state.user?.id))
})
.addCase(fetchUser.fulfilled, (state, action) => {
state.user = action.payload
})
.addCase(rollback.pending, (state, action) => {
if (state.deploying === RequestStatus.Idle) {
Expand Down
5 changes: 3 additions & 2 deletions ui/src/views/Deployment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,11 @@ export default function DeploymentView(): JSX.Element {
const f = async () => {
await dispatch(slice.actions.init({namespace, name, number: parseInt(number, 10)}))
await dispatch(fetchDeployment())
await dispatch(slice.actions.setDisplay(true))
await dispatch(fetchDeploymentChanges())
await dispatch(fetchApprovals())
await dispatch(fetchMyApproval())
await dispatch(slice.actions.setDisplay(true))
await dispatch(fetchDeploymentChanges())
await dispatch(searchCandidates(""))
}
f()

Expand Down
2 changes: 2 additions & 0 deletions ui/src/views/RepoDeploy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
checkTag,
addTagManually,
searchCandidates,
fetchUser,
deploy} from "../redux/repoDeploy"

import DeployForm, {Option} from "../components/DeployForm"
Expand Down Expand Up @@ -55,6 +56,7 @@ export default function RepoDeploy(): JSX.Element {
await dispatch(actions.setDisplay(true))
await dispatch(fetchBranches())
await dispatch(fetchTags())
await dispatch(fetchUser())
await dispatch(searchCandidates(""))
}
f()
Expand Down
10 changes: 9 additions & 1 deletion ui/src/views/RepoRollback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ import { PageHeader, Result, Button } from 'antd'
import { shallowEqual } from "react-redux";

import { useAppDispatch, useAppSelector } from "../redux/hooks"
import { repoRollbackSlice, fetchConfig, fetchDeployments, searchCandidates, rollback } from "../redux/repoRollback"
import {
repoRollbackSlice,
fetchConfig,
fetchDeployments,
searchCandidates,
fetchUser,
rollback,
} from "../redux/repoRollback"

import { User, Deployment, RequestStatus, Env } from '../models'
import RollbackForm from "../components/RollbackForm";
Expand Down Expand Up @@ -33,6 +40,7 @@ export default function RepoHome(): JSX.Element {
await dispatch(actions.init({namespace, name}))
await dispatch(fetchConfig())
await dispatch(actions.setDisplay(true))
await dispatch(fetchUser())
await dispatch(searchCandidates(""))
}
f()
Expand Down

0 comments on commit f243811

Please sign in to comment.