diff --git a/pkg/api/api.go b/pkg/api/api.go index 6e8fe57fddf..7ad4ae73b4c 100644 --- a/pkg/api/api.go +++ b/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) diff --git a/pkg/api/dtos/invite.go b/pkg/api/dtos/invite.go index bc674aa2a75..495acce8da9 100644 --- a/pkg/api/dtos/invite.go +++ b/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 { diff --git a/pkg/api/org_invite.go b/pkg/api/org_invite.go index 52f0ce78de4..f4c64e8db7d 100644 --- a/pkg/api/org_invite.go +++ b/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 { diff --git a/pkg/models/temp_user.go b/pkg/models/temp_user.go index cf20517921c..9aab24f48fc 100644 --- a/pkg/models/temp_user.go +++ b/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"` } diff --git a/pkg/services/sqlstore/temp_user.go b/pkg/services/sqlstore/temp_user.go index 0931cd2b1df..df1bdd96127 100644 --- a/pkg/services/sqlstore/temp_user.go +++ b/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 } diff --git a/pkg/services/sqlstore/temp_user_test.go b/pkg/services/sqlstore/temp_user_test.go index ad3681c2071..6b550799e73 100644 --- a/pkg/services/sqlstore/temp_user_test.go +++ b/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) diff --git a/pkg/util/strings.go b/pkg/util/strings.go index 277e5e036c8..7e503a99118 100644 --- a/pkg/util/strings.go +++ b/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 +} diff --git a/public/app/controllers/invitedCtrl.js b/public/app/controllers/invitedCtrl.js index e3e36d56463..0b4a096fb1b 100644 --- a/public/app/controllers/invitedCtrl.js +++ b/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; }); }; diff --git a/public/app/partials/signup_invited.html b/public/app/partials/signup_invited.html index e4b5e9dc7a8..329d1fee1bf 100644 --- a/public/app/partials/signup_invited.html +++ b/public/app/partials/signup_invited.html @@ -14,8 +14,8 @@ Hello {{greeting}}. - -
- -
-
diff --git a/public/css/less/grafana.less b/public/css/less/grafana.less index 2ec921cb267..163cb7d792e 100644 --- a/public/css/less/grafana.less +++ b/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 { diff --git a/public/css/less/type.less b/public/css/less/type.less new file mode 100644 index 00000000000..1d833792484 --- /dev/null +++ b/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; +} diff --git a/public/vendor/bootstrap/less/bootstrap.less b/public/vendor/bootstrap/less/bootstrap.less index a22c4b24756..758dbde9848 100644 --- a/public/vendor/bootstrap/less/bootstrap.less +++ b/public/vendor/bootstrap/less/bootstrap.less @@ -22,7 +22,6 @@ // Base CSS @import "type.less"; -@import "code.less"; @import "forms.less"; @import "tables.less"; diff --git a/public/vendor/bootstrap/less/type.less b/public/vendor/bootstrap/less/type.less index 109b09de44d..8b137891791 100644 --- a/public/vendor/bootstrap/less/type.less +++ b/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; -}