init III
This commit is contained in:
505
Perl OTRS/Kernel/System/VirtualFS.pm
Normal file
505
Perl OTRS/Kernel/System/VirtualFS.pm
Normal file
@@ -0,0 +1,505 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
package Kernel::System::VirtualFS;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::Config',
|
||||
'Kernel::System::DB',
|
||||
'Kernel::System::Log',
|
||||
'Kernel::System::Main',
|
||||
);
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Kernel::System::VirtualFS - virtual filesystem lib
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
All virtual filesystem functions.
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
=head2 new()
|
||||
|
||||
Don't use the constructor directly, use the ObjectManager instead:
|
||||
|
||||
my $VirtualFSObject = $Kernel::OM->Get('Kernel::System::VirtualFS');
|
||||
|
||||
=cut
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# allocate new hash for object
|
||||
my $Self = {};
|
||||
bless( $Self, $Type );
|
||||
|
||||
# load backend
|
||||
$Self->{BackendDefault} = $Kernel::OM->Get('Kernel::Config')->Get('VirtualFS::Backend')
|
||||
|| 'Kernel::System::VirtualFS::DB';
|
||||
|
||||
if ( !$Kernel::OM->Get('Kernel::System::Main')->Require( $Self->{BackendDefault} ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$Self->{Backend}->{ $Self->{BackendDefault} } = $Self->{BackendDefault}->new();
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
=head2 Read()
|
||||
|
||||
read a file from virtual file system
|
||||
|
||||
my %File = $VirtualFSObject->Read(
|
||||
Filename => '/Object/some/name.txt',
|
||||
Mode => 'utf8',
|
||||
|
||||
# optional
|
||||
DisableWarnings => 1,
|
||||
);
|
||||
|
||||
returns
|
||||
|
||||
my %File = (
|
||||
Content => $ContentSCALAR,
|
||||
|
||||
# preferences data
|
||||
Preferences => {
|
||||
|
||||
# generated automatically
|
||||
FilesizeRaw => 12345,
|
||||
|
||||
# optional
|
||||
ContentType => 'text/plain',
|
||||
ContentID => '<some_id@example.com>',
|
||||
ContentAlternative => 1,
|
||||
SomeCustomParams => 'with our own value',
|
||||
},
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub Read {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
for (qw(Filename Mode)) {
|
||||
if ( !$Param{$_} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $_!"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# lookup
|
||||
my ( $FileID, $BackendKey, $Backend ) = $Self->_FileLookup( $Param{Filename} );
|
||||
if ( !$BackendKey ) {
|
||||
if ( !$Param{DisableWarnings} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "No such file '$Param{Filename}'!",
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
# get database object
|
||||
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
||||
|
||||
# get preferences
|
||||
my %Preferences;
|
||||
return if !$DBObject->Prepare(
|
||||
SQL => 'SELECT preferences_key, preferences_value FROM '
|
||||
. 'virtual_fs_preferences WHERE virtual_fs_id = ?',
|
||||
Bind => [ \$FileID ],
|
||||
);
|
||||
|
||||
while ( my @Row = $DBObject->FetchrowArray() ) {
|
||||
$Preferences{ $Row[0] } = $Row[1];
|
||||
}
|
||||
|
||||
# load backend (if not default)
|
||||
if ( !$Self->{Backend}->{$Backend} ) {
|
||||
|
||||
return if !$Kernel::OM->Get('Kernel::System::Main')->Require($Backend);
|
||||
|
||||
$Self->{Backend}->{$Backend} = $Backend->new();
|
||||
|
||||
return if !$Self->{Backend}->{$Backend};
|
||||
}
|
||||
|
||||
# get file
|
||||
my $Content = $Self->{Backend}->{$Backend}->Read(
|
||||
%Param,
|
||||
BackendKey => $BackendKey,
|
||||
);
|
||||
return if !$Content;
|
||||
|
||||
return (
|
||||
Preferences => \%Preferences,
|
||||
Content => $Content,
|
||||
);
|
||||
}
|
||||
|
||||
=head2 Write()
|
||||
|
||||
write a file to virtual file system
|
||||
|
||||
my $Success = $VirtualFSObject->Write(
|
||||
Content => \$Content,
|
||||
Filename => '/Object/SomeFileName.txt',
|
||||
Mode => 'binary' # (binary|utf8)
|
||||
|
||||
# optional, preferences data
|
||||
Preferences => {
|
||||
ContentType => 'text/plain',
|
||||
ContentID => '<some_id@example.com>',
|
||||
ContentAlternative => 1,
|
||||
SomeCustomParams => 'with our own value',
|
||||
},
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub Write {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
for (qw(Filename Content Mode)) {
|
||||
if ( !$Param{$_} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $_!"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# lookup
|
||||
my ($FileID) = $Self->_FileLookup( $Param{Filename} );
|
||||
if ($FileID) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "File already exists '$Param{Filename}'!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
# get database object
|
||||
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
||||
|
||||
# insert
|
||||
return if !$DBObject->Do(
|
||||
SQL => 'INSERT INTO virtual_fs (filename, backend_key, backend, create_time)'
|
||||
. ' VALUES ( ?, \'TMP\', ?, current_timestamp)',
|
||||
Bind => [ \$Param{Filename}, \$Self->{BackendDefault} ],
|
||||
);
|
||||
|
||||
($FileID) = $Self->_FileLookup( $Param{Filename} );
|
||||
|
||||
if ( !$FileID ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Unable to store '$Param{Filename}'!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
# size calculation
|
||||
$Param{Preferences}->{FilesizeRaw} = bytes::length( ${ $Param{Content} } );
|
||||
|
||||
# insert preferences
|
||||
for my $Key ( sort keys %{ $Param{Preferences} } ) {
|
||||
return if !$DBObject->Do(
|
||||
SQL => 'INSERT INTO virtual_fs_preferences '
|
||||
. '(virtual_fs_id, preferences_key, preferences_value) VALUES ( ?, ?, ?)',
|
||||
Bind => [ \$FileID, \$Key, \$Param{Preferences}->{$Key} ],
|
||||
);
|
||||
}
|
||||
|
||||
# store file
|
||||
my $BackendKey = $Self->{Backend}->{ $Self->{BackendDefault} }->Write(%Param);
|
||||
return if !$BackendKey;
|
||||
|
||||
# update backend key
|
||||
return if !$DBObject->Do(
|
||||
SQL => 'UPDATE virtual_fs SET backend_key = ? WHERE id = ?',
|
||||
Bind => [ \$BackendKey, \$FileID ],
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 Delete()
|
||||
|
||||
delete a file from virtual file system
|
||||
|
||||
my $Success = $VirtualFSObject->Delete(
|
||||
Filename => '/Object/SomeFileName.txt',
|
||||
|
||||
# optional
|
||||
DisableWarnings => 1,
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub Delete {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
for (qw(Filename)) {
|
||||
if ( !$Param{$_} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $_!"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# lookup
|
||||
my ( $FileID, $BackendKey, $Backend ) = $Self->_FileLookup( $Param{Filename} );
|
||||
if ( !$FileID ) {
|
||||
if ( !$Param{DisableWarnings} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "No such file '$Param{Filename}'!",
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
# load backend (if not default)
|
||||
if ( !$Self->{Backend}->{$Backend} ) {
|
||||
|
||||
return if !$Kernel::OM->Get('Kernel::System::Main')->Require($Backend);
|
||||
|
||||
$Self->{Backend}->{$Backend} = $Backend->new();
|
||||
|
||||
return if !$Self->{Backend}->{$Backend};
|
||||
}
|
||||
|
||||
# get database object
|
||||
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
||||
|
||||
# delete preferences
|
||||
return if !$DBObject->Do(
|
||||
SQL => 'DELETE FROM virtual_fs_preferences WHERE virtual_fs_id = ?',
|
||||
Bind => [ \$FileID ],
|
||||
);
|
||||
|
||||
# delete
|
||||
return if !$DBObject->Do(
|
||||
SQL => 'DELETE FROM virtual_fs WHERE id = ?',
|
||||
Bind => [ \$FileID ],
|
||||
);
|
||||
|
||||
# delete file
|
||||
return $Self->{Backend}->{$Backend}->Delete(
|
||||
%Param,
|
||||
BackendKey => $BackendKey,
|
||||
);
|
||||
}
|
||||
|
||||
=head2 Find()
|
||||
|
||||
find files in virtual file system
|
||||
|
||||
only for file name
|
||||
|
||||
my @List = $VirtualFSObject->Find(
|
||||
Filename => '/Object/some_what/*.txt',
|
||||
);
|
||||
|
||||
only for preferences
|
||||
|
||||
my @List = $VirtualFSObject->Find(
|
||||
Preferences => {
|
||||
ContentType => 'text/plain',
|
||||
},
|
||||
);
|
||||
|
||||
for file name and for preferences
|
||||
|
||||
my @List = $VirtualFSObject->Find(
|
||||
Filename => '/Object/some_what/*.txt',
|
||||
Preferences => {
|
||||
ContentType => 'text/plain',
|
||||
},
|
||||
);
|
||||
|
||||
Returns:
|
||||
|
||||
my @List = (
|
||||
'/Object/some/file.txt',
|
||||
'/Object/my.pdf',
|
||||
);
|
||||
|
||||
=cut
|
||||
|
||||
sub Find {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
if ( !$Param{Filename} && !$Param{Preferences} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => 'Need Filename or/and Preferences!',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
# get database object
|
||||
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
||||
|
||||
# get like escape string needed for some databases (e.g. oracle)
|
||||
my $LikeEscapeString = $DBObject->GetDatabaseFunction('LikeEscapeString');
|
||||
|
||||
# prepare file name search
|
||||
my $SQLResult = 'vfs.filename';
|
||||
my $SQLTable = 'virtual_fs vfs ';
|
||||
my $SQLWhere = '';
|
||||
my @SQLBind;
|
||||
if ( $Param{Filename} ) {
|
||||
my $Like = $Param{Filename};
|
||||
$Like =~ s/\*/%/g;
|
||||
$Like = $DBObject->Quote( $Like, 'Like' );
|
||||
$SQLWhere .= "vfs.filename LIKE '$Like' $LikeEscapeString";
|
||||
}
|
||||
|
||||
# prepare preferences search
|
||||
if ( $Param{Preferences} ) {
|
||||
$SQLResult = 'vfs.filename, vfsp.preferences_key, vfsp.preferences_value';
|
||||
$SQLTable .= ', virtual_fs_preferences vfsp';
|
||||
if ($SQLWhere) {
|
||||
$SQLWhere .= ' AND ';
|
||||
}
|
||||
$SQLWhere .= 'vfs.id = vfsp.virtual_fs_id ';
|
||||
my $SQL = '';
|
||||
for my $Key ( sort keys %{ $Param{Preferences} } ) {
|
||||
if ($SQL) {
|
||||
$SQL .= ' OR ';
|
||||
}
|
||||
$SQL .= '(vfsp.preferences_key = ? AND ';
|
||||
push @SQLBind, \$Key;
|
||||
|
||||
my $Value = $Param{Preferences}->{$Key};
|
||||
if ( $Value =~ /(\*|\%)/ ) {
|
||||
$Value =~ s/\*/%/g;
|
||||
$Value = $DBObject->Quote( $Value, 'Like' );
|
||||
$SQL .= "vfsp.preferences_value LIKE '$Value' $LikeEscapeString";
|
||||
}
|
||||
else {
|
||||
$SQL .= 'vfsp.preferences_value = ?';
|
||||
push @SQLBind, \$Value;
|
||||
}
|
||||
$SQL .= ')';
|
||||
}
|
||||
|
||||
$SQLWhere .= " AND ($SQL)";
|
||||
}
|
||||
|
||||
# search
|
||||
return if !$DBObject->Prepare(
|
||||
SQL => "SELECT $SQLResult FROM $SQLTable WHERE $SQLWhere",
|
||||
Bind => \@SQLBind,
|
||||
);
|
||||
my @List;
|
||||
my %Result;
|
||||
while ( my @Row = $DBObject->FetchrowArray() ) {
|
||||
if ( $Param{Preferences} ) {
|
||||
for my $Key ( sort keys %{ $Param{Preferences} } ) {
|
||||
$Result{ $Row[0] }->{ $Row[1] } = $Row[2];
|
||||
}
|
||||
}
|
||||
else {
|
||||
push @List, $Row[0];
|
||||
}
|
||||
}
|
||||
|
||||
# check preferences search
|
||||
if ( $Param{Preferences} ) {
|
||||
FILE:
|
||||
for my $File ( sort keys %Result ) {
|
||||
for my $Key ( sort keys %{ $Param{Preferences} } ) {
|
||||
my $DB = $Result{$File}->{$Key};
|
||||
my $Given = $Param{Preferences}->{$Key};
|
||||
next FILE if defined $DB && !defined $Given;
|
||||
next FILE if !defined $DB && defined $Given;
|
||||
if ( $Given =~ /\*/ ) {
|
||||
$Given =~ s/\*/.\*/g;
|
||||
$Given =~ s/\//\\\//g;
|
||||
next FILE if $DB !~ /$Given/;
|
||||
}
|
||||
else {
|
||||
next FILE if $DB ne $Given;
|
||||
}
|
||||
}
|
||||
push @List, $File;
|
||||
}
|
||||
}
|
||||
|
||||
# return result
|
||||
return @List;
|
||||
}
|
||||
|
||||
=begin Internal:
|
||||
|
||||
returns internal meta information, unique file id, where and with what arguments the
|
||||
file is stored
|
||||
|
||||
my ( $FileID, $BackendKey, $Backend ) = $Self->_FileLookup( '/Object/SomeFile.txt' );
|
||||
|
||||
=cut
|
||||
|
||||
sub _FileLookup {
|
||||
my ( $Self, $Filename ) = @_;
|
||||
|
||||
# get database object
|
||||
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
||||
|
||||
# lookup
|
||||
return if !$DBObject->Prepare(
|
||||
SQL => 'SELECT id, backend_key, backend FROM virtual_fs WHERE filename = ?',
|
||||
Bind => [ \$Filename ],
|
||||
);
|
||||
|
||||
my $FileID;
|
||||
my $BackendKey;
|
||||
my $Backend;
|
||||
while ( my @Row = $DBObject->FetchrowArray() ) {
|
||||
$FileID = $Row[0];
|
||||
$BackendKey = $Row[1];
|
||||
$Backend = $Row[2];
|
||||
}
|
||||
|
||||
return ( $FileID, $BackendKey, $Backend );
|
||||
}
|
||||
|
||||
=end Internal:
|
||||
|
||||
=cut
|
||||
|
||||
1;
|
||||
|
||||
=head1 TERMS AND CONDITIONS
|
||||
|
||||
This software is part of the OTRS project (L<https://otrs.org/>).
|
||||
|
||||
This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
the enclosed file COPYING for license information (GPL). If you
|
||||
did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user