瀏覽代碼

feat(invite): progress on invite feature, #2353

Torkel Ödegaard 10 年之前
父節點
當前提交
775e044e69

+ 1 - 1
pkg/api/api.go

@@ -22,7 +22,7 @@ func Register(r *macaron.Macaron) {
 	r.Post("/login", bind(dtos.LoginCommand{}), wrap(LoginPost))
 	r.Get("/login/:name", OAuthLogin)
 	r.Get("/login", LoginView)
-	r.Get("/invite", Index)
+	r.Get("/invite/:code", Index)
 
 	// authed views
 	r.Get("/profile/", reqSignedIn, Index)

+ 4 - 3
pkg/api/dtos/invite.go

@@ -10,9 +10,10 @@ type AddInviteForm struct {
 }
 
 type InviteInfo struct {
-	Email    string `json:"email"`
-	Name     string `json:"name"`
-	Username string `json:"username"`
+	Email     string `json:"email"`
+	Name      string `json:"name"`
+	Username  string `json:"username"`
+	InvitedBy string `json:"invitedBy"`
 }
 
 type CompleteInviteForm struct {

+ 8 - 7
pkg/api/org_invite.go

@@ -78,7 +78,7 @@ func AddOrgInvite(c *middleware.Context, inviteDto dtos.AddInviteForm) Response
 				"OrgName":     c.OrgName,
 				"Email":       c.Email,
 				"LinkUrl":     setting.ToAbsUrl("invite/" + cmd.Code),
-				"InvitedBy":   util.StringsFallback2(c.Name, c.Email),
+				"InvitedBy":   util.StringsFallback3(c.Name, c.Email, c.Login),
 			},
 		}
 
@@ -114,13 +114,14 @@ func GetInviteInfoByCode(c *middleware.Context) Response {
 		return ApiError(500, "Failed to get invite", err)
 	}
 
-	info := dtos.InviteInfo{
-		Email:    query.Result.Email,
-		Name:     query.Result.Name,
-		Username: query.Result.Email,
-	}
+	invite := query.Result
 
