2019-07-17 13:37:18 -04:00
# include <algorithm>
# include <utility>
# include <log/LogUtils.h>
# include <misc/memtracker.h>
# include "Group.h"
2020-01-26 12:04:38 -05:00
# include "VirtualServer.h"
2019-07-17 13:37:18 -04:00
# include "src/client/ConnectedClient.h"
# include "InstanceHandler.h"
# include "src/server/file/FileServer.h"
using namespace std ;
using namespace std : : chrono ;
using namespace ts ;
using namespace ts : : server ;
using namespace ts : : permission ;
extern InstanceHandler * serverInstance ;
Group : : Group ( GroupManager * handle , GroupTarget target , GroupType type , GroupId groupId ) : _target ( target ) , _type ( type ) {
memtrack : : allocated < Group > ( this ) ;
this - > handle = handle ;
this - > _properties = new Properties ( ) ;
2020-01-23 20:57:58 -05:00
this - > _properties - > register_property_type < property : : GroupProperties > ( ) ;
this - > setPermissionManager ( make_shared < permission : : v2 : : PermissionManager > ( ) ) ;
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
this - > properties ( ) [ property : : GROUP_ID ] = groupId ;
this - > properties ( ) [ property : : GROUP_TYPE ] = type ;
/*
2019-07-17 13:37:18 -04:00
this - > _properties - > registerProperty ( " sgid " , groupId , PROP_GROUP_INIT_SERVER ) ;
this - > _properties - > registerProperty ( " cgid " , groupId , PROP_GROUP_INIT_CHANNEL ) ;
this - > _properties - > registerProperty ( " gid " , groupId , PROP_PRIVATE_TEMP ) ;
this - > _properties - > registerProperty ( " type " , ( uint8_t ) type , PROP_GROUP_INIT ) ;
this - > _properties - > registerProperty ( " name " , " Undefined group # " + to_string ( groupId ) , PROP_GROUP_INIT | PROP_SNAPSHOT ) ;
this - > _properties - > registerProperty ( " sortid " , 0 , PROP_GROUP_INIT ) ;
this - > _properties - > registerProperty ( " savedb " , 0 , PROP_GROUP_INIT ) ;
this - > _properties - > registerProperty ( " namemode " , 0 , PROP_GROUP_INIT ) ;
this - > _properties - > registerProperty ( " iconid " , 0 , PROP_GROUP_INIT ) ;
this - > _properties - > registerProperty ( " default_group " , false , PROP_PRIVATE_TEMP ) ;
*/
this - > _properties - > registerNotifyHandler ( [ & ] ( Property & prop ) {
if ( ( prop . type ( ) . flags & property : : FLAG_SAVE ) = = 0 ) return ;
if ( ! this - > handle ) return ;
std : : string sql ;
if ( prop . hasDbReference ( ) ) {
sql = " UPDATE `properties` SET `value` = :value WHERE `serverId` = :sid AND `type` = :type AND `id` = :gid AND `key` = :key " ;
} else {
prop . setDbReference ( true ) ;
sql = " INSERT INTO `properties` (`serverId`, `type`, `id`, `key`, `value`) VALUES (:sid, :type, :gid, :key, :value) " ;
}
sql : : command ( this - > handle - > sql , sql ,
variable { " :sid " , this - > handle - > getServerId ( ) } , variable { " :type " , property : : PropertyType : : PROP_TYPE_GROUP } , variable { " :gid " , this - > groupId ( ) } , variable { " :key " , prop . type ( ) . name } , variable { " :value " , prop . value ( ) } )
. executeLater ( ) . waitAndGetLater ( LOG_SQL_CMD , { 1 , " future failed " } ) ;
} ) ;
}
void Group : : setPermissionManager ( const std : : shared_ptr < permission : : v2 : : PermissionManager > & manager ) {
2020-01-23 20:57:58 -05:00
this - > _permissions = manager ;
this - > apply_properties_from_permissions ( ) ;
2019-07-17 13:37:18 -04:00
}
void Group : : apply_properties_from_permissions ( ) {
2020-01-23 20:57:58 -05:00
{
auto permission = this - > _permissions - > permission_value_flagged ( permission : : i_icon_id ) ;
this - > properties ( ) [ property : : GROUP_ICONID ] = permission . has_value ? permission . value : 0 ;
}
{
auto permission = this - > _permissions - > permission_value_flagged ( permission : : i_group_show_name_in_tree ) ;
this - > properties ( ) [ property : : GROUP_NAMEMODE ] = permission . has_value ? permission . value : 0 ;
}
{
auto permission = this - > _permissions - > permission_value_flagged ( permission : : i_group_sort_id ) ;
this - > properties ( ) [ property : : GROUP_SORTID ] = permission . has_value ? permission . value : 0 ;
}
{
auto permission = this - > _permissions - > permission_value_flagged ( permission : : b_group_is_permanent ) ;
this - > properties ( ) [ property : : GROUP_SAVEDB ] = permission . has_value ? permission . value : 0 ;
}
2019-07-17 13:37:18 -04:00
}
Group : : ~ Group ( ) {
delete this - > _properties ;
memtrack : : freed < Group > ( this ) ;
}
2020-01-26 12:04:38 -05:00
GroupManager : : GroupManager ( const shared_ptr < VirtualServer > & server , sql : : SqlManager * sql , std : : shared_ptr < GroupManager > root ) : server ( server ) , sql ( sql ) , root ( std : : move ( root ) ) { }
2019-07-17 13:37:18 -04:00
GroupManager : : ~ GroupManager ( ) { }
bool GroupManager : : loadGroupFormDatabase ( GroupId id ) {
if ( id = = 0 ) {
this - > groups . clear ( ) ;
auto res = sql : : command ( this - > sql , " SELECT * FROM `groups` WHERE `serverId` = :sid " , variable { " :sid " , this - > getServerId ( ) } ) . query ( & GroupManager : : insertGroupFromDb , this ) ;
LOG_SQL_CMD ( res ) ;
return true ;
} else {
for ( const auto & e : this - > groups )
if ( e - > groupId ( ) = = id ) {
this - > groups . erase ( find ( this - > groups . begin ( ) , this - > groups . end ( ) , e ) ) ;
break ;
}
auto res = sql : : command ( this - > sql , " SELECT * FROM `groups` WHERE `serverId` = :sid AND `groupId` = :gid " ,
variable { " :sid " , this - > getServerId ( ) } , variable { " :gid " , id } ) . query ( & GroupManager : : insertGroupFromDb , this ) ;
auto fn = LOG_SQL_CMD ;
fn ( res ) ;
return res ;
}
}
std : : vector < std : : shared_ptr < Group > > GroupManager : : availableGroups ( bool root ) {
2020-01-23 20:57:58 -05:00
std : : vector < std : : shared_ptr < Group > > response ;
for ( const auto & group : this - > groups )
response . push_back ( group ) ;
if ( root & & this - > root ) {
auto elm = this - > root - > availableGroups ( ) ;
for ( const auto & e : elm )
response . push_back ( e ) ;
}
return response ;
2019-07-17 13:37:18 -04:00
}
std : : vector < std : : shared_ptr < Group > > GroupManager : : availableServerGroups ( bool root ) {
2020-01-23 20:57:58 -05:00
std : : vector < std : : shared_ptr < Group > > response ;
for ( const auto & group : this - > groups )
if ( group - > target ( ) = = GroupTarget : : GROUPTARGET_SERVER )
response . push_back ( group ) ;
if ( root & & this - > root ) {
auto elm = this - > root - > availableServerGroups ( ) ;
for ( const auto & e : elm )
response . push_back ( e ) ;
}
return response ;
2019-07-17 13:37:18 -04:00
}
std : : vector < std : : shared_ptr < Group > > GroupManager : : availableChannelGroups ( bool root ) {
2020-01-23 20:57:58 -05:00
std : : vector < std : : shared_ptr < Group > > response ;
for ( const auto & group : this - > groups )
if ( group - > target ( ) = = GroupTarget : : GROUPTARGET_CHANNEL )
response . push_back ( group ) ;
if ( root & & this - > root ) {
auto elm = this - > root - > availableChannelGroups ( true ) ;
for ( const auto & e : elm )
response . push_back ( e ) ;
}
return response ;
2019-07-17 13:37:18 -04:00
}
int GroupManager : : insertGroupFromDb ( int count , char * * values , char * * column ) {
GroupId groupId = 0 ;
auto target = ( GroupTarget ) 0xff ;
auto type = ( GroupType ) 0xff ;
std : : string targetName ;
for ( int index = 0 ; index < count ; index + + ) {
if ( strcmp ( column [ index ] , " target " ) = = 0 )
target = ( GroupTarget ) stoll ( values [ index ] ) ;
else if ( strcmp ( column [ index ] , " type " ) = = 0 )
type = ( GroupType ) stoll ( values [ index ] ) ;
else if ( strcmp ( column [ index ] , " groupId " ) = = 0 )
groupId = ( GroupType ) stoll ( values [ index ] ) ;
else if ( strcmp ( column [ index ] , " displayName " ) = = 0 )
targetName = values [ index ] ;
else if ( strcmp ( column [ index ] , " serverId " ) = = 0 ) ;
else cerr < < " Invalid group table row " < < column [ index ] < < endl ;
}
2019-09-14 08:22:16 -04:00
if ( ( size_t ) groupId = = 0 | | ( size_t ) target = = 0xff | | ( size_t ) type = = 0xff | | targetName . empty ( ) ) {
2019-07-17 13:37:18 -04:00
logCritical ( this - > getServerId ( ) , " Found invalid group ad database! (GroupId " + to_string ( groupId ) + " , Target " + to_string ( target ) + " , Type " + to_string ( type ) + " , Name ' " + targetName + " ') " ) ;
return 0 ;
}
/*
assert ( groupId ! = 0 ) ;
assert ( target ! = 0xff ) ;
assert ( type ! = 0xff ) ;
assert ( ! targetName . empty ( ) ) ;
*/
shared_ptr < Group > group = std : : make_shared < Group > ( this , target , type , groupId ) ;
/*
auto res = sql : : command ( this - > sql , " SELECT `key`, `value` FROM `properties` WHERE `serverId` = :sid AND `type` = :type AND `id` = :gid " ,
variable { " :sid " , this - > getServerId ( ) } , variable { " :type " , property : : PROP_TYPE_GROUP } , variable { " :gid " , group - > groupId ( ) } ) . query ( [ this ] ( Group * g , int length , char * * values , char * * columns ) {
string key , value ;
for ( int index = 0 ; index < length ; index + + )
if ( strcmp ( columns [ index ] , " key " ) = = 0 )
key = values [ index ] ;
else if ( strcmp ( columns [ index ] , " value " ) = = 0 )
value = values [ index ] ;
2020-01-23 20:57:58 -05:00
auto info = property : : info < property : : GroupProperties > ( key ) ;
if ( info = = property : : GROUP_UNDEFINED ) {
logError ( this - > getServerId ( ) , " Invalid property for group: " + key ) ;
return 0 ;
}
2019-07-17 13:37:18 -04:00
auto prop = g - > properties ( ) [ info . property ] ;
prop . setDbReference ( true ) ;
prop . value ( value , false ) ;
return 0 ;
} , group . get ( ) ) ;
auto print = LOG_SQL_CMD ;
print ( res ) ;
*/
//FIXME load group properties view database helper (or drop it full because no saved properties)
group - > properties ( ) [ property : : GROUP_NAME ] = targetName ;
group - > setPermissionManager ( serverInstance - > databaseHelper ( ) - > loadGroupPermissions ( this - > server . lock ( ) , group - > groupId ( ) ) ) ;
debugMessage ( this - > getServerId ( ) , " Push back group -> " + to_string ( group - > groupId ( ) ) + " - " + group - > name ( ) ) ;
this - > groups . push_back ( group ) ;
auto iconId = ( IconId ) group - > icon_id ( ) ;
if ( iconId ! = 0 & & serverInstance & & serverInstance - > getFileServer ( ) & & ! serverInstance - > getFileServer ( ) - > iconExists ( this - > server . lock ( ) , iconId ) ) {
logMessage ( this - > getServerId ( ) , " [FILE] Missing group icon ( " + to_string ( iconId ) + " ). " ) ;
if ( config : : server : : delete_missing_icon_permissions ) group - > permissions ( ) - > set_permission ( permission : : i_icon_id , { 0 , 0 } , permission : : v2 : : delete_value , permission : : v2 : : do_nothing ) ;
}
return 0 ;
}
2019-09-14 08:22:16 -04:00
void GroupManager : : handleChannelDeleted ( const ChannelId & channel_id ) {
2020-01-23 20:57:58 -05:00
unique_lock cache_lock ( this - > cacheLock ) ;
auto cached_clients = std : : vector < shared_ptr < CachedClient > > { this - > cachedClients . begin ( ) , this - > cachedClients . end ( ) } ;
cache_lock . unlock ( ) ;
2019-09-14 08:22:16 -04:00
2020-01-23 20:57:58 -05:00
for ( auto & entry : cached_clients ) {
lock_guard entry_lock ( entry - > lock ) ;
entry - > channel_groups . erase ( channel_id ) ;
}
2019-07-17 13:37:18 -04:00
}
bool GroupManager : : isLocalGroup ( std : : shared_ptr < Group > gr ) {
return std : : find ( this - > groups . begin ( ) , this - > groups . end ( ) , gr ) ! = this - > groups . end ( ) ;
}
std : : shared_ptr < Group > GroupManager : : defaultGroup ( GroupTarget type , bool enforce_property ) {
2020-01-23 20:57:58 -05:00
threads : : MutexLock lock ( this - > cacheLock ) ;
2019-07-17 13:37:18 -04:00
if ( this - > groups . empty ( ) ) return nullptr ;
2020-01-23 20:57:58 -05:00
auto server = this - > server . lock ( ) ;
auto id =
server ?
server - > properties ( ) [ type = = GroupTarget : : GROUPTARGET_SERVER ? property : : VIRTUALSERVER_DEFAULT_SERVER_GROUP : property : : VIRTUALSERVER_DEFAULT_CHANNEL_GROUP ] . as_save < GroupId > ( ) :
serverInstance - > properties ( ) [ property : : SERVERINSTANCE_GUEST_SERVERQUERY_GROUP ] . as_save < GroupId > ( ) ;
auto group = this - > findGroupLocal ( id ) ;
if ( group | | enforce_property ) return group ;
2019-07-17 13:37:18 -04:00
for ( auto elm : this - > groups )
if ( elm - > target ( ) = = type )
return elm ;
return nullptr ; //Worst case!
}
std : : shared_ptr < Group > GroupManager : : findGroup ( GroupId groupId ) {
auto result = this - > findGroupLocal ( groupId ) ;
2020-01-23 20:57:58 -05:00
if ( ! result & & this - > root ) result = this - > root - > findGroup ( groupId ) ;
2019-07-17 13:37:18 -04:00
return result ;
}
std : : shared_ptr < Group > GroupManager : : findGroupLocal ( GroupId groupId ) {
2020-01-23 20:57:58 -05:00
for ( const auto & elm : this - > groups )
if ( elm - > groupId ( ) = = groupId ) return elm ;
return nullptr ;
2019-07-17 13:37:18 -04:00
}
std : : vector < std : : shared_ptr < Group > > GroupManager : : findGroup ( GroupTarget target , std : : string name ) {
vector < shared_ptr < Group > > res ;
for ( const auto & elm : this - > groups )
if ( elm - > name ( ) = = name & & elm - > target ( ) = = target ) res . push_back ( elm ) ;
if ( this - > root ) {
auto r = root - > findGroup ( target , name ) ;
for ( const auto & e : r ) res . push_back ( e ) ;
}
return res ;
}
ServerId GroupManager : : getServerId ( ) {
2020-01-23 20:57:58 -05:00
auto l = this - > server . lock ( ) ;
return l ? l - > getServerId ( ) : 0 ;
2019-07-17 13:37:18 -04:00
}
std : : shared_ptr < Group > GroupManager : : createGroup ( GroupTarget target , GroupType type , std : : string name ) {
if ( type ! = GROUP_TYPE_NORMAL & & this - > root ) return root - > createGroup ( target , type , name ) ;
2020-01-23 20:57:58 -05:00
auto rawId = generateGroupId ( this - > sql ) ;
if ( rawId < = 0 ) {
logError ( this - > getServerId ( ) , " Could not create a new group! ({}) " , " Could not generate group id " ) ;
return nullptr ;
}
2019-07-17 13:37:18 -04:00
auto groupId = ( GroupId ) rawId ;
auto res = sql : : command ( this - > sql , " INSERT INTO `groups` (`serverId`, `groupId`, `target`, `type`, `displayName`) VALUES (:sid, :gid, :target, :type, :name) " ,
variable { " :sid " , this - > getServerId ( ) } , variable { " :gid " , groupId } , variable { " :target " , target } , variable { " :type " , type } , variable { " :name " , name } ) . execute ( ) ;
auto print = LOG_SQL_CMD ;
print ( res ) ;
if ( ! res ) return nullptr ;
std : : shared_ptr < Group > group = std : : make_shared < Group > ( this , target , type , groupId ) ;
group - > properties ( ) [ property : : GROUP_NAME ] = name ;
group - > setPermissionManager ( serverInstance - > databaseHelper ( ) - > loadGroupPermissions ( this - > server . lock ( ) , group - > groupId ( ) ) ) ;
this - > groups . push_back ( group ) ;
return group ;
}
2019-10-21 14:46:17 -04:00
GroupId GroupManager : : copyGroup ( std : : shared_ptr < Group > group , GroupType type , std : : string name , ServerId targetServerId ) {
2020-01-23 20:57:58 -05:00
auto group_server = group - > handle - > getServerId ( ) ;
2019-07-17 13:37:18 -04:00
auto groupId = generateGroupId ( this - > sql ) ;
auto print = LOG_SQL_CMD ;
auto res = sql : : command ( this - > sql , " INSERT INTO `permissions` (`serverId`, `type`, `id`, `channelId`, `permId`, `value`, `grant`) SELECT :tsid AS `serverId`, `type`, :target AS `id`, 0 AS `channelId`, `permId`, `value`,`grant` FROM `permissions` WHERE `serverId` = :ssid AND `type` = :type AND `id` = :source " ,
variable { " :target " , groupId } , variable { " :ssid " , group_server } , variable { " :tsid " , targetServerId } , variable { " :source " , group - > groupId ( ) } , variable { " :type " , SQL_PERM_GROUP } ) . execute ( ) ;
print ( res ) ;
//Properties not used currently
res = sql : : command ( this - > sql , " INSERT INTO `properties` (`serverId`, `type`, `id`, `key`, `value`) SELECT :tsid AS `serverId`, `type`, :target AS `id`, `key`, `value` FROM `properties` WHERE `serverId` = :ssid AND `type` = :type AND `id` = :source " ,
variable { " :target " , groupId } , variable { " :ssid " , group_server } , variable { " :tsid " , targetServerId } , variable { " :source " , group - > groupId ( ) } , variable { " :type " , property : : PropertyType : : PROP_TYPE_GROUP } ) . execute ( ) ;
print ( res ) ;
res = sql : : command ( this - > sql , " INSERT INTO `groups` (`serverId`, `groupId`, `target`, `type`, `displayName`) VALUES (:sid, :gid, :target, :type, :name) " ,
variable { " :sid " , targetServerId } , variable { " :gid " , groupId } , variable { " :target " , group - > target ( ) } , variable { " :type " , type } , variable { " :name " , name } ) . execute ( ) ;
print ( res ) ;
2020-01-23 20:57:58 -05:00
if ( targetServerId = = ( this - > getServerId ( ) ) )
2019-07-17 13:37:18 -04:00
this - > loadGroupFormDatabase ( groupId ) ;
2020-01-23 20:57:58 -05:00
else if ( this - > root )
this - > root - > loadGroupFormDatabase ( groupId ) ;
2019-10-21 14:46:17 -04:00
return groupId ;
2019-07-17 13:37:18 -04:00
}
bool GroupManager : : copyGroupPermissions ( const shared_ptr < Group > & source , const shared_ptr < Group > & target ) {
2020-01-23 20:57:58 -05:00
auto targetServer = target - > handle - > getServerId ( ) ;
auto sourceServer = source - > handle - > getServerId ( ) ;
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
auto res = sql : : command ( this - > sql , " DELETE FROM `permissions` WHERE `serverId` = :sid AND `type` = :type AND `id` = :id " , variable { " :sid " , targetServer } , variable { " :type " , SQL_PERM_GROUP } , variable { " :id " , target - > groupId ( ) } ) . execute ( ) ;
LOG_SQL_CMD ( res ) ;
2019-07-17 13:37:18 -04:00
res = sql : : command ( this - > sql , " INSERT INTO `permissions` (`serverId`, `type`, `id`, `channelId`, `permId`, `value`, `grant`) SELECT :tsid AS `serverId`, `type`, :target AS `id`, 0 AS `channelId`, `permId`, `value`,`grant` FROM `permissions` WHERE `serverId` = :ssid AND `type` = :type AND `id` = :source " ,
variable { " :ssid " , sourceServer } , variable { " :tsid " , targetServer } , variable { " :type " , SQL_PERM_GROUP } , variable { " :source " , source - > groupId ( ) } , variable { " :target " , target - > groupId ( ) } ) . execute ( ) ;
2020-01-23 20:57:58 -05:00
target - > setPermissionManager ( serverInstance - > databaseHelper ( ) - > loadGroupPermissions ( target - > handle - > server . lock ( ) , target - > groupId ( ) ) ) ;
2019-07-17 13:37:18 -04:00
LOG_SQL_CMD ( res ) ;
2020-01-23 20:57:58 -05:00
return true ;
2019-07-17 13:37:18 -04:00
}
bool GroupManager : : reloadGroupPermissions ( std : : shared_ptr < Group > group ) {
if ( ! isLocalGroup ( group ) ) {
if ( this - > root ) return this - > root - > reloadGroupPermissions ( group ) ;
return false ;
}
group - > setPermissionManager ( serverInstance - > databaseHelper ( ) - > loadGroupPermissions ( this - > server . lock ( ) , group - > groupId ( ) ) ) ;
return true ;
}
bool GroupManager : : renameGroup ( std : : shared_ptr < Group > group , std : : string name ) {
if ( ! isLocalGroup ( group ) ) {
if ( this - > root ) return this - > root - > renameGroup ( group , name ) ;
return false ;
}
// CREATE_TABLE("groups", "`serverId` INT NOT NULL, `groupId` INTEGER, `target` INT, `type` INT, `displayName` TEXT");
group - > properties ( ) [ property : : GROUP_NAME ] = name ;
sql : : command ( this - > sql , " UPDATE `groups` SET `displayName` = :name WHERE `serverId` = :sid AND `groupId` = :gid AND `target` = :target " ,
variable { " :name " , name } , variable { " :gid " , group - > groupId ( ) } , variable { " :target " , group - > target ( ) } , variable { " :sid " , this - > getServerId ( ) } ) . executeLater ( ) . waitAndGetLater ( LOG_SQL_CMD , { - 1 , " failed " } ) ;
return true ;
}
bool GroupManager : : deleteAllGroups ( ) {
2020-01-23 20:57:58 -05:00
LOG_SQL_CMD ( sql : : command ( this - > sql , " DELETE FROM `groups` WHERE `serverId` = :sid " , variable { " :sid " , this - > getServerId ( ) } ) . execute ( ) ) ;
LOG_SQL_CMD ( sql : : command ( this - > sql , " DELETE FROM `assignedGroups` WHERE `serverId` = :sid " , variable { " :sid " , this - > getServerId ( ) } ) . execute ( ) ) ;
LOG_SQL_CMD ( sql : : command ( this - > sql , " DELETE FROM `permissions` WHERE `serverId` = :sid AND `type` = :type " , variable { " :sid " , this - > getServerId ( ) } , variable { " :type " , SQL_PERM_GROUP } ) . execute ( ) ) ;
{
lock_guard cache_lock ( this - > cacheLock ) ;
for ( const auto & entry : this - > cachedClients ) {
lock_guard entry_lock ( entry - > lock ) ;
entry - > server_groups . clear ( ) ;
entry - > channel_groups . clear ( ) ;
}
}
this - > groups . clear ( ) ;
return true ;
2019-07-17 13:37:18 -04:00
}
bool GroupManager : : deleteGroup ( std : : shared_ptr < Group > group ) {
if ( ! isLocalGroup ( group ) ) {
if ( this - > root ) return this - > root - > deleteGroup ( group ) ;
return false ;
}
this - > groups . erase ( std : : find ( this - > groups . begin ( ) , this - > groups . end ( ) , group ) ) ;
2019-09-14 08:22:16 -04:00
/* erase the group out of our cache */
2020-01-23 20:57:58 -05:00
{
lock_guard cache_lock ( this - > cacheLock ) ;
for ( auto & entry : this - > cachedClients ) {
lock_guard entry_lock ( entry - > lock ) ;
entry - > server_groups . erase ( std : : remove_if ( entry - > server_groups . begin ( ) , entry - > server_groups . end ( ) , [ & ] ( const std : : shared_ptr < GroupAssignment > & group_assignment ) {
return group_assignment - > group = = group ;
} ) , entry - > server_groups . end ( ) ) ;
for ( auto it = entry - > channel_groups . begin ( ) ; it ! = entry - > channel_groups . end ( ) ; ) {
if ( it - > second - > group = = group )
it = entry - > channel_groups . erase ( it ) ;
else
it + + ;
}
}
}
2019-09-14 08:22:16 -04:00
2019-07-17 13:37:18 -04:00
bool flag_sql = false ;
auto res = sql : : command ( this - > sql , " DELETE FROM `groups` WHERE `serverId` = :sid AND `groupId` = :gid " , variable { " :sid " , this - > getServerId ( ) } , variable { " :gid " , group - > groupId ( ) } ) . execute ( ) ;
2020-01-23 20:57:58 -05:00
LOG_SQL_CMD ( res ) ;
flag_sql | = ! res ;
2019-07-17 13:37:18 -04:00
res = sql : : command ( this - > sql , " DELETE FROM `assignedGroups` WHERE `serverId` = :sid AND `groupId` = :gid " , variable { " :sid " , this - > getServerId ( ) } , variable { " :gid " , group - > groupId ( ) } ) . execute ( ) ;
2020-01-23 20:57:58 -05:00
LOG_SQL_CMD ( res ) ;
flag_sql | = ! res ;
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
flag_sql & = serverInstance - > databaseHelper ( ) - > deleteGroupPermissions ( this - > server . lock ( ) , group - > groupId ( ) ) ;
if ( flag_sql )
logError ( this - > getServerId ( ) , " Could not delete group {} ({}) from database. May leader to invalid data " , group - > name ( ) , group - > groupId ( ) ) ;
2019-07-17 13:37:18 -04:00
return true ;
}
int64_t GroupManager : : generateGroupId ( sql : : SqlManager * sql ) {
2020-01-23 20:57:58 -05:00
int64_t hightestGroupId = 0 ;
2019-07-17 13:37:18 -04:00
sql : : command ( sql , " SELECT `groupId` FROM `groups` ORDER BY `groupId` DESC LIMIT 1 " ) . query ( [ ] ( int64_t * ptr , int , char * * values , char * * ) {
* ptr = stoul ( values [ 0 ] ) ;
return 0 ;
} , & hightestGroupId ) ;
return hightestGroupId + 1 ;
}
2019-10-29 11:06:34 -04:00
std : : deque < property : : ClientProperties > GroupManager : : update_server_group_property ( const shared_ptr < server : : ConnectedClient > & client , bool channel_lock , const std : : shared_ptr < BasicChannel > & channel ) {
2020-01-23 20:57:58 -05:00
std : : deque < property : : ClientProperties > changed ;
//Server groups
{
auto groups = this - > getServerGroups ( client - > getClientDatabaseId ( ) , client - > getType ( ) ) ;
string group_string ;
for ( const auto & group : groups )
if ( group_string . empty ( ) ) group_string + = to_string ( group - > group - > groupId ( ) ) ;
else group_string + = " , " + to_string ( group - > group - > groupId ( ) ) ;
if ( client - > properties ( ) [ property : : CLIENT_SERVERGROUPS ] ! = group_string ) {
client - > properties ( ) [ property : : CLIENT_SERVERGROUPS ] = group_string ;
changed . push_back ( property : : CLIENT_SERVERGROUPS ) ;
unique_lock chan_lock ( client - > channel_lock , defer_lock ) ;
if ( channel_lock )
chan_lock . lock ( ) ;
client - > cached_server_groups . clear ( ) ;
client - > cached_server_groups . reserve ( groups . size ( ) ) ;
for ( const auto & group : groups )
client - > cached_server_groups . push_back ( group - > group - > groupId ( ) ) ;
}
}
//Channel groups
if ( channel ) {
shared_ptr < GroupAssignment > group = this - > getChannelGroup ( client - > getClientDatabaseId ( ) , channel , true ) ;
if ( client - > properties ( ) [ property : : CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID ] ! = group - > channelId ) {
client - > properties ( ) [ property : : CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID ] = group - > channelId ;
changed . push_back ( property : : CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID ) ;
}
if ( client - > properties ( ) [ property : : CLIENT_CHANNEL_GROUP_ID ] ! = group - > group - > groupId ( ) ) {
client - > properties ( ) [ property : : CLIENT_CHANNEL_GROUP_ID ] = group - > group - > groupId ( ) ;
changed . push_back ( property : : CLIENT_CHANNEL_GROUP_ID ) ;
unique_lock chan_lock ( client - > channel_lock , defer_lock ) ;
if ( channel_lock )
chan_lock . lock ( ) ;
client - > cached_channel_group = group - > group - > groupId ( ) ;
}
}
if ( ! changed . empty ( ) )
client - > join_state_id + + ; /* groups have changed :) */
return changed ;
2019-07-17 13:37:18 -04:00
}
void GroupManager : : cleanupAssignments ( ClientDbId client ) {
2020-01-23 20:57:58 -05:00
if ( this - > root )
this - > root - > cleanupAssignments ( client ) ;
2019-07-17 13:37:18 -04:00
for ( const auto & assignment : this - > getAssignedServerGroups ( client ) ) {
2020-01-23 20:57:58 -05:00
if ( ! assignment - > group - > is_permanent ( ) )
this - > removeServerGroup ( client , assignment - > group ) ;
2019-07-17 13:37:18 -04:00
}
}
2019-09-14 08:22:16 -04:00
void GroupManager : : enableCache ( const ClientDbId & client_database_id ) {
2019-07-17 13:37:18 -04:00
if ( this - > root )
2020-01-23 20:57:58 -05:00
this - > root - > enableCache ( client_database_id ) ;
2019-09-14 08:22:16 -04:00
unique_lock cache_lock ( this - > cacheLock ) ;
/* test if we're already having the client */
for ( auto & entry : this - > cachedClients )
2020-01-23 20:57:58 -05:00
if ( entry - > client_database_id = = client_database_id ) {
entry - > use_count + + ;
return ; /* client already cached, no need to cache client */
}
2019-09-14 08:22:16 -04:00
auto entry = std : : make_shared < CachedClient > ( ) ;
entry - > client_database_id = client_database_id ;
2020-01-23 20:57:58 -05:00
entry - > use_count + + ;
2019-09-14 08:22:16 -04:00
this - > cachedClients . push_back ( entry ) ;
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
lock_guard client_cache_lock ( entry - > lock ) ; /* lock the client because we're currently loading the cache. */
cache_lock . unlock ( ) ;
2019-07-17 13:37:18 -04:00
2019-09-14 08:22:16 -04:00
auto res = sql : : command ( this - > sql , " SELECT `groupId`, `channelId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid " , variable { " :sid " , this - > getServerId ( ) } , variable { " :cldbid " , client_database_id } )
2020-01-23 20:57:58 -05:00
. query ( [ & ] ( int length , std : : string * value , std : : string * column ) {
2019-07-17 13:37:18 -04:00
shared_ptr < Group > group = nullptr ;
time_point < system_clock > until ;
ChannelId channelId = 0 ;
for ( int index = 0 ; index < length ; index + + ) {
2019-09-14 08:22:16 -04:00
try {
2020-01-23 20:57:58 -05:00
if ( column [ index ] = = " groupId " ) {
group = this - > findGroup ( stoll ( value [ index ] ) ) ;
} else if ( column [ index ] = = " until " ) {
until = time_point < system_clock > ( ) + milliseconds ( stoll ( value [ index ] ) ) ;
} else if ( column [ index ] = = " channelId " ) {
channelId = stoll ( value [ index ] ) ;
} else {
logError ( this - > getServerId ( ) , " Unknown column in group assignment query: {} " , column [ index ] ) ;
continue ;
}
2019-09-14 08:22:16 -04:00
} catch ( std : : exception & ex ) {
2020-01-23 20:57:58 -05:00
logError ( this - > getServerId ( ) , " Failed to load group assignment from database for client {}. Column {} contains an invalid value: {} " , client_database_id , column [ index ] , value [ index ] ) ;
return 0 ;
2019-07-17 13:37:18 -04:00
}
}
2019-09-14 08:22:16 -04:00
if ( ! group ) {
2020-01-23 20:57:58 -05:00
return 0 ;
2019-09-14 08:22:16 -04:00
}
2019-07-17 13:37:18 -04:00
2019-09-14 08:22:16 -04:00
auto assignment = std : : make_shared < GroupAssignment > ( ) ;
2019-07-17 13:37:18 -04:00
assignment - > group = group ;
assignment - > until = until ;
2019-09-14 08:22:16 -04:00
assignment - > parent = & * entry ;
2020-01-23 20:57:58 -05:00
assignment - > channelId = channelId ;
assignment - > server = this - > getServerId ( ) ;
2019-09-14 08:22:16 -04:00
2019-07-17 13:37:18 -04:00
if ( channelId = = 0 )
2020-01-23 20:57:58 -05:00
entry - > server_groups . push_back ( assignment ) ;
2019-09-14 08:22:16 -04:00
else
2020-01-23 20:57:58 -05:00
entry - > channel_groups [ channelId ] = assignment ;
2019-07-17 13:37:18 -04:00
return 0 ;
2019-09-14 08:22:16 -04:00
} ) ;
2019-07-17 13:37:18 -04:00
}
2019-09-14 08:22:16 -04:00
//FIXME: This method till get far more often then it should be. We should add a flag if the group cache is loaded for each std::shared_ptr<ConnectedClient> instance
void GroupManager : : disableCache ( const ClientDbId & client_database_id ) {
2019-11-07 20:44:22 -05:00
if ( this - > root ) {
2020-01-23 20:57:58 -05:00
this - > root - > disableCache ( client_database_id ) ;
2019-11-07 20:44:22 -05:00
}
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
lock_guard cache_lock ( this - > cacheLock ) ;
this - > cachedClients . erase ( std : : remove_if ( this - > cachedClients . begin ( ) , this - > cachedClients . end ( ) , [ & ] ( const std : : shared_ptr < CachedClient > & client ) {
if ( client - > client_database_id ! = client_database_id )
return false ;
2019-09-14 08:22:16 -04:00
2020-01-23 20:57:58 -05:00
lock_guard client_lock { client - > lock } ;
return ( - - client - > use_count ) = = 0 ;
} ) , this - > cachedClients . end ( ) ) ;
2019-07-17 13:37:18 -04:00
}
void GroupManager : : clearCache ( ) {
if ( this - > root ) this - > root - > clearCache ( ) ;
2019-09-14 08:22:16 -04:00
lock_guard lock ( this - > cacheLock ) ;
2019-07-17 13:37:18 -04:00
this - > cachedClients . clear ( ) ;
}
2019-09-14 08:22:16 -04:00
bool GroupManager : : isClientCached ( const ClientDbId & client_database_id ) {
2020-01-23 20:57:58 -05:00
return this - > resolve_cached_client ( client_database_id ) = = nullptr ;
2019-07-17 13:37:18 -04:00
}
typedef std : : vector < std : : shared_ptr < GroupMember > > ResList ;
std : : vector < std : : shared_ptr < GroupMember > > GroupManager : : listGroupMembers ( std : : shared_ptr < Group > group , bool names ) { //TODO juse inner join only on names = true
if ( ! isLocalGroup ( group ) ) {
if ( this - > root ) return this - > root - > listGroupMembers ( group , names ) ;
return { } ;
}
ResList result ;
sql : : command ( this - > sql ,
" SELECT assignedGroups.cldbid, assignedGroups.channelId, assignedGroups.until, clients.clientUid, clients.lastName FROM assignedGroups INNER JOIN clients ON (clients.cldbid = assignedGroups.cldbid AND clients.serverId = assignedGroups.serverId) WHERE assignedGroups.`serverId` = :sid AND `groupId` = :gid; " ,
variable { " :sid " , this - > getServerId ( ) } , variable { " :gid " , group - > groupId ( ) } )
. query ( [ & ] ( ResList * list , int columnCount , char * * values , char * * columnName ) {
std : : shared_ptr < GroupMember > member = std : : make_shared < GroupMember > ( ) ;
member - > displayName = " undefined " ;
member - > uid = " undefined " ;
for ( int index = 0 ; index < columnCount ; index + + ) {
if ( values [ index ] = = nullptr ) {
logError ( this - > getServerId ( ) , string ( ) + " Invalid value at " + columnName [ index ] ) ;
continue ;
}
if ( strcmp ( columnName [ index ] , " cldbid " ) = = 0 )
member - > cldbId = stoll ( values [ index ] ) ;
else if ( strcmp ( columnName [ index ] , " until " ) = = 0 )
member - > until = time_point < system_clock > ( ) + milliseconds ( stoll ( values [ index ] ) ) ;
else if ( strcmp ( columnName [ index ] , " clientUid " ) = = 0 )
member - > uid = values [ index ] ;
else if ( strcmp ( columnName [ index ] , " lastName " ) = = 0 )
member - > displayName = values [ index ] ;
else if ( strcmp ( columnName [ index ] , " channelId " ) = = 0 )
member - > channelId = stoll ( values [ index ] ) ;
else cerr < < " Invalid column name " < < columnName [ index ] < < endl ;
}
list - > push_back ( member ) ;
return 0 ;
} , & result ) ;
return result ;
}
vector < shared_ptr < GroupAssignment > > GroupManager : : listGroupAssignments ( ClientDbId cldbId ) {
vector < std : : shared_ptr < GroupAssignment > > result ;
sql : : result res ;
2019-09-14 08:22:16 -04:00
auto cached = resolve_cached_client ( cldbId ) ;
2019-07-17 13:37:18 -04:00
if ( cached ) {
2020-01-23 20:57:58 -05:00
{
lock_guard lock { cached - > lock } ;
for ( const auto & serverGroup : cached - > server_groups )
result . push_back ( serverGroup ) ;
for ( auto & channelGroup : cached - > channel_groups )
result . push_back ( channelGroup . second ) ;
}
2019-07-17 13:37:18 -04:00
if ( this - > root ) {
auto append = this - > root - > listGroupAssignments ( cldbId ) ;
for ( const auto & elm : append )
result . push_back ( elm ) ;
}
return result ;
}
2019-09-14 08:22:16 -04:00
res = sql : : command ( this - > sql , " SELECT `groupId`, `until`, `channelId` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid " , variable { " :sid " , this - > getServerId ( ) } , variable { " :cldbid " , cldbId } )
2020-01-23 20:57:58 -05:00
. query ( [ & ] ( int length , char * * value , char * * column ) {
2019-07-17 13:37:18 -04:00
shared_ptr < Group > group = nullptr ;
time_point < system_clock > until ;
uint64_t channelId = 0 ;
for ( int index = 0 ; index < length ; index + + ) {
if ( value [ index ] = = nullptr ) {
logError ( this - > getServerId ( ) , string ( ) + " Invalid value at " + column [ index ] ) ;
continue ;
}
if ( strcmp ( column [ index ] , " groupId " ) = = 0 ) {
2019-09-14 08:22:16 -04:00
group = this - > findGroup ( stoll ( value [ index ] ) ) ;
2019-07-17 13:37:18 -04:00
} else if ( strcmp ( column [ index ] , " until " ) = = 0 ) {
until = time_point < system_clock > ( ) + milliseconds ( stoll ( value [ index ] ) ) ;
} else if ( strcmp ( column [ index ] , " channelId " ) = = 0 ) {
channelId = stoll ( value [ index ] ) ;
} else cerr < < " Invalid column " < < column [ index ] < < endl ;
}
if ( ! group )
return 0 ;
shared_ptr < GroupAssignment > assignment = std : : make_shared < GroupAssignment > ( ) ;
assignment - > parent = nullptr ;
assignment - > group = group ;
assignment - > until = until ;
assignment - > channelId = channelId ;
assignment - > server = this - > getServerId ( ) ;
2019-09-14 08:22:16 -04:00
result . push_back ( assignment ) ;
2019-07-17 13:37:18 -04:00
return 0 ;
2019-09-14 08:22:16 -04:00
} ) ;
2019-07-17 13:37:18 -04:00
( LOG_SQL_CMD ) ( res ) ;
if ( this - > root ) {
auto append = this - > root - > listGroupAssignments ( cldbId ) ;
for ( const auto & elm : append )
result . push_back ( elm ) ;
}
return result ;
}
2019-09-14 08:22:16 -04:00
std : : shared_ptr < CachedClient > GroupManager : : resolve_cached_client ( ClientDbId client_database_id ) {
2020-01-23 20:57:58 -05:00
{
lock_guard lock ( this - > cacheLock ) ;
for ( auto & entry : this - > cachedClients )
if ( entry - > client_database_id = = client_database_id )
return entry ;
}
2019-09-14 08:22:16 -04:00
2020-01-23 20:57:58 -05:00
return nullptr ;
2019-07-17 13:37:18 -04:00
}
std : : vector < std : : shared_ptr < GroupAssignment > > GroupManager : : getAssignedServerGroups ( ClientDbId cldbid ) {
2020-01-23 20:57:58 -05:00
auto cached = this - > resolve_cached_client ( cldbid ) ;
sql : : result res ;
std : : vector < std : : shared_ptr < GroupAssignment > > result ;
if ( this - > root ) {
2020-02-15 16:03:08 -05:00
auto client_groups = this - > root - > getAssignedServerGroups ( cldbid ) ;
result . insert ( result . begin ( ) , client_groups . begin ( ) , client_groups . end ( ) ) ;
2020-01-23 20:57:58 -05:00
}
if ( cached ) {
lock_guard cache_lock { cached - > lock } ;
result . insert ( result . end ( ) , cached - > server_groups . begin ( ) , cached - > server_groups . end ( ) ) ;
return result ;
}
debugMessage ( this - > getServerId ( ) , " Query client groups for client {} on server {}. " , cldbid , this - > getServerId ( ) ) ;
res = sql : : command ( this - > sql , " SELECT `groupId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` = 0 " , variable { " :sid " , this - > getServerId ( ) } , variable { " :cldbid " , cldbid } ) . query ( [ & ] ( int length , char * * value , char * * column ) {
shared_ptr < Group > group = nullptr ;
time_point < system_clock > until ;
2020-02-15 16:03:08 -05:00
for ( int index = 0 ; index < length ; index + + ) {
2020-01-23 20:57:58 -05:00
if ( value [ index ] = = nullptr ) {
logError ( this - > getServerId ( ) , string ( ) + " Invalid value at " + column [ index ] ) ;
continue ;
}
if ( strcmp ( column [ index ] , " groupId " ) = = 0 & & value [ index ] ! = nullptr ) {
group = this - > findGroup ( stoll ( value [ index ] ) ) ;
} else if ( strcmp ( column [ index ] , " until " ) = = 0 ) {
until = time_point < system_clock > ( ) + milliseconds ( stoll ( value [ index ] = = nullptr ? " 0 " : value [ index ] ) ) ;
} else cerr < < " Invalid column " < < column [ index ] < < endl ;
}
if ( ! group )
return 0 ;
shared_ptr < GroupAssignment > assignment = std : : make_shared < GroupAssignment > ( ) ;
assignment - > parent = nullptr ;
assignment - > group = group ;
assignment - > until = until ;
assignment - > server = this - > getServerId ( ) ;
result . push_back ( assignment ) ;
return 0 ;
} ) ;
LOG_SQL_CMD ( res ) ;
return result ;
2019-07-17 13:37:18 -04:00
}
std : : vector < std : : shared_ptr < GroupAssignment > > GroupManager : : getServerGroups ( ClientDbId cldbid , server : : ClientType type ) {
auto result = this - > getAssignedServerGroups ( cldbid ) ;
2020-01-23 20:57:58 -05:00
if ( result . empty ( ) ) return this - > defaultServerGroupGroupAssignments ( cldbid , type ) ;
return result ;
2019-07-17 13:37:18 -04:00
}
std : : vector < std : : shared_ptr < GroupAssignment > > GroupManager : : defaultServerGroupGroupAssignments ( ClientDbId client , ClientType type ) {
2020-01-23 20:57:58 -05:00
std : : vector < std : : shared_ptr < GroupAssignment > > result ;
if ( type = = ClientType : : CLIENT_QUERY & & this - > root ) {
auto root = this - > root - > defaultServerGroupGroupAssignments ( client , type ) ;
result . insert ( result . begin ( ) , root . begin ( ) , root . end ( ) ) ;
} else if ( type = = ClientType : : CLIENT_MUSIC ) {
threads : : MutexLock lock ( this - > cacheLock ) ;
auto server = this - > server . lock ( ) ;
auto id =
server ?
server - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_MUSIC_GROUP ] . as_save < GroupId > ( ) :
serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP ] . as_save < GroupId > ( ) ;
auto group = this - > findGroupLocal ( id ) ;
if ( group ) {
result . push_back ( std : : make_shared < GroupAssignment > ( nullptr , this - > getServerId ( ) , 0 , group , time_point < system_clock > ( ) ) ) ;
return result ;
}
}
result . push_back ( std : : make_shared < GroupAssignment > ( nullptr , this - > getServerId ( ) , 0 , this - > defaultGroup ( GroupTarget : : GROUPTARGET_SERVER ) , time_point < system_clock > ( ) ) ) ;
return result ;
2019-07-17 13:37:18 -04:00
}
std : : shared_ptr < GroupAssignment > GroupManager : : getChannelGroupExact ( ClientDbId cldbId , const std : : shared_ptr < BasicChannel > & channel , bool assign_default ) {
2020-01-23 20:57:58 -05:00
auto cached = resolve_cached_client ( cldbId ) ;
if ( cached ) {
lock_guard cache_lock ( cached - > lock ) ;
if ( cached - > channel_groups . count ( channel - > channelId ( ) ) > 0 ) {
return cached - > channel_groups [ channel - > channelId ( ) ] ;
} else
return assign_default ? this - > defaultChannelGroupAssignment ( cldbId , channel ) : nullptr ;
}
std : : shared_ptr < GroupAssignment > result ;
auto res = sql : : command ( this - > sql , " SELECT `groupId`, `until` FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` = :chid " , variable { " :sid " , this - > getServerId ( ) } , variable { " :cldbid " , cldbId } , variable { " :chid " , channel - > channelId ( ) } ) . query ( [ & ] ( int length , char * * value , char * * column ) {
shared_ptr < Group > group = nullptr ;
time_point < system_clock > until ;
for ( int index = 0 ; index < length ; index + + ) {
if ( value [ index ] = = nullptr ) {
logError ( this - > getServerId ( ) , string ( ) + " Invalid value at " + column [ index ] ) ;
continue ;
}
if ( strcmp ( column [ index ] , " groupId " ) = = 0 ) {
group = this - > findGroup ( stoll ( value [ index ] ) ) ;
} else if ( strcmp ( column [ index ] , " until " ) = = 0 ) {
until = time_point < system_clock > ( ) + milliseconds ( stoll ( value [ index ] ) ) ;
} else cerr < < " Invalid column " < < column [ index ] < < endl ;
}
if ( ! group )
return 0 ;
shared_ptr < GroupAssignment > assignment = std : : make_shared < GroupAssignment > ( ) ;
assignment - > parent = nullptr ;
assignment - > group = group ;
assignment - > until = until ;
assignment - > server = this - > getServerId ( ) ;
assignment - > channelId = channel - > channelId ( ) ;
result = std : : move ( assignment ) ;
return 0 ;
} ) ;
( LOG_SQL_CMD ) ( res ) ;
return ! result & & assign_default ? this - > defaultChannelGroupAssignment ( cldbId , channel ) : result ;
2019-07-17 13:37:18 -04:00
}
std : : shared_ptr < GroupAssignment > GroupManager : : getChannelGroup ( ClientDbId cldbId , const shared_ptr < BasicChannel > & channel , bool assign_default ) {
2020-01-23 20:57:58 -05:00
shared_ptr < GroupAssignment > group ;
std : : shared_ptr < BasicChannel > inheritance_channel = channel ;
while ( inheritance_channel & & ! group ) {
group = this - > getChannelGroupExact ( cldbId , inheritance_channel , false ) ;
if ( ! group ) {
auto inheritance = inheritance_channel - > permissions ( ) - > permission_value_flagged ( permission : : b_channel_group_inheritance_end ) ;
if ( inheritance . has_value & & inheritance . value = = 1 )
break ;
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
inheritance_channel = inheritance_channel - > parent ( ) ;
}
}
return ! group & & assign_default ? this - > defaultChannelGroupAssignment ( cldbId , channel ) : group ;
2019-07-17 13:37:18 -04:00
}
std : : shared_ptr < GroupAssignment > GroupManager : : defaultChannelGroupAssignment ( ClientDbId cldbId , const std : : shared_ptr < BasicChannel > & channel ) {
2020-01-23 20:57:58 -05:00
return std : : make_shared < GroupAssignment > ( nullptr , this - > getServerId ( ) , channel - > channelId ( ) , this - > defaultGroup ( GroupTarget : : GROUPTARGET_CHANNEL ) , time_point < system_clock > ( ) ) ;
2019-07-17 13:37:18 -04:00
}
void GroupManager : : addServerGroup ( ClientDbId cldbId , std : : shared_ptr < Group > group , time_point < system_clock > until ) {
/*
if ( ! this - > isLocalGroup ( group ) ) {
if ( this - > root ) this - > root - > addServerGroup ( cldbId , group , until ) ;
return ;
}
if ( hasServerGroup ( cldbId , group ) ) return ;
*/
2019-09-14 08:22:16 -04:00
auto cached = resolve_cached_client ( cldbId ) ;
2019-07-17 13:37:18 -04:00
if ( cached ) {
2020-01-23 20:57:58 -05:00
lock_guard cache_lock ( cached - > lock ) ;
cached - > server_groups . push_back ( std : : make_shared < GroupAssignment > ( cached . get ( ) , this - > getServerId ( ) , 0 , group , until ) ) ;
2019-07-17 13:37:18 -04:00
}
sql : : command ( this - > sql , " INSERT INTO `assignedGroups` (`serverId`, `cldbid`, `groupId`, `channelId`, `until`) VALUES (:sid, :cldbid, :gid, :chid, :until) " ,
variable { " :sid " , this - > getServerId ( ) } ,
variable { " :cldbid " , cldbId } ,
variable { " :gid " , group - > groupId ( ) } ,
variable { " :chid " , 0 } ,
variable { " :until " , time_point_cast < milliseconds > ( until ) . time_since_epoch ( ) . count ( ) } )
. executeLater ( ) . waitAndGetLater ( LOG_SQL_CMD , { 1 , " future failed " } ) ;
}
void GroupManager : : removeServerGroup ( ClientDbId cldbId , std : : shared_ptr < Group > group ) {
if ( ! this - > hasServerGroupAssigned ( cldbId , group ) ) return ;
2019-09-14 08:22:16 -04:00
auto cached = resolve_cached_client ( cldbId ) ;
2019-07-17 13:37:18 -04:00
if ( cached ) {
2020-01-23 20:57:58 -05:00
lock_guard cache_lock ( cached - > lock ) ;
cached - > server_groups . erase ( std : : remove_if ( cached - > server_groups . begin ( ) , cached - > server_groups . end ( ) , [ & ] ( const std : : shared_ptr < GroupAssignment > & group_assignment ) {
return group_assignment - > group = = group ;
} ) , cached - > server_groups . end ( ) ) ;
2019-07-17 13:37:18 -04:00
}
sql : : command ( this - > sql , " DELETE FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `groupId` = :gid AND `channelId` = :chid " ,
variable { " :sid " , this - > getServerId ( ) } ,
variable { " :cldbid " , cldbId } ,
variable { " :gid " , group - > groupId ( ) } ,
variable { " :chid " , 0 } )
. executeLater ( ) . waitAndGetLater ( LOG_SQL_CMD , { 1 , " future failed " } ) ;
}
void GroupManager : : setChannelGroup ( ClientDbId cldbId , std : : shared_ptr < Group > group , std : : shared_ptr < BasicChannel > channel , time_point < system_clock > until ) {
2020-01-23 20:57:58 -05:00
auto old_group = getChannelGroupExact ( cldbId , channel , false ) ;
if ( old_group ) {
if ( old_group - > group = = group ) return ;
} else if ( ! group ) return ;
2019-07-17 13:37:18 -04:00
2020-01-23 20:57:58 -05:00
auto default_group = ! group | | group = = this - > defaultGroup ( GroupTarget : : GROUPTARGET_CHANNEL ) ;
2019-09-14 08:22:16 -04:00
auto cached = resolve_cached_client ( cldbId ) ;
2019-07-17 13:37:18 -04:00
if ( cached ) {
2020-01-23 20:57:58 -05:00
lock_guard cache_lock ( cached - > lock ) ;
if ( default_group )
cached - > channel_groups . erase ( channel - > channelId ( ) ) ;
else
cached - > channel_groups [ channel - > channelId ( ) ] = std : : make_shared < GroupAssignment > ( cached . get ( ) , this - > getServerId ( ) , channel - > channelId ( ) , group , until ) ;
2019-07-17 13:37:18 -04:00
}
sql : : command ( this - > sql , " DELETE FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` = :chid " ,
variable { " :sid " , this - > getServerId ( ) } ,
variable { " :cldbid " , cldbId } ,
variable { " :chid " , channel - > channelId ( ) } )
. executeLater ( ) . waitAndGetLater ( LOG_SQL_CMD , { 1 , " future failed " } ) ;
2020-01-23 20:57:58 -05:00
if ( ! default_group ) {
sql : : command ( this - > sql , " INSERT INTO `assignedGroups` (`serverId`, `cldbid`, `groupId`, `channelId`, `until`) VALUES (:sid, :cldbid, :gid, :chid, :until) " ,
variable { " :sid " , this - > getServerId ( ) } ,
variable { " :cldbid " , cldbId } ,
variable { " :gid " , group - > groupId ( ) } ,
variable { " :chid " , channel - > channelId ( ) } ,
variable { " :until " , time_point_cast < milliseconds > ( until ) . time_since_epoch ( ) . count ( ) } )
. executeLater ( ) . waitAndGetLater ( LOG_SQL_CMD , { 1 , " future failed " } ) ;
}
2019-07-17 13:37:18 -04:00
}