mirror of
https://github.com/juanfont/headscale.git
synced 2024-11-29 18:33:05 +00:00
fix constraints
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
parent
60b9595929
commit
4f57410a5b
3 changed files with 30 additions and 11 deletions
|
@ -498,6 +498,25 @@ func NewHeadscaleDatabase(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up indexes and unique constraints outside of GORM, it does not support
|
||||||
|
// conditional unique constraints.
|
||||||
|
// This ensures the following:
|
||||||
|
// - A user name and provider_identifier is unique
|
||||||
|
// - A provider_identifier is unique
|
||||||
|
// - A user name is unique if there is no provider_identifier is not set
|
||||||
|
for _, idx := range []string{
|
||||||
|
"DROP INDEX IF EXISTS `idx_provider_identifier`",
|
||||||
|
"DROP INDEX IF EXISTS `idx_name_provider_identifier`",
|
||||||
|
"CREATE UNIQUE INDEX IF NOT EXISTS `idx_provider_identifier` ON `users` (`provider_identifier`) WHERE provider_identifier IS NOT NULL;",
|
||||||
|
"CREATE UNIQUE INDEX IF NOT EXISTS `idx_name_provider_identifier` ON `users` (`name`,`provider_identifier`);",
|
||||||
|
"CREATE UNIQUE INDEX IF NOT EXISTS `idx_name_no_provider_identifier` ON `users` (`name`) WHERE provider_identifier IS NULL;",
|
||||||
|
} {
|
||||||
|
err = tx.Exec(idx).Error
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("creating username index: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Rollback: func(db *gorm.DB) error { return nil },
|
Rollback: func(db *gorm.DB) error { return nil },
|
||||||
|
|
|
@ -271,8 +271,8 @@ func TestConstraints(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
_, err = CreateUser(db, "user1")
|
_, err = CreateUser(db, "user1")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
// assert.Contains(t, err.Error(), "UNIQUE constraint failed: users.username")
|
assert.Contains(t, err.Error(), "UNIQUE constraint failed:")
|
||||||
require.Contains(t, err.Error(), "user already exists")
|
// require.Contains(t, err.Error(), "user already exists")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -295,7 +295,7 @@ func TestConstraints(t *testing.T) {
|
||||||
|
|
||||||
err = db.Save(&user).Error
|
err = db.Save(&user).Error
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.Contains(t, err.Error(), "UNIQUE constraint failed: users.provider_identifier")
|
require.Contains(t, err.Error(), "UNIQUE constraint failed:")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -318,7 +318,7 @@ func TestConstraints(t *testing.T) {
|
||||||
|
|
||||||
err = db.Save(&user).Error
|
err = db.Save(&user).Error
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.Contains(t, err.Error(), "UNIQUE constraint failed: users.provider_identifier")
|
require.Contains(t, err.Error(), "UNIQUE constraint failed:")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -329,8 +329,8 @@ func TestConstraints(t *testing.T) {
|
||||||
|
|
||||||
user := types.User{
|
user := types.User{
|
||||||
Name: "user1",
|
Name: "user1",
|
||||||
|
ProviderIdentifier: sql.NullString{String: "http://test.com/user1", Valid: true},
|
||||||
}
|
}
|
||||||
user.ProviderIdentifier.String = "http://test.com/user1"
|
|
||||||
|
|
||||||
err = db.Save(&user).Error
|
err = db.Save(&user).Error
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -341,8 +341,8 @@ func TestConstraints(t *testing.T) {
|
||||||
run: func(t *testing.T, db *gorm.DB) {
|
run: func(t *testing.T, db *gorm.DB) {
|
||||||
user := types.User{
|
user := types.User{
|
||||||
Name: "user1",
|
Name: "user1",
|
||||||
|
ProviderIdentifier: sql.NullString{String: "http://test.com/user1", Valid: true},
|
||||||
}
|
}
|
||||||
user.ProviderIdentifier.String = "http://test.com/user1"
|
|
||||||
|
|
||||||
err := db.Save(&user).Error
|
err := db.Save(&user).Error
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -360,7 +360,7 @@ func TestConstraints(t *testing.T) {
|
||||||
t.Fatalf("creating database: %s", err)
|
t.Fatalf("creating database: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.run(t, db.DB)
|
tt.run(t, db.DB.Debug())
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ type User struct {
|
||||||
|
|
||||||
// Username for the user, is used if email is empty
|
// Username for the user, is used if email is empty
|
||||||
// Should not be used, please use Username().
|
// Should not be used, please use Username().
|
||||||
Name string `gorm:"uniqueIndex:idx_name_provider_identifier;index"`
|
Name string
|
||||||
|
|
||||||
// Typically the full name of the user
|
// Typically the full name of the user
|
||||||
DisplayName string
|
DisplayName string
|
||||||
|
@ -39,7 +39,7 @@ type User struct {
|
||||||
// Unique identifier of the user from OIDC,
|
// Unique identifier of the user from OIDC,
|
||||||
// comes from `sub` claim in the OIDC token
|
// comes from `sub` claim in the OIDC token
|
||||||
// and is used to lookup the user.
|
// and is used to lookup the user.
|
||||||
ProviderIdentifier sql.NullString `gorm:"uniqueIndex:idx_name_provider_identifier;uniqueIndex:idx_provider_identifier"`
|
ProviderIdentifier sql.NullString
|
||||||
|
|
||||||
// Provider is the origin of the user account,
|
// Provider is the origin of the user account,
|
||||||
// same as RegistrationMethod, without authkey.
|
// same as RegistrationMethod, without authkey.
|
||||||
|
|
Loading…
Reference in a new issue