-	return Json(200, &info)
+	return Json(200, dtos.InviteInfo{
+		Email:     invite.Email,
+		Name:      invite.Name,
+		Username:  invite.Email,
+		InvitedBy: util.StringsFallback3(invite.InvitedByName, invite.InvitedByLogin, invite.InvitedByEmail),
+	})
 }
 
 func CompleteInvite(c *middleware.Context, completeInvite dtos.CompleteInviteForm) Response {

+ 14 - 11
pkg/models/temp_user.go

@@ -70,18 +70,21 @@ type GetTempUsersForOrgQuery struct {
 type GetTempUserByCodeQuery struct {
 	Code string
 
-	Result *TempUser
+	Result *TempUserDTO
 }
 
 type TempUserDTO struct {
-	Id          int64     `json:"id"`
-	Name        string    `json:"name"`
-	Email       string    `json:"email"`
-	Role        string    `json:"role"`
-	InvitedBy   string    `json:"invitedBy"`
-	Code        string    `json:"code"`
-	Url         string    `json:"url"`
-	EmailSent   bool      `json:"emailSent"`
-	EmailSentOn time.Time `json:"emailSentOn"`
-	Created     time.Time `json:"createdOn"`
+	Id             int64          `json:"id"`
+	Name           string         `json:"name"`
+	Email          string         `json:"email"`
+	Role           string         `json:"role"`
+	InvitedByLogin string         `json:"invitedByLogin"`
+	InvitedByEmail string         `json:"invitedByEmail"`
+	InvitedByName  string         `json:"invitedByName"`
+	Code           string         `json:"code"`
+	Status         TempUserStatus `json:"status"`
+	Url            string         `json:"url"`
+	EmailSent      bool           `json:"emailSent"`
+	EmailSentOn    time.Time      `json:"emailSentOn"`
+	Created        time.Time      `json:"createdOn"`
 }

+ 25 - 4
pkg/services/sqlstore/temp_user.go

@@ -56,10 +56,13 @@ func GetTempUsersForOrg(query *m.GetTempUsersForOrgQuery) error {
 									tu.name           as name,
 									tu.role           as role,
 									tu.code           as code,
+									tu.status         as status,
 									tu.email_sent     as email_sent,
 									tu.email_sent_on  as email_sent_on,
 									tu.created				as created,
-									u.login						as invited_by
+									u.login						as invited_by_login,
+									u.name						as invited_by_name,
+									u.email						as invited_by_email
 	                FROM ` + dialect.Quote("temp_user") + ` as tu
 									LEFT OUTER JOIN ` + dialect.Quote("user") + ` as u on u.id = tu.invited_by_user_id
 	                WHERE tu.org_id=? AND tu.status =? ORDER BY tu.created desc`
@@ -71,8 +74,26 @@ func GetTempUsersForOrg(query *m.GetTempUsersForOrgQuery) error {
 }
 
 func GetTempUserByCode(query *m.GetTempUserByCodeQuery) error {
-	var user m.TempUser
-	has, err := x.Table("temp_user").Where("code=?", query.Code).Get(&user)
+	var rawSql = `SELECT
+	                tu.id             as id,
+	                tu.email          as email,
+									tu.name           as name,
+									tu.role           as role,
+									tu.code           as code,
+									tu.status         as status,
+									tu.email_sent     as email_sent,
+									tu.email_sent_on  as email_sent_on,
+									tu.created				as created,
+									u.login						as invited_by_login,
+									u.name						as invited_by_name,
+									u.email						as invited_by_email
+	                FROM ` + dialect.Quote("temp_user") + ` as tu
+									LEFT OUTER JOIN ` + dialect.Quote("user") + ` as u on u.id = tu.invited_by_user_id
+	                WHERE tu.code=?`
+
+	var tempUser m.TempUserDTO
+	sess := x.Sql(rawSql, query.Code)
+	has, err := sess.Get(&tempUser)
 
 	if err != nil {
 		return err
@@ -80,6 +101,6 @@ func GetTempUserByCode(query *m.GetTempUserByCodeQuery) error {
 		return m.ErrTempUserNotFound
 	}
 
-	query.Result = &user
+	query.Result = &tempUser
 	return err
 }

+ 8 - 0
pkg/services/sqlstore/temp_user_test.go

@@ -32,6 +32,14 @@ func TestTempUserCommandsAndQueries(t *testing.T) {
 				So(len(query.Result), ShouldEqual, 1)
 			})
 
+			Convey("Should be able to get temp users by code", func() {
+				query := m.GetTempUserByCodeQuery{Code: "asd"}
+				err = GetTempUserByCode(&query)
+
+				So(err, ShouldBeNil)
+				So(query.Result.Name, ShouldEqual, "hello")
+			})
+
 			Convey("Should be able update status", func() {
 				cmd2 := m.UpdateTempUserStatusCommand{Code: "asd", Status: m.TmpUserRevoked}
 				err := UpdateTempUserStatus(&cmd2)

+ 10 - 0
pkg/util/strings.go

@@ -6,3 +6,13 @@ func StringsFallback2(val1 string, val2 string) string {
 	}
 	return val2
 }
+
+func StringsFallback3(val1 string, val2 string, val3 string) string {
+	if val1 != "" {
+		return val1
+	}
+	if val2 != "" {
+		return val2
+	}
+	return val3
+}

+ 2 - 1
public/app/controllers/invitedCtrl.js

@@ -20,7 +20,8 @@ function (angular, config) {
         $scope.formModel.username = invite.email;
         $scope.formModel.inviteCode =  $routeParams.code;
 
-        $scope.greeting = invite.name || invite.email;
+        $scope.greeting = invite.name || invite.email || invite.username;
+        $scope.invitedBy = invite.invitedBy;
       });
     };
 

+ 2 - 13
public/app/partials/signup_invited.html

@@ -14,8 +14,8 @@
 				Hello {{greeting}}.
 			</h3>
 
-			<div class="long-tag modal-tagline">
-				<span class="body-copy-emphasis">{{.InvitedBy}}</span> has invited you to join the <span class="highlight-word">{{contextSrv.user.orgName}}</span> organization in Grafana.</br>Please complete the following to accept your invitation and continue:
+			<div class="modal-tagline">
+				<em>{{invitedBy}}</em> has invited you to join the <span class="highlight-word">{{contextSrv.user.orgName}}</span> organization in Grafana.</br>Please complete the following to accept your invitation and continue:
 			</div>
 
       <form name="inviteForm" class="login-form">
@@ -65,17 +65,6 @@
 						</ul>
 						<div class="clearfix"></div>
 					</div>
-					<div class="tight-form">
-						<ul class="tight-form-list">
-							<li class="tight-form-item" style="width: 128px">
-								Confirm Password
-							</li>
-							<li>
-								<input type="password" name="confirmPassword" class="tight-form-input last" required ng-model="formModel.confirmPassword" id="confirmPassword" style="width: 253px" placeholder="confirm password">
-							</li>
-						</ul>
-						<div class="clearfix"></div>
-					</div>
 				</div>
 
 				<div style="margin-left: 147px; width: 254px;">

+ 2 - 6
public/css/less/grafana.less

@@ -1,3 +1,4 @@
+@import "type.less";
 @import "login.less";
 @import "submenu.less";
 @import "graph.less";
@@ -277,11 +278,6 @@
   }
 }
 
-.long-tag {
-  width: 90%;
-  margin: 0 auto;
-}
-
 .confirm-modal {
   max-width: 500px;
 
@@ -371,7 +367,7 @@
 }
 
 .body-copy-emphasis {
-    color: @headingsColor;
+  color: @headingsColor;
 }
 
 .signup-page-container {

+ 247 - 0
public/css/less/type.less

@@ -0,0 +1,247 @@
+//
+// Typography
+// --------------------------------------------------
+
+
+// Body text
+// -------------------------
+
+p {
+  margin: 0 0 @baseLineHeight / 2;
+}
+.lead {
+  margin-bottom: @baseLineHeight;
+  font-size: @baseFontSize * 1.5;
+  font-weight: 200;
+  line-height: @baseLineHeight * 1.5;
+}
+
+
+// Emphasis & misc
+// -------------------------
+
+// Ex: 14px base font * 85% = about 12px
+small   { font-size: 85%; }
+
+strong  { font-weight: 500; }
+em      { font-style: italic; color: @headingsColor; }
+cite    { font-style: normal; }
+
+// Utility classes
+.muted               { color: @grayLight; }
+a.muted:hover,
+a.muted:focus        { color: darken(@grayLight, 10%); }
+
+.text-warning        { color: @warningText; }
+a.text-warning:hover,
+a.text-warning:focus { color: darken(@warningText, 10%); }
+
+.text-error          { color: @errorText; }
+a.text-error:hover,
+a.text-error:focus   { color: darken(@errorText, 10%); }
+
+.text-info           { color: @infoText; }
+a.text-info:hover,
+a.text-info:focus    { color: darken(@infoText, 10%); }
+
+.text-success        { color: @successText; }
+a.text-success:hover,
+a.text-success:focus { color: darken(@successText, 10%); }
+
+.text-left           { text-align: left; }
+.text-right          { text-align: right; }
+.text-center         { text-align: center; }
+
+
+// Headings
+// -------------------------
+
+h1, h2, h3, h4, h5, h6 {
+  margin: (@baseLineHeight / 2) 0;
+  font-family: @headingsFontFamily;
+  font-weight: @headingsFontWeight;
+  line-height: @baseLineHeight;
+  color: @headingsColor;
+  text-rendering: optimizelegibility; // Fix the character spacing for headings
+  small {
+    font-weight: normal;
+    line-height: 1;
+    color: @grayLight;
+  }
+}
+
+h1,
+h2,
+h3 { line-height: @baseLineHeight * 2; }
+
+h1 { font-size: @baseFontSize * 2.00; } // ~38px
+h2 { font-size: @baseFontSize * 1.75; } // ~32px
+h3 { font-size: @baseFontSize * 1.50; } // ~24px
+h4 { font-size: @baseFontSize * 1.25; } // ~18px
+h5 { font-size: @baseFontSize; }
+h6 { font-size: @baseFontSize * 0.85; } // ~12px
+
+h1 small { font-size: @baseFontSize * 1.75; } // ~24px
+h2 small { font-size: @baseFontSize * 1.25; } // ~18px
+h3 small { font-size: @baseFontSize; }
+h4 small { font-size: @baseFontSize; }
+
+
+// Page header
+// -------------------------
+
+.page-header {
+  padding-bottom: (@baseLineHeight / 2) - 1;
+  margin: @baseLineHeight 0 (@baseLineHeight * 1.5);
+  border-bottom: 1px solid @grayLighter;
+}
+
+
+
+// Lists
+// --------------------------------------------------
+
+// Unordered and Ordered lists
+ul, ol {
+  padding: 0;
+  margin: 0 0 @baseLineHeight / 2 25px;
+}
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+  margin-bottom: 0;
+}
+li {
+  line-height: @baseLineHeight;
+}
+
+// Remove default list styles
+ul.unstyled,
+ol.unstyled {
+  margin-left: 0;
+  list-style: none;
+}
+
+// Single-line list items
+ul.inline,
+ol.inline {
+  margin-left: 0;
+  list-style: none;
+  > li {
+    display: inline-block;
+    .ie7-inline-block();
+    padding-left: 5px;
+    padding-right: 5px;
+  }
+}
+
+// Description Lists
+dl {
+  margin-bottom: @baseLineHeight;
+}
+dt,
+dd {
+  line-height: @baseLineHeight;
+}
+dt {
+  font-weight: bold;
+}
+dd {
+  margin-left: @baseLineHeight / 2;
+}
+// Horizontal layout (like forms)
+.dl-horizontal {
+  .clearfix(); // Ensure dl clears floats if empty dd elements present
+  dt {
+    float: left;
+    width: @horizontalComponentOffset - 20;
+    clear: left;
+    text-align: right;
+    .text-overflow();
+  }
+  dd {
+    margin-left: @horizontalComponentOffset;
+  }
+}
+
+// MISC
+// ----
+
+// Horizontal rules
+hr {
+  margin: @baseLineHeight 0;
+  border: 0;
+  border-top: 1px solid @hrBorder;
+  border-bottom: 1px solid @white;
+}
+
+// Abbreviations and acronyms
+abbr[title],
+// Added data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257
+abbr[data-original-title] {
+  cursor: help;
+  border-bottom: 1px dotted @grayLight;
+}
+abbr.initialism {
+  font-size: 90%;
+  text-transform: uppercase;
+}
+
+// Blockquotes
+blockquote {
+  padding: 0 0 0 15px;
+  margin: 0 0 @baseLineHeight;
+  border-left: 5px solid @grayLighter;
+  p {
+    margin-bottom: 0;
+    font-size: @baseFontSize * 1.25;
+    font-weight: 300;
+    line-height: 1.25;
+  }
+  small {
+    display: block;
+    line-height: @baseLineHeight;
+    color: @grayLight;
+    &:before {
+      content: '\2014 \00A0';
+    }
+  }
+
+  // Float right with text-align: right
+  &.pull-right {
+    float: right;
+    padding-right: 15px;
+    padding-left: 0;
+    border-right: 5px solid @grayLighter;
+    border-left: 0;
+    p,
+    small {
+      text-align: right;
+    }
+    small {
+      &:before {
+        content: '';
+      }
+      &:after {
+        content: '\00A0 \2014';
+      }
+    }
+  }
+}
+
+// Quotes
+q:before,
+q:after,
+blockquote:before,
+blockquote:after {
+  content: "";
+}
+
+// Addresses
+address {
+  display: block;
+  margin-bottom: @baseLineHeight;
+  font-style: normal;
+  line-height: @baseLineHeight;
+}

+ 0 - 1
public/vendor/bootstrap/less/bootstrap.less

@@ -22,7 +22,6 @@
 
 // Base CSS
 @import "type.less";
-@import "code.less";
 @import "forms.less";
 @import "tables.less";
 

+ 0 - 246
public/vendor/bootstrap/less/type.less

@@ -1,247 +1 @@
-//
-// Typography
-// --------------------------------------------------
 
-
-// Body text
-// -------------------------
-
-p {
-  margin: 0 0 @baseLineHeight / 2;
-}
-.lead {
-  margin-bottom: @baseLineHeight;
-  font-size: @baseFontSize * 1.5;
-  font-weight: 200;
-  line-height: @baseLineHeight * 1.5;
-}
-
-
-// Emphasis & misc
-// -------------------------
-
-// Ex: 14px base font * 85% = about 12px
-small   { font-size: 85%; }
-
-strong  { font-weight: bold; }
-em      { font-style: italic; }
-cite    { font-style: normal; }
-
-// Utility classes
-.muted               { color: @grayLight; }
-a.muted:hover,
-a.muted:focus        { color: darken(@grayLight, 10%); }
-
-.text-warning        { color: @warningText; }
-a.text-warning:hover,
-a.text-warning:focus { color: darken(@warningText, 10%); }
-
-.text-error          { color: @errorText; }
-a.text-error:hover,
-a.text-error:focus   { color: darken(@errorText, 10%); }
-
-.text-info           { color: @infoText; }
-a.text-info:hover,
-a.text-info:focus    { color: darken(@infoText, 10%); }
-
-.text-success        { color: @successText; }
-a.text-success:hover,
-a.text-success:focus { color: darken(@successText, 10%); }
-
-.text-left           { text-align: left; }
-.text-right          { text-align: right; }
-.text-center         { text-align: center; }
-
-
-// Headings
-// -------------------------
-
-h1, h2, h3, h4, h5, h6 {
-  margin: (@baseLineHeight / 2) 0;
-  font-family: @headingsFontFamily;
-  font-weight: @headingsFontWeight;
-  line-height: @baseLineHeight;
-  color: @headingsColor;
-  text-rendering: optimizelegibility; // Fix the character spacing for headings
-  small {
-    font-weight: normal;
-    line-height: 1;
-    color: @grayLight;
-  }
-}
-
-h1,
-h2,
-h3 { line-height: @baseLineHeight * 2; }
-
-h1 { font-size: @baseFontSize * 2.00; } // ~38px
-h2 { font-size: @baseFontSize * 1.75; } // ~32px
-h3 { font-size: @baseFontSize * 1.50; } // ~24px
-h4 { font-size: @baseFontSize * 1.25; } // ~18px
-h5 { font-size: @baseFontSize; }
-h6 { font-size: @baseFontSize * 0.85; } // ~12px
-
-h1 small { font-size: @baseFontSize * 1.75; } // ~24px
-h2 small { font-size: @baseFontSize * 1.25; } // ~18px
-h3 small { font-size: @baseFontSize; }
-h4 small { font-size: @baseFontSize; }
-
-
-// Page header
-// -------------------------
-
-.page-header {
-  padding-bottom: (@baseLineHeight / 2) - 1;
-  margin: @baseLineHeight 0 (@baseLineHeight * 1.5);
-  border-bottom: 1px solid @grayLighter;
-}
-
-
-
-// Lists
-// --------------------------------------------------
-
-// Unordered and Ordered lists
-ul, ol {
-  padding: 0;
-  margin: 0 0 @baseLineHeight / 2 25px;
-}
-ul ul,
-ul ol,
-ol ol,
-ol ul {
-  margin-bottom: 0;
-}
-li {
-  line-height: @baseLineHeight;
-}
-
-// Remove default list styles
-ul.unstyled,
-ol.unstyled {
-  margin-left: 0;
-  list-style: none;
-}
-
-// Single-line list items
-ul.inline,
-ol.inline {
-  margin-left: 0;
-  list-style: none;
-  > li {
-    display: inline-block;
-    .ie7-inline-block();
-    padding-left: 5px;
-    padding-right: 5px;
-  }
-}
-
-// Description Lists
-dl {
-  margin-bottom: @baseLineHeight;
-}
-dt,
-dd {
-  line-height: @baseLineHeight;
-}
-dt {
-  font-weight: bold;
-}
-dd {
-  margin-left: @baseLineHeight / 2;
-}
-// Horizontal layout (like forms)
-.dl-horizontal {
-  .clearfix(); // Ensure dl clears floats if empty dd elements present
-  dt {
-    float: left;
-    width: @horizontalComponentOffset - 20;
-    clear: left;
-    text-align: right;
-    .text-overflow();
-  }
-  dd {
-    margin-left: @horizontalComponentOffset;
-  }
-}
-
-// MISC
-// ----
-
-// Horizontal rules
-hr {
-  margin: @baseLineHeight 0;
-  border: 0;
-  border-top: 1px solid @hrBorder;
-  border-bottom: 1px solid @white;
-}
-
-// Abbreviations and acronyms
-abbr[title],
-// Added data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257
-abbr[data-original-title] {
-  cursor: help;
-  border-bottom: 1px dotted @grayLight;
-}
-abbr.initialism {
-  font-size: 90%;
-  text-transform: uppercase;
-}
-
-// Blockquotes
-blockquote {
-  padding: 0 0 0 15px;
-  margin: 0 0 @baseLineHeight;
-  border-left: 5px solid @grayLighter;
-  p {
-    margin-bottom: 0;
-    font-size: @baseFontSize * 1.25;
-    font-weight: 300;
-    line-height: 1.25;
-  }
-  small {
-    display: block;
-    line-height: @baseLineHeight;
-    color: @grayLight;
-    &:before {
-      content: '\2014 \00A0';
-    }
-  }
-
-  // Float right with text-align: right
-  &.pull-right {
-    float: right;
-    padding-right: 15px;
-    padding-left: 0;
-    border-right: 5px solid @grayLighter;
-    border-left: 0;
-    p,
-    small {
-      text-align: right;
-    }
-    small {
-      &:before {
-        content: '';
-      }
-      &:after {
-        content: '\00A0 \2014';
-      }
-    }
-  }
-}
-
-// Quotes
-q:before,
-q:after,
-blockquote:before,
-blockquote:after {
-  content: "";
-}
-
-// Addresses
-address {
-  display: block;
-  margin-bottom: @baseLineHeight;
-  font-style: normal;
-  line-height: @baseLineHeight;
-}