summaryrefslogtreecommitdiffstats
path: root/apps/files_versions
diff options
context:
space:
mode:
authorFrank Karlitschek <karlitschek@kde.org>2012-04-23 23:54:49 +0200
committerFrank Karlitschek <karlitschek@kde.org>2012-04-23 23:54:49 +0200
commit4ea927a7987d7fdcefcacb341f1a60b094ccf8d2 (patch)
treedeb1cad81406276ffd2e3db66a77cd3d78af73c4 /apps/files_versions
parentf5c9fe9ece6fdfb35bab5eefdf83830b5045b5a8 (diff)
downloadnextcloud-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.php19
-rw-r--r--apps/files_versions/appinfo/info.xml12
-rw-r--r--apps/files_versions/appinfo/version1
-rw-r--r--apps/files_versions/css/versions.css2
-rw-r--r--apps/files_versions/history.php60
-rw-r--r--apps/files_versions/js/versions.js2
-rw-r--r--apps/files_versions/settings.php10
-rw-r--r--apps/files_versions/templates/history.php18
-rw-r--r--apps/files_versions/templates/settings.php7
-rw-r--r--apps/files_versions/versions.php216
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.
+ }
+
+
+}