dashboard.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. package sqlstore
  2. import (
  3. "bytes"
  4. "fmt"
  5. "github.com/go-xorm/xorm"
  6. "github.com/grafana/grafana/pkg/bus"
  7. "github.com/grafana/grafana/pkg/metrics"
  8. m "github.com/grafana/grafana/pkg/models"
  9. "github.com/grafana/grafana/pkg/services/search"
  10. )
  11. func init() {
  12. bus.AddHandler("sql", SaveDashboard)
  13. bus.AddHandler("sql", GetDashboard)
  14. bus.AddHandler("sql", GetDashboards)
  15. bus.AddHandler("sql", DeleteDashboard)
  16. bus.AddHandler("sql", SearchDashboards)
  17. bus.AddHandler("sql", GetDashboardTags)
  18. bus.AddHandler("sql", GetDashboardSlugById)
  19. }
  20. func SaveDashboard(cmd *m.SaveDashboardCommand) error {
  21. return inTransaction(func(sess *xorm.Session) error {
  22. dash := cmd.GetDashboardModel()
  23. // try get existing dashboard
  24. var existing, sameTitle m.Dashboard
  25. if dash.Id > 0 {
  26. dashWithIdExists, err := sess.Where("id=? AND org_id=?", dash.Id, dash.OrgId).Get(&existing)
  27. if err != nil {
  28. return err
  29. }
  30. if !dashWithIdExists {
  31. return m.ErrDashboardNotFound
  32. }
  33. // check for is someone else has written in between
  34. if dash.Version != existing.Version {
  35. if cmd.Overwrite {
  36. dash.Version = existing.Version
  37. } else {
  38. return m.ErrDashboardVersionMismatch
  39. }
  40. }
  41. }
  42. sameTitleExists, err := sess.Where("org_id=? AND slug=?", dash.OrgId, dash.Slug).Get(&sameTitle)
  43. if err != nil {
  44. return err
  45. }
  46. if sameTitleExists {
  47. // another dashboard with same name
  48. if dash.Id != sameTitle.Id {
  49. if cmd.Overwrite {
  50. dash.Id = sameTitle.Id
  51. } else {
  52. return m.ErrDashboardWithSameNameExists
  53. }
  54. }
  55. }
  56. affectedRows := int64(0)
  57. if dash.Id == 0 {
  58. metrics.M_Models_Dashboard_Insert.Inc(1)
  59. affectedRows, err = sess.Insert(dash)
  60. } else {
  61. dash.Version += 1
  62. dash.Data.Set("version", dash.Version)
  63. affectedRows, err = sess.Id(dash.Id).Update(dash)
  64. }
  65. if affectedRows == 0 {
  66. return m.ErrDashboardNotFound
  67. }
  68. // delete existing tabs
  69. _, err = sess.Exec("DELETE FROM dashboard_tag WHERE dashboard_id=?", dash.Id)
  70. if err != nil {
  71. return err
  72. }
  73. // insert new tags
  74. tags := dash.GetTags()
  75. if len(tags) > 0 {
  76. for _, tag := range tags {
  77. if _, err := sess.Insert(&DashboardTag{DashboardId: dash.Id, Term: tag}); err != nil {
  78. return err
  79. }
  80. }
  81. }
  82. cmd.Result = dash
  83. return err
  84. })
  85. }
  86. func GetDashboard(query *m.GetDashboardQuery) error {
  87. dashboard := m.Dashboard{Slug: query.Slug, OrgId: query.OrgId}
  88. has, err := x.Get(&dashboard)
  89. if err != nil {
  90. return err
  91. } else if has == false {
  92. return m.ErrDashboardNotFound
  93. }
  94. dashboard.Data.Set("id", dashboard.Id)
  95. query.Result = &dashboard
  96. return nil
  97. }
  98. type DashboardSearchProjection struct {
  99. Id int64
  100. Title string
  101. Slug string
  102. Term string
  103. }
  104. func SearchDashboards(query *search.FindPersistedDashboardsQuery) error {
  105. limit := query.Limit
  106. if limit == 0 {
  107. limit = 1000
  108. }
  109. var sql bytes.Buffer
  110. params := make([]interface{}, 0)
  111. sql.WriteString(`SELECT
  112. dashboard.id,
  113. dashboard.title,
  114. dashboard.slug,
  115. dashboard_tag.term
  116. FROM dashboard
  117. LEFT OUTER JOIN dashboard_tag on dashboard_tag.dashboard_id = dashboard.id`)
  118. if query.IsStarred {
  119. sql.WriteString(" INNER JOIN star on star.dashboard_id = dashboard.id")
  120. }
  121. sql.WriteString(` WHERE dashboard.org_id=?`)
  122. params = append(params, query.OrgId)
  123. if query.IsStarred {
  124. sql.WriteString(` AND star.user_id=?`)
  125. params = append(params, query.UserId)
  126. }
  127. if len(query.DashboardIds) > 0 {
  128. sql.WriteString(" AND (")
  129. for i, dashboardId := range query.DashboardIds {
  130. if i != 0 {
  131. sql.WriteString(" OR")
  132. }
  133. sql.WriteString(" dashboard.id = ?")
  134. params = append(params, dashboardId)
  135. }
  136. sql.WriteString(")")
  137. }
  138. if len(query.Title) > 0 {
  139. sql.WriteString(" AND dashboard.title " + dialect.LikeStr() + " ?")
  140. params = append(params, "%"+query.Title+"%")
  141. }
  142. sql.WriteString(fmt.Sprintf(" ORDER BY dashboard.title ASC LIMIT ?"))
  143. params = append(params, limit)
  144. var res []DashboardSearchProjection
  145. err := x.Sql(sql.String(), params...).Find(&res)
  146. if err != nil {
  147. return err
  148. }
  149. query.Result = make([]*search.Hit, 0)
  150. hits := make(map[int64]*search.Hit)
  151. for _, item := range res {
  152. hit, exists := hits[item.Id]
  153. if !exists {
  154. hit = &search.Hit{
  155. Id: item.Id,
  156. Title: item.Title,
  157. Uri: "db/" + item.Slug,
  158. Type: search.DashHitDB,
  159. Tags: []string{},
  160. }
  161. query.Result = append(query.Result, hit)
  162. hits[item.Id] = hit
  163. }
  164. if len(item.Term) > 0 {
  165. hit.Tags = append(hit.Tags, item.Term)
  166. }
  167. }
  168. return err
  169. }
  170. func GetDashboardTags(query *m.GetDashboardTagsQuery) error {
  171. sql := `SELECT
  172. COUNT(*) as count,
  173. term
  174. FROM dashboard
  175. INNER JOIN dashboard_tag on dashboard_tag.dashboard_id = dashboard.id
  176. WHERE dashboard.org_id=?
  177. GROUP BY term`
  178. query.Result = make([]*m.DashboardTagCloudItem, 0)
  179. sess := x.Sql(sql, query.OrgId)
  180. err := sess.Find(&query.Result)
  181. return err
  182. }
  183. func DeleteDashboard(cmd *m.DeleteDashboardCommand) error {
  184. return inTransaction2(func(sess *session) error {
  185. dashboard := m.Dashboard{Slug: cmd.Slug, OrgId: cmd.OrgId}
  186. has, err := sess.Get(&dashboard)
  187. if err != nil {
  188. return err
  189. } else if has == false {
  190. return m.ErrDashboardNotFound
  191. }
  192. deletes := []string{
  193. "DELETE FROM dashboard_tag WHERE dashboard_id = ? ",
  194. "DELETE FROM star WHERE dashboard_id = ? ",
  195. "DELETE FROM dashboard WHERE id = ?",
  196. }
  197. for _, sql := range deletes {
  198. _, err := sess.Exec(sql, dashboard.Id)
  199. if err != nil {
  200. return err
  201. }
  202. }
  203. if err := DeleteAlertDefinition(dashboard.Id, sess.Session); err != nil {
  204. return nil
  205. }
  206. return nil
  207. })
  208. }
  209. func GetDashboards(query *m.GetDashboardsQuery) error {
  210. if len(query.DashboardIds) == 0 {
  211. return m.ErrCommandValidationFailed
  212. }
  213. var dashboards = make([]m.Dashboard, 0)
  214. err := x.In("id", query.DashboardIds).Find(&dashboards)
  215. query.Result = &dashboards
  216. if err != nil {
  217. return err
  218. }
  219. return nil
  220. }
  221. type DashboardSlugDTO struct {
  222. Slug string
  223. }
  224. func GetDashboardSlugById(query *m.GetDashboardSlugByIdQuery) error {
  225. var rawSql = `SELECT slug from dashboard WHERE Id=?`
  226. var slug = DashboardSlugDTO{}
  227. exists, err := x.Sql(rawSql, query.Id).Get(&slug)
  228. if err != nil {
  229. return err
  230. } else if exists == false {
  231. return m.ErrDashboardNotFound
  232. }
  233. query.Result = slug.Slug
  234. return nil
  235. }