Add initial implementation of grants
This commit is contained in:
parent
b8f1281f78
commit
69b6579de7
15 changed files with 308 additions and 73 deletions
|
|
@ -20,6 +20,7 @@ func (dis *Distillery) init() {
|
||||||
lazy.RegisterPoolGroup[component.Provisionable](&dis.pool)
|
lazy.RegisterPoolGroup[component.Provisionable](&dis.pool)
|
||||||
lazy.RegisterPoolGroup[component.Routeable](&dis.pool)
|
lazy.RegisterPoolGroup[component.Routeable](&dis.pool)
|
||||||
lazy.RegisterPoolGroup[component.Cronable](&dis.pool)
|
lazy.RegisterPoolGroup[component.Cronable](&dis.pool)
|
||||||
|
lazy.RegisterPoolGroup[component.UserDeleteHook](&dis.pool)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@ import (
|
||||||
type Auth struct {
|
type Auth struct {
|
||||||
component.Base
|
component.Base
|
||||||
Dependencies struct {
|
Dependencies struct {
|
||||||
SQL *sql.SQL
|
SQL *sql.SQL
|
||||||
|
UserDeleteHooks []component.UserDeleteHook
|
||||||
}
|
}
|
||||||
|
|
||||||
store lazy.Lazy[sessions.Store]
|
store lazy.Lazy[sessions.Store]
|
||||||
|
|
|
||||||
70
internal/dis/component/auth/permission.go
Normal file
70
internal/dis/component/auth/permission.go
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Permission represents a permission granted to a user.
|
||||||
|
//
|
||||||
|
// The nil permission represents any authenticated user.
|
||||||
|
type Permission func(user *AuthUser, r *http.Request) (ok Grant, err error)
|
||||||
|
|
||||||
|
// Grant represents an object that either grants or denies access for a certain permission
|
||||||
|
type Grant interface {
|
||||||
|
isGranted()
|
||||||
|
|
||||||
|
// Granted returns a boolean indicating if permission to the resource in question
|
||||||
|
// has been granted
|
||||||
|
Granted() bool
|
||||||
|
|
||||||
|
// Denied returns a string containing an error message to display to the user when permission is denied.
|
||||||
|
// When Granted() returns true, the behaviour is undefined.
|
||||||
|
Denied() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool2Grant returns a new grant that returns granted for the given boolean, and message as the denied message.
|
||||||
|
func Bool2Grant(granted bool, message string) Grant {
|
||||||
|
if granted {
|
||||||
|
return grantAllow{}
|
||||||
|
}
|
||||||
|
return grantDeny(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
type grantAllow struct{}
|
||||||
|
|
||||||
|
func (grantAllow) isGranted() {}
|
||||||
|
func (grantAllow) Granted() bool { return true }
|
||||||
|
func (grantAllow) Denied() string { return "" }
|
||||||
|
|
||||||
|
type grantDeny string
|
||||||
|
|
||||||
|
func (grantDeny) isGranted() {}
|
||||||
|
func (g grantDeny) Granted() bool { return false }
|
||||||
|
func (g grantDeny) Denied() string {
|
||||||
|
if g == "" {
|
||||||
|
return "Forbidden"
|
||||||
|
}
|
||||||
|
return string(g)
|
||||||
|
}
|
||||||
|
|
||||||
|
var errPermissionPanic = errors.New("permission: panic()")
|
||||||
|
|
||||||
|
// Permit checks if the given user has this permission.
|
||||||
|
func (perm Permission) Permit(user *AuthUser, r *http.Request) (ok Grant, err error) {
|
||||||
|
// if there is no permission, then we just check if there is some user
|
||||||
|
if perm == nil {
|
||||||
|
return Bool2Grant(user != nil, ""), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// recover any panic()ed permission call
|
||||||
|
// to prevent the handler from panic()ing
|
||||||
|
defer func() {
|
||||||
|
if p := recover(); p != nil {
|
||||||
|
ok = Bool2Grant(false, "unknown error")
|
||||||
|
err = errPermissionPanic
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return perm(user, r)
|
||||||
|
}
|
||||||
123
internal/dis/component/auth/policy/grants.go
Normal file
123
internal/dis/component/auth/policy/grants.go
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
package policy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrNoAccess = errors.New("no access")
|
||||||
|
ErrInvalid = errors.New("invalid parameters")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Set sets a specific grant, overwriting a previous grant (if any)
|
||||||
|
func (policy *Policy) Set(ctx context.Context, grant models.Grant) error {
|
||||||
|
if grant.User == "" || grant.Slug == "" || grant.DrupalUsername == "" {
|
||||||
|
return ErrInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the table
|
||||||
|
table, err := policy.table(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// and create or update the given user / slug combination
|
||||||
|
return table.Clauses(clause.OnConflict{
|
||||||
|
Columns: []clause.Column{{Name: "user"}, {Name: "slug"}},
|
||||||
|
DoUpdates: clause.AssignmentColumns([]string{"drupal_user", "admin"}),
|
||||||
|
}).Create(&grant).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove removes access for the given username form the given instance.
|
||||||
|
// The user not having access is not an error.
|
||||||
|
func (policy *Policy) Remove(ctx context.Context, username string, slug string) error {
|
||||||
|
// empty username or slug never have acccess
|
||||||
|
if username == "" || slug == "" {
|
||||||
|
return ErrInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the table
|
||||||
|
table, err := policy.table(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete the access from the database
|
||||||
|
return table.Delete(&models.Grant{}, models.Grant{User: username, Slug: slug}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// User returns all grants for the given user
|
||||||
|
func (policy *Policy) User(ctx context.Context, username string) (grants []models.Grant, err error) {
|
||||||
|
if username == "" {
|
||||||
|
return nil, ErrInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the table
|
||||||
|
table, err := policy.table(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the grants
|
||||||
|
err = table.Find(&grants, models.Grant{User: username}).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return grants, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instance returns all the grants for the given instance
|
||||||
|
func (policy *Policy) Instance(ctx context.Context, slug string) (grants []models.Grant, err error) {
|
||||||
|
if slug == "" {
|
||||||
|
return nil, ErrInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the table
|
||||||
|
table, err := policy.table(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the grants
|
||||||
|
err = table.Find(&grants, models.Grant{Slug: slug}).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return grants, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Has checks if the given username has access to the given instance.
|
||||||
|
// If the user has access, returns the provided grant.
|
||||||
|
//
|
||||||
|
// If the user does not have access, returns ErrNoAccess.
|
||||||
|
// Other errors may be returned in other cases.
|
||||||
|
func (policy *Policy) Has(ctx context.Context, username string, slug string) (grant models.Grant, err error) {
|
||||||
|
// empty username or slug never have acccess
|
||||||
|
if username == "" || slug == "" {
|
||||||
|
return grant, ErrInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the table
|
||||||
|
table, err := policy.table(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return grant, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the access from the database
|
||||||
|
res := table.Find(&grant, models.Grant{User: username, Slug: slug})
|
||||||
|
if err := res.Error; err != nil {
|
||||||
|
return grant, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there were no rows affected, then there was no access granted
|
||||||
|
if res.RowsAffected == 0 {
|
||||||
|
return grant, ErrNoAccess
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the username and admin
|
||||||
|
return grant, nil
|
||||||
|
}
|
||||||
1
internal/dis/component/auth/policy/info.go
Normal file
1
internal/dis/component/auth/policy/info.go
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
package policy
|
||||||
27
internal/dis/component/auth/policy/policy.go
Normal file
27
internal/dis/component/auth/policy/policy.go
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
package policy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/sql"
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Policy struct {
|
||||||
|
component.Base
|
||||||
|
|
||||||
|
Dependencies struct {
|
||||||
|
SQL *sql.SQL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ component.Provisionable = (*Policy)(nil)
|
||||||
|
_ component.UserDeleteHook = (*Policy)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
func (pol *Policy) table(ctx context.Context) (*gorm.DB, error) {
|
||||||
|
return pol.Dependencies.SQL.QueryTable(ctx, true, models.GrantTable)
|
||||||
|
}
|
||||||
30
internal/dis/component/auth/policy/purge.go
Normal file
30
internal/dis/component/auth/policy/purge.go
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
package policy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (*Policy) Provision(ctx context.Context, instance models.Instance, domain string) error {
|
||||||
|
// component is purge-only
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purge purges every policy for the given slug form the database
|
||||||
|
func (pol *Policy) Purge(ctx context.Context, instance models.Instance, domain string) error {
|
||||||
|
table, err := pol.table(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return table.Delete(&models.Grant{}, &models.Grant{Slug: instance.Slug}).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnUserDelete is called when a user is deleted
|
||||||
|
func (pol *Policy) OnUserDelete(ctx context.Context, user *models.User) error {
|
||||||
|
table, err := pol.table(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return table.Delete(&models.Grant{}, &models.Grant{User: user.User}).Error
|
||||||
|
}
|
||||||
|
|
@ -2,77 +2,12 @@ package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/FAU-CDI/wisski-distillery/pkg/httpx"
|
"github.com/FAU-CDI/wisski-distillery/pkg/httpx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Permission represents a permission granted to a user.
|
|
||||||
//
|
|
||||||
// The nil permission represents any authenticated user.
|
|
||||||
type Permission func(user *AuthUser, r *http.Request) (ok Grant, err error)
|
|
||||||
|
|
||||||
// Grant represents an object that either grants or denies access for a certain permission
|
|
||||||
type Grant interface {
|
|
||||||
isGranted()
|
|
||||||
|
|
||||||
// Granted returns a boolean indicating if permission to the resource in question
|
|
||||||
// has been granted
|
|
||||||
Granted() bool
|
|
||||||
|
|
||||||
// Denied returns a string containing an error message to display to the user when permission is denied.
|
|
||||||
// When Granted() returns true, the behaviour is undefined.
|
|
||||||
Denied() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bool2Grant returns a new grant that returns granted for the given boolean, and message as the denied message.
|
|
||||||
func Bool2Grant(granted bool, message string) Grant {
|
|
||||||
if granted {
|
|
||||||
return grantAllow{}
|
|
||||||
}
|
|
||||||
return grantDeny(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
type grantAllow struct{}
|
|
||||||
|
|
||||||
func (grantAllow) isGranted() {}
|
|
||||||
func (grantAllow) Granted() bool { return true }
|
|
||||||
func (grantAllow) Denied() string { return "" }
|
|
||||||
|
|
||||||
type grantDeny string
|
|
||||||
|
|
||||||
func (grantDeny) isGranted() {}
|
|
||||||
func (g grantDeny) Granted() bool { return false }
|
|
||||||
func (g grantDeny) Denied() string {
|
|
||||||
if g == "" {
|
|
||||||
return "Forbidden"
|
|
||||||
}
|
|
||||||
return string(g)
|
|
||||||
}
|
|
||||||
|
|
||||||
var errPermissionPanic = errors.New("permission: panic()")
|
|
||||||
|
|
||||||
// Permit checks if the given user has this permission.
|
|
||||||
func (perm Permission) Permit(user *AuthUser, r *http.Request) (ok Grant, err error) {
|
|
||||||
// if there is no permission, then we just check if there is some user
|
|
||||||
if perm == nil {
|
|
||||||
return Bool2Grant(user != nil, ""), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// recover any panic()ed permission call
|
|
||||||
// to prevent the handler from panic()ing
|
|
||||||
defer func() {
|
|
||||||
if p := recover(); p != nil {
|
|
||||||
ok = Bool2Grant(false, "unknown error")
|
|
||||||
err = errPermissionPanic
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return perm(user, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Protect returns a new handler which requires a user to be logged in and pass the perm function.
|
// Protect returns a new handler which requires a user to be logged in and pass the perm function.
|
||||||
//
|
//
|
||||||
// If an unauthenticated user attempts to access the returned handler, they are redirected to the login endpoint.
|
// If an unauthenticated user attempts to access the returned handler, they are redirected to the login endpoint.
|
||||||
|
|
|
||||||
|
|
@ -278,5 +278,13 @@ func (au *AuthUser) Delete(ctx context.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// run all the user delete hooks
|
||||||
|
for _, c := range au.auth.Dependencies.UserDeleteHooks {
|
||||||
|
if err := c.OnUserDelete(ctx, &au.User); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return table.Delete(&au.User).Error
|
return table.Delete(&au.User).Error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package malt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/policy"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/exporter/logger"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/exporter/logger"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/meta"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/meta"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/sql"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/sql"
|
||||||
|
|
@ -16,4 +17,5 @@ type Malt struct {
|
||||||
SQL *sql.SQL `auto:"true"`
|
SQL *sql.SQL `auto:"true"`
|
||||||
Meta *meta.Meta `auto:"true"`
|
Meta *meta.Meta `auto:"true"`
|
||||||
ExporterLog *logger.Logger `auto:"true"`
|
ExporterLog *logger.Logger `auto:"true"`
|
||||||
|
Policy *policy.Policy `auto:"true"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ type Storage struct {
|
||||||
// Get retrieves metadata with the provided key and deserializes the first one into target.
|
// Get retrieves metadata with the provided key and deserializes the first one into target.
|
||||||
// If no metadatum exists, returns [ErrMetadatumNotSet].
|
// If no metadatum exists, returns [ErrMetadatumNotSet].
|
||||||
func (s Storage) Get(ctx context.Context, key Key, target any) error {
|
func (s Storage) Get(ctx context.Context, key Key, target any) error {
|
||||||
table, err := s.sql.QueryTable(ctx, true, models.AccessTable)
|
table, err := s.sql.QueryTable(ctx, true, models.GrantTable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -55,7 +55,7 @@ func (s Storage) Get(ctx context.Context, key Key, target any) error {
|
||||||
//
|
//
|
||||||
// When no metadatum exists, targets is not called, and nil error is returned.
|
// When no metadatum exists, targets is not called, and nil error is returned.
|
||||||
func (s Storage) GetAll(ctx context.Context, key Key, target func(index, total int) any) error {
|
func (s Storage) GetAll(ctx context.Context, key Key, target func(index, total int) any) error {
|
||||||
table, err := s.sql.QueryTable(ctx, true, models.AccessTable)
|
table, err := s.sql.QueryTable(ctx, true, models.GrantTable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +82,7 @@ func (s Storage) GetAll(ctx context.Context, key Key, target func(index, total i
|
||||||
|
|
||||||
// Delete deletes all metadata with the provided key.
|
// Delete deletes all metadata with the provided key.
|
||||||
func (s Storage) Delete(ctx context.Context, key Key) error {
|
func (s Storage) Delete(ctx context.Context, key Key) error {
|
||||||
table, err := s.sql.QueryTable(ctx, true, models.AccessTable)
|
table, err := s.sql.QueryTable(ctx, true, models.GrantTable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +98,7 @@ func (s Storage) Delete(ctx context.Context, key Key) error {
|
||||||
// Set serializes value and stores it with the provided key.
|
// Set serializes value and stores it with the provided key.
|
||||||
// Any other metadata with the same key is deleted.
|
// Any other metadata with the same key is deleted.
|
||||||
func (s Storage) Set(ctx context.Context, key Key, value any) error {
|
func (s Storage) Set(ctx context.Context, key Key, value any) error {
|
||||||
table, err := s.sql.QueryTable(ctx, true, models.AccessTable)
|
table, err := s.sql.QueryTable(ctx, true, models.GrantTable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -133,7 +133,7 @@ func (s Storage) Set(ctx context.Context, key Key, value any) error {
|
||||||
// Set serializes values and stores them with the provided key.
|
// Set serializes values and stores them with the provided key.
|
||||||
// Any other metadata with the same key is deleted.
|
// Any other metadata with the same key is deleted.
|
||||||
func (s Storage) SetAll(ctx context.Context, key Key, values ...any) error {
|
func (s Storage) SetAll(ctx context.Context, key Key, values ...any) error {
|
||||||
table, err := s.sql.QueryTable(ctx, true, models.AccessTable)
|
table, err := s.sql.QueryTable(ctx, true, models.GrantTable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -167,7 +167,7 @@ func (s Storage) SetAll(ctx context.Context, key Key, values ...any) error {
|
||||||
|
|
||||||
// Purge removes all metadata, regardless of key.
|
// Purge removes all metadata, regardless of key.
|
||||||
func (s Storage) Purge(ctx context.Context) error {
|
func (s Storage) Purge(ctx context.Context) error {
|
||||||
table, err := s.sql.QueryTable(ctx, true, models.AccessTable)
|
table, err := s.sql.QueryTable(ctx, true, models.GrantTable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ func (sql *SQL) Update(ctx context.Context, progress io.Writer) error {
|
||||||
{
|
{
|
||||||
"metadata",
|
"metadata",
|
||||||
&models.Metadatum{},
|
&models.Metadatum{},
|
||||||
models.AccessTable,
|
models.GrantTable,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"snapshot",
|
"snapshot",
|
||||||
|
|
@ -108,6 +108,11 @@ func (sql *SQL) Update(ctx context.Context, progress io.Writer) error {
|
||||||
&models.User{},
|
&models.User{},
|
||||||
models.UserTable,
|
models.UserTable,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"grant",
|
||||||
|
&models.Grant{},
|
||||||
|
models.GrantTable,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// migrate all of the tables!
|
// migrate all of the tables!
|
||||||
|
|
|
||||||
15
internal/dis/component/userdelete.go
Normal file
15
internal/dis/component/userdelete.go
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package component
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserDeleteHook represents a hook that is called just before a user is deleted
|
||||||
|
type UserDeleteHook interface {
|
||||||
|
Component
|
||||||
|
|
||||||
|
// OnUserDelete is called right before a user is deleted
|
||||||
|
OnUserDelete(ctx context.Context, user *models.User) error
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth"
|
||||||
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/policy"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control/cron"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control/cron"
|
||||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control/home"
|
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control/home"
|
||||||
|
|
@ -127,6 +128,7 @@ func (dis *Distillery) allComponents() []initFunc {
|
||||||
|
|
||||||
// auth
|
// auth
|
||||||
auto[*auth.Auth],
|
auto[*auth.Auth],
|
||||||
|
auto[*policy.Policy],
|
||||||
|
|
||||||
// instances
|
// instances
|
||||||
auto[*instances.Instances],
|
auto[*instances.Instances],
|
||||||
|
|
|
||||||
15
internal/models/grant.go
Normal file
15
internal/models/grant.go
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
// GrantTable is the name of the table the 'Grant' model is stored in.
|
||||||
|
const GrantTable = "grant"
|
||||||
|
|
||||||
|
// Grant represents an access grant to a specific user
|
||||||
|
type Grant struct {
|
||||||
|
Pk uint `gorm:"column:pk;primaryKey"`
|
||||||
|
|
||||||
|
User string `gorm:"column:user;not null;uniqueIndex:user_slug"` // (distillery) username
|
||||||
|
Slug string `gorm:"column:slug;not null;uniqueIndex:user_slug"` // (distillery) instance slug
|
||||||
|
|
||||||
|
DrupalUsername string `gorm:"column:drupal_user;not null"` // drupal username
|
||||||
|
DrupalAdminRole bool `gorm:"column:admin;not null"` // drupal admin rights
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue