Skip to content

Commit 52e05e5

Browse files
committed
Delete all data from user on delete
1 parent 61506c6 commit 52e05e5

File tree

10 files changed

+218
-20
lines changed

10 files changed

+218
-20
lines changed

dashboard/dashboard_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,22 @@ func TestDashboard(t *testing.T) {
8383
require.NoError(t, err)
8484
require.Empty(t, dashboards)
8585
}
86+
87+
func TestDeleteDashboard(t *testing.T) {
88+
db := test.InMemoryDB(t)
89+
defer db.Close()
90+
91+
dbOne := db.User(1).Dashboard("test")
92+
dbOne.Range("r")
93+
dbOne.Entry("e")
94+
dbTwo := db.User(2).Dashboard("test")
95+
dbTwo.Range("r")
96+
dbTwo.Entry("e")
97+
98+
resolver := NewResolverForDashboard(db.DB)
99+
_, err := resolver.RemoveDashboard(fake.User(dbOne.User.ID), dbOne.Dashboard.ID)
100+
require.NoError(t, err)
101+
102+
dbOne.AssertExists(false).AssertHasEntry("e", false).AssertHasRange("r", false)
103+
dbTwo.AssertExists(true).AssertHasEntry("e", true).AssertHasRange("r", true)
104+
}

database/database.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ func New(dialect, connection string) (*gorm.DB, error) {
3636
// concurrent writes, so we limit sqlite to one connection.
3737
// see https://github.com/mattn/go-sqlite3/issues/274
3838
db.DB().SetMaxOpenConns(1)
39+
db.Exec("PRAGMA foreign_keys = ON")
3940
}
4041

4142
log.Debug().Msg("Auto migrating schema's")

