diff --git a/controllers/dco.go b/controllers/dco.go
new file mode 100644
index 0000000..76bf664
--- /dev/null
+++ b/controllers/dco.go
@@ -0,0 +1,127 @@
+package controllers
+
+import (
+ "strings"
+
+ "github.com/opensourceways/app-cla-server/models"
+)
+
+type DCOController struct {
+ baseController
+}
+
+func (ctl *DCOController) Prepare() {
+ if ctl.isGetRequest() && strings.HasSuffix(ctl.routerPattern(), "/:link_id/:id") {
+ ctl.apiPrepare("")
+ } else {
+ ctl.apiPrepare(PermissionOwnerOfOrg)
+ }
+}
+
+// @Title Add
+// @Description add dco
+// @Tags DCO
+// @Accept json
+// @Param body body models.DCOCreateOpt true "body for adding dco"
+// @Success 201 {object} controllers.respData
+// @router /:link_id [post]
+func (ctl *DCOController) Add() {
+ action := "add dco"
+ linkID := ctl.GetString(":link_id")
+
+ pl, fr := ctl.tokenPayloadBasedOnCodePlatform()
+ if fr != nil {
+ ctl.sendFailedResultAsResp(fr, action)
+ return
+ }
+ if fr := pl.isOwnerOfLink(linkID); fr != nil {
+ ctl.sendFailedResultAsResp(fr, action)
+ return
+ }
+
+ input := &models.DCOCreateOpt{}
+ if fr := ctl.fetchInputPayloadFromFormData(input); fr != nil {
+ ctl.sendFailedResultAsResp(fr, action)
+ return
+ }
+
+ if err := models.AddDCOInstance(linkID, input); err != nil {
+ ctl.sendModelErrorAsResp(err, action)
+ } else {
+ ctl.sendSuccessResp(action, "successfully")
+ }
+}
+
+// @Title Delete
+// @Description delete dco
+// @Tags DCO
+// @Accept json
+// @Param link_id path string true "link id"
+// @Param id path string true "dco id"
+// @Success 204 {object} controllers.respData
+// @router /:link_id/:id [delete]
+func (ctl *DCOController) Delete() {
+ action := "delete dco"
+ linkID := ctl.GetString(":link_id")
+ dcoId := ctl.GetString(":id")
+
+ pl, fr := ctl.tokenPayloadBasedOnCodePlatform()
+ if fr != nil {
+ ctl.sendFailedResultAsResp(fr, action)
+ return
+ }
+ if fr := pl.isOwnerOfLink(linkID); fr != nil {
+ ctl.sendFailedResultAsResp(fr, action)
+ return
+ }
+
+ if err := models.RemoveDCOInstance(linkID, dcoId); err != nil {
+ ctl.sendModelErrorAsResp(err, action)
+
+ return
+ }
+
+ ctl.sendSuccessResp(action, "successfully")
+}
+
+// @Title DownloadPDF
+// @Description get dco pdf
+// @Tags DCO
+// @Accept json
+// @Param link_id path string true "link id"
+// @Param id path string true "dco id"
+// @Success 200
+// @router /:link_id/:id [get]
+func (ctl *DCOController) DownloadPDF() {
+ ctl.downloadFile(models.DCOFile(
+ ctl.GetString(":link_id"), ctl.GetString(":id"),
+ ))
+}
+
+// @Title List
+// @Description list dcos of link
+// @Tags DCO
+// @Accept json
+// @Param link_id path string true "link id"
+// @Success 200 {object} models.CLADetail
+// @router /:link_id [get]
+func (ctl *DCOController) List() {
+ action := "list dco"
+ linkID := ctl.GetString(":link_id")
+
+ pl, fr := ctl.tokenPayloadBasedOnCodePlatform()
+ if fr != nil {
+ ctl.sendFailedResultAsResp(fr, action)
+ return
+ }
+ if fr := pl.isOwnerOfLink(linkID); fr != nil {
+ ctl.sendFailedResultAsResp(fr, action)
+ return
+ }
+
+ if dcos, merr := models.ListDCOInstances(linkID); merr != nil {
+ ctl.sendModelErrorAsResp(merr, action)
+ } else {
+ ctl.sendSuccessResp(action, dcos)
+ }
+}
diff --git a/controllers/dco_link.go b/controllers/dco_link.go
new file mode 100644
index 0000000..316df87
--- /dev/null
+++ b/controllers/dco_link.go
@@ -0,0 +1,134 @@
+package controllers
+
+import (
+ "strings"
+
+ "github.com/opensourceways/app-cla-server/models"
+)
+
+type DCOLinkController struct {
+ baseController
+}
+
+func (ctl *DCOLinkController) Prepare() {
+ if strings.HasSuffix(ctl.routerPattern(), "dcos") {
+ ctl.apiPrepare("")
+ } else {
+ ctl.apiPrepare(PermissionOwnerOfOrg)
+ }
+}
+
+// @Title Create
+// @Description create a link(dco application)
+// @Tags DCOLink
+// @Accept json
+// @Param body body models.DCOLinkCreateOption true "body for creating link"
+// @Success 201 {object} controllers.respData
+// @router / [post]
+func (ctl *DCOLinkController) Create() {
+ action := "community manager creates link(dco application)"
+ sendResp := ctl.newFuncForSendingFailedResp(action)
+
+ pl, fr := ctl.tokenPayloadBasedOnCodePlatform()
+ if fr != nil {
+ sendResp(fr)
+ return
+ }
+
+ input := &models.DCOLinkCreateOption{}
+ if fr := ctl.fetchInputPayloadFromFormData(input); fr != nil {
+ ctl.sendFailedResultAsResp(fr, action)
+ return
+ }
+
+ if fr := pl.isOwnerOfOrg(input.Platform, input.OrgID); fr != nil {
+ sendResp(fr)
+ return
+ }
+
+ if merr := models.AddDCOLink(pl.User, input); merr != nil {
+ ctl.sendModelErrorAsResp(merr, action)
+ return
+ }
+
+ ctl.sendSuccessResp(action, "successfully")
+}
+
+// @Title Delete
+// @Description delete link
+// @Tags DCOLink
+// @Accept json
+// @Param link_id path string true "link id"
+// @Success 204 {object} controllers.respData
+// @router /:link_id [delete]
+func (ctl *DCOLinkController) Delete() {
+ linkId := ctl.GetString(":link_id")
+ action := "community manager delete dco link: " + linkId
+ sendResp := ctl.newFuncForSendingFailedResp(action)
+
+ pl, fr := ctl.tokenPayloadBasedOnCodePlatform()
+ if fr != nil {
+ sendResp(fr)
+ return
+ }
+
+ if fr := pl.isOwnerOfLink(linkId); fr != nil {
+ sendResp(fr)
+ return
+ }
+
+ if err := models.RemoveDCOLink(linkId); err != nil {
+ ctl.sendModelErrorAsResp(err, action)
+ return
+ }
+
+ ctl.sendSuccessResp(action, "successfully")
+}
+
+// @Title List
+// @Description list all links
+// @Tags DCOLink
+// @Accept json
+// @Success 200 {object} models.LinkInfo
+// @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 500 system_error: system error
+// @router / [get]
+func (ctl *DCOLinkController) List() {
+ action := "community manager list dco links"
+
+ pl, fr := ctl.tokenPayloadBasedOnCodePlatform()
+ if fr != nil {
+ ctl.sendFailedResultAsResp(fr, action)
+ return
+ }
+
+ if r, merr := models.ListDCOLink(pl.Platform, pl.Orgs); merr != nil {
+ ctl.sendModelErrorAsResp(merr, action)
+ } else {
+ ctl.sendSuccessResp(action, r)
+ }
+}
+
+// @Title GetDCOForSigning
+// @Description get signing page info
+// @Tags DCOLink
+// @Accept json
+// @Param link_id path string true "link id"
+// @Param apply_to path string true "apply to"
+// @Success 200 {object} models.CLADetail
+// @Failure util.ErrNoCLABindingDoc "org has not been bound any clas"
+// @Failure util.ErrNotReadyToSign "the corp signing is not ready"
+// @router /:link_id/dcos [get]
+func (ctl *DCOLinkController) GetDCOForSigning() {
+ action := "fetch dco signing page info"
+
+ result, err := models.ListDCOs(ctl.GetString(":link_id"))
+ if err != nil {
+ ctl.sendModelErrorAsResp(err, action)
+ } else {
+ ctl.sendSuccessResp(action, result)
+ }
+}
diff --git a/controllers/link.go b/controllers/link.go
index f48fdef..a4a0dc1 100644
--- a/controllers/link.go
+++ b/controllers/link.go
@@ -18,14 +18,14 @@ func (ctl *LinkController) Prepare() {
}
}
-// @Title Link
+// @Title Create
// @Description create a link(cla application)
// @Tags Link
// @Accept json
// @Param body body models.LinkCreateOption true "body for creating link"
// @Success 201 {object} controllers.respData
// @router / [post]
-func (ctl *LinkController) Link() {
+func (ctl *LinkController) Create() {
action := "community manager creates link(cla application)"
sendResp := ctl.newFuncForSendingFailedResp(action)
diff --git a/controllers/token.go b/controllers/token.go
index 1d9e11d..4243207 100644
--- a/controllers/token.go
+++ b/controllers/token.go
@@ -6,7 +6,6 @@ import (
"net"
"strings"
- "github.com/beego/beego/v2/core/logs"
"github.com/opensourceways/app-cla-server/models"
)
@@ -92,17 +91,12 @@ func (ctl *baseController) setToken(t models.AccessToken) {
func (ctl *baseController) getRemoteAddr() (string, *failedApiResult) {
ips := ctl.Ctx.Request.Header.Get("x-forwarded-for")
- logs.Info("x-forwarded-for value is: %s", ips)
for _, item := range strings.Split(ips, ", ") {
if net.ParseIP(item) != nil {
- logs.Info("x-forwarded-for value is: %s, remote addr: %s", ips, item)
-
return item, nil
}
}
- logs.Info("x-forwarded-for value is: %s, no remote addr", ips)
-
return "", newFailedApiResult(400, errCanNotFetchClientIP, fmt.Errorf("can not fetch client ip"))
}
diff --git a/models/adapter.go b/models/adapter.go
index 9ce2cd4..ba9f888 100644
--- a/models/adapter.go
+++ b/models/adapter.go
@@ -48,6 +48,8 @@ func ListLink(platform string, orgs []string) ([]LinkInfo, IModelError) {
return linkAdapterInstance.List(platform, orgs)
}
+// function of signing
+
func GetLinkCLA(linkId, claId string) (OrgInfo, CLAInfo, IModelError) {
return linkAdapterInstance.GetLinkCLA(linkId, claId)
}
@@ -60,6 +62,42 @@ func GetLink(linkId string) (OrgInfo, IModelError) {
return linkAdapterInstance.GetLink(linkId)
}
+// dco
+
+func AddDCOInstance(linkId string, opt *DCOCreateOpt) IModelError {
+ return dcoAdapterInstance.Add(linkId, opt)
+}
+
+func DCOFile(linkId, dcoId string) string {
+ return dcoAdapterInstance.DCOLocalFilePath(linkId, dcoId)
+}
+
+func ListDCOInstances(linkId string) ([]CLADetail, IModelError) {
+ return dcoAdapterInstance.List(linkId)
+}
+
+func RemoveDCOInstance(linkId, dcoId string) IModelError {
+ return dcoAdapterInstance.Remove(linkId, dcoId)
+}
+
+// dco link
+
+func AddDCOLink(submitter string, opt *DCOLinkCreateOption) IModelError {
+ return dcoLinkAdapterInstance.Add(submitter, opt)
+}
+
+func RemoveDCOLink(linkId string) IModelError {
+ return dcoLinkAdapterInstance.Remove(linkId)
+}
+
+func ListDCOLink(platform string, orgs []string) ([]LinkInfo, IModelError) {
+ return dcoLinkAdapterInstance.List(platform, orgs)
+}
+
+func ListDCOs(linkId string) ([]CLADetail, IModelError) {
+ return dcoLinkAdapterInstance.ListDCOs(linkId)
+}
+
// corp signing
func VCOfCorpSigning(linkId, email string) (string, IModelError) {
diff --git a/models/dco.go b/models/dco.go
new file mode 100644
index 0000000..5dbf53e
--- /dev/null
+++ b/models/dco.go
@@ -0,0 +1,16 @@
+package models
+
+type DCOLinkCreateOption struct {
+ Platform string `json:"platform"`
+ OrgID string `json:"org_id"`
+ RepoID string `json:"repo_id"`
+ OrgAlias string `json:"org_alias"`
+ OrgEmail string `json:"org_email"`
+ DCO *DCOCreateOpt `json:"dco"`
+}
+
+type DCOCreateOpt = struct {
+ URL string `json:"url"`
+ Fields []CLAField `json:"fields"`
+ Language string `json:"language"`
+}
diff --git a/models/error.go b/models/error.go
index 6117efc..886d7ca 100644
--- a/models/error.go
+++ b/models/error.go
@@ -49,10 +49,15 @@ const (
ErrNoRefreshToken ModelErrCode = "no_refresh_token"
ErrInvalidToken ModelErrCode = "invalid_token"
ErrCLAExists ModelErrCode = "cla_exists"
+ ErrCLAIsUsed ModelErrCode = "cla_is_used"
+ ErrDCOExists ModelErrCode = "dco_exists"
+ ErrDCOIsUsed ModelErrCode = "dco_is_used"
ErrTooManyRequest ModelErrCode = "too_many_request"
ErrUserLoginFrozen ModelErrCode = "user_login_frozen"
- ErrCLAIsUsed ModelErrCode = "cla_is_used"
ErrLinkIsUsed ModelErrCode = "link_is_used"
+ ErrNoDCOLink ModelErrCode = "no_dco_link"
+ ErrDCOLinkExists ModelErrCode = "dco_link_exists"
+ ErrDCOLinkIsUsed ModelErrCode = "dco_link_is_used"
)
type IModelError interface {
diff --git a/models/init.go b/models/init.go
index 54a9c01..cd47d5c 100644
--- a/models/init.go
+++ b/models/init.go
@@ -2,9 +2,11 @@ package models
var (
claAdapterInstance claAdapter
+ dcoAdapterInstance dcoAdapter
linkAdapterInstance linkAdapter
userAdapterInstance userAdapter
smtpAdapterInstance smtpAdapter
+ dcoLinkAdapterInstance dcoLinkAdapter
corpPDFAdapterInstance corpPDFAdapter
corpAdminAdatperInstance corpAdminAdatper
accessTokenAdapterInstance accessTokenAdapter
@@ -151,3 +153,27 @@ type linkAdapter interface {
func RegisterLinkAdapter(a linkAdapter) {
linkAdapterInstance = a
}
+
+// dcoAdapter
+type dcoAdapter interface {
+ Add(linkId string, opt *DCOCreateOpt) IModelError
+ Remove(linkId, dcoId string) IModelError
+ DCOLocalFilePath(linkId, dcoId string) string
+ List(linkId string) ([]CLADetail, IModelError)
+}
+
+func RegisterDCOAdapter(a dcoAdapter) {
+ dcoAdapterInstance = a
+}
+
+// dcoLinkAdapter
+type dcoLinkAdapter interface {
+ Add(submitter string, opt *DCOLinkCreateOption) IModelError
+ Remove(linkId string) IModelError
+ List(platform string, orgs []string) ([]LinkInfo, IModelError)
+ ListDCOs(linkId string) ([]CLADetail, IModelError)
+}
+
+func RegisterDCOLinkAdapter(a dcoLinkAdapter) {
+ dcoLinkAdapterInstance = a
+}
diff --git a/routers/commentsRouter.go b/routers/commentsRouter.go
index 0ff6a4f..05e2a7d 100644
--- a/routers/commentsRouter.go
+++ b/routers/commentsRouter.go
@@ -223,6 +223,78 @@ func init() {
Filters: nil,
Params: nil})
+ beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOController"] = append(beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOController"],
+ beego.ControllerComments{
+ Method: "Add",
+ Router: `/:link_id`,
+ AllowHTTPMethods: []string{"post"},
+ MethodParams: param.Make(),
+ Filters: nil,
+ Params: nil})
+
+ beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOController"] = append(beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOController"],
+ beego.ControllerComments{
+ Method: "List",
+ Router: `/:link_id`,
+ AllowHTTPMethods: []string{"get"},
+ MethodParams: param.Make(),
+ Filters: nil,
+ Params: nil})
+
+ beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOController"] = append(beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOController"],
+ beego.ControllerComments{
+ Method: "Delete",
+ Router: `/:link_id/:id`,
+ AllowHTTPMethods: []string{"delete"},
+ MethodParams: param.Make(),
+ Filters: nil,
+ Params: nil})
+
+ beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOController"] = append(beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOController"],
+ beego.ControllerComments{
+ Method: "DownloadPDF",
+ Router: `/:link_id/:id`,
+ AllowHTTPMethods: []string{"get"},
+ MethodParams: param.Make(),
+ Filters: nil,
+ Params: nil})
+
+ beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOLinkController"] = append(beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOLinkController"],
+ beego.ControllerComments{
+ Method: "Create",
+ Router: `/`,
+ AllowHTTPMethods: []string{"post"},
+ MethodParams: param.Make(),
+ Filters: nil,
+ Params: nil})
+
+ beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOLinkController"] = append(beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOLinkController"],
+ beego.ControllerComments{
+ Method: "List",
+ Router: `/`,
+ AllowHTTPMethods: []string{"get"},
+ MethodParams: param.Make(),
+ Filters: nil,
+ Params: nil})
+
+ beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOLinkController"] = append(beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOLinkController"],
+ beego.ControllerComments{
+ Method: "Delete",
+ Router: `/:link_id`,
+ AllowHTTPMethods: []string{"delete"},
+ MethodParams: param.Make(),
+ Filters: nil,
+ Params: nil})
+
+ beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOLinkController"] = append(beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:DCOLinkController"],
+ beego.ControllerComments{
+ Method: "GetDCOForSigning",
+ Router: `/:link_id/dcos`,
+ AllowHTTPMethods: []string{"get"},
+ MethodParams: param.Make(),
+ Filters: nil,
+ Params: nil})
+
beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:EmployeeManagerController"] = append(beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:EmployeeManagerController"],
beego.ControllerComments{
Method: "Post",
@@ -333,7 +405,7 @@ func init() {
beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:LinkController"] = append(beego.GlobalControllerRouter["github.com/opensourceways/app-cla-server/controllers:LinkController"],
beego.ControllerComments{
- Method: "Link",
+ Method: "Create",
Router: `/`,
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
diff --git a/routers/router.go b/routers/router.go
index 9ad3b8a..ebafeb8 100644
--- a/routers/router.go
+++ b/routers/router.go
@@ -25,6 +25,17 @@ func init() {
&controllers.LinkController{},
),
),
+
+ beego.NSNamespace("/dco",
+ beego.NSInclude(
+ &controllers.DCOController{},
+ ),
+ ),
+ beego.NSNamespace("/dco-link",
+ beego.NSInclude(
+ &controllers.DCOLinkController{},
+ ),
+ ),
beego.NSNamespace("/individual-signing",
beego.NSInclude(
&controllers.IndividualSigningController{},
diff --git a/signing.go b/signing.go
index 3294fbd..9235e01 100644
--- a/signing.go
+++ b/signing.go
@@ -158,5 +158,22 @@ func initSigning(cfg *config.Config) error {
),
)
+ //
+
+ dcoAapter := adapter.NewDCOAdapter(
+ app.NewDCOService(linkRepo, cla, individual),
+ cfg.Domain.MaxSizeOfCLAContent,
+ cfg.Domain.FileTypeOfCLAContent,
+ )
+
+ models.RegisterDCOAdapter(dcoAapter)
+
+ models.RegisterDCOLinkAdapter(
+ adapter.NewDCOLinkAdapter(
+ app.NewDCOLinkService(linkRepo, cla, individual, echelper),
+ dcoAapter,
+ ),
+ )
+
return nil
}
diff --git a/signing/adapter/cla.go b/signing/adapter/cla.go
index 0536d77..9fa849e 100644
--- a/signing/adapter/cla.go
+++ b/signing/adapter/cla.go
@@ -51,12 +51,12 @@ func (adapter *claAdatper) List(linkId string) (models.CLAOfLink, models.IModelE
}
return models.CLAOfLink{
- IndividualCLAs: adapter.toCLADetail(individuals),
- CorpCLAs: adapter.toCLADetail(corps),
+ IndividualCLAs: toCLADetail(individuals),
+ CorpCLAs: toCLADetail(corps),
}, nil
}
-func (adapter *claAdatper) toCLADetail(v []app.CLADTO) []models.CLADetail {
+func toCLADetail(v []app.CLADTO) []models.CLADetail {
r := make([]models.CLADetail, len(v))
for i := range v {
@@ -114,12 +114,12 @@ func (adapter *claAdatper) cmdToAddCLA(opt *models.CLACreateOpt) (
return
}
- cmd.Fields, err = adapter.toFields(cmd.Type, opt.Fields)
+ cmd.Fields, err = toCLAFields(cmd.Type, opt.Fields)
return
}
-func (adapter *claAdatper) toFields(claType dp.CLAType, fields []models.CLAField) (r []domain.Field, err error) {
+func toCLAFields(claType dp.CLAType, fields []models.CLAField) (r []domain.Field, err error) {
if len(fields) == 0 {
err = errors.New("no fields")
@@ -139,7 +139,7 @@ func (adapter *claAdatper) toFields(claType dp.CLAType, fields []models.CLAField
m[item.Type] = true
- if r[i], err = adapter.toField(item, f); err != nil {
+ if r[i], err = toCLAField(item, f); err != nil {
return
}
}
@@ -151,7 +151,7 @@ func (adapter *claAdatper) toFields(claType dp.CLAType, fields []models.CLAField
return
}
-func (adapter *claAdatper) toField(
+func toCLAField(
opt *models.CLAField,
f func(string) (dp.CLAFieldType, error),
) (domain.Field, error) {
diff --git a/signing/adapter/dco.go b/signing/adapter/dco.go
new file mode 100644
index 0000000..d1f5fa1
--- /dev/null
+++ b/signing/adapter/dco.go
@@ -0,0 +1,96 @@
+package adapter
+
+import (
+ "github.com/opensourceways/app-cla-server/models"
+ "github.com/opensourceways/app-cla-server/signing/app"
+ "github.com/opensourceways/app-cla-server/signing/domain"
+ "github.com/opensourceways/app-cla-server/signing/domain/dp"
+ "github.com/opensourceways/app-cla-server/util"
+)
+
+func NewDCOAdapter(
+ s app.DCOService,
+ maxSizeOfDCOContent int,
+ fileTypeOfDCOContent string,
+) *dcoAdapter {
+ return &dcoAdapter{
+ s: s,
+ maxSizeOfDCOContent: maxSizeOfDCOContent,
+ fileTypeOfDCOContent: fileTypeOfDCOContent,
+ }
+}
+
+type dcoAdapter struct {
+ s app.DCOService
+ maxSizeOfDCOContent int
+ fileTypeOfDCOContent string
+}
+
+// Remove
+func (adapter *dcoAdapter) Remove(linkId, claId string) models.IModelError {
+ err := adapter.s.Remove(domain.CLAIndex{
+ LinkId: linkId,
+ CLAId: claId,
+ })
+
+ if err != nil {
+ return toModelError(err)
+ }
+
+ return nil
+}
+
+// List
+func (adapter *dcoAdapter) List(linkId string) ([]models.CLADetail, models.IModelError) {
+ v, err := adapter.s.List(linkId)
+ if err != nil {
+ return nil, toModelError(err)
+ }
+
+ return toCLADetail(v), nil
+}
+
+// DCOLocalFilePath
+func (adapter *dcoAdapter) DCOLocalFilePath(linkId, claId string) string {
+ return adapter.s.DCOLocalFilePath(domain.CLAIndex{
+ LinkId: linkId,
+ CLAId: claId,
+ })
+}
+
+// Add
+func (adapter *dcoAdapter) Add(linkId string, opt *models.DCOCreateOpt) models.IModelError {
+ cmd, err := adapter.cmdToAddDCO(opt)
+ if err != nil {
+ return errBadRequestParameter(err)
+ }
+
+ if err := adapter.s.Add(linkId, &cmd); err != nil {
+ return toModelError(err)
+ }
+
+ return nil
+}
+
+func (adapter *dcoAdapter) cmdToAddDCO(opt *models.DCOCreateOpt) (
+ cmd app.CmdToAddDCO, err error,
+) {
+ cmd.Text, err = util.DownloadFile(
+ opt.URL, adapter.fileTypeOfDCOContent, adapter.maxSizeOfDCOContent,
+ )
+ if err != nil {
+ return
+ }
+
+ if cmd.URL, err = dp.NewURL(opt.URL); err != nil {
+ return
+ }
+
+ if cmd.Language, err = dp.NewLanguage(opt.Language); err != nil {
+ return
+ }
+
+ cmd.Fields, err = toCLAFields(dp.CLATypeIndividual, opt.Fields)
+
+ return
+}
diff --git a/signing/adapter/dco_link.go b/signing/adapter/dco_link.go
new file mode 100644
index 0000000..a6512b6
--- /dev/null
+++ b/signing/adapter/dco_link.go
@@ -0,0 +1,125 @@
+package adapter
+
+import (
+ "errors"
+
+ "github.com/opensourceways/app-cla-server/models"
+ "github.com/opensourceways/app-cla-server/signing/app"
+ "github.com/opensourceways/app-cla-server/signing/domain/dp"
+)
+
+func NewDCOLinkAdapter(
+ s app.DCOLinkService,
+ dco *dcoAdapter,
+) *dcoLinkAdapter {
+ return &dcoLinkAdapter{
+ dco: dco,
+ s: s,
+ }
+}
+
+type dcoLinkAdapter struct {
+ dco *dcoAdapter
+
+ s app.DCOLinkService
+}
+
+// ListDCOs
+func (adapter *dcoLinkAdapter) ListDCOs(linkId string) ([]models.CLADetail, models.IModelError) {
+ v, err := adapter.s.FindDCOs(linkId)
+ if err != nil {
+ return nil, toModelError(err)
+ }
+
+ r := make([]models.CLADetail, len(v))
+ for i := range v {
+ item := &v[i]
+
+ detail := &r[i]
+ detail.CLAId = item.Id
+ detail.Language = item.Language
+ detail.Fields = toFields(item.Fileds)
+ }
+
+ return r, nil
+}
+
+// List
+func (adapter *dcoLinkAdapter) List(platform string, orgs []string) ([]models.LinkInfo, models.IModelError) {
+ v, err := adapter.s.List(&app.CmdToListLink{
+ Platform: platform,
+ Orgs: orgs,
+ })
+ if err != nil {
+ return nil, toModelError(err)
+ }
+
+ r := make([]models.LinkInfo, len(v))
+ for i := range v {
+ item := &v[i]
+
+ li := &r[i]
+
+ li.LinkID = item.Id
+ li.Submitter = item.Submitter
+
+ li.OrgID = item.Org.Org
+ li.Platform = item.Org.Platform
+
+ li.OrgAlias = item.Org.Alias
+ li.OrgEmail = item.Email.Addr.EmailAddr()
+ li.OrgEmailPlatform = item.Email.Platform
+ }
+
+ return r, nil
+}
+
+// Remove
+func (adapter *dcoLinkAdapter) Remove(linkId string) models.IModelError {
+ if err := adapter.s.Remove(linkId); err != nil {
+ return toModelError(err)
+ }
+
+ return nil
+}
+
+// Add
+func (adapter *dcoLinkAdapter) Add(submitter string, opt *models.DCOLinkCreateOption) models.IModelError {
+ cmd, err := adapter.cmdToAddLink(submitter, opt)
+ if err != nil {
+ return errBadRequestParameter(err)
+ }
+
+ if err := adapter.s.Add(&cmd); err != nil {
+ return toModelError(err)
+ }
+
+ return nil
+}
+
+func (adapter *dcoLinkAdapter) cmdToAddLink(submitter string, opt *models.DCOLinkCreateOption) (
+ cmd app.CmdToAddDCOLink, err error,
+) {
+ if opt.DCO == nil {
+ err = errors.New("no dco instance")
+
+ return
+ }
+
+ v, err := adapter.dco.cmdToAddDCO(opt.DCO)
+ if err != nil {
+ return
+ }
+ cmd.DCOs = append(cmd.DCOs, v)
+
+ if cmd.Email, err = dp.NewEmailAddr(opt.OrgEmail); err != nil {
+ return
+ }
+
+ cmd.Org.Org = opt.OrgID
+ cmd.Org.Alias = opt.OrgAlias
+ cmd.Org.Platform = opt.Platform
+ cmd.Submitter = submitter
+
+ return
+}
diff --git a/signing/adapter/error.go b/signing/adapter/error.go
index d515693..d738df0 100644
--- a/signing/adapter/error.go
+++ b/signing/adapter/error.go
@@ -115,6 +115,23 @@ func codeMap(code string) models.ModelErrCode {
case domain.ErrorCodeLinkCanNotRemove:
return models.ErrLinkIsUsed
+ // cla
+ case domain.ErrorCodeDCOExists:
+ return models.ErrDCOExists
+
+ case domain.ErrorCodeDCOCanNotRemove:
+ return models.ErrDCOIsUsed
+
+ // link
+ case domain.ErrorCodeDCOLinkNotExists:
+ return models.ErrNoDCOLink
+
+ case domain.ErrorCodeDCOLinkExists:
+ return models.ErrDCOLinkExists
+
+ case domain.ErrorCodeDCOLinkCanNotRemove:
+ return models.ErrDCOLinkIsUsed
+
// gmail
case domain.ErrorCodeGmailNoRefreshToken:
return models.ErrNoRefreshToken
diff --git a/signing/adapter/link.go b/signing/adapter/link.go
index ff449fd..329b4e3 100644
--- a/signing/adapter/link.go
+++ b/signing/adapter/link.go
@@ -48,7 +48,7 @@ func (adapter *linkAdatper) GetLink(linkId string) (
func (adapter *linkAdatper) GetLinkCLA(linkId, claId string) (
org models.OrgInfo, cla models.CLAInfo, merr models.IModelError,
) {
- v, err := adapter.s.FindLinkCLA(&domain.CLAIndex{
+ v, err := adapter.s.FindCLA(&domain.CLAIndex{
LinkId: linkId,
CLAId: claId,
})
@@ -67,7 +67,7 @@ func (adapter *linkAdatper) GetLinkCLA(linkId, claId string) (
cla.CLAId = v.CLA.Id
cla.CLAFile = v.CLA.LocalFile
cla.CLALang = v.CLA.Language
- cla.Fields = adapter.toFields(v.CLA.Fileds)
+ cla.Fields = toFields(v.CLA.Fileds)
return
}
@@ -94,13 +94,13 @@ func (adapter *linkAdatper) ListCLAs(linkId, applyTo string) ([]models.CLADetail
detail := &r[i]
detail.CLAId = item.Id
detail.Language = item.Language
- detail.Fields = adapter.toFields(item.Fileds)
+ detail.Fields = toFields(item.Fileds)
}
return r, nil
}
-func (adapter *linkAdatper) toFields(fields []domain.Field) []models.CLAField {
+func toFields(fields []domain.Field) []models.CLAField {
r := make([]models.CLAField, len(fields))
for i := range fields {
diff --git a/signing/app/cla.go b/signing/app/cla.go
index 8b193de..79e9b5e 100644
--- a/signing/app/cla.go
+++ b/signing/app/cla.go
@@ -36,8 +36,25 @@ type claService struct {
individual repository.IndividualSigning
}
+func (s *claService) findLink(linkId string) (domain.Link, error) {
+ v, err := s.repo.Find(linkId)
+ if err != nil {
+ if commonRepo.IsErrorResourceNotFound(err) {
+ err = domain.NewDomainError(domain.ErrorCodeLinkNotExists)
+ }
+
+ return v, err
+ }
+
+ if !dp.IsLinkTypeCLA(v.Type) {
+ return v, domain.NewDomainError(domain.ErrorCodeLinkNotExists)
+ }
+
+ return v, nil
+}
+
func (s *claService) Add(linkId string, cmd *CmdToAddCLA) error {
- link, err := s.repo.Find(linkId)
+ link, err := s.findLink(linkId)
if err != nil {
if commonRepo.IsErrorResourceNotFound(err) {
err = domain.NewDomainError(domain.ErrorCodeLinkNotExists)
@@ -52,7 +69,7 @@ func (s *claService) Add(linkId string, cmd *CmdToAddCLA) error {
}
func (s *claService) Remove(cmd domain.CLAIndex) error {
- link, err := s.repo.Find(cmd.LinkId)
+ link, err := s.findLink(cmd.LinkId)
if err != nil {
if commonRepo.IsErrorResourceNotFound(err) {
err = domain.NewDomainError(domain.ErrorCodeLinkNotExists)
@@ -115,7 +132,7 @@ func (s *claService) checkIfCanRemoveCorpCLA(cmd *domain.CLAIndex) (bool, error)
}
func (s *claService) List(linkId string) (individuals []CLADTO, corps []CLADTO, err error) {
- v, err := s.repo.Find(linkId)
+ v, err := s.findLink(linkId)
if err != nil {
return
}
diff --git a/signing/app/dco.go b/signing/app/dco.go
new file mode 100644
index 0000000..9bcfec1
--- /dev/null
+++ b/signing/app/dco.go
@@ -0,0 +1,125 @@
+package app
+
+import (
+ commonRepo "github.com/opensourceways/app-cla-server/common/domain/repository"
+ "github.com/opensourceways/app-cla-server/signing/domain"
+ "github.com/opensourceways/app-cla-server/signing/domain/claservice"
+ "github.com/opensourceways/app-cla-server/signing/domain/dp"
+ "github.com/opensourceways/app-cla-server/signing/domain/repository"
+)
+
+func NewDCOService(
+ repo repository.Link,
+ dco claservice.CLAService,
+ individual repository.IndividualSigning,
+) *dcoService {
+ return &dcoService{
+ repo: repo,
+ dco: dco,
+ individual: individual,
+ }
+}
+
+type DCOService interface {
+ Add(linkId string, cmd *CmdToAddDCO) error
+ Remove(cmd domain.CLAIndex) error
+ DCOLocalFilePath(domain.CLAIndex) string
+ List(linkId string) ([]CLADTO, error)
+}
+
+type dcoService struct {
+ repo repository.Link
+ dco claservice.CLAService
+ individual repository.IndividualSigning
+}
+
+func (s *dcoService) findLink(linkId string) (domain.Link, error) {
+ v, err := s.repo.Find(linkId)
+ if err != nil {
+ if commonRepo.IsErrorResourceNotFound(err) {
+ err = domain.NewDomainError(domain.ErrorCodeDCOLinkNotExists)
+ }
+
+ return v, err
+ }
+
+ if dp.IsLinkTypeCLA(v.Type) {
+ return v, domain.NewDomainError(domain.ErrorCodeDCOLinkNotExists)
+ }
+
+ return v, nil
+}
+
+func (s *dcoService) Add(linkId string, cmd *CmdToAddDCO) error {
+ link, err := s.findLink(linkId)
+ if err != nil {
+ if commonRepo.IsErrorResourceNotFound(err) {
+ err = domain.NewDomainError(domain.ErrorCodeDCOLinkNotExists)
+ }
+
+ return err
+ }
+
+ v := cmd.toDCO()
+
+ return s.dco.Add(&link, &v)
+}
+
+func (s *dcoService) Remove(cmd domain.CLAIndex) error {
+ link, err := s.findLink(cmd.LinkId)
+ if err != nil {
+ if commonRepo.IsErrorResourceNotFound(err) {
+ err = domain.NewDomainError(domain.ErrorCodeDCOLinkNotExists)
+ }
+
+ return err
+ }
+
+ cla := link.FindCLA(cmd.CLAId)
+ if cla == nil {
+ return domain.NewDomainError(domain.ErrorCodeDCONotExists)
+ }
+
+ if err := s.checkIfCanRemove(&cmd); err != nil {
+ return err
+ }
+
+ return s.repo.RemoveCLA(&link, cla)
+}
+
+func (s *dcoService) checkIfCanRemove(cmd *domain.CLAIndex) error {
+ v, err := s.individual.HasSignedCLA(cmd)
+ if err != nil {
+ return err
+ }
+ if v {
+ return domain.NewDomainError(domain.ErrorCodeDCOCanNotRemove)
+ }
+
+ return nil
+}
+
+func (s *dcoService) List(linkId string) (dcos []CLADTO, err error) {
+ v, err := s.findLink(linkId)
+ if err != nil {
+ return
+ }
+
+ dcos = make([]CLADTO, 0, len(v.CLAs))
+
+ for i := range v.CLAs {
+ item := &v.CLAs[i]
+
+ dcos = append(dcos, CLADTO{
+ Id: item.Id,
+ URL: item.URL.URL(),
+ Language: item.Language.Language(),
+ })
+ }
+
+ return
+}
+
+func (s *dcoService) DCOLocalFilePath(index domain.CLAIndex) string {
+ return s.dco.CLALocalFilePath(&index)
+}
diff --git a/signing/app/dco_dto.go b/signing/app/dco_dto.go
new file mode 100644
index 0000000..b48d702
--- /dev/null
+++ b/signing/app/dco_dto.go
@@ -0,0 +1,23 @@
+package app
+
+import (
+ "github.com/opensourceways/app-cla-server/signing/domain"
+ "github.com/opensourceways/app-cla-server/signing/domain/dp"
+)
+
+type CmdToAddDCO struct {
+ URL dp.URL
+ Text []byte
+ Fields []domain.Field
+ Language dp.Language
+}
+
+func (cmd *CmdToAddDCO) toDCO() domain.CLA {
+ return domain.CLA{
+ URL: cmd.URL,
+ Text: cmd.Text,
+ Type: dp.CLATypeIndividual,
+ Fields: cmd.Fields,
+ Language: cmd.Language,
+ }
+}
diff --git a/signing/app/dco_link.go b/signing/app/dco_link.go
new file mode 100644
index 0000000..fd59764
--- /dev/null
+++ b/signing/app/dco_link.go
@@ -0,0 +1,113 @@
+package app
+
+import (
+ commonRepo "github.com/opensourceways/app-cla-server/common/domain/repository"
+ "github.com/opensourceways/app-cla-server/signing/domain"
+ "github.com/opensourceways/app-cla-server/signing/domain/claservice"
+ "github.com/opensourceways/app-cla-server/signing/domain/dp"
+ "github.com/opensourceways/app-cla-server/signing/domain/repository"
+)
+
+func NewDCOLinkService(
+ repo repository.Link,
+ dco claservice.CLAService,
+ individual repository.IndividualSigning,
+ emailCredential repository.EmailCredential,
+) *dcoLinkService {
+ return &dcoLinkService{
+ repo: repo,
+ dco: dco,
+ individual: individual,
+ emailCredential: emailCredential,
+ }
+}
+
+type DCOLinkService interface {
+ Add(cmd *CmdToAddDCOLink) error
+ Remove(linkId string) error
+ List(cmd *CmdToListLink) ([]repository.LinkSummary, error)
+ FindDCOs(string) ([]CLADetailDTO, error)
+}
+
+type dcoLinkService struct {
+ repo repository.Link
+ dco claservice.CLAService
+ individual repository.IndividualSigning
+ emailCredential repository.EmailCredential
+}
+
+func (s *dcoLinkService) Add(cmd *CmdToAddDCOLink) error {
+ v, err := s.emailCredential.Find(cmd.Email)
+ if err != nil {
+ return err
+ }
+
+ link := cmd.toDCOLink()
+ link.Email = domain.EmailInfo{
+ Addr: cmd.Email,
+ Platform: v.Platform,
+ }
+
+ return s.dco.AddLink(&link)
+}
+
+func (s *dcoLinkService) Remove(linkId string) error {
+ b, err := s.checkIfCanRemove(linkId)
+ if err != nil {
+ return err
+ }
+ if !b {
+ return domain.NewDomainError(domain.ErrorCodeDCOLinkCanNotRemove)
+ }
+
+ v, err := s.repo.Find(linkId)
+ if err != nil {
+ if commonRepo.IsErrorResourceNotFound(err) {
+ return nil
+ }
+
+ return err
+ }
+
+ if dp.IsLinkTypeCLA(v.Type) {
+ return nil
+ }
+
+ return s.repo.Remove(&v)
+}
+
+func (s *dcoLinkService) checkIfCanRemove(linkId string) (bool, error) {
+ v, err := s.individual.HasSignedLink(linkId)
+
+ return !v, err
+}
+
+func (s *dcoLinkService) List(cmd *CmdToListLink) ([]repository.LinkSummary, error) {
+ opt := cmd.toOpt(dp.LinkTypeDCO)
+
+ return s.repo.FindAll(&opt)
+}
+
+func (s *dcoLinkService) FindDCOs(linkId string) ([]CLADetailDTO, error) {
+ v, err := s.repo.Find(linkId)
+ if err != nil {
+ return nil, err
+ }
+
+ if dp.IsLinkTypeCLA(v.Type) {
+ return nil, nil
+ }
+
+ r := make([]CLADetailDTO, 0, len(v.CLAs))
+ for i := range v.CLAs {
+ item := &v.CLAs[i]
+
+ r = append(r, CLADetailDTO{
+ Id: item.Id,
+ Fileds: item.Fields,
+ Language: item.Language.Language(),
+ })
+ }
+
+ return r, nil
+}
diff --git a/signing/app/dco_link_dto.go b/signing/app/dco_link_dto.go
new file mode 100644
index 0000000..e51262e
--- /dev/null
+++ b/signing/app/dco_link_dto.go
@@ -0,0 +1,31 @@
+package app
+
+import (
+ "strconv"
+
+ "github.com/opensourceways/app-cla-server/signing/domain"
+ "github.com/opensourceways/app-cla-server/signing/domain/dp"
+)
+
+type CmdToAddDCOLink struct {
+ Org domain.OrgInfo
+ Email dp.EmailAddr
+ DCOs []CmdToAddDCO
+ Submitter string
+}
+
+func (cmd *CmdToAddDCOLink) toDCOLink() domain.Link {
+ v := make([]domain.CLA, len(cmd.DCOs))
+ for i := range cmd.DCOs {
+ v[i] = cmd.DCOs[i].toDCO()
+ v[i].Id = strconv.Itoa(i)
+ }
+
+ return domain.Link{
+ Type: dp.LinkTypeDCO,
+ Org: cmd.Org,
+ CLAs: v,
+ CLANum: len(cmd.DCOs),
+ Submitter: cmd.Submitter,
+ }
+}
diff --git a/signing/app/link.go b/signing/app/link.go
index 4f110d6..a26cf10 100644
--- a/signing/app/link.go
+++ b/signing/app/link.go
@@ -4,6 +4,7 @@ import (
commonRepo "github.com/opensourceways/app-cla-server/common/domain/repository"
"github.com/opensourceways/app-cla-server/signing/domain"
"github.com/opensourceways/app-cla-server/signing/domain/claservice"
+ "github.com/opensourceways/app-cla-server/signing/domain/dp"
"github.com/opensourceways/app-cla-server/signing/domain/repository"
)
@@ -29,7 +30,7 @@ type LinkService interface {
List(cmd *CmdToListLink) ([]repository.LinkSummary, error)
Find(linkId string) (dto LinkDTO, err error)
FindCLAs(cmd *CmdToFindCLAs) ([]CLADetailDTO, error)
- FindLinkCLA(cmd *domain.CLAIndex) (dto LinkCLADTO, err error)
+ FindCLA(cmd *domain.CLAIndex) (dto LinkCLADTO, err error)
}
type linkService struct {
@@ -73,6 +74,10 @@ func (s *linkService) Remove(linkId string) error {
return err
}
+ if !dp.IsLinkTypeCLA(v.Type) {
+ return nil
+ }
+
return s.repo.Remove(&v)
}
@@ -91,7 +96,9 @@ func (s *linkService) checkIfCanRemove(linkId string) (bool, error) {
}
func (s *linkService) List(cmd *CmdToListLink) ([]repository.LinkSummary, error) {
- return s.repo.FindAll(cmd)
+ opt := cmd.toOpt(dp.LinkTypeCLA)
+
+ return s.repo.FindAll(&opt)
}
func (s *linkService) FindCLAs(cmd *CmdToFindCLAs) ([]CLADetailDTO, error) {
@@ -100,6 +107,10 @@ func (s *linkService) FindCLAs(cmd *CmdToFindCLAs) ([]CLADetailDTO, error) {
return nil, err
}
+ if !dp.IsLinkTypeCLA(v.Type) {
+ return nil, nil
+ }
+
t := cmd.Type.CLAType()
r := make([]CLADetailDTO, 0, len(v.CLAs))
@@ -118,7 +129,7 @@ func (s *linkService) FindCLAs(cmd *CmdToFindCLAs) ([]CLADetailDTO, error) {
return r, nil
}
-func (s *linkService) FindLinkCLA(cmd *domain.CLAIndex) (dto LinkCLADTO, err error) {
+func (s *linkService) FindCLA(cmd *domain.CLAIndex) (dto LinkCLADTO, err error) {
v, err := s.repo.Find(cmd.LinkId)
if err != nil {
return
diff --git a/signing/app/link_dto.go b/signing/app/link_dto.go
index b86df11..acd79a5 100644
--- a/signing/app/link_dto.go
+++ b/signing/app/link_dto.go
@@ -23,6 +23,7 @@ func (cmd *CmdToAddLink) toLink() domain.Link {
}
return domain.Link{
+ Type: dp.LinkTypeCLA,
Org: cmd.Org,
CLAs: v,
CLANum: len(cmd.CLAs),
@@ -30,8 +31,6 @@ func (cmd *CmdToAddLink) toLink() domain.Link {
}
}
-type CmdToListLink = repository.FindLinksOpt
-
type CmdToFindCLAs struct {
LinkId string
Type dp.CLAType
@@ -47,3 +46,16 @@ type LinkDTO struct {
Org domain.OrgInfo
Email domain.EmailInfo
}
+
+type CmdToListLink struct {
+ Orgs []string
+ Platform string
+}
+
+func (cmd *CmdToListLink) toOpt(t dp.LinkType) repository.FindLinksOpt {
+ return repository.FindLinksOpt{
+ Type: t,
+ Orgs: cmd.Orgs,
+ Platform: cmd.Platform,
+ }
+}
diff --git a/signing/domain/claservice/service.go b/signing/domain/claservice/service.go
index d2c2da4..8a9c108 100644
--- a/signing/domain/claservice/service.go
+++ b/signing/domain/claservice/service.go
@@ -1,9 +1,7 @@
package claservice
import (
- "fmt"
"github.com/beego/beego/v2/core/logs"
- "time"
commonRepo "github.com/opensourceways/app-cla-server/common/domain/repository"
"github.com/opensourceways/app-cla-server/signing/domain"
@@ -56,9 +54,6 @@ func (s *claService) CLALocalFilePath(index *domain.CLAIndex) string {
}
func (s *claService) AddLink(link *domain.Link) error {
- linkId := genLinkID(link)
- link.Id = linkId
-
tempFiles := []string{}
clean := func() {
for _, p := range tempFiles {
@@ -68,10 +63,12 @@ func (s *claService) AddLink(link *domain.Link) error {
}
}
+ link.Id = link.Org.LinkId()
+
for i := range link.CLAs {
item := &link.CLAs[i]
- p, err := s.local.AddCLA(linkId, item)
+ p, err := s.local.AddCLA(link.Id, item)
if err != nil {
clean()
@@ -93,9 +90,3 @@ func (s *claService) AddLink(link *domain.Link) error {
return nil
}
-
-func genLinkID(v *domain.Link) string {
- org := &v.Org
-
- return fmt.Sprintf("%s_%s-%d", org.Platform, org.Org, time.Now().UnixNano())
-}
diff --git a/signing/domain/dp/link_type.go b/signing/domain/dp/link_type.go
new file mode 100644
index 0000000..8bf6fdd
--- /dev/null
+++ b/signing/domain/dp/link_type.go
@@ -0,0 +1,34 @@
+package dp
+
+import "errors"
+
+var (
+ LinkTypeCLA = linkType("cla")
+ LinkTypeDCO = linkType("dco")
+)
+
+type LinkType interface {
+ LinkType() string
+}
+
+type linkType string
+
+func (v linkType) LinkType() string {
+ return string(v)
+}
+
+func NewLinkType(v string) (LinkType, error) {
+ if v == LinkTypeCLA.LinkType() {
+ return LinkTypeCLA, nil
+ }
+
+ if v == LinkTypeDCO.LinkType() {
+ return LinkTypeDCO, nil
+ }
+
+ return nil, errors.New("invalid link type")
+}
+
+func IsLinkTypeCLA(v LinkType) bool {
+ return v != nil && v.LinkType() == LinkTypeCLA.LinkType()
+}
diff --git a/signing/domain/error.go b/signing/domain/error.go
index 547909f..13036b4 100644
--- a/signing/domain/error.go
+++ b/signing/domain/error.go
@@ -54,6 +54,14 @@ const (
ErrorCodeLinkExists = "link_exists"
ErrorCodeLinkNotExists = "link_not_exists"
ErrorCodeLinkCanNotRemove = "link_can_not_remove"
+
+ ErrorCodeDCOExists = "dco_exists"
+ ErrorCodeDCONotExists = "dco_not_exists"
+ ErrorCodeDCOCanNotRemove = "dco_can_not_remove"
+
+ ErrorCodeDCOLinkExists = "dco_link_exists"
+ ErrorCodeDCOLinkNotExists = "dco_link_not_exists"
+ ErrorCodeDCOLinkCanNotRemove = "dco_link_can_not_remove"
)
// domainError
diff --git a/signing/domain/link.go b/signing/domain/link.go
index b95db7c..029e2ac 100644
--- a/signing/domain/link.go
+++ b/signing/domain/link.go
@@ -1,7 +1,9 @@
package domain
import (
+ "fmt"
"strconv"
+ "time"
"github.com/opensourceways/app-cla-server/signing/domain/dp"
)
@@ -17,10 +19,15 @@ type OrgInfo struct {
Alias string
}
+func (v *OrgInfo) LinkId() string {
+ return fmt.Sprintf("%s_%s-%d", v.Platform, v.Org, time.Now().UnixNano())
+}
+
type Link struct {
Id string
Org OrgInfo
Email EmailInfo
+ Type dp.LinkType
CLAs []CLA
Submitter string
CLANum int
diff --git a/signing/domain/repository/link.go b/signing/domain/repository/link.go
index f26f58d..067e46b 100644
--- a/signing/domain/repository/link.go
+++ b/signing/domain/repository/link.go
@@ -1,10 +1,14 @@
package repository
-import "github.com/opensourceways/app-cla-server/signing/domain"
+import (
+ "github.com/opensourceways/app-cla-server/signing/domain"
+ "github.com/opensourceways/app-cla-server/signing/domain/dp"
+)
type FindLinksOpt struct {
- Platform string
+ Type dp.LinkType
Orgs []string
+ Platform string
}
type LinkSummary struct {
diff --git a/signing/infrastructure/repositoryimpl/link.go b/signing/infrastructure/repositoryimpl/link.go
index f860600..084096a 100644
--- a/signing/infrastructure/repositoryimpl/link.go
+++ b/signing/infrastructure/repositoryimpl/link.go
@@ -89,6 +89,7 @@ func (impl *link) Find(linkId string) (r domain.Link, err error) {
func (impl *link) FindAll(opt *repository.FindLinksOpt) ([]repository.LinkSummary, error) {
filter := bson.M{
fieldDeleted: false,
+ fieldType: opt.Type.LinkType(),
childField(fieldOrg, fieldOrg): bson.M{mongodbCmdIn: opt.Orgs},
childField(fieldOrg, fieldPlatform): opt.Platform,
}
diff --git a/signing/infrastructure/repositoryimpl/link_do.go b/signing/infrastructure/repositoryimpl/link_do.go
index 8d32860..bda6f3e 100644
--- a/signing/infrastructure/repositoryimpl/link_do.go
+++ b/signing/infrastructure/repositoryimpl/link_do.go
@@ -10,6 +10,7 @@ import (
const (
fieldOrg = "org"
fieldCLAs = "clas"
+ fieldType = "type"
fieldRemoved = "removed"
fieldPlatform = "platform"
)
@@ -19,6 +20,7 @@ func toLinkDO(v *domain.Link) linkDO {
Id: v.Id,
Org: toOrgInfoDO(&v.Org),
Email: toEmailInfoDO(&v.Email),
+ Type: v.Type.LinkType(),
Submitter: v.Submitter,
CLANum: v.CLANum,
}
@@ -37,6 +39,7 @@ type linkDO struct {
Id string `bson:"id" json:"id" required:"true"`
Org orgInfoDO `bson:"org" json:"org" required:"true"`
Email emailInfoDO `bson:"email" json:"email" required:"true"`
+ Type string `bson:"type" json:"type" required:"true"`
Submitter string `bson:"submitter" json:"submitter" required:"true"`
CLAs []claDO `bson:"clas" json:"clas"`
CLANum int `bson:"cla_num" json:"cla_num"`
@@ -51,6 +54,11 @@ func (do *linkDO) toLink(link *domain.Link) (err error) {
return
}
+ t, err := dp.NewLinkType(do.Type)
+ if err != nil {
+ return
+ }
+
clas := make([]domain.CLA, len(do.CLAs))
for i := range do.CLAs {
if clas[i], err = do.CLAs[i].toCLA(); err != nil {
@@ -62,6 +70,7 @@ func (do *linkDO) toLink(link *domain.Link) (err error) {
Id: do.Id,
Org: do.Org.toOrgInfo(),
Email: e,
+ Type: t,
CLAs: clas,
Submitter: do.Submitter,
CLANum: do.CLANum,
diff --git a/swagger/swagger.json b/swagger/swagger.json
index 6dd8b0b..4b5265b 100644
--- a/swagger/swagger.json
+++ b/swagger/swagger.json
@@ -1020,6 +1020,290 @@
}
}
},
+ "/dco-link/": {
+ "get": {
+ "tags": [
+ "dco-link"
+ ],
+ "description": "list all links\n\u003cbr\u003e",
+ "operationId": "DCOLinkController.List",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "responses": {
+ "200": {
+ "description": "",
+ "schema": {
+ "$ref": "#/definitions/models.LinkInfo"
+ }
+ },
+ "401": {
+ "description": "missing_token: token is missing"
+ },
+ "402": {
+ "description": "unknown_token: token is unknown"
+ },
+ "403": {
+ "description": "expired_token: token is expired"
+ },
+ "404": {
+ "description": "unauthorized_token: the permission of token is unmatched"
+ },
+ "500": {
+ "description": "system_error: system error"
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "dco-link"
+ ],
+ "description": "create a link(dco application)\n\u003cbr\u003e",
+ "operationId": "DCOLinkController.Create",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "body",
+ "name": "body",
+ "description": "body for creating link",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/models.DCOLinkCreateOption"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "",
+ "schema": {
+ "$ref": "#/definitions/controllers.respData"
+ }
+ }
+ }
+ }
+ },
+ "/dco-link/{link_id}": {
+ "delete": {
+ "tags": [
+ "dco-link"
+ ],
+ "description": "delete link\n\u003cbr\u003e",
+ "operationId": "DCOLinkController.Delete",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "path",
+ "name": "link_id",
+ "description": "link id",
+ "required": true,
+ "type": "string"
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "",
+ "schema": {
+ "$ref": "#/definitions/controllers.respData"
+ }
+ }
+ }
+ }
+ },
+ "/dco-link/{link_id}/dcos": {
+ "get": {
+ "tags": [
+ "dco-link"
+ ],
+ "description": "get signing page info\n\u003cbr\u003e",
+ "operationId": "DCOLinkController.GetDCOForSigning",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "path",
+ "name": "link_id",
+ "description": "link id",
+ "required": true,
+ "type": "string"
+ },
+ {
+ "in": "path",
+ "name": "apply_to",
+ "description": "apply to",
+ "required": true,
+ "type": "string"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "",
+ "schema": {
+ "$ref": "#/definitions/models.CLADetail"
+ }
+ },
+ "util.ErrNoCLABindingDoc": {
+ "description": "\"org has not been bound any clas\""
+ },
+ "util.ErrNotReadyToSign": {
+ "description": "\"the corp signing is not ready\""
+ }
+ }
+ }
+ },
+ "/dco/{link_id}": {
+ "get": {
+ "tags": [
+ "dco"
+ ],
+ "description": "list dcos of link\n\u003cbr\u003e",
+ "operationId": "DCOController.List",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "path",
+ "name": "link_id",
+ "description": "link id",
+ "required": true,
+ "type": "string"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "",
+ "schema": {
+ "$ref": "#/definitions/models.CLADetail"
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "dco"
+ ],
+ "description": "add dco\n\u003cbr\u003e",
+ "operationId": "DCOController.Add",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "body",
+ "name": "body",
+ "description": "body for adding dco",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/models.DCOCreateOpt"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "",
+ "schema": {
+ "$ref": "#/definitions/controllers.respData"
+ }
+ }
+ }
+ }
+ },
+ "/dco/{link_id}/{id}": {
+ "get": {
+ "tags": [
+ "dco"
+ ],
+ "description": "get dco pdf\n\u003cbr\u003e",
+ "operationId": "DCOController.DownloadPDF",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "path",
+ "name": "link_id",
+ "description": "link id",
+ "required": true,
+ "type": "string"
+ },
+ {
+ "in": "path",
+ "name": "id",
+ "description": "dco id",
+ "required": true,
+ "type": "string"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": ""
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "dco"
+ ],
+ "description": "delete dco\n\u003cbr\u003e",
+ "operationId": "DCOController.Delete",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "in": "path",
+ "name": "link_id",
+ "description": "link id",
+ "required": true,
+ "type": "string"
+ },
+ {
+ "in": "path",
+ "name": "id",
+ "description": "dco id",
+ "required": true,
+ "type": "string"
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "",
+ "schema": {
+ "$ref": "#/definitions/controllers.respData"
+ }
+ }
+ }
+ }
+ },
"/employee-manager/": {
"get": {
"tags": [
@@ -1581,7 +1865,7 @@
"link"
],
"description": "create a link(cla application)\n\u003cbr\u003e",
- "operationId": "LinkController.Link",
+ "operationId": "LinkController.Create",
"consumes": [
"application/json"
],
@@ -2214,6 +2498,48 @@
}
}
},
+ "models.DCOCreateOpt": {
+ "title": "DCOCreateOpt",
+ "type": "object",
+ "properties": {
+ "fields": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/models.CLAField"
+ }
+ },
+ "language": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string"
+ }
+ }
+ },
+ "models.DCOLinkCreateOption": {
+ "title": "DCOLinkCreateOption",
+ "type": "object",
+ "properties": {
+ "dco": {
+ "$ref": "#/definitions/models.DCOCreateOpt"
+ },
+ "org_alias": {
+ "type": "string"
+ },
+ "org_email": {
+ "type": "string"
+ },
+ "org_id": {
+ "type": "string"
+ },
+ "platform": {
+ "type": "string"
+ },
+ "repo_id": {
+ "type": "string"
+ }
+ }
+ },
"models.EmailAuthorization": {
"title": "EmailAuthorization",
"type": "object",
diff --git a/swagger/swagger.yml b/swagger/swagger.yml
index 42fb315..712024f 100644
--- a/swagger/swagger.yml
+++ b/swagger/swagger.yml
@@ -733,6 +733,210 @@ paths:
community'
"500":
description: 'system_error: system error'
+ /dco-link/:
+ get:
+ tags:
+ - dco-link
+ description: |-
+ list all links
+
+ operationId: DCOLinkController.List
+ consumes:
+ - application/json
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: ""
+ schema:
+ $ref: '#/definitions/models.LinkInfo'
+ "401":
+ description: 'missing_token: token is missing'
+ "402":
+ description: 'unknown_token: token is unknown'
+ "403":
+ description: 'expired_token: token is expired'
+ "404":
+ description: 'unauthorized_token: the permission of token is unmatched'
+ "500":
+ description: 'system_error: system error'
+ post:
+ tags:
+ - dco-link
+ description: |-
+ create a link(dco application)
+
+ operationId: DCOLinkController.Create
+ consumes:
+ - application/json
+ produces:
+ - application/json
+ parameters:
+ - in: body
+ name: body
+ description: body for creating link
+ required: true
+ schema:
+ $ref: '#/definitions/models.DCOLinkCreateOption'
+ responses:
+ "201":
+ description: ""
+ schema:
+ $ref: '#/definitions/controllers.respData'
+ /dco-link/{link_id}:
+ delete:
+ tags:
+ - dco-link
+ description: |-
+ delete link
+
+ operationId: DCOLinkController.Delete
+ consumes:
+ - application/json
+ produces:
+ - application/json
+ parameters:
+ - in: path
+ name: link_id
+ description: link id
+ required: true
+ type: string
+ responses:
+ "204":
+ description: ""
+ schema:
+ $ref: '#/definitions/controllers.respData'
+ /dco-link/{link_id}/dcos:
+ get:
+ tags:
+ - dco-link
+ description: |-
+ get signing page info
+
+ operationId: DCOLinkController.GetDCOForSigning
+ consumes:
+ - application/json
+ produces:
+ - application/json
+ parameters:
+ - in: path
+ name: link_id
+ description: link id
+ required: true
+ type: string
+ - in: path
+ name: apply_to
+ description: apply to
+ required: true
+ type: string
+ responses:
+ "200":
+ description: ""
+ schema:
+ $ref: '#/definitions/models.CLADetail'
+ util.ErrNoCLABindingDoc:
+ description: '"org has not been bound any clas"'
+ util.ErrNotReadyToSign:
+ description: '"the corp signing is not ready"'
+ /dco/{link_id}:
+ get:
+ tags:
+ - dco
+ description: |-
+ list dcos of link
+
+ operationId: DCOController.List
+ consumes:
+ - application/json
+ produces:
+ - application/json
+ parameters:
+ - in: path
+ name: link_id
+ description: link id
+ required: true
+ type: string
+ responses:
+ "200":
+ description: ""
+ schema:
+ $ref: '#/definitions/models.CLADetail'
+ post:
+ tags:
+ - dco
+ description: |-
+ add dco
+
+ operationId: DCOController.Add
+ consumes:
+ - application/json
+ produces:
+ - application/json
+ parameters:
+ - in: body
+ name: body
+ description: body for adding dco
+ required: true
+ schema:
+ $ref: '#/definitions/models.DCOCreateOpt'
+ responses:
+ "201":
+ description: ""
+ schema:
+ $ref: '#/definitions/controllers.respData'
+ /dco/{link_id}/{id}:
+ get:
+ tags:
+ - dco
+ description: |-
+ get dco pdf
+
+ operationId: DCOController.DownloadPDF
+ consumes:
+ - application/json
+ produces:
+ - application/json
+ parameters:
+ - in: path
+ name: link_id
+ description: link id
+ required: true
+ type: string
+ - in: path
+ name: id
+ description: dco id
+ required: true
+ type: string
+ responses:
+ "200":
+ description: ""
+ delete:
+ tags:
+ - dco
+ description: |-
+ delete dco
+
+ operationId: DCOController.Delete
+ consumes:
+ - application/json
+ produces:
+ - application/json
+ parameters:
+ - in: path
+ name: link_id
+ description: link id
+ required: true
+ type: string
+ - in: path
+ name: id
+ description: dco id
+ required: true
+ type: string
+ responses:
+ "204":
+ description: ""
+ schema:
+ $ref: '#/definitions/controllers.respData'
/employee-manager/:
get:
tags:
@@ -1140,7 +1344,7 @@ paths:
description: |-
create a link(cla application)
- operationId: LinkController.Link
+ operationId: LinkController.Create
consumes:
- application/json
produces:
@@ -1573,6 +1777,34 @@ definitions:
type: string
pdf_uploaded:
type: boolean
+ models.DCOCreateOpt:
+ title: DCOCreateOpt
+ type: object
+ properties:
+ fields:
+ type: array
+ items:
+ $ref: '#/definitions/models.CLAField'
+ language:
+ type: string
+ url:
+ type: string
+ models.DCOLinkCreateOption:
+ title: DCOLinkCreateOption
+ type: object
+ properties:
+ dco:
+ $ref: '#/definitions/models.DCOCreateOpt'
+ org_alias:
+ type: string
+ org_email:
+ type: string
+ org_id:
+ type: string
+ platform:
+ type: string
+ repo_id:
+ type: string
models.EmailAuthorization:
title: EmailAuthorization
type: object