feat(signup): progress on new signup flow, #2353

This commit is contained in:
Torkel Ödegaard 2015-08-30 18:56:53 +02:00
parent de0f04ec3c
commit 14884d5a2b
7 changed files with 76 additions and 50 deletions

View File

@ -18,11 +18,13 @@ it allows you to add queries of differnet data source types & instances to the s
- [Issue #2565](https://github.com/grafana/grafana/issues/2565). TimePicker: Fix for when you applied custom time range it did not refreh dashboard
- [Issue #2563](https://github.com/grafana/grafana/issues/2563). Annotations: Fixed issue when html sanitizer failes for title to annotation body, now fallbacks to html escaping title and text
- [Issue #2564](https://github.com/grafana/grafana/issues/2564). Templating: Another atempt at fixing #2534 (Init multi value template var used in repeat panel from url)
- [Issue #2620](https://github.com/grafana/grafana/issues/2620). Graph: multi series tooltip did no highlight correct point when stacking was enabled and series were of different resolution
**Breaking Changes**
- Notice to makers/users of custom data sources, there is a minor breaking change in 2.2 that
require an update to custom data sources for them to work in 2.2. [Read this doc](https://github.com/grafana/grafana/tree/master/docs/sources/datasources/plugin_api.md) for more on the
data source api change.
- The duplicate query function used in data source editors is changed, and moveMetricQuery function was renamed
2.1.3 (2015-08-24)

View File

@ -111,13 +111,8 @@ func inviteExistingUserToOrg(c *middleware.Context, user *m.User, inviteDto *dto
}
func RevokeInvite(c *middleware.Context) Response {
cmd := m.UpdateTempUserStatusCommand{
Code: c.Params(":code"),
Status: m.TmpUserRevoked,
}
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to update invite status", err)
if ok, rsp := updateTempUserStatus(c.Params(":code"), m.TmpUserRevoked); !ok {
return rsp
}
return ApiSuccess("Invite revoked")
@ -169,36 +164,55 @@ func CompleteInvite(c *middleware.Context, completeInvite dtos.CompleteInviteFor
return ApiError(500, "failed to create user", err)
}
user := cmd.Result
user := &cmd.Result
bus.Publish(&events.SignUpCompleted{
Name: user.NameOrFallback(),
Email: user.Email,
})
// add to org
addOrgUserCmd := m.AddOrgUserCommand{OrgId: invite.OrgId, UserId: user.Id, Role: invite.Role}
if err := bus.Dispatch(&addOrgUserCmd); err != nil {
if err != m.ErrOrgUserAlreadyAdded {
return ApiError(500, "Error while trying to create org user", err)
}
if ok, rsp := applyUserInvite(user, invite, true); !ok {
return rsp
}
// set org to active
if err := bus.Dispatch(&m.SetUsingOrgCommand{OrgId: invite.OrgId, UserId: user.Id}); err != nil {
return ApiError(500, "Failed to set org as active", err)
}
// update temp user status
updateTmpUserCmd := m.UpdateTempUserStatusCommand{Code: invite.Code, Status: m.TmpUserCompleted}
if err := bus.Dispatch(&updateTmpUserCmd); err != nil {
return ApiError(500, "Failed to update invite status", err)
}
loginUserWithUser(&user, c)
loginUserWithUser(user, c)
metrics.M_Api_User_SignUpCompleted.Inc(1)
metrics.M_Api_User_SignUpInvite.Inc(1)
return ApiSuccess("User created and logged in")
}
func updateTempUserStatus(code string, status m.TempUserStatus) (bool, Response) {
// update temp user status
updateTmpUserCmd := m.UpdateTempUserStatusCommand{Code: code, Status: status}
if err := bus.Dispatch(&updateTmpUserCmd); err != nil {
return false, ApiError(500, "Failed to update invite status", err)
}
return true, nil
}
func applyUserInvite(user *m.User, invite *m.TempUserDTO, setActive bool) (bool, Response) {
// add to org
addOrgUserCmd := m.AddOrgUserCommand{OrgId: invite.OrgId, UserId: user.Id, Role: invite.Role}
if err := bus.Dispatch(&addOrgUserCmd); err != nil {
if err != m.ErrOrgUserAlreadyAdded {
return false, ApiError(500, "Error while trying to create org user", err)
}
}
// update temp user status
if ok, rsp := updateTempUserStatus(invite.Code, m.TmpUserCompleted); !ok {
return false, rsp
}
if setActive {
// set org to active
if err := bus.Dispatch(&m.SetUsingOrgCommand{OrgId: invite.OrgId, UserId: user.Id}); err != nil {
return false, ApiError(500, "Failed to set org as active", err)
}
}
return true, nil
}

View File

@ -81,20 +81,41 @@ func SignUpStep2(c *middleware.Context, form dtos.SignUpStep2Form) Response {
return ApiError(500, "Failed to create user", err)
}
user := createUserCmd.Result
// publish signup event
user := &createUserCmd.Result
bus.Publish(&events.SignUpCompleted{
Email: user.Email,
Name: user.NameOrFallback(),
})
// update tempuser
updateTempUserCmd := m.UpdateTempUserStatusCommand{
Code: tempUser.Code,
Status: m.TmpUserCompleted,
}
if err := bus.Dispatch(&updateTempUserCmd); err != nil {
return ApiError(500, "Failed to update temp user", err)
}
// check for pending invites
invitesQuery := m.GetTempUsersQuery{Email: tempUser.Email, Status: m.TmpUserInvitePending}
if err := bus.Dispatch(&invitesQuery); err != nil {
return ApiError(500, "Failed to query database for invites", err)
}
loginUserWithUser(&user, c)
apiResponse := util.DynMap{"message": "User sign up completed succesfully", "code": "redirect-to-landing-page"}
for _, invite := range invitesQuery.Result {
if ok, rsp := applyUserInvite(user, invite, false); !ok {
return rsp
}
apiResponse["code"] = "redirect-to-select-org"
}
loginUserWithUser(user, c)
metrics.M_Api_User_SignUpCompleted.Inc(1)
return Json(200, util.DynMap{"status": "SignUpCreated"})
return Json(200, apiResponse)
}

View File

@ -45,7 +45,10 @@ func getOrgIdForNewUser(cmd *m.CreateUserCommand, sess *session) (int64, error)
org.Id = 1
}
} else {
org.Name = util.StringsFallback2(cmd.Email, cmd.Login)
org.Name = cmd.OrgName
if len(org.Name) == 0 {
org.Name = util.StringsFallback2(cmd.Email, cmd.Login)
}
}
org.Created = time.Now()

View File

@ -26,8 +26,9 @@ function (angular, config) {
return;
}
backendSrv.post('/api/user/signup/step2', $scope.formModel).then(function() {
window.location.href = config.appSubUrl + '/';
backendSrv.post('/api/user/signup/step2', $scope.formModel).then(function(rsp) {
console.log(rsp);
//window.location.href = config.appSubUrl + '/';
});
};

View File

@ -53,21 +53,6 @@
<div class="clearfix"></div>
</div>
<div class="tight-form" ng-if="!loginMode">
<ul class="tight-form-list">
<li class="tight-form-item" style="width: 79px">
<strong>Password</strong>
</li>
<li>
<input type="password" class="tight-form-input last" watch-change="formModel.password = inputValue;" ng-minlength="4" required ng-model='formModel.password' placeholder="password" style="width: 253px">
</li>
</ul>
<div class="clearfix"></div>
</div>
</div>
<div ng-if="!loginMode" style="margin-left: 97px; width: 254px;">
<password-strength password="formModel.password"></password-strength>
</div>
<div class="login-submit-button-row">

View File

@ -40,7 +40,7 @@
<div class="tight-form">
<ul class="tight-form-list">
<li class="tight-form-item" style="width: 128px">
Organization
Organization name
</li>
<li>
<input type="text" name="orgName" class="tight-form-input last" ng-model='formModel.orgName' placeholder="Name your organization" style="width: 253px">
@ -52,10 +52,10 @@
<div class="tight-form">
<ul class="tight-form-list">
<li class="tight-form-item" style="width: 128px">
Name
Your name
</li>
<li>
<input type="text" name="name" class="tight-form-input last" ng-model='formModel.name' placeholder="Name (optional)" style="width: 253px">
<input type="text" name="name" class="tight-form-input last" ng-model='formModel.name' placeholder="(optional)" style="width: 253px">
</li>
</ul>
<div class="clearfix"></div>