Skip to content

Commit

Permalink
adding update and delete operations to gitlab organizations (#3080)
Browse files Browse the repository at this point in the history
Signed-off-by: makkalot <[email protected]>
  • Loading branch information
makkalot authored Jul 28, 2021
1 parent 7137777 commit 7c28b24
Show file tree
Hide file tree
Showing 6 changed files with 541 additions and 10 deletions.
181 changes: 181 additions & 0 deletions cla-backend-go/go.sum

Large diffs are not rendered by default.

79 changes: 79 additions & 0 deletions cla-backend-go/swagger/cla.v2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1679,6 +1679,82 @@ paths:
tags:
- gitlab-organizations

/project/{projectSFID}/gitlab/organizations/{orgName}/config:
put:
summary: Update Gitlab Organization Configuration
description: Endpoint to adjust the Gitlab Organization Configuration, such as toggling the auto-enable flag
operationId: updateProjectGitlabOrganizationConfig
parameters:
- $ref: "#/parameters/x-request-id"
- $ref: "#/parameters/x-acl"
- $ref: "#/parameters/x-username"
- $ref: "#/parameters/x-email"
- name: projectSFID
in: path
type: string
required: true
- name: orgName
in: path
type: string
required: true
- in: body
name: body
schema:
$ref: '#/definitions/update-gitlab-organization'
required: true
responses:
'200':
description: 'Resource Updated'
headers:
x-request-id:
type: string
description: The unique request ID value - assigned/set by the API Gateway based on the session
'400':
$ref: '#/responses/invalid-request'
'401':
$ref: '#/responses/unauthorized'
'403':
$ref: '#/responses/forbidden'
'404':
$ref: '#/responses/not-found'
tags:
- gitlab-organizations

delete:
summary: Delete Gitlab organization in the project
description: Endpoint to delete the Gitlab organization for the project
operationId: deleteProjectGitlabOrganization
parameters:
- $ref: "#/parameters/x-request-id"
- $ref: "#/parameters/x-acl"
- $ref: "#/parameters/x-username"
- $ref: "#/parameters/x-email"
- name: projectSFID
in: path
type: string
required: true
- name: orgName
in: path
type: string
required: true
responses:
'204':
description: 'Deleted'
headers:
x-request-id:
type: string
description: The unique request ID value - assigned/set by the API Gateway based on the session
'400':
$ref: '#/responses/invalid-request'
'401':
$ref: '#/responses/unauthorized'
'403':
$ref: '#/responses/forbidden'
'404':
$ref: '#/responses/not-found'
tags:
- gitlab-organizations

/cla-group/{claGroupID}/icla/signatures:
get:
summary: List individual signatures for CLA Group
Expand Down Expand Up @@ -4237,6 +4313,9 @@ definitions:
create-gitlab-organization:
$ref: './common/create-github-organization.yaml'

update-gitlab-organization:
$ref: './common/update-github-organization.yaml'

user:
$ref: './common/user.yaml'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ properties:
description: Specifies which Cla group ID to be used when autoEnabled flag in enabled for the Github Organization. If autoEnabled is on this field needs to be set as well.
branchProtectionEnabled:
type: boolean
description: Flag to indicate if this GitHub Organization is configured to automatically setup branch protection on CLA enabled repositories.
description: Flag to indicate if this Organization is configured to automatically setup branch protection on CLA enabled repositories.
x-omitempty: true
86 changes: 86 additions & 0 deletions cla-backend-go/v2/gitlab_organizations/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ package gitlab_organizations

import (
"context"
"errors"
"fmt"
"strings"

"github.com/communitybridge/easycla/cla-backend-go/projects_cla_groups"

"github.com/communitybridge/easycla/cla-backend-go/gen/v2/models"
"github.com/communitybridge/easycla/cla-backend-go/gen/v2/restapi/operations/gitlab_activity"
"github.com/communitybridge/easycla/cla-backend-go/gitlab"
Expand Down Expand Up @@ -136,6 +139,89 @@ func Configure(api *operations.EasyclaAPI, service Service, eventService events.
return gitlab_organizations.NewAddProjectGitlabOrganizationOK().WithPayload(result)
})

api.GitlabOrganizationsUpdateProjectGitlabOrganizationConfigHandler = gitlab_organizations.UpdateProjectGitlabOrganizationConfigHandlerFunc(func(params gitlab_organizations.UpdateProjectGitlabOrganizationConfigParams, authUser *auth.User) middleware.Responder {
reqID := utils.GetRequestID(params.XREQUESTID)
ctx := context.WithValue(context.Background(), utils.XREQUESTID, reqID) // nolint
if params.Body.AutoEnabled == nil {
return gitlab_organizations.NewUpdateProjectGitlabOrganizationConfigBadRequest().WithPayload(&models.ErrorResponse{
Code: "400",
Message: "EasyCLA - 400 Bad Request - missing auto enable value in body",
})
}

if !utils.ValidateAutoEnabledClaGroupID(params.Body.AutoEnabled, params.Body.AutoEnabledClaGroupID) {
return gitlab_organizations.NewUpdateProjectGitlabOrganizationConfigBadRequest().WithPayload(&models.ErrorResponse{
Code: "400",
Message: "EasyCLA - 400 Bad Request - AutoEnabledClaGroupID can't be empty when AutoEnabled",
})
}

err := service.UpdateGitlabOrganization(ctx, params.ProjectSFID, params.OrgName, *params.Body.AutoEnabled, params.Body.AutoEnabledClaGroupID, params.Body.BranchProtectionEnabled)
if err != nil {
if errors.Is(err, projects_cla_groups.ErrCLAGroupDoesNotExist) {
return gitlab_organizations.NewUpdateProjectGitlabOrganizationConfigNotFound().WithPayload(utils.ErrorResponseNotFound(reqID, err.Error()))
}
return gitlab_organizations.NewUpdateProjectGitlabOrganizationConfigBadRequest().WithPayload(utils.ErrorResponseBadRequestWithError(reqID, "updating gitlab org", err))
}

eventService.LogEventWithContext(ctx, &events.LogEventArgs{
EventType: events.GitlabOrganizationUpdated,
ProjectSFID: params.ProjectSFID,
LfUsername: authUser.UserName,
UserName: authUser.UserName,
EventData: &events.GitlabOrganizationUpdatedEventData{
GitlabOrganizationName: params.OrgName,
AutoEnabled: *params.Body.AutoEnabled,
},
})

return gitlab_organizations.NewUpdateProjectGitlabOrganizationConfigOK()
})

api.GitlabOrganizationsDeleteProjectGitlabOrganizationHandler = gitlab_organizations.DeleteProjectGitlabOrganizationHandlerFunc(func(params gitlab_organizations.DeleteProjectGitlabOrganizationParams, authUser *auth.User) middleware.Responder {
reqID := utils.GetRequestID(params.XREQUESTID)
utils.SetAuthUserProperties(authUser, params.XUSERNAME, params.XEMAIL)
ctx := context.WithValue(context.Background(), utils.XREQUESTID, reqID) // nolint
f := logrus.Fields{
"functionName": "github_organization.handlers.GithubOrganizationsDeleteProjectGithubOrganizationHandler",
utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
"projectSFID": params.ProjectSFID,
"orgName": params.OrgName,
"authUser": authUser.UserName,
"authEmail": authUser.Email,
}

if !utils.IsUserAuthorizedForProjectTree(ctx, authUser, params.ProjectSFID, utils.ALLOW_ADMIN_SCOPE) {
msg := fmt.Sprintf("authUser %s does not have access to Delete Project GitHub Organizations with Project scope of %s",
authUser.UserName, params.ProjectSFID)
log.WithFields(f).Debug(msg)
return gitlab_organizations.NewDeleteProjectGitlabOrganizationForbidden().WithPayload(utils.ErrorResponseForbidden(reqID, msg))
}

err := service.DeleteGitlabOrganization(ctx, params.ProjectSFID, params.OrgName)
if err != nil {
if strings.Contains(err.Error(), "getProjectNotFound") {
msg := fmt.Sprintf("project not found with given SFID: %s", params.ProjectSFID)
log.WithFields(f).Debug(msg)
return gitlab_organizations.NewDeleteProjectGitlabOrganizationNotFound().WithPayload(utils.ErrorResponseNotFoundWithError(reqID, msg, err))
}
msg := fmt.Sprintf("problem deleting Gitlab Organization with project SFID: %s for organization: %s", params.ProjectSFID, params.OrgName)
log.WithFields(f).Debug(msg)
return gitlab_organizations.NewDeleteProjectGitlabOrganizationBadRequest().WithPayload(utils.ErrorResponseBadRequestWithError(reqID, msg, err))
}

eventService.LogEventWithContext(ctx, &events.LogEventArgs{
LfUsername: authUser.UserName,
EventType: events.GitHubOrganizationDeleted,
ProjectSFID: params.ProjectSFID,
EventData: &events.GitlabOrganizationDeletedEventData{
GitlabOrganizationName: params.OrgName,
},
})

return gitlab_organizations.NewDeleteProjectGitlabOrganizationNoContent()
})

api.GitlabActivityGitlabOauthCallbackHandler = gitlab_activity.GitlabOauthCallbackHandlerFunc(func(params gitlab_activity.GitlabOauthCallbackParams) middleware.Responder {
f := logrus.Fields{
"functionName": "gitlab_organization.handlers.GitlabActivityGitlabOauthCallbackHandler",
Expand Down
151 changes: 148 additions & 3 deletions cla-backend-go/v2/gitlab_organizations/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ type RepositoryInterface interface {
GetGitlabOrganizations(ctx context.Context, projectSFID string) (*models2.GitlabOrganizations, error)
GetGitlabOrganization(ctx context.Context, gitlabOrganizationID string) (*GitlabOrganization, error)
UpdateGitlabOrganizationAuth(ctx context.Context, gitlabOrganizationID, authInfo string) error
UpdateGitlabOrganization(ctx context.Context, projectSFID string, organizationName string, autoEnabled bool, autoEnabledClaGroupID string, branchProtectionEnabled bool, enabled *bool) error
DeleteGitlabOrganization(ctx context.Context, projectSFID, gitlabOrgName string) error
}

// Repository object/struct
Expand Down Expand Up @@ -98,7 +100,7 @@ func (repo Repository) AddGitlabOrganization(ctx context.Context, parentProjectS
return nil, err
}

enabled := false
enabled := true
gitlabOrg := &GitlabOrganization{
OrganizationID: organizationID.String(),
DateCreated: currentTime,
Expand Down Expand Up @@ -154,8 +156,8 @@ func (repo Repository) GetGitlabOrganizations(ctx context.Context, projectSFID s
condition := expression.Key("organization_sfid").Equal(expression.Value(projectSFID))
builder := expression.NewBuilder().WithKeyCondition(condition)

//filter := expression.Name("enabled").Equal(expression.Value(true))
//builder = builder.WithFilter(filter)
filter := expression.Name("enabled").Equal(expression.Value(true))
builder = builder.WithFilter(filter)

// Use the nice builder to create the expression
expr, err := builder.Build()
Expand Down Expand Up @@ -207,6 +209,8 @@ func (repo Repository) GetGitlabOrganizationByName(ctx context.Context, githubOr
"githubOrganizationName": githubOrganizationName,
}

githubOrganizationName = strings.ToLower(githubOrganizationName)

condition := expression.Key("organization_name_lower").Equal(expression.Value(strings.ToLower(githubOrganizationName)))
builder := expression.NewBuilder().WithKeyCondition(condition)
// Use the nice builder to create the expression
Expand Down Expand Up @@ -339,6 +343,147 @@ func (repo Repository) UpdateGitlabOrganizationAuth(ctx context.Context, gitlabO
return nil
}

func (repo Repository) UpdateGitlabOrganization(ctx context.Context, projectSFID string, organizationName string, autoEnabled bool, autoEnabledClaGroupID string, branchProtectionEnabled bool, enabled *bool) error {
f := logrus.Fields{
"functionName": "gitlab_organizations.repository.UpdateGitlabOrganization",
utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
"projectSFID": projectSFID,
"organizationName": organizationName,
"autoEnabled": autoEnabled,
"autoEnabledClaGroupID": autoEnabledClaGroupID,
"branchProtectionEnabled": branchProtectionEnabled,
"tableName": repo.gitlabOrgTableName,
}

_, currentTime := utils.CurrentTime()
gitlabOrgs, lookupErr := repo.GetGitlabOrganizationByName(ctx, organizationName)
if lookupErr != nil {
log.WithFields(f).Warnf("error looking up Gitlab organization by name, error: %+v", lookupErr)
return lookupErr
}
if gitlabOrgs == nil || len(gitlabOrgs.List) == 0 {
lookupErr := errors.New("unable to lookup Gitlab organization by name")
log.WithFields(f).Warnf("error looking up Gitlab organization, error: %+v", lookupErr)
return lookupErr
}

gitlabOrg := gitlabOrgs.List[0]

expressionAttributeNames := map[string]*string{
"#A": aws.String("auto_enabled"),
"#C": aws.String("auto_enabled_cla_group_id"),
"#B": aws.String("branch_protection_enabled"),
"#M": aws.String("date_modified"),
}
expressionAttributeValues := map[string]*dynamodb.AttributeValue{
":a": {
BOOL: aws.Bool(autoEnabled),
},
":c": {
S: aws.String(autoEnabledClaGroupID),
},
":b": {
BOOL: aws.Bool(branchProtectionEnabled),
},
":m": {
S: aws.String(currentTime),
},
}
updateExpression := "SET #A = :a, #C = :c, #B = :b, #M = :m"

if enabled != nil {
expressionAttributeNames["#E"] = aws.String("enabled")
expressionAttributeValues[":e"] = &dynamodb.AttributeValue{
BOOL: aws.Bool(*enabled),
}
updateExpression = updateExpression + ", #E = :e "
}

input := &dynamodb.UpdateItemInput{
Key: map[string]*dynamodb.AttributeValue{
"organization_id": {
S: aws.String(gitlabOrg.OrganizationID),
},
},
ExpressionAttributeNames: expressionAttributeNames,
ExpressionAttributeValues: expressionAttributeValues,
UpdateExpression: &updateExpression,
TableName: aws.String(repo.gitlabOrgTableName),
}

log.WithFields(f).Debugf("updating gitlab organization record: %+v", input)
_, updateErr := repo.dynamoDBClient.UpdateItem(input)
if updateErr != nil {
log.WithFields(f).Warnf("unable to update Gitlab organization record, error: %+v", updateErr)
return updateErr
}

return nil
}

func (repo Repository) DeleteGitlabOrganization(ctx context.Context, projectSFID, gitlabOrgName string) error {
f := logrus.Fields{
"functionName": "v1.github_organizations.repository.DeleteGitHubOrganization",
utils.XREQUESTID: ctx.Value(utils.XREQUESTID),
"projectSFID": projectSFID,
"githubOrgName": gitlabOrgName,
}

var gitlabOrganizationID string
orgs, orgErr := repo.GetGitlabOrganizations(ctx, projectSFID)
if orgErr != nil {
errMsg := fmt.Sprintf("gitlab organization is not found using projectSFID: %s, error: %+v", projectSFID, orgErr)
log.WithFields(f).Warn(errMsg)
return errors.New(errMsg)
}

for _, githubOrg := range orgs.List {
if strings.EqualFold(githubOrg.OrganizationName, gitlabOrgName) {
gitlabOrganizationID = githubOrg.OrganizationID
break
}
}

log.WithFields(f).Debug("Deleting GitHub organization...")
// Update enabled flag as false
_, currentTime := utils.CurrentTime()
note := fmt.Sprintf("Enabled set to false due to org deletion at %s ", currentTime)
_, err := repo.dynamoDBClient.UpdateItem(
&dynamodb.UpdateItemInput{
Key: map[string]*dynamodb.AttributeValue{
"organization_id": {
S: aws.String(gitlabOrganizationID),
},
},
ExpressionAttributeNames: map[string]*string{
"#E": aws.String("enabled"),
"#N": aws.String("note"),
"#D": aws.String("date_modified"),
},
ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
":e": {
BOOL: aws.Bool(false),
},
":n": {
S: aws.String(note),
},
":d": {
S: aws.String(currentTime),
},
},
UpdateExpression: aws.String("SET #E = :e, #N = :n, #D = :d"),
TableName: aws.String(repo.gitlabOrgTableName),
},
)
if err != nil {
errMsg := fmt.Sprintf("error deleting gitlab organization: %s - %+v", gitlabOrgName, err)
log.WithFields(f).Warnf(errMsg)
return errors.New(errMsg)
}

return nil
}

func buildGitlabOrganizationListModels(ctx context.Context, gitlabOrganizations []*GitlabOrganization) []*models2.GitlabOrganization {
f := logrus.Fields{
"functionName": "buildGitlabOrganizationListModels",
Expand Down
Loading

0 comments on commit 7c28b24

Please sign in to comment.