ApproveIssue approves the approval flow of the issue.
(ctx context.Context, req *connect.Request[v1pb.ApproveIssueRequest])
| 578 | |
| 579 | // ApproveIssue approves the approval flow of the issue. |
| 580 | func (s *IssueService) ApproveIssue(ctx context.Context, req *connect.Request[v1pb.ApproveIssueRequest]) (*connect.Response[v1pb.Issue], error) { |
| 581 | issue, err := s.getIssueMessage(ctx, req.Msg.Name) |
| 582 | if err != nil { |
| 583 | return nil, err |
| 584 | } |
| 585 | project, err := s.store.GetProject(ctx, &store.FindProjectMessage{Workspace: common.GetWorkspaceIDFromContext(ctx), ResourceID: &issue.ProjectID}) |
| 586 | if err != nil { |
| 587 | return nil, connect.NewError(connect.CodeInternal, errors.Wrapf(err, "failed to get project")) |
| 588 | } |
| 589 | if project == nil { |
| 590 | return nil, connect.NewError(connect.CodeNotFound, errors.Errorf("project %s not found", issue.ProjectID)) |
| 591 | } |
| 592 | payload := issue.Payload |
| 593 | if payload.Approval == nil { |
| 594 | return nil, connect.NewError(connect.CodeInternal, errors.Errorf("issue payload approval is nil")) |
| 595 | } |
| 596 | if !payload.Approval.ApprovalFindingDone { |
| 597 | return nil, connect.NewError(connect.CodeFailedPrecondition, errors.Errorf("approval template finding is not done")) |
| 598 | } |
| 599 | if payload.Approval.ApprovalTemplate == nil { |
| 600 | return nil, connect.NewError(connect.CodeInternal, errors.New("approval template is required")) |
| 601 | } |
| 602 | |
| 603 | rejectedRole := utils.FindRejectedRole(payload.Approval) |
| 604 | if rejectedRole != "" { |
| 605 | return nil, connect.NewError(connect.CodeInvalidArgument, errors.Errorf("cannot approve because the issue has been rejected")) |
| 606 | } |
| 607 | |
| 608 | role := utils.FindNextPendingRole(payload.Approval) |
| 609 | if role == "" { |
| 610 | return nil, connect.NewError(connect.CodeInvalidArgument, errors.Errorf("the issue has been approved")) |
| 611 | } |
| 612 | |
| 613 | user, ok := GetUserFromContext(ctx) |
| 614 | if !ok { |
| 615 | return nil, connect.NewError(connect.CodeInternal, errors.Errorf("user not found")) |
| 616 | } |
| 617 | |
| 618 | canApprove := s.isUserReviewer(ctx, issue, role, user) |
| 619 | if !canApprove { |
| 620 | return nil, connect.NewError(connect.CodePermissionDenied, errors.Errorf("cannot approve because the user does not have the required permission")) |
| 621 | } |
| 622 | |
| 623 | if !project.Setting.GetAllowSelfApproval() && issue.CreatorEmail == user.Email { |
| 624 | return nil, connect.NewError(connect.CodePermissionDenied, errors.Errorf("cannot approve because self-approval is not allowed for this project")) |
| 625 | } |
| 626 | |
| 627 | payload.Approval.Approvers = append(payload.Approval.Approvers, &storepb.IssuePayloadApproval_Approver{ |
| 628 | Status: storepb.IssuePayloadApproval_Approver_APPROVED, |
| 629 | Principal: common.FormatUserEmail(user.Email), |
| 630 | }) |
| 631 | |
| 632 | approved, err := utils.CheckApprovalApproved(payload.Approval) |
| 633 | if err != nil { |
| 634 | return nil, connect.NewError(connect.CodeInternal, errors.Wrapf(err, "failed to check if the approval is approved")) |
| 635 | } |
| 636 | |
| 637 | issue, err = s.store.UpdateIssue(ctx, issue.ProjectID, issue.UID, &store.UpdateIssueMessage{ |
nothing calls this directly
no test coverage detected