Commit ad3d15e2 by Torkel Ödegaard

Worked on dashboard starring and unstarring, renamed favorite model to star

parent 706481b1
Subproject commit 66d9c4f1afb689eb2a1640561a06cb166e28c062 Subproject commit 1e3970c6e56af810047ab815acd7fd5e681b5139
...@@ -45,8 +45,8 @@ func Register(r *macaron.Macaron) { ...@@ -45,8 +45,8 @@ func Register(r *macaron.Macaron) {
r.Put("/", bind(m.UpdateUserCommand{}), UpdateUser) r.Put("/", bind(m.UpdateUserCommand{}), UpdateUser)
r.Post("/using/:id", SetUsingAccount) r.Post("/using/:id", SetUsingAccount)
r.Get("/accounts", GetUserAccounts) r.Get("/accounts", GetUserAccounts)
r.Post("/favorites/dashboard/:id", AddAsFavorite) r.Post("/stars/dashboard/:id", StarDashboard)
r.Delete("/favorites/dashboard/:id", RemoveAsFavorite) r.Delete("/stars/dashboard/:id", UnstarDashboard)
}) })
// account // account
......
...@@ -8,6 +8,19 @@ import ( ...@@ -8,6 +8,19 @@ import (
"github.com/torkelo/grafana-pro/pkg/util" "github.com/torkelo/grafana-pro/pkg/util"
) )
func isDasboardStarredByUser(c *middleware.Context, dashId int64) (bool, error) {
if !c.IsSignedIn {
return false, nil
}
query := m.IsStarredByUserQuery{UserId: c.UserId, DashboardId: dashId}
if err := bus.Dispatch(&query); err != nil {
return false, err
}
return query.Result, nil
}
func GetDashboard(c *middleware.Context) { func GetDashboard(c *middleware.Context) {
slug := c.Params(":slug") slug := c.Params(":slug")
...@@ -18,10 +31,16 @@ func GetDashboard(c *middleware.Context) { ...@@ -18,10 +31,16 @@ func GetDashboard(c *middleware.Context) {
return return
} }
isStarred, err := isDasboardStarredByUser(c, query.Result.Id)
if err != nil {
c.JsonApiErr(500, "Error while checking if dashboard was starred by user", err)
return
}
dash := query.Result dash := query.Result
dto := dtos.Dashboard{ dto := dtos.Dashboard{
IsFavorite: false, Model: dash.Data,
Dashboard: dash.Data, Meta: dtos.DashboardMeta{IsStarred: isStarred},
} }
c.JSON(200, dto) c.JSON(200, dto)
......
...@@ -25,9 +25,13 @@ type CurrentUser struct { ...@@ -25,9 +25,13 @@ type CurrentUser struct {
GravatarUrl string `json:"gravatarUrl"` GravatarUrl string `json:"gravatarUrl"`
} }
type DashboardMeta struct {
IsStarred bool `json:"isStarred"`
}
type Dashboard struct { type Dashboard struct {
IsFavorite bool `json:"isFavorite"` Meta DashboardMeta `json:"meta"`
Dashboard map[string]interface{} `json:"dashboard"` Model map[string]interface{} `json:"model"`
} }
type DataSource struct { type DataSource struct {
......
...@@ -6,30 +6,40 @@ import ( ...@@ -6,30 +6,40 @@ import (
m "github.com/torkelo/grafana-pro/pkg/models" m "github.com/torkelo/grafana-pro/pkg/models"
) )
func AddAsFavorite(c *middleware.Context) { func StarDashboard(c *middleware.Context) {
var cmd = m.AddAsFavoriteCommand{ var cmd = m.StarDashboardCommand{
UserId: c.UserId, UserId: c.UserId,
DashboardId: c.ParamsInt64(":id"), DashboardId: c.ParamsInt64(":id"),
} }
if cmd.DashboardId <= 0 {
c.JsonApiErr(400, "Missing dashboard id", nil)
return
}
if err := bus.Dispatch(&cmd); err != nil { if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(500, "Failed to add favorite", err) c.JsonApiErr(500, "Failed to star dashboard", err)
return return
} }
c.JsonOK("Dashboard marked as favorite") c.JsonOK("Dashboard starred!")
} }
func RemoveAsFavorite(c *middleware.Context) { func UnstarDashboard(c *middleware.Context) {
var cmd = m.RemoveAsFavoriteCommand{ var cmd = m.UnstarDashboardCommand{
UserId: c.UserId, UserId: c.UserId,
DashboardId: c.ParamsInt64(":id"), DashboardId: c.ParamsInt64(":id"),
} }
if cmd.DashboardId <= 0 {
c.JsonApiErr(400, "Missing dashboard id", nil)
return
}
if err := bus.Dispatch(&cmd); err != nil { if err := bus.Dispatch(&cmd); err != nil {
c.JsonApiErr(500, "Failed to remove favorite", err) c.JsonApiErr(500, "Failed to unstar dashboard", err)
return return
} }
c.JsonOK("Favorite removed") c.JsonOK("Dashboard unstarred")
} }
package models package models
type Favorite struct { import "errors"
var ErrCommandValidationFailed = errors.New("Command missing required fields")
type Star struct {
Id int64 Id int64
UserId int64 UserId int64
DashboardId int64 DashboardId int64
...@@ -9,12 +13,12 @@ type Favorite struct { ...@@ -9,12 +13,12 @@ type Favorite struct {
// ---------------------- // ----------------------
// COMMANDS // COMMANDS
type AddAsFavoriteCommand struct { type StarDashboardCommand struct {
UserId int64 UserId int64
DashboardId int64 DashboardId int64
} }
type RemoveAsFavoriteCommand struct { type UnstarDashboardCommand struct {
UserId int64 UserId int64
DashboardId int64 DashboardId int64
} }
...@@ -22,8 +26,15 @@ type RemoveAsFavoriteCommand struct { ...@@ -22,8 +26,15 @@ type RemoveAsFavoriteCommand struct {
// --------------------- // ---------------------
// QUERIES // QUERIES
type GetUserFavoritesQuery struct { type GetUserStarsQuery struct {
UserId int64 UserId int64
Result []Favorite Result []Star
}
type IsStarredByUserQuery struct {
UserId int64
DashboardId int64
Result bool
} }
...@@ -10,7 +10,7 @@ import . "github.com/torkelo/grafana-pro/pkg/services/sqlstore/migrator" ...@@ -10,7 +10,7 @@ import . "github.com/torkelo/grafana-pro/pkg/services/sqlstore/migrator"
func addMigrations(mg *Migrator) { func addMigrations(mg *Migrator) {
addMigrationLogMigrations(mg) addMigrationLogMigrations(mg)
addUserMigrations(mg) addUserMigrations(mg)
addFavoritesMigrations(mg) addStarMigrations(mg)
addAccountMigrations(mg) addAccountMigrations(mg)
addDashboardMigration(mg) addDashboardMigration(mg)
addDataSourceMigration(mg) addDataSourceMigration(mg)
...@@ -55,16 +55,16 @@ func addUserMigrations(mg *Migrator) { ...@@ -55,16 +55,16 @@ func addUserMigrations(mg *Migrator) {
Table("user").Column(&Column{Name: "rands", Type: DB_NVarchar, Length: 255, Nullable: true})) Table("user").Column(&Column{Name: "rands", Type: DB_NVarchar, Length: 255, Nullable: true}))
} }
func addFavoritesMigrations(mg *Migrator) { func addStarMigrations(mg *Migrator) {
mg.AddMigration("create favorite table", new(AddTableMigration). mg.AddMigration("create star table", new(AddTableMigration).
Name("favorite").WithColumns( Name("star").WithColumns(
&Column{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, &Column{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
&Column{Name: "user_id", Type: DB_BigInt, Nullable: false}, &Column{Name: "user_id", Type: DB_BigInt, Nullable: false},
&Column{Name: "dashboard_id", Type: DB_BigInt, Nullable: false}, &Column{Name: "dashboard_id", Type: DB_BigInt, Nullable: false},
)) ))
mg.AddMigration("add unique index favorite.user_id_dashboard_id", new(AddIndexMigration). mg.AddMigration("add unique index star.user_id_dashboard_id", new(AddIndexMigration).
Table("favorite").Columns("user_id", "dashboard_id").Unique()) Table("star").Columns("user_id", "dashboard_id").Unique())
} }
func addAccountMigrations(mg *Migrator) { func addAccountMigrations(mg *Migrator) {
......
package sqlstore package sqlstore
import ( import (
"strconv"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
"github.com/torkelo/grafana-pro/pkg/bus" "github.com/torkelo/grafana-pro/pkg/bus"
...@@ -8,15 +10,36 @@ import ( ...@@ -8,15 +10,36 @@ import (
) )
func init() { func init() {
bus.AddHandler("sql", AddAsFavorite) bus.AddHandler("sql", StarDashboard)
bus.AddHandler("sql", RemoveAsFavorite) bus.AddHandler("sql", UnstarDashboard)
bus.AddHandler("sql", GetUserFavorites) bus.AddHandler("sql", GetUserStars)
bus.AddHandler("sql", IsStarredByUser)
} }
func AddAsFavorite(cmd *m.AddAsFavoriteCommand) error { func IsStarredByUser(query *m.IsStarredByUserQuery) error {
rawSql := "SELECT 1 from star where user_id=? and dashboard_id=?"
results, err := x.Query(rawSql, query.UserId, query.DashboardId)
if err != nil {
return err
}
if len(results) == 0 {
return nil
}
query.Result, _ = strconv.ParseBool(string(results[0]["1"]))
return nil
}
func StarDashboard(cmd *m.StarDashboardCommand) error {
if cmd.DashboardId == 0 || cmd.UserId == 0 {
return m.ErrCommandValidationFailed
}
return inTransaction(func(sess *xorm.Session) error { return inTransaction(func(sess *xorm.Session) error {
entity := m.Favorite{ entity := m.Star{
UserId: cmd.UserId, UserId: cmd.UserId,
DashboardId: cmd.DashboardId, DashboardId: cmd.DashboardId,
} }
...@@ -26,16 +49,20 @@ func AddAsFavorite(cmd *m.AddAsFavoriteCommand) error { ...@@ -26,16 +49,20 @@ func AddAsFavorite(cmd *m.AddAsFavoriteCommand) error {
}) })
} }
func RemoveAsFavorite(cmd *m.RemoveAsFavoriteCommand) error { func UnstarDashboard(cmd *m.UnstarDashboardCommand) error {
if cmd.DashboardId == 0 || cmd.UserId == 0 {
return m.ErrCommandValidationFailed
}
return inTransaction(func(sess *xorm.Session) error { return inTransaction(func(sess *xorm.Session) error {
var rawSql = "DELETE FROM favorite WHERE user_id=? and dashboard_id=?" var rawSql = "DELETE FROM star WHERE user_id=? and dashboard_id=?"
_, err := sess.Exec(rawSql, cmd.UserId, cmd.DashboardId) _, err := sess.Exec(rawSql, cmd.UserId, cmd.DashboardId)
return err return err
}) })
} }
func GetUserFavorites(query *m.GetUserFavoritesQuery) error { func GetUserStars(query *m.GetUserStarsQuery) error {
query.Result = make([]m.Favorite, 0) query.Result = make([]m.Star, 0)
err := x.Where("user_id=?", query.UserId).Find(&query.Result) err := x.Where("user_id=?", query.UserId).Find(&query.Result)
return err return err
} }
package sqlstore
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
m "github.com/torkelo/grafana-pro/pkg/models"
)
func TestUserStarsDataAccess(t *testing.T) {
Convey("Testing User Stars Data Access", t, func() {
InitTestDB(t)
Convey("Given saved star", func() {
cmd := m.StarDashboardCommand{
DashboardId: 10,
UserId: 12,
}
err := StarDashboard(&cmd)
So(err, ShouldBeNil)
Convey("IsStarredByUser should return true when starred", func() {
query := m.IsStarredByUserQuery{UserId: 12, DashboardId: 10}
err := IsStarredByUser(&query)
So(err, ShouldBeNil)
So(query.Result, ShouldBeTrue)
})
Convey("IsStarredByUser should return false when not starred", func() {
query := m.IsStarredByUserQuery{UserId: 12, DashboardId: 12}
err := IsStarredByUser(&query)
So(err, ShouldBeNil)
So(query.Result, ShouldBeFalse)
})
})
})
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment