diff options
author | Frank Karlitschek <karlitschek@kde.org> | 2012-04-23 23:54:49 +0200 |
---|---|---|
committer | Frank Karlitschek <karlitschek@kde.org> | 2012-04-23 23:54:49 +0200 |
commit | 4ea927a7987d7fdcefcacb341f1a60b094ccf8d2 (patch) | |
tree | deb1cad81406276ffd2e3db66a77cd3d78af73c4 /apps/files_versions | |
parent | f5c9fe9ece6fdfb35bab5eefdf83830b5045b5a8 (diff) | |
download | nextcloud-server-4ea927a7987d7fdcefcacb341f1a60b094ccf8d2.tar.gz nextcloud-server-4ea927a7987d7fdcefcacb341f1a60b094ccf8d2.zip |
wrote a new versioning app over the weekend. Basic functionality to far but it works (TM) and has all the needed features (TM) for ownCloud 4. Userinterface integration and small improvements still missing.
Diffstat (limited to 'apps/files_versions')
-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. + } + + +} |