diff options
-rw-r--r-- | apps/files_versions/appinfo/app.php | 19 | ||||
-rw-r--r-- | apps/files_versions/appinfo/info.xml | 12 | ||||
-rw-r--r-- | apps/files_versions/appinfo/version | 1 | ||||
-rw-r--r-- | apps/files_versions/css/versions.css | 2 | ||||
-rw-r--r-- | apps/files_versions/history.php | 60 | ||||
-rw-r--r-- | apps/files_versions/js/versions.js | 2 | ||||
-rw-r--r-- | apps/files_versions/settings.php | 10 | ||||
-rw-r--r-- | apps/files_versions/templates/history.php | 18 | ||||
-rw-r--r-- | apps/files_versions/templates/settings.php | 7 | ||||
-rw-r--r-- | apps/files_versions/versions.php | 216 |
10 files changed, 347 insertions, 0 deletions
diff --git a/apps/files_versions/appinfo/app.php b/apps/files_versions/appinfo/app.php new file mode 100644 index 00000000000..6e7a803252e --- /dev/null +++ b/apps/files_versions/appinfo/app.php @@ -0,0 +1,19 @@ +<?php + +require_once('apps/files_versions/versions.php'); + +// Add an entry in the app list +OC_App::register( array( + 'order' => 10, + 'id' => 'files_versions', + 'name' => 'Versioning' )); + +OC_APP::registerAdmin('files_versions', 'settings'); + +// Listen to write signals +OC_Hook::connect(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, "OCA_Versions\Storage", "write_hook"); + + + + +?> diff --git a/apps/files_versions/appinfo/info.xml b/apps/files_versions/appinfo/info.xml new file mode 100644 index 00000000000..9936a2ad8b2 --- /dev/null +++ b/apps/files_versions/appinfo/info.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<info> + <id>files_versions</id> + <name>Versions</name> + <licence>AGPL</licence> + <author>Frank Karlitschek</author> + <require>3</require> + <description>Versioning of files</description> + <types> + <filesystem/> + </types> +</info> diff --git a/apps/files_versions/appinfo/version b/apps/files_versions/appinfo/version new file mode 100644 index 00000000000..afaf360d37f --- /dev/null +++ b/apps/files_versions/appinfo/version @@ -0,0 +1 @@ +1.0.0
\ No newline at end of file diff --git a/apps/files_versions/css/versions.css b/apps/files_versions/css/versions.css new file mode 100644 index 00000000000..139597f9cb0 --- /dev/null +++ b/apps/files_versions/css/versions.css @@ -0,0 +1,2 @@ + + diff --git a/apps/files_versions/history.php b/apps/files_versions/history.php new file mode 100644 index 00000000000..6c7626ca4ed --- /dev/null +++ b/apps/files_versions/history.php @@ -0,0 +1,60 @@ +<?php + +/** + * ownCloud - History page of the Versions App + * + * @author Frank Karlitschek + * @copyright 2011 Frank Karlitschek karlitschek@kde.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + */ +require_once('../../lib/base.php'); + +OC_Util::checkLoggedIn(); + +if (isset($_GET['path'])) { + + $path = $_GET['path']; + $path = strip_tags($path); + + // roll back to old version if button clicked + if(isset($_GET['revert'])) { + \OCA_Versions\Storage::rollback($path,$_GET['revert']); + } + + // show the history only if there is something to show + if(OCA_Versions\Storage::isversioned($path)) { + + $count=5; //show the newest revisions + $versions=OCA_Versions\Storage::getversions($path,$count); + + $tmpl = new OC_Template('files_versions', 'history', 'user'); + $tmpl->assign('path', $path); + $tmpl->assign('versions', array_reverse($versions)); + $tmpl->printPage(); + }else{ + $tmpl = new OC_Template('files_versions', 'history', 'user'); + $tmpl->assign('path', $path); + $tmpl->assign('message', 'No old versions available'); + $tmpl->printPage(); + } +}else{ + $tmpl = new OC_Template('files_versions', 'history', 'user'); + $tmpl->assign('message', 'No path specified'); + $tmpl->printPage(); +} + + +?> diff --git a/apps/files_versions/js/versions.js b/apps/files_versions/js/versions.js new file mode 100644 index 00000000000..139597f9cb0 --- /dev/null +++ b/apps/files_versions/js/versions.js @@ -0,0 +1,2 @@ + + diff --git a/apps/files_versions/settings.php b/apps/files_versions/settings.php new file mode 100644 index 00000000000..eb154d3edd3 --- /dev/null +++ b/apps/files_versions/settings.php @@ -0,0 +1,10 @@ +<?php + +OC_Util::checkAdminUser(); + +OC_Util::addScript( 'files_versions', 'versions' ); + +$tmpl = new OC_Template( 'files_versions', 'settings'); + +return $tmpl->fetchPage(); +?> diff --git a/apps/files_versions/templates/history.php b/apps/files_versions/templates/history.php new file mode 100644 index 00000000000..1b3de9ce77c --- /dev/null +++ b/apps/files_versions/templates/history.php @@ -0,0 +1,18 @@ +<?php + if(isset($_['message'])){ + + + if(isset($_['path'])) echo('<strong>File: '.$_['path']).'</strong><br>'; + echo('<strong>'.$_['message']).'</strong><br>'; + + }else{ + + echo('<strong>Versions of '.$_['path']).'</strong><br>'; + echo('<p><em>You can click on the revert button to revert to the specific verson.</em></p><br />'); + foreach ($_['versions'] as $v){ + echo(' '.OC_Util::formatDate($v).' <a href="history.php?path='.urlencode($_['path']).'&revert='.$v.'" class="button">revert</a><br /><br />'); + } + + } + +?> diff --git a/apps/files_versions/templates/settings.php b/apps/files_versions/templates/settings.php new file mode 100644 index 00000000000..8c8def94429 --- /dev/null +++ b/apps/files_versions/templates/settings.php @@ -0,0 +1,7 @@ +<form id="external"> + <fieldset class="personalblock"> + <strong>Versions</strong><br /> + + Configuration goes here... + </fieldset> +</form> diff --git a/apps/files_versions/versions.php b/apps/files_versions/versions.php new file mode 100644 index 00000000000..156a4f59c73 --- /dev/null +++ b/apps/files_versions/versions.php @@ -0,0 +1,216 @@ +<?php +/** + * Copyright (c) 2012 Frank Karlitschek <frank@owncloud.org> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Versions + * + * A class to handle the versioning of files. + */ + +namespace OCA_Versions; + +class Storage { + + + // config.php configuration: + // - files_versions + // - files_versionsfolder + // - files_versionsblacklist + // - files_versionsmaxfilesize + // - files_versionsinterval + // - files_versionmaxversions + // + // todo: + // - port to oc_filesystem to enable network transparency + // - check if it works well together with encryption + // - do configuration web interface + // - implement expire all function. And find a place to call it ;-) + // - add transparent compression. first test if it´s worth it. + + const DEFAULTENABLED=true; + const DEFAULTFOLDER='versions'; + const DEFAULTBLACKLIST='avi mp3 mpg mp4'; + const DEFAULTMAXFILESIZE=1048576; // 10MB + const DEFAULTMININTERVAL=300; // 5 min + const DEFAULTMAXVERSIONS=50; + + /** + * init the versioning and create the versions folder. + */ + public static function init() { + if(\OC_Config::getValue('files_versions', Storage::DEFAULTENABLED)=='true') { + // create versions folder + $foldername=\OC_Config::getValue('datadirectory').'/'. \OC_User::getUser() .'/'.\OC_Config::getValue('files_versionsfolder', Storage::DEFAULTFOLDER); + if(!is_dir($foldername)){ + mkdir($foldername); + } + } + } + + + /** + * listen to write event. + */ + public static function write_hook($params) { + if(\OC_Config::getValue('files_versions', Storage::DEFAULTENABLED)=='true') { + $path = $params[\OC_Filesystem::signal_param_path]; + if($path<>'') Storage::store($path); + } + } + + + + /** + * store a new version of a file. + */ + public static function store($filename) { + if(\OC_Config::getValue('files_versions', Storage::DEFAULTENABLED)=='true') { + $versionsfoldername=\OC_Config::getValue('datadirectory').'/'. \OC_User::getUser() .'/'.\OC_Config::getValue('files_versionsfolder', Storage::DEFAULTFOLDER); + $filesfoldername=\OC_Config::getValue('datadirectory').'/'. \OC_User::getUser() .'/files'; + Storage::init(); + + // check if filename is a directory + if(is_dir($filesfoldername.$filename)){ + return false; + } + + // check filetype blacklist + $blacklist=explode(' ',\OC_Config::getValue('files_versionsblacklist', Storage::DEFAULTBLACKLIST)); + foreach($blacklist as $bl) { + $parts=explode('.', $filename); + $ext=end($parts); + if(strtolower($ext)==$bl) { + return false; + } + } + + // check filesize + if(filesize($filesfoldername.$filename)>\OC_Config::getValue('files_versionsmaxfilesize', Storage::DEFAULTMAXFILESIZE)){ + return false; + } + + + // check mininterval + $matches=glob($versionsfoldername.$filename.'.v*'); + sort($matches); + $parts=explode('.v',end($matches)); + if((end($parts)+Storage::DEFAULTMININTERVAL)>time()){ + return false; + } + + + // create all parent folders + $info=pathinfo($filename); + @mkdir($versionsfoldername.$info['dirname'],0700,true); + + + // store a new version of a file + copy($filesfoldername.$filename,$versionsfoldername.$filename.'.v'.time()); + + // expire old revisions + Storage::expire($filename); + } + } + + + /** + * rollback to an old version of a file. + */ + public static function rollback($filename,$revision) { + if(\OC_Config::getValue('files_versions', Storage::DEFAULTENABLED)=='true') { + $versionsfoldername=\OC_Config::getValue('datadirectory').'/'. \OC_User::getUser() .'/'.\OC_Config::getValue('files_versionsfolder', Storage::DEFAULTFOLDER); + $filesfoldername=\OC_Config::getValue('datadirectory').'/'. \OC_User::getUser() .'/files'; + // rollback + @copy($versionsfoldername.$filename.'.v'.$revision,$filesfoldername.$filename); + } + } + + /** + * check if old versions of a file exist. + */ + public static function isversioned($filename) { + if(\OC_Config::getValue('files_versions', Storage::DEFAULTENABLED)=='true') { + $versionsfoldername=\OC_Config::getValue('datadirectory').'/'. \OC_User::getUser() .'/'.\OC_Config::getValue('files_versionsfolder', Storage::DEFAULTFOLDER); + + // check for old versions + $matches=glob($versionsfoldername.$filename.'.v*'); + if(count($matches)>1){ + return true; + }else{ + return false; + } + }else{ + return(false); + } + } + + + + /** + * get a list of old versions of a file. + */ + public static function getversions($filename,$count=0) { + if(\OC_Config::getValue('files_versions', Storage::DEFAULTENABLED)=='true') { + $versionsfoldername=\OC_Config::getValue('datadirectory').'/'. \OC_User::getUser() .'/'.\OC_Config::getValue('files_versionsfolder', Storage::DEFAULTFOLDER); + $versions=array(); + + // fetch for old versions + $matches=glob($versionsfoldername.$filename.'.v*'); + sort($matches); + foreach($matches as $ma) { + $parts=explode('.v',$ma); + $versions[]=(end($parts)); + } + + // only show the newest commits + if($count<>0 and (count($versions)>$count)) { + $versions=array_slice($versions,count($versions)-$count); + } + + return($versions); + + + }else{ + return(array()); + } + } + + + + /** + * expire old versions of a file. + */ + public static function expire($filename) { + if(\OC_Config::getValue('files_versions', Storage::DEFAULTENABLED)=='true') { + + $versionsfoldername=\OC_Config::getValue('datadirectory').'/'. \OC_User::getUser() .'/'.\OC_Config::getValue('files_versionsfolder', Storage::DEFAULTFOLDER); + + // check for old versions + $matches=glob($versionsfoldername.$filename.'.v*'); + if(count($matches)>\OC_Config::getValue('files_versionmaxversions', Storage::DEFAULTMAXVERSIONS)){ + $numbertodelete=count($matches-\OC_Config::getValue('files_versionmaxversions', Storage::DEFAULTMAXVERSIONS)); + + // delete old versions of a file + $deleteitems=array_slice($matches,0,$numbertodelete); + foreach($deleteitems as $de){ + unlink($versionsfoldername.$filename.'.v'.$de); + } + } + } + } + + /** + * expire all old versions. + */ + public static function expireall($filename) { + // todo this should go through all the versions directories and delete all the not needed files and not needed directories. + // useful to be included in a cleanup cronjob. + } + + +} |