2019-05-15 14:56:09 +00:00
/ *
*
* ( c ) Copyright Ascensio System Limited 2010 - 2018
*
* This program is freeware . You can redistribute it and / or modify it under the terms of the GNU
* General Public License ( GPL ) version 3 as published by the Free Software Foundation ( https : //www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7 ( a ) of the GNU GPL 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 more details , see GNU GPL at https : //www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales @onlyoffice . com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices , as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3 ( b ) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software . If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons , you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute .
* Pursuant to Section 7 § 3 ( e ) we decline to grant you any rights under trademark law for use of our trademarks .
*
* /
namespace TMResourceData
{
public class DBResourceManager : ResourceManager
{
2022-01-19 14:16:15 +00:00
public static readonly bool WhiteLableEnabled = false ;
2022-02-14 21:02:57 +00:00
private readonly ConcurrentDictionary < string , ResourceSet > _resourceSets = new ConcurrentDictionary < string , ResourceSet > ( ) ;
2019-05-15 14:56:09 +00:00
public DBResourceManager ( string filename , Assembly assembly )
: base ( filename , assembly )
{
2020-02-17 08:58:14 +00:00
}
2019-12-16 09:30:01 +00:00
2020-02-17 08:58:14 +00:00
public DBResourceManager (
IConfiguration configuration ,
IOptionsMonitor < ILog > option ,
DbContextManager < ResourceDbContext > dbContext ,
string filename ,
2019-12-16 09:30:01 +00:00
Assembly assembly )
2019-10-09 10:09:54 +00:00
: base ( filename , assembly )
2019-11-06 15:03:09 +00:00
{
2022-02-14 21:02:57 +00:00
_configuration = configuration ;
_option = option ;
_dbContext = dbContext ;
2019-10-09 10:09:54 +00:00
}
2019-05-15 14:56:09 +00:00
2019-11-06 15:03:09 +00:00
public static void PatchAssemblies ( IOptionsMonitor < ILog > option )
2019-05-15 14:56:09 +00:00
{
2019-10-22 11:21:44 +00:00
AppDomain . CurrentDomain . AssemblyLoad + = ( _ , a ) = > PatchAssembly ( option , a . LoadedAssembly ) ;
Array . ForEach ( AppDomain . CurrentDomain . GetAssemblies ( ) , a = > PatchAssembly ( option , a ) ) ;
2019-05-15 14:56:09 +00:00
}
2019-11-06 15:03:09 +00:00
public static void PatchAssembly ( IOptionsMonitor < ILog > option , Assembly a , bool onlyAsc = true )
{
var log = option . CurrentValue ;
2019-10-22 11:21:44 +00:00
2019-05-15 14:56:09 +00:00
if ( ! onlyAsc | | Accept ( a ) )
{
2022-02-14 21:02:57 +00:00
var types = Array . Empty < Type > ( ) ;
2019-05-15 14:56:09 +00:00
try
{
types = a . GetTypes ( ) ;
}
catch ( ReflectionTypeLoadException rtle )
{
log . WarnFormat ( "Can not GetTypes() from assembly {0}, try GetExportedTypes(), error: {1}" , a . FullName , rtle . Message ) ;
foreach ( var e in rtle . LoaderExceptions )
{
log . Info ( e . Message ) ;
}
try
{
types = a . GetExportedTypes ( ) ;
}
catch ( Exception err )
{
log . ErrorFormat ( "Can not GetExportedTypes() from assembly {0}: {1}" , a . FullName , err . Message ) ;
}
}
foreach ( var type in types )
{
var prop = type . GetProperty ( "ResourceManager" , BindingFlags . Static | BindingFlags . NonPublic | BindingFlags . Public ) ;
if ( prop ! = null )
{
var rm = ( ResourceManager ) prop . GetValue ( type ) ;
if ( ! ( rm is DBResourceManager ) )
{
var dbrm = new DBResourceManager ( rm . BaseName , a ) ;
2020-10-12 19:39:23 +00:00
type . InvokeMember ( "resourceMan" , BindingFlags . Static | BindingFlags . NonPublic | BindingFlags . SetField , null , type , new object [ ] { dbrm } ) ;
2019-05-15 14:56:09 +00:00
}
}
}
}
}
private static bool Accept ( Assembly a )
{
2022-02-14 21:02:57 +00:00
var n = a . GetName ( ) . Name ;
2019-05-15 14:56:09 +00:00
2022-02-14 21:02:57 +00:00
return ( n . StartsWith ( "ASC." ) | | n . StartsWith ( "App_GlobalResources" ) ) & & a . GetManifestResourceNames ( ) . Length > 0 ;
2019-11-06 15:03:09 +00:00
}
2022-02-14 21:02:57 +00:00
public override Type ResourceSetType = > typeof ( DBResourceSet ) ;
private readonly IConfiguration _configuration ;
private readonly IOptionsMonitor < ILog > _option ;
private readonly DbContextManager < ResourceDbContext > _dbContext ;
2020-02-17 08:58:14 +00:00
2019-05-15 14:56:09 +00:00
protected override ResourceSet InternalGetResourceSet ( CultureInfo culture , bool createIfNotExists , bool tryParents )
{
2022-02-14 21:02:57 +00:00
_resourceSets . TryGetValue ( culture . Name , out var set ) ;
2019-05-15 14:56:09 +00:00
if ( set = = null )
{
var invariant = culture = = CultureInfo . InvariantCulture ? base . InternalGetResourceSet ( CultureInfo . InvariantCulture , true , true ) : null ;
2022-02-14 21:02:57 +00:00
set = new DBResourceSet ( _configuration , _option , _dbContext , invariant , culture , BaseName ) ;
_resourceSets . AddOrUpdate ( culture . Name , set , ( k , v ) = > set ) ;
}
2019-05-15 14:56:09 +00:00
return set ;
}
class DBResourceSet : ResourceSet
{
2022-02-14 21:02:57 +00:00
private const string NeutralCulture = "Neutral" ;
2019-05-15 14:56:09 +00:00
2022-02-14 21:02:57 +00:00
private readonly TimeSpan _cacheTimeout = TimeSpan . FromMinutes ( 120 ) ; // for performance
private readonly object _locker = new object ( ) ;
private readonly MemoryCache _cache ;
private readonly ResourceSet _invariant ;
private readonly string _culture ;
private readonly string _fileName ;
private readonly ILog _logger ;
private readonly DbContextManager < ResourceDbContext > _dbContext ;
2020-02-17 08:58:14 +00:00
public DBResourceSet (
IConfiguration configuration ,
IOptionsMonitor < ILog > option ,
DbContextManager < ResourceDbContext > dbContext ,
ResourceSet invariant ,
CultureInfo culture ,
2019-12-16 09:30:01 +00:00
string filename )
2019-05-15 14:56:09 +00:00
{
if ( culture = = null )
{
2022-01-24 10:49:00 +00:00
throw new ArgumentNullException ( nameof ( culture ) ) ;
2019-05-15 14:56:09 +00:00
}
if ( string . IsNullOrEmpty ( filename ) )
{
2022-01-24 10:49:00 +00:00
throw new ArgumentNullException ( nameof ( filename ) ) ;
2019-11-06 15:03:09 +00:00
}
2022-02-14 21:02:57 +00:00
_dbContext = dbContext ;
_logger = option . CurrentValue ;
2019-11-06 15:03:09 +00:00
2019-10-09 10:09:54 +00:00
try
{
2022-02-14 21:02:57 +00:00
var defaultValue = ( ( int ) _cacheTimeout . TotalMinutes ) . ToString ( ) ;
_cacheTimeout = TimeSpan . FromMinutes ( Convert . ToInt32 ( configuration [ "resources:cache-timeout" ] ? ? defaultValue ) ) ;
2019-05-15 14:56:09 +00:00
}
2019-10-09 10:09:54 +00:00
catch ( Exception err )
{
2022-02-14 21:02:57 +00:00
_logger . Error ( err ) ;
2019-11-06 15:03:09 +00:00
}
2022-02-14 21:02:57 +00:00
_invariant = invariant ;
_culture = invariant ! = null ? NeutralCulture : culture . Name ;
_fileName = filename . Split ( '.' ) . Last ( ) + ".resx" ;
_cache = MemoryCache . Default ;
2019-05-15 14:56:09 +00:00
}
public override string GetString ( string name , bool ignoreCase )
{
var result = ( string ) null ;
try
{
var dic = GetResources ( ) ;
2020-10-12 19:39:23 +00:00
dic . TryGetValue ( name , out result ) ;
2019-05-15 14:56:09 +00:00
}
catch ( Exception err )
{
2022-02-14 21:02:57 +00:00
_logger . ErrorFormat ( "Can not get resource from {0} for {1}: GetString({2}), {3}" , _fileName , _culture , name , err ) ;
2019-05-15 14:56:09 +00:00
}
2022-02-14 21:02:57 +00:00
if ( _invariant ! = null & & result = = null )
2019-05-15 14:56:09 +00:00
{
2022-02-14 21:02:57 +00:00
result = _invariant . GetString ( name , ignoreCase ) ;
2019-05-15 14:56:09 +00:00
}
return result ;
}
public override IDictionaryEnumerator GetEnumerator ( )
{
var result = new Hashtable ( ) ;
2022-02-14 21:02:57 +00:00
if ( _invariant ! = null )
2019-05-15 14:56:09 +00:00
{
2022-02-14 21:02:57 +00:00
foreach ( DictionaryEntry e in _invariant )
2019-05-15 14:56:09 +00:00
{
result [ e . Key ] = e . Value ;
}
}
try
{
var dic = GetResources ( ) ;
foreach ( var e in dic )
{
result [ e . Key ] = e . Value ;
}
}
catch ( Exception err )
{
2022-02-14 21:02:57 +00:00
_logger . Error ( err ) ;
}
2019-05-15 14:56:09 +00:00
return result . GetEnumerator ( ) ;
}
private Dictionary < string , string > GetResources ( )
{
2022-02-14 21:02:57 +00:00
var key = $"{_fileName}/{_culture}" ;
if ( ! ( _cache . Get ( key ) is Dictionary < string , string > dic ) )
2019-05-15 14:56:09 +00:00
{
2022-02-14 21:02:57 +00:00
lock ( _locker )
2019-05-15 14:56:09 +00:00
{
2022-02-14 21:02:57 +00:00
dic = _cache . Get ( key ) as Dictionary < string , string > ;
2019-05-15 14:56:09 +00:00
if ( dic = = null )
{
2022-02-14 21:02:57 +00:00
var policy = _cacheTimeout = = TimeSpan . Zero ? null : new CacheItemPolicy ( ) { AbsoluteExpiration = DateTimeOffset . Now . Add ( _cacheTimeout ) } ;
dic = LoadResourceSet ( _fileName , _culture ) ;
_cache . Set ( key , dic , policy ) ;
2019-05-15 14:56:09 +00:00
}
}
2022-02-14 21:02:57 +00:00
}
2019-05-15 14:56:09 +00:00
return dic ;
}
2019-10-10 08:52:21 +00:00
private Dictionary < string , string > LoadResourceSet ( string filename , string culture )
2020-02-17 08:58:14 +00:00
{
2022-02-14 21:02:57 +00:00
using var context = _dbContext . Get ( "tmresource" ) ;
2020-02-17 08:58:14 +00:00
var q = context . ResData
. Where ( r = > r . CultureTitle = = culture )
. Join ( context . ResFiles , r = > r . FileId , a = > a . Id , ( d , f ) = > new { data = d , files = f } )
. Where ( r = > r . files . ResName = = filename ) ;
2019-12-16 09:30:01 +00:00
return q
. ToDictionary ( r = > r . data . Title , r = > r . data . TextValue , StringComparer . InvariantCultureIgnoreCase ) ;
2019-05-15 14:56:09 +00:00
}
}
}
2020-10-19 15:53:15 +00:00
[Singletone]
2019-10-22 11:21:44 +00:00
public class WhiteLabelHelper
2019-05-15 14:56:09 +00:00
{
2022-02-14 21:02:57 +00:00
private readonly ILog _logger ;
private readonly ConcurrentDictionary < int , string > _whiteLabelDictionary ;
2022-01-21 11:02:17 +00:00
public string DefaultLogoText { get ; set ; }
2019-11-06 15:03:09 +00:00
2022-02-14 21:02:57 +00:00
private readonly IConfiguration _configuration ;
2019-11-06 15:03:09 +00:00
public WhiteLabelHelper ( IConfiguration configuration , IOptionsMonitor < ILog > option )
{
2022-02-14 21:02:57 +00:00
_logger = option . Get ( "ASC.Resources" ) ;
_whiteLabelDictionary = new ConcurrentDictionary < int , string > ( ) ;
DefaultLogoText = string . Empty ;
_configuration = configuration ;
2019-10-22 11:21:44 +00:00
}
2019-05-15 14:56:09 +00:00
2019-10-22 11:21:44 +00:00
public void SetNewText ( int tenantId , string newText )
2019-05-15 14:56:09 +00:00
{
try
{
2022-02-14 21:02:57 +00:00
_whiteLabelDictionary . AddOrUpdate ( tenantId , r = > newText , ( i , s ) = > newText ) ;
2019-05-15 14:56:09 +00:00
}
catch ( Exception e )
{
2022-02-14 21:02:57 +00:00
_logger . Error ( "SetNewText" , e ) ;
2019-05-15 14:56:09 +00:00
}
}
2019-10-22 11:21:44 +00:00
public void RestoreOldText ( int tenantId )
2019-05-15 14:56:09 +00:00
{
try
{
2022-02-14 21:02:57 +00:00
_whiteLabelDictionary . TryRemove ( tenantId , out var text ) ;
2019-05-15 14:56:09 +00:00
}
catch ( Exception e )
{
2022-02-14 21:02:57 +00:00
_logger . Error ( "RestoreOldText" , e ) ;
2019-05-15 14:56:09 +00:00
}
}
2019-10-22 11:21:44 +00:00
internal string ReplaceLogo ( TenantManager tenantManager , IHttpContextAccessor httpContextAccessor , string resourceName , string resourceValue )
2019-05-15 14:56:09 +00:00
{
if ( string . IsNullOrEmpty ( resourceValue ) )
{
return resourceValue ;
2019-11-06 15:03:09 +00:00
}
if ( ! DBResourceManager . WhiteLableEnabled )
{
return resourceValue ;
}
2019-05-15 14:56:09 +00:00
2019-10-18 08:48:27 +00:00
if ( httpContextAccessor . HttpContext ! = null ) //if in Notify Service or other process without HttpContext
2019-05-15 14:56:09 +00:00
{
try
{
2019-10-11 08:57:35 +00:00
var tenant = tenantManager . GetCurrentTenant ( false ) ;
2022-02-14 21:02:57 +00:00
if ( tenant = = null )
{
return resourceValue ;
}
2022-02-15 10:30:05 +00:00
if ( _whiteLabelDictionary . TryGetValue ( tenant . Id , out var newText ) )
2019-05-15 14:56:09 +00:00
{
var newTextReplacement = newText ;
2022-01-13 12:53:57 +00:00
if ( resourceValue . IndexOf ( '<' ) > = 0 & & resourceValue . IndexOf ( '>' ) > = 0 | | resourceName . StartsWith ( "pattern_" ) )
2019-05-15 14:56:09 +00:00
{
newTextReplacement = HttpUtility . HtmlEncode ( newTextReplacement ) ;
}
if ( resourceValue . Contains ( "{0" ) )
{
//Hack for string which used in string.Format
newTextReplacement = newTextReplacement . Replace ( "{" , "{{" ) . Replace ( "}" , "}}" ) ;
2019-11-06 15:03:09 +00:00
}
2022-02-14 21:02:57 +00:00
var replPattern = _configuration [ "resources:whitelabel-text.replacement.pattern" ] ? ? "(?<=[^@/\\\\]|^)({0})(?!\\.com)" ;
2019-05-15 14:56:09 +00:00
var pattern = string . Format ( replPattern , DefaultLogoText ) ;
//Hack for resource strings with mails looked like ...@onlyoffice... or with website http://www.onlyoffice.com link or with the https://www.facebook.com/pages/OnlyOffice/833032526736775
return Regex . Replace ( resourceValue , pattern , newTextReplacement , RegexOptions . IgnoreCase ) . Replace ( "™" , "" ) ;
}
}
catch ( Exception e )
{
2022-02-14 21:02:57 +00:00
_logger . Error ( "ReplaceLogo" , e ) ;
2019-05-15 14:56:09 +00:00
}
}
return resourceValue ;
}
2019-11-06 15:03:09 +00:00
}
2019-05-15 14:56:09 +00:00
}