Dashboard snapshot: added delete key which can be used to delete snapshots, #1623

This commit is contained in:
Torkel Ödegaard 2015-03-26 20:34:58 +01:00
parent 7d0ae23c0e
commit 4322f29f34
7 changed files with 97 additions and 26 deletions

View File

@ -44,7 +44,9 @@ func Register(r *macaron.Macaron) {
// dashboard snapshots // dashboard snapshots
r.Post("/api/snapshots/", bind(m.CreateDashboardSnapshotCommand{}), CreateDashboardSnapshot) r.Post("/api/snapshots/", bind(m.CreateDashboardSnapshotCommand{}), CreateDashboardSnapshot)
r.Get("/dashboard/snapshots/*", Index) r.Get("/dashboard/snapshots/*", Index)
r.Get("/api/snapshots/:key", GetDashboardSnapshot) r.Get("/api/snapshots/:key", GetDashboardSnapshot)
r.Get("/api/snapshots-delete/:key", DeleteDashboardSnapshot)
// authed api // authed api
r.Group("/api", func() { r.Group("/api", func() {

View File

@ -1,7 +1,6 @@
package api package api
import ( import (
"strconv"
"time" "time"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
@ -15,12 +14,15 @@ import (
func CreateDashboardSnapshot(c *middleware.Context, cmd m.CreateDashboardSnapshotCommand) { func CreateDashboardSnapshot(c *middleware.Context, cmd m.CreateDashboardSnapshotCommand) {
cmd.Key = util.GetRandomString(32) cmd.Key = util.GetRandomString(32)
cmd.DeleteKey = util.GetRandomString(32)
if cmd.External { if cmd.External {
cmd.OrgId = -1 cmd.OrgId = -1
cmd.UserId = -1
metrics.M_Api_Dashboard_Snapshot_External.Inc(1) metrics.M_Api_Dashboard_Snapshot_External.Inc(1)
} else { } else {
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
cmd.UserId = c.UserId
metrics.M_Api_Dashboard_Snapshot_Create.Inc(1) metrics.M_Api_Dashboard_Snapshot_Create.Inc(1)
} }
@ -29,7 +31,12 @@ func CreateDashboardSnapshot(c *middleware.Context, cmd m.CreateDashboardSnapsho
return return
} }
c.JSON(200, util.DynMap{"key": cmd.Key, "url": setting.ToAbsUrl("dashboard/snapshot/" + cmd.Key)}) c.JSON(200, util.DynMap{
"key": cmd.Key,
"deleteKey": cmd.DeleteKey,
"url": setting.ToAbsUrl("dashboard/snapshot/" + cmd.Key),
"deleteUrl": setting.ToAbsUrl("api/snapshots-delete/" + cmd.DeleteKey),
})
} }
func GetDashboardSnapshot(c *middleware.Context) { func GetDashboardSnapshot(c *middleware.Context) {
@ -58,9 +65,18 @@ func GetDashboardSnapshot(c *middleware.Context) {
metrics.M_Api_Dashboard_Snapshot_Get.Inc(1) metrics.M_Api_Dashboard_Snapshot_Get.Inc(1)
maxAge := int64(snapshot.Expires.Sub(time.Now()).Seconds()) c.Resp.Header().Set("Cache-Control", "public, max-age=3600")
c.Resp.Header().Set("Cache-Control", "public, max-age="+strconv.FormatInt(maxAge, 10))
c.JSON(200, dto) c.JSON(200, dto)
} }
func DeleteDashboardSnapshot(c *middleware.Context) {
key := c.Params(":key")
cmd := &m.DeleteDashboardSnapshotCommand{DeleteKey: key}
if err := bus.Dispatch(cmd); err != nil {
c.JsonApiErr(500, "Failed to delete dashboard snapshot", err)
return
}
c.JSON(200, util.DynMap{"message": "Snapshot deleted. It might take an hour before it is cleared from a CDN cache."})
}

View File

@ -4,10 +4,14 @@ import "time"
// DashboardSnapshot model // DashboardSnapshot model
type DashboardSnapshot struct { type DashboardSnapshot struct {
Id int64 Id int64
Name string Name string
Key string Key string
OrgId int64 DeleteKey string
OrgId int64
UserId int64
External bool
ExternalUrl string
Expires time.Time Expires time.Time
Created time.Time Created time.Time
@ -20,16 +24,23 @@ type DashboardSnapshot struct {
// COMMANDS // COMMANDS
type CreateDashboardSnapshotCommand struct { type CreateDashboardSnapshotCommand struct {
Dashboard map[string]interface{} `json:"dashboard" binding:"Required"` Dashboard map[string]interface{} `json:"dashboard" binding:"Required"`
External bool `json:"external"` External bool `json:"external"`
Expires int64 `json:"expires"` ExternalUrl string `json:"externalUrl"`
Expires int64 `json:"expires"`
OrgId int64 `json:"-"` OrgId int64 `json:"-"`
Key string `json:"-"` UserId int64 `json:"-"`
Key string `json:"-"`
DeleteKey string `json:"-"`
Result *DashboardSnapshot Result *DashboardSnapshot
} }
type DeleteDashboardSnapshotCommand struct {
DeleteKey string `json:"-"`
}
type GetDashboardSnapshotQuery struct { type GetDashboardSnapshotQuery struct {
Key string Key string

View File

@ -11,6 +11,7 @@ import (
func init() { func init() {
bus.AddHandler("sql", CreateDashboardSnapshot) bus.AddHandler("sql", CreateDashboardSnapshot)
bus.AddHandler("sql", GetDashboardSnapshot) bus.AddHandler("sql", GetDashboardSnapshot)
bus.AddHandler("sql", DeleteDashboardSnapshot)
} }
func CreateDashboardSnapshot(cmd *m.CreateDashboardSnapshotCommand) error { func CreateDashboardSnapshot(cmd *m.CreateDashboardSnapshotCommand) error {
@ -23,12 +24,16 @@ func CreateDashboardSnapshot(cmd *m.CreateDashboardSnapshotCommand) error {
} }
snapshot := &m.DashboardSnapshot{ snapshot := &m.DashboardSnapshot{
Key: cmd.Key, Key: cmd.Key,
OrgId: cmd.OrgId, DeleteKey: cmd.DeleteKey,
Dashboard: cmd.Dashboard, OrgId: cmd.OrgId,
Expires: expires, UserId: cmd.UserId,
Created: time.Now(), External: cmd.External,
Updated: time.Now(), ExternalUrl: cmd.ExternalUrl,
Dashboard: cmd.Dashboard,
Expires: expires,
Created: time.Now(),
Updated: time.Now(),
} }
_, err := sess.Insert(snapshot) _, err := sess.Insert(snapshot)
@ -38,6 +43,14 @@ func CreateDashboardSnapshot(cmd *m.CreateDashboardSnapshotCommand) error {
}) })
} }
func DeleteDashboardSnapshot(cmd *m.DeleteDashboardSnapshotCommand) error {
return inTransaction(func(sess *xorm.Session) error {
var rawSql = "DELETE FROM dashboard_snapshot WHERE delete_key=?"
_, err := sess.Exec(rawSql, cmd.DeleteKey)
return err
})
}
func GetDashboardSnapshot(query *m.GetDashboardSnapshotQuery) error { func GetDashboardSnapshot(query *m.GetDashboardSnapshotQuery) error {
snapshot := m.DashboardSnapshot{Key: query.Key} snapshot := m.DashboardSnapshot{Key: query.Key}
has, err := x.Get(&snapshot) has, err := x.Get(&snapshot)

View File

@ -19,12 +19,36 @@ func addDashboardSnapshotMigrations(mg *Migrator) {
}, },
} }
// add v4
mg.AddMigration("create dashboard_snapshot table v4", NewAddTableMigration(snapshotV4)) mg.AddMigration("create dashboard_snapshot table v4", NewAddTableMigration(snapshotV4))
addTableIndicesMigrations(mg, "v4", snapshotV4)
mg.AddMigration("add org_id to dashboard_snapshot", new(AddColumnMigration). // drop v4
Table("dashboard_snapshot").Column(&Column{Name: "org_id", Type: DB_BigInt, Nullable: true})) addDropAllIndicesMigrations(mg, "v4", snapshotV4)
mg.AddMigration("drop table dashboard_snapshot_v4 #1", NewDropTableMigration("dashboard_snapshot"))
mg.AddMigration("add index org_id to dashboard_snapshot", snapshotV5 := Table{
NewAddIndexMigration(snapshotV4, &Index{Cols: []string{"org_id"}})) Name: "dashboard_snapshot",
Columns: []*Column{
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false},
{Name: "key", Type: DB_NVarchar, Length: 255, Nullable: false},
{Name: "delete_key", Type: DB_NVarchar, Length: 255, Nullable: false},
{Name: "org_id", Type: DB_BigInt, Nullable: false},
{Name: "user_id", Type: DB_BigInt, Nullable: false},
{Name: "external", Type: DB_Bool, Nullable: false},
{Name: "external_url", Type: DB_NVarchar, Length: 255, Nullable: false},
{Name: "dashboard", Type: DB_Text, Nullable: false},
{Name: "expires", Type: DB_DateTime, Nullable: false},
{Name: "created", Type: DB_DateTime, Nullable: false},
{Name: "updated", Type: DB_DateTime, Nullable: false},
},
Indices: []*Index{
{Cols: []string{"key"}, Type: UniqueIndex},
{Cols: []string{"delete_key"}, Type: UniqueIndex},
{Cols: []string{"user_id"}},
},
}
mg.AddMigration("create dashboard_snapshot table v5 #2", NewAddTableMigration(snapshotV5))
addTableIndicesMigrations(mg, "v5", snapshotV5)
} }

View File

@ -110,6 +110,9 @@
</button> </button>
</div> </div>
<div class="pull-right" ng-if="step === 2" style="padding: 5px">
Did you make a mistake? <a href="{{deleteUrl}}" target="_blank">delete snapshot.</a>
</div>
</div> </div>
</div> </div>

View File

@ -84,10 +84,12 @@ function (angular, _) {
$scope.loading = false; $scope.loading = false;
if (external) { if (external) {
$scope.deleteUrl = results.deleteUrl;
$scope.snapshotUrl = results.url; $scope.snapshotUrl = results.url;
} else { } else {
var baseUrl = $location.absUrl().replace($location.url(), ""); var baseUrl = $location.absUrl().replace($location.url(), "");
$scope.snapshotUrl = baseUrl + '/dashboard/snapshot/' + results.key; $scope.snapshotUrl = baseUrl + '/dashboard/snapshot/' + results.key;
$scope.deleteUrl = baseUrl + '/api/snapshots-delete/' + results.deleteKey;
} }
$scope.step = 2; $scope.step = 2;