model/dashboard.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
type DashboardRange struct {
1010
ID int `gorm:"primary_key;unique_index;AUTO_INCREMENT"`
1111
Name string
12-
DashboardID int
12+
DashboardID int `gorm:"type:int REFERENCES dashboards(id) ON DELETE CASCADE"`
1313
Editable bool
1414
From string
1515
To string
@@ -18,7 +18,7 @@ type DashboardRange struct {
1818
// Dashboard a dashboard
1919
type Dashboard struct {
2020
ID int `gorm:"primary_key;unique_index;AUTO_INCREMENT"`
21-
UserID int
21+
UserID int `gorm:"type:int REFERENCES users(id) ON DELETE CASCADE"`
2222
Name string
2323
Entries []DashboardEntry
2424
Ranges []DashboardRange
@@ -27,7 +27,7 @@ type Dashboard struct {
2727
// DashboardEntry an entry which represents a diagram in a dashboard.
2828
type DashboardEntry struct {
2929
ID int `gorm:"primary_key;unique_index;AUTO_INCREMENT"`
30-
DashboardID int
30+
DashboardID int `gorm:"type:int REFERENCES dashboards(id) ON DELETE CASCADE"`
3131
Title string
3232
Type DashboardType
3333
Keys string

model/device.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type Device struct {
1212
ID int `gorm:"primary_key;unique_index;AUTO_INCREMENT"`
1313
Token string `gorm:"unique"`
1414
Name string
15-
UserID int
15+
UserID int `gorm:"type:int REFERENCES users(id) ON DELETE CASCADE"`
1616
CreatedAt time.Time
1717
Type DeviceType
1818
ActiveAt time.Time

model/tagdefinition.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package model
33
// TagDefinition describes a tag.
44
type TagDefinition struct {
55
Key string
6-
UserID int
6+
UserID int `gorm:"type:int REFERENCES users(id) ON DELETE CASCADE"`
77
Color string
88
Type TagDefinitionType
99
}

model/timespan.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ type TimeSpan struct {
1010
StartUserTime time.Time
1111
EndUserTime *time.Time
1212
OffsetUTC int
13-
UserID int
13+
UserID int `gorm:"type:int REFERENCES users(id) ON DELETE CASCADE"`
1414
Tags []TimeSpanTag
1515
}
1616

1717
// TimeSpanTag is a tag for a time range
1818
type TimeSpanTag struct {
19-
TimeSpanID int
19+
TimeSpanID int `gorm:"type:int REFERENCES time_spans(id) ON DELETE CASCADE"`
2020
Key string
2121
StringValue *string
2222
}

test/db.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ func (d *UserWithDatabase) AssertHasTagDefinition(key string, exist bool) *UserW
7575
return d
7676
}
7777

78+
// AssertHasDevice asserts if a device exists.
79+
func (d *UserWithDatabase) AssertHasDevice(name string, exist bool) *UserWithDatabase {
80+
existActual := !d.DB.
81+
Where(&model.Device{Name: name, UserID: d.User.ID}).
82+
Find(new(model.Device)).
83+
RecordNotFound()
84+
assert.True(d.t, exist == existActual)
85+
return d
86+
}
87+
7888
// NewUser creates a user
7989
func (d *Database) NewUser(id int, name string, admin bool) model.User {
8090
return d.NewUserPass(id, name, []byte{1, 2, 3}, admin)
@@ -92,6 +102,16 @@ func (d *Database) NewUserPass(id int, name string, pass []byte, admin bool) mod
92102
return user
93103
}
94104

105+
// AssertExists asserts if the tag exists or not.
106+
func (d *UserWithDatabase) AssertExists(exist bool) *UserWithDatabase {
107+
existActual := !d.DB.
108+
Where(&model.User{ID: d.User.ID}).
109+
Find(new(model.User)).
110+
RecordNotFound()
111+
assert.True(d.t, exist == existActual)
112+
return d
113+
}
114+
95115
// RunningTimeSpan adds a time span without end.
96116
func (d *UserWithDatabase) RunningTimeSpan(from string) *TimeSpanWithDatabase {
97117
timeSpan := model.TimeSpan{
@@ -110,6 +130,77 @@ func (d *UserWithDatabase) RunningTimeSpan(from string) *TimeSpanWithDatabase {
110130
}
111131
}
112132

133+
// RunningTimeSpan adds a time span without end.
134+
func (d *UserWithDatabase) Dashboard(name string) *DashboardWithDatabase {
135+
dashboard := model.Dashboard{
136+
UserID: d.User.ID,
137+
Name: name,
138+
}
139+
140+
d.DB.Create(&dashboard)
141+
142+
return &DashboardWithDatabase{
143+
User: d.User,
144+
Dashboard: dashboard,
145+
DB: d.DB,
146+
t: d.t,
147+
}
148+
}
149+
150+
// Range adds a range to the dashboard.
151+
func (d *DashboardWithDatabase) Range(name string) *DashboardWithDatabase {
152+
dbRange := model.DashboardRange{
153+
DashboardID: d.Dashboard.ID,
154+
Name: name,
155+
From: "now-1d",
156+
To: "now",
157+
}
158+
d.Dashboard.Ranges = append(d.Dashboard.Ranges, dbRange)
159+
d.DB.Save(&dbRange)
160+
return d
161+
}
162+
163+
// Entry adds an entry to the dashboard.
164+
func (d *DashboardWithDatabase) Entry(name string) *DashboardWithDatabase {
165+
entry := model.DashboardEntry{
166+
DashboardID: d.Dashboard.ID,
167+
Title: name,
168+
}
169+
d.Dashboard.Entries = append(d.Dashboard.Entries, entry)
170+
d.DB.Save(&entry)
171+
return d
172+
}
173+
174+
// AssertExists asserts if the dashboard exists or not.
175+
func (d *DashboardWithDatabase) AssertExists(exist bool) *DashboardWithDatabase {
176+
existActual := !d.DB.
177+
Where(&model.Dashboard{ID: d.Dashboard.ID}).
178+
Find(new(model.Dashboard)).
179+
RecordNotFound()
180+
assert.True(d.t, exist == existActual)
181+
return d
182+
}
183+
184+
// AssertHasEntry asserts if the entry exists or not.
185+
func (d *DashboardWithDatabase) AssertHasEntry(name string, exist bool) *DashboardWithDatabase {
186+
existActual := !d.DB.
187+
Where(&model.DashboardEntry{DashboardID: d.Dashboard.ID, Title: name}).
188+
Find(new(model.DashboardEntry)).
189+
RecordNotFound()
190+
assert.True(d.t, exist == existActual)
191+
return d
192+
}
193+
194+
// AssertHasRange asserts if the range exists or not.
195+
func (d *DashboardWithDatabase) AssertHasRange(name string, exist bool) *DashboardWithDatabase {
196+
existActual := !d.DB.
197+
Where(&model.DashboardRange{DashboardID: d.Dashboard.ID, Name: name}).
198+
Find(new(model.DashboardRange)).
199+
RecordNotFound()
200+
assert.True(d.t, exist == existActual)
201+
return d
202+
}
203+
113204
// TimeSpan adds a time span.
114205
func (d *UserWithDatabase) TimeSpan(from string, to string) *TimeSpanWithDatabase {
115206
wrapper := d.RunningTimeSpan(from)
@@ -160,3 +251,11 @@ func (d *TimeSpanWithDatabase) Tag(key string, stringValue string) *TimeSpanWith
160251
d.DB.Save(tag)
161252
return d
162253
}
254+
255+
// DashboardWithDatabase wraps gorm.DB and provides helper methods
256+
type DashboardWithDatabase struct {
257+
User model.User
258+
Dashboard model.Dashboard
259+
t assert.TestingT
260+
*gorm.DB
261+
}

test/db_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ func TestDatabase(t *testing.T) {
1818
db := test.InMemoryDB(t)
1919
defer db.Close()
2020
user := db.User(1)
21+
user.AssertHasDevice("test device", false)
2122
user.NewDevice(1, "lol", "test device")
23+
user.AssertHasDevice("test device", true)
2224
ts := user.TimeSpan("2009-06-30T18:30:00Z", "2009-06-30T18:40:00Z")
2325

2426
ts.AssertHasTag("abc", "def", false)
@@ -77,4 +79,21 @@ func TestDatabase(t *testing.T) {
7779
user.NewTagDefinition("oops")
7880
user.AssertHasTagDefinition("oops", true)
7981

82+
user.AssertExists(true)
83+
db.Delete(new(model.User), "id = ?", user.User.ID)
84+
user.AssertExists(false)
85+
86+
dash := user.Dashboard("hello")
87+
88+
dash.AssertHasRange("hello", false)
89+
dash.Range("hello")
90+
dash.AssertHasRange("hello", true)
91+
92+
dash.AssertHasEntry("abc", false)
93+
dash.Entry("abc")
94+
dash.AssertHasEntry("abc", true)
95+
96+
dash.AssertExists(true)
97+
db.Delete(new(model.Dashboard), "id = ?", dash.Dashboard.ID)
98+
dash.AssertExists(false)
8099
}

timespan/remove.go

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,7 @@ func (r *ResolverForTimeSpan) RemoveTimeSpan(ctx context.Context, id int) (*gqlm
1616
return nil, fmt.Errorf("timespan with id %d does not exist", timeSpan.ID)
1717
}
1818

19-
tx := r.DB.Begin()
20-
21-
if err := tx.Delete(&timeSpan).Error; err != nil {
22-
tx.Rollback()
23-
return nil, err
24-
}
25-
26-
if err := tx.Where(&model.TimeSpanTag{TimeSpanID: timeSpan.ID}).Delete(new(model.TimeSpanTag)).Error; err != nil {
27-
tx.Rollback()
28-
return nil, err
29-
}
30-
31-
remove := tx.Commit()
19+
remove := r.DB.Where(&model.TimeSpan{ID: id}).Delete(new(model.TimeSpan))
3220

3321
external := timeSpanToExternal(timeSpan)
3422
return external, remove.Error

user/remove_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,78 @@ func TestGQL_RemoveUser_succeeds_removesUser(t *testing.T) {
2020
assertUserCount(t, db, 0)
2121
}
2222

23+
func TestGQL_RemoveUser_succeeds_removesDevices(t *testing.T) {
24+
test.LogDebug()
25+
db := test.InMemoryDB(t)
26+
defer db.Close()
27+
user := db.User(1)
28+
user.NewDevice(2, "abc", "devicename")
29+
other := db.User(2)
30+
other.NewDevice(5, "abcx", "devicename")
31+
32+
resolver := ResolverForUser{DB: db.DB, PassStrength: 4}
33+
_, err := resolver.RemoveUser(context.Background(), 1)
34+
35+
require.Nil(t, err)
36+
user.AssertHasDevice("devicename", false).AssertExists(false)
37+
other.AssertExists(true).AssertHasDevice("devicename", true)
38+
}
39+
40+
func TestGQL_RemoveUser_succeeds_removesTags(t *testing.T) {
41+
db := test.InMemoryDB(t)
42+
defer db.Close()
43+
user := db.User(1)
44+
user.NewTagDefinition("oops")
45+
other := db.User(2)
46+
other.NewTagDefinition("oops")
47+
48+
resolver := ResolverForUser{DB: db.DB, PassStrength: 4}
49+
_, err := resolver.RemoveUser(context.Background(), 1)
50+
51+
require.Nil(t, err)
52+
user.AssertExists(false).AssertHasTagDefinition("oops", false)
53+
other.AssertExists(true).AssertHasTagDefinition("oops", true)
54+
}
55+
56+
func TestGQL_RemoveUser_succeeds_removesTimeSpans(t *testing.T) {
57+
db := test.InMemoryDB(t)
58+
defer db.Close()
59+
user := db.User(1)
60+
other := db.User(2)
61+
ts := user.TimeSpan("2019-06-11T18:00:00Z", "2019-06-11T18:00:00Z")
62+
ts.Tag("hello", "world")
63+
otherTs := other.TimeSpan("2019-06-11T18:00:00Z", "2019-06-11T18:00:00Z")
64+
otherTs.Tag("hello", "world")
65+
66+
resolver := ResolverForUser{DB: db.DB, PassStrength: 4}
67+
_, err := resolver.RemoveUser(context.Background(), 1)
68+
69+
require.Nil(t, err)
70+
ts.AssertExists(false).AssertHasTag("hello", "world", false)
71+
otherTs.AssertExists(true).AssertHasTag("hello", "world", true)
72+
}
73+
74+
func TestGQL_RemoveUser_succeeds_removesDashboard(t *testing.T) {
75+
db := test.InMemoryDB(t)
76+
defer db.Close()
77+
user := db.User(1)
78+
other := db.User(2)
79+
userDB := user.Dashboard("cool")
80+
userDB.Range("cool range")
81+
userDB.Entry("cool entry")
82+
83+
otherDB := other.Dashboard("cool")
84+
otherDB.Range("cool range")
85+
otherDB.Entry("cool entry")
86+
87+
resolver := ResolverForUser{DB: db.DB, PassStrength: 4}
88+
_, err := resolver.RemoveUser(context.Background(), 1)
89+
90+
require.Nil(t, err)
91+
userDB.AssertExists(false).AssertHasRange("cool range", false).AssertHasEntry("cool entry", false)
92+
otherDB.AssertExists(true).AssertHasRange("cool range", true).AssertHasEntry("cool entry", true)
93+
}
94+
2395
func TestGQL_RemoveUser_fails_notExistingUser(t *testing.T) {
2496
db := test.InMemoryDB(t)
2597
defer db.Close()

0 commit comments

Comments
 (0)