mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-01-03 20:49:08 +01:00
Added journaling/versioning. Not well tested yet, but seems to be working fine
This commit is contained in:
parent
0551ebb4ef
commit
523e7c5977
@ -41,6 +41,15 @@
|
||||
|
||||
/* These are used in calls to extra_sql () */
|
||||
define (VFS_SQL_SELECT, 1);
|
||||
define (VFS_SQL_DELETE, 2);
|
||||
|
||||
/* These are used in calls to add_journal (), and allow journal messages to be more standard */
|
||||
define (VFS_OPERATION_CREATED, 1);
|
||||
define (VFS_OPERATION_EDITED, 2);
|
||||
define (VFS_OPERATION_EDITED_COMMENT, 4);
|
||||
define (VFS_OPERATION_COPIED, 8);
|
||||
define (VFS_OPERATION_MOVED, 16);
|
||||
define (VFS_OPERATION_DELETED, 32);
|
||||
|
||||
/*!
|
||||
@class path_class
|
||||
@ -98,17 +107,24 @@ class vfs
|
||||
$this->now = date ("Y-m-d");
|
||||
$this->override_acl = 0;
|
||||
|
||||
/* File/dir attributes, each corresponding to a database field. Useful for use in loops */
|
||||
$this->attributes = array ("file_id", "owner_id", "createdby_id", "modifiedby_id", "created", "modified", "size", "mime_type", "deleteable", "comment", "app", "directory", "name", "link_directory", "link_name");
|
||||
/*
|
||||
File/dir attributes, each corresponding to a database field. Useful for use in loops
|
||||
If an attribute was added to the table, add it here and possibly add it to
|
||||
set_attributes ()
|
||||
*/
|
||||
|
||||
$this->attributes = array ("file_id", "owner_id", "createdby_id", "modifiedby_id", "created", "modified", "size", "mime_type", "deleteable", "comment", "app", "directory", "name", "link_directory", "link_name", "version");
|
||||
|
||||
/*
|
||||
These are stored in the MIME-type field and should normally be ignored.
|
||||
Adding a type here will ensure it is normally ignored, but you will have to
|
||||
explicitly add it to acl_check (), and to any other SELECT's in this file
|
||||
*/
|
||||
$this->meta_types = array ("journal");
|
||||
|
||||
$this->meta_types = array ("journal", "journal-deleted");
|
||||
|
||||
/* We store the linked directories in an array now, so we don't have to make the SQL call again */
|
||||
|
||||
$query = $phpgw->db->query ("SELECT directory, name, link_directory, link_name FROM phpgw_vfs WHERE link_directory != '' AND link_name != ''" . $this->extra_sql (VFS_SQL_SELECT));
|
||||
|
||||
$this->linked_dirs = array ();
|
||||
@ -212,22 +228,191 @@ class vfs
|
||||
{
|
||||
global $phpgw, $phpgw_info;
|
||||
|
||||
$sql = " AND (mime_type != ";
|
||||
if ($query_type == VFS_SQL_SELECT || $query_type == VFS_SQL_DELETE)
|
||||
{
|
||||
$sql = " AND ((";
|
||||
|
||||
reset ($this->meta_types);
|
||||
while (list ($num, $type) = each ($this->meta_types))
|
||||
{
|
||||
if ($num)
|
||||
$sql .= ", ";
|
||||
$sql .= " AND ";
|
||||
|
||||
$sql .= "'$type'";
|
||||
$sql .= "mime_type != '$type'";
|
||||
}
|
||||
|
||||
$sql .= "OR mime_type IS NULL)";
|
||||
$sql .= ") OR mime_type IS NULL)";
|
||||
}
|
||||
|
||||
return ($sql);
|
||||
}
|
||||
|
||||
/*!
|
||||
@function add_journal
|
||||
@abstract Add a journal entry after completing an operation, and increment the version number
|
||||
This function should be used internally only
|
||||
@discussion Note that $state_one and $state_two are optional, and are only used for some
|
||||
VFS_OPERATION's and not for any "custom" operation
|
||||
@param $string File or directory to add entry for
|
||||
@param $relatives Relativity array
|
||||
@param $operation The operation that was performed. Either a VFS_OPERATION define or
|
||||
a non-integer descriptive text string
|
||||
@param $state_one The first "state" of the file or directory. Can be a file name, size,
|
||||
location, whatever is appropriate for the specific operation
|
||||
@param $state_two The second "state" of the file or directory
|
||||
@param $incversion Boolean True/False. Increment the version for the file? Note that this is
|
||||
handled automatically for the VFS_OPERATION defines.
|
||||
i.e. VFS_OPERATION_EDITED would increment the version, VFS_OPERATION_COPIED
|
||||
would not
|
||||
@result Boolean True/False
|
||||
*/
|
||||
|
||||
function add_journal ($string, $relatives = array (RELATIVE_CURRENT), $operation, $state_one, $state_two, $incversion = True)
|
||||
{
|
||||
global $phpgw, $phpgw_info;
|
||||
|
||||
$p = $this->path_parts ($string, array ($relatives[0]));
|
||||
|
||||
/* We check that they have some sort of access to the file other than read */
|
||||
if (!$this->acl_check ($p->fake_full_path, array ($p->mask), PHPGW_ACL_WRITE) && !$this->acl_check ($p->fake_full_path, array ($p->mask), PHPGW_ACL_EDIT) && !$this->acl_check ($p->fake_full_path, array ($p->mask), PHPGW_ACL_DELETE))
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!$this->file_exists ($p->fake_full_path, array ($p->mask)))
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
$ls_array = $this->ls ($p->fake_full_path, array ($p->mask), False, False, True);
|
||||
$file_array = $ls_array[0];
|
||||
|
||||
$sql = "INSERT INTO phpgw_vfs (";
|
||||
$sql2 .= " VALUES (";
|
||||
|
||||
for ($i = 0; list ($attribute, $value) = each ($file_array); $i++)
|
||||
{
|
||||
if ($attribute == "file_id")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($i > 1)
|
||||
{
|
||||
$sql .= ", ";
|
||||
$sql2 .= ", ";
|
||||
}
|
||||
|
||||
if ($attribute == "mime_type")
|
||||
{
|
||||
$value = "journal";
|
||||
}
|
||||
|
||||
if ($attribute == "comment")
|
||||
{
|
||||
switch ($operation)
|
||||
{
|
||||
case VFS_OPERATION_CREATED:
|
||||
$value = "Created";
|
||||
$incversion = True;
|
||||
break;
|
||||
case VFS_OPERATION_EDITED:
|
||||
$value = "Edited";
|
||||
$incversion = True;
|
||||
break;
|
||||
case VFS_OPERATION_EDITED_COMMENT:
|
||||
$value = "Edited comment";
|
||||
$incversion = False;
|
||||
break;
|
||||
case VFS_OPERATION_COPIED:
|
||||
if (!$state_one)
|
||||
$state_one = $p->fake_full_path;
|
||||
$value = "Copied $state_one to $state_two";
|
||||
$incversion = False;
|
||||
break;
|
||||
case VFS_OPERATION_MOVED:
|
||||
if (!$state_one)
|
||||
$state_one = $p->fake_full_path;
|
||||
$value = "Moved $state_one to $state_two";
|
||||
$incversion = False;
|
||||
break;
|
||||
case VFS_OPERATION_DELETED:
|
||||
$value = "Deleted";
|
||||
$incversion = False;
|
||||
break;
|
||||
default:
|
||||
$value = $operation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Let's increment the version for the file itself. We keep the current
|
||||
version when making the journal entry, because that was the version that
|
||||
was operated on. The maximum numbers for each part in the version string:
|
||||
none.99.9.9
|
||||
*/
|
||||
if ($attribute == "version" && $incversion)
|
||||
{
|
||||
$version_parts = split ("\.", $value);
|
||||
$newnumofparts = $numofparts = count ($version_parts);
|
||||
|
||||
if ($version_parts[3] >= 9)
|
||||
{
|
||||
$version_parts[3] = 0;
|
||||
$version_parts[2]++;
|
||||
$version_parts_3_update = 1;
|
||||
}
|
||||
elseif (isset ($version_parts[3]))
|
||||
{
|
||||
$version_parts[3]++;
|
||||
}
|
||||
|
||||
if ($version_parts[2] >= 9 && $version_parts[3] == 0 && $version_parts_3_update)
|
||||
{
|
||||
$version_parts[2] = 0;
|
||||
$version_parts[1]++;
|
||||
}
|
||||
|
||||
if ($version_parts[1] > 99)
|
||||
{
|
||||
$version_parts[1] = 0;
|
||||
$version_parts[0]++;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $newnumofparts; $i++)
|
||||
{
|
||||
if (!isset ($version_parts[$i]))
|
||||
break;
|
||||
|
||||
if ($i)
|
||||
$newversion .= ".";
|
||||
|
||||
$newversion .= $version_parts[$i];
|
||||
}
|
||||
|
||||
$this->set_attributes ($p->fake_full_path, array ($p->mask), array ("version" => $newversion));
|
||||
}
|
||||
|
||||
$sql .= "$attribute";
|
||||
$sql2 .= "'$value'";
|
||||
}
|
||||
|
||||
$sql .= ")";
|
||||
$sql2 .= ")";
|
||||
|
||||
$sql .= $sql2;
|
||||
|
||||
$query = $phpgw->db->query ($sql, __LINE__, __FILE__);
|
||||
|
||||
if ($operation == VFS_OPERATION_DELETED)
|
||||
{
|
||||
$query = $phpgw->db->query ("UPDATE phpgw_vfs SET mime_type='journal-deleted' WHERE directory='$p->fake_leading_dirs_clean' AND name='$p->fake_name_clean' AND mime_type='journal'");
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*!
|
||||
@function path_parts
|
||||
@abstract take a real or fake pathname and return an array of its component parts
|
||||
@ -361,7 +546,7 @@ class vfs
|
||||
reset ($this->linked_dirs);
|
||||
while (list ($num, $link_info) = each ($this->linked_dirs))
|
||||
{
|
||||
if (ereg ("^$link_info[directory]/$link_info[name]", $rarray["fake_full_path"]))
|
||||
if (ereg ("^$link_info[directory]/$link_info[name](/|$)", $rarray["fake_full_path"]))
|
||||
{
|
||||
$rarray["real_full_path"] = ereg_replace ("^$this->basedir", "", $rarray["real_full_path"]);
|
||||
$rarray["real_full_path"] = ereg_replace ("^$link_info[directory]" . SEP . "$link_info[name]", $link_info["link_directory"] . SEP . $link_info["link_name"], $rarray["real_full_path"]);
|
||||
@ -789,6 +974,7 @@ class vfs
|
||||
fclose ($fp);
|
||||
|
||||
$this->set_attributes ($p->fake_full_path, array ($p->mask), array ("size" => filesize ($p->real_full_path)));
|
||||
|
||||
return True;
|
||||
}
|
||||
else
|
||||
@ -848,6 +1034,8 @@ class vfs
|
||||
|
||||
$this->set_attributes ($p->fake_full_path, array ($p->mask), array ("createdby_id" => $account_id, "created" => $this->now, "size" => 0, "deleteable" => "Y", "app" => $currentapp));
|
||||
$this->correct_attributes ($p->fake_full_path, array ($p->mask));
|
||||
|
||||
$this->add_journal ($p->fake_full_path, array ($p->mask), VFS_OPERATION_CREATED);
|
||||
}
|
||||
|
||||
if ($rr || $vr || $query)
|
||||
@ -924,6 +1112,8 @@ class vfs
|
||||
$phpgw->db->query ("UPDATE phpgw_vfs SET owner_id='$this->working_id', directory='$t->fake_leading_dirs_clean', name='$t->fake_name_clean' WHERE owner_id='$this->working_id' AND directory='$t->fake_leading_dirs_clean' AND name='$t->fake_name_clean'", __LINE__, __FILE__);
|
||||
|
||||
$this->set_attributes ($t->fake_full_path, array ($t->mask), array ("createdby_id" => $account_id, "created" => $this->now, "size" => $size, "mime_type" => $record["mime_type"], "deleteable" => $record["deleteable"], "comment" => $record["comment"], "app" => $record["app"]));
|
||||
|
||||
$this->add_journal ($t->fake_full_path, array ($t->mask), VFS_OPERATION_EDITED);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -933,8 +1123,6 @@ class vfs
|
||||
}
|
||||
|
||||
$this->correct_attributes ($t->fake_full_path, array ($t->mask));
|
||||
|
||||
return True;
|
||||
}
|
||||
else /* It's a directory */
|
||||
{
|
||||
@ -963,10 +1151,15 @@ class vfs
|
||||
$newdir = ereg_replace ("^$f->fake_full_path", "$t->fake_full_path", $entry["directory"]);
|
||||
$this->cp ("$entry[directory]/$entry[name]", "$newdir/$entry[name]", array ($f->mask, $t->mask));
|
||||
}
|
||||
}
|
||||
|
||||
if (!$f->outside)
|
||||
{
|
||||
$this->add_journal ($f->fake_full_path, array ($f->mask), VFS_OPERATION_COPIED, NULL, $t->fake_full_path);
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
}
|
||||
|
||||
function copy ($from, $to, $relatives = array (RELATIVE_CURRENT, RELATIVE_CURRENT))
|
||||
{
|
||||
@ -1029,6 +1222,15 @@ class vfs
|
||||
|
||||
$this->rm ($t->fake_full_path, array ($t->mask));
|
||||
|
||||
/*
|
||||
We add the journal entry now, before we delete. This way the mime_type
|
||||
field will be updated to 'journal-old' when the file is actually deleted
|
||||
*/
|
||||
if (!$f->outside)
|
||||
{
|
||||
$this->add_journal ($f->fake_full_path, array ($f->mask), VFS_OPERATION_MOVED, $f->fake_full_path, $t->fake_full_path);
|
||||
}
|
||||
|
||||
/*
|
||||
If the from file is outside, it won't have a database entry,
|
||||
so we have to touch it and find the size
|
||||
@ -1037,7 +1239,7 @@ class vfs
|
||||
{
|
||||
$size = filesize ($f->real_full_path);
|
||||
|
||||
$this->touch ($t->fake_full_path, $t->mask);
|
||||
$this->touch ($t->fake_full_path, array ($t->mask));
|
||||
$query = $phpgw->db->query ("UPDATE phpgw_vfs SET size=$size WHERE directory='$t->fake_leading_dirs_clean' AND name='$t->fake_name_clean'");
|
||||
}
|
||||
elseif (!$t->outside)
|
||||
@ -1077,6 +1279,8 @@ class vfs
|
||||
}
|
||||
}
|
||||
|
||||
$this->add_journal ($t->fake_full_path, array ($t->mask), VFS_OPERATION_MOVED, $f->fake_full_path, $t->fake_full_path);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
@ -1127,7 +1331,9 @@ class vfs
|
||||
|
||||
if ($this->file_type ($string, array ($relatives[0])) != "Directory")
|
||||
{
|
||||
$query = $phpgw->db->query ("DELETE FROM phpgw_vfs WHERE directory='$p->fake_leading_dirs_clean' AND name='$p->fake_name_clean'", __LINE__, __FILE__);
|
||||
$this->add_journal ($p->fake_full_path, array ($p->mask), VFS_OPERATION_DELETED);
|
||||
|
||||
$query = $phpgw->db->query ("DELETE FROM phpgw_vfs WHERE directory='$p->fake_leading_dirs_clean' AND name='$p->fake_name_clean'" . $this->extra_sql (VFS_SQL_DELETE), __LINE__, __FILE__);
|
||||
$rr = unlink ($p->real_full_path);
|
||||
|
||||
if ($query || $rr)
|
||||
@ -1178,7 +1384,10 @@ class vfs
|
||||
}
|
||||
|
||||
/* Last, we delete the directory itself */
|
||||
$query = $phpgw->db->query ("DELETE FROM phpgw_vfs WHERE directory='$p->fake_leading_dirs_clean' AND name='$p->fake_name_clean'", __LINE__, __FILE__);
|
||||
$this->add_journal ($p->fake_full_path, array ($p->mask), VFS_OPERATION_DELETED);
|
||||
|
||||
$query = $phpgw->db->query ("DELETE FROM phpgw_vfs WHERE directory='$p->fake_leading_dirs_clean' AND name='$p->fake_name_clean'" . $this->extra_sql (VFS_SQL_DELETE), __LINE__, __FILE__);
|
||||
|
||||
rmdir ($p->real_full_path);
|
||||
|
||||
return True;
|
||||
@ -1228,7 +1437,6 @@ class vfs
|
||||
|
||||
if (!mkdir ($p->real_full_path, 0770))
|
||||
{
|
||||
echo "$p->real_full_path<br>";
|
||||
return False;
|
||||
}
|
||||
|
||||
@ -1239,6 +1447,8 @@ class vfs
|
||||
$this->set_attributes ($p->fake_full_path, array ($p->mask), array ("createdby_id" => $account_id, "size" => 1024, "mime_type" => "Directory", "created" => $this->now, "modified" => "NULL", deleteable => "Y", "app" => $currentapp));
|
||||
|
||||
$this->correct_attributes ($p->fake_full_path, array ($p->mask));
|
||||
|
||||
$this->add_journal ($p->fake_full_path, array ($p->mask), VFS_OPERATION_CREATED);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1314,6 +1524,7 @@ class vfs
|
||||
app
|
||||
link_directory
|
||||
link_name
|
||||
version
|
||||
*/
|
||||
|
||||
function set_attributes ($file, $relatives = array (RELATIVE_CURRENT), $attributes = array ())
|
||||
@ -1345,13 +1556,18 @@ class vfs
|
||||
$ls_array = $this->ls ($p->fake_full_path, array ($p->mask), False, False, True);
|
||||
$record = $ls_array[0];
|
||||
|
||||
$attribute_names = array ("owner_id", "createdby_id", "modifiedby_id", "created", "modified", "size", "mime_type", "deleteable", "comment", "app", "link_directory", "link_name");
|
||||
$attribute_names = array ("owner_id", "createdby_id", "modifiedby_id", "created", "modified", "size", "mime_type", "deleteable", "comment", "app", "link_directory", "link_name", "version");
|
||||
|
||||
while (list ($num, $attribute) = each ($attribute_names))
|
||||
{
|
||||
if (isset ($attributes[$attribute]))
|
||||
{
|
||||
$$attribute = $attributes[$attribute];
|
||||
|
||||
if ($attribute == "comment")
|
||||
{
|
||||
$edited_comment = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1378,6 +1594,11 @@ class vfs
|
||||
|
||||
if ($query)
|
||||
{
|
||||
if ($edited_comment)
|
||||
{
|
||||
$this->add_journal ($p->fake_full_path, array ($p->mask), VFS_OPERATION_EDITED_COMMENT);
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user