Skip to content

Commit 83ad62b

Browse files
Self registration (#1640)
* Added DB file for self registration * Check api for self registration * imported user service to add emailid * working self registration * changed response of check * changed sequence number for sql script Co-authored-by: nikeshDevtron <[email protected]>
1 parent 11d3bc2 commit 83ad62b

14 files changed

+374
-3
lines changed

214

Whitespace-only changes.

Wire.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ func InitializeApp() (*App, error) {
103103
wire.Build(
104104
// ----- wireset start
105105
sql.PgSqlWireSet,
106+
user.SelfRegistrationWireSet,
106107
externalLink.ExternalLinkWireSet,
107108
team.TeamsWireSet,
108109
AuthWireSet,

api/router/router.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ type MuxRouter struct {
102102
dashboardTelemetryRouter dashboardEvent.DashboardTelemetryRouter
103103
commonDeploymentRouter appStoreDeployment.CommonDeploymentRouter
104104
externalLinkRouter externalLink.ExternalLinkRouter
105+
selfRegistrationRolesRouter user.SelfRegistrationRolesRouter
105106
moduleRouter module.ModuleRouter
106107
serverRouter server.ServerRouter
107108
}
@@ -126,7 +127,7 @@ func NewMuxRouter(logger *zap.SugaredLogger, HelmRouter HelmRouter, PipelineConf
126127
commonRouter CommonRouter, grafanaRouter GrafanaRouter, ssoLoginRouter sso.SsoLoginRouter, telemetryRouter TelemetryRouter, telemetryWatcher telemetry.TelemetryEventClient, bulkUpdateRouter BulkUpdateRouter, webhookListenerRouter WebhookListenerRouter, appLabelsRouter AppLabelRouter,
127128
coreAppRouter CoreAppRouter, helmAppRouter client.HelmAppRouter, k8sApplicationRouter k8s.K8sApplicationRouter,
128129
pProfRouter PProfRouter, deploymentConfigRouter deployment.DeploymentConfigRouter, dashboardTelemetryRouter dashboardEvent.DashboardTelemetryRouter,
129-
commonDeploymentRouter appStoreDeployment.CommonDeploymentRouter, externalLinkRouter externalLink.ExternalLinkRouter, moduleRouter module.ModuleRouter,
130+
commonDeploymentRouter appStoreDeployment.CommonDeploymentRouter, externalLinkRouter externalLink.ExternalLinkRouter, moduleRouter module.ModuleRouter, selfRegistrationRolesRouter user.SelfRegistrationRolesRouter,
130131
serverRouter server.ServerRouter) *MuxRouter {
131132
r := &MuxRouter{
132133
Router: mux.NewRouter(),
@@ -184,6 +185,7 @@ func NewMuxRouter(logger *zap.SugaredLogger, HelmRouter HelmRouter, PipelineConf
184185
dashboardTelemetryRouter: dashboardTelemetryRouter,
185186
commonDeploymentRouter: commonDeploymentRouter,
186187
externalLinkRouter: externalLinkRouter,
188+
selfRegistrationRolesRouter: selfRegistrationRolesRouter,
187189
moduleRouter: moduleRouter,
188190
serverRouter: serverRouter,
189191
}
@@ -359,6 +361,9 @@ func (r MuxRouter) Init() {
359361
externalLinkRouter := r.Router.PathPrefix("/orchestrator/external-links").Subrouter()
360362
r.externalLinkRouter.InitExternalLinkRouter(externalLinkRouter)
361363

364+
selfRegistrationRolesRouter := r.Router.PathPrefix("/orchestrator/self-register").Subrouter()
365+
r.selfRegistrationRolesRouter.InitSelfRegistrationRolesRouter(selfRegistrationRolesRouter)
366+
362367
// module router
363368
moduleRouter := r.Router.PathPrefix("/orchestrator/module").Subrouter()
364369
r.moduleRouter.Init(moduleRouter)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package user
2+
3+
import (
4+
"encoding/json"
5+
"github.com/devtron-labs/devtron/api/bean"
6+
"github.com/devtron-labs/devtron/api/restHandler/common"
7+
"github.com/devtron-labs/devtron/pkg/user"
8+
"go.uber.org/zap"
9+
"net/http"
10+
)
11+
12+
type SelfRegistrationRolesHandler interface {
13+
SelfRegister(w http.ResponseWriter, r *http.Request)
14+
SelfRegisterCheck(w http.ResponseWriter, r *http.Request)
15+
}
16+
17+
type SelfRegistrationRolesHandlerImpl struct {
18+
logger *zap.SugaredLogger
19+
selfRegistrationRolesService user.SelfRegistrationRolesService
20+
}
21+
22+
func NewSelfRegistrationRolesHandlerImpl(logger *zap.SugaredLogger,
23+
selfRegistrationRolesService user.SelfRegistrationRolesService) *SelfRegistrationRolesHandlerImpl {
24+
return &SelfRegistrationRolesHandlerImpl{
25+
logger: logger,
26+
selfRegistrationRolesService: selfRegistrationRolesService,
27+
}
28+
}
29+
30+
func (impl *SelfRegistrationRolesHandlerImpl) SelfRegister(w http.ResponseWriter, r *http.Request) {
31+
32+
decoder := json.NewDecoder(r.Body)
33+
var userInfo bean.UserInfo
34+
err := decoder.Decode(&userInfo)
35+
if err != nil {
36+
impl.logger.Errorw("request err, selfRegister", "err", err, "payload", userInfo)
37+
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
38+
return
39+
}
40+
impl.selfRegistrationRolesService.SelfRegister(userInfo.EmailId)
41+
common.WriteJsonResp(w, nil, map[string]string{"status": "ok"}, http.StatusOK)
42+
}
43+
44+
func (impl *SelfRegistrationRolesHandlerImpl) SelfRegisterCheck(w http.ResponseWriter, r *http.Request) {
45+
res, err := impl.selfRegistrationRolesService.Check()
46+
if err != nil {
47+
impl.logger.Errorw("service err, Check", "err", err)
48+
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
49+
return
50+
}
51+
common.WriteJsonResp(w, err, map[string]bool{"enabled": res.Enabled}, http.StatusOK)
52+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package user
2+
3+
import (
4+
"github.com/gorilla/mux"
5+
"go.uber.org/zap"
6+
)
7+
8+
type SelfRegistrationRolesRouter interface {
9+
InitSelfRegistrationRolesRouter(router *mux.Router)
10+
}
11+
12+
type SelfRegistrationRolesRouterImpl struct {
13+
logger *zap.SugaredLogger
14+
selfRegistrationRolesHandler SelfRegistrationRolesHandler
15+
}
16+
17+
func NewSelfRegistrationRolesRouterImpl(logger *zap.SugaredLogger, selfRegistrationRolesHandler SelfRegistrationRolesHandler) *SelfRegistrationRolesRouterImpl {
18+
return &SelfRegistrationRolesRouterImpl{
19+
logger: logger,
20+
selfRegistrationRolesHandler: selfRegistrationRolesHandler,
21+
}
22+
}
23+
24+
func (impl *SelfRegistrationRolesRouterImpl) InitSelfRegistrationRolesRouter(router *mux.Router) {
25+
router.Path("").
26+
HandlerFunc(impl.selfRegistrationRolesHandler.SelfRegister).Methods("POST")
27+
router.Path("/check").
28+
HandlerFunc(impl.selfRegistrationRolesHandler.SelfRegisterCheck).Methods("GET")
29+
30+
}

api/user/wire_selfRegistration.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package user
2+
3+
import (
4+
"github.com/devtron-labs/devtron/pkg/user"
5+
"github.com/devtron-labs/devtron/pkg/user/repository"
6+
"github.com/google/wire"
7+
)
8+
9+
//depends on sql,
10+
//TODO integrate user auth module
11+
12+
var SelfRegistrationWireSet = wire.NewSet(
13+
repository.NewSelfRegistrationRolesRepositoryImpl,
14+
wire.Bind(new(repository.SelfRegistrationRolesRepository), new(*repository.SelfRegistrationRolesRepositoryImpl)),
15+
16+
user.NewSelfRegistrationRolesServiceImpl,
17+
wire.Bind(new(user.SelfRegistrationRolesService), new(*user.SelfRegistrationRolesServiceImpl)),
18+
NewSelfRegistrationRolesHandlerImpl,
19+
wire.Bind(new(SelfRegistrationRolesHandler), new(*SelfRegistrationRolesHandlerImpl)),
20+
NewSelfRegistrationRolesRouterImpl,
21+
wire.Bind(new(SelfRegistrationRolesRouter), new(*SelfRegistrationRolesRouterImpl)),
22+
)

api/user/wire_user.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,5 @@ var UserWireSet = wire.NewSet(
4242

4343
user.NewUserCommonServiceImpl,
4444
wire.Bind(new(user.UserCommonService), new(*user.UserCommonServiceImpl)),
45+
4546
)
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package user
2+
3+
import (
4+
"github.com/devtron-labs/devtron/api/bean"
5+
"github.com/devtron-labs/devtron/pkg/user/repository"
6+
"go.uber.org/zap"
7+
)
8+
9+
type SelfRegistrationRolesService interface {
10+
Check() (CheckResponse, error)
11+
SelfRegister(emailId string)
12+
}
13+
14+
type SelfRegistrationRolesServiceImpl struct {
15+
logger *zap.SugaredLogger
16+
selfRegistrationRolesRepository repository.SelfRegistrationRolesRepository
17+
userService UserService
18+
}
19+
20+
func NewSelfRegistrationRolesServiceImpl(logger *zap.SugaredLogger,
21+
selfRegistrationRolesRepository repository.SelfRegistrationRolesRepository, userService UserService) *SelfRegistrationRolesServiceImpl {
22+
return &SelfRegistrationRolesServiceImpl{
23+
logger: logger,
24+
selfRegistrationRolesRepository: selfRegistrationRolesRepository,
25+
userService: userService,
26+
}
27+
}
28+
29+
func (impl *SelfRegistrationRolesServiceImpl) GetAll() ([]string, error) {
30+
roleEntries, err := impl.selfRegistrationRolesRepository.GetAll()
31+
if err != nil {
32+
impl.logger.Errorf("error fetching all role %+v", err)
33+
return nil, err
34+
}
35+
var roles []string
36+
for _, role := range roleEntries {
37+
if role.Role != "" {
38+
roles = append(roles, role.Role)
39+
}
40+
}
41+
return roles, nil
42+
}
43+
44+
type CheckResponse struct {
45+
Enabled bool `json:"enabled"`
46+
Roles []string `json:"roles"`
47+
}
48+
49+
func (impl *SelfRegistrationRolesServiceImpl) Check() (CheckResponse, error) {
50+
roleEntries, err := impl.selfRegistrationRolesRepository.GetAll()
51+
var checkResponse CheckResponse
52+
if err != nil {
53+
impl.logger.Errorf("error fetching all role %+v", err)
54+
checkResponse.Enabled = false
55+
return checkResponse, err
56+
}
57+
//var roles []string
58+
if roleEntries != nil {
59+
for _, role := range roleEntries {
60+
if role.Role != "" {
61+
checkResponse.Roles = append(checkResponse.Roles, role.Role)
62+
checkResponse.Enabled = true
63+
//return checkResponse, err
64+
}
65+
}
66+
if checkResponse.Enabled == true {
67+
return checkResponse, err
68+
}
69+
checkResponse.Enabled = false
70+
return checkResponse, err
71+
}
72+
checkResponse.Enabled = false
73+
return checkResponse, nil
74+
}
75+
func (impl *SelfRegistrationRolesServiceImpl) SelfRegister(emailId string) {
76+
77+
roles, err := impl.Check()
78+
if err != nil || roles.Enabled == false {
79+
return
80+
}
81+
82+
userInfo := &bean.UserInfo{
83+
EmailId: emailId,
84+
Roles: roles.Roles,
85+
SuperAdmin: false,
86+
}
87+
_, err = impl.userService.SelfRegisterUserIfNotExists(userInfo)
88+
if err != nil {
89+
impl.logger.Errorw("error while register user", "error", err)
90+
}
91+
}

pkg/user/UserService.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636

3737
type UserService interface {
3838
CreateUser(userInfo *bean.UserInfo) ([]*bean.UserInfo, error)
39+
SelfRegisterUserIfNotExists(userInfo *bean.UserInfo) ([]*bean.UserInfo, error)
3940
UpdateUser(userInfo *bean.UserInfo) (*bean.UserInfo, error)
4041
GetById(id int32) (*bean.UserInfo, error)
4142
GetAll() ([]bean.UserInfo, error)
@@ -101,6 +102,114 @@ func (impl UserServiceImpl) validateUserRequest(userInfo *bean.UserInfo) (bool,
101102
return true, nil
102103
}
103104

105+
func (impl UserServiceImpl) SelfRegisterUserIfNotExists(userInfo *bean.UserInfo) ([]*bean.UserInfo, error) {
106+
var pass []string
107+
var userResponse []*bean.UserInfo
108+
emailIds := strings.Split(userInfo.EmailId, ",")
109+
dbConnection := impl.userRepository.GetConnection()
110+
tx, err := dbConnection.Begin()
111+
if err != nil {
112+
return nil, err
113+
}
114+
// Rollback tx on error.
115+
defer tx.Rollback()
116+
117+
var policies []casbin2.Policy
118+
for _, emailId := range emailIds {
119+
dbUser, err := impl.userRepository.FetchActiveOrDeletedUserByEmail(emailId)
120+
if err != nil && err != pg.ErrNoRows {
121+
impl.logger.Errorw("error while fetching user from db", "error", err)
122+
return nil, err
123+
}
124+
125+
//if found, update it with new roles
126+
if dbUser != nil && dbUser.Id > 0 {
127+
return nil, fmt.Errorf("existing user, cant self register")
128+
}
129+
130+
// if not found, create new user
131+
userInfo, err = impl.saveUser(userInfo, emailId)
132+
if err != nil {
133+
err = &util.ApiError{
134+
Code: constants.UserCreateDBFailed,
135+
InternalMessage: "failed to create new user in db",
136+
UserMessage: fmt.Sprintf("requested by %d", userInfo.UserId),
137+
}
138+
return nil, err
139+
}
140+
141+
roles, err := impl.userAuthRepository.GetRoleByRoles(userInfo.Roles)
142+
if err != nil {
143+
err = &util.ApiError{
144+
Code: constants.UserCreateDBFailed,
145+
InternalMessage: "configured roles for selfregister are wrong",
146+
UserMessage: fmt.Sprintf("requested by %d", userInfo.UserId),
147+
}
148+
return nil, err
149+
}
150+
for _, roleModel := range roles {
151+
userRoleModel := &repository2.UserRoleModel{UserId: userInfo.Id, RoleId: roleModel.Id}
152+
userRoleModel, err = impl.userAuthRepository.CreateUserRoleMapping(userRoleModel, tx)
153+
if err != nil {
154+
return nil, err
155+
}
156+
policies = append(policies, casbin2.Policy{Type: "g", Sub: casbin2.Subject(userInfo.EmailId), Obj: casbin2.Object(roleModel.Role)})
157+
}
158+
159+
pass = append(pass, emailId)
160+
userInfo.EmailId = emailId
161+
userInfo.Exist = dbUser.Active
162+
userResponse = append(userResponse, &bean.UserInfo{Id: userInfo.Id, EmailId: emailId, Groups: userInfo.Groups, RoleFilters: userInfo.RoleFilters, SuperAdmin: userInfo.SuperAdmin})
163+
}
164+
if len(policies) > 0 {
165+
pRes := casbin2.AddPolicy(policies)
166+
println(pRes)
167+
}
168+
err = tx.Commit()
169+
if err != nil {
170+
return nil, err
171+
}
172+
return userResponse, nil
173+
}
174+
175+
func (impl UserServiceImpl) saveUser(userInfo *bean.UserInfo, emailId string) (*bean.UserInfo, error) {
176+
dbConnection := impl.userRepository.GetConnection()
177+
tx, err := dbConnection.Begin()
178+
if err != nil {
179+
return nil, err
180+
}
181+
// Rollback tx on error.
182+
defer tx.Rollback()
183+
184+
_, err = impl.validateUserRequest(userInfo)
185+
if err != nil {
186+
err = &util.ApiError{HttpStatusCode: http.StatusBadRequest, UserMessage: "Invalid request, please provide role filters"}
187+
return nil, err
188+
}
189+
190+
//create new user in our db on d basis of info got from google api or hex. assign a basic role
191+
model := &repository2.UserModel{
192+
EmailId: emailId,
193+
AccessToken: userInfo.AccessToken,
194+
}
195+
model.Active = true
196+
model.CreatedBy = userInfo.UserId
197+
model.UpdatedBy = userInfo.UserId
198+
model.CreatedOn = time.Now()
199+
model.UpdatedOn = time.Now()
200+
model, err = impl.userRepository.CreateUser(model, tx)
201+
if err != nil {
202+
impl.logger.Errorw("error in creating new user", "error", err)
203+
return nil, err
204+
}
205+
err = tx.Commit()
206+
if err != nil {
207+
return nil, err
208+
}
209+
userInfo.Id = model.Id
210+
return userInfo, nil
211+
}
212+
104213
func (impl UserServiceImpl) CreateUser(userInfo *bean.UserInfo) ([]*bean.UserInfo, error) {
105214
var pass []string
106215
var userResponse []*bean.UserInfo

0 commit comments

Comments
 (0)