2022-03-15 18:00:53 +00:00
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
2022-02-09 18:49:52 +00:00
namespace ASC.Data.Backup.Tasks.Modules ;
public abstract class ModuleSpecificsBase : IModuleSpecifics
2020-05-20 15:14:44 +00:00
{
2022-02-09 18:49:52 +00:00
public abstract ModuleName ModuleName { get ; }
public abstract IEnumerable < TableInfo > Tables { get ; }
public abstract IEnumerable < RelationInfo > TableRelations { get ; }
public virtual string ConnectionStringName
= > _connectionStringName ? ? = ModuleName . ToString ( ) . ToLower ( ) ;
private string _connectionStringName ;
private readonly Helpers _helpers ;
2022-01-24 09:57:01 +00:00
protected ModuleSpecificsBase ( Helpers helpers )
2020-05-20 15:14:44 +00:00
{
2022-02-09 18:49:52 +00:00
_helpers = helpers ;
}
public IEnumerable < TableInfo > GetTablesOrdered ( )
{
var notOrderedTables = new List < TableInfo > ( Tables ) ;
2022-02-09 18:33:50 +00:00
2022-02-09 18:49:52 +00:00
var totalTablesCount = notOrderedTables . Count ;
var orderedTablesCount = 0 ;
while ( orderedTablesCount < totalTablesCount )
2020-05-20 15:14:44 +00:00
{
2022-02-09 18:49:52 +00:00
var orderedTablesCountBeforeIter = orderedTablesCount ; // ensure we not in infinite loop...
2020-05-20 15:14:44 +00:00
2022-02-09 18:49:52 +00:00
var i = 0 ;
while ( i < notOrderedTables . Count )
2020-05-20 15:14:44 +00:00
{
2022-02-09 18:49:52 +00:00
var table = notOrderedTables [ i ] ;
2020-05-20 15:14:44 +00:00
2022-02-09 18:49:52 +00:00
var parentTables = TableRelations
. Where ( x = > x . FitsForTable ( table . Name ) & & ! x . IsExternal ( ) & & ! x . IsSelfRelation ( ) & & x . Importance ! = RelationImportance . Low )
. Select ( x = > x . ParentTable ) ;
if ( parentTables . All ( x = > notOrderedTables . All ( y = > ! string . Equals ( y . Name , x , StringComparison . InvariantCultureIgnoreCase ) ) ) )
2020-05-20 15:14:44 +00:00
{
2022-02-09 18:49:52 +00:00
notOrderedTables . RemoveAt ( i ) ;
orderedTablesCount + + ;
2020-05-20 15:14:44 +00:00
2022-02-09 18:49:52 +00:00
yield return table ;
}
else
2022-02-09 18:33:50 +00:00
{
2022-02-09 18:49:52 +00:00
i + + ;
2022-02-09 18:33:50 +00:00
}
2020-05-20 15:14:44 +00:00
}
2022-02-09 18:49:52 +00:00
if ( orderedTablesCountBeforeIter = = orderedTablesCount ) // ensure we not in infinite loop...
2022-02-09 16:46:09 +00:00
{
2022-02-09 18:49:52 +00:00
throw ThrowHelper . CantOrderTables ( notOrderedTables . Select ( x = > x . Name ) ) ;
2022-02-09 16:46:09 +00:00
}
2022-02-09 18:49:52 +00:00
}
}
2020-05-20 15:14:44 +00:00
2022-02-09 18:49:52 +00:00
public DbCommand CreateSelectCommand ( DbConnection connection , int tenantId , TableInfo table , int limit , int offset )
{
var command = connection . CreateCommand ( ) ;
command . CommandText = string . Format ( "select t.* from {0} as t {1} limit {2},{3};" , table . Name , GetSelectCommandConditionText ( tenantId , table ) , offset , limit ) ;
2020-05-20 15:14:44 +00:00
2022-02-09 18:49:52 +00:00
return command ;
}
2020-05-20 15:14:44 +00:00
2022-02-09 18:49:52 +00:00
public DbCommand CreateDeleteCommand ( DbConnection connection , int tenantId , TableInfo table )
{
var command = connection . CreateCommand ( ) ;
2022-01-14 13:12:37 +00:00
command . CommandText = $"delete t.* from {table.Name} as t {GetDeleteCommandConditionText(tenantId, table)};" ;
2022-02-09 18:33:50 +00:00
2022-02-09 18:49:52 +00:00
return command ;
}
2022-02-09 18:33:50 +00:00
2022-02-09 18:49:52 +00:00
public DbCommand CreateInsertCommand ( bool dump , DbConnection connection , ColumnMapper columnMapper , TableInfo table , DataRowInfo row )
{
if ( table . InsertMethod = = InsertMethod . None )
{
return null ;
2020-05-20 15:14:44 +00:00
}
2022-02-09 18:33:50 +00:00
2022-02-09 18:49:52 +00:00
if ( ! TryPrepareRow ( dump , connection , columnMapper , table , row , out var valuesForInsert ) )
2020-05-26 08:52:47 +00:00
{
2022-02-09 18:49:52 +00:00
return null ;
}
2020-05-20 15:14:44 +00:00
2022-02-09 18:49:52 +00:00
var columns = valuesForInsert . Keys . Intersect ( table . Columns ) . ToArray ( ) ;
2022-01-14 13:12:37 +00:00
var insert = table . InsertMethod ! = InsertMethod . Ignore
2022-02-09 18:49:52 +00:00
? table . InsertMethod . ToString ( ) . ToLower ( )
2022-01-14 13:12:37 +00:00
: "insert ignore" ;
var insertCommantText = $"{insert} into {table.Name}({string.Join(" , ", columns)}) values({string.Join(" , ", columns.Select(c => " @" + c))});" ;
2022-02-09 18:33:50 +00:00
2022-02-09 18:49:52 +00:00
var command = connection . CreateCommand ( ) ;
command . CommandText = insertCommantText ;
foreach ( var parameter in valuesForInsert )
{
AddParameter ( command , parameter . Key , parameter . Value ) ;
2020-05-26 08:52:47 +00:00
}
2022-02-09 18:49:52 +00:00
return command ;
}
public DbCommand AddParameter ( DbCommand command , string name , object value )
{
var p = command . CreateParameter ( ) ;
if ( ! string . IsNullOrEmpty ( name ) )
2020-05-26 08:52:47 +00:00
{
2022-02-15 16:56:43 +00:00
p . ParameterName = name . StartsWith ( '@' ) ? name : "@" + name ;
2022-02-09 18:49:52 +00:00
}
2020-05-26 08:52:47 +00:00
2022-02-09 18:49:52 +00:00
p . Value = GetParameterValue ( value ) ;
2020-05-26 08:52:47 +00:00
2022-02-09 18:49:52 +00:00
command . Parameters . Add ( p ) ;
2022-02-09 18:33:50 +00:00
2022-02-09 18:49:52 +00:00
return command ;
}
2022-02-09 18:33:50 +00:00
2022-02-09 18:49:52 +00:00
public object GetParameterValue ( object value )
{
if ( value = = null )
2020-05-20 15:14:44 +00:00
{
2022-02-09 18:49:52 +00:00
return DBNull . Value ;
2020-05-20 15:14:44 +00:00
}
2022-02-09 18:49:52 +00:00
if ( value is Enum @enum )
2022-02-09 18:33:50 +00:00
{
2022-02-09 18:49:52 +00:00
return @enum . ToString ( "d" ) ;
2022-02-09 18:33:50 +00:00
}
2022-02-09 18:49:52 +00:00
if ( value is DateTime d )
2022-02-09 18:33:50 +00:00
{
2022-02-09 18:49:52 +00:00
return new DateTime ( d . Year , d . Month , d . Day , d . Hour , d . Minute , d . Second , DateTimeKind . Unspecified ) ;
2022-02-09 18:33:50 +00:00
}
2022-02-09 18:49:52 +00:00
return value ;
}
2020-05-20 15:14:44 +00:00
2022-02-09 18:49:52 +00:00
public virtual bool TryAdjustFilePath ( bool dump , ColumnMapper columnMapper , ref string filePath )
{
return true ;
}
public virtual void PrepareData ( DataTable data )
{
// nothing to do
}
public virtual Stream PrepareData ( string key , Stream stream , ColumnMapper columnMapper )
{
return stream ;
}
2020-05-20 15:14:44 +00:00
2022-02-09 18:49:52 +00:00
protected virtual string GetSelectCommandConditionText ( int tenantId , TableInfo table )
{
if ( ! table . HasTenantColumn ( ) )
2020-05-20 15:14:44 +00:00
{
2022-02-09 18:49:52 +00:00
throw ThrowHelper . CantDetectTenant ( table . Name ) ;
2020-05-20 15:14:44 +00:00
}
2022-02-09 18:49:52 +00:00
return string . Format ( "where t.{0} = {1}" , table . TenantColumn , tenantId ) ;
}
2020-05-20 15:14:44 +00:00
2022-02-09 18:49:52 +00:00
protected virtual string GetDeleteCommandConditionText ( int tenantId , TableInfo table )
{
return GetSelectCommandConditionText ( tenantId , table ) ;
}
protected virtual bool TryPrepareRow ( bool dump , DbConnection connection , ColumnMapper columnMapper , TableInfo table , DataRowInfo row , out Dictionary < string , object > preparedRow )
{
preparedRow = new Dictionary < string , object > ( ) ;
2020-05-20 15:14:44 +00:00
2022-02-09 18:49:52 +00:00
var parentRelations = TableRelations
. Where ( x = > x . FitsForRow ( row ) & & x . Importance ! = RelationImportance . Low )
. GroupBy ( x = > x . ChildColumn )
. ToDictionary ( x = > x . Key ) ;
foreach ( var columnName in row . ColumnNames )
{
if ( table . IdType = = IdType . Autoincrement & & columnName . Equals ( table . IdColumn , StringComparison . OrdinalIgnoreCase ) )
2020-05-20 15:14:44 +00:00
{
2022-02-09 18:49:52 +00:00
continue ;
}
2020-05-20 15:14:44 +00:00
2022-02-09 18:49:52 +00:00
var val = row [ columnName ] ;
if ( ! parentRelations . ContainsKey ( columnName ) )
{
if ( ! TryPrepareValue ( connection , columnMapper , table , columnName , ref val ) )
2020-05-20 15:14:44 +00:00
{
2022-02-09 18:49:52 +00:00
return false ;
2020-05-20 15:14:44 +00:00
}
2022-02-09 18:49:52 +00:00
}
else
{
if ( ! TryPrepareValue ( dump , connection , columnMapper , table , columnName , parentRelations [ columnName ] , ref val ) )
2020-05-20 15:14:44 +00:00
{
2022-02-09 18:49:52 +00:00
return false ;
2020-05-20 15:14:44 +00:00
}
2022-02-09 18:49:52 +00:00
if ( ! table . HasIdColumn ( ) & & ! table . HasTenantColumn ( ) & & val = = row [ columnName ] )
2022-02-09 16:46:09 +00:00
{
2020-05-20 15:14:44 +00:00
return false ;
2022-02-09 16:46:09 +00:00
}
2022-02-09 18:49:52 +00:00
}
2022-02-09 16:46:09 +00:00
2022-02-09 18:49:52 +00:00
preparedRow . Add ( columnName , val ) ;
}
2022-02-09 18:33:50 +00:00
2022-02-09 18:49:52 +00:00
return true ;
}
2020-05-20 15:14:44 +00:00
2022-02-09 18:49:52 +00:00
protected virtual bool TryPrepareValue ( DbConnection connection , ColumnMapper columnMapper , TableInfo table , string columnName , ref object value )
{
if ( columnName . Equals ( table . TenantColumn , StringComparison . OrdinalIgnoreCase ) )
{
var tenantMapping = columnMapper . GetTenantMapping ( ) ;
if ( tenantMapping < 1 )
2020-05-20 15:14:44 +00:00
{
2022-02-09 18:49:52 +00:00
return false ;
}
2022-02-09 16:46:09 +00:00
2022-02-09 18:49:52 +00:00
value = tenantMapping ;
2022-02-09 18:33:50 +00:00
2022-02-09 18:49:52 +00:00
return true ;
}
2020-05-20 15:14:44 +00:00
2022-02-09 18:49:52 +00:00
if ( table . UserIDColumns . Any ( x = > columnName . Equals ( x , StringComparison . OrdinalIgnoreCase ) ) )
{
var strVal = Convert . ToString ( value ) ;
var userMapping = columnMapper . GetUserMapping ( strVal ) ;
if ( userMapping = = null )
2022-02-09 16:46:09 +00:00
{
2022-02-09 18:49:52 +00:00
return _helpers . IsEmptyOrSystemUser ( strVal ) ;
2022-02-09 16:46:09 +00:00
}
2020-05-20 15:14:44 +00:00
2022-02-09 18:49:52 +00:00
value = userMapping ;
2020-05-20 15:14:44 +00:00
return true ;
}
2022-02-09 18:49:52 +00:00
var mapping = columnMapper . GetMapping ( table . Name , columnName , value ) ;
if ( mapping ! = null )
2020-05-20 15:14:44 +00:00
{
2022-02-09 18:49:52 +00:00
value = mapping ;
2020-05-20 15:14:44 +00:00
}
2022-02-09 18:49:52 +00:00
return true ;
}
2022-02-09 18:33:50 +00:00
2022-02-09 18:49:52 +00:00
protected virtual bool TryPrepareValue ( bool dump , DbConnection connection , ColumnMapper columnMapper , TableInfo table , string columnName , IEnumerable < RelationInfo > relations , ref object value )
{
return TryPrepareValue ( connection , columnMapper , relations . Single ( ) , ref value ) ;
}
2021-08-31 09:40:28 +00:00
2022-02-09 18:49:52 +00:00
protected virtual bool TryPrepareValue ( DbConnection connection , ColumnMapper columnMapper , RelationInfo relation , ref object value )
{
var mappedValue = columnMapper . GetMapping ( relation . ParentTable , relation . ParentColumn , value ) ;
if ( mappedValue ! = null )
{
value = mappedValue ;
return true ;
2020-05-20 15:14:44 +00:00
}
2022-02-09 18:49:52 +00:00
return value = = null | |
Guid . TryParse ( Convert . ToString ( value ) , out _ ) | |
int . TryParse ( Convert . ToString ( value ) , out _ ) ;
2020-05-20 15:14:44 +00:00
}
}