2022-06-28 07:32:25 -05:00
package orgimpl
import (
"context"
2022-09-22 12:02:55 -05:00
"fmt"
"sort"
2022-09-27 08:33:38 -05:00
"strconv"
2022-09-27 03:34:31 -05:00
"strings"
2022-08-23 12:26:21 -05:00
"time"
2022-06-28 07:32:25 -05:00
"github.com/grafana/grafana/pkg/events"
2022-10-19 08:02:15 -05:00
"github.com/grafana/grafana/pkg/infra/db"
2022-09-27 03:34:31 -05:00
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/accesscontrol"
2022-06-28 07:32:25 -05:00
"github.com/grafana/grafana/pkg/services/org"
2022-11-14 13:08:10 -06:00
"github.com/grafana/grafana/pkg/services/quota"
"github.com/grafana/grafana/pkg/services/sqlstore"
2022-06-28 07:32:25 -05:00
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
2022-09-27 03:34:31 -05:00
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
2022-06-28 07:32:25 -05:00
)
const MainOrgName = "Main Org."
type store interface {
Get ( context . Context , int64 ) ( * org . Org , error )
2023-02-24 11:08:44 -06:00
// Insert adds a new organization. returns organization id
2022-06-28 07:32:25 -05:00
Insert ( context . Context , * org . Org ) ( int64 , error )
2023-02-24 11:08:44 -06:00
// InsertOrgUser adds a new membership record for a user in an organization. returns membership id
2022-07-15 11:06:44 -05:00
InsertOrgUser ( context . Context , * org . OrgUser ) ( int64 , error )
DeleteUserFromAll ( context . Context , int64 ) error
2022-08-23 12:26:21 -05:00
Update ( ctx context . Context , cmd * org . UpdateOrgCommand ) error
2022-09-21 11:00:18 -05:00
// TO BE REFACTORED - move logic to service methods and leave CRUD methods for store
UpdateAddress ( context . Context , * org . UpdateOrgAddressCommand ) error
Delete ( context . Context , * org . DeleteOrgCommand ) error
2022-09-22 12:02:55 -05:00
GetUserOrgList ( context . Context , * org . GetUserOrgListQuery ) ( [ ] * org . UserOrgDTO , error )
Search ( context . Context , * org . SearchOrgsQuery ) ( [ ] * org . OrgDTO , error )
CreateWithMember ( context . Context , * org . CreateOrgCommand ) ( * org . Org , error )
2022-09-27 03:34:31 -05:00
AddOrgUser ( context . Context , * org . AddOrgUserCommand ) error
UpdateOrgUser ( context . Context , * org . UpdateOrgUserCommand ) error
2023-01-04 09:20:26 -06:00
GetByID ( context . Context , * org . GetOrgByIDQuery ) ( * org . Org , error )
2022-09-27 09:53:45 -05:00
GetByName ( context . Context , * org . GetOrgByNameQuery ) ( * org . Org , error )
2022-09-27 08:33:38 -05:00
SearchOrgUsers ( context . Context , * org . SearchOrgUsersQuery ) ( * org . SearchOrgUsersQueryResult , error )
RemoveOrgUser ( context . Context , * org . RemoveOrgUserCommand ) error
2022-11-14 13:08:10 -06:00
Count ( context . Context , * quota . ScopeParameters ) ( * quota . Map , error )
2023-10-18 04:40:26 -05:00
RegisterDelete ( query string )
2022-06-28 07:32:25 -05:00
}
type sqlStore struct {
db db . DB
dialect migrator . Dialect
2022-09-27 03:34:31 -05:00
//TODO: moved to service
2023-10-18 04:40:26 -05:00
log log . Logger
cfg * setting . Cfg
deletes [ ] string
2022-06-28 07:32:25 -05:00
}
func ( ss * sqlStore ) Get ( ctx context . Context , orgID int64 ) ( * org . Org , error ) {
var orga org . Org
2022-10-19 08:02:15 -05:00
err := ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
2022-06-28 07:32:25 -05:00
has , err := sess . Where ( "id=?" , orgID ) . Get ( & orga )
if err != nil {
return err
}
if ! has {
2023-03-06 01:57:46 -06:00
return org . ErrOrgNotFound . Errorf ( "failed to get organization with ID: %d" , orgID )
2022-06-28 07:32:25 -05:00
}
return nil
} )
if err != nil {
return nil , err
}
return & orga , nil
}
2023-09-13 09:42:19 -05:00
func ( ss * sqlStore ) Insert ( ctx context . Context , orga * org . Org ) ( int64 , error ) {
2022-06-28 07:32:25 -05:00
var orgID int64
var err error
2022-10-19 08:02:15 -05:00
err = ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
2023-09-13 09:42:19 -05:00
if isNameTaken , err := isOrgNameTaken ( orga . Name , orga . ID , sess ) ; err != nil {
2022-06-28 07:32:25 -05:00
return err
2023-09-13 09:42:19 -05:00
} else if isNameTaken {
return org . ErrOrgNameTaken
2022-06-28 07:32:25 -05:00
}
2023-02-24 11:08:44 -06:00
2023-09-13 09:42:19 -05:00
if _ , err = sess . Insert ( orga ) ; err != nil {
return err
}
orgID = orga . ID
2023-02-24 11:08:44 -06:00
2023-09-13 09:42:19 -05:00
if orga . ID != 0 {
2022-06-28 07:32:25 -05:00
// it sets the setval in the sequence
if err := ss . dialect . PostInsertId ( "org" , sess . Session ) ; err != nil {
return err
}
}
sess . PublishAfterCommit ( & events . OrgCreated {
2023-09-13 09:42:19 -05:00
Timestamp : orga . Created ,
Id : orga . ID ,
Name : orga . Name ,
2022-06-28 07:32:25 -05:00
} )
return nil
} )
if err != nil {
return 0 , err
}
return orgID , nil
}
2023-02-24 11:08:44 -06:00
// InsertOrgUser adds a new membership record for a user in an organization.
2022-07-15 11:06:44 -05:00
func ( ss * sqlStore ) InsertOrgUser ( ctx context . Context , cmd * org . OrgUser ) ( int64 , error ) {
2022-06-28 07:32:25 -05:00
var err error
2022-10-19 08:02:15 -05:00
err = ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
2023-02-24 11:08:44 -06:00
if _ , err = sess . Insert ( cmd ) ; err != nil {
2022-06-28 07:32:25 -05:00
return err
}
return nil
} )
if err != nil {
return 0 , err
}
2023-02-24 11:08:44 -06:00
return cmd . ID , nil
2022-06-28 07:32:25 -05:00
}
2022-07-15 11:06:44 -05:00
func ( ss * sqlStore ) DeleteUserFromAll ( ctx context . Context , userID int64 ) error {
2022-10-19 08:02:15 -05:00
return ss . db . WithDbSession ( ctx , func ( sess * db . Session ) error {
2022-07-15 11:06:44 -05:00
if _ , err := sess . Exec ( "DELETE FROM org_user WHERE user_id = ?" , userID ) ; err != nil {
return err
}
return nil
} )
}
2022-08-23 12:26:21 -05:00
func ( ss * sqlStore ) Update ( ctx context . Context , cmd * org . UpdateOrgCommand ) error {
2022-10-19 08:02:15 -05:00
return ss . db . WithTransactionalDbSession ( ctx , func ( sess * db . Session ) error {
2022-08-23 12:26:21 -05:00
if isNameTaken , err := isOrgNameTaken ( cmd . Name , cmd . OrgId , sess ) ; err != nil {
return err
} else if isNameTaken {
2023-01-04 09:20:26 -06:00
return org . ErrOrgNameTaken
2022-08-23 12:26:21 -05:00
}
2023-01-04 09:20:26 -06:00
orga := org . Org {
2022-08-23 12:26:21 -05:00
Name : cmd . Name ,
Updated : time . Now ( ) ,
}
2023-01-04 09:20:26 -06:00
affectedRows , err := sess . ID ( cmd . OrgId ) . Update ( & orga )
2022-08-23 12:26:21 -05:00
if err != nil {
return err
}
if affectedRows == 0 {
2023-03-06 01:57:46 -06:00
return org . ErrOrgNotFound . Errorf ( "failed to update organization with ID: %d" , cmd . OrgId )
2022-08-23 12:26:21 -05:00
}
sess . PublishAfterCommit ( & events . OrgUpdated {
2023-01-04 09:20:26 -06:00
Timestamp : orga . Updated ,
Id : orga . ID ,
Name : orga . Name ,
2022-08-23 12:26:21 -05:00
} )
return nil
} )
}
2022-10-19 08:02:15 -05:00
func isOrgNameTaken ( name string , existingId int64 , sess * db . Session ) ( bool , error ) {
2022-08-23 12:26:21 -05:00
// check if org name is taken
2022-09-27 03:34:31 -05:00
var org org . Org
2022-08-23 12:26:21 -05:00
exists , err := sess . Where ( "name=?" , name ) . Get ( & org )
if err != nil {
return false , nil
}
2022-09-27 03:34:31 -05:00
if exists && existingId != org . ID {
2022-08-23 12:26:21 -05:00
return true , nil
}
return false , nil
}
2022-09-21 11:00:18 -05:00
// TODO: refactor move logic to service method
func ( ss * sqlStore ) UpdateAddress ( ctx context . Context , cmd * org . UpdateOrgAddressCommand ) error {
2022-10-19 08:02:15 -05:00
return ss . db . WithTransactionalDbSession ( ctx , func ( sess * db . Session ) error {
2022-09-27 03:34:31 -05:00
org := org . Org {
2022-09-21 11:00:18 -05:00
Address1 : cmd . Address1 ,
Address2 : cmd . Address2 ,
City : cmd . City ,
ZipCode : cmd . ZipCode ,
State : cmd . State ,
Country : cmd . Country ,
Updated : time . Now ( ) ,
}
if _ , err := sess . ID ( cmd . OrgID ) . Update ( & org ) ; err != nil {
return err
}
sess . PublishAfterCommit ( & events . OrgUpdated {
Timestamp : org . Updated ,
2022-09-27 03:34:31 -05:00
Id : org . ID ,
2022-09-21 11:00:18 -05:00
Name : org . Name ,
} )
return nil
} )
}
// TODO: refactor move logic to service method
func ( ss * sqlStore ) Delete ( ctx context . Context , cmd * org . DeleteOrgCommand ) error {
2022-10-19 08:02:15 -05:00
return ss . db . WithTransactionalDbSession ( ctx , func ( sess * db . Session ) error {
2022-09-21 11:00:18 -05:00
if res , err := sess . Query ( "SELECT 1 from org WHERE id=?" , cmd . ID ) ; err != nil {
return err
} else if len ( res ) != 1 {
2023-03-06 01:57:46 -06:00
return org . ErrOrgNotFound . Errorf ( "failed to delete organisation with ID: %d" , cmd . ID )
2022-09-21 11:00:18 -05:00
}
deletes := [ ] string {
"DELETE FROM star WHERE EXISTS (SELECT 1 FROM dashboard WHERE org_id = ? AND star.dashboard_id = dashboard.id)" ,
"DELETE FROM dashboard_tag WHERE EXISTS (SELECT 1 FROM dashboard WHERE org_id = ? AND dashboard_tag.dashboard_id = dashboard.id)" ,
"DELETE FROM dashboard WHERE org_id = ?" ,
"DELETE FROM api_key WHERE org_id = ?" ,
"DELETE FROM data_source WHERE org_id = ?" ,
"DELETE FROM org_user WHERE org_id = ?" ,
"DELETE FROM org WHERE id = ?" ,
"DELETE FROM temp_user WHERE org_id = ?" ,
"DELETE FROM ngalert_configuration WHERE org_id = ?" ,
"DELETE FROM alert_configuration WHERE org_id = ?" ,
"DELETE FROM alert_instance WHERE rule_org_id = ?" ,
"DELETE FROM alert_notification WHERE org_id = ?" ,
"DELETE FROM alert_notification_state WHERE org_id = ?" ,
"DELETE FROM alert_rule WHERE org_id = ?" ,
"DELETE FROM alert_rule_tag WHERE EXISTS (SELECT 1 FROM alert WHERE alert.org_id = ? AND alert.id = alert_rule_tag.alert_id)" ,
"DELETE FROM alert_rule_version WHERE rule_org_id = ?" ,
"DELETE FROM alert WHERE org_id = ?" ,
"DELETE FROM annotation WHERE org_id = ?" ,
"DELETE FROM kv_store WHERE org_id = ?" ,
2023-10-18 04:40:26 -05:00
"DELETE FROM team WHERE org_id = ?" ,
"DELETE FROM team_member WHERE org_id = ?" ,
"DELETE FROM team_role WHERE org_id = ?" ,
"DELETE FROM user_role WHERE org_id = ?" ,
"DELETE FROM builtin_role WHERE org_id = ?" ,
2022-09-21 11:00:18 -05:00
}
2023-10-18 04:40:26 -05:00
// Add registered deletes
deletes = append ( deletes , ss . deletes ... )
2022-09-21 11:00:18 -05:00
for _ , sql := range deletes {
_ , err := sess . Exec ( sql , cmd . ID )
if err != nil {
return err
}
}
return nil
} )
}
2022-09-22 12:02:55 -05:00
// TODO: refactor move logic to service method
func ( ss * sqlStore ) GetUserOrgList ( ctx context . Context , query * org . GetUserOrgListQuery ) ( [ ] * org . UserOrgDTO , error ) {
result := make ( [ ] * org . UserOrgDTO , 0 )
2022-10-19 08:02:15 -05:00
err := ss . db . WithDbSession ( ctx , func ( dbSess * db . Session ) error {
2022-09-22 12:02:55 -05:00
sess := dbSess . Table ( "org_user" )
sess . Join ( "INNER" , "org" , "org_user.org_id=org.id" )
sess . Join ( "INNER" , ss . dialect . Quote ( "user" ) , fmt . Sprintf ( "org_user.user_id=%s.id" , ss . dialect . Quote ( "user" ) ) )
sess . Where ( "org_user.user_id=?" , query . UserID )
sess . Where ( ss . notServiceAccountFilter ( ) )
sess . Cols ( "org.name" , "org_user.role" , "org_user.org_id" )
sess . OrderBy ( "org.name" )
err := sess . Find ( & result )
sort . Sort ( org . ByOrgName ( result ) )
return err
} )
if err != nil {
return nil , err
}
return result , nil
}
func ( ss * sqlStore ) notServiceAccountFilter ( ) string {
return fmt . Sprintf ( "%s.is_service_account = %s" ,
ss . dialect . Quote ( "user" ) ,
ss . dialect . BooleanStr ( false ) )
}
func ( ss * sqlStore ) Search ( ctx context . Context , query * org . SearchOrgsQuery ) ( [ ] * org . OrgDTO , error ) {
result := make ( [ ] * org . OrgDTO , 0 )
2022-10-19 08:02:15 -05:00
err := ss . db . WithDbSession ( ctx , func ( dbSession * db . Session ) error {
2022-09-22 12:02:55 -05:00
sess := dbSession . Table ( "org" )
if query . Query != "" {
sess . Where ( "name LIKE ?" , query . Query + "%" )
}
if query . Name != "" {
sess . Where ( "name=?" , query . Name )
}
if len ( query . IDs ) > 0 {
sess . In ( "id" , query . IDs )
}
if query . Limit > 0 {
sess . Limit ( query . Limit , query . Limit * query . Page )
}
sess . Cols ( "id" , "name" )
err := sess . Find ( & result )
return err
} )
if err != nil {
return nil , err
}
return result , nil
}
// CreateWithMember creates an organization with a certain name and a certain user as member.
func ( ss * sqlStore ) CreateWithMember ( ctx context . Context , cmd * org . CreateOrgCommand ) ( * org . Org , error ) {
orga := org . Org {
Name : cmd . Name ,
Created : time . Now ( ) ,
Updated : time . Now ( ) ,
}
2022-10-19 08:02:15 -05:00
if err := ss . db . WithTransactionalDbSession ( ctx , func ( sess * db . Session ) error {
2022-09-22 12:02:55 -05:00
if isNameTaken , err := isOrgNameTaken ( cmd . Name , 0 , sess ) ; err != nil {
return err
} else if isNameTaken {
2023-01-04 09:20:26 -06:00
return org . ErrOrgNameTaken
2022-09-22 12:02:55 -05:00
}
if _ , err := sess . Insert ( & orga ) ; err != nil {
return err
}
user := org . OrgUser {
OrgID : orga . ID ,
UserID : cmd . UserID ,
Role : org . RoleAdmin ,
Created : time . Now ( ) ,
Updated : time . Now ( ) ,
}
_ , err := sess . Insert ( & user )
sess . PublishAfterCommit ( & events . OrgCreated {
Timestamp : orga . Created ,
Id : orga . ID ,
Name : orga . Name ,
} )
return err
} ) ; err != nil {
return & orga , err
}
return & orga , nil
}
2022-09-27 03:34:31 -05:00
func ( ss * sqlStore ) AddOrgUser ( ctx context . Context , cmd * org . AddOrgUserCommand ) error {
2022-10-19 08:02:15 -05:00
return ss . db . WithTransactionalDbSession ( ctx , func ( sess * db . Session ) error {
2022-09-27 03:34:31 -05:00
// check if user exists
var usr user . User
session := sess . ID ( cmd . UserID )
if ! cmd . AllowAddingServiceAccount {
session = session . Where ( ss . notServiceAccountFilter ( ) )
}
if exists , err := session . Get ( & usr ) ; err != nil {
return err
} else if ! exists {
return user . ErrUserNotFound
}
if res , err := sess . Query ( "SELECT 1 from org_user WHERE org_id=? and user_id=?" , cmd . OrgID , usr . ID ) ; err != nil {
return err
} else if len ( res ) == 1 {
2023-01-09 07:39:53 -06:00
return org . ErrOrgUserAlreadyAdded
2022-09-27 03:34:31 -05:00
}
if res , err := sess . Query ( "SELECT 1 from org WHERE id=?" , cmd . OrgID ) ; err != nil {
return err
} else if len ( res ) != 1 {
2023-03-06 01:57:46 -06:00
return org . ErrOrgNotFound . Errorf ( "failed to add user to organization with ID: %d" , cmd . OrgID )
2022-09-27 03:34:31 -05:00
}
entity := org . OrgUser {
OrgID : cmd . OrgID ,
UserID : cmd . UserID ,
Role : cmd . Role ,
Created : time . Now ( ) ,
Updated : time . Now ( ) ,
}
_ , err := sess . Insert ( & entity )
if err != nil {
return err
}
var userOrgs [ ] * org . UserOrgDTO
sess . Table ( "org_user" )
sess . Join ( "INNER" , "org" , "org_user.org_id=org.id" )
sess . Where ( "org_user.user_id=? AND org_user.org_id=?" , usr . ID , usr . OrgID )
sess . Cols ( "org.name" , "org_user.role" , "org_user.org_id" )
err = sess . Find ( & userOrgs )
if err != nil {
return err
}
if len ( userOrgs ) == 0 {
return setUsingOrgInTransaction ( sess , usr . ID , cmd . OrgID )
}
return nil
} )
}
2022-11-14 13:08:10 -06:00
func ( ss * sqlStore ) Count ( ctx context . Context , scopeParams * quota . ScopeParameters ) ( * quota . Map , error ) {
u := & quota . Map { }
type result struct {
Count int64
}
r := result { }
if err := ss . db . WithDbSession ( ctx , func ( sess * sqlstore . DBSession ) error {
rawSQL := "SELECT COUNT(*) as count from org"
if _ , err := sess . SQL ( rawSQL ) . Get ( & r ) ; err != nil {
return err
}
return nil
} ) ; err != nil {
return u , err
} else {
tag , err := quota . NewTag ( quota . TargetSrv ( org . QuotaTargetSrv ) , quota . Target ( org . OrgQuotaTarget ) , quota . GlobalScope )
if err != nil {
return u , err
}
u . Set ( tag , r . Count )
}
2023-01-16 04:54:15 -06:00
if scopeParams != nil && scopeParams . OrgID != 0 {
2022-11-14 13:08:10 -06:00
if err := ss . db . WithDbSession ( ctx , func ( sess * sqlstore . DBSession ) error {
rawSQL := fmt . Sprintf ( "SELECT COUNT(*) AS count FROM (SELECT user_id FROM org_user WHERE org_id=? AND user_id IN (SELECT id AS user_id FROM %s WHERE is_service_account=%s)) as subq" ,
ss . db . GetDialect ( ) . Quote ( "user" ) ,
ss . db . GetDialect ( ) . BooleanStr ( false ) ,
)
if _ , err := sess . SQL ( rawSQL , scopeParams . OrgID ) . Get ( & r ) ; err != nil {
return err
}
return nil
} ) ; err != nil {
return u , err
} else {
tag , err := quota . NewTag ( quota . TargetSrv ( org . QuotaTargetSrv ) , quota . Target ( org . OrgUserQuotaTarget ) , quota . OrgScope )
if err != nil {
return u , err
}
u . Set ( tag , r . Count )
}
}
2023-01-16 04:54:15 -06:00
if scopeParams != nil && scopeParams . UserID != 0 {
2022-11-14 13:08:10 -06:00
if err := ss . db . WithDbSession ( ctx , func ( sess * sqlstore . DBSession ) error {
// should we exclude service accounts?
rawSQL := "SELECT COUNT(*) AS count FROM org_user WHERE user_id=?"
if _ , err := sess . SQL ( rawSQL , scopeParams . UserID ) . Get ( & r ) ; err != nil {
return err
}
return nil
} ) ; err != nil {
return u , err
} else {
tag , err := quota . NewTag ( quota . TargetSrv ( org . QuotaTargetSrv ) , quota . Target ( org . OrgUserQuotaTarget ) , quota . UserScope )
if err != nil {
return u , err
}
u . Set ( tag , r . Count )
}
}
return u , nil
}
2022-10-19 08:02:15 -05:00
func setUsingOrgInTransaction ( sess * db . Session , userID int64 , orgID int64 ) error {
2022-09-27 03:34:31 -05:00
user := user . User {
ID : userID ,
OrgID : orgID ,
}
_ , err := sess . ID ( userID ) . Update ( & user )
return err
}
func ( ss * sqlStore ) UpdateOrgUser ( ctx context . Context , cmd * org . UpdateOrgUserCommand ) error {
2022-10-19 08:02:15 -05:00
return ss . db . WithTransactionalDbSession ( ctx , func ( sess * db . Session ) error {
2022-09-27 03:34:31 -05:00
var orgUser org . OrgUser
exists , err := sess . Where ( "org_id=? AND user_id=?" , cmd . OrgID , cmd . UserID ) . Get ( & orgUser )
if err != nil {
return err
}
if ! exists {
2023-01-09 07:39:53 -06:00
return org . ErrOrgUserNotFound
2022-09-27 03:34:31 -05:00
}
orgUser . Role = cmd . Role
orgUser . Updated = time . Now ( )
_ , err = sess . ID ( orgUser . ID ) . Update ( & orgUser )
if err != nil {
return err
}
return validateOneAdminLeftInOrg ( cmd . OrgID , sess )
} )
}
// validate that there is an org admin user left
2022-10-19 08:02:15 -05:00
func validateOneAdminLeftInOrg ( orgID int64 , sess * db . Session ) error {
2022-09-27 03:34:31 -05:00
res , err := sess . Query ( "SELECT 1 from org_user WHERE org_id=? and role='Admin'" , orgID )
if err != nil {
return err
}
if len ( res ) == 0 {
2023-01-09 07:39:53 -06:00
return org . ErrLastOrgAdmin
2022-09-27 03:34:31 -05:00
}
return err
}
2023-01-04 09:20:26 -06:00
func ( ss * sqlStore ) GetByID ( ctx context . Context , query * org . GetOrgByIDQuery ) ( * org . Org , error ) {
2022-09-27 09:53:45 -05:00
var orga org . Org
2022-10-19 08:02:15 -05:00
err := ss . db . WithDbSession ( ctx , func ( dbSession * db . Session ) error {
2022-09-27 09:53:45 -05:00
exists , err := dbSession . ID ( query . ID ) . Get ( & orga )
if err != nil {
return err
}
if ! exists {
2023-03-06 01:57:46 -06:00
return org . ErrOrgNotFound . Errorf ( "failed to get org by ID: %d" , query . ID )
2022-09-27 09:53:45 -05:00
}
return nil
} )
if err != nil {
return nil , err
}
return & orga , nil
}
2022-09-27 08:33:38 -05:00
func ( ss * sqlStore ) SearchOrgUsers ( ctx context . Context , query * org . SearchOrgUsersQuery ) ( * org . SearchOrgUsersQueryResult , error ) {
result := org . SearchOrgUsersQueryResult {
OrgUsers : make ( [ ] * org . OrgUserDTO , 0 ) ,
}
2022-10-19 08:02:15 -05:00
err := ss . db . WithDbSession ( ctx , func ( dbSession * db . Session ) error {
2022-09-27 08:33:38 -05:00
sess := dbSession . Table ( "org_user" )
2023-09-28 03:16:18 -05:00
sess . Join ( "INNER" , [ ] string { ss . dialect . Quote ( "user" ) , "u" } , "org_user.user_id=u.id" )
2022-09-27 08:33:38 -05:00
whereConditions := make ( [ ] string , 0 )
2023-08-30 10:46:47 -05:00
whereParams := make ( [ ] any , 0 )
2022-09-27 08:33:38 -05:00
whereConditions = append ( whereConditions , "org_user.org_id = ?" )
whereParams = append ( whereParams , query . OrgID )
2023-01-09 02:54:33 -06:00
if query . UserID != 0 {
whereConditions = append ( whereConditions , "org_user.user_id = ?" )
whereParams = append ( whereParams , query . UserID )
}
2022-09-27 08:33:38 -05:00
2023-09-28 03:16:18 -05:00
whereConditions = append ( whereConditions , "u.is_service_account = ?" )
2023-01-09 02:54:33 -06:00
whereParams = append ( whereParams , ss . dialect . BooleanStr ( false ) )
if query . User == nil {
ss . log . Warn ( "Query user not set for filtering." )
}
2023-08-25 08:19:58 -05:00
if ! query . DontEnforceAccessControl {
2022-09-27 08:33:38 -05:00
acFilter , err := accesscontrol . Filter ( query . User , "org_user.user_id" , "users:id:" , accesscontrol . ActionOrgUsersRead )
if err != nil {
return err
}
whereConditions = append ( whereConditions , acFilter . Where )
whereParams = append ( whereParams , acFilter . Args ... )
}
if query . Query != "" {
queryWithWildcards := "%" + query . Query + "%"
whereConditions = append ( whereConditions , "(email " + ss . dialect . LikeStr ( ) + " ? OR name " + ss . dialect . LikeStr ( ) + " ? OR login " + ss . dialect . LikeStr ( ) + " ?)" )
whereParams = append ( whereParams , queryWithWildcards , queryWithWildcards , queryWithWildcards )
}
if len ( whereConditions ) > 0 {
sess . Where ( strings . Join ( whereConditions , " AND " ) , whereParams ... )
}
if query . Limit > 0 {
offset := query . Limit * ( query . Page - 1 )
sess . Limit ( query . Limit , offset )
}
sess . Cols (
"org_user.org_id" ,
"org_user.user_id" ,
2023-09-28 03:16:18 -05:00
"u.email" ,
"u.name" ,
"u.login" ,
2022-09-27 08:33:38 -05:00
"org_user.role" ,
2023-09-28 03:16:18 -05:00
"u.last_seen_at" ,
"u.created" ,
"u.updated" ,
"u.is_disabled" ,
2022-09-27 08:33:38 -05:00
)
2023-09-28 03:16:18 -05:00
if len ( query . SortOpts ) > 0 {
for i := range query . SortOpts {
for j := range query . SortOpts [ i ] . Filter {
sess . OrderBy ( query . SortOpts [ i ] . Filter [ j ] . OrderBy ( ) )
}
}
} else {
sess . Asc ( "u.login" , "u.email" )
}
2022-09-27 08:33:38 -05:00
if err := sess . Find ( & result . OrgUsers ) ; err != nil {
return err
}
// get total count
orgUser := org . OrgUser { }
countSess := dbSession . Table ( "org_user" ) .
2023-09-28 03:16:18 -05:00
Join ( "INNER" , [ ] string { ss . dialect . Quote ( "user" ) , "u" } , "org_user.user_id=u.id" )
2022-09-27 08:33:38 -05:00
if len ( whereConditions ) > 0 {
countSess . Where ( strings . Join ( whereConditions , " AND " ) , whereParams ... )
}
count , err := countSess . Count ( & orgUser )
if err != nil {
return err
}
result . TotalCount = count
for _ , user := range result . OrgUsers {
user . LastSeenAtAge = util . GetAgeString ( user . LastSeenAt )
}
return nil
} )
if err != nil {
return nil , err
}
return & result , nil
}
2022-09-27 09:53:45 -05:00
func ( ss * sqlStore ) GetByName ( ctx context . Context , query * org . GetOrgByNameQuery ) ( * org . Org , error ) {
var orga org . Org
2022-10-19 08:02:15 -05:00
err := ss . db . WithDbSession ( ctx , func ( dbSession * db . Session ) error {
2022-09-27 09:53:45 -05:00
exists , err := dbSession . Where ( "name=?" , query . Name ) . Get ( & orga )
if err != nil {
return err
}
if ! exists {
2023-03-06 01:57:46 -06:00
return org . ErrOrgNotFound . Errorf ( "failed to get org by name: %s" , query . Name )
2022-09-27 09:53:45 -05:00
}
return nil
} )
if err != nil {
return nil , err
}
return & orga , nil
}
2022-09-27 08:33:38 -05:00
func ( ss * sqlStore ) RemoveOrgUser ( ctx context . Context , cmd * org . RemoveOrgUserCommand ) error {
2022-10-19 08:02:15 -05:00
return ss . db . WithTransactionalDbSession ( ctx , func ( sess * db . Session ) error {
2022-09-27 08:33:38 -05:00
// check if user exists
var usr user . User
if exists , err := sess . ID ( cmd . UserID ) . Where ( ss . notServiceAccountFilter ( ) ) . Get ( & usr ) ; err != nil {
return err
} else if ! exists {
return user . ErrUserNotFound
}
deletes := [ ] string {
"DELETE FROM org_user WHERE org_id=? and user_id=?" ,
"DELETE FROM dashboard_acl WHERE org_id=? and user_id = ?" ,
"DELETE FROM team_member WHERE org_id=? and user_id = ?" ,
"DELETE FROM query_history_star WHERE org_id=? and user_id = ?" ,
}
for _ , sql := range deletes {
_ , err := sess . Exec ( sql , cmd . OrgID , cmd . UserID )
if err != nil {
return err
}
}
// validate that after delete, there is at least one user with admin role in org
if err := validateOneAdminLeftInOrg ( cmd . OrgID , sess ) ; err != nil {
return err
}
// check user other orgs and update user current org
2023-01-04 09:20:26 -06:00
var userOrgs [ ] * org . UserOrgDTO
2022-09-27 08:33:38 -05:00
sess . Table ( "org_user" )
sess . Join ( "INNER" , "org" , "org_user.org_id=org.id" )
sess . Where ( "org_user.user_id=?" , usr . ID )
sess . Cols ( "org.name" , "org_user.role" , "org_user.org_id" )
err := sess . Find ( & userOrgs )
if err != nil {
return err
}
if len ( userOrgs ) > 0 {
hasCurrentOrgSet := false
for _ , userOrg := range userOrgs {
2023-01-04 09:20:26 -06:00
if usr . OrgID == userOrg . OrgID {
2022-09-27 08:33:38 -05:00
hasCurrentOrgSet = true
break
}
}
if ! hasCurrentOrgSet {
2023-01-04 09:20:26 -06:00
err = setUsingOrgInTransaction ( sess , usr . ID , userOrgs [ 0 ] . OrgID )
2022-09-27 08:33:38 -05:00
if err != nil {
return err
}
}
} else if cmd . ShouldDeleteOrphanedUser {
// no other orgs, delete the full user
2023-01-03 08:25:35 -06:00
if err := ss . deleteUserInTransaction ( sess , & user . DeleteUserCommand { UserID : usr . ID } ) ; err != nil {
2022-09-27 08:33:38 -05:00
return err
}
cmd . UserWasDeleted = true
} else {
// no orgs, but keep the user -> clean up orgId
err = removeUserOrg ( sess , usr . ID )
if err != nil {
return err
}
}
return nil
} )
}
2023-01-03 08:25:35 -06:00
func ( ss * sqlStore ) deleteUserInTransaction ( sess * db . Session , cmd * user . DeleteUserCommand ) error {
2022-09-27 08:33:38 -05:00
// Check if user exists
2023-01-03 08:25:35 -06:00
usr := user . User { ID : cmd . UserID }
2022-09-27 08:33:38 -05:00
has , err := sess . Where ( ss . notServiceAccountFilter ( ) ) . Get ( & usr )
if err != nil {
return err
}
if ! has {
return user . ErrUserNotFound
}
for _ , sql := range ss . userDeletions ( ) {
2023-01-03 08:25:35 -06:00
_ , err := sess . Exec ( sql , cmd . UserID )
2022-09-27 08:33:38 -05:00
if err != nil {
return err
}
}
2023-01-03 08:25:35 -06:00
return deleteUserAccessControl ( sess , cmd . UserID )
2022-09-27 08:33:38 -05:00
}
2022-10-19 08:02:15 -05:00
func deleteUserAccessControl ( sess * db . Session , userID int64 ) error {
2022-09-27 08:33:38 -05:00
// Delete user role assignments
if _ , err := sess . Exec ( "DELETE FROM user_role WHERE user_id = ?" , userID ) ; err != nil {
return err
}
// Delete permissions that are scoped to user
if _ , err := sess . Exec ( "DELETE FROM permission WHERE scope = ?" , accesscontrol . Scope ( "users" , "id" , strconv . FormatInt ( userID , 10 ) ) ) ; err != nil {
return err
}
var roleIDs [ ] int64
if err := sess . SQL ( "SELECT id FROM role WHERE name = ?" , accesscontrol . ManagedUserRoleName ( userID ) ) . Find ( & roleIDs ) ; err != nil {
return err
}
if len ( roleIDs ) == 0 {
return nil
}
query := "DELETE FROM permission WHERE role_id IN(? " + strings . Repeat ( ",?" , len ( roleIDs ) - 1 ) + ")"
2023-08-30 10:46:47 -05:00
args := make ( [ ] any , 0 , len ( roleIDs ) + 1 )
2022-09-27 08:33:38 -05:00
args = append ( args , query )
for _ , id := range roleIDs {
args = append ( args , id )
}
// Delete managed user permissions
if _ , err := sess . Exec ( args ... ) ; err != nil {
return err
}
// Delete managed user roles
if _ , err := sess . Exec ( "DELETE FROM role WHERE name = ?" , accesscontrol . ManagedUserRoleName ( userID ) ) ; err != nil {
return err
}
return nil
}
func ( ss * sqlStore ) userDeletions ( ) [ ] string {
deletes := [ ] string {
"DELETE FROM star WHERE user_id = ?" ,
"DELETE FROM " + ss . dialect . Quote ( "user" ) + " WHERE id = ?" ,
"DELETE FROM org_user WHERE user_id = ?" ,
"DELETE FROM dashboard_acl WHERE user_id = ?" ,
"DELETE FROM preferences WHERE user_id = ?" ,
"DELETE FROM team_member WHERE user_id = ?" ,
"DELETE FROM user_auth WHERE user_id = ?" ,
"DELETE FROM user_auth_token WHERE user_id = ?" ,
"DELETE FROM quota WHERE user_id = ?" ,
}
return deletes
}
2022-10-19 08:02:15 -05:00
func removeUserOrg ( sess * db . Session , userID int64 ) error {
2022-09-27 08:33:38 -05:00
user := user . User {
ID : userID ,
OrgID : 0 ,
}
_ , err := sess . ID ( userID ) . MustCols ( "org_id" ) . Update ( & user )
return err
}
2023-10-18 04:40:26 -05:00
// RegisterDelete registers a delete query to be executed when an org is deleted, used to delete enterprise data.
func ( ss * sqlStore ) RegisterDelete ( query string ) {
ss . deletes = append ( ss . deletes , query )
}