From 46adcd037a9914aa37cd2ebde5cd9a0d8f398674 Mon Sep 17 00:00:00 2001 From: zengchen Date: Mon, 15 Mar 2021 10:39:50 +0800 Subject: [PATCH] Delete corp signing (#83) * delete corp signing * add lock before deleting signing * add lock --- controllers/cla.go | 16 +++---- controllers/corporation-manager.go | 9 ++-- controllers/corporation-pdf.go | 8 ++++ controllers/corporation-signing.go | 57 +++++++++++++++++++++++++ controllers/util.go | 14 +++++-- dbmodels/db.go | 1 + models/corporation-signing.go | 12 ++++++ mongodb/corporation-signing-deleted.go | 58 ++++++++++++++++++++++++++ mongodb/db-ops.go | 20 +++++++++ mongodb/models.go | 1 + routers/commentsRouter_controllers.go | 9 ++++ 11 files changed, 189 insertions(+), 16 deletions(-) create mode 100644 mongodb/corporation-signing-deleted.go diff --git a/controllers/cla.go b/controllers/cla.go index 25120c2..3a9c5ca 100644 --- a/controllers/cla.go +++ b/controllers/cla.go @@ -62,11 +62,9 @@ func (this *CLAController) Add() { return } - orgInfo := pl.orgInfo(linkID) - filePath := genOrgFileLockPath(orgInfo.Platform, orgInfo.OrgID, orgInfo.RepoID) - unlock, err := util.Lock(filePath) - if err != nil { - this.sendFailedResponse(500, errSystemError, err, action) + unlock, fr := lockOnRepo(pl.orgInfo(linkID)) + if fr != nil { + this.sendFailedResultAsResp(fr, action) return } defer unlock() @@ -101,11 +99,9 @@ func (this *CLAController) Delete() { return } - orgInfo := pl.orgInfo(linkID) - filePath := genOrgFileLockPath(orgInfo.Platform, orgInfo.OrgID, orgInfo.RepoID) - unlock, err := util.Lock(filePath) - if err != nil { - this.sendFailedResponse(500, errSystemError, err, action) + unlock, fr := lockOnRepo(pl.orgInfo(linkID)) + if fr != nil { + this.sendFailedResultAsResp(fr, action) return } defer unlock() diff --git a/controllers/corporation-manager.go b/controllers/corporation-manager.go index 70dad24..f98940e 100644 --- a/controllers/corporation-manager.go +++ b/controllers/corporation-manager.go @@ -48,12 +48,15 @@ func (this *CorporationManagerController) Put() { this.sendFailedResultAsResp(fr, action) return } + orgInfo := pl.orgInfo(linkID) - orgInfo, merr := models.GetOrgOfLink(linkID) - if merr != nil { - this.sendModelErrorAsResp(merr, action) + // lock to avoid the conflict with the deleting corp signing + unlock, fr := lockOnRepo(orgInfo) + if fr != nil { + this.sendFailedResultAsResp(fr, action) return } + defer unlock() // call models.GetCorpSigningBasicInfo before models.IsCorpSigningPDFUploaded // to check wheather corp has signed diff --git a/controllers/corporation-pdf.go b/controllers/corporation-pdf.go index 841c3eb..503633c 100644 --- a/controllers/corporation-pdf.go +++ b/controllers/corporation-pdf.go @@ -78,6 +78,14 @@ func (this *CorporationPDFController) Upload() { return } + // lock to avoid conflict with deleting corp signing + unlock, fr := lockOnRepo(pl.orgInfo(linkID)) + if fr != nil { + this.sendFailedResultAsResp(fr, action) + return + } + defer unlock() + b, merr := models.IsCorpSigned(linkID, corpEmail) if merr != nil { this.sendModelErrorAsResp(merr, action) diff --git a/controllers/corporation-signing.go b/controllers/corporation-signing.go index 45f7827..52183e5 100644 --- a/controllers/corporation-signing.go +++ b/controllers/corporation-signing.go @@ -119,6 +119,63 @@ func (this *CorporationSigningController) checkCLAForSigning(claFile, orgSignatu return nil } +// @Title Delete +// @Description delete corp signing +// @Param :link_id path string true "link id" +// @Param :email path string true "corp email" +// @Success 204 {string} delete success! +// @Failure 400 missing_url_path_parameter: missing url path parameter +// @Failure 401 missing_token: token is missing +// @Failure 402 unknown_token: token is unknown +// @Failure 403 expired_token: token is expired +// @Failure 404 unauthorized_token: the permission of token is unmatched +// @Failure 405 not_yours_org: the link doesn't belong to your community +// @Failure 406 unknown_link: unkown link id +// @Failure 407 no_link: the link id is not exists +// @Failure 500 system_error: system error +// @router /:link_id/:email [delete] +func (this *CorporationSigningController) Delete() { + action := "delete corp signing" + linkID := this.GetString(":link_id") + corpEmail := this.GetString(":email") + + pl, fr := this.tokenPayloadBasedOnCodePlatform() + if fr != nil { + this.sendFailedResultAsResp(fr, action) + return + } + if fr := pl.isOwnerOfLink(linkID); fr != nil { + this.sendFailedResultAsResp(fr, action) + return + } + + unlock, fr := lockOnRepo(pl.orgInfo(linkID)) + if fr != nil { + this.sendFailedResultAsResp(fr, action) + return + } + defer unlock() + + managers, merr := models.ListCorporationManagers(linkID, corpEmail, dbmodels.RoleAdmin) + if merr != nil { + this.sendModelErrorAsResp(merr, action) + return + } + if len(managers) > 0 { + this.sendFailedResponse( + 400, errCorpManagerExists, + fmt.Errorf("can't delete corp signing info, because admin manager exists"), action) + return + } + + if err := models.DeleteCorpSigning(linkID, corpEmail); err != nil { + this.sendModelErrorAsResp(err, action) + return + } + + this.sendSuccessResp("delete corp signing successfully") +} + // @Title ResendCorpSigningEmail // @Description resend corp signing email // @Param :org_id path string true "org cla id" diff --git a/controllers/util.go b/controllers/util.go index 03beb06..a394d4e 100644 --- a/controllers/util.go +++ b/controllers/util.go @@ -151,9 +151,9 @@ func signHelper(linkID, claLang, applyTo string, doSign func(*models.CLAInfo) *f // no contributor signed for this language. lock to avoid the cla to be changed // before writing to the db. - unlock, err := util.Lock(genOrgFileLockPath(orgInfo.Platform, orgInfo.OrgID, orgInfo.RepoID)) - if err != nil { - return newFailedApiResult(500, errSystemError, err) + unlock, fr := lockOnRepo(orgInfo) + if fr != nil { + return fr } defer unlock() @@ -193,3 +193,11 @@ func saveCorpCLAAtLocal(cla *models.CLACreateOpt, linkID string) *failedApiResul return nil } + +func lockOnRepo(orgInfo *dbmodels.OrgInfo) (func(), *failedApiResult) { + unlock, err := util.Lock(genOrgFileLockPath(orgInfo.Platform, orgInfo.OrgID, orgInfo.RepoID)) + if err != nil { + return nil, newFailedApiResult(500, errSystemError, err) + } + return unlock, nil +} diff --git a/dbmodels/db.go b/dbmodels/db.go index 0bb3ff0..6e12bcc 100644 --- a/dbmodels/db.go +++ b/dbmodels/db.go @@ -23,6 +23,7 @@ type IDB interface { type ICorporationSigning interface { InitializeCorpSigning(linkID string, info *OrgInfo, cla *CLAInfo) IDBError SignCorpCLA(orgCLAID string, info *CorpSigningCreateOpt) IDBError + DeleteCorpSigning(linkID, email string) IDBError IsCorpSigned(linkID, email string) (bool, IDBError) ListCorpSignings(linkID, language string) ([]CorporationSigningSummary, IDBError) GetCorpSigningDetail(linkID, email string) ([]Field, *CorpSigningCreateOpt, IDBError) diff --git a/models/corporation-signing.go b/models/corporation-signing.go index f2a4605..ba9355b 100644 --- a/models/corporation-signing.go +++ b/models/corporation-signing.go @@ -121,3 +121,15 @@ func GetCorpSigningDetail(linkID, email string) ([]dbmodels.Field, *dbmodels.Cor return f, s, parseDBError(err) } + +func DeleteCorpSigning(linkID, email string) IModelError { + err := dbmodels.GetDB().DeleteCorpSigning(linkID, email) + if err == nil { + return nil + } + + if err.IsErrorOf(dbmodels.ErrNoDBRecord) { + return newModelError(ErrNoLink, err) + } + return parseDBError(err) +} diff --git a/mongodb/corporation-signing-deleted.go b/mongodb/corporation-signing-deleted.go new file mode 100644 index 0000000..4f81b8e --- /dev/null +++ b/mongodb/corporation-signing-deleted.go @@ -0,0 +1,58 @@ +package mongodb + +import ( + "context" + + "github.com/opensourceways/app-cla-server/dbmodels" +) + +func (this *client) getCorpSigning(linkID, email string) (*dCorpSigning, dbmodels.IDBError) { + var v []cCorpSigning + + f := func(ctx context.Context) error { + return this.getArrayElem( + ctx, this.corpSigningCollection, fieldSignings, + docFilterOfSigning(linkID), elemFilterOfCorpSigning(email), + nil, &v, + ) + } + + if err := withContext(f); err != nil { + return nil, newSystemError(err) + } + + if len(v) == 0 { + return nil, errNoDBRecord + } + + signings := v[0].Signings + if len(signings) == 0 { + return nil, nil + } + + return &signings[0], nil +} + +func (this *client) DeleteCorpSigning(linkID, email string) dbmodels.IDBError { + data, err := this.getCorpSigning(linkID, email) + if err != nil { + return err + } + if data == nil { + return nil + } + + doc, err := structToMap(data) + if err != nil { + return err + } + + f := func(ctx context.Context) dbmodels.IDBError { + return this.moveArrayElem( + ctx, this.corpSigningCollection, fieldSignings, fieldDeleted, + docFilterOfSigning(linkID), elemFilterOfCorpSigning(email), doc, + ) + } + + return withContext1(f) +} diff --git a/mongodb/db-ops.go b/mongodb/db-ops.go index d434481..a47967e 100644 --- a/mongodb/db-ops.go +++ b/mongodb/db-ops.go @@ -153,6 +153,26 @@ func (this *client) pullAndReturnArrayElem(ctx context.Context, collection, arra return nil } +func (this *client) moveArrayElem(ctx context.Context, collection, from, to string, filterOfDoc, filterOfArray, value bson.M) dbmodels.IDBError { + col := this.collection(collection) + + r, err := col.UpdateOne( + ctx, filterOfDoc, + bson.M{ + "$pull": bson.M{from: filterOfArray}, + "$push": bson.M{to: value}, + }, + ) + if err != nil { + return newSystemError(err) + } + + if r.MatchedCount == 0 { + return errNoDBRecord + } + return nil +} + func (this *client) getDoc(ctx context.Context, collection string, filterOfDoc, project bson.M, result interface{}) dbmodels.IDBError { col := this.collection(collection) diff --git a/mongodb/models.go b/mongodb/models.go index 24f15e7..d1ee6e7 100644 --- a/mongodb/models.go +++ b/mongodb/models.go @@ -14,6 +14,7 @@ const ( fieldRepo = "repo" fieldCorpID = "corp_id" fieldSignings = "signings" + fieldDeleted = "deleted" fieldLang = "lang" fieldOrgEmail = "org_email" fieldOrgAlias = "org_alias" diff --git a/routers/commentsRouter_controllers.go b/routers/commentsRouter_controllers.go index d307d37..5840ad9 100644 --- a/routers/commentsRouter_controllers.go +++ b/routers/commentsRouter_controllers.go @@ -142,6 +142,15 @@ func init() { Filters: nil, Params: nil}) + beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:CorporationSigningController"] = append(beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:CorporationSigningController"], + beego.ControllerComments{ + Method: "Delete", + Router: "/:link_id/:email", + AllowHTTPMethods: []string{"delete"}, + MethodParams: param.Make(), + Filters: nil, + Params: nil}) + beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:CorporationSigningController"] = append(beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:CorporationSigningController"], beego.ControllerComments{ Method: "ResendCorpSigningEmail",