Date: Fri, 16 Mar 2012 21:09:36 +0000
Subject: [PATCH 035/133] Fix export for admin and users. Added 3 admin export
types
---
apps/admin_export/settings.php | 9 +-
apps/admin_export/templates/settings.php | 2 +-
apps/user_migrate/settings.php | 2 +-
lib/migrate.php | 144 +++++++++++++----------
4 files changed, 90 insertions(+), 67 deletions(-)
diff --git a/apps/admin_export/settings.php b/apps/admin_export/settings.php
index 9db1d75db9..33fca26630 100644
--- a/apps/admin_export/settings.php
+++ b/apps/admin_export/settings.php
@@ -40,12 +40,12 @@ if (isset($_POST['admin_export'])) {
header("Content-Disposition: attachment; filename=" . basename($path));
header("Content-Length: " . filesize($path));
@ob_end_clean();
- readfile($path);
- OC_Migrate::cleanUp( $path );
+ readfile( $path );
+ unlink( $path );
}
// Import?
} else if( isset($_POST['admin_import']) ){
-
+ /*
$root = OC::$SERVERROOT . "/";
$importname = "owncloud_import_" . date("y-m-d_H-i-s");
@@ -85,7 +85,8 @@ if (isset($_POST['admin_export'])) {
exit();
}
- OC_DB::replaceDB( get_temp_dir() . '/' . $importname . '/dbexport.xml' );
+ OC_DB::replaceDB( get_temp_dir() . '/' . $importname . '/dbexport.xml' );
+ */
} else {
// fill template
$tmpl = new OC_Template('admin_export', 'settings');
diff --git a/apps/admin_export/templates/settings.php b/apps/admin_export/templates/settings.php
index 15a19b7c63..6d848048c4 100644
--- a/apps/admin_export/templates/settings.php
+++ b/apps/admin_export/templates/settings.php
@@ -8,7 +8,7 @@
ownCloud instance ( suitable for import )
ownCloud system files
- Just user files
+ Just user files
diff --git a/apps/user_migrate/settings.php b/apps/user_migrate/settings.php
index d862ac5a82..2d200c0f76 100644
--- a/apps/user_migrate/settings.php
+++ b/apps/user_migrate/settings.php
@@ -36,7 +36,7 @@ if (isset($_POST['user_export'])) {
header("Content-Length: " . filesize($path));
@ob_end_clean();
readfile($path);
- OC_Migrate::cleanUp( $path );
+ unlink( $path );
}
} if( isset( $_POST['user_import'] ) ){
// TODO
diff --git a/lib/migrate.php b/lib/migrate.php
index 8f26ea7ae6..522d8da843 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -40,6 +40,10 @@ class OC_Migrate{
static private $zip=false;
// String path to export
static private $zippath=false;
+ // Stores the type of export
+ static private $exporttype=false;
+ // Array of temp files to be deleted after zip creation
+ static private $tmpfiles=array();
/**
* register a new migration provider
@@ -138,14 +142,7 @@ class OC_Migrate{
self::$zippath = $path . $zipname;
} else {
// Save in tmp dir
- $structure = sys_get_temp_dir() . '/owncloudexports/';
- if( !file_exists( $structure ) ){
- if ( !mkdir( $structure ) ) {
- OC_Log::write('migration', 'Could not create the temporary export at: '.$structure, OC_Log::ERROR);
- return false;
- }
- }
- self::$zippath = $structure . $zipname;
+ self::$zippath = sys_get_temp_dir() . '/' . $zipname;
}
// Create the zip object
self::$zip = new ZipArchive;
@@ -154,42 +151,48 @@ class OC_Migrate{
return false;
}
// Handle export types
- if( $exporttype == 'instance' ){
- // Creates a zip that is compatable with the import function
- /*
- $dbfile = self:: . "/dbexport.xml";
- OC_DB::getDbStructure( $dbfile, 'MDB2_SCHEMA_DUMP_ALL');
-
- // Now add in *dbname* and *dbtableprefix*
- $dbexport = file_get_contents( $dbfile );
-
- $dbnamestring = "\n\n " . OC_Config::getValue( "dbname", "owncloud" );
- $dbtableprefixstring = "\n\n " . OC_Config::getValue( "dbtableprefix", "_oc" );
-
- $dbexport = str_replace( $dbnamestring, "\n\n *dbname*", $dbexport );
- $dbexport = str_replace( $dbtableprefixstring, "\n\n *dbprefix*", $dbexport );
-
- // Write the new db export file
- file_put_contents( $dbfile, $dbexport );
-
- $zip->addFile($dbfile, "dbexport.xml");
- */
- } else if( $exporttype == 'system' ){
- // Creates a zip with the owncloud system files
- self::addDirToZip( OC::$SERVERROOT . '/', false);
- foreach (array(".git", "3rdparty", "apps", "core", "files", "l10n", "lib", "ocs", "search", "settings", "tests") as $dir) {
- self::addDirToZip( OC::$SERVERROOT . '/' . $dir, true, "/");
- }
- } else if ( $exporttype == 'userfiles' ){
- // Creates a zip with all of the users files
- foreach(OC_User::getUsers() as $user){
- self::addDirToZip( $datadir . '/' . $user . '/', true, "/" . $user);
- }
- } else {
- // Invalid export type supplied
- OC_Log::write('migration', 'Invalid export type supplied to createSysExportFile() "'.$exporttype.'"', OC_Log::ERROR);
+ $exporttypes = array( 'userfiles', 'instance', 'system' );
+ self::$exporttype = in_array( $exporttype, $exporttypes ) ? $exporttype : false;
+ if( !self::$exporttype ){
+ OC_Log::write( 'migration', 'Export type: '.$exporttype.' is not supported.', OC_Log::ERROR);
return false;
}
+ switch( self::$exporttype ){
+ case 'instance':
+ // Creates a zip that is compatable with the import function
+ $dbfile = tempnam( "/tmp", "owncloud_export_data_" );
+ OC_DB::getDbStructure( $dbfile, 'MDB2_SCHEMA_DUMP_ALL');
+
+ // Now add in *dbname* and *dbprefix*
+ $dbexport = file_get_contents( $dbfile );
+ $dbnamestring = "\n\n " . OC_Config::getValue( "dbname", "owncloud" );
+ $dbtableprefixstring = "\n\n " . OC_Config::getValue( "dbtableprefix", "oc_" );
+ $dbexport = str_replace( $dbnamestring, "\n\n *dbname*", $dbexport );
+ $dbexport = str_replace( $dbtableprefixstring, "\n\n *dbprefix*", $dbexport );
+ // Write the new db export file
+ file_put_contents( $dbfile, $dbexport );
+ self::$zip->addFile( $dbfile, "dbexport.xml" );
+ // Add user data
+ foreach(OC_User::getUsers() as $user){
+ self::addDirToZip( $datadir . '/' . $user . '/', true, "/userdata/" );
+ }
+ break;
+ case 'userfiles':
+ // Creates a zip with all of the users files
+ foreach(OC_User::getUsers() as $user){
+ self::addDirToZip( $datadir . '/' . $user . '/', true, "/" );
+ }
+ break;
+ case 'system':
+ // Creates a zip with the owncloud system files
+ self::addDirToZip( OC::$SERVERROOT . '/', false, '/');
+ foreach (array(".git", "3rdparty", "apps", "core", "files", "l10n", "lib", "ocs", "search", "settings", "tests") as $dir) {
+ self::addDirToZip( OC::$SERVERROOT . '/' . $dir, true, "/");
+ }
+ break;
+ }
+ // Add export info
+ self::addExportInfo();
// Close the zip
if( !self::closeZip() ){
return false;
@@ -198,6 +201,30 @@ class OC_Migrate{
}
+ /**
+ * @breif adds a json file with infomation on the export to the zips root (used on import)
+ * @return bool
+ */
+ static private function addExportInfo(){
+ $info = array(
+ 'ocversion' => OC_Util::getVersion(),
+ 'exporttime' => time(),
+ 'exportedby' => OC_User::getUser(),
+ 'exporttype' => self::$exporttype
+ );
+ // Create json
+ $json = json_encode( $info );
+ $tmpfile = tempnam("/tmp", "oc_export_info_");
+ self::$tmpfiles[] = $tmpfile;
+ if( !file_put_contents( $tmpfile, $json ) ){
+ return false;
+ } else {
+ self::$zip->addFile( $tmpfile, "export_info.json" );
+ return true;
+ }
+ }
+
+
/**
* @breif tried to finalise the zip
* @return bool
@@ -205,13 +232,25 @@ class OC_Migrate{
static private function closeZip(){
if( !self::$zip->close() ){
OC_Log::write('migration', 'Failed to save the zip with error: '.self::$zip->getStatusString(), OC_Log::ERROR);
+ self::cleanup();
return false;
} else {
- OC_Log::write('migration', 'Created export file for: '.self::$uid, OC_Log::INFO);
+ OC_Log::write('migration', 'Export zip created ok', OC_Log::INFO);
+ self::cleanup();
return true;
}
}
+ /**
+ * @breif cleans up after the zip
+ */
+ static private function cleanup(){
+ // Delete tmp files
+ foreach(self::$tmpfiles as $i){
+ unlink( $i );
+ }
+ }
+
/**
* @breif creates a zip user export
* @param optional $uid string user id of the user to export (defaults to current)
@@ -647,22 +686,5 @@ class OC_Migrate{
return $result ? true : false;
}
-
- /**
- * @breif removes migration.db and exportinfo.json from the users data dir
- * @param optional $path string path to the export zip to delete
- * @return void
- */
- static public function cleanUp( $path=null ){
- $userdatadir = OC_Config::getValue( 'datadirectory' ) . '/' . self::$uid;
- // Remove migration.db
- unlink( $userdatadir . '/migration.db' );
- // Remove exportinfo.json
- unlink( $userdatadir . '/exportinfo.json' );
- // Remove the zip
- if( !is_null( $path ) ){
- unlink( $path );
- }
- return true;
- }
+
}
From 5332c319a2140563478d83047d9f717c0d3e179f Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Fri, 16 Mar 2012 22:50:35 +0000
Subject: [PATCH 036/133] Migration info is an object. Other fixes
---
apps/bookmarks/lib/migrate.php | 6 +++---
lib/migrate.php | 12 ++++++------
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/apps/bookmarks/lib/migrate.php b/apps/bookmarks/lib/migrate.php
index 4f11bc5bde..46b68ad5ba 100644
--- a/apps/bookmarks/lib/migrate.php
+++ b/apps/bookmarks/lib/migrate.php
@@ -34,16 +34,16 @@ class OC_Migrate_Provider_Bookmarks extends OC_Migrate_Provider{
// Import function for bookmarks
function import( $info ){
- switch( $info['appversion'] ){
+ switch( $info->appversion ){
default:
// All versions of the app have had the same db structure, so all can use the same import function
$query = OC_Migrate::prepare( "SELECT * FROM bookmarks WHERE user_id LIKE ?" );
- $results = $query->execute( array( $info['olduid'] ) );
+ $results = $query->execute( array( $info->olduid ) );
$idmap = array();
while( $row = $data->fetchRow() ){
// Import each bookmark, saving its id into the map
$query = OC_DB::prepare( "INSERT INTO *PREFIX*bookmarks(url, title, user_id, public, added, lastmodified) VALUES (?, ?, ?, ?, ?, ?)" );
- $query->execute( array( $row['url'], $row['title'], $info['newuid'], $row['public'], $row['added'], $row['lastmodified'] ) );
+ $query->execute( array( $row['url'], $row['title'], $info->newuid, $row['public'], $row['added'], $row['lastmodified'] ) );
// Map the id
$idmap[$row['id']] = OC_DB::insertid();
}
diff --git a/lib/migrate.php b/lib/migrate.php
index 522d8da843..28c36e9616 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -377,11 +377,11 @@ class OC_Migrate{
/**
* @breif imports a new user
* @param $db string path to migration.db
- * @param $migrateinfo array of migration ino
+ * @param $info array of migration ino
* @param $uid optional uid to use
* @return bool if the import succedded
*/
- public static function importAppData( $db, $migrateinfo, $uid=false ){
+ public static function importAppData( $db, $info, $uid=false ){
if(!self::$uid){
OC_Log::write('migration','Tried to import without passing a uid',OC_Log::FATAL);
@@ -399,15 +399,15 @@ class OC_Migrate{
return false;
}
- if( !is_array( $migrateinfo ) ){
+ if( !is_array( $info ) ){
OC_Log::write('migration','$migrateinfo is not an array', OC_Log::FATAL);
return false;
}
// Set the user id
- self::$uid = $info['migrateinfo']['uid'];
+ self::$uid = $info->migrateinfo->uid;
- $apps = $info['apps'];
+ $apps = $info->app;
foreach( self::$providers as $provider){
// Is the app in the export?
@@ -415,7 +415,7 @@ class OC_Migrate{
// Did it succeed?
if( $app[$provider->id] ){
// Then do the import
- $provider->import();
+ $provider->import( $info );
}
}
}
From 222bb2303fb0825b4e279024ff723db84e23153d Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Fri, 16 Mar 2012 22:54:37 +0000
Subject: [PATCH 037/133] Added prototype of user import
---
apps/admin_export/settings.php | 4 +-
apps/admin_export/templates/settings.php | 2 +-
apps/user_migrate/settings.php | 117 +++++++++++++++++++++++
3 files changed, 120 insertions(+), 3 deletions(-)
diff --git a/apps/admin_export/settings.php b/apps/admin_export/settings.php
index 33fca26630..e7de74f758 100644
--- a/apps/admin_export/settings.php
+++ b/apps/admin_export/settings.php
@@ -45,7 +45,7 @@ if (isset($_POST['admin_export'])) {
}
// Import?
} else if( isset($_POST['admin_import']) ){
- /*
+
$root = OC::$SERVERROOT . "/";
$importname = "owncloud_import_" . date("y-m-d_H-i-s");
@@ -86,7 +86,7 @@ if (isset($_POST['admin_export'])) {
}
OC_DB::replaceDB( get_temp_dir() . '/' . $importname . '/dbexport.xml' );
- */
+
} else {
// fill template
$tmpl = new OC_Template('admin_export', 'settings');
diff --git a/apps/admin_export/templates/settings.php b/apps/admin_export/templates/settings.php
index 6d848048c4..36eec84d48 100644
--- a/apps/admin_export/templates/settings.php
+++ b/apps/admin_export/templates/settings.php
@@ -14,7 +14,7 @@
diff --git a/apps/user_migrate/templates/settings.php b/apps/user_migrate/templates/settings.php
index 59a27a926d..389de563a6 100644
--- a/apps/user_migrate/templates/settings.php
+++ b/apps/user_migrate/templates/settings.php
@@ -5,13 +5,4 @@
-
-
-
- t('Import user account');?>
-
- t('ownCloud User Zip');?>
-
-
-
-
+
\ No newline at end of file
From 5234e66bab0ebc6fd7eeef8170cf9f61f035124d Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sat, 17 Mar 2012 13:53:00 +0000
Subject: [PATCH 039/133] Add exportinfo to user exports.
---
apps/user_migrate/admin.php | 10 ++++------
lib/migrate.php | 37 +++++++++++++++++++++++--------------
2 files changed, 27 insertions(+), 20 deletions(-)
diff --git a/apps/user_migrate/admin.php b/apps/user_migrate/admin.php
index 56fe887514..da2e53d2a1 100644
--- a/apps/user_migrate/admin.php
+++ b/apps/user_migrate/admin.php
@@ -1,10 +1,8 @@
open(get_temp_dir().'/'.$importname.'.zip') != TRUE) {
- OC_Log::write('admin_export',"Failed to open zip file",OC_Log::INFO);
+ OC_Log::write('migration',"Failed to open zip file",OC_Log::INFO);
exit();
}
$zip->extractTo(get_temp_dir().'/'.$importname.'/');
diff --git a/lib/migrate.php b/lib/migrate.php
index 28c36e9616..f5fb808f17 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -84,7 +84,7 @@ class OC_Migrate{
if( is_array( $tables ) ){
// Save the table names
foreach($tables as $table){
- $return['app'][$provider->id]['tables'][] = $table;
+ $return['apps'][$provider->id]['tables'][] = $table;
}
} else {
// It failed to create the tables
@@ -94,22 +94,17 @@ class OC_Migrate{
// Run the import function?
if( !$failed ){
- $return['app'][$provider->id]['success'] = $provider->export( self::$uid );
+ $return['apps'][$provider->id]['success'] = $provider->export( self::$uid );
} else {
- $return['app'][$provider->id]['success'] = false;
- $return['app'][$provider->id]['message'] = 'failed to create the app tables';
+ $return['apps'][$provider->id]['success'] = false;
+ $return['apps'][$provider->id]['message'] = 'failed to create the app tables';
}
// Now add some app info the the return array
$appinfo = OC_App::getAppInfo( $provider->id );
- $return['app'][$provider->id]['version'] = $appinfo['version'];
+ $return['apps'][$provider->id]['version'] = $appinfo['version'];
}
-
-
- // Add some general info to the return array
- $return['migrateinfo']['uid'] = self::$uid;
- $return['migrateinfo']['ocversion'] = OC_Util::getVersionString();
return $return;
@@ -205,13 +200,27 @@ class OC_Migrate{
* @breif adds a json file with infomation on the export to the zips root (used on import)
* @return bool
*/
- static private function addExportInfo(){
+ static private function addExportInfo( $array=array() ){
$info = array(
'ocversion' => OC_Util::getVersion(),
'exporttime' => time(),
'exportedby' => OC_User::getUser(),
'exporttype' => self::$exporttype
);
+ // Add hash if user export
+ if( self::$exporttype = 'user' ){
+ $query = OC_DB::prepare( "SELECT password FROM *PREFIX*users WHERE uid LIKE ?" );
+ $result = $query->execute( array( self::$uid ) );
+ $row = $result->fetchRow();
+ $hash = $row ? $row['password'] : false;
+ if( !$hash ){
+ OC_Log::write( 'migration', 'Failed to get the users password hash', OC_log::ERROR);
+ return false;
+ }
+ $info['hash'] = $hash;
+ }
+ // Merge in other data
+ $info = array_merge( $info, $array );
// Create json
$json = json_encode( $info );
$tmpfile = tempnam("/tmp", "oc_export_info_");
@@ -297,8 +306,8 @@ class OC_Migrate{
return false;
}
// Export the app info
- $info = json_encode( self::exportAppData() );
- file_put_contents( $userdatadir . '/exportinfo.json', $info );
+ $exportinfo = json_encode( self::addExportInfo( self::exportAppData() ) );
+ file_put_contents( $userdatadir . '/exportinfo.json', $exportinfo );
// Add the data dir to the zip
self::addDirToZip( $userdatadir );
// Close the zip
@@ -670,7 +679,7 @@ class OC_Migrate{
// @param $uid string user_id of the user to be created
// @param $hash string hash of the user to be created
// @return bool result of user creation
- private static function createUser( $uid, $hash ){
+ public static function createUser( $uid, $hash ){
// Check if userid exists
if(OC_User::userExists( $uid )){
From 247b25e7a97fcbe8386c63b1318537e669d40480 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sat, 17 Mar 2012 15:01:08 +0000
Subject: [PATCH 040/133] Fix structure of export zip
---
lib/migrate.php | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/lib/migrate.php b/lib/migrate.php
index f5fb808f17..44d28297d4 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -228,7 +228,7 @@ class OC_Migrate{
if( !file_put_contents( $tmpfile, $json ) ){
return false;
} else {
- self::$zip->addFile( $tmpfile, "export_info.json" );
+ self::$zip->addFile( $tmpfile, "/" . self::$uid . "/export_info.json" );
return true;
}
}
@@ -278,6 +278,8 @@ class OC_Migrate{
self::$uid = $uid;
// Create the zip object
self::$zip = new ZipArchive;
+ // Set export type
+ self::$exporttype = 'user';
// Calculate users data dir
$user = OC_User::getUser();
$userdatadir = OC_Config::getValue( 'datadirectory' ) . '/' . $user . '/';
@@ -306,8 +308,9 @@ class OC_Migrate{
return false;
}
// Export the app info
- $exportinfo = json_encode( self::addExportInfo( self::exportAppData() ) );
- file_put_contents( $userdatadir . '/exportinfo.json', $exportinfo );
+ $appinfo = self::exportAppData();
+ // Save the migration results
+ self::addExportInfo( $appinfo );
// Add the data dir to the zip
self::addDirToZip( $userdatadir );
// Close the zip
From bc085c3ff40bd7980bb28a20238bf18a754ffba2 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sat, 17 Mar 2012 16:25:14 +0000
Subject: [PATCH 041/133] Create new user, create new data dir, copy files,
import app data
---
apps/admin_export/settings.php | 1 -
apps/bookmarks/lib/migrate.php | 9 +++--
apps/user_migrate/admin.php | 27 ++++++++------
lib/migrate.php | 65 +++++++++++++++++++---------------
lib/migrate/provider.php | 3 +-
5 files changed, 59 insertions(+), 46 deletions(-)
diff --git a/apps/admin_export/settings.php b/apps/admin_export/settings.php
index e7de74f758..1c98bb552f 100644
--- a/apps/admin_export/settings.php
+++ b/apps/admin_export/settings.php
@@ -144,7 +144,6 @@ function unlinkRecursive($dir, $deleteRootToo)
return;
}
-
function copy_r( $path, $dest )
{
diff --git a/apps/bookmarks/lib/migrate.php b/apps/bookmarks/lib/migrate.php
index 46b68ad5ba..ffc5e9f838 100644
--- a/apps/bookmarks/lib/migrate.php
+++ b/apps/bookmarks/lib/migrate.php
@@ -32,18 +32,17 @@ class OC_Migrate_Provider_Bookmarks extends OC_Migrate_Provider{
}
// Import function for bookmarks
- function import( $info ){
-
- switch( $info->appversion ){
+ function import( $app, $info ){
+ switch( $app->version ){
default:
// All versions of the app have had the same db structure, so all can use the same import function
$query = OC_Migrate::prepare( "SELECT * FROM bookmarks WHERE user_id LIKE ?" );
- $results = $query->execute( array( $info->olduid ) );
+ $results = $query->execute( array( $info['olduid'] ) );
$idmap = array();
while( $row = $data->fetchRow() ){
// Import each bookmark, saving its id into the map
$query = OC_DB::prepare( "INSERT INTO *PREFIX*bookmarks(url, title, user_id, public, added, lastmodified) VALUES (?, ?, ?, ?, ?, ?)" );
- $query->execute( array( $row['url'], $row['title'], $info->newuid, $row['public'], $row['added'], $row['lastmodified'] ) );
+ $query->execute( array( $row['url'], $row['title'], $info['newuid'], $row['public'], $row['added'], $row['lastmodified'] ) );
// Map the id
$idmap[$row['id']] = OC_DB::insertid();
}
diff --git a/apps/user_migrate/admin.php b/apps/user_migrate/admin.php
index da2e53d2a1..6f3565788e 100644
--- a/apps/user_migrate/admin.php
+++ b/apps/user_migrate/admin.php
@@ -62,14 +62,15 @@ if (isset($_POST['user_import'])) {
// Get the user
if( count($files) != 1 ){
OC_Log::write('migration', 'Invalid import file', OC_Log::ERROR);
- die('invalid import');
+ die('invalid import, no user included');
}
- $user = reset($files);
+ $olduser = reset($files);
// Check for dbexport.xml and export info and data dir
- $files = scandir( $importdir . '/' . $user );
- $required = array( 'migration.db', 'exportinfo.json', 'files');
+ $files = scandir( $importdir . '/' . $olduser );
+
+ $required = array( 'migration.db', 'export_info.json', 'files');
foreach($required as $require){
if( !in_array( $require, $files) ){
OC_Log::write('migration', 'Invlaid import file', OC_Log::ERROR);
@@ -77,31 +78,37 @@ if (isset($_POST['user_import'])) {
}
}
- $migrateinfo = $importdir . '/' . $user . '/exportinfo.json';
+ $migrateinfo = $importdir . '/' . $olduser . '/export_info.json';
$migrateinfo = json_decode( file_get_contents( $migrateinfo ) );
- $olduid = $migrateinfo->migrateinfo->uid;
// Check if uid is available
- if( OC_User::UserExists( $olduid ) ){
+ if( OC_User::UserExists( $olduser ) ){
OC_Log::write('migration','Username exists', OC_Log::ERROR);
die('user exists');
}
// Create the user
- if( !OC_Migrate::createUser( $olduid, $migrateinfo->migrateinfo->hash ) ){
+ if( !OC_Migrate::createUser( $olduser, $migrateinfo->hash ) ){
OC_Log::write('migration', 'Failed to create the new user', OC_Log::ERROR);
die('coundlt create new user');
}
$datadir = OC_Config::getValue( 'datadirectory' );
+ // Make the new users data dir
+ $path = $datadir . '/' . $olduser . '/files/';
+ if( !mkdir( $path, 0755, true ) ){
+ OC_Log::write('migration','Failed to create users data dir: '.$path, OC_Log::ERROR);
+ die('failed to create users data dir');
+ }
+
// Copy data
- if( !copy_r( $importdir . '/files', $datadir . '/' ) ){
+ if( !copy_r( $importdir . '/' . $olduser . '/files', $datadir . '/' . $olduser . '/files' ) ){
OC_Log::write('migration','Failed to copy user files to destination', OC_Log::ERROR);
die('failed to copy user files');
}
// Import user data
- if( !OC_Migrate::importUser( $importdir . '/migration.db', $migrateinfo ) ){
+ if( !OC_Migrate::importAppData( $importdir . '/' . $olduser . '/migration.db', $migrateinfo ) ){
OC_Log::write('migration','Failed to import user data', OC_Log::ERROR);
die('failed to import user data');
}
diff --git a/lib/migrate.php b/lib/migrate.php
index 44d28297d4..415c33e5be 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -53,6 +53,21 @@ class OC_Migrate{
self::$providers[]=$provider;
}
+ /**
+ * @breif finds and loads the providers
+ */
+ static private function findProviders(){
+ // Find the providers
+ $apps = OC_App::getAllApps();
+
+ foreach($apps as $app){
+ $path = OC::$SERVERROOT . '/apps/' . $app . '/lib/migrate.php';
+ if( file_exists( $path ) ){
+ include( $path );
+ }
+ }
+ }
+
/**
* @breif creates a migration.db in the users data dir with their app data in
* @return bool whether operation was successfull
@@ -64,14 +79,7 @@ class OC_Migrate{
$return = array();
// Find the providers
- $apps = OC_App::getAllApps();
-
- foreach($apps as $app){
- $path = OC::$SERVERROOT . '/apps/' . $app . '/lib/migrate.php';
- if( file_exists( $path ) ){
- include( $path );
- }
- }
+ self::findProviders();
// Foreach provider
foreach( self::$providers as $provider ){
@@ -217,7 +225,8 @@ class OC_Migrate{
OC_Log::write( 'migration', 'Failed to get the users password hash', OC_log::ERROR);
return false;
}
- $info['hash'] = $hash;
+ $info['hash'] = $hash;
+ $info['exporteduser'] = self::$uid;
}
// Merge in other data
$info = array_merge( $info, $array );
@@ -393,17 +402,15 @@ class OC_Migrate{
* @param $uid optional uid to use
* @return bool if the import succedded
*/
- public static function importAppData( $db, $info, $uid=false ){
+ public static function importAppData( $db, $info, $uid=null ){
- if(!self::$uid){
- OC_Log::write('migration','Tried to import without passing a uid',OC_Log::FATAL);
- return false;
- }
+ self::$uid = !is_null( $uid ) ? $uid : $info->exporteduser;
// Check if the db exists
if( file_exists( $db ) ){
// Connect to the db
if(!self::connectDB( $db )){
+ OC_Log::write('migration','Failed to connect to migration.db',OC_Log::ERROR);
return false;
}
} else {
@@ -411,25 +418,25 @@ class OC_Migrate{
return false;
}
- if( !is_array( $info ) ){
- OC_Log::write('migration','$migrateinfo is not an array', OC_Log::FATAL);
- return false;
- }
-
- // Set the user id
- self::$uid = $info->migrateinfo->uid;
-
- $apps = $info->app;
-
+ // Find providers
+ self::findProviders();
+
+ // Generate importinfo array
+ $importinfo = array(
+ 'olduid' => $info->exporteduser,
+ 'newuid' => self::$uid
+ );
+
foreach( self::$providers as $provider){
// Is the app in the export?
- if( array_key_exists( $provider->id, $apps ) ){
+ $id = $provider->id;
+ if( isset( $info->apps->$id ) ){
// Did it succeed?
- if( $app[$provider->id] ){
+ if( $info->apps->$id->success ){
// Then do the import
- $provider->import( $info );
+ $provider->import( $info->apps->$id, $importinfo );
}
- }
+ }
}
return true;
@@ -691,7 +698,7 @@ class OC_Migrate{
// Create the user
$query = OC_DB::prepare( "INSERT INTO `*PREFIX*users` ( `uid`, `password` ) VALUES( ?, ? )" );
- $result = $query->execute( array( $uid, $data['hash']));
+ $result = $query->execute( array( $uid, $hash));
if( !$result ){
OC_Log::write('migration', 'Failed to create the new user "'.$uid."");
}
diff --git a/lib/migrate/provider.php b/lib/migrate/provider.php
index e2e01b3b5a..7ac3cf97ca 100644
--- a/lib/migrate/provider.php
+++ b/lib/migrate/provider.php
@@ -20,8 +20,9 @@ abstract class OC_Migrate_Provider{
/**
* @breif imports data for the app
+ * @param $appinfo object with the data that the app exported
* @param $info array of info including exportinfo.json
* @return void
*/
- abstract function import( $info );
+ abstract function import( $appinfo, $info );
}
From 77f6872ea4859e13637efbc6d051072a5085394f Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sat, 17 Mar 2012 17:45:39 +0000
Subject: [PATCH 042/133] Shorten export zip names
---
lib/migrate.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/migrate.php b/lib/migrate.php
index 415c33e5be..84eafcd4cd 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -126,7 +126,7 @@ class OC_Migrate{
*/
static public function createSysExportFile( $exporttype='instance', $path=null ){
// Calculate zip name
- $zipname = "owncloud_export_" . date("y-m-d_H-i-s") . ".zip";
+ $zipname = "oc_export_" . date("y-m-d_H-i-s") . ".zip";
// Get the data dir
$datadir = OC_Config::getValue( 'datadirectory' );
// Calculate destination
@@ -293,7 +293,7 @@ class OC_Migrate{
$user = OC_User::getUser();
$userdatadir = OC_Config::getValue( 'datadirectory' ) . '/' . $user . '/';
// Calculate zip name
- $zipname = "owncloud_userexport_" . $user . '_' . date("y-m-d_H-i-s") . ".zip";
+ $zipname = "oc_userexport_" . $user . '_' . date("y-m-d_H-i-s") . ".zip";
// Calculate destination
if( !is_null( $path ) ){
// Path given
From 145d6f35660669397eaee08988ffbad1b65daff0 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Mon, 19 Mar 2012 20:44:20 +0000
Subject: [PATCH 043/133] Add OC_Migration_Content class to help app devs.
Restructure OC_Migrate.
---
apps/admin_export/settings.php | 134 +-----
apps/bookmarks/lib/migrate.php | 20 +-
apps/user_migrate/settings.php | 2 +-
lib/migrate.php | 781 ++++++++++++---------------------
lib/migrate/provider.php | 28 --
lib/migration/content.php | 239 ++++++++++
lib/migration/provider.php | 49 +++
7 files changed, 593 insertions(+), 660 deletions(-)
delete mode 100644 lib/migrate/provider.php
create mode 100644 lib/migration/content.php
create mode 100644 lib/migration/provider.php
diff --git a/apps/admin_export/settings.php b/apps/admin_export/settings.php
index 1c98bb552f..af8dd0dbf5 100644
--- a/apps/admin_export/settings.php
+++ b/apps/admin_export/settings.php
@@ -27,11 +27,10 @@ OC_Util::checkAppEnabled('admin_export');
define('DS', '/');
-
// Export?
if (isset($_POST['admin_export'])) {
// Create the export zip
- if( !$path = OC_Migrate::createSysExportFile( $_POST['export_type'] ) ){
+ if( !$path = OC_Migrate::export( $_POST['export_type'] ) ){
// Error
die('error');
} else {
@@ -46,136 +45,11 @@ if (isset($_POST['admin_export'])) {
// Import?
} else if( isset($_POST['admin_import']) ){
- $root = OC::$SERVERROOT . "/";
- $importname = "owncloud_import_" . date("y-m-d_H-i-s");
-
- // Save data dir for later
- $datadir = OC_Config::getValue( 'datadirectory' );
-
- // Copy the uploaded file
- $from = $_FILES['owncloud_import']['tmp_name'];
- $to = get_temp_dir().'/'.$importname.'.zip';
- if( !move_uploaded_file( $from, $to ) ){
- OC_Log::write('admin_export',"Failed to copy the uploaded file",OC_Log::INFO);
- exit();
- }
-
- // Extract zip
- $zip = new ZipArchive();
- if ($zip->open(get_temp_dir().'/'.$importname.'.zip') != TRUE) {
- OC_Log::write('admin_export',"Failed to open zip file",OC_Log::INFO);
- exit();
- }
- $zip->extractTo(get_temp_dir().'/'.$importname.'/');
- $zip->close();
-
- // Delete uploaded file
- unlink( get_temp_dir() . '/' . $importname . '.zip' );
-
- // Now we need to check if everything is present. Data and dbexport.xml
-
-
- // Delete current data folder.
- OC_Log::write('admin_export',"Deleting current data dir",OC_Log::INFO);
- unlinkRecursive( $datadir, false );
-
- // Copy over data
- if( !copy_r( get_temp_dir() . '/' . $importname . '/data', $datadir ) ){
- OC_Log::write('admin_export',"Failed to copy over data directory",OC_Log::INFO);
- exit();
- }
-
- OC_DB::replaceDB( get_temp_dir() . '/' . $importname . '/dbexport.xml' );
+ // TODO
+ // OC_Migrate::import( $pathtozipfile );
} else {
// fill template
$tmpl = new OC_Template('admin_export', 'settings');
return $tmpl->fetchPage();
-}
-
-function zipAddDir($dir, $zip, $recursive=true, $internalDir='') {
- $dirname = basename($dir);
- $zip->addEmptyDir($internalDir . $dirname);
- $internalDir.=$dirname.='/';
-
- if ($dirhandle = opendir($dir)) {
- while (false !== ( $file = readdir($dirhandle))) {
-
- if (( $file != '.' ) && ( $file != '..' )) {
-
- if (is_dir($dir . '/' . $file) && $recursive) {
- zipAddDir($dir . '/' . $file, $zip, $recursive, $internalDir);
- } elseif (is_file($dir . '/' . $file)) {
- $zip->addFile($dir . '/' . $file, $internalDir . $file);
- }
- }
- }
- closedir($dirhandle);
- } else {
- OC_Log::write('admin_export',"Was not able to open directory: " . $dir,OC_Log::ERROR);
- }
-}
-
-function unlinkRecursive($dir, $deleteRootToo)
-{
- if(!$dh = @opendir($dir))
- {
- return;
- }
- while (false !== ($obj = readdir($dh)))
- {
- if($obj == '.' || $obj == '..')
- {
- continue;
- }
-
- if (!@unlink($dir . '/' . $obj))
- {
- unlinkRecursive($dir.'/'.$obj, true);
- }
- }
-
- closedir($dh);
-
- if ($deleteRootToo)
- {
- @rmdir($dir);
- }
-
- return;
-}
-
- function copy_r( $path, $dest )
- {
- if( is_dir($path) )
- {
- @mkdir( $dest );
- $objects = scandir($path);
- if( sizeof($objects) > 0 )
- {
- foreach( $objects as $file )
- {
- if( $file == "." || $file == ".." )
- continue;
- // go on
- if( is_dir( $path.DS.$file ) )
- {
- copy_r( $path.DS.$file, $dest.DS.$file );
- }
- else
- {
- copy( $path.DS.$file, $dest.DS.$file );
- }
- }
- }
- return true;
- }
- elseif( is_file($path) )
- {
- return copy($path, $dest);
- }
- else
- {
- return false;
- }
- }
+}
\ No newline at end of file
diff --git a/apps/bookmarks/lib/migrate.php b/apps/bookmarks/lib/migrate.php
index ffc5e9f838..36a08c0cf4 100644
--- a/apps/bookmarks/lib/migrate.php
+++ b/apps/bookmarks/lib/migrate.php
@@ -1,16 +1,16 @@
'bookmarks',
'matchcol'=>'user_id',
- 'matchval'=>$uid,
+ 'matchval'=>$this->uid,
'idcol'=>'id'
);
- $ids = OC_Migrate::copyRows( $options );
+ $ids = $this->content->copyRows( $options );
$options = array(
'table'=>'bookmarks_tags',
@@ -19,7 +19,7 @@ class OC_Migrate_Provider_Bookmarks extends OC_Migrate_Provider{
);
// Export tags
- $ids2 = OC_Migrate::copyRows( $options );
+ $ids2 = $this->content->copyRows( $options );
// If both returned some ids then they worked
if( is_array( $ids ) && is_array( $ids2 ) )
@@ -32,17 +32,17 @@ class OC_Migrate_Provider_Bookmarks extends OC_Migrate_Provider{
}
// Import function for bookmarks
- function import( $app, $info ){
- switch( $app->version ){
+ function import( ){
+ switch( $this->appinfo->version ){
default:
// All versions of the app have had the same db structure, so all can use the same import function
$query = OC_Migrate::prepare( "SELECT * FROM bookmarks WHERE user_id LIKE ?" );
- $results = $query->execute( array( $info['olduid'] ) );
+ $results = $query->execute( array( $this->info['olduid'] ) );
$idmap = array();
while( $row = $data->fetchRow() ){
// Import each bookmark, saving its id into the map
$query = OC_DB::prepare( "INSERT INTO *PREFIX*bookmarks(url, title, user_id, public, added, lastmodified) VALUES (?, ?, ?, ?, ?, ?)" );
- $query->execute( array( $row['url'], $row['title'], $info['newuid'], $row['public'], $row['added'], $row['lastmodified'] ) );
+ $query->execute( array( $row['url'], $row['title'], $this->info['newuid'], $row['public'], $row['added'], $row['lastmodified'] ) );
// Map the id
$idmap[$row['id']] = OC_DB::insertid();
}
@@ -66,4 +66,4 @@ class OC_Migrate_Provider_Bookmarks extends OC_Migrate_Provider{
}
// Load the provider
-new OC_Migrate_Provider_Bookmarks( 'bookmarks' );
\ No newline at end of file
+new OC_Migration_Provider_Bookmarks( 'bookmarks' );
\ No newline at end of file
diff --git a/apps/user_migrate/settings.php b/apps/user_migrate/settings.php
index 62f5e3f20d..38eee990b4 100644
--- a/apps/user_migrate/settings.php
+++ b/apps/user_migrate/settings.php
@@ -26,7 +26,7 @@ OC_Util::checkAppEnabled('user_migrate');
if (isset($_POST['user_export'])) {
// Create the export zip
- if( !$path = OC_Migrate::createUserExportFile() ){
+ if( !$path = OC_Migrate::export() ){
// Error
die('error');
} else {
diff --git a/lib/migrate.php b/lib/migrate.php
index 84eafcd4cd..338d091af8 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -22,28 +22,31 @@
/**
- * provides an interface to all search providers
+ * provides an interface to migrate users and whole ownclouds
*/
class OC_Migrate{
- // Holds the db object
- static private $MDB2=false;
+
// Array of OC_Migration_Provider objects
static private $providers=array();
- // Schema db object
- static private $schema=false;
// User id of the user to import/export
static private $uid=false;
- // Path to the sqlite db
- static private $dbpath=false;
// Holds the ZipArchive object
static private $zip=false;
- // String path to export
- static private $zippath=false;
// Stores the type of export
static private $exporttype=false;
// Array of temp files to be deleted after zip creation
static private $tmpfiles=array();
+ // Holds the db object
+ static private $MDB2=false;
+ // Schema db object
+ static private $schema=false;
+ // Path to the sqlite db
+ static private $dbpath=false;
+ // Holds the path to the zip file
+ static private $zippath=false;
+ // Holds the OC_Migration_Content object
+ static private $content=false;
/**
* register a new migration provider
@@ -69,99 +72,78 @@ class OC_Migrate{
}
/**
- * @breif creates a migration.db in the users data dir with their app data in
- * @return bool whether operation was successfull
+ * @breif exports a user, or owncloud instance
+ * @param ootional $type string type of export, defualts to user
+ * @param otional $path string path to zip output folder
+ * @param optional $uid string user id of user to export if export type is user, defaults to current
*/
- private static function exportAppData( ){
-
- self::connectDB();
- $ok = true;
- $return = array();
-
- // Find the providers
- self::findProviders();
-
- // Foreach provider
- foreach( self::$providers as $provider ){
- $failed = false;
-
- // Does this app use the database?
- if(file_exists(OC::$SERVERROOT.'/apps/'.$provider->id.'/appinfo/database.xml')){
- // Create some app tables
- $tables = self::createAppTables( $provider->id );
- if( is_array( $tables ) ){
- // Save the table names
- foreach($tables as $table){
- $return['apps'][$provider->id]['tables'][] = $table;
- }
- } else {
- // It failed to create the tables
- $failed = true;
- }
- }
-
- // Run the import function?
- if( !$failed ){
- $return['apps'][$provider->id]['success'] = $provider->export( self::$uid );
- } else {
- $return['apps'][$provider->id]['success'] = false;
- $return['apps'][$provider->id]['message'] = 'failed to create the app tables';
- }
-
- // Now add some app info the the return array
- $appinfo = OC_App::getAppInfo( $provider->id );
- $return['apps'][$provider->id]['version'] = $appinfo['version'];
-
- }
-
- return $return;
-
- }
-
- /**
- * @breif creates an export file for the whole system
- * @param optional $exporttype string export type ('instance','system' or 'userfiles')
- * @param optional $path string path to zip destination (with trailing slash)
- * @return path to the zip or false if there was a problem
- */
- static public function createSysExportFile( $exporttype='instance', $path=null ){
- // Calculate zip name
- $zipname = "oc_export_" . date("y-m-d_H-i-s") . ".zip";
- // Get the data dir
+ public static function export( $type='user', $path=null, $uid=null ){
$datadir = OC_Config::getValue( 'datadirectory' );
- // Calculate destination
- if( !is_null( $path ) ){
- // Path given
- // Is a directory?
- if( !is_dir( $path ) ){
- OC_Log::write('migration', 'Path supplied to createSysExportFile() is not a directory', OC_Log::ERROR);
- return false;
- }
- // Is writeable
- if( !is_writeable( $path ) ){
- OC_Log::write('migration', 'Path supplied to createSysExportFile() is not writeable', OC_Log::ERROR);
- return false;
- }
- self::$zippath = $path . $zipname;
- } else {
- // Save in tmp dir
- self::$zippath = sys_get_temp_dir() . '/' . $zipname;
- }
- // Create the zip object
- self::$zip = new ZipArchive;
- // Try to create the zip
- if( !self::createZip() ){
- return false;
- }
- // Handle export types
- $exporttypes = array( 'userfiles', 'instance', 'system' );
- self::$exporttype = in_array( $exporttype, $exporttypes ) ? $exporttype : false;
- if( !self::$exporttype ){
- OC_Log::write( 'migration', 'Export type: '.$exporttype.' is not supported.', OC_Log::ERROR);
- return false;
- }
- switch( self::$exporttype ){
- case 'instance':
+ // Validate export type
+ $types = array( 'user', 'instance', 'system', 'userfiles' );
+ if( !in_array( $type, $types ) ){
+ OC_Log::write( 'migration', 'Invalid export type', OC_Log::ERROR );
+ return false;
+ }
+ self::$exporttype = $type;
+ // Userid?
+ if( self::$exporttype == 'user' ){
+ // Check user exists
+ if( !is_null($uid) ){
+ if( !OC_User_Database::userExists( $uid ) ){
+ OC_Log::write('migration', 'User: '.$uid.' is not in the database and so cannot be exported.', OC_Log::ERROR);
+ return false;
+ }
+ self::$uid = $uid;
+ } else {
+ self::$uid = OC_User::getUser();
+ }
+ }
+ // Calculate zipname
+ if( self::$exporttype == 'user' ){
+ $zipname = 'oc_export_' . self::$uid . '_' . date("y-m-d_H-i-s") . '.zip';
+ } else {
+ $zipname = 'oc_export_' . self::$exporttype . '_' . date("y-m-d_H-i-s") . '.zip';
+ }
+ // Calculate path
+ if( self::$exporttype == 'user' ){
+ self::$zippath = $datadir . '/' . self::$uid . '/' . $zipname;
+ } else {
+ if( !is_null( $path ) ){
+ // Validate custom path
+ if( !file_exists( $path ) || !is_writeable( $path ) ){
+ OC_Log::write( 'migration', 'Path supplied is invalid.', OC_Log::ERROR );
+ return false;
+ }
+ self::$zippath = $path . $zipname;
+ } else {
+ // Default path
+ self::$zippath = get_temp_dir() . '/' . $zipname;
+ }
+ }
+ // Create the zip object
+ self::$zip = new ZipArchive;
+ if( !self::createZip() ){
+ return false;
+ }
+ // Do the export
+ self::findProviders();
+ $exportdata = array();
+ switch( self::$exporttype ){
+ case 'user':
+ // Connect to the db
+ self::$dbpath = $datadir . '/' . self::$uid . '/migration.db';
+ if( !self::connectDB() ){
+ return false;
+ }
+ self::$content = new OC_Migration_Content( self::$zip, self::$MDB2 );
+ // Export the app info
+ $exportdata = self::exportAppData();
+ // Add the data dir to the zip
+ self::$content->addDir( $datadir . '/' . self::$uid, true, '/' );
+ break;
+ case 'instance':
+ self::$content = new OC_Migration_Content( self::$zip );
// Creates a zip that is compatable with the import function
$dbfile = tempnam( "/tmp", "owncloud_export_data_" );
OC_DB::getDbStructure( $dbfile, 'MDB2_SCHEMA_DUMP_ALL');
@@ -172,43 +154,112 @@ class OC_Migrate{
$dbtableprefixstring = "\n\n " . OC_Config::getValue( "dbtableprefix", "oc_" );
$dbexport = str_replace( $dbnamestring, "\n\n *dbname*", $dbexport );
$dbexport = str_replace( $dbtableprefixstring, "\n\n *dbprefix*", $dbexport );
- // Write the new db export file
- file_put_contents( $dbfile, $dbexport );
- self::$zip->addFile( $dbfile, "dbexport.xml" );
+ // Add the export to the zip
+ self::$content->addFromString( $dbexport, "dbexport.xml" );
// Add user data
foreach(OC_User::getUsers() as $user){
- self::addDirToZip( $datadir . '/' . $user . '/', true, "/userdata/" );
+ self::$content->addDir( $datadir . '/' . $user . '/', true, "/userdata/" );
}
break;
case 'userfiles':
+ self::$content = new OC_Migration_Content( self::$zip );
// Creates a zip with all of the users files
foreach(OC_User::getUsers() as $user){
- self::addDirToZip( $datadir . '/' . $user . '/', true, "/" );
+ self::$content->addDir( $datadir . '/' . $user . '/', true, "/" );
}
break;
case 'system':
+ self::$content = new OC_Migration_Content( self::$zip );
// Creates a zip with the owncloud system files
- self::addDirToZip( OC::$SERVERROOT . '/', false, '/');
+ self::$content->addDir( OC::$SERVERROOT . '/', false, '/');
foreach (array(".git", "3rdparty", "apps", "core", "files", "l10n", "lib", "ocs", "search", "settings", "tests") as $dir) {
- self::addDirToZip( OC::$SERVERROOT . '/' . $dir, true, "/");
+ self::$content->addDir( OC::$SERVERROOT . '/' . $dir, true, "/");
}
- break;
+ break;
+ }
+ if( !$info = self::getExportInfo( $exportdata ) ){
+ return false;
+ }
+ // Add the export info json to the export zip
+ self::$content->addFromString( $info, 'export_info.json' );
+ if( !self::$content->finish() ){
+ return false;
+ }
+ return self::$zippath;
+ }
+
+ /**
+ * @brief connects to a MDB2 database scheme
+ * @returns bool
+ */
+ static private function connectScheme(){
+ // We need a mdb2 database connection
+ self::$MDB2->loadModule( 'Manager' );
+ self::$MDB2->loadModule( 'Reverse' );
+
+ // Connect if this did not happen before
+ if( !self::$schema ){
+ require_once('MDB2/Schema.php');
+ self::$schema=MDB2_Schema::factory( self::$MDB2 );
}
- // Add export info
- self::addExportInfo();
- // Close the zip
- if( !self::closeZip() ){
- return false;
- }
- return self::$zippath;
-
+
+ return true;
}
/**
- * @breif adds a json file with infomation on the export to the zips root (used on import)
- * @return bool
- */
- static private function addExportInfo( $array=array() ){
+ * @breif creates a migration.db in the users data dir with their app data in
+ * @return bool whether operation was successfull
+ */
+ private static function exportAppData( ){
+
+ $success = true;
+ $return = array();
+
+ // Foreach provider
+ foreach( self::$providers as $provider ){
+ $success = true;
+ // Does this app use the database?
+ if( file_exists( OC::$SERVERROOT.'/apps/'.$provider->getID().'/appinfo/database.xml' ) ){
+ // Create some app tables
+ $tables = self::createAppTables( $provider->getID() );
+ if( is_array( $tables ) ){
+ // Save the table names
+ foreach($tables as $table){
+ $return['apps'][$provider->getID()]['tables'][] = $table;
+ }
+ } else {
+ // It failed to create the tables
+ $success = false;
+ }
+ }
+
+ // Run the export function?
+ if( $success ){
+ // Set the provider properties
+ $provider->setData( self::$uid, self::$content );
+ $return['apps'][$provider->getID()]['success'] = $provider->export();
+ } else {
+ $return['apps'][$provider->getID()]['success'] = false;
+ $return['apps'][$provider->getID()]['message'] = 'failed to create the app tables';
+ }
+
+ // Now add some app info the the return array
+ $appinfo = OC_App::getAppInfo( $provider->getID() );
+ $return['apps'][$provider->getID()]['version'] = $appinfo['version'];
+
+ }
+
+ return $return;
+
+ }
+
+
+ /**
+ * @breif generates json containing export info, and merges any data supplied
+ * @param optional $array array of data to include in the returned json
+ * @return bool
+ */
+ static private function getExportInfo( $array=array() ){
$info = array(
'ocversion' => OC_Util::getVersion(),
'exporttime' => time(),
@@ -216,11 +267,12 @@ class OC_Migrate{
'exporttype' => self::$exporttype
);
// Add hash if user export
- if( self::$exporttype = 'user' ){
+ if( self::$exporttype == 'user' ){
$query = OC_DB::prepare( "SELECT password FROM *PREFIX*users WHERE uid LIKE ?" );
$result = $query->execute( array( self::$uid ) );
$row = $result->fetchRow();
$hash = $row ? $row['password'] : false;
+ die(var_dump($hash));
if( !$hash ){
OC_Log::write( 'migration', 'Failed to get the users password hash', OC_log::ERROR);
return false;
@@ -228,110 +280,122 @@ class OC_Migrate{
$info['hash'] = $hash;
$info['exporteduser'] = self::$uid;
}
+ if( !is_array( $array ) ){
+ OC_Log::write( 'migration', 'Supplied $array was not an array in getExportInfo()', OC_Log::ERROR );
+ }
// Merge in other data
- $info = array_merge( $info, $array );
+ $info = array_merge( $info, (array)$array );
// Create json
$json = json_encode( $info );
- $tmpfile = tempnam("/tmp", "oc_export_info_");
- self::$tmpfiles[] = $tmpfile;
- if( !file_put_contents( $tmpfile, $json ) ){
- return false;
- } else {
- self::$zip->addFile( $tmpfile, "/" . self::$uid . "/export_info.json" );
- return true;
- }
- }
-
-
- /**
- * @breif tried to finalise the zip
- * @return bool
- */
- static private function closeZip(){
- if( !self::$zip->close() ){
- OC_Log::write('migration', 'Failed to save the zip with error: '.self::$zip->getStatusString(), OC_Log::ERROR);
- self::cleanup();
- return false;
- } else {
- OC_Log::write('migration', 'Export zip created ok', OC_Log::INFO);
- self::cleanup();
- return true;
- }
+ return true;
}
/**
- * @breif cleans up after the zip
- */
- static private function cleanup(){
- // Delete tmp files
- foreach(self::$tmpfiles as $i){
- unlink( $i );
- }
- }
-
- /**
- * @breif creates a zip user export
- * @param optional $uid string user id of the user to export (defaults to current)
- * @param optional $path string path to folder to create file in (with trailing slash) (defaults to current user's data dir)
- * @return false on failure | string path on success
- */
- static public function createUserExportFile( $uid=null, $path=null ){
- // User passed?
- $uid = is_null( $uid ) ? OC_User::getUser() : $uid ;
- // Is a database user?
- if( !OC_User_Database::userExists( $uid ) ){
- OC_Log::write('migration', 'User: '.$uid.' is not in the database and so cannot be exported.', OC_Log::ERROR);
+ * @breif connects to migration.db, or creates if not found
+ * @param $db optional path to migration.db, defaults to user data dir
+ * @return bool whether the operation was successful
+ */
+ static private function connectDB( $path=null ){
+ // Has the dbpath been set?
+ self::$dbpath = !is_null( $path ) ? $path : self::$dbpath;
+ if( !self::$dbpath ){
+ OC_Log::write( 'migration', 'connectDB() was called without dbpath being set', OC_Log::ERROR );
return false;
}
- // Set the uid
- self::$uid = $uid;
- // Create the zip object
- self::$zip = new ZipArchive;
- // Set export type
- self::$exporttype = 'user';
- // Calculate users data dir
- $user = OC_User::getUser();
- $userdatadir = OC_Config::getValue( 'datadirectory' ) . '/' . $user . '/';
- // Calculate zip name
- $zipname = "oc_userexport_" . $user . '_' . date("y-m-d_H-i-s") . ".zip";
- // Calculate destination
- if( !is_null( $path ) ){
- // Path given
- // Is a directory?
- if( !is_dir( $path ) ){
- OC_Log::write('migration', 'Path supplied to createUserExportFile() is not a directory', OC_Log::ERROR);
- return false;
- }
- // Is writeable
- if( !is_writeable( $path ) ){
- OC_Log::write('migration', 'Path supplied to createUserExportFile() is not writeable', OC_Log::ERROR);
+ // Already connected
+ if(!self::$MDB2){
+ require_once('MDB2.php');
+
+ $datadir = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" );
+
+ // Prepare options array
+ $options = array(
+ 'portability' => MDB2_PORTABILITY_ALL & (!MDB2_PORTABILITY_FIX_CASE),
+ 'log_line_break' => ' ',
+ 'idxname_format' => '%s',
+ 'debug' => true,
+ 'quote_identifier' => true
+ );
+ $dsn = array(
+ 'phptype' => 'sqlite3',
+ 'database' => self::$dbpath,
+ 'mode' => '0644'
+ );
+
+ // Try to establish connection
+ self::$MDB2 = MDB2::factory( $dsn, $options );
+ // Die if we could not connect
+ if( PEAR::isError( self::$MDB2 ) ){
+ die( self::$MDB2->getMessage() );
+ OC_Log::write( 'migration', 'Failed to create/connect to migration.db', OC_Log::FATAL );
+ OC_Log::write( 'migration', self::$MDB2->getUserInfo(), OC_Log::FATAL );
+ OC_Log::write( 'migration', self::$MDB2->getMessage(), OC_Log::FATAL );
return false;
}
- self::$zippath = $path . $zipname;
- } else {
- // Save in users data dir
- self::$zippath = $userdatadir . $zipname;
+ // We always, really always want associative arrays
+ self::$MDB2->setFetchMode(MDB2_FETCHMODE_ASSOC);
}
- // Try to create the zip
- if( !self::createZip() ){
- return false;
- }
- // Export the app info
- $appinfo = self::exportAppData();
- // Save the migration results
- self::addExportInfo( $appinfo );
- // Add the data dir to the zip
- self::addDirToZip( $userdatadir );
- // Close the zip
- if( !self::closeZip() ){
- return false;
- }
- // All good
- return self::$zippath;
- }
+ return true;
+
+ }
+ /**
+ * @breif creates the tables in migration.db from an apps database.xml
+ * @param $appid string id of the app
+ * @return bool whether the operation was successful
+ */
+ static private function createAppTables( $appid ){
+
+ if( !self::connectScheme() ){
+ return false;
+ }
+
+ // There is a database.xml file
+ $content = file_get_contents( OC::$SERVERROOT . '/apps/' . $appid . '/appinfo/database.xml' );
+
+ $file2 = 'static://db_scheme';
+ // TODO get the relative path to migration.db from the data dir
+ // For now just cheat
+ $path = pathinfo( self::$dbpath );
+ $content = str_replace( '*dbname*', self::$uid.'/migration', $content );
+ $content = str_replace( '*dbprefix*', '', $content );
+
+ $xml = new SimpleXMLElement($content);
+ foreach($xml->table as $table){
+ $tables[] = (string)$table->name;
+ }
+
+ file_put_contents( $file2, $content );
+
+ // Try to create tables
+ $definition = self::$schema->parseDatabaseDefinitionFile( $file2 );
+
+ unlink( $file2 );
+
+ // Die in case something went wrong
+ if( $definition instanceof MDB2_Schema_Error ){
+ OC_Log::write( 'migration', 'Failed to parse database.xml for: '.$appid, OC_Log::FATAL );
+ OC_Log::write( 'migration', $definition->getMessage().': '.$definition->getUserInfo(), OC_Log::FATAL );
+ return false;
+ }
+
+ $definition['overwrite'] = true;
+
+ $ret = self::$schema->createDatabase( $definition );
+
+ // Die in case something went wrong
+ if( $ret instanceof MDB2_Error ){
+ OC_Log::write( 'migration', 'Failed to create tables for: '.$appid, OC_Log::FATAL );
+ OC_Log::write( 'migration', $ret->getMessage().': '.$ret->getUserInfo(), OC_Log::FATAL );
+ return false;
+ }
+ return $tables;
+
+ }
+
/**
* @breif tries to create the zip
+ * @param $path string path to zip destination
* @return bool
*/
static private function createZip(){
@@ -340,45 +404,13 @@ class OC_Migrate{
OC_Log::write('migration', 'createZip() called but $zip and/or $zippath have not been set', OC_Log::ERROR);
return false;
}
- if ( self::$zip->open( self::$zippath, ZIPARCHIVE::CREATE ) !== TRUE ) {
+ if ( self::$zip->open( self::$zippath, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE ) !== TRUE ) {
OC_Log::write('migration', 'Failed to create the zip with error: '.self::$zip->getStatusString(), OC_Log::ERROR);
return false;
} else {
return true;
}
}
-
- /**
- * @breif adds a directory to the zip object
- * @param $dir string path of the directory to add
- * @param $recursive bool
- * @param $internaldir string path of folder to add dir to in zip
- * @return bool
- */
- static private function addDirToZip($dir, $recursive=true, $internaldir='') {
- $dirname = basename($dir);
- self::$zip->addEmptyDir($internaldir . $dirname);
- $internaldir.=$dirname.='/';
-
- if ($dirhandle = opendir($dir)) {
- while (false !== ( $file = readdir($dirhandle))) {
-
- if (( $file != '.' ) && ( $file != '..' )) {
-
- if (is_dir($dir . '/' . $file) && $recursive) {
- self::addDirToZip($dir . '/' . $file, $recursive, $internaldir);
- } elseif (is_file($dir . '/' . $file)) {
- self::$zip->addFile($dir . '/' . $file, $internaldir . $file);
- }
- }
- }
- closedir($dirhandle);
- } else {
- OC_Log::write('admin_export',"Was not able to open directory: " . $dir,OC_Log::ERROR);
- return false;
- }
- return true;
- }
/**
* @breif returns an array of apps that support migration
@@ -429,10 +461,17 @@ class OC_Migrate{
foreach( self::$providers as $provider){
// Is the app in the export?
- $id = $provider->id;
+ $id = $provider->getID();
if( isset( $info->apps->$id ) ){
// Did it succeed?
if( $info->apps->$id->success ){
+ // Give the provider the content object
+ // TODO PASS THE PATH TO MIGRATION.DB
+ if( !self::connectDB() ){
+ return false;
+ }
+ $content = new OC_Migration_Content( self::$zip, self::$db );
+ $provider->setObject( $content );
// Then do the import
$provider->import( $info->apps->$id, $importinfo );
}
@@ -443,252 +482,12 @@ class OC_Migrate{
}
- // @breif connects to migration.db, or creates if not found
- // @param $db optional path to migration.db, defaults to user data dir
- // @return bool whether the operation was successful
- private static function connectDB( $dbpath=null ){
- OC_Log::write('migration','connecting to migration.db for user: '.self::$uid,OC_Log::INFO);
- // Fail if no user is set
- if(!self::$uid){
- OC_Log::write('migration','connectDB() called without self::$uid being set',OC_Log::INFO);
- return false;
- }
- // Already connected
- if(!self::$MDB2){
- require_once('MDB2.php');
-
- $datadir = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" );
-
- self::$dbpath = $datadir.'/'.self::$uid.'/migration.db';//!is_null( $dbpath ) ? $dbpath : $datadir.'/'.self::$uid.'/migration.db';
-
- // Prepare options array
- $options = array(
- 'portability' => MDB2_PORTABILITY_ALL & (!MDB2_PORTABILITY_FIX_CASE),
- 'log_line_break' => ' ',
- 'idxname_format' => '%s',
- 'debug' => true,
- 'quote_identifier' => true
- );
- $dsn = array(
- 'phptype' => 'sqlite3',
- 'database' => self::$dbpath,
- 'mode' => '0644'
- );
-
- // Try to establish connection
- self::$MDB2 = MDB2::factory( $dsn, $options );
- // Die if we could not connect
- if( PEAR::isError( self::$MDB2 )){
- die(self::$MDB2->getMessage());
- OC_Log::write('migration', 'Failed to create/connect to migration.db',OC_Log::FATAL);
- OC_Log::write('migration',self::$MDB2->getUserInfo(),OC_Log::FATAL);
- OC_Log::write('migration',self::$MDB2->getMessage(),OC_Log::FATAL);
- return false;
- } else {
- }
- // We always, really always want associative arrays
- self::$MDB2->setFetchMode(MDB2_FETCHMODE_ASSOC);
- }
- return true;
-
- }
-
- // @breif prepares the db
- // @param $query the sql query to prepare
- public static function prepare( $query ){
-
- // Optimize the query
- $query = self::processQuery( $query );
-
- // Optimize the query
- $query = self::$MDB2->prepare( $query );
-
- // Die if we have an error (error means: bad query, not 0 results!)
- if( PEAR::isError( $query )) {
- $entry = 'DB Error: "'.$result->getMessage().'" ';
- $entry .= 'Offending command was: '.$query.' ';
- OC_Log::write('migration',$entry,OC_Log::FATAL);
- return false;
- } else {
- return $query;
- }
-
- }
-
- // @breif processes the db query
- // @param $query the query to process
- // @return string of processed query
- private static function processQuery( $query ){
-
- self::connectDB();
- $prefix = '';
-
- $query = str_replace( '`', '\'', $query );
- $query = str_replace( 'NOW()', 'datetime(\'now\')', $query );
- $query = str_replace( 'now()', 'datetime(\'now\')', $query );
-
- // replace table name prefix
- $query = str_replace( '*PREFIX*', $prefix, $query );
-
- return $query;
-
- }
-
- // @brief copys rows to migration.db from the main database
- // @param $options array of options.
- // @return bool
- public static function copyRows( $options ){
- if( !array_key_exists( 'table', $options ) ){
- return false;
- }
-
- $return = array();
-
- // Need to include 'where' in the query?
- if( array_key_exists( 'matchval', $options ) && array_key_exists( 'matchcol', $options ) ){
-
- // If only one matchval, create an array
- if(!is_array($options['matchval'])){
- $options['matchval'] = array( $options['matchval'] );
- }
-
- foreach( $options['matchval'] as $matchval ){
- // Run the query for this match value (where x = y value)
- $query = OC_DB::prepare( "SELECT * FROM *PREFIX*" . $options['table'] . " WHERE " . $options['matchcol'] . " LIKE ?" );
- $results = $query->execute( array( $matchval ) );
- $newreturns = self::insertData( $results, $options );
- $return = array_merge( $return, $newreturns );
- }
-
- } else {
- // Just get everything
- $query = OC_DB::prepare( "SELECT * FROM *PREFIX*" . $options['table'] );
- $results = $query->execute();
- $return = self::insertData( $results, $options );
-
- }
-
- return $return;
-
- }
-
- // @breif saves a sql data set into migration.db
- // @param $data a sql data set returned from self::prepare()->query()
- // @param $options array of copyRows options
- // @return void
- private static function insertData( $data, $options ){
- $return = array();
- while( $row = $data->fetchRow() ){
- // Now save all this to the migration.db
- $fields = array();
- $values = array();
- foreach($row as $field=>$value){
- $fields[] = $field;
- $values[] = $value;
- }
-
- // Generate some sql
- $sql = "INSERT INTO `" . $options['table'] . '` ( `';
- $fieldssql = implode( '`, `', $fields );
- $sql .= $fieldssql . "` ) VALUES( ";
- $valuessql = substr( str_repeat( '?, ', count( $fields ) ),0,-2 );
- $sql .= $valuessql . " )";
- // Make the query
- $query = self::prepare( $sql );
- if(!$query){
- OC_Log::write('migration','Invalid sql produced: '.$sql,OC_Log::FATAL);
- return false;
- exit();
- } else {
- $query->execute( $values );
- // Do we need to return some values?
- if( array_key_exists( 'idcol', $options ) ){
- // Yes we do
- $return[] = $row[$options['idcol']];
- } else {
- // Take a guess and return the first field :)
- $return[] = reset($row);
- }
- }
- }
- return $return;
- }
-
- // @breif creates the tables in migration.db from an apps database.xml
- // @param $appid string id of the app
- // @return bool whether the operation was successful
- private static function createAppTables( $appid ){
-
- if(!self::connectScheme()){
- return false;
- }
-
- // There is a database.xml file
- $content = file_get_contents( OC::$SERVERROOT . '/apps/' . $appid . '/appinfo/database.xml' );
-
- $file2 = 'static://db_scheme';
- $content = str_replace( '*dbname*', self::$uid.'/migration', $content );
- $content = str_replace( '*dbprefix*', '', $content );
-
- $xml = new SimpleXMLElement($content);
- foreach($xml->table as $table){
- $tables[] = (string)$table->name;
- }
-
- file_put_contents( $file2, $content );
-
- // Try to create tables
- $definition = self::$schema->parseDatabaseDefinitionFile( $file2 );
-
- unlink( $file2 );
-
- // Die in case something went wrong
- if( $definition instanceof MDB2_Schema_Error ){
- OC_Log::write('migration','Failed to parse database.xml for: '.$appid,OC_Log::FATAL);
- OC_Log::write('migration',$definition->getMessage().': '.$definition->getUserInfo(),OC_Log::FATAL);
- return false;
- }
-
- $definition['overwrite'] = true;
-
- $ret = self::$schema->createDatabase( $definition );
- // Die in case something went wrong
-
- if( $ret instanceof MDB2_Error ){
- OC_Log::write('migration','Failed to create tables for: '.$appid,OC_Log::FATAL);
- OC_Log::write('migration',$ret->getMessage().': '.$ret->getUserInfo(),OC_Log::FATAL);
- return false;
- }
- return $tables;
-
- }
-
-
- /**
- * @brief connects to a MDB2 database scheme
- * @returns true/false
- *
- * Connects to a MDB2 database scheme
- */
- private static function connectScheme(){
- // We need a mdb2 database connection
- self::connectDB();
- self::$MDB2->loadModule( 'Manager' );
- self::$MDB2->loadModule( 'Reverse' );
-
- // Connect if this did not happen before
- if( !self::$schema ){
- require_once('MDB2/Schema.php');
- self::$schema=MDB2_Schema::factory( self::$MDB2 );
- }
-
- return true;
- }
-
- // @breif creates a new user in the database
- // @param $uid string user_id of the user to be created
- // @param $hash string hash of the user to be created
- // @return bool result of user creation
+ /*
+ * @breif creates a new user in the database
+ * @param $uid string user_id of the user to be created
+ * @param $hash string hash of the user to be created
+ * @return bool result of user creation
+ */
public static function createUser( $uid, $hash ){
// Check if userid exists
diff --git a/lib/migrate/provider.php b/lib/migrate/provider.php
deleted file mode 100644
index 7ac3cf97ca..0000000000
--- a/lib/migrate/provider.php
+++ /dev/null
@@ -1,28 +0,0 @@
-id = $appid;
- OC_Migrate::registerProvider( $this );
- }
-
- /**
- * @breif exports data for apps
- * @param string $uid
- * @return array appdata to be exported
- */
- abstract function export($uid);
-
- /**
- * @breif imports data for the app
- * @param $appinfo object with the data that the app exported
- * @param $info array of info including exportinfo.json
- * @return void
- */
- abstract function import( $appinfo, $info );
-}
diff --git a/lib/migration/content.php b/lib/migration/content.php
new file mode 100644
index 0000000000..fe8a21a45b
--- /dev/null
+++ b/lib/migration/content.php
@@ -0,0 +1,239 @@
+.
+ *
+ */
+
+
+/**
+ * provides methods to add and access data from the migration
+ */
+class OC_Migration_Content{
+
+ private $zip=false;
+ // Holds the MDB2 object
+ private $db=false;
+ // Holds an array of tmpfiles to delete after zip creation
+ private $tmpfiles=false;
+
+ /**
+ * @breif sets up the
+ * @param $zip ZipArchive object
+ * @param optional $db a MDB2 database object (required for exporttype user)
+ * @return bool
+ */
+ public function __construct( $zip, $db=false ){
+
+ $this->zip = $zip;
+ $this->db = $db;
+
+ }
+
+ // @breif prepares the db
+ // @param $query the sql query to prepare
+ public function prepare( $query ){
+
+ // Optimize the query
+ $query = $this->processQuery( $query );
+
+ // Optimize the query
+ $query = $this->MDB2->prepare( $query );
+
+ // Die if we have an error (error means: bad query, not 0 results!)
+ if( PEAR::isError( $query ) ) {
+ $entry = 'DB Error: "'.$result->getMessage().'" ';
+ $entry .= 'Offending command was: '.$query.' ';
+ OC_Log::write( 'migration', $entry, OC_Log::FATAL );
+ return false;
+ } else {
+ return $query;
+ }
+
+ }
+
+ /**
+ * @breif processes the db query
+ * @param $query the query to process
+ * @return string of processed query
+ */
+ private function processQuery( $query ){
+ $query = str_replace( '`', '\'', $query );
+ $query = str_replace( 'NOW()', 'datetime(\'now\')', $query );
+ $query = str_replace( 'now()', 'datetime(\'now\')', $query );
+ // remove table prefixes
+ $query = str_replace( '*PREFIX*', '', $query );
+ return $query;
+ }
+
+ /**
+ * @brief copys rows to migration.db from the main database
+ * @param $options array of options.
+ * @return bool
+ */
+ public function copyRows( $options ){
+ if( !array_key_exists( 'table', $options ) ){
+ return false;
+ }
+
+ $return = array();
+
+ // Need to include 'where' in the query?
+ if( array_key_exists( 'matchval', $options ) && array_key_exists( 'matchcol', $options ) ){
+
+ // If only one matchval, create an array
+ if(!is_array($options['matchval'])){
+ $options['matchval'] = array( $options['matchval'] );
+ }
+
+ foreach( $options['matchval'] as $matchval ){
+ // Run the query for this match value (where x = y value)
+ $query = OC_DB::prepare( "SELECT * FROM *PREFIX*" . $options['table'] . " WHERE " . $options['matchcol'] . " LIKE ?" );
+ $results = $query->execute( array( $matchval ) );
+ $newreturns = $this->insertData( $results, $options );
+ $return = array_merge( $return, $newreturns );
+ }
+
+ } else {
+ // Just get everything
+ $query = OC_DB::prepare( "SELECT * FROM *PREFIX*" . $options['table'] );
+ $results = $query->execute();
+ $return = $this->insertData( $results, $options );
+
+ }
+
+ return $return;
+
+ }
+
+ /**
+ * @breif saves a sql data set into migration.db
+ * @param $data a sql data set returned from self::prepare()->query()
+ * @param $options array of copyRows options
+ * @return void
+ */
+ private function insertData( $data, $options ){
+ $return = array();
+ while( $row = $data->fetchRow() ){
+ // Now save all this to the migration.db
+ foreach($row as $field=>$value){
+ $fields[] = $field;
+ $values[] = $value;
+ }
+
+ // Generate some sql
+ $sql = "INSERT INTO `" . $options['table'] . '` ( `';
+ $fieldssql = implode( '`, `', $fields );
+ $sql .= $fieldssql . "` ) VALUES( ";
+ $valuessql = substr( str_repeat( '?, ', count( $fields ) ),0,-2 );
+ $sql .= $valuessql . " )";
+ // Make the query
+ $query = $this->prepare( $sql );
+ if( !$query ){
+ OC_Log::write( 'migration', 'Invalid sql produced: '.$sql, OC_Log::FATAL );
+ return false;
+ exit();
+ } else {
+ $query->execute( $values );
+ // Do we need to return some values?
+ if( array_key_exists( 'idcol', $options ) ){
+ // Yes we do
+ $return[] = $row[$options['idcol']];
+ } else {
+ // Take a guess and return the first field :)
+ $return[] = reset($row);
+ }
+ }
+ }
+ return $return;
+ }
+
+ /**
+ * @breif adds a directory to the zip object
+ * @param $dir string path of the directory to add
+ * @param $recursive bool
+ * @param $internaldir string path of folder to add dir to in zip
+ * @return bool
+ */
+ public function addDir( $dir, $recursive=true, $internaldir='' ) {
+ $dirname = basename($dir);
+ $this->zip->addEmptyDir($internaldir . $dirname);
+ $internaldir.=$dirname.='/';
+
+ if ($dirhandle = opendir($dir)) {
+ while (false !== ( $file = readdir($dirhandle))) {
+
+ if (( $file != '.' ) && ( $file != '..' )) {
+
+ if (is_dir($dir . '/' . $file) && $recursive) {
+ $this->addDir($dir . '/' . $file, $recursive, $internaldir);
+ } elseif (is_file($dir . '/' . $file)) {
+ $this->zip->addFile($dir . '/' . $file, $internaldir . $file);
+ }
+ }
+ }
+ closedir($dirhandle);
+ } else {
+ OC_Log::write('admin_export',"Was not able to open directory: " . $dir,OC_Log::ERROR);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @breif adds a file to the zip from a given string
+ * @param $data string of data to add
+ * @param $path the relative path inside of the zip to save the file to
+ * @return bool
+ */
+ public function addFromString( $data, $path ){
+ // Create a temp file
+ $file = tempnam( get_temp_dir(). '/', 'oc_export_tmp_' );
+ $this->tmpfiles[] = $file;
+ if( !file_put_contents( $file, $data ) ){
+ OC_Log::write( 'migation', 'Failed to save data to a temporary file', OC_Log::ERROR );
+ return false;
+ }
+ // Add file to the zip
+ $this->zip->addFile( $file, $path );
+ return true;
+ }
+
+ /**
+ * @breif closes the zip, removes temp files
+ * @return bool
+ */
+ public function finish(){
+ if( !$this->zip->close() ){
+ OC_Log::write( 'migration', 'Failed to write the zip file with error: '.$this->zip->getStatusString(), OC_Log::ERROR );
+ return false;
+ }
+ $this->cleanup();
+ return true;
+ }
+
+ /**
+ * @breif cleans up after the zip
+ */
+ private function cleanup(){
+ // Delete tmp files
+ foreach($this->tmpfiles as $i){
+ unlink( $i );
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/migration/provider.php b/lib/migration/provider.php
new file mode 100644
index 0000000000..b9e2c47620
--- /dev/null
+++ b/lib/migration/provider.php
@@ -0,0 +1,49 @@
+id = $appid;
+ OC_Migrate::registerProvider( $this );
+ }
+
+ /**
+ * @breif exports data for apps
+ * @return array appdata to be exported
+ */
+ abstract function export( );
+
+ /**
+ * @breif imports data for the app
+ * @return void
+ */
+ abstract function import( );
+
+ /**
+ * @breif sets the OC_Migration_Content object to $this->content
+ * @param $content a OC_Migration_Content object
+ */
+ public function setData( $uid, $content, $info=false, $appinfo=false ){
+ $this->content = $content;
+ $this->uid = $uid;
+ $this->info = $info;
+ $this->appinfo = $appinfo;
+ }
+
+ /**
+ * @breif returns the appid of the provider
+ * @return string
+ */
+ public function getID(){
+ return $this->id;
+ }
+}
From 514c9ad8e7df1d7882adc33c42eb32a209537273 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Tue, 20 Mar 2012 20:19:21 +0000
Subject: [PATCH 044/133] Added unified import method.
---
apps/admin_export/settings.php | 10 +-
apps/bookmarks/lib/migrate.php | 10 +-
apps/user_migrate/admin.php | 18 +---
lib/db.php | 7 +-
lib/migrate.php | 188 +++++++++++++++++++++++++++++++--
lib/migration/content.php | 6 +-
lib/migration/provider.php | 10 +-
7 files changed, 206 insertions(+), 43 deletions(-)
diff --git a/apps/admin_export/settings.php b/apps/admin_export/settings.php
index af8dd0dbf5..cd85bedcd7 100644
--- a/apps/admin_export/settings.php
+++ b/apps/admin_export/settings.php
@@ -25,8 +25,6 @@
OC_Util::checkAdminUser();
OC_Util::checkAppEnabled('admin_export');
-define('DS', '/');
-
// Export?
if (isset($_POST['admin_export'])) {
// Create the export zip
@@ -44,9 +42,11 @@ if (isset($_POST['admin_export'])) {
}
// Import?
} else if( isset($_POST['admin_import']) ){
-
- // TODO
- // OC_Migrate::import( $pathtozipfile );
+ $from = $_FILES['owncloud_import']['tmp_name'];
+
+ if( !OC_Migrate::import( $from ) ){
+ die('failed');
+ }
} else {
// fill template
diff --git a/apps/bookmarks/lib/migrate.php b/apps/bookmarks/lib/migrate.php
index 36a08c0cf4..02c96e5963 100644
--- a/apps/bookmarks/lib/migrate.php
+++ b/apps/bookmarks/lib/migrate.php
@@ -36,19 +36,19 @@ class OC_Migration_Provider_Bookmarks extends OC_Migration_Provider{
switch( $this->appinfo->version ){
default:
// All versions of the app have had the same db structure, so all can use the same import function
- $query = OC_Migrate::prepare( "SELECT * FROM bookmarks WHERE user_id LIKE ?" );
- $results = $query->execute( array( $this->info['olduid'] ) );
+ $query = $this->content->prepare( "SELECT * FROM bookmarks WHERE user_id LIKE ?" );
+ $results = $query->execute( array( $this->olduid ) );
$idmap = array();
- while( $row = $data->fetchRow() ){
+ while( $row = $results->fetchRow() ){
// Import each bookmark, saving its id into the map
$query = OC_DB::prepare( "INSERT INTO *PREFIX*bookmarks(url, title, user_id, public, added, lastmodified) VALUES (?, ?, ?, ?, ?, ?)" );
- $query->execute( array( $row['url'], $row['title'], $this->info['newuid'], $row['public'], $row['added'], $row['lastmodified'] ) );
+ $query->execute( array( $row['url'], $row['title'], $this->uid, $row['public'], $row['added'], $row['lastmodified'] ) );
// Map the id
$idmap[$row['id']] = OC_DB::insertid();
}
// Now tags
foreach($idmap as $oldid => $newid){
- $query = OC_Migrate::prepare( "SELECT * FROM bookmarks_tags WHERE user_id LIKE ?" );
+ $query = $this->content->prepare( "SELECT * FROM bookmarks_tags WHERE user_id LIKE ?" );
$results = $query->execute( array( $oldid ) );
while( $row = $data->fetchRow() ){
// Import the tags for this bookmark, using the new bookmark id
diff --git a/apps/user_migrate/admin.php b/apps/user_migrate/admin.php
index 6f3565788e..d54bd6965b 100644
--- a/apps/user_migrate/admin.php
+++ b/apps/user_migrate/admin.php
@@ -36,24 +36,12 @@ if (isset($_POST['user_import'])) {
$from = $_FILES['owncloud_import']['tmp_name'];
$to = get_temp_dir().'/'.$importname.'.zip';
if( !move_uploaded_file( $from, $to ) ){
- OC_Log::write('migration',"Failed to copy the uploaded file",OC_Log::INFO);
+ OC_Log::write( 'user_migrate', "Failed to copy the uploaded file", OC_Log::ERROR );
exit();
}
- // Extract zip
- $zip = new ZipArchive();
- if ($zip->open(get_temp_dir().'/'.$importname.'.zip') != TRUE) {
- OC_Log::write('migration',"Failed to open zip file",OC_Log::INFO);
- exit();
- }
- $zip->extractTo(get_temp_dir().'/'.$importname.'/');
- $zip->close();
-
- $importdir = get_temp_dir() . '/' . $importname;
-
- // Delete uploaded file
- unlink( $importdir . '.zip' );
-
+ OC_Migrate::import( $to, 'user', 'newuser' );
+ die();
// Find folder
$files = scandir( $importdir );
unset($files[0]);
diff --git a/lib/db.php b/lib/db.php
index 07e5859096..bfcff67869 100644
--- a/lib/db.php
+++ b/lib/db.php
@@ -487,6 +487,7 @@ class OC_DB {
/**
* @breif replaces the owncloud tables with a new set
+ * @param $file string path to the MDB2 xml db export file
*/
public static function replaceDB( $file ){
@@ -503,7 +504,11 @@ class OC_DB {
}
// Create new tables
- self::createDBFromStructure( $file );
+ if( self::createDBFromStructure( $file ) ){
+ return true;
+ } else {
+ return false;
+ }
}
diff --git a/lib/migrate.php b/lib/migrate.php
index 338d091af8..0058de7391 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -122,7 +122,6 @@ class OC_Migrate{
}
}
// Create the zip object
- self::$zip = new ZipArchive;
if( !self::createZip() ){
return false;
}
@@ -188,6 +187,177 @@ class OC_Migrate{
return self::$zippath;
}
+ /**
+ * @breif imports a user, or owncloud instance
+ * @param $path string path to zip
+ * @param optional $uid userid of new user
+ */
+ public static function import( $path, $uid=null ){
+ OC_Util::checkAdminUser();
+ $datadir = OC_Config::getValue( 'datadirectory' );
+ // Extract the zip
+ if( !$extractpath = self::extractZip( $path ) ){
+ return false;
+ }
+ // Get export_info.json
+ $scan = scandir( $extractpath );
+ // Check for export_info.json
+ if( !in_array( 'export_info.json', $scan ) ){
+ OC_Log::write( 'migration', 'Invalid import file, export_info.json note found', OC_Log::ERROR );
+ return false;
+ }
+ $json = json_decode( file_get_contents( $extractpath . 'export_info.json' ) );
+ self::$exporttype = $json->exporttype;
+
+ // Have we got a user if type is user
+ if( self::$exporttype == 'user' ){
+ if( !$uid ){
+ self::$uid = $json->exporteduser;
+ } else {
+ self::$uid = $uid;
+ }
+ }
+
+ // Handle export types
+ switch( self::$exporttype ){
+ case 'user':
+ // Check user availability
+ if( OC_User::userExists( self::$uid ) ){
+ OC_Log::write( 'migration', 'User already exists', OC_Log::ERROR );
+ return false;
+ }
+ // Create the user
+ if( !self::createUser( self::$uid, $json->hash ) ){
+ return false;
+ }
+ // Make the new users data dir
+ $path = $datadir . '/' . self::$uid . '/files/';
+ if( !mkdir( $path, 0755, true ) ){
+ OC_Log::write( 'migration', 'Failed to create users data dir: '.$path, OC_Log::ERROR );
+ return false;
+ }
+ // Copy data
+ if( !self::copy_r( $extractpath . $json->exporteduser . '/files', $datadir . '/' . self::$uid . '/files' ) ){
+ return false;
+ }
+ // Import user app data
+ if( !self::importAppData( $extractpath . $json->exporteduser . '/migration.db', $json, self::$uid ) ){
+ return false;
+ }
+ // All done!
+ if( !self::unlink_r( $extractpath ) ){
+ OC_Log::write( 'migration', 'Failed to delete the extracted zip', OC_Log::ERROR );
+ }
+ return true;
+ break;
+ case 'instance':
+ // Check for new data dir and dbexport before doing anything
+ // TODO
+ /*
+ // Delete current data folder.
+ OC_Log::write( 'migration', "Deleting current data dir", OC_Log::INFO );
+ if( self::unlink_r( $datadir, false ) ){
+ OC_Log::write( 'migration', 'Failed to delete the current data dir', OC_Log::ERROR );
+ return false;
+ }
+
+ // Copy over data
+ if( !self::copy_r( $extractname . 'data', $datadir ) ){
+ OC_Log::write( 'migration', 'Failed to copy over data directory', OC_Log::ERROR );
+ return false;
+ }
+ */
+ // Import the db
+ if( !OC_DB::replaceDB( $extractpath . 'dbexport.xml' ) ){
+ return false;
+ }
+ // Done
+ return true;
+ break;
+ }
+
+ }
+
+ /**
+ * @breif recursively deletes a directory
+ * @param $dir string path of dir to delete
+ * $param optional $deleteRootToo bool delete the root directory
+ * @return bool
+ */
+ private static function unlink_r( $dir, $deleteRootToo=true ){
+ if( !$dh = @opendir( $dir ) ){
+ return false;
+ }
+ while (false !== ($obj = readdir($dh))){
+ if($obj == '.' || $obj == '..') {
+ continue;
+ }
+ if (!@unlink($dir . '/' . $obj)){
+ self::unlink_r($dir.'/'.$obj, true);
+ }
+ }
+ closedir($dh);
+ if ( $deleteRootToo ) {
+ @rmdir($dir);
+ }
+ return true;
+ }
+
+ /**
+ * @breif copies recursively
+ * @param $path string path to source folder
+ * @param $dest string path to destination
+ * @return bool
+ */
+ private static function copy_r( $path, $dest ){
+ if( is_dir($path) ){
+ @mkdir( $dest );
+ $objects = scandir( $path );
+ if( sizeof( $objects ) > 0 ){
+ foreach( $objects as $file ){
+ if( $file == "." || $file == ".." )
+ continue;
+ // go on
+ if( is_dir( $path . '/' . $file ) ){
+ self::copy_r( $path .'/' . $file, $dest . '/' . $file );
+ } else {
+ copy( $path . '/' . $file, $dest . '/' . $file );
+ }
+ }
+ }
+ return true;
+ }
+ elseif( is_file( $path ) ){
+ return copy( $path, $dest );
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @breif tries to extract the import zip
+ * @param $path string path to the zip
+ * @return string path to extract location (with a trailing slash) or false on failure
+ */
+ static private function extractZip( $path ){
+ self::$zip = new ZipArchive;
+ // Validate path
+ if( !file_exists( $path ) ){
+ OC_Log::write( 'migration', 'Zip not found', OC_Log::ERROR );
+ return false;
+ }
+ if ( self::$zip->open( $path ) != TRUE ) {
+ OC_Log::write( 'migration', "Failed to open zip file", OC_Log::ERROR );
+ return false;
+ }
+ $to = get_temp_dir() . '/oc_import_' . self::$exporttype . '_' . date("y-m-d_H-i-s") . '/';
+ if( !self::$zip->extractTo( $to ) ){
+ return false;
+ }
+ self::$zip->close();
+ return $to;
+ }
+
/**
* @brief connects to a MDB2 database scheme
* @returns bool
@@ -272,7 +442,6 @@ class OC_Migrate{
$result = $query->execute( array( self::$uid ) );
$row = $result->fetchRow();
$hash = $row ? $row['password'] : false;
- die(var_dump($hash));
if( !$hash ){
OC_Log::write( 'migration', 'Failed to get the users password hash', OC_log::ERROR);
return false;
@@ -287,7 +456,7 @@ class OC_Migrate{
$info = array_merge( $info, (array)$array );
// Create json
$json = json_encode( $info );
- return true;
+ return $json;
}
/**
@@ -399,8 +568,9 @@ class OC_Migrate{
* @return bool
*/
static private function createZip(){
+ self::$zip = new ZipArchive;
// Check if properties are set
- if( !self::$zip || !self::$zippath ){
+ if( !self::$zippath ){
OC_Log::write('migration', 'createZip() called but $zip and/or $zippath have not been set', OC_Log::ERROR);
return false;
}
@@ -435,9 +605,6 @@ class OC_Migrate{
* @return bool if the import succedded
*/
public static function importAppData( $db, $info, $uid=null ){
-
- self::$uid = !is_null( $uid ) ? $uid : $info->exporteduser;
-
// Check if the db exists
if( file_exists( $db ) ){
// Connect to the db
@@ -466,12 +633,11 @@ class OC_Migrate{
// Did it succeed?
if( $info->apps->$id->success ){
// Give the provider the content object
- // TODO PASS THE PATH TO MIGRATION.DB
- if( !self::connectDB() ){
+ if( !self::connectDB( $db ) ){
return false;
}
- $content = new OC_Migration_Content( self::$zip, self::$db );
- $provider->setObject( $content );
+ $content = new OC_Migration_Content( self::$zip, self::$MDB2 );
+ $provider->setData( self::$uid, $content, $info );
// Then do the import
$provider->import( $info->apps->$id, $importinfo );
}
diff --git a/lib/migration/content.php b/lib/migration/content.php
index fe8a21a45b..d25b5af293 100644
--- a/lib/migration/content.php
+++ b/lib/migration/content.php
@@ -53,7 +53,7 @@ class OC_Migration_Content{
$query = $this->processQuery( $query );
// Optimize the query
- $query = $this->MDB2->prepare( $query );
+ $query = $this->db->prepare( $query );
// Die if we have an error (error means: bad query, not 0 results!)
if( PEAR::isError( $query ) ) {
@@ -174,7 +174,9 @@ class OC_Migration_Content{
$dirname = basename($dir);
$this->zip->addEmptyDir($internaldir . $dirname);
$internaldir.=$dirname.='/';
-
+ if( !file_exists( $dir ) ){
+ return false;
+ }
if ($dirhandle = opendir($dir)) {
while (false !== ( $file = readdir($dirhandle))) {
diff --git a/lib/migration/provider.php b/lib/migration/provider.php
index b9e2c47620..d592ed6726 100644
--- a/lib/migration/provider.php
+++ b/lib/migration/provider.php
@@ -7,7 +7,7 @@ abstract class OC_Migration_Provider{
protected $id=false;
protected $content=false;
protected $uid=false;
- protected $info=false;
+ protected $olduid=false;
protected $appinfo=false;
public function __construct( $appid ){
@@ -32,11 +32,13 @@ abstract class OC_Migration_Provider{
* @breif sets the OC_Migration_Content object to $this->content
* @param $content a OC_Migration_Content object
*/
- public function setData( $uid, $content, $info=false, $appinfo=false ){
+ public function setData( $uid, $content, $info=false ){
$this->content = $content;
$this->uid = $uid;
- $this->info = $info;
- $this->appinfo = $appinfo;
+ $this->olduid = $info->exporteduser;
+ $id = $this->id;
+ $this->appinfo = $info->apps->$id;
+
}
/**
From 0fa5e196ef8d0b220e4af17b008fb4908b080445 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Tue, 20 Mar 2012 20:32:01 +0000
Subject: [PATCH 045/133] Try to use old uid when importing
---
apps/user_migrate/admin.php | 65 ++-----------------------------
apps/user_migrate/appinfo/app.php | 1 -
lib/migrate.php | 11 ++++--
3 files changed, 11 insertions(+), 66 deletions(-)
diff --git a/apps/user_migrate/admin.php b/apps/user_migrate/admin.php
index d54bd6965b..c1afb0aed4 100644
--- a/apps/user_migrate/admin.php
+++ b/apps/user_migrate/admin.php
@@ -40,69 +40,10 @@ if (isset($_POST['user_import'])) {
exit();
}
- OC_Migrate::import( $to, 'user', 'newuser' );
- die();
- // Find folder
- $files = scandir( $importdir );
- unset($files[0]);
- unset($files[1]);
-
- // Get the user
- if( count($files) != 1 ){
- OC_Log::write('migration', 'Invalid import file', OC_Log::ERROR);
- die('invalid import, no user included');
+ if( !OC_Migrate::import( $to, 'user' ) ){
+ die( 'failed to to import' );
}
-
- $olduser = reset($files);
-
- // Check for dbexport.xml and export info and data dir
- $files = scandir( $importdir . '/' . $olduser );
-
- $required = array( 'migration.db', 'export_info.json', 'files');
- foreach($required as $require){
- if( !in_array( $require, $files) ){
- OC_Log::write('migration', 'Invlaid import file', OC_Log::ERROR);
- die('invalid import');
- }
- }
-
- $migrateinfo = $importdir . '/' . $olduser . '/export_info.json';
- $migrateinfo = json_decode( file_get_contents( $migrateinfo ) );
-
- // Check if uid is available
- if( OC_User::UserExists( $olduser ) ){
- OC_Log::write('migration','Username exists', OC_Log::ERROR);
- die('user exists');
- }
-
- // Create the user
- if( !OC_Migrate::createUser( $olduser, $migrateinfo->hash ) ){
- OC_Log::write('migration', 'Failed to create the new user', OC_Log::ERROR);
- die('coundlt create new user');
- }
-
- $datadir = OC_Config::getValue( 'datadirectory' );
- // Make the new users data dir
- $path = $datadir . '/' . $olduser . '/files/';
- if( !mkdir( $path, 0755, true ) ){
- OC_Log::write('migration','Failed to create users data dir: '.$path, OC_Log::ERROR);
- die('failed to create users data dir');
- }
-
- // Copy data
- if( !copy_r( $importdir . '/' . $olduser . '/files', $datadir . '/' . $olduser . '/files' ) ){
- OC_Log::write('migration','Failed to copy user files to destination', OC_Log::ERROR);
- die('failed to copy user files');
- }
-
- // Import user data
- if( !OC_Migrate::importAppData( $importdir . '/' . $olduser . '/migration.db', $migrateinfo ) ){
- OC_Log::write('migration','Failed to import user data', OC_Log::ERROR);
- die('failed to import user data');
- }
-
- // All done!
- die('done');
+
} else {
// fill template
diff --git a/apps/user_migrate/appinfo/app.php b/apps/user_migrate/appinfo/app.php
index 18b97b93df..4b9cbd1308 100644
--- a/apps/user_migrate/appinfo/app.php
+++ b/apps/user_migrate/appinfo/app.php
@@ -22,7 +22,6 @@
*/
OC_APP::registerPersonal('user_migrate','settings');
-OC_APP::registerAdmin('user_migrate','admin');
// add settings page to navigation
$entry = array(
diff --git a/lib/migrate.php b/lib/migrate.php
index 0058de7391..8b0a2aa3f7 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -190,9 +190,10 @@ class OC_Migrate{
/**
* @breif imports a user, or owncloud instance
* @param $path string path to zip
+ * @param optional $type type of import (user or instance)
* @param optional $uid userid of new user
*/
- public static function import( $path, $uid=null ){
+ public static function import( $path, $type='user', $uid=null ){
OC_Util::checkAdminUser();
$datadir = OC_Config::getValue( 'datadirectory' );
// Extract the zip
@@ -207,8 +208,12 @@ class OC_Migrate{
return false;
}
$json = json_decode( file_get_contents( $extractpath . 'export_info.json' ) );
- self::$exporttype = $json->exporttype;
-
+ if( !$json->exporttype != $type ){
+ OC_Log::write( 'migration', 'Invalid import file', OC_Log::ERROR );
+ return false;
+ }
+ self::$exporttype = $type;
+
// Have we got a user if type is user
if( self::$exporttype == 'user' ){
if( !$uid ){
From 07d7138df08834acc1ac6ff019859ceca09d4690 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Tue, 20 Mar 2012 20:34:20 +0000
Subject: [PATCH 046/133] Register admin pane
---
apps/user_migrate/appinfo/app.php | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/apps/user_migrate/appinfo/app.php b/apps/user_migrate/appinfo/app.php
index 4b9cbd1308..18ea8f52b2 100644
--- a/apps/user_migrate/appinfo/app.php
+++ b/apps/user_migrate/appinfo/app.php
@@ -21,7 +21,8 @@
*
*/
-OC_APP::registerPersonal('user_migrate','settings');
+OC_APP::registerPersonal( 'user_migrate', 'settings' );
+OC_APP::registerAdmin( 'user_migrate', 'admin' );
// add settings page to navigation
$entry = array(
From 892343c7c11e7ba967f69174820a501b3954badb Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Wed, 21 Mar 2012 16:30:59 +0000
Subject: [PATCH 047/133] Fix instance import
---
apps/admin_export/settings.php | 2 +-
lib/migrate.php | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/apps/admin_export/settings.php b/apps/admin_export/settings.php
index cd85bedcd7..269147a3bc 100644
--- a/apps/admin_export/settings.php
+++ b/apps/admin_export/settings.php
@@ -44,7 +44,7 @@ if (isset($_POST['admin_export'])) {
} else if( isset($_POST['admin_import']) ){
$from = $_FILES['owncloud_import']['tmp_name'];
- if( !OC_Migrate::import( $from ) ){
+ if( !OC_Migrate::import( $from, 'instance' ) ){
die('failed');
}
diff --git a/lib/migrate.php b/lib/migrate.php
index 8b0a2aa3f7..718dc57b9f 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -208,7 +208,7 @@ class OC_Migrate{
return false;
}
$json = json_decode( file_get_contents( $extractpath . 'export_info.json' ) );
- if( !$json->exporttype != $type ){
+ if( $json->exporttype != $type ){
OC_Log::write( 'migration', 'Invalid import file', OC_Log::ERROR );
return false;
}
From 7ed8f3974417964df18b135b154fdfdbd4f1b6ca Mon Sep 17 00:00:00 2001
From: Nils Jansen
Date: Fri, 23 Mar 2012 13:34:07 +0100
Subject: [PATCH 048/133] as preperation for the sgf viewer app i added a file
icon for .sgf files (saved go games), and an according mimetype.
---
core/img/filetypes/application-sgf.png | Bin 0 -> 725 bytes
lib/mimetypes.fixlist.php | 3 ++-
2 files changed, 2 insertions(+), 1 deletion(-)
create mode 100644 core/img/filetypes/application-sgf.png
diff --git a/core/img/filetypes/application-sgf.png b/core/img/filetypes/application-sgf.png
new file mode 100644
index 0000000000000000000000000000000000000000..f171f5579e735fe5cc729144e059263a0bc20741
GIT binary patch
literal 725
zcmV;`0xJE9P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iyY|
z5)UXgb;nEq00LD>L_t(2&y`Y3NK|1M{r<;&%|*p1(?-!0dSaM?nHfsC5sVfsOl)03
zZCV9E(8fiyx1e2%+GJ1=Cgn~ggT$~@vMH)@Y@8Wq#&O1b@BjE(jH$Kj>^?Y$^Ks50
zhzS1!zVjF!x;#C<8u^)9imwsS6}zkhwWV!Ml|5G;Z*fS`;p5og$k_YwnN%X}NvQ)N
zf*|mHPsyOJDs(97r9Q_~884OHpv;m|Nh(1jAd>CmP-~4E0pR;mb|tpRmlNyxf^S)bF~(6N
z>YYJrt(8(rD@4rYgIGMrtM<5zDBt%10EAHbUx5%pDW$b8FSTp-mGbfu)3xbJ+EYp)
z=f2Vb0r=Ctuapo%N(lgU;j(bUDT0WX&Nq)w|00xe#;SqXh)O9bm6Rgpd9lEgQiW{e
zTK|c=4<|VQoNWnzT1+e_3WUJ6)t{ZY)
zHxvrlwqqCuW0VlW7;QXQF?6T9$lM%X-^DJ|pu?jJU!xfzl-3#%DJ3PYdHhIaU(eC2
zw_pA>z9L>c=$)L7&P9?xVp-edwc)a+!+YDBt2_E1ZE=1B;p|h!+58Bn00000NkvXX
Hu0mjfh3`Xt
literal 0
HcmV?d00001
diff --git a/lib/mimetypes.fixlist.php b/lib/mimetypes.fixlist.php
index 51f12dbcc2..a40fbd9e22 100644
--- a/lib/mimetypes.fixlist.php
+++ b/lib/mimetypes.fixlist.php
@@ -16,5 +16,6 @@ return array(
'xls'=>'application/msexcel',
'xlsx'=>'application/msexcel',
'ppt'=>'application/mspowerpoint',
- 'pptx'=>'application/mspowerpoint'
+ 'pptx'=>'application/mspowerpoint',
+ 'sgf' => 'application/sgf'
);
From b201e5152840406f0b5de9a403fd8f6ceedd3636 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Tue, 27 Mar 2012 20:43:44 +0000
Subject: [PATCH 049/133] Stop error on export
---
lib/migration/provider.php | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/lib/migration/provider.php b/lib/migration/provider.php
index d592ed6726..98804ee91c 100644
--- a/lib/migration/provider.php
+++ b/lib/migration/provider.php
@@ -32,13 +32,14 @@ abstract class OC_Migration_Provider{
* @breif sets the OC_Migration_Content object to $this->content
* @param $content a OC_Migration_Content object
*/
- public function setData( $uid, $content, $info=false ){
+ public function setData( $uid, $content, $info=null ){
$this->content = $content;
$this->uid = $uid;
- $this->olduid = $info->exporteduser;
+ if( !is_null( $info ) ){
+ $this->olduid = $info->exporteduser;
+ $this->appinfo = $info->apps->$id;
+ }
$id = $this->id;
- $this->appinfo = $info->apps->$id;
-
}
/**
From 553f4533c081e38e65ffb9981063d944fc58f431 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Tue, 27 Mar 2012 20:45:37 +0000
Subject: [PATCH 050/133] look for migrate.php in appinfo folder
---
apps/bookmarks/{lib => appinfo}/migrate.php | 0
lib/migrate.php | 2 +-
2 files changed, 1 insertion(+), 1 deletion(-)
rename apps/bookmarks/{lib => appinfo}/migrate.php (100%)
diff --git a/apps/bookmarks/lib/migrate.php b/apps/bookmarks/appinfo/migrate.php
similarity index 100%
rename from apps/bookmarks/lib/migrate.php
rename to apps/bookmarks/appinfo/migrate.php
diff --git a/lib/migrate.php b/lib/migrate.php
index 718dc57b9f..6b1497d1d0 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -64,7 +64,7 @@ class OC_Migrate{
$apps = OC_App::getAllApps();
foreach($apps as $app){
- $path = OC::$SERVERROOT . '/apps/' . $app . '/lib/migrate.php';
+ $path = OC::$SERVERROOT . '/apps/' . $app . '/appinfo/migrate.php';
if( file_exists( $path ) ){
include( $path );
}
From 31d268fe929abefbbf14e76a96c02f18235451a8 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Tue, 27 Mar 2012 20:55:53 +0000
Subject: [PATCH 051/133] check for sqlite
---
lib/migrate.php | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/lib/migrate.php b/lib/migrate.php
index 6b1497d1d0..d7d1400e2f 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -482,6 +482,12 @@ class OC_Migrate{
$datadir = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" );
+ // DB type
+ if( !is_callable( 'sqlite_open' ) || !class_exists( 'SQLite3' ) ){
+ OC_Log::write( 'migration', 'SQLite not found', OC_Log::ERROR );
+ return false;
+ }
+
// Prepare options array
$options = array(
'portability' => MDB2_PORTABILITY_ALL & (!MDB2_PORTABILITY_FIX_CASE),
From ef33219e4f83652676c7a668b6126c3c1c0da34d Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Tue, 27 Mar 2012 21:21:14 +0000
Subject: [PATCH 052/133] import method returns each apps' import status
---
apps/user_migrate/admin.php | 16 ++++++++++++++-
lib/migrate.php | 40 ++++++++++++++++++++++++-------------
lib/migration/provider.php | 2 +-
3 files changed, 42 insertions(+), 16 deletions(-)
diff --git a/apps/user_migrate/admin.php b/apps/user_migrate/admin.php
index c1afb0aed4..1c4894c0f2 100644
--- a/apps/user_migrate/admin.php
+++ b/apps/user_migrate/admin.php
@@ -40,8 +40,22 @@ if (isset($_POST['user_import'])) {
exit();
}
- if( !OC_Migrate::import( $to, 'user' ) ){
+ if( !$appsstatus = OC_Migrate::import( $to, 'user' ) ){
die( 'failed to to import' );
+ } else {
+ // Check import status
+ foreach( $appsstatus as $app => $status ){
+ if( $status != 'true' ){
+ // It failed for some reason
+ if( $status == 'notsupported' ){
+ $notsupported[] = $app;
+ } else if( !$status ){
+ $failed[] = $app;
+ }
+ }
+ }
+ die(print_r($notsupported));
+ die( 'Some apps failed to import, or were not supported.' );
}
diff --git a/lib/migrate.php b/lib/migrate.php
index d7d1400e2f..b16b84b2a4 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -246,14 +246,14 @@ class OC_Migrate{
return false;
}
// Import user app data
- if( !self::importAppData( $extractpath . $json->exporteduser . '/migration.db', $json, self::$uid ) ){
+ if( !$appsimported = self::importAppData( $extractpath . $json->exporteduser . '/migration.db', $json, self::$uid ) ){
return false;
}
// All done!
if( !self::unlink_r( $extractpath ) ){
OC_Log::write( 'migration', 'Failed to delete the extracted zip', OC_Log::ERROR );
}
- return true;
+ return $appsimported;
break;
case 'instance':
// Check for new data dir and dbexport before doing anything
@@ -611,9 +611,9 @@ class OC_Migrate{
/**
* @breif imports a new user
* @param $db string path to migration.db
- * @param $info array of migration ino
+ * @param $info object of migration info
* @param $uid optional uid to use
- * @return bool if the import succedded
+ * @return array of apps with import statuses, or false on failure.
*/
public static function importAppData( $db, $info, $uid=null ){
// Check if the db exists
@@ -641,21 +641,33 @@ class OC_Migrate{
// Is the app in the export?
$id = $provider->getID();
if( isset( $info->apps->$id ) ){
- // Did it succeed?
- if( $info->apps->$id->success ){
- // Give the provider the content object
- if( !self::connectDB( $db ) ){
- return false;
+ // Is the app installed
+ if( !OC_App::isEnabled( $id ) ){
+ OC_Log::write( 'migration', 'App: ' . $id . ' is not installed, can\'t import data.', OC_Log::INFO );
+ $appsstatus[$id] = 'notsupported';
+ } else {
+ // Did it succeed on export?
+ if( $info->apps->$id->success ){
+ // Give the provider the content object
+ if( !self::connectDB( $db ) ){
+ return false;
+ }
+ $content = new OC_Migration_Content( self::$zip, self::$MDB2 );
+ $provider->setData( self::$uid, $content, $info );
+ // Then do the import
+ if( !$appsstatus[$id] = $provider->import( $info->apps->$id, $importinfo ) ){
+ // Failed to import app
+ OC_Log::write( 'migration', 'Failed to import app data for user: ' . self::$uid . ' for app: ' . $id, OC_Log::ERROR );
+ }
+ } else {
+ // Add to failed list
+ $appsstatus[$id] = false;
}
- $content = new OC_Migration_Content( self::$zip, self::$MDB2 );
- $provider->setData( self::$uid, $content, $info );
- // Then do the import
- $provider->import( $info->apps->$id, $importinfo );
}
}
}
- return true;
+ return $appsstatus;
}
diff --git a/lib/migration/provider.php b/lib/migration/provider.php
index 98804ee91c..feae29f135 100644
--- a/lib/migration/provider.php
+++ b/lib/migration/provider.php
@@ -35,11 +35,11 @@ abstract class OC_Migration_Provider{
public function setData( $uid, $content, $info=null ){
$this->content = $content;
$this->uid = $uid;
+ $id = $this->id;
if( !is_null( $info ) ){
$this->olduid = $info->exporteduser;
$this->appinfo = $info->apps->$id;
}
- $id = $this->id;
}
/**
From bd4fd76bfb94a7b4af0f85838ac9e539e730fa5d Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Tue, 27 Mar 2012 21:35:29 +0000
Subject: [PATCH 053/133] Fix bookmarks migration provider
---
apps/bookmarks/appinfo/migrate.php | 4 ++--
apps/user_migrate/admin.php | 11 ++++++++---
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/apps/bookmarks/appinfo/migrate.php b/apps/bookmarks/appinfo/migrate.php
index 02c96e5963..603a8b72d3 100644
--- a/apps/bookmarks/appinfo/migrate.php
+++ b/apps/bookmarks/appinfo/migrate.php
@@ -48,9 +48,9 @@ class OC_Migration_Provider_Bookmarks extends OC_Migration_Provider{
}
// Now tags
foreach($idmap as $oldid => $newid){
- $query = $this->content->prepare( "SELECT * FROM bookmarks_tags WHERE user_id LIKE ?" );
+ $query = $this->content->prepare( "SELECT * FROM bookmarks_tags WHERE bookmark_id LIKE ?" );
$results = $query->execute( array( $oldid ) );
- while( $row = $data->fetchRow() ){
+ while( $row = $results->fetchRow() ){
// Import the tags for this bookmark, using the new bookmark id
$query = OC_DB::prepare( "INSERT INTO *PREFIX*bookmarks_tags(bookmark_id, tag) VALUES (?, ?)" );
$query->execute( array( $newid, $row['tag'] ) );
diff --git a/apps/user_migrate/admin.php b/apps/user_migrate/admin.php
index 1c4894c0f2..61b83c2a14 100644
--- a/apps/user_migrate/admin.php
+++ b/apps/user_migrate/admin.php
@@ -54,11 +54,16 @@ if (isset($_POST['user_import'])) {
}
}
}
- die(print_r($notsupported));
- die( 'Some apps failed to import, or were not supported.' );
+ // Any problems?
+ if( isset( $notsupported ) || isset( $failed ) ){
+ if( count( $failed ) > 0 ){
+ die( 'Some apps failed to import. View the log please.' );
+ } else if( count( $notsupported ) > 0 ){
+ die( 'Some apps were not found in this owncloud instance and therefore could not be installed' );
+ }
+ }
}
-
} else {
// fill template
$tmpl = new OC_Template('user_migrate', 'admin');
From bcda46eda3b3b9208609bc5a9497632aa0dabfa9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20H=C3=BClsmann?=
Date: Wed, 28 Mar 2012 16:07:50 +0200
Subject: [PATCH 054/133] webfinger installation creates symlink in document
root
---
apps/user_webfinger/appinfo/install.php | 32 ++++++++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/apps/user_webfinger/appinfo/install.php b/apps/user_webfinger/appinfo/install.php
index f570a3a249..9ba953a4e6 100644
--- a/apps/user_webfinger/appinfo/install.php
+++ b/apps/user_webfinger/appinfo/install.php
@@ -3,4 +3,34 @@ $appInfoDir = __DIR__;
$thisAppDir = dirname($appInfoDir);
$appsDir = dirname($thisAppDir);
$ownCloudDir = dirname($appsDir);
-@symlink($thisAppDir, $ownCloudDir.'/.well-known');
+$docRoot = $_SERVER['DOCUMENT_ROOT'];
+if(file_exists($docRoot . '/.well-known/host-meta')) {
+ OC_Log::write(
+ 'user_webfinger',
+ $docRoot . "/.well-known already exists; installation aborted",
+ OC_Log::ERROR
+ );
+} else {
+ if(@symlink($thisAppDir, $docRoot . '/.well-known')) {
+ OC_Log::write(
+ 'user_webfinger',
+ "Webfinger symlink created at " . $docRoot . "/.well-known",
+ OC_Log::INFO
+ );
+ } else {
+ if(@symlink($thisAppDir, $ownCloudDir . '/.well-known')) {
+ OC_Log::write(
+ 'user_webfinger',
+ "Couldn't create webfinger symlink in document root, linked to " . $ownCloudDir . "/.well-known instead",
+ OC_Log::WARN
+ );
+ } else {
+ OC_Log::write(
+ 'user_webfinger',
+ "Couldn't create webfinger symlink, either check write permissions or create the link manually!",
+ OC_Log::ERROR
+ );
+ }
+ }
+}
+?>
From 34a0128ddf01a44302f89a1dfa14bb9565a8ae47 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20H=C3=BClsmann?=
Date: Wed, 28 Mar 2012 16:12:34 +0200
Subject: [PATCH 055/133] whitespace indentation fix
---
apps/user_webfinger/appinfo/install.php | 52 ++++++++++++-------------
1 file changed, 26 insertions(+), 26 deletions(-)
diff --git a/apps/user_webfinger/appinfo/install.php b/apps/user_webfinger/appinfo/install.php
index 9ba953a4e6..775141dce4 100644
--- a/apps/user_webfinger/appinfo/install.php
+++ b/apps/user_webfinger/appinfo/install.php
@@ -5,32 +5,32 @@ $appsDir = dirname($thisAppDir);
$ownCloudDir = dirname($appsDir);
$docRoot = $_SERVER['DOCUMENT_ROOT'];
if(file_exists($docRoot . '/.well-known/host-meta')) {
- OC_Log::write(
- 'user_webfinger',
- $docRoot . "/.well-known already exists; installation aborted",
- OC_Log::ERROR
- );
+ OC_Log::write(
+ 'user_webfinger',
+ $docRoot . "/.well-known already exists; installation aborted",
+ OC_Log::ERROR
+ );
} else {
- if(@symlink($thisAppDir, $docRoot . '/.well-known')) {
- OC_Log::write(
- 'user_webfinger',
- "Webfinger symlink created at " . $docRoot . "/.well-known",
- OC_Log::INFO
- );
- } else {
- if(@symlink($thisAppDir, $ownCloudDir . '/.well-known')) {
- OC_Log::write(
- 'user_webfinger',
- "Couldn't create webfinger symlink in document root, linked to " . $ownCloudDir . "/.well-known instead",
- OC_Log::WARN
- );
- } else {
- OC_Log::write(
- 'user_webfinger',
- "Couldn't create webfinger symlink, either check write permissions or create the link manually!",
- OC_Log::ERROR
- );
- }
- }
+ if(@symlink($thisAppDir, $docRoot . '/.well-known')) {
+ OC_Log::write(
+ 'user_webfinger',
+ "Webfinger symlink created at " . $docRoot . "/.well-known",
+ OC_Log::INFO
+ );
+ } else {
+ if(@symlink($thisAppDir, $ownCloudDir . '/.well-known')) {
+ OC_Log::write(
+ 'user_webfinger',
+ "Couldn't create webfinger symlink in document root, linked to " . $ownCloudDir . "/.well-known instead",
+ OC_Log::WARN
+ );
+ } else {
+ OC_Log::write(
+ 'user_webfinger',
+ "Couldn't create webfinger symlink, either check write permissions or create the link manually!",
+ OC_Log::ERROR
+ );
+ }
+ }
}
?>
From 73eca66a892ade0894e35fb4b57d7b45a5e1c872 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Thu, 29 Mar 2012 10:17:08 +0000
Subject: [PATCH 056/133] Fix comments
---
lib/migrate.php | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/migrate.php b/lib/migrate.php
index b16b84b2a4..fe5ac45600 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -75,7 +75,8 @@ class OC_Migrate{
* @breif exports a user, or owncloud instance
* @param ootional $type string type of export, defualts to user
* @param otional $path string path to zip output folder
- * @param optional $uid string user id of user to export if export type is user, defaults to current
+ * @param optional $uid string user id of user to export if export type is user, defaults to current
+ * @return false on error, path to zip on success
*/
public static function export( $type='user', $path=null, $uid=null ){
$datadir = OC_Config::getValue( 'datadirectory' );
From 65eee1f69dbbbe86bb4bf0716a464dc9f2c66a67 Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Fri, 30 Mar 2012 19:44:38 +0200
Subject: [PATCH 057/133] clean pre-path_hash fscache entries
---
db_structure.xml | 3 +--
files/ajax/scan.php | 1 +
lib/filecache.php | 8 ++++++++
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/db_structure.xml b/db_structure.xml
index 82d2a731d4..2df218d359 100644
--- a/db_structure.xml
+++ b/db_structure.xml
@@ -67,8 +67,7 @@
path_hash
text
-
-
+
true
32
diff --git a/files/ajax/scan.php b/files/ajax/scan.php
index 565275911b..db09b7d5c6 100644
--- a/files/ajax/scan.php
+++ b/files/ajax/scan.php
@@ -17,6 +17,7 @@ if($force or !OC_FileCache::inCache('')){
if(!$checkOnly){
OC_DB::beginTransaction();
OC_FileCache::scan('',$eventSource);
+ OC_FileCache::clean();
OC_DB::commit();
$eventSource->send('success',true);
}else{
diff --git a/lib/filecache.php b/lib/filecache.php
index a8c48e3f14..86d865ed9f 100644
--- a/lib/filecache.php
+++ b/lib/filecache.php
@@ -637,6 +637,14 @@ class OC_FileCache{
self::fileSystemWatcherWrite(array('path'=>$path),$root);
}
}
+
+ /**
+ * clean old pre-path_hash entries
+ */
+ public static function clean(){
+ $query=OC_DB::prepare('DELETE FROM *PREFIX*fscache WHERE LENGTH(path_hash)<30');
+ $query->execute();
+ }
}
//watch for changes and try to keep the cache up to date
From 6abb2cb92edc1edaefea7e37cd46a6c866239c27 Mon Sep 17 00:00:00 2001
From: Bartek Przybylski
Date: Fri, 30 Mar 2012 21:14:01 +0200
Subject: [PATCH 058/133] fix sharing nested galleries
---
apps/gallery/js/album_cover.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/apps/gallery/js/album_cover.js b/apps/gallery/js/album_cover.js
index 061bbcd0b4..cd26001964 100644
--- a/apps/gallery/js/album_cover.js
+++ b/apps/gallery/js/album_cover.js
@@ -43,8 +43,9 @@ function shareGallery() {
{text: 'Shared gallery address', name: 'address', type: 'text', value: existing_token}];
OC.dialogs.form(form_fields, t('gallery', 'Share gallery'), function(values){
var p = '';
- for (var i in paths) p += '/'+paths[i];
+ for (var i in paths) p += paths[i]+'/';
if (p == '') p = '/';
+ alert(p);
$.getJSON(OC.filePath('gallery', 'ajax', 'galleryOp.php'), {operation: 'share', path: p, share: values[0].value, recursive: values[1].value}, function(r) {
if (r.status == 'success') {
Albums.shared = r.sharing;
From 5161758921efb5bb50e579d8e6debfa93e595a7d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20H=C3=BClsmann?=
Date: Fri, 30 Mar 2012 21:35:09 +0200
Subject: [PATCH 059/133] create static host-meta instead of symlink and
.htaccess
---
apps/user_webfinger/appinfo/install.php | 57 ++++++++++++-------------
1 file changed, 28 insertions(+), 29 deletions(-)
diff --git a/apps/user_webfinger/appinfo/install.php b/apps/user_webfinger/appinfo/install.php
index 775141dce4..678d57ae8f 100644
--- a/apps/user_webfinger/appinfo/install.php
+++ b/apps/user_webfinger/appinfo/install.php
@@ -4,33 +4,32 @@ $thisAppDir = dirname($appInfoDir);
$appsDir = dirname($thisAppDir);
$ownCloudDir = dirname($appsDir);
$docRoot = $_SERVER['DOCUMENT_ROOT'];
-if(file_exists($docRoot . '/.well-known/host-meta')) {
- OC_Log::write(
- 'user_webfinger',
- $docRoot . "/.well-known already exists; installation aborted",
- OC_Log::ERROR
- );
-} else {
- if(@symlink($thisAppDir, $docRoot . '/.well-known')) {
- OC_Log::write(
- 'user_webfinger',
- "Webfinger symlink created at " . $docRoot . "/.well-known",
- OC_Log::INFO
- );
- } else {
- if(@symlink($thisAppDir, $ownCloudDir . '/.well-known')) {
- OC_Log::write(
- 'user_webfinger',
- "Couldn't create webfinger symlink in document root, linked to " . $ownCloudDir . "/.well-known instead",
- OC_Log::WARN
- );
- } else {
- OC_Log::write(
- 'user_webfinger',
- "Couldn't create webfinger symlink, either check write permissions or create the link manually!",
- OC_Log::ERROR
- );
- }
- }
+try {
+ $webRoot = substr(realpath($ownCloudDir), strlen(realpath($docRoot)));
+} catch(Exception $e) {
+ // some servers fail on realpath(), let's try it the unsecure way:
+ $webRoot = substr($ownCloudDir, strlen($docRoot));
}
-?>
+$serverName = $_SERVER['SERVER_NAME'];
+$lrddTmpl = 'http';
+if(isset($_SERVER['HTTPS'])) {
+ $lrddTmpl .= 's';
+}
+$lrddTmpl .= '://' . $serverName . $webRoot . '/apps/user_webfinger/webfinger.php?q={uri}';
+$hostMetaPath = $docRoot . '/.well-known/host-meta';
+$hostMetaContents = "
+
+ " . $serverName . "
+
+ Resource Descriptor
+
+ ";
+@mkdir(dirname($hostMetaPath));
+$hostMeta = fopen($hostMetaPath, 'w');
+if(!$hostMeta) {
+ die("Could not open " . $hostMetaPath . " for writing, please check permissions!");
+}
+if(!fwrite($hostMeta, $hostMetaContents, strlen($hostMetaContents))) {
+ die("Could not write to " . $hostMetaPath . ", please check permissions!");
+}
+fclose($hostMeta);
From 6b704a780dbe3daa4c13ad49ad4265c1db4a67aa Mon Sep 17 00:00:00 2001
From: Bartek Przybylski
Date: Fri, 30 Mar 2012 22:50:57 +0200
Subject: [PATCH 060/133] select field added to oc.dialogs.form, gallery ported
to use it
---
apps/gallery/js/album_cover.js | 46 +++++++++++---------------------
apps/gallery/templates/index.php | 39 +--------------------------
core/js/oc-dialogs.js | 14 +++++++---
3 files changed, 28 insertions(+), 71 deletions(-)
diff --git a/apps/gallery/js/album_cover.js b/apps/gallery/js/album_cover.js
index cd26001964..d44e7f83d1 100644
--- a/apps/gallery/js/album_cover.js
+++ b/apps/gallery/js/album_cover.js
@@ -113,42 +113,28 @@ function scanForAlbums(cleanup) {
}
function settings() {
- $( '#g-dialog-settings' ).dialog({
- height: 180,
- width: 350,
- modal: false,
- buttons: [
- {
- text: t('gallery', 'Apply'),
- click: function() {
- var scanning_root = $('#g-scanning-root').val();
- var disp_order = $('#g-display-order option:selected').val();
+ OC.dialogs.form([{text: t('gallery', 'Scanning root'), name: 'root', type:'text', value:gallery_scanning_root},
+ {text: t('gallery', 'Default order'), name: 'order', type:'select', value:gallery_default_order, options:[
+ {text:t('gallery', 'Ascending'), value:'ASC'}, {text: t('gallery', 'Descending'), value:'DESC'} ]}],
+ t('gallery', 'Settings'),
+ function(values) {
+ var scanning_root = values[0].value;
+ var disp_order = values[1].value;
if (scanning_root == '') {
- alert('Scanning root cannot be empty');
+ OC.dialogs.alert(t('gallery', 'Scanning root cannot be empty'), t('gallery', 'Error'));
return;
}
$.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: 'store_settings', root: scanning_root, order: disp_order}, function(r) {
if (r.status == 'success') {
- if (r.rescan == 'yes') {
- $('#g-dialog-settings').dialog('close');
- Albums.clear(document.getElementById('gallery_list'));
- scanForAlbums(true);
- return;
- }
+ if (r.rescan == 'yes') {
+ Albums.clear(document.getElementById('gallery_list'));
+ scanForAlbums(true);
+ }
+ gallery_scanning_root = scanning_root;
} else {
- alert('Error: ' + r.cause);
- return;
+ OC.dialogs.alert(t('gallery', 'Error: ') + r.cause, t('gallery', 'Error'));
+ return;
}
- $('#g-dialog-settings').dialog('close');
});
- }
- },
- {
- text: t('gallery', 'Cancel'),
- click: function() {
- $(this).dialog('close');
- }
- }
- ],
- });
+ });
}
diff --git a/apps/gallery/templates/index.php b/apps/gallery/templates/index.php
index c6373d3b0a..9bec5db1b9 100644
--- a/apps/gallery/templates/index.php
+++ b/apps/gallery/templates/index.php
@@ -9,7 +9,7 @@ OC_Util::addScript('files_imageviewer', 'jquery.fancybox-1.3.4.pack');
OC_Util::addStyle( 'files_imageviewer', 'jquery.fancybox-1.3.4' );
$l = new OC_L10N('gallery');
?>
-
+
@@ -29,40 +29,3 @@ $l = new OC_L10N('gallery');
-
-
-
t('Do you want to remove album');?> ?
-
-
-
-
-
- t('New album name');?>
-
-
-
-
-
-
-
-
- t('Scanning root');?>
-
-
- t('Default sorting'); ?>
-
- >t('Ascending'); ?>
- >t('Descending'); ?>
-
-
-
-
-
-
diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js
index c11ac13332..35d0a0c5c4 100644
--- a/core/js/oc-dialogs.js
+++ b/core/js/oc-dialogs.js
@@ -84,10 +84,18 @@ OCdialogs = {
} else content += '>';
} else if (type == 'text' || type == 'password' && fields[a].value)
content += ' value="'+fields[a].value+'">';
+ } else if (type == 'select') {
+ content += '
';
+ for (var o in fields[a].options)
+ content += ''+fields[a].options[o].text+' ';
+ content += ' ';
}
- content += ""
+ content += '';
}
- content += "
";
+ content += '
';
OCdialogs.message(content, title, OCdialogs.FORM_DIALOG, OCdialogs.OK_CANCEL_BUTTONS, callback);
},
message:function(content, title, dialog_type, buttons, callback) {
@@ -144,7 +152,7 @@ OCdialogs = {
if (callback != undefined) {
var r = [];
var c = 0;
- $(c_id + ' input').each(function(i, elem) {
+ $(c_id + ' input, '+c_id+' select').each(function(i, elem) {
r[c] = {name: $(elem).attr('name'), value: OCdialogs.determineValue(elem)};
c++;
});
From 3a4521a012fe75d8ec3685e1eb87374e5abd9da2 Mon Sep 17 00:00:00 2001
From: Bart Visscher
Date: Fri, 30 Mar 2012 23:15:48 +0200
Subject: [PATCH 061/133] Add support for logging to syslog
---
lib/log.php | 71 +++++++++---------------------------
lib/log/owncloud.php | 78 ++++++++++++++++++++++++++++++++++++++++
lib/log/syslog.php | 37 +++++++++++++++++++
settings/ajax/getlog.php | 2 +-
settings/log.php | 2 +-
5 files changed, 133 insertions(+), 57 deletions(-)
create mode 100644 lib/log/owncloud.php
create mode 100644 lib/log/syslog.php
diff --git a/lib/log.php b/lib/log.php
index 4e450a027f..8bb2839be6 100644
--- a/lib/log.php
+++ b/lib/log.php
@@ -1,78 +1,39 @@
.
- *
+ * Copyright (c) 2012 Bart Visscher
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
*/
/**
- *logging utilities
+ * logging utilities
*
- * Log is saved at data/owncloud.log (on default)
+ * Log is saved by default at data/owncloud.log using OC_Log_Owncloud.
+ * Selecting other backend is done with a config option 'log_type'.
*/
-class OC_Log{
+class OC_Log {
const DEBUG=0;
const INFO=1;
const WARN=2;
const ERROR=3;
const FATAL=4;
+ static protected $class = null;
+
/**
* write a message in the log
* @param string $app
* @param string $message
* @param int level
*/
- public static function write($app,$message,$level){
- $minLevel=OC_Config::getValue( "loglevel", 2 );
- if($level>=$minLevel){
- $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' );
- $logFile=OC_Config::getValue( "logfile", $datadir.'/owncloud.log' );
- $entry=array('app'=>$app,'message'=>$message,'level'=>$level,'time'=>time());
- $fh=fopen($logFile,'a');
- fwrite($fh,json_encode($entry)."\n");
- fclose($fh);
+ public static function write($app, $message, $level) {
+ if (!self::$class) {
+ self::$class = 'OC_Log_'.ucfirst(OC_Config::getValue('log_type', 'owncloud'));
+ call_user_func(array(self::$class, 'init'));
}
- }
-
- /**
- * get entries from the log in reverse chronological order
- * @param int limit
- * @param int offset
- * @return array
- */
- public static function getEntries($limit=50,$offset=0){
- $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' );
- $logFile=OC_Config::getValue( "logfile", $datadir.'/owncloud.log' );
- $entries=array();
- if(!file_exists($logFile)){
- return array();
- }
- $contents=file($logFile);
- if(!$contents){//error while reading log
- return array();
- }
- $end=max(count($contents)-$offset-1,0);
- $start=max($end-$limit,0);
- for($i=$end;$i>$start;$i--){
- $entries[]=json_decode($contents[$i]);
- }
- return $entries;
+ $log_class=self::$class;
+ $log_class::write($app, $message, $level);
}
}
diff --git a/lib/log/owncloud.php b/lib/log/owncloud.php
new file mode 100644
index 0000000000..6df346e9b1
--- /dev/null
+++ b/lib/log/owncloud.php
@@ -0,0 +1,78 @@
+.
+ *
+ */
+
+/**
+ * logging utilities
+ *
+ * Log is saved at data/owncloud.log (on default)
+ */
+
+class OC_Log_Owncloud {
+ /**
+ * Init class data
+ */
+ public static function init() {
+ }
+
+ /**
+ * write a message in the log
+ * @param string $app
+ * @param string $message
+ * @param int level
+ */
+ public static function write($app, $message, $level) {
+ $minLevel=OC_Config::getValue( "loglevel", 2 );
+ if($level>=$minLevel){
+ $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' );
+ $logFile=OC_Config::getValue( "logfile", $datadir.'/owncloud.log' );
+ $entry=array('app'=>$app, 'message'=>$message, 'level'=>$level,'time'=>time());
+ $fh=fopen($logFile, 'a');
+ fwrite($fh, json_encode($entry)."\n");
+ fclose($fh);
+ }
+ }
+
+ /**
+ * get entries from the log in reverse chronological order
+ * @param int limit
+ * @param int offset
+ * @return array
+ */
+ public static function getEntries($limit=50, $offset=0){
+ $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' );
+ $logFile=OC_Config::getValue( "logfile", $datadir.'/owncloud.log' );
+ $entries=array();
+ if(!file_exists($logFile)) {
+ return array();
+ }
+ $contents=file($logFile);
+ if(!$contents) {//error while reading log
+ return array();
+ }
+ $end=max(count($contents)-$offset-1, 0);
+ $start=max($end-$limit,0);
+ for($i=$end;$i>$start;$i--) {
+ $entries[]=json_decode($contents[$i]);
+ }
+ return $entries;
+ }
+}
diff --git a/lib/log/syslog.php b/lib/log/syslog.php
new file mode 100644
index 0000000000..d1fb28d8b0
--- /dev/null
+++ b/lib/log/syslog.php
@@ -0,0 +1,37 @@
+
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+class OC_Log_Syslog {
+ static protected $levels = array(
+ OC_Log::DEBUG => LOG_DEBUG,
+ OC_Log::INFO => LOG_INFO,
+ OC_Log::WARN => LOG_WARNING,
+ OC_Log::ERROR => LOG_ERR,
+ OC_Log::FATAL => LOG_CRIT,
+ );
+
+ /**
+ * Init class data
+ */
+ public static function init() {
+ openlog('ownCloud', LOG_PID | LOG_CONS, LOG_USER);
+ // Close at shutdown
+ register_shutdown_function('closelog');
+ }
+
+ /**
+ * write a message in the log
+ * @param string $app
+ * @param string $message
+ * @param int level
+ */
+ public static function write($app, $message, $level) {
+ $syslog_level = self::$levels[$level];
+ syslog($syslog_level, '{'.$app.'} '.$message);
+ }
+}
diff --git a/settings/ajax/getlog.php b/settings/ajax/getlog.php
index 600ebefcec..ed48b2cae1 100644
--- a/settings/ajax/getlog.php
+++ b/settings/ajax/getlog.php
@@ -13,5 +13,5 @@ OC_JSON::checkAdminUser();
$count=(isset($_GET['count']))?$_GET['count']:50;
$offset=(isset($_GET['offset']))?$_GET['offset']:0;
-$entries=OC_Log::getEntries($count,$offset);
+$entries=OC_Log_Owncloud::getEntries($count,$offset);
OC_JSON::success(array("data" => $entries));
diff --git a/settings/log.php b/settings/log.php
index 946f2b6f8e..ddbf72c443 100644
--- a/settings/log.php
+++ b/settings/log.php
@@ -28,7 +28,7 @@ OC_Util::addStyle( "settings", "settings" );
OC_Util::addScript( "settings", "apps" );
OC_App::setActiveNavigationEntry( "core_log" );
-$entries=OC_Log::getEntries();
+$entries=OC_Log_Owncloud::getEntries();
OC_Util::addScript('settings','log');
OC_Util::addStyle('settings','settings');
From a7438189f315288c5e57bbf3bfb59a37c896cd6c Mon Sep 17 00:00:00 2001
From: Bart Visscher
Date: Fri, 30 Mar 2012 23:31:05 +0200
Subject: [PATCH 062/133] Move more from base init to separate functions
---
lib/base.php | 64 ++++++++++++++++++++++++++++------------------------
1 file changed, 35 insertions(+), 29 deletions(-)
diff --git a/lib/base.php b/lib/base.php
index b031572f17..e9788f54b6 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -229,6 +229,39 @@ class OC{
}
}
+ public static function initTemplateEngine() {
+ // if the formfactor is not yet autodetected do the autodetection now. For possible forfactors check the detectFormfactor documentation
+ if(!isset($_SESSION['formfactor'])){
+ $_SESSION['formfactor']=OC::detectFormfactor();
+ }
+ // allow manual override via GET parameter
+ if(isset($_GET['formfactor'])){
+ $_SESSION['formfactor']=$_GET['formfactor'];
+ }
+
+ // Add the stuff we need always
+ OC_Util::addScript( "jquery-1.6.4.min" );
+ OC_Util::addScript( "jquery-ui-1.8.16.custom.min" );
+ OC_Util::addScript( "jquery-showpassword" );
+ OC_Util::addScript( "jquery.infieldlabel.min" );
+ OC_Util::addScript( "jquery-tipsy" );
+ OC_Util::addScript( "oc-dialogs" );
+ OC_Util::addScript( "js" );
+ OC_Util::addScript( "eventsource" );
+ OC_Util::addScript( "config" );
+ //OC_Util::addScript( "multiselect" );
+ OC_Util::addScript('search','result');
+ OC_Util::addStyle( "styles" );
+ OC_Util::addStyle( "multiselect" );
+ OC_Util::addStyle( "jquery-ui-1.8.16.custom" );
+ OC_Util::addStyle( "jquery-tipsy" );
+ }
+
+ public static function initSession() {
+ ini_set('session.cookie_httponly','1;');
+ session_start();
+ }
+
public static function init(){
// register autoloader
spl_autoload_register(array('OC','autoload'));
@@ -272,35 +305,8 @@ class OC{
self::checkSSL();
self::checkUpgrade();
- ini_set('session.cookie_httponly','1;');
- session_start();
-
- // if the formfactor is not yet autodetected do the autodetection now. For possible forfactors check the detectFormfactor documentation
- if(!isset($_SESSION['formfactor'])){
- $_SESSION['formfactor']=OC::detectFormfactor();
- }
- // allow manual override via GET parameter
- if(isset($_GET['formfactor'])){
- $_SESSION['formfactor']=$_GET['formfactor'];
- }
-
-
- // Add the stuff we need always
- OC_Util::addScript( "jquery-1.6.4.min" );
- OC_Util::addScript( "jquery-ui-1.8.16.custom.min" );
- OC_Util::addScript( "jquery-showpassword" );
- OC_Util::addScript( "jquery.infieldlabel.min" );
- OC_Util::addScript( "jquery-tipsy" );
- OC_Util::addScript( "oc-dialogs" );
- OC_Util::addScript( "js" );
- OC_Util::addScript( "eventsource" );
- OC_Util::addScript( "config" );
- //OC_Util::addScript( "multiselect" );
- OC_Util::addScript('search','result');
- OC_Util::addStyle( "styles" );
- OC_Util::addStyle( "multiselect" );
- OC_Util::addStyle( "jquery-ui-1.8.16.custom" );
- OC_Util::addStyle( "jquery-tipsy" );
+ self::initSession();
+ self::initTemplateEngine();
$errors=OC_Util::checkServer();
if(count($errors)>0) {
From 3300d6ea532a973e987c7aeeef1af63a60487c58 Mon Sep 17 00:00:00 2001
From: Bart Visscher
Date: Fri, 30 Mar 2012 23:33:36 +0200
Subject: [PATCH 063/133] checkUpgrade has to be after template initialization
The error path of checkUpgrade uses the template
---
lib/base.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/base.php b/lib/base.php
index e9788f54b6..22f7f4ea48 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -303,10 +303,10 @@ class OC{
self::checkInstalled();
self::checkSSL();
- self::checkUpgrade();
self::initSession();
self::initTemplateEngine();
+ self::checkUpgrade();
$errors=OC_Util::checkServer();
if(count($errors)>0) {
From 20fc23c82bbcaff56caafe6a6cc0ef15db9b2bf8 Mon Sep 17 00:00:00 2001
From: Bart Visscher
Date: Fri, 30 Mar 2012 23:40:16 +0200
Subject: [PATCH 064/133] Move logfile determination to init function
---
lib/log/owncloud.php | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/lib/log/owncloud.php b/lib/log/owncloud.php
index 6df346e9b1..5e14320556 100644
--- a/lib/log/owncloud.php
+++ b/lib/log/owncloud.php
@@ -27,10 +27,14 @@
*/
class OC_Log_Owncloud {
+ static protected $logFile;
+
/**
* Init class data
*/
public static function init() {
+ $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' );
+ self::$logFile=OC_Config::getValue( "logfile", $datadir.'/owncloud.log' );
}
/**
@@ -42,10 +46,8 @@ class OC_Log_Owncloud {
public static function write($app, $message, $level) {
$minLevel=OC_Config::getValue( "loglevel", 2 );
if($level>=$minLevel){
- $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' );
- $logFile=OC_Config::getValue( "logfile", $datadir.'/owncloud.log' );
$entry=array('app'=>$app, 'message'=>$message, 'level'=>$level,'time'=>time());
- $fh=fopen($logFile, 'a');
+ $fh=fopen(self::$logFile, 'a');
fwrite($fh, json_encode($entry)."\n");
fclose($fh);
}
@@ -58,10 +60,9 @@ class OC_Log_Owncloud {
* @return array
*/
public static function getEntries($limit=50, $offset=0){
- $datadir=OC_Config::getValue( "datadirectory", OC::$SERVERROOT.'/data' );
- $logFile=OC_Config::getValue( "logfile", $datadir.'/owncloud.log' );
+ self::init();
$entries=array();
- if(!file_exists($logFile)) {
+ if(!file_exists(self::$logFile)) {
return array();
}
$contents=file($logFile);
From 71b70bb05f2c3a90a51d70c78c68332111400cf5 Mon Sep 17 00:00:00 2001
From: Bart Visscher
Date: Fri, 30 Mar 2012 23:40:29 +0200
Subject: [PATCH 065/133] Fix HTML, misspelled span close tag
---
files/templates/index.php | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/files/templates/index.php b/files/templates/index.php
index 418a170fec..f591d066d8 100644
--- a/files/templates/index.php
+++ b/files/templates/index.php
@@ -63,12 +63,12 @@
- t('Files are being scanned, please wait.');?>
+ t('Files are being scanned, please wait.');?>
- t('Current scanning');?>
+ t('Current scanning');?>
-
\ No newline at end of file
+
From f9f91a08b47c0a086c43966b1ecdf87185ceef83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20H=C3=BClsmann?=
Date: Sat, 31 Mar 2012 02:42:41 +0200
Subject: [PATCH 066/133] webfinger reimplementation started
---
apps/remoteStorage/appinfo/info.xml | 2 +-
apps/remoteStorage/appinfo/webfinger.php | 6 +++
apps/user_webfinger/.htaccess | 3 --
apps/user_webfinger/appinfo/info.xml | 6 +--
apps/user_webfinger/host-meta | 1 -
apps/user_webfinger/host-meta.php | 16 -------
apps/user_webfinger/webfinger.php | 57 +++++++++++++++++-------
7 files changed, 52 insertions(+), 39 deletions(-)
create mode 100644 apps/remoteStorage/appinfo/webfinger.php
delete mode 100644 apps/user_webfinger/.htaccess
delete mode 100644 apps/user_webfinger/host-meta
delete mode 100644 apps/user_webfinger/host-meta.php
diff --git a/apps/remoteStorage/appinfo/info.xml b/apps/remoteStorage/appinfo/info.xml
index 121587795d..1ab55e8c09 100644
--- a/apps/remoteStorage/appinfo/info.xml
+++ b/apps/remoteStorage/appinfo/info.xml
@@ -3,7 +3,7 @@
remoteStorage
remoteStorage compatibility
Enables your users to use ownCloud as their remote storage for unhosted applications.
- 0.5
+ 0.6
AGPL or MIT
Michiel de Jong
2
diff --git a/apps/remoteStorage/appinfo/webfinger.php b/apps/remoteStorage/appinfo/webfinger.php
new file mode 100644
index 0000000000..bb3fe1681b
--- /dev/null
+++ b/apps/remoteStorage/appinfo/webfinger.php
@@ -0,0 +1,6 @@
+
+
diff --git a/apps/user_webfinger/.htaccess b/apps/user_webfinger/.htaccess
deleted file mode 100644
index 4d4d2e9c58..0000000000
--- a/apps/user_webfinger/.htaccess
+++ /dev/null
@@ -1,3 +0,0 @@
-RewriteEngine On
-RewriteBase /
-RewriteRule host-meta$ \/\.well-known\/host-meta\.php [L]
diff --git a/apps/user_webfinger/appinfo/info.xml b/apps/user_webfinger/appinfo/info.xml
index 55cf2cf220..d47fb723a3 100644
--- a/apps/user_webfinger/appinfo/info.xml
+++ b/apps/user_webfinger/appinfo/info.xml
@@ -2,9 +2,9 @@
user_webfinger
Webfinger
- Provide WebFinger for all users so they get a user address like user@owncloudinstance which can be used for unhosted applications. If you don't run ownCloud in the root of your domain, for instance if you run it on example.com/owncloud/, then make sure you link example.com/.well-known/ to example.com/owncloud/apps/user_webfinger/ - by running something like "ln -s /var/www/owncloud/apps/user_webfinger /var/www/.well-known". Only enable this app if you run this ownCloud installation on a public web address, not if you run it on an intranet or on localhost.
- 0.2
+ Provide WebFinger for all users so they get a user address like user@owncloudinstance which can be used for external applications. Other apps can provide information for webfinger requests, such as remoteStorage compatibility.
+ 0.3
AGPL or MIT
- Michiel de Jong
+ Michiel de Jong, Florian Hülsmann
2
diff --git a/apps/user_webfinger/host-meta b/apps/user_webfinger/host-meta
deleted file mode 100644
index dfaf363614..0000000000
--- a/apps/user_webfinger/host-meta
+++ /dev/null
@@ -1 +0,0 @@
-please run 'a2enmod rewrite' on your server, set 'AllowOverride All' for /var/www in /etc/apache2/sites-enabled/000-default or equivalent, and then run '/etc/init.d/apache2 restart'
diff --git a/apps/user_webfinger/host-meta.php b/apps/user_webfinger/host-meta.php
deleted file mode 100644
index ac577cf9a0..0000000000
--- a/apps/user_webfinger/host-meta.php
+++ /dev/null
@@ -1,16 +0,0 @@
-
-?xml version="1.0" encoding="UTF-8"?>
-
-
-
-
-
-
diff --git a/apps/user_webfinger/webfinger.php b/apps/user_webfinger/webfinger.php
index 5c2a24aa07..ecbfeed8e4 100644
--- a/apps/user_webfinger/webfinger.php
+++ b/apps/user_webfinger/webfinger.php
@@ -1,41 +1,68 @@
/apps/myApp/profile.php?user=">
+ *
+ *
+ '* but can also use complex database queries to generate the webfinger result
+ **/
// calculate the documentroot
// modified version of the one in lib/base.php that takes the .well-known symlink into account
-$DOCUMENTROOT=realpath($_SERVER['DOCUMENT_ROOT']);
+/*$DOCUMENTROOT=realpath($_SERVER['DOCUMENT_ROOT']);
$SERVERROOT=str_replace("\\",'/',dirname(dirname(dirname(dirname(__FILE__)))));
$SUBURI=substr(realpath($_SERVER["SCRIPT_FILENAME"]),strlen($SERVERROOT));
$WEBROOT=substr($SUBURI,0,-34);
+*/
+require_once('../../lib/base.php');
+$id = $_GET['q'];
if($_GET['q']) {
$bits = explode('@', $_GET['q']);
$userName = $bits[0];
} else {
+ $id = '';
$userName = '';
}
if(substr($userName, 0, 5) == 'acct:') {
$userName = substr($userName, 5);
}
if(isset($_SERVER['HTTPS'])) {
- $baseAddress = 'https://'.$_SERVER['SERVER_NAME'].'/apps/remoteStorage/';
+ $baseAddress = 'https://';
} else {
- $baseAddress = 'http://'.$_SERVER['SERVER_NAME'].'/apps/remoteStorage/';
+ $baseAddress = 'http://';
}
+$baseAddress .= $_SERVER['SERVER_NAME'].OC::$WEBROOT;
+define('WF_USER', $userName);
+define('WF_ADDRESS', $id);
+define('WF_ROOT', $baseAddress);
echo "<";
?>
?xml version="1.0" encoding="UTF-8"?>
-
-
+
+ acct:
+
From ad495a92180da7e5dc369f7d8606a525dfe8a4e5 Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Sat, 31 Mar 2012 16:10:29 +0200
Subject: [PATCH 067/133] fix potential problem when using multiply
eventsource's
---
core/js/eventsource.js | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/core/js/eventsource.js b/core/js/eventsource.js
index dece1a69d0..34bce60c24 100644
--- a/core/js/eventsource.js
+++ b/core/js/eventsource.js
@@ -33,8 +33,12 @@
*/
OC.EventSource=function(src,data){
var dataStr='';
- for(name in data){
- dataStr+=name+'='+encodeURIComponent(data[name])+'&';
+ this.typelessListeners=[];
+ this.listeners={};
+ if(data){
+ for(name in data){
+ dataStr+=name+'='+encodeURIComponent(data[name])+'&';
+ }
}
if(!this.useFallBack && typeof EventSource !='undefined'){
this.source=new EventSource(src+'?'+dataStr);
@@ -42,7 +46,7 @@ OC.EventSource=function(src,data){
for(var i=0;i
Date: Sat, 31 Mar 2012 16:20:32 +0200
Subject: [PATCH 068/133] make sure output buffering is dissabled when using
eventsource
---
lib/eventsource.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/eventsource.php b/lib/eventsource.php
index 523f72403c..dc28616c2d 100644
--- a/lib/eventsource.php
+++ b/lib/eventsource.php
@@ -32,6 +32,7 @@ class OC_EventSource{
private $fallBackId=0;
public function __construct(){
+ @ob_end_clean();
header('Cache-Control: no-cache');
$this->fallback=isset($_GET['fallback']) and $_GET['fallback']=='true';
if($this->fallback){
From 9d2f8aa717826c1db8f8ec5f49a4128af3651edb Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Sat, 31 Mar 2012 16:24:53 +0200
Subject: [PATCH 069/133] send more progress updates when scanning large
folders
---
lib/filecache.php | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/lib/filecache.php b/lib/filecache.php
index 86d865ed9f..59b0fb1b50 100644
--- a/lib/filecache.php
+++ b/lib/filecache.php
@@ -469,6 +469,10 @@ class OC_FileCache{
* @param string root (optionak)
*/
public static function scan($path,$eventSource=false,&$count=0,$root=''){
+ if($eventSource){
+ $eventSource->send('scanning',array('file'=>$path,'count'=>$count));
+ }
+ $lastSend=$count;
if(!$root){
$view=OC_Filesystem::getView();
}else{
@@ -482,13 +486,15 @@ class OC_FileCache{
if($filename != '.' and $filename != '..'){
$file=$path.'/'.$filename;
if($view->is_dir($file.'/')){
- if($eventSource){
- $eventSource->send('scanning',array('file'=>$file,'count'=>$count));
- }
self::scan($file,$eventSource,$count,$root);
}else{
$totalSize+=self::scanFile($file,$root);
$count++;
+ if($count>$lastSend+25){
+ if($eventSource){
+ $eventSource->send('scanning',array('file'=>$path,'count'=>$count));
+ }
+ }
}
}
}
From ebc7a6a0a6249213122bf97104f850d2ce6b7c1a Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Sat, 31 Mar 2012 16:28:22 +0200
Subject: [PATCH 070/133] dont send to much when scanning large folders
---
lib/filecache.php | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/lib/filecache.php b/lib/filecache.php
index 59b0fb1b50..4a4183cbdb 100644
--- a/lib/filecache.php
+++ b/lib/filecache.php
@@ -490,10 +490,9 @@ class OC_FileCache{
}else{
$totalSize+=self::scanFile($file,$root);
$count++;
- if($count>$lastSend+25){
- if($eventSource){
- $eventSource->send('scanning',array('file'=>$path,'count'=>$count));
- }
+ if($count>$lastSend+25 and $eventSource){
+ $lastSend=$count;
+ $eventSource->send('scanning',array('file'=>$path,'count'=>$count));
}
}
}
From 2f68b084919437013cc6d977c0f077e541cf83f9 Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Sat, 31 Mar 2012 16:40:42 +0200
Subject: [PATCH 071/133] fix eventsource for ie
---
core/js/eventsource.js | 2 +-
lib/eventsource.php | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/core/js/eventsource.js b/core/js/eventsource.js
index 34bce60c24..08259e02ca 100644
--- a/core/js/eventsource.js
+++ b/core/js/eventsource.js
@@ -68,7 +68,7 @@ OC.EventSource=function(src,data){
OC.EventSource.fallBackSources=[];
OC.EventSource.iframeCount=0;//number of fallback iframes
OC.EventSource.fallBackCallBack=function(id,type,data){
- OC.EventSource.fallBackSources[id].fallBackCallBack(type,JSON.parse(data));
+ OC.EventSource.fallBackSources[id].fallBackCallBack(type,data);
}
OC.EventSource.prototype={
typelessListeners:[],
diff --git a/lib/eventsource.php b/lib/eventsource.php
index dc28616c2d..cf10660b94 100644
--- a/lib/eventsource.php
+++ b/lib/eventsource.php
@@ -59,7 +59,7 @@ class OC_EventSource{
$type=null;
}
if($this->fallback){
- $response=''.PHP_EOL;
+ $response=''.PHP_EOL;
echo $response;
}else{
if($type){
From 4e327295c65b25fc5d6ceec5a8242eecf57b94e2 Mon Sep 17 00:00:00 2001
From: Bartek Przybylski
Date: Sun, 1 Apr 2012 00:30:52 +0200
Subject: [PATCH 072/133] adding callback when ok click on alert dialog
---
core/js/oc-dialogs.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js
index 35d0a0c5c4..17c987ae87 100644
--- a/core/js/oc-dialogs.js
+++ b/core/js/oc-dialogs.js
@@ -115,7 +115,7 @@ OCdialogs = {
var f;
switch(dialog_type) {
case OCdialogs.ALERT_DIALOG:
- f = function(){$(c_id).dialog('close'); };
+ f = function(){$(c_id).dialog('close'); callback();};
break;
case OCdialogs.PROMPT_DIALOG:
f = function(){OCdialogs.prompt_ok_handler(callback, c_id)};
From d20eea9761238e0569f538c6f8b1bb553068bf7b Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sat, 31 Mar 2012 22:41:43 +0000
Subject: [PATCH 073/133] Use ajax to download file, OC_Dialogs for errors
---
apps/user_migrate/ajax/export.php | 63 ++++++++++++++++++++++++
apps/user_migrate/appinfo/app.php | 1 +
apps/user_migrate/js/export.js | 27 ++++++++++
apps/user_migrate/settings.php | 22 ++-------
apps/user_migrate/templates/settings.php | 14 +++---
lib/migrate.php | 4 +-
6 files changed, 102 insertions(+), 29 deletions(-)
create mode 100644 apps/user_migrate/ajax/export.php
create mode 100644 apps/user_migrate/js/export.js
diff --git a/apps/user_migrate/ajax/export.php b/apps/user_migrate/ajax/export.php
new file mode 100644
index 0000000000..ef947c610f
--- /dev/null
+++ b/apps/user_migrate/ajax/export.php
@@ -0,0 +1,63 @@
+.
+ *
+ */
+// Init owncloud
+require_once('../../../lib/base.php');
+
+// Check if we are a user
+OC_JSON::checkLoggedIn();
+OC_Util::checkAppEnabled('user_migrate');
+ OC_JSON::error();
+ die();
+// Which operation
+if( $_GET['operation']=='create' ){
+$uid = !empty( $_POST['uid'] ) ? $_POST['uid'] : OC_User::getUser();
+if( $uid != OC_User::getUser() ){
+ // Needs to be admin to export someone elses account
+ OC_JSON::error();
+ die();
+}
+// Create the export zip
+if( !$path = OC_Migrate::export( $uid ) ){
+ // Error
+ OC_JSON::error();
+ die();
+} else {
+ // Save path in session
+ $_SESSION['ocuserexportpath'] = $path;
+}
+OC_JSON::success();
+die();
+} else if( $_GET['operation']=='download' ){
+ // Download the export
+ $path = isset( $_SESSION['ocuserexportpath'] ) ? $_SESSION['ocuserexportpath'] : false;
+ if( !$path ){
+ die();
+ }
+ header("Content-Type: application/zip");
+ header("Content-Disposition: attachment; filename=" . basename($path));
+ header("Content-Length: " . filesize($path));
+ @ob_end_clean();
+ readfile($path);
+ unlink( $path );
+ $_SESSION['ocuserexportpath'] = '';
+}
diff --git a/apps/user_migrate/appinfo/app.php b/apps/user_migrate/appinfo/app.php
index 18ea8f52b2..a59b6dd705 100644
--- a/apps/user_migrate/appinfo/app.php
+++ b/apps/user_migrate/appinfo/app.php
@@ -23,6 +23,7 @@
OC_APP::registerPersonal( 'user_migrate', 'settings' );
OC_APP::registerAdmin( 'user_migrate', 'admin' );
+OC_Util::addScript( 'user_migrate', 'export');
// add settings page to navigation
$entry = array(
diff --git a/apps/user_migrate/js/export.js b/apps/user_migrate/js/export.js
new file mode 100644
index 0000000000..0e1e396f65
--- /dev/null
+++ b/apps/user_migrate/js/export.js
@@ -0,0 +1,27 @@
+$(document).ready(function(){
+ // Do the export
+ $('#exportbtn').click(function(){
+ // Show loader
+ $('.loading').show();
+ $.getJSON(
+ OC.filePath('user_migrate','ajax','export.php'),
+ {operation:'create'},
+ function(result){
+ if(result.status == 'success'){
+ // Download the file
+ window.location = OC.filePath('user_migrate','ajax','export.php?operation=download') ;
+ $('.loading').hide();
+ $('#exportbtn').val(t('user_migrate', 'Export'));
+ } else {
+ // Cancel loading
+ $('#exportbtn').html('Failed');
+ // Show Dialog
+ OC.dialogs.alert(t('user_migrate', 'Something went wrong while the export file was being generated'), t('user_migrate', 'An error has occurred'), function(){
+ $('#exportbtn').html(t('user_migrate', 'Export')+' ');
+ });
+ }
+ }
+ // End ajax
+ );
+ });
+});
\ No newline at end of file
diff --git a/apps/user_migrate/settings.php b/apps/user_migrate/settings.php
index 38eee990b4..62f347b355 100644
--- a/apps/user_migrate/settings.php
+++ b/apps/user_migrate/settings.php
@@ -24,22 +24,6 @@
*/
OC_Util::checkAppEnabled('user_migrate');
-if (isset($_POST['user_export'])) {
- // Create the export zip
- if( !$path = OC_Migrate::export() ){
- // Error
- die('error');
- } else {
- // Download it
- header("Content-Type: application/zip");
- header("Content-Disposition: attachment; filename=" . basename($path));
- header("Content-Length: " . filesize($path));
- @ob_end_clean();
- readfile($path);
- unlink( $path );
- }
-} else {
- // fill template
- $tmpl = new OC_Template('user_migrate', 'settings');
- return $tmpl->fetchPage();
-}
\ No newline at end of file
+// fill template
+$tmpl = new OC_Template('user_migrate', 'settings');
+return $tmpl->fetchPage();
\ No newline at end of file
diff --git a/apps/user_migrate/templates/settings.php b/apps/user_migrate/templates/settings.php
index 389de563a6..5f4857de5f 100644
--- a/apps/user_migrate/templates/settings.php
+++ b/apps/user_migrate/templates/settings.php
@@ -1,8 +1,6 @@
-
-
- t('Export your user account');?>
- t('This will create a compressed file that contains your ownCloud account.');?>
-
-
-
-
\ No newline at end of file
+
+ t('Export your user account');?>
+ t('This will create a compressed file that contains your ownCloud account.');?>
+
+ Export
+
diff --git a/lib/migrate.php b/lib/migrate.php
index fe5ac45600..db3852fb83 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -73,12 +73,12 @@ class OC_Migrate{
/**
* @breif exports a user, or owncloud instance
+ * @param optional $uid string user id of user to export if export type is user, defaults to current
* @param ootional $type string type of export, defualts to user
* @param otional $path string path to zip output folder
- * @param optional $uid string user id of user to export if export type is user, defaults to current
* @return false on error, path to zip on success
*/
- public static function export( $type='user', $path=null, $uid=null ){
+ public static function export( $uid=null, $type='user', $path=null ){
$datadir = OC_Config::getValue( 'datadirectory' );
// Validate export type
$types = array( 'user', 'instance', 'system', 'userfiles' );
From aba3182a7d6c2dc5573a5cca75b2ed5e8abbc3e0 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sat, 31 Mar 2012 22:47:38 +0000
Subject: [PATCH 074/133] Fix loading image after export failure
---
apps/user_migrate/js/export.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/user_migrate/js/export.js b/apps/user_migrate/js/export.js
index 0e1e396f65..2d660b2de6 100644
--- a/apps/user_migrate/js/export.js
+++ b/apps/user_migrate/js/export.js
@@ -17,7 +17,7 @@ $(document).ready(function(){
$('#exportbtn').html('Failed');
// Show Dialog
OC.dialogs.alert(t('user_migrate', 'Something went wrong while the export file was being generated'), t('user_migrate', 'An error has occurred'), function(){
- $('#exportbtn').html(t('user_migrate', 'Export')+' ');
+ $('#exportbtn').html(t('user_migrate', 'Export')+' ');
});
}
}
From 3e84d8548296152112c09aa0e4a3a4c02b816494 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sat, 31 Mar 2012 22:50:57 +0000
Subject: [PATCH 075/133] remove debug
---
apps/user_migrate/ajax/export.php | 2 --
1 file changed, 2 deletions(-)
diff --git a/apps/user_migrate/ajax/export.php b/apps/user_migrate/ajax/export.php
index ef947c610f..fac96577fa 100644
--- a/apps/user_migrate/ajax/export.php
+++ b/apps/user_migrate/ajax/export.php
@@ -26,8 +26,6 @@ require_once('../../../lib/base.php');
// Check if we are a user
OC_JSON::checkLoggedIn();
OC_Util::checkAppEnabled('user_migrate');
- OC_JSON::error();
- die();
// Which operation
if( $_GET['operation']=='create' ){
$uid = !empty( $_POST['uid'] ) ? $_POST['uid'] : OC_User::getUser();
From d01b78a4b486860ab7110677e9969a37ee2a832f Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Sun, 1 Apr 2012 00:55:12 +0200
Subject: [PATCH 076/133] prevent an possible xss exploit
---
core/templates/login.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/core/templates/login.php b/core/templates/login.php
index 82222c8212..4ba92221a7 100644
--- a/core/templates/login.php
+++ b/core/templates/login.php
@@ -7,7 +7,7 @@
t( 'Username' ); ?>
- autocomplete="off" required />
+ autocomplete="off" required />
t( 'Password' ); ?>
From ce89ff15aaa971ec930196db64e7437c2fe47fa5 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sat, 31 Mar 2012 23:20:08 +0000
Subject: [PATCH 077/133] Remove db tmp file after export creation
---
lib/migration/content.php | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/lib/migration/content.php b/lib/migration/content.php
index d25b5af293..a9fa05596b 100644
--- a/lib/migration/content.php
+++ b/lib/migration/content.php
@@ -28,7 +28,7 @@ class OC_Migration_Content{
private $zip=false;
// Holds the MDB2 object
- private $db=false;
+ private $db=null;
// Holds an array of tmpfiles to delete after zip creation
private $tmpfiles=false;
@@ -38,11 +38,18 @@ class OC_Migration_Content{
* @param optional $db a MDB2 database object (required for exporttype user)
* @return bool
*/
- public function __construct( $zip, $db=false ){
+ public function __construct( $zip, $db=null ){
$this->zip = $zip;
$this->db = $db;
+ if( !is_null( $db ) ){
+ // Get db path
+ $db = $this->db->getDatabase();
+ $this->tmpfiles[] = $db;
+ OC_Log::write('user-migrate',$db, OC_Log::INFO);
+ }
+
}
// @breif prepares the db
From daf742c086fefab9d715be3308088e626de1216c Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sat, 31 Mar 2012 23:55:41 +0000
Subject: [PATCH 078/133] Fix owncloud log
---
apps/contacts/appinfo/migrate.php | 68 +++++++++++++++++++++++++++++++
lib/log/owncloud.php | 2 +-
2 files changed, 69 insertions(+), 1 deletion(-)
create mode 100644 apps/contacts/appinfo/migrate.php
diff --git a/apps/contacts/appinfo/migrate.php b/apps/contacts/appinfo/migrate.php
new file mode 100644
index 0000000000..a6c6bc20fa
--- /dev/null
+++ b/apps/contacts/appinfo/migrate.php
@@ -0,0 +1,68 @@
+'contacts_addressbooks',
+ 'matchcol'=>'userid',
+ 'matchval'=>$this->uid,
+ 'idcol'=>'id'
+ );
+ $ids = $this->content->copyRows( $options );
+
+ $options = array(
+ 'table'=>'contacts_cards',
+ 'matchcol'=>'addressbookid',
+ 'matchval'=>$ids
+ );
+
+ // Export tags
+ $ids2 = $this->content->copyRows( $options );
+
+ // If both returned some ids then they worked
+ if( is_array( $ids ) && is_array( $ids2 ) )
+ {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
+ // Import function for bookmarks
+ function import( ){
+ switch( $this->appinfo->version ){
+ default:
+ // All versions of the app have had the same db structure, so all can use the same import function
+ $query = $this->content->prepare( "SELECT * FROM contacts_addressbooks WHERE userid LIKE ?" );
+ $results = $query->execute( array( $this->olduid ) );
+ $idmap = array();
+ while( $row = $results->fetchRow() ){
+ // Import each bookmark, saving its id into the map
+ $query = OC_DB::prepare( "INSERT INTO *PREFIX*contacts_addressbooks (`userid`, `displayname`, `uri`, `description`, `ctag`) VALUES (?, ?, ?, ?, ?)" );
+ $query->execute( array( $this->uid, $row['displayname'], $row['uri'], $row['description'], $row['ctag'] ) );
+ // Map the id
+ $idmap[$row['id']] = OC_DB::insertid();
+ }
+ // Now tags
+ foreach($idmap as $oldid => $newid){
+ $query = $this->content->prepare( "SELECT * FROM contacts_cards WHERE addressbookid LIKE ?" );
+ $results = $query->execute( array( $oldid ) );
+ while( $row = $results->fetchRow() ){
+ // Import the tags for this bookmark, using the new bookmark id
+ $query = OC_DB::prepare( "INSERT INTO *PREFIX*contacts_cards (`addressbookid`, `fullname`, `carddata`, `uri`, `lastmodified`) VALUES (?, ?, ?, ?, ?)" );
+ $query->execute( array( $newid, $row['fullname'], $row['carddata'], $row['uri'], $row['lastmodified'] ) );
+ }
+ }
+ // All done!
+ break;
+ }
+
+ return true;
+ }
+
+}
+
+// Load the provider
+new OC_Migration_Provider_Contacts( 'contacts' );
\ No newline at end of file
diff --git a/lib/log/owncloud.php b/lib/log/owncloud.php
index 5e14320556..0ed3051013 100644
--- a/lib/log/owncloud.php
+++ b/lib/log/owncloud.php
@@ -65,7 +65,7 @@ class OC_Log_Owncloud {
if(!file_exists(self::$logFile)) {
return array();
}
- $contents=file($logFile);
+ $contents=file(self::$logFile);
if(!$contents) {//error while reading log
return array();
}
From ffbd72bbcf775ac31a43b958ec1e8eaddf0f8356 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sun, 1 Apr 2012 00:07:39 +0000
Subject: [PATCH 079/133] Fix user app data export
---
lib/migration/content.php | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/lib/migration/content.php b/lib/migration/content.php
index a9fa05596b..d304051f3e 100644
--- a/lib/migration/content.php
+++ b/lib/migration/content.php
@@ -47,7 +47,6 @@ class OC_Migration_Content{
// Get db path
$db = $this->db->getDatabase();
$this->tmpfiles[] = $db;
- OC_Log::write('user-migrate',$db, OC_Log::INFO);
}
}
@@ -110,7 +109,8 @@ class OC_Migration_Content{
foreach( $options['matchval'] as $matchval ){
// Run the query for this match value (where x = y value)
- $query = OC_DB::prepare( "SELECT * FROM *PREFIX*" . $options['table'] . " WHERE " . $options['matchcol'] . " LIKE ?" );
+ $sql = "SELECT * FROM *PREFIX*" . $options['table'] . " WHERE " . $options['matchcol'] . " LIKE ?";
+ $query = OC_DB::prepare( $sql );
$results = $query->execute( array( $matchval ) );
$newreturns = $this->insertData( $results, $options );
$return = array_merge( $return, $newreturns );
@@ -118,7 +118,8 @@ class OC_Migration_Content{
} else {
// Just get everything
- $query = OC_DB::prepare( "SELECT * FROM *PREFIX*" . $options['table'] );
+ $sql = "SELECT * FROM *PREFIX*" . $options['table'];
+ $query = OC_DB::prepare( $sql );
$results = $query->execute();
$return = $this->insertData( $results, $options );
@@ -136,6 +137,7 @@ class OC_Migration_Content{
*/
private function insertData( $data, $options ){
$return = array();
+ // Foreach row of data to insert
while( $row = $data->fetchRow() ){
// Now save all this to the migration.db
foreach($row as $field=>$value){
@@ -166,6 +168,8 @@ class OC_Migration_Content{
$return[] = reset($row);
}
}
+ $fields = '';
+ $values = '';
}
return $return;
}
From eba6a65908ab848741a29467a2c054818e3c740c Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sun, 1 Apr 2012 00:25:47 +0000
Subject: [PATCH 080/133] try to use transactions to replace db
---
apps/admin_export/settings.php | 2 +-
lib/db.php | 9 +++------
lib/migrate.php | 10 ++++++----
3 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/apps/admin_export/settings.php b/apps/admin_export/settings.php
index 269147a3bc..719bedb66e 100644
--- a/apps/admin_export/settings.php
+++ b/apps/admin_export/settings.php
@@ -28,7 +28,7 @@ OC_Util::checkAppEnabled('admin_export');
// Export?
if (isset($_POST['admin_export'])) {
// Create the export zip
- if( !$path = OC_Migrate::export( $_POST['export_type'] ) ){
+ if( !$path = OC_Migrate::export( null, $_POST['export_type'] ) ){
// Error
die('error');
} else {
diff --git a/lib/db.php b/lib/db.php
index a7b7ae75da..9c46a40add 100644
--- a/lib/db.php
+++ b/lib/db.php
@@ -489,7 +489,7 @@ class OC_DB {
public static function replaceDB( $file ){
$apps = OC_App::getAllApps();
-
+ self::beginTransaction();
// Delete the old tables
self::removeDBStructure( OC::$SERVERROOT . '/db_structure.xml' );
@@ -501,11 +501,8 @@ class OC_DB {
}
// Create new tables
- if( self::createDBFromStructure( $file ) ){
- return true;
- } else {
- return false;
- }
+ self::createDBFromStructure( $file );
+ self::commit();
}
diff --git a/lib/migrate.php b/lib/migrate.php
index db3852fb83..815333b4d8 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -257,28 +257,30 @@ class OC_Migrate{
return $appsimported;
break;
case 'instance':
+ /*
// Check for new data dir and dbexport before doing anything
// TODO
- /*
+
// Delete current data folder.
OC_Log::write( 'migration', "Deleting current data dir", OC_Log::INFO );
- if( self::unlink_r( $datadir, false ) ){
+ if( !self::unlink_r( $datadir, false ) ){
OC_Log::write( 'migration', 'Failed to delete the current data dir', OC_Log::ERROR );
return false;
}
// Copy over data
- if( !self::copy_r( $extractname . 'data', $datadir ) ){
+ if( !self::copy_r( $extractpath . 'userdata', $datadir ) ){
OC_Log::write( 'migration', 'Failed to copy over data directory', OC_Log::ERROR );
return false;
}
- */
+
// Import the db
if( !OC_DB::replaceDB( $extractpath . 'dbexport.xml' ) ){
return false;
}
// Done
return true;
+ */
break;
}
From 6bb48b2731185dd93ad1a1edc52f33725cd99061 Mon Sep 17 00:00:00 2001
From: Michael Gapczynski
Date: Sun, 1 Apr 2012 02:38:26 -0400
Subject: [PATCH 081/133] Check file handle exists before trying to read file
---
lib/filesystemview.php | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/lib/filesystemview.php b/lib/filesystemview.php
index 39e47975b2..a3736f1976 100644
--- a/lib/filesystemview.php
+++ b/lib/filesystemview.php
@@ -137,13 +137,16 @@ class OC_FilesystemView {
}
public function readfile($path){
$handle=$this->fopen($path,'r');
- $chunkSize = 1024*1024;// 1 MB chunks
- while (!feof($handle)) {
- echo fread($handle, $chunkSize);
- @ob_flush();
- flush();
+ if ($handle) {
+ $chunkSize = 1024*1024;// 1 MB chunks
+ while (!feof($handle)) {
+ echo fread($handle, $chunkSize);
+ @ob_flush();
+ flush();
+ }
+ return $this->filesize($path);
}
- return $this->filesize($path);
+ return false;
}
public function is_readable($path){
return $this->basicOperation('is_readable',$path);
From 6545e4878715c10d85a72b1cdb3f7cef73d7e383 Mon Sep 17 00:00:00 2001
From: Frank Karlitschek
Date: Sun, 1 Apr 2012 11:20:12 +0200
Subject: [PATCH 082/133] Show the different editions to the user. Used in the
status call, on the personal settings page and in the updater to update to
the next available version from the same edition.
---
lib/updater.php | 1 +
lib/util.php | 8 ++++++++
settings/templates/personal.php | 2 +-
status.php | 2 +-
4 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/lib/updater.php b/lib/updater.php
index 57623797ae..196822ac35 100644
--- a/lib/updater.php
+++ b/lib/updater.php
@@ -36,6 +36,7 @@ class OC_Updater{
$version['installed']=OC_Config::getValue('installedat');
$version['updated']=OC_Appconfig::getValue('core', 'lastupdatedat', OC_Config::getValue( 'lastupdatedat'));
$version['updatechannel']='stable';
+ $version['edition']=OC_Util::getEditionString();
$versionstring=implode('x',$version);
//fetch xml data from updater
diff --git a/lib/util.php b/lib/util.php
index 529b6d958f..722b7404d0 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -77,6 +77,14 @@ class OC_Util {
return '3';
}
+ /**
+ * get the current installed edition of ownCloud. There is the community edition that just returns an empty string and the enterprise edition that returns "Enterprise".
+ * @return string
+ */
+ public static function getEditionString(){
+ return '';
+ }
+
/**
* add a javascript file
*
diff --git a/settings/templates/personal.php b/settings/templates/personal.php
index 57731d979d..d40da7eb77 100644
--- a/settings/templates/personal.php
+++ b/settings/templates/personal.php
@@ -50,7 +50,7 @@
};?>
- ownCloud
+ ownCloud
developed by the ownCloud community
source code licensed freely under AGPL
diff --git a/status.php b/status.php
index 94c8cfce84..81f339fa53 100644
--- a/status.php
+++ b/status.php
@@ -26,7 +26,7 @@ $RUNTIME_NOAPPS = TRUE; //no apps, yet
require_once('lib/base.php');
if(OC_Config::getValue('installed')==1) $installed='true'; else $installed='false';
-$values=array('installed'=>$installed,'version'=>implode('.',OC_Util::getVersion()),'versionstring'=>OC_Util::getVersionString());
+$values=array('installed'=>$installed,'version'=>implode('.',OC_Util::getVersion()),'versionstring'=>OC_Util::getVersionString(),'edition'=>OC_Util::getEditionString());
echo(json_encode($values));
From 1b8a644c31a83279e9829aac74fbbc843d49f65d Mon Sep 17 00:00:00 2001
From: Frank Karlitschek
Date: Sun, 1 Apr 2012 16:06:08 +0200
Subject: [PATCH 083/133] update outdated README
---
README | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/README b/README
index 4d4be2728e..77379a4645 100644
--- a/README
+++ b/README
@@ -3,10 +3,11 @@ A personal cloud which runs on your own server.
http://ownCloud.org
-Installation instructions: http://owncloud.org/support/setup-and-installation/
-Source code: http://gitorious.org/owncloud
+Installation instructions: http://owncloud.org/support
+Source code: http://gitorious.org/owncloud
Mailing list: http://mail.kde.org/mailman/listinfo/owncloud
IRC channel: http://webchat.freenode.net/?channels=owncloud
Diaspora: https://joindiaspora.com/u/owncloud
Identi.ca: http://identi.ca/owncloud
+
From b758725bf7fad960e971adfeb826596e02673244 Mon Sep 17 00:00:00 2001
From: Frank Karlitschek
Date: Sun, 1 Apr 2012 17:02:32 +0200
Subject: [PATCH 084/133] =?UTF-8?q?Try=20to=20configure=20php=20to=20enabl?=
=?UTF-8?q?e=20big=20file=20uploads.=20This=20doesn=C2=B4t=20work=20always?=
=?UTF-8?q?=20depending=20on=20the=20webserver=20and=20php=20configuration?=
=?UTF-8?q?.=20Let=C2=B4s=20try=20to=20overwrite=20some=20defaults=20anywa?=
=?UTF-8?q?ys?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
lib/base.php | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/lib/base.php b/lib/base.php
index 22f7f4ea48..a4a94e8696 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -277,6 +277,24 @@ class OC{
date_default_timezone_set('Europe/Berlin');
ini_set('arg_separator.output','&');
+ //try to configure php to enable big file uploads.
+ //this doesn´t work always depending on the webserver and php configuration.
+ //Let´s try to overwrite some defaults anyways
+
+ //try to set the maximum execution time to 60min
+ @set_time_limit(3600);
+ @ini_set('max_execution_time',3600);
+ @ini_set('max_input_time',3600);
+
+ //try to set the maximum filesize to 10G
+ @ini_set('upload_max_filesize','10G');
+ @ini_set('post_max_size','10G');
+ @ini_set('file_uploads','50');
+
+ //try to set the session lifetime to 60min
+ @ini_set('gc_maxlifetime','3600');
+
+
//set http auth headers for apache+php-cgi work around
if (isset($_SERVER['HTTP_AUTHORIZATION']) && preg_match('/Basic\s+(.*)$/i', $_SERVER['HTTP_AUTHORIZATION'], $matches))
{
From 39e8981bc2ef098a020476a9d94a4b0cc4d9e1c9 Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Sun, 1 Apr 2012 17:31:44 +0200
Subject: [PATCH 085/133] oc_db is not pdo
also pgsql does not like double quotes
---
lib/app.php | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/lib/app.php b/lib/app.php
index 6c882963a0..625ef88967 100755
--- a/lib/app.php
+++ b/lib/app.php
@@ -103,9 +103,9 @@ class OC_App{
*/
public static function getEnabledApps(){
$apps=array();
- $query = OC_DB::prepare( 'SELECT appid FROM *PREFIX*appconfig WHERE configkey = "enabled" AND configvalue="yes"' );
- $query->execute();
- while($row=$query->fetchRow()){
+ $query = OC_DB::prepare( 'SELECT appid FROM *PREFIX*appconfig WHERE configkey = \'enabled\' AND configvalue=\'yes\'' );
+ $result=$query->execute();
+ while($row=$result->fetchRow()){
$apps[]=$row['appid'];
}
return $apps;
@@ -452,7 +452,7 @@ class OC_App{
*/
public static function getAppVersions(){
$versions=array();
- $query = OC_DB::prepare( 'SELECT appid, configvalue FROM *PREFIX*appconfig WHERE configkey = "installed_version"' );
+ $query = OC_DB::prepare( 'SELECT appid, configvalue FROM *PREFIX*appconfig WHERE configkey = \'installed_version\'' );
$result = $query->execute();
while($row = $result->fetchRow()){
$versions[$row['appid']]=$row['configvalue'];
From cce59df2ae399bc43f1c11a3162b4855de70a1bc Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Sun, 1 Apr 2012 19:20:59 +0200
Subject: [PATCH 086/133] the core apps don't have types
---
lib/app.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/app.php b/lib/app.php
index 625ef88967..7d5e8fa91c 100755
--- a/lib/app.php
+++ b/lib/app.php
@@ -55,7 +55,7 @@ class OC_App{
// Our very own core apps are hardcoded
foreach( array('files', 'settings') as $app ){
- if(is_null($types) or self::isType($app,$types)){
+ if(is_null($types)){
require( $app.'/appinfo/app.php' );
}
}
From ff4b0c4d7f6b422c9426205897c015b497429b03 Mon Sep 17 00:00:00 2001
From: Michael Gapczynski
Date: Sun, 1 Apr 2012 13:30:41 -0400
Subject: [PATCH 087/133] Move writable check into local filestorage so shared
files can be renamed
---
lib/filestorage/local.php | 4 ++++
lib/filesystemview.php | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/lib/filestorage/local.php b/lib/filestorage/local.php
index 688501aee9..bd757f52ce 100644
--- a/lib/filestorage/local.php
+++ b/lib/filestorage/local.php
@@ -86,6 +86,10 @@ class OC_Filestorage_Local extends OC_Filestorage{
return $this->delTree($path);
}
public function rename($path1,$path2){
+ if (!$this->is_writable($path1)) {
+ OC_Log::write('core','unable to rename, file is not writable : '.$path1,OC_Log::ERROR);
+ return false;
+ }
if(! $this->file_exists($path1)){
OC_Log::write('core','unable to rename, file does not exists : '.$path1,OC_Log::ERROR);
return false;
diff --git a/lib/filesystemview.php b/lib/filesystemview.php
index a3736f1976..9d530c7ad6 100644
--- a/lib/filesystemview.php
+++ b/lib/filesystemview.php
@@ -192,7 +192,7 @@ class OC_FilesystemView {
return $this->basicOperation('unlink',$path,array('delete'));
}
public function rename($path1,$path2){
- if(OC_FileProxy::runPreProxies('rename',$path1,$path2) and $this->is_writable($path1) and OC_Filesystem::isValidPath($path2)){
+ if(OC_FileProxy::runPreProxies('rename',$path1,$path2) and OC_Filesystem::isValidPath($path2)){
$run=true;
OC_Hook::emit( OC_Filesystem::CLASSNAME, OC_Filesystem::signal_rename, array( OC_Filesystem::signal_param_oldpath => $path1 , OC_Filesystem::signal_param_newpath=>$path2, OC_Filesystem::signal_param_run => &$run));
if($run){
From 3e150ff548a8bf3b29729ab9b04a1f38538737f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20H=C3=BClsmann?=
Date: Mon, 2 Apr 2012 06:31:00 +0200
Subject: [PATCH 088/133] webfinger protocol compatible + minor changes
---
apps/remoteStorage/appinfo/webfinger.php | 4 +--
apps/user_webfinger/appinfo/install.php | 18 +++++++++++++-
apps/user_webfinger/webfinger.php | 31 +++++++++++++-----------
3 files changed, 36 insertions(+), 17 deletions(-)
diff --git a/apps/remoteStorage/appinfo/webfinger.php b/apps/remoteStorage/appinfo/webfinger.php
index bb3fe1681b..7c0ab84605 100644
--- a/apps/remoteStorage/appinfo/webfinger.php
+++ b/apps/remoteStorage/appinfo/webfinger.php
@@ -1,6 +1,6 @@
+ auth="/apps/remoteStorage/auth.php/">
diff --git a/apps/user_webfinger/appinfo/install.php b/apps/user_webfinger/appinfo/install.php
index 678d57ae8f..c8d9a42742 100644
--- a/apps/user_webfinger/appinfo/install.php
+++ b/apps/user_webfinger/appinfo/install.php
@@ -1,4 +1,8 @@
'*',
+ 'Content-Type' => 'application/xml+xrd'
+);
$appInfoDir = __DIR__;
$thisAppDir = dirname($appInfoDir);
$appsDir = dirname($thisAppDir);
@@ -17,6 +21,7 @@ if(isset($_SERVER['HTTPS'])) {
}
$lrddTmpl .= '://' . $serverName . $webRoot . '/apps/user_webfinger/webfinger.php?q={uri}';
$hostMetaPath = $docRoot . '/.well-known/host-meta';
+$hostMetaDir = $docRoot . '/.well-known';
$hostMetaContents = "
" . $serverName . "
@@ -24,7 +29,7 @@ $hostMetaContents = "
Resource Descriptor
";
-@mkdir(dirname($hostMetaPath));
+@mkdir($hostMetaDir);
$hostMeta = fopen($hostMetaPath, 'w');
if(!$hostMeta) {
die("Could not open " . $hostMetaPath . " for writing, please check permissions!");
@@ -33,3 +38,14 @@ if(!fwrite($hostMeta, $hostMetaContents, strlen($hostMetaContents))) {
die("Could not write to " . $hostMetaPath . ", please check permissions!");
}
fclose($hostMeta);
+
+// write custom headers into .htaccess:
+$htaccess = fopen($hostMetaDir . '/.htaccess', 'w');
+//TODO: check compatibility!
+fwrite($htaccess, "
+\n");
+foreach($hostMetaHeader as $header => $value) {
+ fwrite($htaccess, "Header set " . $header . " \"" . $value . "\"\n");
+}
+fwrite($htaccess, " \n ");
+fclose($htaccess);
diff --git a/apps/user_webfinger/webfinger.php b/apps/user_webfinger/webfinger.php
index ecbfeed8e4..9ada473ca8 100644
--- a/apps/user_webfinger/webfinger.php
+++ b/apps/user_webfinger/webfinger.php
@@ -6,13 +6,13 @@ header("Content-Type: application/xrd+xml");
* To include your app in the webfinger XML, add a new script with file name
* 'webfinger.php' to /apps/yourapp/appinfo/, which prints out the XML parts
* to be included. That script can make use of the constants WF_USER (e. g.
- * "user"), WF_ADDRESS ("user@host") and WF_ROOT ("https://host/owncloud").
+ * "user"), WF_ID (user@host) and WF_BASEURL (e. g. https://host/owncloud).
* An example could look like this:
*
*
+ * href="/apps/myApp/profile.php?user=">
*
*
'* but can also use complex database queries to generate the webfinger result
@@ -24,19 +24,25 @@ $SERVERROOT=str_replace("\\",'/',dirname(dirname(dirname(dirname(__FILE__)))));
$SUBURI=substr(realpath($_SERVER["SCRIPT_FILENAME"]),strlen($SERVERROOT));
$WEBROOT=substr($SUBURI,0,-34);
*/
-require_once('../../lib/base.php');
-$id = $_GET['q'];
+require_once('../../lib/base.php');
+$request = urldecode($_GET['q']);
if($_GET['q']) {
- $bits = explode('@', $_GET['q']);
- $userName = $bits[0];
+ $reqParts = explode('@', $request);
+ $userName = $reqParts[0];
+ $hostName = $reqParts[1];
} else {
- $id = '';
$userName = '';
+ $hostName = '';
}
if(substr($userName, 0, 5) == 'acct:') {
$userName = substr($userName, 5);
}
+if($userName == "") {
+ $id = "";
+} else {
+ $id = $userName . '@' . $hostName;
+}
if(isset($_SERVER['HTTPS'])) {
$baseAddress = 'https://';
} else {
@@ -44,22 +50,19 @@ if(isset($_SERVER['HTTPS'])) {
}
$baseAddress .= $_SERVER['SERVER_NAME'].OC::$WEBROOT;
define('WF_USER', $userName);
-define('WF_ADDRESS', $id);
-define('WF_ROOT', $baseAddress);
+define('WF_ID', $id);
+define('WF_BASEURL', $baseAddress);
echo "<";
?>
?xml version="1.0" encoding="UTF-8"?>
-
- acct:
+
+ acct:
Date: Mon, 2 Apr 2012 17:12:52 +0200
Subject: [PATCH 089/133] webfinger protocol compatible + minor changes
---
apps/remoteStorage/appinfo/webfinger.php | 4 +--
apps/user_webfinger/appinfo/install.php | 18 +++++++++++++-
apps/user_webfinger/webfinger.php | 31 +++++++++++++-----------
3 files changed, 36 insertions(+), 17 deletions(-)
diff --git a/apps/remoteStorage/appinfo/webfinger.php b/apps/remoteStorage/appinfo/webfinger.php
index bb3fe1681b..7c0ab84605 100644
--- a/apps/remoteStorage/appinfo/webfinger.php
+++ b/apps/remoteStorage/appinfo/webfinger.php
@@ -1,6 +1,6 @@
+ auth="/apps/remoteStorage/auth.php/">
diff --git a/apps/user_webfinger/appinfo/install.php b/apps/user_webfinger/appinfo/install.php
index 678d57ae8f..c8d9a42742 100644
--- a/apps/user_webfinger/appinfo/install.php
+++ b/apps/user_webfinger/appinfo/install.php
@@ -1,4 +1,8 @@
'*',
+ 'Content-Type' => 'application/xml+xrd'
+);
$appInfoDir = __DIR__;
$thisAppDir = dirname($appInfoDir);
$appsDir = dirname($thisAppDir);
@@ -17,6 +21,7 @@ if(isset($_SERVER['HTTPS'])) {
}
$lrddTmpl .= '://' . $serverName . $webRoot . '/apps/user_webfinger/webfinger.php?q={uri}';
$hostMetaPath = $docRoot . '/.well-known/host-meta';
+$hostMetaDir = $docRoot . '/.well-known';
$hostMetaContents = "
" . $serverName . "
@@ -24,7 +29,7 @@ $hostMetaContents = "
Resource Descriptor
";
-@mkdir(dirname($hostMetaPath));
+@mkdir($hostMetaDir);
$hostMeta = fopen($hostMetaPath, 'w');
if(!$hostMeta) {
die("Could not open " . $hostMetaPath . " for writing, please check permissions!");
@@ -33,3 +38,14 @@ if(!fwrite($hostMeta, $hostMetaContents, strlen($hostMetaContents))) {
die("Could not write to " . $hostMetaPath . ", please check permissions!");
}
fclose($hostMeta);
+
+// write custom headers into .htaccess:
+$htaccess = fopen($hostMetaDir . '/.htaccess', 'w');
+//TODO: check compatibility!
+fwrite($htaccess, "
+\n");
+foreach($hostMetaHeader as $header => $value) {
+ fwrite($htaccess, "Header set " . $header . " \"" . $value . "\"\n");
+}
+fwrite($htaccess, " \n ");
+fclose($htaccess);
diff --git a/apps/user_webfinger/webfinger.php b/apps/user_webfinger/webfinger.php
index ecbfeed8e4..9ada473ca8 100644
--- a/apps/user_webfinger/webfinger.php
+++ b/apps/user_webfinger/webfinger.php
@@ -6,13 +6,13 @@ header("Content-Type: application/xrd+xml");
* To include your app in the webfinger XML, add a new script with file name
* 'webfinger.php' to /apps/yourapp/appinfo/, which prints out the XML parts
* to be included. That script can make use of the constants WF_USER (e. g.
- * "user"), WF_ADDRESS ("user@host") and WF_ROOT ("https://host/owncloud").
+ * "user"), WF_ID (user@host) and WF_BASEURL (e. g. https://host/owncloud).
* An example could look like this:
*
*
+ * href="/apps/myApp/profile.php?user=">
*
*
'* but can also use complex database queries to generate the webfinger result
@@ -24,19 +24,25 @@ $SERVERROOT=str_replace("\\",'/',dirname(dirname(dirname(dirname(__FILE__)))));
$SUBURI=substr(realpath($_SERVER["SCRIPT_FILENAME"]),strlen($SERVERROOT));
$WEBROOT=substr($SUBURI,0,-34);
*/
-require_once('../../lib/base.php');
-$id = $_GET['q'];
+require_once('../../lib/base.php');
+$request = urldecode($_GET['q']);
if($_GET['q']) {
- $bits = explode('@', $_GET['q']);
- $userName = $bits[0];
+ $reqParts = explode('@', $request);
+ $userName = $reqParts[0];
+ $hostName = $reqParts[1];
} else {
- $id = '';
$userName = '';
+ $hostName = '';
}
if(substr($userName, 0, 5) == 'acct:') {
$userName = substr($userName, 5);
}
+if($userName == "") {
+ $id = "";
+} else {
+ $id = $userName . '@' . $hostName;
+}
if(isset($_SERVER['HTTPS'])) {
$baseAddress = 'https://';
} else {
@@ -44,22 +50,19 @@ if(isset($_SERVER['HTTPS'])) {
}
$baseAddress .= $_SERVER['SERVER_NAME'].OC::$WEBROOT;
define('WF_USER', $userName);
-define('WF_ADDRESS', $id);
-define('WF_ROOT', $baseAddress);
+define('WF_ID', $id);
+define('WF_BASEURL', $baseAddress);
echo "<";
?>
?xml version="1.0" encoding="UTF-8"?>
-
- acct:
+
+ acct:
Date: Mon, 2 Apr 2012 16:35:11 +0000
Subject: [PATCH 090/133] use OC_Dialogs instead of alert()
---
apps/files_texteditor/js/editor.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/files_texteditor/js/editor.js b/apps/files_texteditor/js/editor.js
index 02d39b9843..9a87601a4f 100644
--- a/apps/files_texteditor/js/editor.js
+++ b/apps/files_texteditor/js/editor.js
@@ -210,7 +210,7 @@ function showFileEditor(dir,filename){
});
} else {
// Failed to get the file.
- alert(result.data.message);
+ OC.dialogs.alert(result.data.message, t('files_texteditor','An error occurred!'));
}
// End success
}
From dc499c5b4e9dc1c64ca81487bfa979121bd407f6 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Mon, 2 Apr 2012 17:27:06 +0000
Subject: [PATCH 091/133] add * to filename when changes have been made
---
apps/files_texteditor/js/editor.js | 68 ++++++++++++++++++------------
1 file changed, 42 insertions(+), 26 deletions(-)
diff --git a/apps/files_texteditor/js/editor.js b/apps/files_texteditor/js/editor.js
index 9a87601a4f..ca6a3a965f 100644
--- a/apps/files_texteditor/js/editor.js
+++ b/apps/files_texteditor/js/editor.js
@@ -141,31 +141,38 @@ function doSearch(){
// Tries to save the file.
function doFileSave(){
if(editorIsShown()){
- // Get file path
- var path = $('#editor').attr('data-dir')+'/'+$('#editor').attr('data-filename');
- // Get original mtime
- var mtime = $('#editor').attr('data-mtime');
- // Show saving spinner
- $("#editor_save").die('click',doFileSave);
- $('#save_result').remove();
- $('#editor_save').text(t('files_texteditor','Saving...'));
- // Get the data
- var filecontents = window.aceEditor.getSession().getValue();
- // Send the data
- $.post(OC.filePath('files_texteditor','ajax','savefile.php'), { filecontents: filecontents, path: path, mtime: mtime },function(jsondata){
- if(jsondata.status!='success'){
- // Save failed
- $('#editor_save').text(t('files_texteditor','Save'));
- $('#editor_save').after('Failed to save file
');
- $("#editor_save").live('click',doFileSave);
- } else {
- // Save OK
- // Update mtime
- $('#editor').attr('data-mtime',jsondata.data.mtime);
- $('#editor_save').text(t('files_texteditor','Save'));
- $("#editor_save").live('click',doFileSave);
- }
- },'json');
+ // Changed contents?
+ if($('#editor').attr('data-edited')=='true'){
+ // Get file path
+ var path = $('#editor').attr('data-dir')+'/'+$('#editor').attr('data-filename');
+ // Get original mtime
+ var mtime = $('#editor').attr('data-mtime');
+ // Show saving spinner
+ $("#editor_save").die('click',doFileSave);
+ $('#save_result').remove();
+ $('#editor_save').text(t('files_texteditor','Saving...'));
+ // Get the data
+ var filecontents = window.aceEditor.getSession().getValue();
+ // Send the data
+ $.post(OC.filePath('files_texteditor','ajax','savefile.php'), { filecontents: filecontents, path: path, mtime: mtime },function(jsondata){
+ if(jsondata.status!='success'){
+ // Save failed
+ $('#editor_save').text(t('files_texteditor','Save'));
+ $('#editor_save').after('Failed to save file
');
+ $("#editor_save").live('click',doFileSave);
+ } else {
+ // Save OK
+ // Update mtime
+ $('#editor').attr('data-mtime',jsondata.data.mtime);
+ $('#editor_save').text(t('files_texteditor','Save'));
+ $("#editor_save").live('click',doFileSave);
+ // Update titles
+ $('#editor').attr('data-edited', 'false');
+ $('#breadcrumb_file').text($('#editor').attr('data-filename'));
+ document.title = $('#editor').attr('data-filename')+' - ownCloud';
+ }
+ },'json');
+ }
}
};
@@ -192,10 +199,11 @@ function showFileEditor(dir,filename){
// Show the control bar
showControls(filename,result.data.write);
// Update document title
- document.title = filename;
+ document.title = filename+' - ownCloud';
$('#editor').text(result.data.filecontents);
$('#editor').attr('data-dir', dir);
$('#editor').attr('data-filename', filename);
+ $('#editor').attr('data-edited', 'false');
window.aceEditor = ace.edit("editor");
aceEditor.setShowPrintMargin(false);
aceEditor.getSession().setUseWrapMode(true);
@@ -207,6 +215,13 @@ function showFileEditor(dir,filename){
OC.addScript('files_texteditor','aceeditor/theme-clouds', function(){
window.aceEditor.setTheme("ace/theme/clouds");
});
+ window.aceEditor.getSession().on('change', function(){
+ if($('#editor').attr('data-edited')!='true'){
+ $('#editor').attr('data-edited', 'true');
+ $('#breadcrumb_file').text($('#breadcrumb_file').text()+' *');
+ document.title = $('#editor').attr('data-filename')+' * - ownCloud';
+ }
+ });
});
} else {
// Failed to get the file.
@@ -287,4 +302,5 @@ $(document).ready(function(){
$('#editor').remove();
// Binds the save keyboard shortcut events
//$(document).unbind('keydown').bind('keydown',checkForSaveKeyPress);
+
});
From f21d6d4f9fcd48ffe4e2e42b4f3a4e8b7bcfd142 Mon Sep 17 00:00:00 2001
From: Bartek Przybylski
Date: Mon, 2 Apr 2012 19:39:24 +0200
Subject: [PATCH 092/133] dialogs filepicker first draft
---
core/css/styles.css | 6 +++
core/js/js.js | 8 +++-
core/js/oc-dialogs.js | 91 ++++++++++++++++++++++++++++++++++++------
files/ajax/rawlist.php | 23 +++++++++++
4 files changed, 114 insertions(+), 14 deletions(-)
create mode 100644 files/ajax/rawlist.php
diff --git a/core/css/styles.css b/core/css/styles.css
index f5a181c452..1c50df9e58 100644
--- a/core/css/styles.css
+++ b/core/css/styles.css
@@ -131,3 +131,9 @@ li.error { width:640px; margin:4em auto; padding:1em 1em 1em 4em; background:#ff
.separator { display: inline; border-left: 1px solid #d3d3d3; border-right: 1px solid #fff; height: 10px; width:0px; margin: 4px; }
a.bookmarklet { background-color: #ddd; border:1px solid #ccc; padding: 5px;padding-top: 0px;padding-bottom: 2px; text-decoration: none; margin-top: 5px }
+
+/* ---- DIALOGS ---- */
+
+#dirtree {width: 100%;}
+#filelist {height: 270px; overflow:scroll; background-color: white;}
+.filepicker_element_selected { background-color: lightblue;}
diff --git a/core/js/js.js b/core/js/js.js
index df1b5c6ce7..44b4f503b8 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -126,7 +126,13 @@ OC={
});
}
},
- dialogs:OCdialogs
+ dialogs:OCdialogs,
+ mtime2date:function(mtime) {
+ mtime = parseInt(mtime);
+ var date = new Date(1000*mtime);
+ var ret = date.getDate()+'.'+(date.getMonth()+1)+'.'+date.getFullYear()+', '+date.getHours()+':'+date.getMinutes();
+ return ret;
+ }
};
OC.search.customResults={};
OC.search.currentResult=-1;
diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js
index 17c987ae87..31aa76d96c 100644
--- a/core/js/oc-dialogs.js
+++ b/core/js/oc-dialogs.js
@@ -17,7 +17,6 @@
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see .
*
- * todo(bartek): add select option in form
*/
/**
@@ -30,9 +29,9 @@ OCdialogs = {
* @param title dialog title
* @param callback which will be triggered when user press OK
*/
- alert:function(text, title, callback) {
+ alert:function(text, title, callback, modal) {
var content = ' '+text+'
';
- OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.OK_BUTTON, callback);
+ OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.OK_BUTTON, callback, modal);
},
/**
* displays info dialog
@@ -40,9 +39,9 @@ OCdialogs = {
* @param title dialog title
* @param callback which will be triggered when user press OK
*/
- info:function(text, title, callback) {
+ info:function(text, title, callback, modal) {
var content = ' '+text+'
';
- OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.OK_BUTTON, callback);
+ OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.OK_BUTTON, callback, modal);
},
/**
* displays confirmation dialog
@@ -50,9 +49,9 @@ OCdialogs = {
* @param title dialog title
* @param callback which will be triggered when user press YES or NO (true or false would be passed to callback respectively)
*/
- confirm:function(text, title, callback) {
+ confirm:function(text, title, callback, modal) {
var content = ' '+text+'
';
- OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.YES_NO_BUTTONS, callback);
+ OCdialogs.message(content, title, OCdialogs.ALERT_DIALOG, OCdialogs.YES_NO_BUTTONS, callback, modal);
},
/**
* prompt for user input
@@ -60,9 +59,9 @@ OCdialogs = {
* @param title dialog title
* @param callback which will be triggered when user press OK (input text will be passed to callback)
*/
- prompt:function(text, title, default_value, callback) {
+ prompt:function(text, title, default_value, callback, modal) {
var content = ' '+text+':
';
- OCdialogs.message(content, title, OCdialogs.PROMPT_DIALOG, OCdialogs.OK_CANCEL_BUTTONS, callback);
+ OCdialogs.message(content, title, OCdialogs.PROMPT_DIALOG, OCdialogs.OK_CANCEL_BUTTONS, callback, modal);
},
/**
* prompt user for input with custom form
@@ -71,7 +70,7 @@ OCdialogs = {
* @param title dialog title
* @param callback which will be triggered when user press OK (user answers will be passed to callback in following format: [{name:'return name', value: 'user value'},...])
*/
- form:function(fields, title, callback) {
+ form:function(fields, title, callback, modal) {
var content = '';
for (var a in fields) {
content += ''+fields[a].text+' ';
@@ -96,12 +95,41 @@ OCdialogs = {
content += ' ';
}
content += '
';
- OCdialogs.message(content, title, OCdialogs.FORM_DIALOG, OCdialogs.OK_CANCEL_BUTTONS, callback);
+ OCdialogs.message(content, title, OCdialogs.FORM_DIALOG, OCdialogs.OK_CANCEL_BUTTONS, callback, modal);
},
- message:function(content, title, dialog_type, buttons, callback) {
+ filepicker:function(title, name_filter, mimetype_filter, callback, modal) {
+ var c_name = 'oc-dialog-'+OCdialogs.dialogs_counter+'-content';
+ var c_id = '#'+c_name;
+ var d = '';
+ if (modal == undefined) modal = false;
+ $('body').append(d);
+ $(c_id + ' #dirtree').focus(function() { var t = $(this); t.data('oldval', t.val())})
+ .change({dcid: c_id}, OC.dialogs.handleTreeListSelect);
+ $(c_id).ready(function(){
+ $.getJSON(OC.webroot+'/files/ajax/rawlist.php', function(r){OC.dialogs.fillFilePicker(r, c_id, callback)});
+ });
+ // build buttons
+ var b = [
+ {text: t('dialogs', 'Choose'), click: function(){
+ if (callback != undefined) {
+ var p = $(c_id).attr('data');
+ if (p == undefined) p = '';
+ callback(p+'/'+$(c_id+' .filepicker_element_selected #filename').text());
+ $(c_id).dialog('close');
+ }
+ }
+ },
+ {text: t('dialogs', 'Cancel'), click: function(){$(c_id).dialog('close'); }}
+ ];
+ $(c_id).dialog({width: 4*$(document).width()/9, height: 400, modal: modal, buttons: b});
+ OCdialogs.dialogs_counter++;
+ },
+ // guts, dont use, dont touch
+ message:function(content, title, dialog_type, buttons, callback, modal) {
var c_name = 'oc-dialog-'+OCdialogs.dialogs_counter+'-content';
var c_id = '#'+c_name;
var d = ''+content+'
';
+ if (modal == undefined) modal = false;
$('body').append(d);
var b = [];
switch (buttons) {
@@ -128,7 +156,7 @@ OCdialogs = {
break;
}
var possible_height = ($('tr', d).size()+1)*30;
- $(c_id).dialog({width: 4*$(document).width()/9, height: possible_height + 120, modal: false, buttons: b});
+ $(c_id).dialog({width: 4*$(document).width()/9, height: possible_height + 120, modal: modal, buttons: b});
OCdialogs.dialogs_counter++;
},
// dialogs buttons types
@@ -161,5 +189,42 @@ OCdialogs = {
} else {
$(c_id).dialog('close');
}
+ },
+ fillFilePicker:function(r, dialog_content_id) {
+ var entry_template = '*NAME* *LASTMODDATE*
';
+ var names = '';
+ for (var a in r.data) {
+ names += entry_template.replace('*LASTMODDATE*', OC.mtime2date(r.data[a].mtime)).replace('*NAME*', r.data[a].name).replace('*MIMETYPEICON*', OC.webroot+'/core/img/filetypes/'+(r.data[a].type=='dir'?'folder':r.data[a].mimetype.replace('/','-'))+'.png').replace('*ENTRYNAME*', r.data[a].name).replace('*ENTRYTYPE*', r.data[a].type);
+ }
+ $(dialog_content_id + ' #filelist').html(names);
+ },
+ handleTreeListSelect:function(event) {
+ var newval = parseInt($(this).val());
+ var oldval = parseInt($(this).data('oldval'));
+ while (newval != oldval && oldval > 0) {
+ $('option:last', this).remove();
+ $('option:last', this).attr('selected','selected');
+ oldval--;
+ }
+ var skip_first = true;
+ var path = '';
+ $(this).children().each(function(i, element) { if (skip_first) {skip_first = false; return; }path += '/'+$(element).text(); });
+ $(event.data.dcid).attr('data', path);
+ $.getJSON(OC.webroot+'/files/ajax/rawlist.php', {dir: path}, function(r){OC.dialogs.fillFilePicker(r, event.data.dcid)});
+ },
+ // this function is in early development state, please dont use it unlsess you know what you are doing
+ handlePickerClick:function(element, name, dcid) {
+ var p = $(dcid).attr('data');
+ if (p == undefined) p = '';
+ p = p+'/'+name;
+ if ($(element).attr('data') == 'file'){
+ $(element).toggleClass('filepicker_element_selected');
+ return;
+ }
+ $(dcid).attr('data', p);
+ $(dcid + ' #dirtree option:last').removeAttr('selected');
+ var newval = parseInt($(dcid + ' #dirtree option:last').val())+1;
+ $(dcid + ' #dirtree').append(''+name+' ');
+ $.getJSON(OC.webroot+'/files/ajax/rawlist.php', {dir: p}, function(r){OC.dialogs.fillFilePicker(r, dcid)});
}
};
diff --git a/files/ajax/rawlist.php b/files/ajax/rawlist.php
new file mode 100644
index 0000000000..0abe81e672
--- /dev/null
+++ b/files/ajax/rawlist.php
@@ -0,0 +1,23 @@
+ $files));
+
+?>
From adc9d906e4b45082dc08463afce6835a49feb438 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Mon, 2 Apr 2012 17:44:15 +0000
Subject: [PATCH 093/133] confirm close when there are unsaved changes
---
apps/files_texteditor/js/editor.js | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/apps/files_texteditor/js/editor.js b/apps/files_texteditor/js/editor.js
index ca6a3a965f..1e136fe68e 100644
--- a/apps/files_texteditor/js/editor.js
+++ b/apps/files_texteditor/js/editor.js
@@ -76,7 +76,7 @@ function showControls(filename,writeperms){
function bindControlEvents(){
$("#editor_save").die('click',doFileSave).live('click',doFileSave);
- $('#editor_close').die('click',hideFileEditor).live('click',hideFileEditor);
+ $('#editor_close').die('click',closeBtnClick).live('click',closeBtnClick);
$('#gotolineval').die('keyup', goToLine).live('keyup', goToLine);
$('#editorsearchval').die('keyup', doSearch).live('keyup', doSearch);
$('#clearsearchbtn').die('click', resetSearch).live('click', resetSearch);
@@ -235,6 +235,19 @@ function showFileEditor(dir,filename){
}
}
+function closeBtnClick(){
+ if($('#editor').attr('data-edited')=='true'){
+ // Show confirm
+ OC.dialogs.confirm(t('files_texteditor','You have unsaved changes that will be lost! Do you still want to close?'),t('files_texteditor','Really close?'),function(close){
+ if(close){
+ hideFileEditor();
+ }
+ });
+ } else {
+ hideFileEditor();
+ }
+}
+
// Fades out the editor.
function hideFileEditor(){
// Fades out editor controls
From ff5dbc52b8137bc1d4e082c422049271d5f89978 Mon Sep 17 00:00:00 2001
From: Bartek Przybylski
Date: Mon, 2 Apr 2012 21:31:34 +0200
Subject: [PATCH 094/133] multiselect handle for filepicker
---
core/js/oc-dialogs.js | 30 +++++++++++++++++++++---------
1 file changed, 21 insertions(+), 9 deletions(-)
diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js
index 31aa76d96c..d40c433bda 100644
--- a/core/js/oc-dialogs.js
+++ b/core/js/oc-dialogs.js
@@ -97,24 +97,34 @@ OCdialogs = {
content += '
';
OCdialogs.message(content, title, OCdialogs.FORM_DIALOG, OCdialogs.OK_CANCEL_BUTTONS, callback, modal);
},
- filepicker:function(title, name_filter, mimetype_filter, callback, modal) {
+ filepicker:function(title, callback, multiselect, mimetype_filter, modal) {
var c_name = 'oc-dialog-'+OCdialogs.dialogs_counter+'-content';
var c_id = '#'+c_name;
var d = '';
- if (modal == undefined) modal = false;
+ if (!modal) modal = false;
+ if (!multiselect) multiselect = false;
$('body').append(d);
$(c_id + ' #dirtree').focus(function() { var t = $(this); t.data('oldval', t.val())})
.change({dcid: c_id}, OC.dialogs.handleTreeListSelect);
$(c_id).ready(function(){
$.getJSON(OC.webroot+'/files/ajax/rawlist.php', function(r){OC.dialogs.fillFilePicker(r, c_id, callback)});
- });
+ }).data('multiselect', multiselect);
// build buttons
var b = [
{text: t('dialogs', 'Choose'), click: function(){
if (callback != undefined) {
- var p = $(c_id).attr('data');
- if (p == undefined) p = '';
- callback(p+'/'+$(c_id+' .filepicker_element_selected #filename').text());
+ var p;
+ if ($(c_id).data('multiselect') == true) {
+ p = [];
+ $(c_id+' .filepicker_element_selected #filename').each(function(i, elem) {
+ p.push(($(c_id).data('path')?$(c_id).data('path'):'')+'/'+$(elem).text());
+ });
+ } else {
+ var p = $(c_id).data('path');
+ if (p == undefined) p = '';
+ p = p+'/'+$(c_id+' .filepicker_element_selected #filename').text()
+ }
+ callback(p);
$(c_id).dialog('close');
}
}
@@ -209,19 +219,21 @@ OCdialogs = {
var skip_first = true;
var path = '';
$(this).children().each(function(i, element) { if (skip_first) {skip_first = false; return; }path += '/'+$(element).text(); });
- $(event.data.dcid).attr('data', path);
+ $(event.data.dcid).data('path', path);
$.getJSON(OC.webroot+'/files/ajax/rawlist.php', {dir: path}, function(r){OC.dialogs.fillFilePicker(r, event.data.dcid)});
},
// this function is in early development state, please dont use it unlsess you know what you are doing
handlePickerClick:function(element, name, dcid) {
- var p = $(dcid).attr('data');
+ var p = $(dcid).data('path');
if (p == undefined) p = '';
p = p+'/'+name;
if ($(element).attr('data') == 'file'){
+ if ($(dcid).data('multiselect') != true)
+ $(dcid+' .filepicker_element_selected').removeClass('filepicker_element_selected');
$(element).toggleClass('filepicker_element_selected');
return;
}
- $(dcid).attr('data', p);
+ $(dcid).data('path', p);
$(dcid + ' #dirtree option:last').removeAttr('selected');
var newval = parseInt($(dcid + ' #dirtree option:last').val())+1;
$(dcid + ' #dirtree').append(''+name+' ');
From 896bff57480448456b2ca7d57f5ff2b0439315f6 Mon Sep 17 00:00:00 2001
From: Thomas Tanghus
Date: Thu, 29 Mar 2012 18:54:06 +0200
Subject: [PATCH 095/133] Contacts: rescan categories on load if there are
none.
---
apps/contacts/index.php | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/apps/contacts/index.php b/apps/contacts/index.php
index 04f6c65a14..076b10c2ee 100644
--- a/apps/contacts/index.php
+++ b/apps/contacts/index.php
@@ -34,7 +34,28 @@ if(!is_null($id)) {
}
$property_types = OC_Contacts_App::getAddPropertyOptions();
$phone_types = OC_Contacts_App::getTypesOfProperty('TEL');
-$categories = OC_Contacts_App::$categories->categories();
+$categories = OC_Contacts_App::getCategories();
+if(count($categories) == 0) {
+ $vcaddressbooks = OC_Contacts_Addressbook::all(OC_User::getUser());
+ if(count($vcaddressbooks) > 0) {
+ $vcaddressbookids = array();
+ foreach($vcaddressbooks as $vcaddressbook) {
+ $vcaddressbookids[] = $vcaddressbook['id'];
+ }
+ $vccontacts = OC_Contacts_VCard::all($vcaddressbookids);
+ if(count($vccontacts) == 0) {
+ bailOut(OC_Contacts_App::$l10n->t('No contacts found.'));
+ }
+
+ $cards = array();
+ foreach($vccontacts as $vccontact) {
+ $cards[] = $vccontact['carddata'];
+ }
+
+ OC_Contacts_App::$categories->rescan($cards);
+ $categories = OC_Contacts_App::$categories->categories();
+ }
+}
$upload_max_filesize = OC_Helper::computerFileSize(ini_get('upload_max_filesize'));
$post_max_size = OC_Helper::computerFileSize(ini_get('post_max_size'));
@@ -61,7 +82,6 @@ $tmpl = new OC_Template( "contacts", "index", "user" );
$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize);
$tmpl->assign('uploadMaxHumanFilesize', OC_Helper::humanFileSize($maxUploadFilesize));
$tmpl->assign('property_types',$property_types);
-$tmpl->assign('categories',OC_Contacts_App::getCategories());
$tmpl->assign('phone_types',$phone_types);
$tmpl->assign('categories',$categories);
$tmpl->assign('addressbooks', $addressbooks);
From b3f107dddaf4f3b5b65d8dd67d66bf1bd36d9ae1 Mon Sep 17 00:00:00 2001
From: Thomas Tanghus
Date: Tue, 3 Apr 2012 03:28:12 +0200
Subject: [PATCH 096/133] Contacts: First work on cleaner design.
---
apps/contacts/ajax/addcontact.php | 5 +-
apps/contacts/css/contacts.css | 32 ++++----
apps/contacts/img/person_large.png | Bin 11517 -> 7929 bytes
apps/contacts/js/contacts.js | 74 ++++++++++--------
apps/contacts/js/jquery.combobox.js | 23 +++---
apps/contacts/js/jquery.multi-autocomplete.js | 4 +-
apps/contacts/templates/part.contact.php | 73 ++++++++---------
7 files changed, 113 insertions(+), 98 deletions(-)
diff --git a/apps/contacts/ajax/addcontact.php b/apps/contacts/ajax/addcontact.php
index 839a391998..947b35bab5 100644
--- a/apps/contacts/ajax/addcontact.php
+++ b/apps/contacts/ajax/addcontact.php
@@ -39,7 +39,10 @@ foreach ($_POST as $key=>$element) {
debug('_POST: '.$key.'=>'.$element);
}
-$aid = $_POST['aid'];
+$aid = isset($_POST['aid'])?$_POST['aid']:null;
+if(!$aid) {
+ $aid = min(OC_Contacts_Addressbook::activeIds()); // first active addressbook.
+}
OC_Contacts_App::getAddressbook( $aid ); // is owner access check
$fn = trim($_POST['fn']);
diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css
index 76b5972ba3..9d238c36f3 100644
--- a/apps/contacts/css/contacts.css
+++ b/apps/contacts/css/contacts.css
@@ -14,21 +14,21 @@
#contacts_propertymenu li:hover { background-color: #1d2d44; }
#contacts_propertymenu li a:hover { color: #fff }
#actionbar { height: 30px; width: 200px; position: fixed; right: 0px; top: 75px; margin: 0 0 0 0; padding: 0 0 0 0;}
-#card { /*max-width: 70em; border: thin solid lightgray; display: block;*/ }
+#card { width: auto;/*max-width: 70em; border: thin solid lightgray; display: block;*/ }
#firstrun { width: 100%; position: absolute; top: 5em; left: 0; text-align: center; font-weight:bold; font-size:1.5em; color:#777; }
#firstrun #selections { font-size:0.8em; margin: 2em auto auto auto; clear: both; }
-#card input[type="text"].contacts_property,input[type="email"].contacts_property { width: 14em; }
+#card input[type="text"].contacts_property,input[type="email"].contacts_property { width: 14em; float: left; }
.categories { float: left; width: 16em; }
-#card input[type="text"],input[type="email"],input[type="tel"],input[type="date"], select { background-color: #f8f8f8; border: 0 !important; -webkit-appearance:none !important; -moz-appearance:none !important; -webkit-box-sizing:none !important; -moz-box-sizing:none !important; box-sizing:none !important; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; float: left; }
+#card input[type="text"],input[type="email"],input[type="tel"],input[type="date"], select { background-color: #fefefe; border: 0 !important; -webkit-appearance:none !important; -moz-appearance:none !important; -webkit-box-sizing:none !important; -moz-box-sizing:none !important; box-sizing:none !important; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; float: left; }
#card input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active,input[type="email"]:hover,input[type="tel"]:hover,input[type="date"]:hover,input[type="date"],input[type="date"]:hover,input[type="date"]:active,input[type="date"]:active,input[type="date"]:active,input[type="email"]:active,input[type="tel"]:active, select:hover, select:focus, select:active { border: 0 !important; -webkit-appearance:textfield; -moz-appearance:textfield; -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box; background:#fff; color:#333; border:1px solid #ddd; -moz-box-shadow:0 1px 1px #fff, 0 2px 0 #bbb inset; -webkit-box-shadow:0 1px 1px #fff, 0 1px 0 #bbb inset; box-shadow:0 1px 1px #fff, 0 1px 0 #bbb inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; outline:none; float: left; }
-input[type="text"]:invalid,input[type="email"]:invalid,input[type="tel"]:invalid,input[type="date"]:invalid { background-color: #ffc0c0 !important; }
+input[type="text"]:invalid,input[type="email"]:invalid,input[type="tel"]:invalid,input[type="date"]:invalid { color: #bbb !important; }
dl.form { width: 100%; float: left; clear: right; margin: 0; padding: 0; }
-.form dt { display: table-cell; clear: left; float: left; width: 7em; margin: 0; padding: 0.8em 0.5em 0 0; font-weight: bold; text-align:right; text-overflow:ellipsis; o-text-overflow: ellipsis; vertical-align: text-bottom;/* white-space: pre-wrap; white-space: -moz-pre-wrap !important; white-space: -pre-wrap; white-space: -o-pre-wrap;*/ }
+.form dt { display: table-cell; clear: left; float: left; width: 7em; margin: 0; padding: 0.8em 0.5em 0 0; text-align:right; text-overflow:ellipsis; o-text-overflow: ellipsis; vertical-align: text-bottom; color: #bbb;/* white-space: pre-wrap; white-space: -moz-pre-wrap !important; white-space: -pre-wrap; white-space: -o-pre-wrap;*/ }
.form dd { display: table-cell; clear: right; float: left; margin: 0; padding: 0px; white-space: nowrap; vertical-align: text-bottom; }
.loading { background: url('../../../core/img/loading.gif') no-repeat center !important; /*cursor: progress; */ cursor: wait; }
-
+.float { float: left; }
.listactions { height: 1em; width:60px; float: left; clear: right; }
.add,.edit,.delete,.mail, .globe { cursor: pointer; width: 20px; height: 20px; margin: 0; float: left; position:relative; display: none; }
.add { background:url('../../../core/img/actions/add.svg') no-repeat center; clear: both; }
@@ -43,18 +43,18 @@ dl.form { width: 100%; float: left; clear: right; margin: 0; padding: 0; }
#edit_address_dialog { /*width: 30em;*/ }
#edit_address_dialog > input { width: 15em; }
#edit_photo_dialog_img { display: block; width: 150; height: 200; border: thin solid black; }
-#fn { float: left; }
-/**
- * Create classes form, floateven and floatodd which flows left and right respectively.
- */
-.contactsection { float: left; min-width: 30em; max-width: 40em; margin: 0.5em; border: thin solid lightgray; -webkit-border-radius: 0.5em; -moz-border-radius: 0.5em; border-radius: 0.5em; background-color: #f8f8f8; }
+#fn { float: left !important; width: 18em !important; }
+#name { /*position: absolute; top: 0px; left: 0px;*/ min-width: 25em; height: 2em; clear: right; display: block; }
+#identityprops { /*position: absolute; top: 2.5em; left: 0px;*/ }
+/*#contact_photo { max-width: 250px; }*/
+#contact_identity { min-width: 30em; }
+.contactsection { position: relative; float: left; /*max-width: 40em;*/ padding: 0.5em; height: auto: border: thin solid lightgray;/* -webkit-border-radius: 0.5em; -moz-border-radius: 0.5em; border-radius: 0.5em; background-color: #f8f8f8;*/ }
.contactpart legend { width:auto; padding:.3em; border:1px solid #ddd; font-weight:bold; cursor:pointer; background:#f8f8f8; color:#555; text-shadow:#fff 0 1px 0; -moz-box-shadow:0 1px 1px #fff, 0 1px 1px #fff inset; -webkit-box-shadow:0 1px 1px #fff, 0 1px 1px #fff inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; }
#cropbox { margin: auto; }
-
-#contacts_details_photo { border-radius: 0.5em; border: thin solid #bbb; padding: 0.5em; margin: 1em 1em 1em 7em; cursor: pointer; background: url(../../../core/img/loading.gif) no-repeat center center; clear: right; }
+#contacts_details_photo { border-radius: 0.5em; border: thin solid #bbb; padding: 0.5em; margin: 0.3em; cursor: pointer; background: url(../../../core/img/loading.gif) no-repeat center center; display: block; /* clear: right;*/ }
#contacts_details_photo:hover { background: #fff; }
-#contacts_details_photo_progress { margin: 0.3em 0.3em 0.3em 7em; clear: left; }
+/*#contacts_details_photo_progress { margin: 0.3em 0.3em 0.3em 7em; clear: left; }*/
/* Address editor */
#addressdisplay { padding: 0.5em; }
dl.addresscard { background-color: #fff; float: left; width: 45%; margin: 0 0.3em 0.3em 0.3em; padding: 0; border: thin solid lightgray; }
@@ -72,8 +72,10 @@ dl.addresscard dd > ul { margin: 0.3em; padding: 0.3em; }
#file_upload_target, #crop_target { display:none; }
-#file_upload_start { opacity:0; filter:alpha(opacity=0); z-index:1; position:absolute; left:0; top:0; cursor:pointer; width:0; height:0;}
+#file_upload_start { opacity:0; filter:alpha(opacity=0); z-index:1; /*position:absolute; left:0; top:0;*/ cursor:pointer; width:0; height:0;}
input[type="checkbox"] { width: 20px; height: 20px; vertical-align: bottom; }
+.big { font-weight:bold; font-size:1.2em; }
+.huge { font-weight:bold; font-size:1.5em; }
.propertycontainer dd { float: left; width: 25em; }
.propertylist { clear: none; max-width: 28em; }
.propertylist li { /*background-color: cyan; */ min-width: 25em; /*max-width: 30em;*/ display: block; clear: right; }
diff --git a/apps/contacts/img/person_large.png b/apps/contacts/img/person_large.png
index f57511e1000690c223bc5de2313ddfface12f29a..4edba0c5489d1e92b35f9f813189bd8b7c391f17 100644
GIT binary patch
literal 7929
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
G-Twfpl}P*m
diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js
index d314878cc0..e838d713d4 100644
--- a/apps/contacts/js/contacts.js
+++ b/apps/contacts/js/contacts.js
@@ -65,7 +65,7 @@ Contacts={
propertyTypeFor:function(obj) {
return $(obj).parents('.propertycontainer').first().data('element');
},
- showHideContactInfo:function() {
+ /*showHideContactInfo:function() {
var show = ($('#emaillist li.propertycontainer').length > 0 || $('#phonelist li.propertycontainer').length > 0 || $('#addressdisplay dl.propertycontainer').length > 0);
console.log('showHideContactInfo: ' + show);
if(show) {
@@ -73,8 +73,8 @@ Contacts={
} else {
$('#contact_communication').hide();
}
- },
- checkListFor:function(obj) {
+ },*/
+ /*checkListFor:function(obj) {
var type = $(obj).parents('.propertycontainer').first().data('element');
console.log('checkListFor: ' + type);
switch (type) {
@@ -101,7 +101,7 @@ Contacts={
case 'BDAY':
break;
}
- },
+ },*/
loading:function(obj, state) {
if(state) {
$(obj).addClass('loading');
@@ -137,18 +137,14 @@ Contacts={
$(this).find('.add').fadeOut(500);
}
);*/
- $('.button,.action').tipsy();
- $('#contacts_deletecard').tipsy({gravity: 'ne'});
- $('#contacts_downloadcard').tipsy({gravity: 'ne'});
//$('#fn').jec();
$('#fn_select').combobox({
'id': 'fn',
'name': 'value',
- 'classes': ['contacts_property'],
+ 'classes': ['contacts_property', 'huge', 'tip', 'float'],
+ 'attributes': {'placeholder': t('contacts', 'Enter name')},
'title': t('contacts', 'Format custom, Short name, Full name, Reverse or Reverse with comma')});
//$('.jecEditableOption').attr('title', t('contacts','Custom'));
- $('#fn').tipsy();
- $('#contacts_details_photo_wrapper').tipsy();
$('#bday').datepicker({
dateFormat : 'dd-mm-yy'
});
@@ -200,6 +196,9 @@ Contacts={
}
] );
$('#categories').multiple_autocomplete({source: categories});
+ $('.button,.action,.tip').tipsy();
+ $('#contacts_deletecard').tipsy({gravity: 'ne'});
+ $('#contacts_downloadcard').tipsy({gravity: 'ne'});
Contacts.UI.loadListHandlers();
},
Card:{
@@ -267,7 +266,7 @@ Contacts={
import:function(){
Contacts.UI.notImplemented();
},
- add:function(n, fn, aid){ // add a new contact
+ add:function(n, fn, aid, isnew){ // add a new contact
console.log('Add contact: ' + n + ', ' + fn + ' ' + aid);
$.post(OC.filePath('contacts', 'ajax', 'addcontact.php'), { n: n, fn: fn, aid: aid },
function(jsondata) {
@@ -291,7 +290,15 @@ Contacts={
if(!added) {
$('#leftcontent ul').append(item);
}
-
+ if(isnew) {
+ Contacts.UI.Card.addProperty('EMAIL');
+ Contacts.UI.Card.addProperty('TEL');
+ Contacts.UI.Card.addProperty('BDAY');
+ Contacts.UI.Card.addProperty('NICKNAME');
+ Contacts.UI.Card.addProperty('ORG');
+ Contacts.UI.Card.addProperty('CATEGORIES');
+ $('#fn').focus();
+ }
}
else{
OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
@@ -356,7 +363,7 @@ Contacts={
return false;
},
loadContact:function(jsondata){
- $('#contact_communication').hide();
+ //$('#contact_communication').hide();
this.data = jsondata;
this.id = this.data.id;
$('#rightcontent').data('id',this.id);
@@ -368,7 +375,6 @@ Contacts={
this.loadPhones();
this.loadAddresses();
this.loadSingleProperties();
- // TODO: load NOTE ;-)
if(this.data.NOTE) {
$('#note').data('checksum', this.data.NOTE[0]['checksum']);
$('#note').find('textarea').val(this.data.NOTE[0]['value']);
@@ -376,7 +382,7 @@ Contacts={
} else {
$('#note').data('checksum', '');
$('#note').find('textarea').val('');
- $('#note').hide();
+ //$('#note').hide();
}
},
loadSingleProperties:function() {
@@ -521,17 +527,18 @@ Contacts={
},*/
editNew:function(){ // add a new contact
this.id = ''; this.fn = ''; this.fullname = ''; this.givname = ''; this.famname = ''; this.addname = ''; this.honpre = ''; this.honsuf = '';
- $.getJSON(OC.filePath('contacts', 'ajax', 'newcontact.php'),{},function(jsondata){
+ Contacts.UI.Card.add(';;;;', '', '', true);
+ /*$.getJSON(OC.filePath('contacts', 'ajax', 'newcontact.php'),{},function(jsondata){
if(jsondata.status == 'success'){
id = '';
$('#rightcontent').data('id','');
$('#rightcontent').html(jsondata.data.page);
- Contacts.UI.Card.editName();
+ //Contacts.UI.Card.editName();
} else {
OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
//alert(jsondata.data.message);
}
- });
+ });*/
},
savePropertyInternal:function(name, fields, oldchecksum, checksum){
// TODO: Add functionality for new fields.
@@ -627,8 +634,8 @@ Contacts={
},'json');
}
},
- addProperty:function(obj){
- var type = $(obj).data('type');
+ addProperty:function(type){
+ //var type = $(obj).data('type');
console.log('addProperty:' + type);
switch (type) {
case 'PHOTO':
@@ -647,21 +654,21 @@ Contacts={
$('#emails').show();
}
Contacts.UI.Card.addMail();
- Contacts.UI.showHideContactInfo();
+ //Contacts.UI.showHideContactInfo();
break;
case 'TEL':
if($('#phonelist>li').length == 1) {
$('#phones').show();
}
Contacts.UI.Card.addPhone();
- Contacts.UI.showHideContactInfo();
+ //Contacts.UI.showHideContactInfo();
break;
case 'ADR':
if($('#addressdisplay>dl').length == 1) {
$('#addresses').show();
}
Contacts.UI.Card.editAddress('new', true);
- Contacts.UI.showHideContactInfo();
+ //Contacts.UI.showHideContactInfo();
break;
case 'NICKNAME':
case 'ORG':
@@ -682,8 +689,8 @@ Contacts={
if(jsondata.status == 'success'){
if(type == 'list') {
Contacts.UI.propertyContainerFor(obj).remove();
- Contacts.UI.showHideContactInfo();
- Contacts.UI.checkListFor(obj);
+ //Contacts.UI.showHideContactInfo();
+ //Contacts.UI.checkListFor(obj);
} else if(type == 'single') {
var proptype = Contacts.UI.propertyTypeFor(obj);
console.log('deleteProperty, hiding: ' + proptype);
@@ -718,8 +725,8 @@ Contacts={
} else { // Property hasn't been saved so there's nothing to delete.
if(type == 'list') {
Contacts.UI.propertyContainerFor(obj).remove();
- Contacts.UI.showHideContactInfo();
- Contacts.UI.checkListFor(obj);
+ //Contacts.UI.showHideContactInfo();
+ //Contacts.UI.checkListFor(obj);
} else if(type == 'single') {
var proptype = Contacts.UI.propertyTypeFor(obj);
console.log('deleteProperty, hiding: ' + proptype);
@@ -891,7 +898,7 @@ Contacts={
if(isnew) {
container.remove();
}
- Contacts.UI.showHideContactInfo();
+ //Contacts.UI.showHideContactInfo();
}
},
close : function(event, ui) {
@@ -900,7 +907,7 @@ Contacts={
if(isnew) {
container.remove();
}
- Contacts.UI.showHideContactInfo();
+ //Contacts.UI.showHideContactInfo();
}/*,
open : function(event, ui) {
// load 'ADR' property - maybe :-P
@@ -973,7 +980,7 @@ Contacts={
}
},
loadPhoto:function(force){
- if(this.data.PHOTO||force==true) {
+ //if(this.data.PHOTO||force==true) {
$.getJSON('ajax/loadphoto.php',{'id':this.id},function(jsondata){
if(jsondata.status == 'success'){
//alert(jsondata.data.page);
@@ -986,11 +993,11 @@ Contacts={
});
$('#file_upload_form').show();
$('#contacts_propertymenu a[data-type="PHOTO"]').parent().hide();
- } else {
+ /*} else {
$('#contacts_details_photo_wrapper').empty();
$('#file_upload_form').hide();
$('#contacts_propertymenu a[data-type="PHOTO"]').parent().show();
- }
+ }*/
},
editPhoto:function(id, tmp_path){
//alert('editPhoto: ' + tmp_path);
@@ -1430,7 +1437,8 @@ $(document).ready(function(){
}
});
$('#contacts_propertymenu a').live('click',function(){
- Contacts.UI.Card.addProperty(this);
+ var type = $(this).data('type');
+ Contacts.UI.Card.addProperty(type);
$('#contacts_propertymenu').hide();
});
});
diff --git a/apps/contacts/js/jquery.combobox.js b/apps/contacts/js/jquery.combobox.js
index 6da4ecb514..f46d7c14c1 100644
--- a/apps/contacts/js/jquery.combobox.js
+++ b/apps/contacts/js/jquery.combobox.js
@@ -72,17 +72,10 @@
.appendTo( ul );
};
- this.button = $( " " )
+ /*this.button = $( " " )
.attr( "tabIndex", -1 )
.attr( "title", "Show All Items" )
.insertAfter( input )
- /*.button({
- icons: {
- primary: "ui-icon-triangle-1-s"
- },
- text: false
- })
- .removeClass( "ui-corner-all" )*/
.addClass('svg')
.addClass('action')
.addClass('combo-button')
@@ -99,7 +92,7 @@
// pass empty string as value to search for, displaying all results
input.autocomplete( "search", "" );
input.focus();
- });
+ });*/
$.each(this.options, function(key, value) {
self._setOption(key, value);
});
@@ -123,17 +116,23 @@
case "id":
this.options['id'] = value;
this.input.attr('id', value);
- break;
+ break;
case "name":
this.options['name'] = value;
this.input.attr('name', value);
- break;
+ break;
+ case "attributes":
+ var input = this.input;
+ $.each(this.options['attributes'], function(key, value) {
+ input.attr(key, value);
+ });
+ break;
case "classes":
var input = this.input;
$.each(this.options['classes'], function(key, value) {
input.addClass(value);
});
- break;
+ break;
}
// In jQuery UI 1.8, you have to manually invoke the _setOption method from the base widget
$.Widget.prototype._setOption.apply( this, arguments );
diff --git a/apps/contacts/js/jquery.multi-autocomplete.js b/apps/contacts/js/jquery.multi-autocomplete.js
index 7607de3f91..e1c5d63dc5 100644
--- a/apps/contacts/js/jquery.multi-autocomplete.js
+++ b/apps/contacts/js/jquery.multi-autocomplete.js
@@ -62,7 +62,7 @@
return false;
}
});
- this.button = $( " " )
+ /*this.button = $( " " )
.attr( "tabIndex", -1 )
.attr( "title", "Show All Items" )
.insertAfter( this.element )
@@ -86,7 +86,7 @@
// pass empty string as value to search for, displaying all results
self.element.autocomplete( "search", "" );
self.element.focus();
- });
+ });*/
},
});
})( jQuery );
diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php
index d243c2b5e1..961ce693e6 100644
--- a/apps/contacts/templates/part.contact.php
+++ b/apps/contacts/templates/part.contact.php
@@ -21,12 +21,12 @@ $id = isset($_['id']) ? $_['id'] : '';
-
+
@@ -62,7 +62,7 @@ $id = isset($_['id']) ? $_['id'] : '';
-
+
+
-
+
@@ -131,7 +130,7 @@ $(document).ready(function(){
Contacts.UI.Card.loadContact(jsondata.data);
}
else{
- Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message);
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
}
});
}
diff --git a/apps/contacts/templates/part.edit_address_dialog.php b/apps/contacts/templates/part.edit_address_dialog.php
index 0ecdc4e191..507a3acaa0 100644
--- a/apps/contacts/templates/part.edit_address_dialog.php
+++ b/apps/contacts/templates/part.edit_address_dialog.php
@@ -22,44 +22,44 @@ foreach(isset($adr['parameters']['TYPE'])?array($adr['parameters']['TYPE']):arra
t('PO Box'); ?>
-
+
t('Extended'); ?>
-
+
t('Street'); ?>
-
+
t('City'); ?>
-
+
t('Region'); ?>
-
+
t('Zipcode'); ?>
-
+
t('Country'); ?>
-
+
diff --git a/apps/contacts/templates/settings.php b/apps/contacts/templates/settings.php
index d77c4d3802..5627a15c50 100644
--- a/apps/contacts/templates/settings.php
+++ b/apps/contacts/templates/settings.php
@@ -8,6 +8,6 @@
t('iOS/OS X'); ?>
/principals/
/
+ Powered by geonames.org webservice
- Powered by geonames.org webservice
diff --git a/core/js/oc-vcategories.js b/core/js/oc-vcategories.js
index a6dcccf88e..931ea37edb 100644
--- a/core/js/oc-vcategories.js
+++ b/core/js/oc-vcategories.js
@@ -19,7 +19,7 @@ OCCategories={
height: 350, minHeight:200, width: 250, minWidth: 200,
buttons: {
'Delete':function() {
- OCCategories.delete();
+ OCCategories.do_delete();
},
'Rescan':function() {
OCCategories.rescan();
@@ -53,7 +53,7 @@ OCCategories={
}
});
},
- delete:function(){
+ do_delete:function(){
var categories = $('#categorylist').find('input[type="checkbox"]').serialize();
categories += '&app=' + OCCategories.app;
console.log('OCCategories.delete: ' + categories);
From 23d39f7ef0362d27c6a840585f878bc54c438409 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sat, 7 Apr 2012 16:13:18 +0000
Subject: [PATCH 114/133] Display errors on import
---
apps/user_migrate/admin.php | 32 +++++++++++++--------------
apps/user_migrate/templates/admin.php | 4 ++++
2 files changed, 20 insertions(+), 16 deletions(-)
diff --git a/apps/user_migrate/admin.php b/apps/user_migrate/admin.php
index 280f7b7196..510c54abe3 100644
--- a/apps/user_migrate/admin.php
+++ b/apps/user_migrate/admin.php
@@ -36,18 +36,18 @@ if (isset($_POST['user_import'])) {
$from = $_FILES['owncloud_import']['tmp_name'];
$to = get_temp_dir().'/'.$importname.'.zip';
if( !move_uploaded_file( $from, $to ) ){
- $errors[] = array('error'=>'Failed to move the uploaded file','hint'=>'Try checking the permissions of the '.get_temp_dir().' dir.');
+ $error = array('error'=>'Failed to move the uploaded file','hint'=>'Try checking the permissions of the '.get_temp_dir().' dir.');
OC_Log::write( 'user_migrate', "Failed to copy the uploaded file", OC_Log::ERROR );
- $t = new OC_Template( '', 'error', 'user' );
- $t->assign('errors',$errors);
- $t->fetchPage();
+ $tmpl = new OC_Template('user_migrate', 'admin');
+ $tmpl->assign('error',$error);
+ return $tmpl->fetchPage();
}
if( !$appsstatus = OC_Migrate::import( $to, 'user' ) ){
- $errors[] = array('error'=>'There was an error while importing the user!','hint'=>'Please check the logs for a more detailed explaination');
- $t = new OC_Template( '', 'error', 'user' );
- $t->assign('errors',$errors);
- $t->fetchPage();
+ $error = array('error'=>'There was an error while importing the user!','hint'=>'Please check the logs for a more detailed explaination');
+ $tmpl = new OC_Template('user_migrate', 'admin');
+ $tmpl->assign('error',$error);
+ return $tmpl->fetchPage();
} else {
// Check import status
foreach( $appsstatus as $app => $status ){
@@ -63,15 +63,15 @@ if (isset($_POST['user_import'])) {
// Any problems?
if( isset( $notsupported ) || isset( $failed ) ){
if( count( $failed ) > 0 ){
- $errors[] = array('error'=>'Some app data failed to import','hint'=>'App data for: '.implode(', ', $failed).' failed to import.');
- $t = new OC_Template( '', 'error', 'user' );
- $t->assign('errors',$errors);
- $t->fetchPage();
+ $error = array('error'=>'Some app data failed to import','hint'=>'App data for: '.implode(', ', $failed).' failed to import.');
+ $tmpl = new OC_Template('user_migrate', 'admin');
+ $tmpl->assign('error',$error);
+ return $tmpl->fetchPage();
} else if( count( $notsupported ) > 0 ){
- $errors[] = array('error'=>'Some app data could not be imported, as the apps are not installed on this instance','hint'=>'App data for: '.implode(', ', $notsupported).' failed to import as they were not found. Please install the apps and try again');
- $t = new OC_Template( '', 'error', 'user' );
- $t->assign('errors',$errors);
- $t->fetchPage();
+ $error = array('error'=>'Some app data could not be imported, as the apps are not installed on this instance','hint'=>'App data for: '.implode(', ', $notsupported).' failed to import as they were not found. Please install the apps and try again');
+ $tmpl = new OC_Template('user_migrate', 'admin');
+ $tmpl->assign('error',$error);
+ return $tmpl->fetchPage();
}
} else {
// Went swimmingly!
diff --git a/apps/user_migrate/templates/admin.php b/apps/user_migrate/templates/admin.php
index b5a9951841..b01e5c7579 100644
--- a/apps/user_migrate/templates/admin.php
+++ b/apps/user_migrate/templates/admin.php
@@ -1,5 +1,9 @@
+
+
+
+
t('Import user account');?>
t('ownCloud User Zip');?>
From 00449cdf3781e9cbd1e7ab6e42cbeebf1fdb2f35 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sat, 7 Apr 2012 17:23:25 +0000
Subject: [PATCH 115/133] rename admin_export -> admin_migrate
---
apps/{admin_export => admin_migrate}/appinfo/app.php | 10 ++++------
apps/{admin_export => admin_migrate}/appinfo/info.xml | 6 +++---
apps/{admin_export => admin_migrate}/settings.php | 6 +++---
.../templates/settings.php | 0
4 files changed, 10 insertions(+), 12 deletions(-)
rename apps/{admin_export => admin_migrate}/appinfo/app.php (76%)
rename apps/{admin_export => admin_migrate}/appinfo/info.xml (57%)
rename apps/{admin_export => admin_migrate}/settings.php (92%)
rename apps/{admin_export => admin_migrate}/templates/settings.php (100%)
diff --git a/apps/admin_export/appinfo/app.php b/apps/admin_migrate/appinfo/app.php
similarity index 76%
rename from apps/admin_export/appinfo/app.php
rename to apps/admin_migrate/appinfo/app.php
index 4e896abd6a..e45d3f6a52 100644
--- a/apps/admin_export/appinfo/app.php
+++ b/apps/admin_migrate/appinfo/app.php
@@ -1,10 +1,8 @@
"admin_export_settings",
+ 'id' => "admin_migrate_settings",
'order'=>1,
- 'href' => OC_Helper::linkTo( "admin_export", "settings.php" ),
+ 'href' => OC_Helper::linkTo( "admin_migrate", "settings.php" ),
'name' => 'Export'
);
diff --git a/apps/admin_export/appinfo/info.xml b/apps/admin_migrate/appinfo/info.xml
similarity index 57%
rename from apps/admin_export/appinfo/info.xml
rename to apps/admin_migrate/appinfo/info.xml
index e434705c9a..67fc3f9c5a 100644
--- a/apps/admin_export/appinfo/info.xml
+++ b/apps/admin_migrate/appinfo/info.xml
@@ -1,8 +1,8 @@
- admin_export
- Import/Export
- Import/Export your owncloud data
+ admin_migrate
+ ownCloud Instance Migration
+ Import/Export your owncloud instance
0.1
AGPL
Thomas Schmidt and Tom Needham
diff --git a/apps/admin_export/settings.php b/apps/admin_migrate/settings.php
similarity index 92%
rename from apps/admin_export/settings.php
rename to apps/admin_migrate/settings.php
index 719bedb66e..981d5f4ca6 100644
--- a/apps/admin_export/settings.php
+++ b/apps/admin_migrate/settings.php
@@ -1,7 +1,7 @@
fetchPage();
}
\ No newline at end of file
diff --git a/apps/admin_export/templates/settings.php b/apps/admin_migrate/templates/settings.php
similarity index 100%
rename from apps/admin_export/templates/settings.php
rename to apps/admin_migrate/templates/settings.php
From d2886f202024243ae4d92e2eea9d3726037a9601 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sat, 7 Apr 2012 17:27:09 +0000
Subject: [PATCH 116/133] Hide instance import as it eats data
---
apps/admin_migrate/templates/settings.php | 9 ++++++++-
lib/migrate.php | 1 +
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/apps/admin_migrate/templates/settings.php b/apps/admin_migrate/templates/settings.php
index 36eec84d48..91e305074e 100644
--- a/apps/admin_migrate/templates/settings.php
+++ b/apps/admin_migrate/templates/settings.php
@@ -6,12 +6,16 @@
What would you like to export?
- ownCloud instance ( suitable for import )
+ ownCloud instance (suitable for import )
ownCloud system files
Just user files
+
t('Import an ownCloud instance. THIS WILL DELETE ALL CURRENT OWNCLOUD DATA');?>
@@ -22,3 +26,6 @@
+
diff --git a/lib/migrate.php b/lib/migrate.php
index 815333b4d8..22c0560691 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -258,6 +258,7 @@ class OC_Migrate{
break;
case 'instance':
/*
+ * EXPERIMENTAL
// Check for new data dir and dbexport before doing anything
// TODO
From c0869887cf91bf17421a9163069584d29ec5ed49 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sat, 7 Apr 2012 21:55:16 +0000
Subject: [PATCH 117/133] Return JSON for import and export methods of
OC_Migrate
---
apps/bookmarks/appinfo/migrate.php | 1 -
apps/user_migrate/admin.php | 6 ++---
apps/user_migrate/ajax/export.php | 35 +++++++++++++------------
lib/migrate.php | 42 +++++++++++++++---------------
4 files changed, 42 insertions(+), 42 deletions(-)
diff --git a/apps/bookmarks/appinfo/migrate.php b/apps/bookmarks/appinfo/migrate.php
index 603a8b72d3..c1251e816e 100644
--- a/apps/bookmarks/appinfo/migrate.php
+++ b/apps/bookmarks/appinfo/migrate.php
@@ -3,7 +3,6 @@ class OC_Migration_Provider_Bookmarks extends OC_Migration_Provider{
// Create the xml for the user supplied
function export( ){
- OC_Log::write('migration','starting export for bookmarks',OC_Log::INFO);
$options = array(
'table'=>'bookmarks',
'matchcol'=>'user_id',
diff --git a/apps/user_migrate/admin.php b/apps/user_migrate/admin.php
index 510c54abe3..0160753af2 100644
--- a/apps/user_migrate/admin.php
+++ b/apps/user_migrate/admin.php
@@ -42,15 +42,15 @@ if (isset($_POST['user_import'])) {
$tmpl->assign('error',$error);
return $tmpl->fetchPage();
}
-
- if( !$appsstatus = OC_Migrate::import( $to, 'user' ) ){
+ $response = json_decode( OC_Migrate::import( $to, 'user' ) );
+ if( !$response->success ){
$error = array('error'=>'There was an error while importing the user!','hint'=>'Please check the logs for a more detailed explaination');
$tmpl = new OC_Template('user_migrate', 'admin');
$tmpl->assign('error',$error);
return $tmpl->fetchPage();
} else {
// Check import status
- foreach( $appsstatus as $app => $status ){
+ foreach( $response->data as $app => $status ){
if( $status != 'true' ){
// It failed for some reason
if( $status == 'notsupported' ){
diff --git a/apps/user_migrate/ajax/export.php b/apps/user_migrate/ajax/export.php
index fac96577fa..86745d6b16 100644
--- a/apps/user_migrate/ajax/export.php
+++ b/apps/user_migrate/ajax/export.php
@@ -28,28 +28,29 @@ OC_JSON::checkLoggedIn();
OC_Util::checkAppEnabled('user_migrate');
// Which operation
if( $_GET['operation']=='create' ){
-$uid = !empty( $_POST['uid'] ) ? $_POST['uid'] : OC_User::getUser();
-if( $uid != OC_User::getUser() ){
- // Needs to be admin to export someone elses account
- OC_JSON::error();
+ $uid = !empty( $_POST['uid'] ) ? $_POST['uid'] : OC_User::getUser();
+ if( $uid != OC_User::getUser() ){
+ // Needs to be admin to export someone elses account
+ OC_JSON::error();
+ die();
+ }
+ // Create the export zip
+ $response = json_decode( OC_Migrate::export( $uid ) );
+ if( !$response->success ){
+ // Error
+ OC_JSON::error();
+ die();
+ } else {
+ // Save path in session
+ $_SESSION['ocuserexportpath'] = $response->data;
+ }
+ OC_JSON::success();
die();
-}
-// Create the export zip
-if( !$path = OC_Migrate::export( $uid ) ){
- // Error
- OC_JSON::error();
- die();
-} else {
- // Save path in session
- $_SESSION['ocuserexportpath'] = $path;
-}
-OC_JSON::success();
-die();
} else if( $_GET['operation']=='download' ){
// Download the export
$path = isset( $_SESSION['ocuserexportpath'] ) ? $_SESSION['ocuserexportpath'] : false;
if( !$path ){
- die();
+ OC_JSON::error();
}
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=" . basename($path));
diff --git a/lib/migrate.php b/lib/migrate.php
index 22c0560691..6734c805fc 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -84,7 +84,7 @@ class OC_Migrate{
$types = array( 'user', 'instance', 'system', 'userfiles' );
if( !in_array( $type, $types ) ){
OC_Log::write( 'migration', 'Invalid export type', OC_Log::ERROR );
- return false;
+ return json_encode( array( array( 'success' => false ) ) );
}
self::$exporttype = $type;
// Userid?
@@ -93,7 +93,7 @@ class OC_Migrate{
if( !is_null($uid) ){
if( !OC_User_Database::userExists( $uid ) ){
OC_Log::write('migration', 'User: '.$uid.' is not in the database and so cannot be exported.', OC_Log::ERROR);
- return false;
+ return json_encode( array( 'success' => false ) );
}
self::$uid = $uid;
} else {
@@ -114,7 +114,7 @@ class OC_Migrate{
// Validate custom path
if( !file_exists( $path ) || !is_writeable( $path ) ){
OC_Log::write( 'migration', 'Path supplied is invalid.', OC_Log::ERROR );
- return false;
+ return json_encode( array( 'success' => false ) );
}
self::$zippath = $path . $zipname;
} else {
@@ -124,7 +124,7 @@ class OC_Migrate{
}
// Create the zip object
if( !self::createZip() ){
- return false;
+ return json_encode( array( 'success' => false ) );
}
// Do the export
self::findProviders();
@@ -134,7 +134,7 @@ class OC_Migrate{
// Connect to the db
self::$dbpath = $datadir . '/' . self::$uid . '/migration.db';
if( !self::connectDB() ){
- return false;
+ return json_encode( array( 'success' => false ) );
}
self::$content = new OC_Migration_Content( self::$zip, self::$MDB2 );
// Export the app info
@@ -178,14 +178,14 @@ class OC_Migrate{
break;
}
if( !$info = self::getExportInfo( $exportdata ) ){
- return false;
+ return json_encode( array( 'success' => false ) );
}
// Add the export info json to the export zip
self::$content->addFromString( $info, 'export_info.json' );
if( !self::$content->finish() ){
- return false;
+ return json_encode( array( 'success' => false ) );
}
- return self::$zippath;
+ return json_encode( array( 'success' => true, 'data' => self::$zippath ) );
}
/**
@@ -199,19 +199,19 @@ class OC_Migrate{
$datadir = OC_Config::getValue( 'datadirectory' );
// Extract the zip
if( !$extractpath = self::extractZip( $path ) ){
- return false;
+ return json_encode( array( 'success' => false ) );
}
// Get export_info.json
$scan = scandir( $extractpath );
// Check for export_info.json
if( !in_array( 'export_info.json', $scan ) ){
OC_Log::write( 'migration', 'Invalid import file, export_info.json note found', OC_Log::ERROR );
- return false;
+ return json_encode( array( 'success' => false ) );
}
$json = json_decode( file_get_contents( $extractpath . 'export_info.json' ) );
if( $json->exporttype != $type ){
OC_Log::write( 'migration', 'Invalid import file', OC_Log::ERROR );
- return false;
+ return json_encode( array( 'success' => false ) );
}
self::$exporttype = $type;
@@ -230,31 +230,31 @@ class OC_Migrate{
// Check user availability
if( OC_User::userExists( self::$uid ) ){
OC_Log::write( 'migration', 'User already exists', OC_Log::ERROR );
- return false;
+ return json_encode( array( 'success' => false ) );
}
// Create the user
if( !self::createUser( self::$uid, $json->hash ) ){
- return false;
+ return json_encode( array( 'success' => false ) );
}
// Make the new users data dir
$path = $datadir . '/' . self::$uid . '/files/';
if( !mkdir( $path, 0755, true ) ){
OC_Log::write( 'migration', 'Failed to create users data dir: '.$path, OC_Log::ERROR );
- return false;
+ return json_encode( array( 'success' => false ) );
}
// Copy data
if( !self::copy_r( $extractpath . $json->exporteduser . '/files', $datadir . '/' . self::$uid . '/files' ) ){
- return false;
+ return json_encode( array( 'success' => false ) );
}
// Import user app data
if( !$appsimported = self::importAppData( $extractpath . $json->exporteduser . '/migration.db', $json, self::$uid ) ){
- return false;
+ return json_encode( array( 'success' => false ) );
}
// All done!
if( !self::unlink_r( $extractpath ) ){
OC_Log::write( 'migration', 'Failed to delete the extracted zip', OC_Log::ERROR );
}
- return $appsimported;
+ return json_encode( array( 'success' => true, 'data' => $appsimported ) );
break;
case 'instance':
/*
@@ -266,21 +266,21 @@ class OC_Migrate{
OC_Log::write( 'migration', "Deleting current data dir", OC_Log::INFO );
if( !self::unlink_r( $datadir, false ) ){
OC_Log::write( 'migration', 'Failed to delete the current data dir', OC_Log::ERROR );
- return false;
+ return json_encode( array( 'success' => false ) );
}
// Copy over data
if( !self::copy_r( $extractpath . 'userdata', $datadir ) ){
OC_Log::write( 'migration', 'Failed to copy over data directory', OC_Log::ERROR );
- return false;
+ return json_encode( array( 'success' => false ) );
}
// Import the db
if( !OC_DB::replaceDB( $extractpath . 'dbexport.xml' ) ){
- return false;
+ return json_encode( array( 'success' => false ) );
}
// Done
- return true;
+ return json_encode( 'success' => true );
*/
break;
}
From 5e314e8effb42b60d720de40fbf74591ae421534 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sat, 7 Apr 2012 22:00:32 +0000
Subject: [PATCH 118/133] Emit hooks for user creation
---
lib/migrate.php | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/lib/migrate.php b/lib/migrate.php
index 6734c805fc..2730d26a74 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -232,10 +232,19 @@ class OC_Migrate{
OC_Log::write( 'migration', 'User already exists', OC_Log::ERROR );
return json_encode( array( 'success' => false ) );
}
+ $run = true;
+ OC_Hook::emit( "OC_User", "pre_createUser", array( "run" => &$run, "uid" => self::$uid, "password" => $json->hash ));
+ if( !$run ){
+ // Something stopped the user creation
+ OC_Log::write( 'migration', 'User creation failed', OC_Log::ERROR );
+ return json_encode( array( 'success' => false ) );
+ }
// Create the user
if( !self::createUser( self::$uid, $json->hash ) ){
return json_encode( array( 'success' => false ) );
}
+ // Emit the post_createUser hook (password is already hashed, will cause problems
+ OC_Hook::emit( "OC_User", "post_createUser", array( "uid" => self::$uid, "password" => $json->hash ));
// Make the new users data dir
$path = $datadir . '/' . self::$uid . '/files/';
if( !mkdir( $path, 0755, true ) ){
From e5ebbacc9e951d1da82762daf67f993ee20e95cb Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sun, 8 Apr 2012 18:52:31 +0000
Subject: [PATCH 119/133] Fix sqlite version detection
---
lib/migrate.php | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/lib/migrate.php b/lib/migrate.php
index 2730d26a74..a8a5e581c3 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -496,10 +496,14 @@ class OC_Migrate{
$datadir = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" );
// DB type
- if( !is_callable( 'sqlite_open' ) || !class_exists( 'SQLite3' ) ){
+ if( class_exists( 'SQLite3' ) ){
+ $dbtype = 'sqlite3';
+ } else if( is_callable( 'sqlite_open' ) ){
+ $dbtype = 'sqlite';
+ } else {
OC_Log::write( 'migration', 'SQLite not found', OC_Log::ERROR );
return false;
- }
+ }
// Prepare options array
$options = array(
@@ -510,7 +514,7 @@ class OC_Migrate{
'quote_identifier' => true
);
$dsn = array(
- 'phptype' => 'sqlite3',
+ 'phptype' => $dbtype,
'database' => self::$dbpath,
'mode' => '0644'
);
From ecc596534a9d6d6faffc6038a5bce61ebdf59781 Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sun, 8 Apr 2012 19:08:17 +0000
Subject: [PATCH 120/133] Decode json response for admin exports
---
apps/admin_migrate/settings.php | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/apps/admin_migrate/settings.php b/apps/admin_migrate/settings.php
index 981d5f4ca6..94bf6052a6 100644
--- a/apps/admin_migrate/settings.php
+++ b/apps/admin_migrate/settings.php
@@ -28,10 +28,12 @@ OC_Util::checkAppEnabled('admin_migrate');
// Export?
if (isset($_POST['admin_export'])) {
// Create the export zip
- if( !$path = OC_Migrate::export( null, $_POST['export_type'] ) ){
+ $response = json_decode( OC_Migrate::export( null, $_POST['export_type'] ) );
+ if( !$response->success ){
// Error
die('error');
} else {
+ $path = $response->data;
// Download it
header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=" . basename($path));
From 8e188cd96f4c1f19664aa5ee870420a26d230c5c Mon Sep 17 00:00:00 2001
From: Tom Needham
Date: Sun, 8 Apr 2012 19:16:03 +0000
Subject: [PATCH 121/133] Copy over all file app data for imported user
---
lib/migrate.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/migrate.php b/lib/migrate.php
index a8a5e581c3..dff3abe9e9 100644
--- a/lib/migrate.php
+++ b/lib/migrate.php
@@ -246,13 +246,13 @@ class OC_Migrate{
// Emit the post_createUser hook (password is already hashed, will cause problems
OC_Hook::emit( "OC_User", "post_createUser", array( "uid" => self::$uid, "password" => $json->hash ));
// Make the new users data dir
- $path = $datadir . '/' . self::$uid . '/files/';
+ $path = $datadir . '/' . self::$uid;
if( !mkdir( $path, 0755, true ) ){
OC_Log::write( 'migration', 'Failed to create users data dir: '.$path, OC_Log::ERROR );
return json_encode( array( 'success' => false ) );
}
// Copy data
- if( !self::copy_r( $extractpath . $json->exporteduser . '/files', $datadir . '/' . self::$uid . '/files' ) ){
+ if( !self::copy_r( $extractpath . $json->exporteduser, $datadir . '/' . self::$uid ) ){
return json_encode( array( 'success' => false ) );
}
// Import user app data
From 53091551d8019fa64dbcf5197a380f60bb2e6827 Mon Sep 17 00:00:00 2001
From: Thomas Tanghus
Date: Mon, 9 Apr 2012 16:02:59 +0200
Subject: [PATCH 122/133] Re-added file I had accidentally removed earlier :-P
---
apps/contacts/templates/part.no_contacts.php | 8 ++++++++
1 file changed, 8 insertions(+)
create mode 100644 apps/contacts/templates/part.no_contacts.php
diff --git a/apps/contacts/templates/part.no_contacts.php b/apps/contacts/templates/part.no_contacts.php
new file mode 100644
index 0000000000..d24f7ae980
--- /dev/null
+++ b/apps/contacts/templates/part.no_contacts.php
@@ -0,0 +1,8 @@
+
\ No newline at end of file
From 9c247ce874697ed6833c58d21ddecee418ddb525 Mon Sep 17 00:00:00 2001
From: Thomas Tanghus
Date: Mon, 9 Apr 2012 16:29:35 +0200
Subject: [PATCH 123/133] Removed padding.
---
apps/contacts/js/contacts.js | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js
index 3b264c0197..b2678e8c52 100644
--- a/apps/contacts/js/contacts.js
+++ b/apps/contacts/js/contacts.js
@@ -264,6 +264,18 @@ Contacts={
},
add:function(n, fn, aid, isnew){ // add a new contact
console.log('Add contact: ' + n + ', ' + fn + ' ' + aid);
+ var card = $('#card')[0];
+ if(!card) {
+ console.log('Loading proper card DOM');
+ $.getJSON(OC.filePath('contacts', 'ajax', 'loadcard.php'),{},function(jsondata){
+ if(jsondata.status == 'success'){
+ $('#rightcontent').html(jsondata.data.page);
+ Contacts.UI.loadHandlers();
+ } else{
+ OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
+ }
+ });
+ }
$.post(OC.filePath('contacts', 'ajax', 'addcontact.php'), { n: n, fn: fn, aid: aid },
function(jsondata) {
if (jsondata.status == 'success'){
From 4fda6af725ea775750905983255ab3dc9ceeb2b9 Mon Sep 17 00:00:00 2001
From: Thomas Tanghus
Date: Mon, 9 Apr 2012 16:29:56 +0200
Subject: [PATCH 124/133] Contacts: Fix for not being able to add contact to
empty/non-existant address book.
---
apps/contacts/ajax/addcontact.php | 2 --
apps/contacts/css/contacts.css | 2 +-
apps/contacts/lib/addressbook.php | 2 +-
3 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/apps/contacts/ajax/addcontact.php b/apps/contacts/ajax/addcontact.php
index 947b35bab5..68da54655a 100644
--- a/apps/contacts/ajax/addcontact.php
+++ b/apps/contacts/ajax/addcontact.php
@@ -47,8 +47,6 @@ OC_Contacts_App::getAddressbook( $aid ); // is owner access check
$fn = trim($_POST['fn']);
$n = trim($_POST['n']);
-debug('N: '.$n);
-debug('FN: '.$fn);
$vcard = new OC_VObject('VCARD');
$vcard->setUID();
diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css
index 5d3ebf65fb..2d20794384 100644
--- a/apps/contacts/css/contacts.css
+++ b/apps/contacts/css/contacts.css
@@ -56,7 +56,7 @@ dl.form { width: 100%; float: left; clear: right; margin: 0; padding: 0; }
.contactpart legend { width:auto; padding:.3em; border:1px solid #ddd; font-weight:bold; cursor:pointer; background:#f8f8f8; color:#555; text-shadow:#fff 0 1px 0; -moz-box-shadow:0 1px 1px #fff, 0 1px 1px #fff inset; -webkit-box-shadow:0 1px 1px #fff, 0 1px 1px #fff inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; }
#cropbox { margin: auto; }
-#contacts_details_photo { border-radius: 0.5em; border: thin solid #bbb; padding: 0.5em; margin: 0.3em; cursor: pointer; background: url(../../../core/img/loading.gif) no-repeat center center; display: block; /* clear: right;*/ }
+#contacts_details_photo { border-radius: 0.5em; border: thin solid #bbb; margin: 0.3em; cursor: pointer; background: url(../../../core/img/loading.gif) no-repeat center center; display: block; /* clear: right;*/ }
#contacts_details_photo:hover { background: #fff; }
/*#contacts_details_photo_progress { margin: 0.3em 0.3em 0.3em 7em; clear: left; }*/
/* Address editor */
diff --git a/apps/contacts/lib/addressbook.php b/apps/contacts/lib/addressbook.php
index 052c19e55f..9061fa1914 100644
--- a/apps/contacts/lib/addressbook.php
+++ b/apps/contacts/lib/addressbook.php
@@ -169,7 +169,7 @@ class OC_Contacts_Addressbook{
$uid = OC_User::getUser();
}
$prefbooks = OC_Preferences::getValue($uid,'contacts','openaddressbooks',null);
- if(is_null($prefbooks)){
+ if(!$prefbooks){
$addressbooks = OC_Contacts_Addressbook::all($uid);
if(count($addressbooks) == 0){
OC_Contacts_Addressbook::add($uid,'default','Default Address Book');
From b0894b314845a52e979539cbf1e6bd94444dca54 Mon Sep 17 00:00:00 2001
From: Frank Karlitschek
Date: Mon, 9 Apr 2012 22:10:29 +0200
Subject: [PATCH 125/133] Add Craigs granite library to 3rdparty and
files_versioning. Still not working and lots ot stuff to do.
---
3rdparty/granite/git/blob.php | 162 +++++
3rdparty/granite/git/commit.php | 232 +++++++
3rdparty/granite/git/object/index.php | 210 ++++++
3rdparty/granite/git/object/loose.php | 81 +++
3rdparty/granite/git/object/packed.php | 304 ++++++++
3rdparty/granite/git/object/raw.php | 153 +++++
3rdparty/granite/git/repository.php | 293 ++++++++
3rdparty/granite/git/tag.php | 38 +
3rdparty/granite/git/tree.php | 198 ++++++
3rdparty/granite/git/tree/node.php | 126 ++++
apps/files_versioning/ajax/gethead.php | 12 +
apps/files_versioning/ajax/sethead.php | 14 +
apps/files_versioning/appinfo/app.php | 20 +
apps/files_versioning/appinfo/info.xml | 14 +
apps/files_versioning/css/settings.css | 3 +
apps/files_versioning/js/settings.js | 25 +
apps/files_versioning/lib_granite.php | 12 +
apps/files_versioning/settings.php | 34 +
apps/files_versioning/templates/settings.php | 12 +
apps/files_versioning/versionstorage.php | 386 +++++++++++
apps/files_versioning/versionwrapper.php | 686 +++++++++++++++++++
21 files changed, 3015 insertions(+)
create mode 100644 3rdparty/granite/git/blob.php
create mode 100644 3rdparty/granite/git/commit.php
create mode 100644 3rdparty/granite/git/object/index.php
create mode 100644 3rdparty/granite/git/object/loose.php
create mode 100644 3rdparty/granite/git/object/packed.php
create mode 100644 3rdparty/granite/git/object/raw.php
create mode 100644 3rdparty/granite/git/repository.php
create mode 100644 3rdparty/granite/git/tag.php
create mode 100644 3rdparty/granite/git/tree.php
create mode 100644 3rdparty/granite/git/tree/node.php
create mode 100644 apps/files_versioning/ajax/gethead.php
create mode 100644 apps/files_versioning/ajax/sethead.php
create mode 100644 apps/files_versioning/appinfo/app.php
create mode 100644 apps/files_versioning/appinfo/info.xml
create mode 100644 apps/files_versioning/css/settings.css
create mode 100644 apps/files_versioning/js/settings.js
create mode 100644 apps/files_versioning/lib_granite.php
create mode 100644 apps/files_versioning/settings.php
create mode 100644 apps/files_versioning/templates/settings.php
create mode 100644 apps/files_versioning/versionstorage.php
create mode 100644 apps/files_versioning/versionwrapper.php
diff --git a/3rdparty/granite/git/blob.php b/3rdparty/granite/git/blob.php
new file mode 100644
index 0000000000..781a697d56
--- /dev/null
+++ b/3rdparty/granite/git/blob.php
@@ -0,0 +1,162 @@
+
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+
+namespace Granite\Git;
+use \Granite\Git\Object\Raw as Raw;
+use \InvalidArgumentException as InvalidArgumentException;
+use \finfo as finfo;
+/**
+ * **Granite\Git\Blob** represents the raw content of an object in a Git repository,
+ * typically a **file**. This class provides methods related to the handling of
+ * blob content, mimetypes, sizes and write support.
+ *
+ * @category Git
+ * @package Granite
+ * @author Craig Roberts
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+class Blob
+{
+
+ /**
+ * Stores the SHA-1 id of the object requested; accessed through the `sha()`
+ * method where it is recalculated based on the blob content.
+ */
+ private $sha = null;
+ /**
+ * The raw binary string of the file contents.
+ */
+ private $content = "";
+ /**
+ * The path to the repository location.
+ */
+ private $path;
+
+ /**
+ * Fetches a raw Git object and parses the result. Throws an
+ * InvalidArgumentException if the object is not of the correct type,
+ * or cannot be found.
+ *
+ * @param string $path The path to the repository root.
+ * @param string $sha The SHA-1 id of the requested object, or `null` if
+ * creating a new blob object.
+ *
+ * @throws InvalidArgumentException If the SHA-1 id provided is not a blob.
+ */
+ public function __construct($path, $sha = NULL)
+ {
+ $this->path = $path;
+ if ($sha !== NULL) {
+ $this->sha = $sha;
+ $object = Raw::factory($path, $sha);
+
+ if ($object->type() !== Raw::OBJ_BLOB) {
+ throw new InvalidArgumentException(
+ "The object $sha is not a blob, type is {$object->type()}"
+ );
+ }
+
+ $this->content = $object->content();
+ unset($object);
+ }
+ }
+
+ /**
+ * Sets or returns the raw file content, depending whether the parameter is
+ * provided.
+ *
+ * @param string $content The object content to set, or `null` if requesting the
+ * current content.
+ *
+ * @return string The raw binary string of the file contents.
+ */
+ public function content($content = NULL)
+ {
+ if ($content == NULL) {
+ return $this->content;
+ }
+ $this->content = $content;
+ }
+
+ /**
+ * Returns the size of the file content in bytes, equivalent to
+ * `strlen($blob->content())`.
+ *
+ * @return int The size of the object in bytes.
+ */
+ public function size()
+ {
+ return strlen($this->content);
+ }
+
+ /**
+ * Updates and returns the SHA-1 id of the object, based on it's contents.
+ *
+ * @return int The SHA-1 id of the object.
+ */
+ public function sha()
+ {
+ $sha = hash_init('sha1');
+ $header = 'blob ' . strlen($this->content) . "\0";
+ hash_update($sha, $header);
+ hash_update($sha, $this->content);
+ $this->sha = hash_final($sha);
+ return $this->sha;
+ }
+
+ /**
+ * Returns the mimetype of the object, using `finfo()` to determine the mimetype
+ * of the string.
+ *
+ * @return string The object mimetype.
+ * @see http://php.net/manual/en/function.finfo-open.php
+ */
+ public function mimetype()
+ {
+ $finfo = new finfo(FILEINFO_MIME);
+ return $finfo->buffer($this->content);
+ }
+
+ /**
+ * Encode and compress the object content, saving it to a 'loose' file.
+ *
+ * @return boolean True on success, false on failure.
+ */
+ public function write()
+ {
+ $sha = $this->sha(TRUE);
+ $path = $this->path
+ . 'objects'
+ . DIRECTORY_SEPARATOR
+ . substr($sha, 0, 2)
+ . DIRECTORY_SEPARATOR
+ . substr($sha, 2);
+ // FIXME: currently writes loose objects only
+ if (file_exists($path)) {
+ return FALSE;
+ }
+
+ if (!is_dir(dirname($path))) {
+ mkdir(dirname($path), 0777, TRUE);
+ }
+
+ $loose = fopen($path, 'wb');
+ $data = 'blob ' . strlen($this->content) . "\0" . $this->content;
+ $write = fwrite($loose, gzcompress($data));
+ fclose($loose);
+
+ return ($write !== FALSE);
+ }
+
+}
diff --git a/3rdparty/granite/git/commit.php b/3rdparty/granite/git/commit.php
new file mode 100644
index 0000000000..51077e89f3
--- /dev/null
+++ b/3rdparty/granite/git/commit.php
@@ -0,0 +1,232 @@
+
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+
+namespace Granite\Git;
+use \Granite\Git\Object\Raw as Raw;
+use \InvalidArgumentException as InvalidArgumentException;
+
+/**
+ * Commit represents a full commit object
+ *
+ * @category Git
+ * @package Granite
+ * @author Craig Roberts
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+class Commit
+{
+
+ /**
+ * The path to the repository root
+ */
+ private $path;
+ /**
+ * The SHA-1 id of the requested commit
+ */
+ private $sha;
+ /**
+ * The size of the commit in bytes
+ */
+ private $size;
+ /**
+ * The commit message
+ */
+ private $message;
+ /**
+ * The full committer string
+ */
+ private $committer;
+ /**
+ * The full author string
+ */
+ private $author;
+ /**
+ * The SHA-1 ids of the parent commits
+ */
+ private $parents = array();
+
+ /**
+ * Fetches a raw Git object and parses the result. Throws an
+ * InvalidArgumentException if the object is not of the correct type,
+ * or cannot be found.
+ *
+ * @param string $path The path to the repository root
+ * @param string $sha The SHA-1 id of the requested object
+ *
+ * @throws InvalidArgumentException
+ */
+ public function __construct($path, $sha = NULL)
+ {
+ $this->path = $path;
+ if ($sha !== NULL) {
+ $this->sha = $sha;
+ $object = Raw::factory($path, $sha);
+ $this->size = $object->size();
+
+ if ($object->type() !== Raw::OBJ_COMMIT) {
+ throw new InvalidArgumentException(
+ "The object $sha is not a commit, type is " . $object->type()
+ );
+ }
+
+ // Parse headers and commit message (delimited with "\n\n")
+ list($headers, $this->message) = explode("\n\n", $object->content(), 2);
+ $headers = explode("\n", $headers);
+
+ foreach ($headers as $header) {
+ list($header, $value) = explode(' ', $header, 2);
+ if ($header == 'parent') {
+ $this->parents[] = $value;
+ } else {
+ $this->$header = $value;
+ }
+ }
+
+ $this->tree = new Tree($this->path, $this->tree);
+ }
+ }
+
+ /**
+ * Returns the message stored in the commit
+ *
+ * @return string The commit message
+ */
+ public function message($message = NULL)
+ {
+ if ($message !== NULL) {
+ $this->message = $message;
+ return $this;
+ }
+ return $this->message;
+ }
+
+ /**
+ * Returns the commiter string
+ *
+ * @return string The committer string
+ */
+ public function committer($committer = NULL)
+ {
+ if ($committer !== NULL) {
+ $this->committer = $committer;
+ return $this;
+ }
+ return $this->committer;
+ }
+
+ /**
+ * Returns the author string
+ *
+ * @return string The author string
+ */
+ public function author($author = NULL)
+ {
+ if ($author !== NULL) {
+ $this->author = $author;
+ return $this;
+ }
+ return $this->author;
+ }
+
+ /**
+ * Returns the parents of the commit, or an empty array if none
+ *
+ * @return array The parents of the commit
+ */
+ public function parents($parents = NULL)
+ {
+ if ($parents !== NULL) {
+ $this->parents = $parents;
+ return $this;
+ }
+ return $this->parents;
+ }
+
+ /**
+ * Returns a tree object associated with the commit
+ *
+ * @return Tree
+ */
+ public function tree(Tree $tree = NULL)
+ {
+ if ($tree !== NULL) {
+ $this->tree = $tree;
+ return $this;
+ }
+ return $this->tree;
+ }
+
+ /**
+ * Returns the size of the commit in bytes (Git header + data)
+ *
+ * @return int
+ */
+ public function size()
+ {
+ return $this->size;
+ }
+
+ /**
+ * Returns the size of the commit in bytes (Git header + data)
+ *
+ * @return int
+ */
+ public function sha()
+ {
+ $this->sha = hash('sha1', $this->_raw());
+ return $this->sha;
+ }
+
+ public function write()
+ {
+ $sha = $this->sha();
+ $path = $this->path
+ . 'objects'
+ . DIRECTORY_SEPARATOR
+ . substr($sha, 0, 2)
+ . DIRECTORY_SEPARATOR
+ . substr($sha, 2);
+ // FIXME: currently writes loose objects only
+ if (file_exists($path)) {
+ return FALSE;
+ }
+
+ if (!is_dir(dirname($path))) {
+ mkdir(dirname($path), 0777, TRUE);
+ }
+
+ $loose = fopen($path, 'wb');
+ $data = $this->_raw();
+ $write = fwrite($loose, gzcompress($data));
+ fclose($loose);
+
+ return ($write !== FALSE);
+ }
+
+ public function _raw()
+ {
+ $data = 'tree ' . $this->tree->sha() . "\n";
+ foreach ($this->parents as $parent)
+ {
+ $data .= "parent $parent\n";
+ }
+ $data .= 'author ' . $this->author . "\n";
+ $data .= 'committer ' . $this->committer . "\n\n";
+ $data .= $this->message;
+
+ $data = 'commit ' . strlen($data) . "\0" . $data;
+ return $data;
+ }
+
+}
diff --git a/3rdparty/granite/git/object/index.php b/3rdparty/granite/git/object/index.php
new file mode 100644
index 0000000000..239706d4ef
--- /dev/null
+++ b/3rdparty/granite/git/object/index.php
@@ -0,0 +1,210 @@
+
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ * @link http://craig0990.github.com/Granite/
+ */
+
+namespace Granite\Git\Object;
+use \UnexpectedValueException as UnexpectedValueException;
+
+/**
+ * Index represents a packfile index
+ *
+ * @category Git
+ * @package Granite
+ * @author Craig Roberts
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ * @link http://craig0990.github.com/Granite/
+ */
+class Index
+{
+ const INDEX_MAGIC = "\377tOc";
+
+ /**
+ * The full path to the packfile index
+ */
+ private $path;
+ /**
+ * The offset at which the fanout begins, version 2+ indexes have a 2-byte header
+ */
+ private $offset = 8;
+ /**
+ * The size of the SHA-1 entries, version 1 stores 4-byte offsets alongside to
+ * total 24 bytes, version 2+ stores offsets separately
+ */
+ private $size = 20;
+ /**
+ * The version of the index file format, versions 1 and 2 are in use and
+ * currently supported
+ */
+ private $version;
+
+ /**
+ * Fetches a raw Git object and parses the result
+ *
+ * @param string $path The path to the repository root
+ * @param string $packname The name of the packfile index to read
+ */
+ public function __construct($path, $packname)
+ {
+ $this->path = $path
+ . 'objects'
+ . DIRECTORY_SEPARATOR
+ . 'pack'
+ . DIRECTORY_SEPARATOR
+ . 'pack-' . $packname . '.idx';
+
+ $this->version = $this->_readVersion();
+ if ($this->version !== 1 && $this->version !== 2) {
+ throw new UnexpectedValueException(
+ "Unsupported index version (version $version)"
+ );
+ }
+
+ if ($this->version == 1) {
+ $this->offset = 0; // Version 1 index has no header/version
+ $this->size = 24; // Offsets + SHA-1 ids are stored together
+ }
+ }
+
+ /**
+ * Returns the offset of the object stored in the index
+ *
+ * @param string $sha The SHA-1 id of the object being requested
+ *
+ * @return int The offset of the object in the packfile
+ */
+ public function find($sha)
+ {
+ $index = fopen($this->path, 'rb');
+ $offset = false; // Offset for object in packfile not found by default
+
+ // Read the fanout to skip to the start char in the sorted SHA-1 list
+ list($start, $after) = $this->_readFanout($index, $sha);
+
+ if ($start == $after) {
+ fclose($index);
+ return false; // Object is apparently located in a 0-length section
+ }
+
+ // Seek $offset + 255 4-byte fanout entries and read 256th entry
+ fseek($index, $this->offset + 4 * 255);
+ $totalObjects = $this->_uint32($index);
+
+ // Look up the SHA-1 id of the object
+ // TODO: Binary search
+ fseek($index, $this->offset + 1024 + $this->size * $start);
+ for ($i = $start; $i < $after; $i++) {
+ if ($this->version == 1) {
+ $offset = $this->_uint32($index);
+ }
+
+ $name = fread($index, 20);
+ if ($name == pack('H40', $sha)) {
+ break; // Found it
+ }
+ }
+
+ if ($i == $after) {
+ fclose($index);
+ return false; // Scanned entire section, couldn't find it
+ }
+
+ if ($this->version == 2) {
+ // Jump to the offset location and read it
+ fseek($index, 1032 + 24 * $totalObjects + 4 * $i);
+ $offset = $this->_uint32($index);
+ if ($offset & 0x80000000) {
+ // Offset is a 64-bit integer; packfile is larger than 2GB
+ fclose($index);
+ throw new UnexpectedValueException(
+ "Packfile larger than 2GB, currently unsupported"
+ );
+ }
+ }
+
+ fclose($index);
+ return $offset;
+ }
+
+ /**
+ * Converts a binary string into a 32-bit unsigned integer
+ *
+ * @param handle $file Binary string to convert
+ *
+ * @return int Integer value
+ */
+ private function _uint32($file)
+ {
+ $val = unpack('Nx', fread($file, 4));
+ return $val['x'];
+ }
+
+ /**
+ * Reads the fanout for a particular SHA-1 id
+ *
+ * Largely modified from Glip, with some reference to Grit - largely because I
+ * can't see how to re-implement this in PHP
+ *
+ * @param handle $file File handle to the index file
+ * @param string $sha The SHA-1 id to search for
+ * @param int $offset The offset at which the fanout begins
+ *
+ * @return array Array containing integer 'start' and
+ * 'past-the-end' locations
+ */
+ private function _readFanout($file, $sha)
+ {
+ $sha = pack('H40', $sha);
+ fseek($file, $this->offset);
+ if ($sha{0} == "\00") {
+ /**
+ * First character is 0, read first fanout entry to provide
+ * 'past-the-end' location (since first fanout entry provides start
+ * point for '1'-prefixed SHA-1 ids)
+ */
+ $start = 0;
+ fseek($file, $this->offset); // Jump to start of fanout, $offset bytes in
+ $after = $this->_uint32($file);
+ } else {
+ /**
+ * Take ASCII value of first character, minus one to get the fanout
+ * position of the offset (minus one because the fanout does not
+ * contain an entry for "\00"), multiplied by four bytes per entry
+ */
+ fseek($file, $this->offset + (ord($sha{0}) - 1) * 4);
+ $start = $this->_uint32($file);
+ $after = $this->_uint32($file);
+ }
+
+ return array($start, $after);
+ }
+
+ /**
+ * Returns the version number of the index file, or 1 if there is no version
+ * information
+ *
+ * @return int
+ */
+ private function _readVersion()
+ {
+ $file = fopen($this->path, 'rb');
+ $magic = fread($file, 4);
+ $version = $this->_uint32($file);
+
+ if ($magic !== self::INDEX_MAGIC) {
+ $version = 1;
+ }
+
+ fclose($file);
+ return $version;
+ }
+
+}
diff --git a/3rdparty/granite/git/object/loose.php b/3rdparty/granite/git/object/loose.php
new file mode 100644
index 0000000000..32f894845b
--- /dev/null
+++ b/3rdparty/granite/git/object/loose.php
@@ -0,0 +1,81 @@
+
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+
+namespace Granite\Git\Object;
+use \UnexpectedValueException as UnexpectedValueException;
+
+/**
+ * Loose represents a loose object in the Git repository
+ *
+ * @category Git
+ * @package Granite
+ * @author Craig Roberts
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+class Loose extends Raw
+{
+
+ /**
+ * Reads an object from a loose object file based on the SHA-1 id
+ *
+ * @param string $path The path to the repository root
+ * @param string $sha The SHA-1 id of the requested object
+ *
+ * @throws UnexpectedValueException If the type is not 'commit', 'tree',
+ * 'tag' or 'blob'
+ */
+ public function __construct($path, $sha)
+ {
+ $this->sha = $sha;
+
+ $loose_path = $path
+ . 'objects/'
+ . substr($sha, 0, 2)
+ . '/'
+ . substr($sha, 2);
+
+ if (!file_exists($loose_path)) {
+ throw new InvalidArgumentException("Cannot open loose object file for $sha");
+ }
+
+ $raw = gzuncompress(file_get_contents($loose_path));
+ $data = explode("\0", $raw, 2);
+
+ $header = $data[0];
+ $this->content = $data[1];
+
+ list($this->type, $this->size) = explode(' ', $header);
+
+ switch ($this->type) {
+ case 'commit':
+ $this->type = Raw::OBJ_COMMIT;
+ break;
+ case 'tree':
+ $this->type = Raw::OBJ_TREE;
+ break;
+ case 'blob':
+ $this->type = Raw::OBJ_BLOB;
+ break;
+ case 'tag':
+ $this->type = Raw::OBJ_TAG;
+ break;
+ default:
+ throw new UnexpectedValueException(
+ "Unexpected type '{$this->type}'"
+ );
+ break;
+ }
+ }
+
+}
diff --git a/3rdparty/granite/git/object/packed.php b/3rdparty/granite/git/object/packed.php
new file mode 100644
index 0000000000..7e8d663b32
--- /dev/null
+++ b/3rdparty/granite/git/object/packed.php
@@ -0,0 +1,304 @@
+
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+
+namespace Granite\Git\Object;
+use \UnexpectedValueException as UnexpectedValueException;
+
+/**
+ * Packed represents a packed object in the Git repository
+ *
+ * @category Git
+ * @package Granite
+ * @author Craig Roberts
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+class Packed extends Raw
+{
+
+ /**
+ * The name of the packfile being read
+ */
+ private $_packfile;
+
+ /**
+ * Added to the object size to make a 'best-guess' effort at how much compressed
+ * data to read - should be reimplemented, ideally with streams.
+ */
+ const OBJ_PADDING = 512;
+
+ /**
+ * Reads the object data from the compressed data at $offset in $packfile
+ *
+ * @param string $packfile The path to the packfile
+ * @param int $offset The offset of the object data
+ */
+ public function __construct($packfile, $offset)
+ {
+ $this->_packfile = $packfile;
+
+ list($this->type, $this->size, $this->content)
+ = $this->_readPackedObject($offset);
+ }
+
+ /**
+ * Reads the object data at $this->_offset
+ *
+ * @param int $offset Offset of the object header
+ *
+ * @return array Containing the type, size and object data
+ */
+ private function _readPackedObject($offset)
+ {
+ $file = fopen($this->_packfile, 'rb');
+ fseek($file, $offset);
+ // Read the type and uncompressed size from the object header
+ list($type, $size) = $this->_readHeader($file, $offset);
+ $object_offset = ftell($file);
+
+ if ($type == self::OBJ_OFS_DELTA || $type == self::OBJ_REF_DELTA) {
+ return $this->_unpackDeltified(
+ $file, $offset, $object_offset, $type, $size
+ );
+ }
+
+ $content = gzuncompress(fread($file, $size + self::OBJ_PADDING), $size);
+
+ return array($type, $size, $content);
+ }
+
+ /**
+ * Reads a packed object header, returning the type and the size. For more
+ * detailed information, refer to the @see tag.
+ *
+ * From the @see tag: "Each byte is really 7 bits of data, with the first bit
+ * being used to say if that hunk is the last one or not before the data starts.
+ * If the first bit is a 1, you will read another byte, otherwise the data starts
+ * next. The first 3 bits in the first byte specifies the type of data..."
+ *
+ * @param handle $file File handle to read
+ * @param int $offset Offset of the object header
+ *
+ * @return array Containing the type and the size
+ * @see http://book.git-scm.com/7_the_packfile.html
+ */
+ private function _readHeader($file, $offset)
+ {
+ // Read the object header byte-by-byte
+ fseek($file, $offset);
+ $byte = ord(fgetc($file));
+ /**
+ * Bit-shift right by four, then ignore the first bit with a bitwise AND
+ * This gives us the object type in binary:
+ * 001 commit self::OBJ_COMMIT
+ * 010 tree self::OBJ_TREE
+ * 011 blob self::OBJ_BLOB
+ * 100 tag self::OBJ_TAG
+ * 110 offset delta self::OBJ_OFS_DELTA
+ * 111 ref delta self::OBJ_REF_DELTA
+ *
+ * (000 is undefined, 101 is not currently in use)
+ * See http://book.git-scm.com/7_the_packfile.html for details
+ */
+ $type = ($byte >> 4) & 0x07;
+
+ // Read the last four bits of the first byte, used to find the size
+ $size = $byte & 0x0F;
+
+ /**
+ * $shift initially set to four, since we use the last four bits of the first
+ * byte
+ *
+ * $byte & 0x80 checks the initial bit is set to 1 (i.e. keep reading data)
+ *
+ * Finally, $shift is incremented by seven for each consecutive byte (because
+ * we ignore the initial bit)
+ */
+ for ($shift = 4; $byte & 0x80; $shift += 7) {
+ $byte = ord(fgetc($file));
+ /**
+ * The size is ANDed against 0x7F to strip the initial bit, then
+ * bitshifted by left $shift (4 or 7, depending on whether it's the
+ * initial byte) and ORed against the existing binary $size. This
+ * continuously increments the $size variable.
+ */
+ $size |= (($byte & 0x7F) << $shift);
+ }
+
+ return array($type, $size);
+ }
+
+ /**
+ * Unpacks a deltified object located at $offset in $file
+ *
+ * @param handle $file File handle to read
+ * @param int $offset Offset of the object data
+ * @param int $object_offset Offset of the object data, past the header
+ * @param int $type The object type, either OBJ_REF_DELTA
+ or OBJ_OFS_DELTA
+ * @param int $size The expected size of the uncompressed data
+ *
+ * @return array Containing the type, size and object data
+ */
+ private function _unpackDeltified($file, $offset, $object_offset, $type, $size)
+ {
+ fseek($file, $object_offset);
+
+ if ($type == self::OBJ_REF_DELTA) {
+
+ $base_sha = bin2hex(fread($file, 20));
+
+ $path = substr($this->_packfile, 0, strpos($this->_packfile, '.git')+5);
+ $base = Raw::factory($path, $base_sha);
+ $type = $base->type();
+ $base = $base->content();
+
+ $delta = gzuncompress(
+ fread($file, $size + self::OBJ_PADDING), $size
+ );
+
+ $content = $this->_applyDelta($base, $delta);
+
+ } elseif ($type == self::OBJ_OFS_DELTA) {
+
+ // 20 = maximum varint size according to Glip
+ $data = fread($file, $size + self::OBJ_PADDING + 20);
+
+ list($base_offset, $length) = $this->_bigEndianNumber($data);
+
+ $delta = gzuncompress(substr($data, $length), $size);
+ unset($data);
+
+ $base_offset = $offset - $base_offset;
+ list($type, $size, $base) = $this->_readPackedObject($base_offset);
+
+ $content = $this->_applyDelta($base, $delta);
+
+ } else {
+ throw new UnexpectedValueException(
+ "Unknown type $type for deltified object"
+ );
+ }
+
+ return array($type, strlen($content), $content);
+ }
+
+ /**
+ * Applies the $delta byte-sequence to $base and returns the
+ * resultant binary string.
+ *
+ * This code is modified from Grit (see below), the Ruby
+ * implementation used for GitHub under an MIT license.
+ *
+ * @param string $base The base string for the delta to be applied to
+ * @param string $delta The delta string to apply
+ *
+ * @return string The patched binary string
+ * @see
+ * https://github.com/mojombo/grit/blob/master/lib/grit/git-ruby/internal/pack.rb
+ */
+ private function _applyDelta($base, $delta)
+ {
+ $pos = 0;
+ $src_size = $this->_varint($delta, $pos);
+ $dst_size = $this->_varint($delta, $pos);
+
+ if ($src_size !== strlen($base)) {
+ throw new UnexpectedValueException(
+ 'Expected base delta size ' . strlen($base) . ' does not match the expected '
+ . "value $src_size"
+ );
+ }
+
+ $dest = "";
+ while ($pos < strlen($delta)) {
+ $byte = ord($delta{$pos++});
+
+ if ($byte & 0x80) {
+ /* copy a part of $base */
+ $offset = 0;
+ if ($byte & 0x01) $offset = ord($delta{$pos++});
+ if ($byte & 0x02) $offset |= ord($delta{$pos++}) << 8;
+ if ($byte & 0x04) $offset |= ord($delta{$pos++}) << 16;
+ if ($byte & 0x08) $offset |= ord($delta{$pos++}) << 24;
+ $length = 0;
+ if ($byte & 0x10) $length = ord($delta{$pos++});
+ if ($byte & 0x20) $length |= ord($delta{$pos++}) << 8;
+ if ($byte & 0x40) $length |= ord($delta{$pos++}) << 16;
+ if ($length == 0) $length = 0x10000;
+ $dest .= substr($base, $offset, $length);
+ } else {
+ /* take the next $byte bytes as they are */
+ $dest .= substr($delta, $pos, $byte);
+ $pos += $byte;
+ }
+ }
+
+ if (strlen($dest) !== $dst_size) {
+ throw new UnexpectedValueException(
+ "Deltified string expected to be $dst_size bytes, but actually "
+ . strlen($dest) . ' bytes'
+ );
+ }
+
+ return $dest;
+ }
+
+ /**
+ * Parse a Git varint (variable-length integer). Used in the `_applyDelta()`
+ * method to read the delta header.
+ *
+ * @param string $string The string to parse
+ * @param int &$pos The position in the string to read from
+ *
+ * @return int The integer value
+ */
+ private function _varint($string, &$pos = 0)
+ {
+ $varint = 0;
+ $bitmask = 0x80;
+ for ($i = 0; $bitmask & 0x80; $i += 7) {
+ $bitmask = ord($string{$pos++});
+ $varint |= (($bitmask & 0x7F) << $i);
+ }
+ return $varint;
+ }
+
+ /**
+ * Decodes a big endian modified base 128 number (refer to @see tag); this only
+ * appears to be used in one place, the offset delta in packfiles. The offset
+ * is the number of bytes to seek back from the start of the delta object to find
+ * the base object.
+ *
+ * This code has been implemented using the C code given in the @see tag below.
+ *
+ * @param string &$data The data to read from and decode the number
+ *
+ * @return Array Containing the base offset (number of bytes to seek back) and
+ * the length to use when reading the delta
+ * @see http://git.rsbx.net/Documents/Git_Data_Formats.txt
+ */
+ private function _bigEndianNumber(&$data)
+ {
+ $i = 0;
+ $byte = ord($data{$i++});
+ $number = $byte & 0x7F;
+ while ($byte & 0x80) {
+ $byte = ord($data{$i++});
+ $number = (($number + 1) << 7) | ($byte & 0x7F);
+ }
+
+ return array($number, $i);
+ }
+
+}
diff --git a/3rdparty/granite/git/object/raw.php b/3rdparty/granite/git/object/raw.php
new file mode 100644
index 0000000000..56f363c37b
--- /dev/null
+++ b/3rdparty/granite/git/object/raw.php
@@ -0,0 +1,153 @@
+
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+
+namespace Granite\Git\Object;
+use \InvalidArgumentException as InvalidArgumentException;
+
+/**
+ * Raw represents a raw Git object, using Index to locate
+ * packed objects.
+ *
+ * @category Git
+ * @package Granite
+ * @author Craig Roberts
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+class Raw
+{
+ /**
+ * Integer values for Git objects
+ * @see http://book.git-scm.com/7_the_packfile.html
+ */
+ const OBJ_COMMIT = 1;
+ const OBJ_TREE = 2;
+ const OBJ_BLOB = 3;
+ const OBJ_TAG = 4;
+ const OBJ_OFS_DELTA = 6;
+ const OBJ_REF_DELTA = 7;
+
+ /**
+ * The SHA-1 id of the requested object
+ */
+ protected $sha;
+ /**
+ * The type of the requested object (see class constants)
+ */
+ protected $type;
+ /**
+ * The binary string content of the requested object
+ */
+ protected $content;
+
+ /**
+ * Returns an instance of a raw Git object
+ *
+ * @param string $path The path to the repository root
+ * @param string $sha The SHA-1 id of the requested object
+ *
+ * @return Packed|Loose
+ */
+ public static function factory($path, $sha)
+ {
+ $loose_path = $path
+ . 'objects/'
+ . substr($sha, 0, 2)
+ . '/'
+ . substr($sha, 2);
+ if (file_exists($loose_path)) {
+ return new Loose($path, $sha);
+ } else {
+ return self::_findPackedObject($path, $sha);
+ }
+ }
+
+ /**
+ * Returns the raw content of the Git object requested
+ *
+ * @return string Raw object content
+ */
+ public function content()
+ {
+ return $this->content;
+ }
+
+ /**
+ * Returns the size of the Git object
+ *
+ * @return int The size of the object in bytes
+ */
+ public function size()
+ {
+ return strlen($this->content);
+ }
+
+ /**
+ * Returns the type of the object as either commit, tag, blob or tree
+ *
+ * @return string The object type
+ */
+ public function type()
+ {
+ return $this->type;
+ }
+
+ /**
+ * Searches a packfile for the SHA id and reads the object from the packfile
+ *
+ * @param string $path The path to the repository
+ * @param string $sha The SHA-1 id of the object being requested
+ *
+ * @throws \InvalidArgumentException
+ * @return array An array containing the type, size and object data
+ */
+ private static function _findPackedObject($path, $sha)
+ {
+ $packfiles = glob(
+ $path
+ . 'objects'
+ . DIRECTORY_SEPARATOR
+ . 'pack'
+ . DIRECTORY_SEPARATOR
+ . 'pack-*.pack'
+ );
+
+ $offset = false;
+ foreach ($packfiles as $packfile) {
+ $packname = substr(basename($packfile, '.pack'), 5);
+ $idx = new Index($path, $packname);
+ $offset = $idx->find($sha);
+
+ if ($offset !== false) {
+ break; // Found it
+ }
+ }
+
+ if ($offset == false) {
+ throw new InvalidArgumentException("Could not find packed object $sha");
+ }
+
+ $packname = $path
+ . 'objects'
+ . DIRECTORY_SEPARATOR
+ . 'pack'
+ . DIRECTORY_SEPARATOR
+ . 'pack-' . $packname . '.pack';
+ $object = new Packed($packname, $offset);
+
+ return $object;
+ }
+
+}
+
+?>
diff --git a/3rdparty/granite/git/repository.php b/3rdparty/granite/git/repository.php
new file mode 100644
index 0000000000..30b58a39f5
--- /dev/null
+++ b/3rdparty/granite/git/repository.php
@@ -0,0 +1,293 @@
+
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+
+namespace Granite\Git;
+use \InvalidArgumentException as InvalidArgumentException;
+use \UnexpectedValueException as UnexpectedValueException;
+
+/**
+ * Repository represents a Git repository, providing a variety of methods for
+ * fetching objects from SHA-1 ids or the tip of a branch with `head()`
+ *
+ * @category Git
+ * @package Granite
+ * @author Craig Roberts
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+class Repository
+{
+
+ /**
+ * The path to the repository root
+ */
+ private $_path;
+ /**
+ * The indexed version of a commit, ready to write with `commit()`
+ */
+ private $idx_commit;
+ /**
+ * The indexed version of a tree, modified to with `add()` and `remove()`
+ */
+ private $idx_tree;
+
+ /**
+ * Sets the repository path
+ *
+ * @param string $path The path to the repository root (i.e. /repo/.git/)
+ */
+ public function __construct($path)
+ {
+ if (!is_dir($path)) {
+ throw new InvalidArgumentException("Unable to find directory $path");
+ } elseif (!is_readable($path)) {
+ throw new InvalidArgumentException("Unable to read directory $path");
+ } elseif (!is_dir($path . DIRECTORY_SEPARATOR . 'objects')
+ || !is_dir($path . DIRECTORY_SEPARATOR . 'refs')
+ ) {
+ throw new UnexpectedValueException(
+ "Invalid directory, could not find 'objects' or 'refs' in $path"
+ );
+ }
+
+ $this->_path = $path;
+ $this->idx_commit = $this->factory('commit');
+ $this->idx_tree = $this->factory('tree');
+ }
+
+ /**
+ * Returns an object from the Repository of the given type, with the given
+ * SHA-1 id, or false if it cannot be found
+ *
+ * @param string $type The type (blob, commit, tag or tree) of object being
+ * requested
+ * @param string $sha The SHA-1 id of the object (or the name of a tag)
+ *
+ * @return Blob|Commit|Tag|Tree
+ */
+ public function factory($type, $sha = null)
+ {
+ if (!in_array($type, array('blob', 'commit', 'tag', 'tree'))) {
+ throw new InvalidArgumentException("Invalid type: $type");
+ }
+
+ if ($type == 'tag') {
+ $sha = $this->_ref('tags' . DIRECTORY_SEPARATOR . $sha);
+ }
+ $type = 'Granite\\Git\\' . ucwords($type);
+
+ return new $type($this->_path, $sha);
+ }
+
+ /**
+ * Returns a Commit object representing the HEAD commit
+ *
+ * @param string $branch The branch name to lookup, defaults to 'master'
+ *
+ * @return Commit An object representing the HEAD commit
+ */
+ public function head($branch = 'master', $value = NULL)
+ {
+ if ($value == NULL)
+ return $this->factory(
+ 'commit', $this->_ref('heads' . DIRECTORY_SEPARATOR . $branch)
+ );
+
+ file_put_contents(
+ $this->_path . DIRECTORY_SEPARATOR
+ . 'refs' . DIRECTORY_SEPARATOR
+ . 'heads' . DIRECTORY_SEPARATOR . 'master',
+ $value
+ );
+ }
+
+ /**
+ * Returns a string representing the repository's location, which may or may
+ * not be initialised
+ *
+ * @return string A string representing the repository's location
+ */
+ public function path()
+ {
+ return $this->_path;
+ }
+
+ /**
+ * Returns an array of the local branches under `refs/heads`
+ *
+ * @return array
+ */
+ public function tags()
+ {
+ return $this->_refs('tags');
+ }
+
+ /**
+ * Returns an array of the local tags under `refs/tags`
+ *
+ * @return array
+ */
+ public function branches()
+ {
+ return $this->_refs('heads');
+ }
+
+ private function _refs($type)
+ {
+ $dir = $this->_path . 'refs' . DIRECTORY_SEPARATOR . $type;
+ $refs = glob($dir . DIRECTORY_SEPARATOR . '*');
+ foreach ($refs as &$ref) {
+ $ref = basename($ref);
+ }
+ return $refs;
+ }
+
+ /**
+ * Initialises a Git repository
+ *
+ * @return boolean Returns true on success, false on error
+ */
+ public static function init($path)
+ {
+ $path .= '/';
+ if (!is_dir($path)) {
+ mkdir($path);
+ } elseif (is_dir($path . 'objects')) {
+ return false;
+ }
+
+ mkdir($path . 'objects');
+ mkdir($path . 'objects/info');
+ mkdir($path . 'objects/pack');
+ mkdir($path . 'refs');
+ mkdir($path . 'refs/heads');
+ mkdir($path . 'refs/tags');
+
+ file_put_contents($path . 'HEAD', 'ref: refs/heads/master');
+
+ return true;
+ }
+
+ /**
+ * Writes the indexed commit to disk, with blobs added/removed via `add()` and
+ * `rm()`
+ *
+ * @param string $message The commit message
+ * @param string $author The author name
+ *
+ * @return boolean True on success, or false on failure
+ */
+ public function commit($message, $author)
+ {
+ $user_string = $username . ' ' . time() . ' +0000';
+
+ try {
+ $parents = array($this->repo->head()->sha());
+ } catch (InvalidArgumentException $e) {
+ $parents = array();
+ }
+
+ $this->idx_commit->message($message);
+ $this->idx_commit->author($user_string);
+ $this->idx_commit->committer($user_string);
+ $this->idx_commit->tree($this->idx_tree);
+ $commit->parents($parents);
+
+ $this->idx_tree->write();
+ $this->idx_commit->write();
+
+ $this->repo->head('master', $this->idx_commit->sha());
+
+ $this->idx_commit = $this->factory('commit');
+ $this->idx_tree = $this->factory('tree');
+ }
+
+ /**
+ * Adds a file to the indexed commit, to be written to disk with `commit()`
+ *
+ * @param string $filename The filename to save it under
+ * @param Granite\Git\Blob $blob The raw blob object to add to the tree
+ */
+ public function add($filename, Granite\Git\Blob $blob)
+ {
+ $blob->write();
+ $nodes = $this->idx_tree->nodes();
+ $nodes[$filename] = new Granite\Git\Tree\Node($filename, '100644', $blob->sha());
+ $this->idx_tree->nodes($nodes);
+ }
+
+ /**
+ * Removes a file from the indexed commit
+ */
+ public function rm($filename)
+ {
+ $nodes = $this->idx_tree->nodes();
+ unset($nodes[$filename]);
+ $this->idx_tree->nodes($nodes);
+ }
+
+ /**
+ * Returns an SHA-1 id of the ref resource
+ *
+ * @param string $ref The ref name to lookup
+ *
+ * @return string An SHA-1 id of the ref resource
+ */
+ private function _ref($ref)
+ {
+ // All refs are stored in `.git/refs`
+ $file = $this->_path . 'refs' . DIRECTORY_SEPARATOR . $ref;
+
+ if (file_exists($file)) {
+ return trim(file_get_contents($file));
+ }
+
+ $sha = $this->_packedRef($ref);
+
+ if ($sha == false) {
+ throw new InvalidArgumentException("The ref $ref could not be found");
+ }
+
+ return $sha;
+ }
+
+ /**
+ * Returns an SHA-1 id of the ref resource, or false if it cannot be found
+ *
+ * @param string $ref The ref name to lookup
+ *
+ * @return string An SHA-1 id of the ref resource
+ */
+ private function _packedRef($ref)
+ {
+ $sha = false;
+ if (file_exists($this->_path . 'packed-refs')) {
+ $file = fopen($this->_path . 'packed-refs', 'r');
+
+ while (($line = fgets($file)) !== false) {
+ $info = explode(' ', $line);
+ if (count($info) == 2
+ && trim($info[1]) == 'refs' . DIRECTORY_SEPARATOR . $ref
+ ) {
+ $sha = trim($info[0]);
+ break;
+ }
+ }
+
+ fclose($file);
+ }
+
+ return $sha;
+ }
+
+}
diff --git a/3rdparty/granite/git/tag.php b/3rdparty/granite/git/tag.php
new file mode 100644
index 0000000000..e26ddaffa6
--- /dev/null
+++ b/3rdparty/granite/git/tag.php
@@ -0,0 +1,38 @@
+
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+
+namespace Granite\Git;
+
+/**
+ * Tag represents a full tag object
+ *
+ * @category Git
+ * @package Granite
+ * @author Craig Roberts
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+class Tag
+{
+
+ public function __construct($path, $sha)
+ {
+ $this->sha = $sha;
+ }
+
+ public function sha()
+ {
+ return $this->sha;
+ }
+
+}
diff --git a/3rdparty/granite/git/tree.php b/3rdparty/granite/git/tree.php
new file mode 100644
index 0000000000..2de7227453
--- /dev/null
+++ b/3rdparty/granite/git/tree.php
@@ -0,0 +1,198 @@
+
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+
+namespace Granite\Git;
+use \Granite\Git\Tree\Node as Node;
+
+/**
+ * Tree represents a full tree object, with nodes pointing to other tree objects
+ * and file blobs
+ *
+ * @category Git
+ * @package Granite
+ * @author Craig Roberts
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+class Tree
+{
+
+ /**
+ * The SHA-1 id of the requested tree
+ */
+ private $sha;
+ /**
+ * The nodes/entries for the requested tree
+ */
+ private $nodes = array();
+ /**
+ * The path to the repository
+ */
+ private $path;
+
+ /**
+ * Reads a tree object by fetching the raw object
+ *
+ * @param string $path The path to the repository root
+ * @param string $sha The SHA-1 id of the requested object
+ */
+ public function __construct($path, $sha = NULL, $dbg = FALSE)
+ {
+ $this->path = $path;
+ if ($sha !== NULL) {
+ $object = Object\Raw::factory($path, $sha);
+ $this->sha = $sha;
+
+ if ($object->type() !== Object\Raw::OBJ_TREE) {
+ throw new \InvalidArgumentException(
+ "The object $sha is not a tree, type is " . $object->type()
+ );
+ }
+
+ $content = $object->content();
+ file_put_contents('/tmp/tree_from_real_repo'.time(), $content);
+ $nodes = array();
+
+ for ($i = 0; $i < strlen($content); $i = $data_start + 21) {
+ $data_start = strpos($content, "\0", $i);
+ $info = substr($content, $i, $data_start-$i);
+ list($mode, $name) = explode(' ', $info, 2);
+ // Read the object SHA-1 id
+ $sha = bin2hex(substr($content, $data_start + 1, 20));
+
+ $this->nodes[$name] = new Node($name, $mode, $sha);
+ }
+ }
+ }
+
+ /**
+ * Returns an array of Tree and Granite\Git\Blob objects,
+ * representing subdirectories and files
+ *
+ * @return array Array of Tree and Granite\Git\Blob objects
+ */
+ public function nodes($nodes = null)
+ {
+ if ($nodes == null) {
+ return $this->nodes;
+ }
+ $this->nodes = $nodes;
+ }
+
+ /**
+ * Adds a blob or a tree to the list of nodes
+ *
+ * @param string $name The basename (filename) of the blob or tree
+ * @param string $mode The mode of the blob or tree (see above)
+ * @param string $sha The SHA-1 id of the blob or tree to add
+ */
+ public function add($name, $mode, $sha)
+ {
+ $this->nodes[$name] = new Node($name, $mode, $sha);
+ uasort($this->nodes, array($this, '_sort'));
+ }
+
+ public function write()
+ {
+ $sha = $this->sha();
+ $path = $this->path
+ . 'objects'
+ . DIRECTORY_SEPARATOR
+ . substr($sha, 0, 2)
+ . DIRECTORY_SEPARATOR
+ . substr($sha, 2);
+ // FIXME: currently writes loose objects only
+ if (file_exists($path)) {
+ return FALSE;
+ }
+
+ if (!is_dir(dirname($path))) {
+ mkdir(dirname($path), 0777, TRUE);
+ }
+
+ $loose = fopen($path, 'wb');
+ $data = $this->_raw();
+ $data = 'tree ' . strlen($data) . "\0" . $data;
+ $write = fwrite($loose, gzcompress($data));
+ fclose($loose);
+
+ return ($write !== FALSE);
+ }
+
+ /**
+ * Returns the SHA-1 id of the Tree
+ *
+ * @return string SHA-1 id of the Tree
+ */
+ public function sha()
+ {
+ $data = $this->_raw();
+ $raw = 'tree ' . strlen($data) . "\0" . $data;
+ $this->sha = hash('sha1', $raw);
+ return $this->sha;
+ }
+
+ /**
+ * Generates the raw object content to be saved to disk
+ */
+ public function _raw()
+ {
+ uasort($this->nodes, array($this, '_sort'));
+ $data = '';
+ foreach ($this->nodes as $node)
+ {
+ $data .= base_convert($node->mode(), 10, 8) . ' ' . $node->name() . "\0";
+ $data .= pack('H40', $node->sha());
+ }
+ file_put_contents('/tmp/tree_made'.time(), $data);
+ return $data;
+ }
+
+ /**
+ * Sorts the node entries in a tree, general sort method adapted from original
+ * Git C code (see @see tag below).
+ *
+ * @return 1, 0 or -1 if the first entry is greater than, the same as, or less
+ * than the second, respectively.
+ * @see https://github.com/gitster/git/blob/master/read-cache.c Around line 352,
+ * the `base_name_compare` function
+ */
+ public function _sort(&$a, &$b)
+ {
+ $length = strlen($a->name()) < strlen($b->name()) ? strlen($a->name()) : strlen($b->name());
+
+ $cmp = strncmp($a->name(), $b->name(), $length);
+ if ($cmp) {
+ return $cmp;
+ }
+
+ $suffix1 = $a->name();
+ $suffix1 = (strlen($suffix1) > $length) ? $suffix1{$length} : FALSE;
+ $suffix2 = $b->name();
+ $suffix2 = (strlen($suffix2) > $length) ? $suffix2{$length} : FALSE;
+ if (!$suffix1 && $a->isDirectory()) {
+ $suffix1 = '/';
+ }
+ if (!$suffix2 && $b->isDirectory()) {
+ $suffix2 = '/';
+ }
+ if ($suffix1 < $suffix2) {
+ return -1;
+ } elseif ($suffix1 > $suffix2) {
+ return 1;
+ }
+
+ return 0;
+ }
+
+}
diff --git a/3rdparty/granite/git/tree/node.php b/3rdparty/granite/git/tree/node.php
new file mode 100644
index 0000000000..f99eb1ae28
--- /dev/null
+++ b/3rdparty/granite/git/tree/node.php
@@ -0,0 +1,126 @@
+
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+
+namespace Granite\Git\Tree;
+
+/**
+ * Node represents an entry in a Tree
+ *
+ * @category Git
+ * @package Granite
+ * @author Craig Roberts
+ * @license http://www.opensource.org/licenses/mit-license.php MIT Expat License
+ * @link http://craig0990.github.com/Granite/
+ */
+class Node
+{
+
+ /**
+ * Name of the file, directory or submodule
+ */
+ private $_name;
+ /**
+ * Mode of the object, in octal
+ */
+ private $_mode;
+ /**
+ * SHA-1 id of the tree
+ */
+ private $_sha;
+ /**
+ * Boolean value for whether the entry represents a directory
+ */
+ private $_is_dir;
+ /**
+ * Boolean value for whether the entry represents a submodule
+ */
+ private $_is_submodule;
+
+ /**
+ * Sets up a Node class with properties corresponding to the $mode parameter
+ *
+ * @param string $name The name of the object (file, directory or submodule name)
+ * @param int $mode The mode of the object, retrieved from the repository
+ * @param string $sha The SHA-1 id of the object
+ */
+ public function __construct($name, $mode, $sha)
+ {
+ $this->_name = $name;
+ $this->_mode = intval($mode, 8);
+ $this->_sha = $sha;
+
+ $this->_is_dir = (bool) ($this->_mode & 0x4000);
+ $this->_is_submodule = ($this->_mode == 0xE000);
+ }
+
+ /**
+ * Returns a boolean value indicating whether the node is a directory
+ *
+ * @return boolean
+ */
+ public function isDirectory()
+ {
+ return $this->_is_dir;
+ }
+
+ /**
+ * Returns a boolean value indicating whether the node is a submodule
+ *
+ * @return boolean
+ */
+ public function isSubmodule()
+ {
+ return $this->_is_submodule;
+ }
+
+ /**
+ * Returns the object name
+ *
+ * @return string
+ */
+ public function name()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Returns the object's SHA-1 id
+ *
+ * @return string
+ */
+ public function sha()
+ {
+ return $this->_sha;
+ }
+
+ /**
+ * Returns the octal value of the file mode
+ *
+ * @return int
+ */
+ public function mode()
+ {
+ return $this->_mode;
+ }
+
+ public function type()
+ {
+ if ($this->isDirectory()) {
+ return 'tree';
+ } elseif ($this->isSubmodule()) {
+ return 'commit';
+ } else {
+ return 'blob';
+ }
+ }
+}
diff --git a/apps/files_versioning/ajax/gethead.php b/apps/files_versioning/ajax/gethead.php
new file mode 100644
index 0000000000..cc93b7a1d1
--- /dev/null
+++ b/apps/files_versioning/ajax/gethead.php
@@ -0,0 +1,12 @@
+ $head));
diff --git a/apps/files_versioning/ajax/sethead.php b/apps/files_versioning/ajax/sethead.php
new file mode 100644
index 0000000000..d1b2df9b00
--- /dev/null
+++ b/apps/files_versioning/ajax/sethead.php
@@ -0,0 +1,14 @@
+ 10,
+ 'id' => 'files_versioning',
+ 'name' => 'Versioning and Backup' ));
+
+// Include stylesheets for the settings page
+OC_Util::addStyle( 'files_versioning', 'settings' );
+OC_Util::addScript('files_versioning','settings');
+
+// Register a settings section in the Admin > Personal page
+OC_APP::registerPersonal('files_versioning','settings');
diff --git a/apps/files_versioning/appinfo/info.xml b/apps/files_versioning/appinfo/info.xml
new file mode 100644
index 0000000000..d5546be54a
--- /dev/null
+++ b/apps/files_versioning/appinfo/info.xml
@@ -0,0 +1,14 @@
+
+
+ files_versioning
+ Versioning and Backup
+ 1.0.0
+ GPLv2
+ Craig Roberts
+ 3
+ Versions files using Git repositories, providing a simple backup facility. Currently in *beta* and explicitly without warranty of any kind.
+
+
+
+
+
diff --git a/apps/files_versioning/css/settings.css b/apps/files_versioning/css/settings.css
new file mode 100644
index 0000000000..afe2cd5508
--- /dev/null
+++ b/apps/files_versioning/css/settings.css
@@ -0,0 +1,3 @@
+#file_versioning_commit_chzn {
+ width: 15em;
+}
diff --git a/apps/files_versioning/js/settings.js b/apps/files_versioning/js/settings.js
new file mode 100644
index 0000000000..8dd13bac03
--- /dev/null
+++ b/apps/files_versioning/js/settings.js
@@ -0,0 +1,25 @@
+$(document).ready(function(){
+ $('#file_versioning_head').chosen();
+
+ $.getJSON(OC.filePath('files_versioning', 'ajax', 'gethead.php'), function(jsondata, status) {
+
+ if (jsondata.head == 'HEAD') {
+ // Most recent commit, do nothing
+ } else {
+ $("#file_versioning_head").val(jsondata.head);
+ // Trigger the chosen update call
+ // See http://harvesthq.github.com/chosen/
+ $("#file_versioning_head").trigger("liszt:updated");
+ }
+ });
+
+ $('#file_versioning_head').change(function() {
+
+ var data = $(this).serialize();
+ $.post( OC.filePath('files_versioning', 'ajax', 'sethead.php'), data, function(data){
+ if(data == 'error'){
+ console.log('Saving new HEAD failed');
+ }
+ });
+ });
+});
diff --git a/apps/files_versioning/lib_granite.php b/apps/files_versioning/lib_granite.php
new file mode 100644
index 0000000000..c69c62d9c4
--- /dev/null
+++ b/apps/files_versioning/lib_granite.php
@@ -0,0 +1,12 @@
+head();
+for ($i = 0; $i < 50; $i++) {
+ $commits[] = $commit;
+ $parents = $commit->parents();
+ if (count($parents) > 0) {
+ $parent = $parents[0];
+ } else {
+ break;
+ }
+
+ $commit = $repository->factory('commit', $parent);
+}
+
+$tmpl = new OC_Template( 'files_versioning', 'settings');
+$tmpl->assign('commits', $commits);
+return $tmpl->fetchPage();
diff --git a/apps/files_versioning/templates/settings.php b/apps/files_versioning/templates/settings.php
new file mode 100644
index 0000000000..17f4cc7f77
--- /dev/null
+++ b/apps/files_versioning/templates/settings.php
@@ -0,0 +1,12 @@
+
+ Versioning and Backup
+ Please note: Backing up large files (around 16MB+) will cause your backup history to grow very large, very quickly.
+ Backup Folder
+
+ sha() . '">' . $commit->message() . '';
+ endforeach;
+ ?>
+
+
diff --git a/apps/files_versioning/versionstorage.php b/apps/files_versioning/versionstorage.php
new file mode 100644
index 0000000000..d083e623df
--- /dev/null
+++ b/apps/files_versioning/versionstorage.php
@@ -0,0 +1,386 @@
+.
+ */
+
+// Include Granite
+require_once('lib_granite.php');
+
+// Create a top-level 'Backup' directory if it does not already exist
+$user = OC_User::getUser();
+if (OC_Filesystem::$loaded and !OC_Filesystem::is_dir('/Backup')) {
+ OC_Filesystem::mkdir('/Backup');
+ OC_Preferences::setValue(OC_User::getUser(), 'files_versioning', 'head', 'HEAD');
+}
+
+// Generate the repository path (currently using 'full' repositories, as opposed to bare ones)
+$repo_path = DIRECTORY_SEPARATOR
+ . OC_User::getUser()
+ . DIRECTORY_SEPARATOR
+ . 'files'
+ . DIRECTORY_SEPARATOR
+ . 'Backup';
+
+// Mount the 'Backup' folder using the versioned storage provider below
+OC_Filesystem::mount('OC_Filestorage_Versioned', array('repo'=>$repo_path), $repo_path . DIRECTORY_SEPARATOR);
+
+class OC_Filestorage_Versioned extends OC_Filestorage {
+
+ /**
+ * Holds an instance of Granite\Git\Repository
+ */
+ protected $repo;
+
+ /**
+ * Constructs a new OC_Filestorage_Versioned instance, expects an associative
+ * array with a `repo` key set to the path of the repository's `.git` folder
+ *
+ * @param array $parameters An array containing the key `repo` pointing to the
+ * repository path.
+ */
+ public function __construct($parameters) {
+ // Get the full path to the repository folder
+ $path = OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data')
+ . $parameters['repo']
+ . DIRECTORY_SEPARATOR
+ . '.git'
+ . DIRECTORY_SEPARATOR;
+
+ try {
+ // Attempt to load the repository
+ $this->repo = new Granite\Git\Repository($path);
+ } catch (InvalidArgumentException $e) {
+ // $path is not a valid Git repository, we must create one
+ Granite\Git\Repository::init($path);
+
+ // Load the newly-initialised repository
+ $this->repo = new Granite\Git\Repository($path);
+
+ /**
+ * Create an initial commit with a README file
+ * FIXME: This functionality should be transferred to the Granite library
+ */
+ $blob = new Granite\Git\Blob($this->repo->path());
+ $blob->content('Your Backup directory is now ready for use.');
+
+ // Create a new tree to hold the README file
+ $tree = $this->repo->factory('tree');
+ // Create a tree node to represent the README blob
+ $tree_node = new Granite\Git\Tree\Node('README', '100644', $blob->sha());
+ $tree->nodes(array($tree_node->name() => $tree_node));
+
+ // Create an initial commit
+ $commit = new Granite\Git\Commit($this->repo->path());
+ $user_string = OC_User::getUser() . ' ' . time() . ' +0000';
+ $commit->author($user_string);
+ $commit->committer($user_string);
+ $commit->message('Initial commit');
+ $commit->tree($tree);
+
+ // Write it all to disk
+ $blob->write();
+ $tree->write();
+ $commit->write();
+
+ // Update the HEAD for the 'master' branch
+ $this->repo->head('master', $commit->sha());
+ }
+
+ // Update the class pointer to the HEAD
+ $head = OC_Preferences::getValue(OC_User::getUser(), 'files_versioning', 'head', 'HEAD');
+
+ // Load the most recent commit if the preference is not set
+ if ($head == 'HEAD') {
+ $this->head = $this->repo->head()->sha();
+ } else {
+ $this->head = $head;
+ }
+ }
+
+ public function mkdir($path) {
+ if (mkdir("versioned:/{$this->repo->path()}$path#{$this->head}")) {
+ $this->head = $this->repo->head()->sha();
+ OC_Preferences::setValue(OC_User::getUser(), 'files_versioning', 'head', $head);
+ return true;
+ }
+
+ return false;
+ }
+
+ public function rmdir($path) {
+
+ }
+
+ /**
+ * Returns a directory handle to the requested path, or FALSE on failure
+ *
+ * @param string $path The directory path to open
+ *
+ * @return boolean|resource A directory handle, or FALSE on failure
+ */
+ public function opendir($path) {
+ return opendir("versioned:/{$this->repo->path()}$path#{$this->head}");
+ }
+
+ /**
+ * Returns TRUE if $path is a directory, or FALSE if not
+ *
+ * @param string $path The path to check
+ *
+ * @return boolean
+ */
+ public function is_dir($path) {
+ return $this->filetype($path) == 'dir';
+ }
+
+ /**
+ * Returns TRUE if $path is a file, or FALSE if not
+ *
+ * @param string $path The path to check
+ *
+ * @return boolean
+ */
+ public function is_file($path) {
+ return $this->filetype($path) == 'file';
+ }
+
+ public function stat($path)
+ {
+ return stat("versioned:/{$this->repo->path()}$path#{$this->head}");
+ }
+
+ /**
+ * Returns the strings 'dir' or 'file', depending on the type of $path
+ *
+ * @param string $path The path to check
+ *
+ * @return string Returns 'dir' if a directory, 'file' otherwise
+ */
+ public function filetype($path) {
+ if ($path == "" || $path == "/") {
+ return 'dir';
+ } else {
+ if (substr($path, -1) == '/') {
+ $path = substr($path, 0, -1);
+ }
+
+ $node = $this->tree_search($this->repo, $this->repo->factory('commit', $this->head)->tree(), $path);
+
+ // Does it exist, or is it new?
+ if ($node == null) {
+ // New file
+ return 'file';
+ } else {
+ // Is it a tree?
+ try {
+ $this->repo->factory('tree', $node);
+ return 'dir';
+ } catch (InvalidArgumentException $e) {
+ // Nope, must be a blob
+ return 'file';
+ }
+ }
+ }
+ }
+
+ public function filesize($path) {
+ return filesize("versioned:/{$this->repo->path()}$path#{$this->head}");
+ }
+
+ /**
+ * Returns a boolean value representing whether $path is readable
+ *
+ * @param string $path The path to check
+ *(
+ * @return boolean Whether or not the path is readable
+ */
+ public function is_readable($path) {
+ return true;
+ }
+
+ /**
+ * Returns a boolean value representing whether $path is writable
+ *
+ * @param string $path The path to check
+ *(
+ * @return boolean Whether or not the path is writable
+ */
+ public function is_writable($path) {
+
+ $head = OC_Preferences::getValue(OC_User::getUser(), 'files_versioning', 'head', 'HEAD');
+ if ($head !== 'HEAD' && $head !== $this->repo->head()->sha()) {
+ // Cannot modify previous commits
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns a boolean value representing whether $path exists
+ *
+ * @param string $path The path to check
+ *(
+ * @return boolean Whether or not the path exists
+ */
+ public function file_exists($path) {
+ return file_exists("versioned:/{$this->repo->path()}$path#{$this->head}");
+ }
+
+ /**
+ * Returns an integer value representing the inode change time
+ * (NOT IMPLEMENTED)
+ *
+ * @param string $path The path to check
+ *(
+ * @return int Timestamp of the last inode change
+ */
+ public function filectime($path) {
+ return -1;
+ }
+
+ /**
+ * Returns an integer value representing the file modification time
+ *
+ * @param string $path The path to check
+ *(
+ * @return int Timestamp of the last file modification
+ */
+ public function filemtime($path) {
+ return filemtime("versioned:/{$this->repo->path()}$path#{$this->head}");
+ }
+
+ public function file_get_contents($path) {
+ return file_get_contents("versioned:/{$this->repo->path()}$path#{$this->head}");
+ }
+
+ public function file_put_contents($path, $data) {
+ $success = file_put_contents("versioned:/{$this->repo->path()}$path#{$this->head}", $data);
+ if ($success !== false) {
+ // Update the HEAD in the preferences
+ OC_Preferences::setValue(OC_User::getUser(), 'files_versioning', 'head', $this->repo->head()->sha());
+ return $success;
+ }
+
+ return false;
+ }
+
+ public function unlink($path) {
+
+ }
+
+ public function rename($path1, $path2) {
+
+ }
+
+ public function copy($path1, $path2) {
+
+ }
+
+ public function fopen($path, $mode) {
+ return fopen("versioned:/{$this->repo->path()}$path#{$this->head}", $mode);
+ }
+
+ public function getMimeType($path) {
+ if ($this->filetype($path) == 'dir') {
+ return 'httpd/unix-directory';
+ } elseif ($this->filesize($path) == 0) {
+ // File's empty, returning text/plain allows opening in the web editor
+ return 'text/plain';
+ } else {
+ $finfo = new finfo(FILEINFO_MIME_TYPE);
+ /**
+ * We need to represent the repository path, the file path, and the
+ * revision, which can be simply achieved with a convention of using
+ * `.git` in the repository directory (bare or not) and the '#part'
+ * segment of a URL to specify the revision. For example
+ *
+ * versioned://var/www/myrepo.git/docs/README.md#HEAD ('bare' repo)
+ * versioned://var/www/myrepo/.git/docs/README.md#HEAD ('full' repo)
+ * versioned://var/www/myrepo/.git/docs/README.md#6a8f...8a54 ('full' repo and SHA-1 commit ID)
+ */
+ $mime = $finfo->buffer(file_get_contents("versioned:/{$this->repo->path()}$path#{$this->head}"));
+ return $mime;
+ }
+ }
+
+ /**
+ * Generates a hash based on the file contents
+ *
+ * @param string $type The hashing algorithm to use (e.g. 'md5', 'sha256', etc.)
+ * @param string $path The file to be hashed
+ * @param boolean $raw Outputs binary data if true, lowercase hex digits otherwise
+ *
+ * @return string Hashed string representing the file contents
+ */
+ public function hash($type, $path, $raw) {
+ return hash($type, file_get_contents($path), $raw);
+ }
+
+ public function free_space($path) {
+ }
+
+ public function search($query) {
+
+ }
+
+ public function touch($path, $mtime=null) {
+
+ }
+
+
+ public function getLocalFile($path) {
+ }
+
+ /**
+ * Recursively searches a tree for a path, returning FALSE if is not found
+ * or an SHA-1 id if it is found.
+ *
+ * @param string $repo The repository containing the tree object
+ * @param string $tree The tree object to search
+ * @param string $path The path to search for (relative to the tree)
+ * @param int $depth The depth of the current search (for recursion)
+ *
+ * @return string|boolean The SHA-1 id of the sub-tree
+ */
+ private function tree_search($repo, $tree, $path, $depth = 0)
+ {
+ $paths = array_values(explode(DIRECTORY_SEPARATOR, $path));
+
+ $current_path = $paths[$depth];
+
+ $nodes = $tree->nodes();
+ foreach ($nodes as $node) {
+ if ($node->name() == $current_path) {
+
+ if (count($paths)-1 == $depth) {
+ // Stop, found it
+ return $node->sha();
+ }
+
+ // Recurse if necessary
+ if ($node->isDirectory()) {
+ $tree = $this->repo->factory('tree', $node->sha());
+ return $this->tree_search($repo, $tree, $path, $depth + 1);
+ }
+ }
+ }
+
+ return false;
+ }
+
+}
diff --git a/apps/files_versioning/versionwrapper.php b/apps/files_versioning/versionwrapper.php
new file mode 100644
index 0000000000..b83a4fd3b2
--- /dev/null
+++ b/apps/files_versioning/versionwrapper.php
@@ -0,0 +1,686 @@
+tree);
+ return true;
+ }
+
+ /**
+ * Open directory handle
+ */
+ public function dir_opendir($path, $options) {
+ // Parse the URL into a repository directory, file path and commit ID
+ list($this->repo, $repo_file, $this->commit) = $this->parse_url($path);
+
+ if ($repo_file == '' || $repo_file == '/') {
+ // Set the tree property for the future `readdir()` etc. calls
+ $this->tree = array_values($this->commit->tree()->nodes());
+ return true;
+ } elseif ($this->tree_search($this->repo, $this->commit->tree(), $repo_file) !== false) {
+ // Something exists at this path, is it a directory though?
+ try {
+ $tree = $this->repo->factory(
+ 'tree',
+ $this->tree_search($this->repo, $this->commit->tree(), $repo_file)
+ );
+ $this->tree = array_values($tree->nodes());
+ return true;
+ } catch (InvalidArgumentException $e) {
+ // Trying to call `opendir()` on a file, return false below
+ }
+ }
+
+ // Unable to find the directory, return false
+ return false;
+ }
+
+ /**
+ * Read entry from directory handle
+ */
+ public function dir_readdir() {
+ return isset($this->tree[$this->dir_position])
+ ? $this->tree[$this->dir_position++]->name()
+ : false;
+ }
+
+ /**
+ * Rewind directory handle
+ */
+ public function dir_rewinddir() {
+ $this->dir_position = 0;
+ }
+
+ /**
+ * Create a directory
+ * Git doesn't track empty directories, so a ".empty" file is added instead
+ */
+ public function mkdir($path, $mode, $options) {
+ // Parse the URL into a repository directory, file path and commit ID
+ list($this->repo, $repo_file, $this->commit) = $this->parse_url($path);
+
+ // Create an empty file for Git
+ $empty = new Granite\Git\Blob($this->repo->path());
+ $empty->content('');
+ $empty->write();
+
+ if (dirname($repo_file) == '.') {
+ // Adding a new directory to the root tree
+ $tree = $this->repo->head()->tree();
+ } else {
+ $tree = $this->repo->factory('tree', $this->tree_search(
+ $this->repo, $this->repo->head()->tree(), dirname($repo_file)
+ )
+ );
+ }
+
+ // Create our new tree, with our empty file
+ $dir = $this->repo->factory('tree');
+ $nodes = array();
+ $nodes[self::EMPTYFILE] = new Granite\Git\Tree\Node(self::EMPTYFILE, '100644', $empty->sha());
+ $dir->nodes($nodes);
+ $dir->write();
+
+ // Add our new tree to its parent
+ $nodes = $tree->nodes();
+ $nodes[basename($repo_file)] = new Granite\Git\Tree\Node(basename($repo_file), '040000', $dir->sha());
+ $tree->nodes($nodes);
+ $tree->write();
+
+ // We need to recursively update each parent tree, since they are all
+ // hashed and the changes will cascade back up the chain
+
+ // So, we're currently at the bottom-most directory
+ $current_dir = dirname($repo_file);
+ $previous_tree = $tree;
+
+ if ($current_dir !== '.') {
+ do {
+ // Determine the parent directory
+ $previous_dir = $current_dir;
+ $current_dir = dirname($current_dir);
+
+ $current_tree = $current_dir !== '.'
+ ? $this->repo->factory(
+ 'tree', $this->tree_search(
+ $this->repo,
+ $this->repo->head()->tree(),
+ $current_dir
+ )
+ )
+ : $this->repo->head()->tree();
+
+ $current_nodes = $current_tree->nodes();
+ $current_nodes[basename($previous_dir)] = new Granite\Git\Tree\Node(
+ basename($previous_dir), '040000', $previous_tree->sha()
+ );
+ $current_tree->nodes($current_nodes);
+ $current_tree->write();
+
+ $previous_tree = $current_tree;
+ } while ($current_dir !== '.');
+
+ $tree = $previous_tree;
+ }
+
+ // Create a new commit to represent this write
+ $commit = $this->repo->factory('commit');
+ $username = OC_User::getUser();
+ $user_string = $username . ' ' . time() . ' +0000';
+ $commit->author($user_string);
+ $commit->committer($user_string);
+ $commit->message("$username created the `$repo_file` directory, " . date('d F Y H:i', time()) . '.');
+ $commit->parents(array($this->repo->head()->sha()));
+ $commit->tree($tree);
+
+ // Write it to disk
+ $commit->write();
+
+ // Update the HEAD for the 'master' branch
+ $this->repo->head('master', $commit->sha());
+
+ return true;
+ }
+
+ /**
+ * Renames a file or directory
+ */
+ public function rename($path_from, $path_to) {
+
+ }
+
+ /**
+ * Removes a directory
+ */
+ public function rmdir($path, $options) {
+
+ }
+
+ /**
+ * Retrieve the underlaying resource (NOT IMPLEMENTED)
+ */
+ public function stream_cast($cast_as) {
+ return false;
+ }
+
+ /**
+ * Close a resource
+ */
+ public function stream_close() {
+ unset($this->blob);
+ return true;
+ }
+
+ /**
+ * Tests for end-of-file on a file pointer
+ */
+ public function stream_eof() {
+ return !($this->file_position < strlen($this->blob));
+ }
+
+ /**
+ * Flushes the output (NOT IMPLEMENTED)
+ */
+ public function stream_flush() {
+ return false;
+ }
+
+ /**
+ * Advisory file locking (NOT IMPLEMENTED)
+ */
+ public function stream_lock($operation) {
+ return false;
+ }
+
+ /**
+ * Change stream options (NOT IMPLEMENTED)
+ * Called in response to `chgrp()`, `chown()`, `chmod()` and `touch()`
+ */
+ public function stream_metadata($path, $option, $var) {
+ return false;
+ }
+
+ /**
+ * Opens file or URL
+ */
+ public function stream_open($path, $mode, $options, &$opened_path) {
+ // Store the path, so we can use it later in `stream_write()` if necessary
+ $this->path = $path;
+ // Parse the URL into a repository directory, file path and commit ID
+ list($this->repo, $repo_file, $this->commit) = $this->parse_url($path);
+
+ $file = $this->tree_search($this->repo, $this->commit->tree(), $repo_file);
+ if ($file !== false) {
+ try {
+ $this->blob = $this->repo->factory('blob', $file)->content();
+ return true;
+ } catch (InvalidArgumentException $e) {
+ // Trying to open a directory, return false below
+ }
+ } elseif ($mode !== 'r') {
+ // All other modes allow opening for reading and writing, clearly
+ // some 'write' files may not exist yet...
+ return true;
+ }
+
+ // File could not be found or is not actually a file
+ return false;
+ }
+
+ /**
+ * Read from stream
+ */
+ public function stream_read($count) {
+ // Fetch the remaining set of bytes
+ $bytes = substr($this->blob, $this->file_position, $count);
+
+ // If EOF or empty string, return false
+ if ($bytes == '' || $bytes == false) {
+ return false;
+ }
+
+ // If $count does not extend past EOF, add $count to stream offset
+ if ($this->file_position + $count < strlen($this->blob)) {
+ $this->file_position += $count;
+ } else {
+ // Otherwise return all remaining bytes
+ $this->file_position = strlen($this->blob);
+ }
+
+ return $bytes;
+ }
+
+ /**
+ * Seeks to specific location in a stream
+ */
+ public function stream_seek($offset, $whence = SEEK_SET) {
+ $new_offset = false;
+
+ switch ($whence)
+ {
+ case SEEK_SET:
+ $new_offset = $offset;
+ break;
+ case SEEK_CUR:
+ $new_offset = $this->file_position += $offset;
+ break;
+ case SEEK_END:
+ $new_offset = strlen($this->blob) + $offset;
+ break;
+ }
+
+ $this->file_position = $offset;
+
+ return ($new_offset !== false);
+ }
+
+ /**
+ * Change stream options (NOT IMPLEMENTED)
+ */
+ public function stream_set_option($option, $arg1, $arg2) {
+ return false;
+ }
+
+ /**
+ * Retrieve information about a file resource (NOT IMPLEMENTED)
+ */
+ public function stream_stat() {
+
+ }
+
+ /**
+ * Retrieve the current position of a stream
+ */
+ public function stream_tell() {
+ return $this->file_position;
+ }
+
+ /**
+ * Truncate stream
+ */
+ public function stream_truncate($new_size) {
+
+ }
+
+ /**
+ * Write to stream
+ * FIXME: Could use heavy refactoring
+ */
+ public function stream_write($data) {
+ /**
+ * FIXME: This also needs to be added to Granite, in the form of `add()`,
+ * `rm()` and `commit()` calls
+ */
+
+ // Parse the URL into a repository directory, file path and commit ID
+ list($this->repo, $repo_file, $this->commit) = $this->parse_url($this->path);
+
+ $node = $this->tree_search($this->repo, $this->commit->tree(), $repo_file);
+
+ if ($node !== false) {
+ // File already exists, attempting modification of existing tree
+ try {
+ $this->repo->factory('blob', $node);
+
+ // Create our new blob with the provided $data
+ $blob = $this->repo->factory('blob');
+ $blob->content($data);
+ $blob->write();
+
+ // We know the tree exists, so strip the filename from the path and
+ // find it...
+
+ if (dirname($repo_file) == '.' || dirname($repo_file) == '') {
+ // Root directory
+ $tree = $this->repo->head()->tree();
+ } else {
+ // Sub-directory
+ $tree = $this->repo->factory('tree', $this->tree_search(
+ $this->repo,
+ $this->repo->head()->tree(),
+ dirname($repo_file)
+ )
+ );
+ }
+
+ // Replace the old blob with our newly modified one
+ $tree_nodes = $tree->nodes();
+ $tree_nodes[basename($repo_file)] = new Granite\Git\Tree\Node(
+ basename($repo_file), '100644', $blob->sha()
+ );
+ $tree->nodes($tree_nodes);
+ $tree->write();
+
+ // We need to recursively update each parent tree, since they are all
+ // hashed and the changes will cascade back up the chain
+
+ // So, we're currently at the bottom-most directory
+ $current_dir = dirname($repo_file);
+ $previous_tree = $tree;
+
+ if ($current_dir !== '.') {
+ do {
+ // Determine the parent directory
+ $previous_dir = $current_dir;
+ $current_dir = dirname($current_dir);
+
+ $current_tree = $current_dir !== '.'
+ ? $this->repo->factory(
+ 'tree', $this->tree_search(
+ $this->repo,
+ $this->repo->head()->tree(),
+ $current_dir
+ )
+ )
+ : $this->repo->head()->tree();
+
+ $current_nodes = $current_tree->nodes();
+ $current_nodes[basename($previous_dir)] = new Granite\Git\Tree\Node(
+ basename($previous_dir), '040000', $previous_tree->sha()
+ );
+ $current_tree->nodes($current_nodes);
+ $current_tree->write();
+
+ $previous_tree = $current_tree;
+ } while ($current_dir !== '.');
+ }
+
+ // Create a new commit to represent this write
+ $commit = $this->repo->factory('commit');
+ $username = OC_User::getUser();
+ $user_string = $username . ' ' . time() . ' +0000';
+ $commit->author($user_string);
+ $commit->committer($user_string);
+ $commit->message("$username modified the `$repo_file` file, " . date('d F Y H:i', time()) . '.');
+ $commit->parents(array($this->repo->head()->sha()));
+ $commit->tree($previous_tree);
+
+ // Write it to disk
+ $commit->write();
+
+ // Update the HEAD for the 'master' branch
+ $this->repo->head('master', $commit->sha());
+
+ // If we made it this far, write was successful - update the stream
+ // position and return the number of bytes written
+ $this->file_position += strlen($data);
+ return strlen($data);
+
+ } catch (InvalidArgumentException $e) {
+ // Attempting to write to a directory or other error, fail
+ return 0;
+ }
+ } else {
+ // File does not exist, needs to be created
+
+ // Create our new blob with the provided $data
+ $blob = $this->repo->factory('blob');
+ $blob->content($data);
+ $blob->write();
+
+ if (dirname($repo_file) == '.') {
+ // Trying to add a new file to the root tree, nice and easy
+ $tree = $this->repo->head()->tree();
+ $tree_nodes = $tree->nodes();
+ $tree_nodes[basename($repo_file)] = new Granite\Git\Tree\Node(
+ basename($repo_file), '100644', $blob->sha()
+ );
+ $tree->nodes($tree_nodes);
+ $tree->write();
+ } else {
+ // Trying to add a new file to a subdirectory, try and find it
+ $tree = $this->repo->factory('tree', $this->tree_search(
+ $this->repo, $this->repo->head()->tree(), dirname($repo_file)
+ )
+ );
+
+ // Add the blob to the tree
+ $nodes = $tree->nodes();
+ $nodes[basename($repo_file)] = new Granite\Git\Tree\Node(
+ basename($repo_file), '100644', $blob->sha()
+ );
+ $tree->nodes($nodes);
+ $tree->write();
+
+ // We need to recursively update each parent tree, since they are all
+ // hashed and the changes will cascade back up the chain
+
+ // So, we're currently at the bottom-most directory
+ $current_dir = dirname($repo_file);
+ $previous_tree = $tree;
+
+ if ($current_dir !== '.') {
+ do {
+ // Determine the parent directory
+ $previous_dir = $current_dir;
+ $current_dir = dirname($current_dir);
+
+ $current_tree = $current_dir !== '.'
+ ? $this->repo->factory(
+ 'tree', $this->tree_search(
+ $this->repo,
+ $this->repo->head()->tree(),
+ $current_dir
+ )
+ )
+ : $this->repo->head()->tree();
+
+ $current_nodes = $current_tree->nodes();
+ $current_nodes[basename($previous_dir)] = new Granite\Git\Tree\Node(
+ basename($previous_dir), '040000', $previous_tree->sha()
+ );
+ $current_tree->nodes($current_nodes);
+ $current_tree->write();
+
+ $previous_tree = $current_tree;
+ } while ($current_dir !== '.');
+
+ $tree = $previous_tree;
+ }
+ }
+
+ // Create a new commit to represent this write
+ $commit = $this->repo->factory('commit');
+ $username = OC_User::getUser();
+ $user_string = $username . ' ' . time() . ' +0000';
+ $commit->author($user_string);
+ $commit->committer($user_string);
+ $commit->message("$username created the `$repo_file` file, " . date('d F Y H:i', time()) . '.');
+ $commit->parents(array($this->repo->head()->sha()));
+ $commit->tree($tree); // Top-level tree (NOT the newly modified tree)
+
+ // Write it to disk
+ $commit->write();
+
+ // Update the HEAD for the 'master' branch
+ $this->repo->head('master', $commit->sha());
+
+ // If we made it this far, write was successful - update the stream
+ // position and return the number of bytes written
+ $this->file_position += strlen($data);
+ return strlen($data);
+ }
+
+ // Write failed
+ return 0;
+ }
+
+ /**
+ * Delete a file
+ */
+ public function unlink($path) {
+
+ }
+
+ /**
+ * Retrieve information about a file
+ */
+ public function url_stat($path, $flags) {
+ // Parse the URL into a repository directory, file path and commit ID
+ list($this->repo, $repo_file, $this->commit) = $this->parse_url($path);
+
+ $node = $this->tree_search($this->repo, $this->commit->tree(), $repo_file);
+
+ if ($node == false && $this->commit->sha() == $this->repo->head()->sha()) {
+ // A new file - no information available
+ $size = 0;
+ $mtime = -1;
+ } else {
+
+ // Is it a directory?
+ try {
+ $this->repo->factory('tree', $node);
+ $size = 4096; // FIXME
+ } catch (InvalidArgumentException $e) {
+ // Must be a file
+ $size = strlen(file_get_contents($path));
+ }
+
+ // Parse the timestamp from the commit message
+ preg_match('/[0-9]{10}+/', $this->commit->committer(), $matches);
+ $mtime = $matches[0];
+ }
+
+ $stat["dev"] = "";
+ $stat["ino"] = "";
+ $stat["mode"] = "";
+ $stat["nlink"] = "";
+ $stat["uid"] = "";
+ $stat["gid"] = "";
+ $stat["rdev"] = "";
+ $stat["size"] = $size;
+ $stat["atime"] = $mtime;
+ $stat["mtime"] = $mtime;
+ $stat["ctime"] = $mtime;
+ $stat["blksize"] = "";
+ $stat["blocks"] = "";
+
+ return $stat;
+ }
+
+ /**
+ * Debug function for development purposes
+ */
+ private function debug($message, $level = OC_Log::DEBUG)
+ {
+ if ($this->debug) {
+ OC_Log::write('files_versioning', $message, $level);
+ }
+ }
+
+ /**
+ * Parses a URL of the form:
+ * `versioned://path/to/git/repository/.git/path/to/file#SHA-1-commit-id`
+ * FIXME: Will throw an InvalidArgumentException if $path is invaid
+ *
+ * @param string $path The path to parse
+ *
+ * @return array An array containing an instance of Granite\Git\Repository,
+ * the file path, and an instance of Granite\Git\Commit
+ * @throws InvalidArgumentException If the repository cannot be loaded
+ */
+ private function parse_url($path)
+ {
+ preg_match('/\/([A-Za-z0-9\/]+\.git\/)([A-Za-z0-9\/\.\/]*)(#([A-Fa-f0-9]+))*/', $path, $matches);
+
+ // Load up the repo
+ $repo = new \Granite\Git\Repository($matches[1]);
+ // Parse the filename (stripping any trailing slashes)
+ $repo_file = $matches[2];
+ if (substr($repo_file, -1) == '/') {
+ $repo_file = substr($repo_file, 0, -1);
+ }
+
+ // Default to HEAD if no commit is provided
+ $repo_commit = isset($matches[4])
+ ? $matches[4]
+ : $repo->head()->sha();
+
+ // Load the relevant commit
+ $commit = $repo->factory('commit', $repo_commit);
+
+ return array($repo, $repo_file, $commit);
+ }
+
+ /**
+ * Recursively searches a tree for a path, returning FALSE if is not found
+ * or an SHA-1 id if it is found.
+ *
+ * @param string $repo The repository containing the tree object
+ * @param string $tree The tree object to search
+ * @param string $path The path to search for (relative to the tree)
+ * @param int $depth The depth of the current search (for recursion)
+ *
+ * @return string|boolean The SHA-1 id of the sub-tree
+ */
+ private function tree_search($repo, $tree, $path, $depth = 0)
+ {
+ $paths = array_values(explode(DIRECTORY_SEPARATOR, $path));
+
+ $current_path = $paths[$depth];
+
+ $nodes = $tree->nodes();
+ foreach ($nodes as $node) {
+ if ($node->name() == $current_path) {
+
+ if (count($paths)-1 == $depth) {
+ // Stop, found it
+ return $node->sha();
+ }
+
+ // Recurse if necessary
+ if ($node->isDirectory()) {
+ $tree = $this->repo->factory('tree', $node->sha());
+ return $this->tree_search($repo, $tree, $path, $depth + 1);
+ }
+ }
+ }
+
+ return false;
+ }
+
+}
From 6cf3f10d3546eda09ceb823af5c2cf1190f18743 Mon Sep 17 00:00:00 2001
From: Frank Karlitschek
Date: Mon, 9 Apr 2012 22:51:53 +0200
Subject: [PATCH 126/133] fix includes
---
apps/files_versioning/lib_granite.php | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/apps/files_versioning/lib_granite.php b/apps/files_versioning/lib_granite.php
index c69c62d9c4..62aebdd99d 100644
--- a/apps/files_versioning/lib_granite.php
+++ b/apps/files_versioning/lib_granite.php
@@ -1,12 +1,12 @@
Date: Tue, 10 Apr 2012 13:53:27 +0200
Subject: [PATCH 127/133] fix: drag'n'drop actions with files containing
special chars, fixes oc-420
---
files/js/files.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/files/js/files.js b/files/js/files.js
index df9f45a7af..1c0a40c236 100644
--- a/files/js/files.js
+++ b/files/js/files.js
@@ -417,7 +417,7 @@ var folderDropOptions={
var dir=$('#dir').val();
$.ajax({
url: 'ajax/move.php',
- data: "dir="+dir+"&file="+file+'&target='+dir+'/'+target,
+ data: "dir="+encodeURIComponent(dir)+"&file="+encodeURIComponent(file)+'&target='+encodeURIComponent(dir)+'/'+encodeURIComponent(target),
complete: function(data){boolOperationFinished(data, function(){
var el = $('#fileList tr').filterAttr('data-file',file).find('td.filename');
el.draggable('destroy');
@@ -443,7 +443,7 @@ var crumbDropOptions={
}
$.ajax({
url: 'ajax/move.php',
- data: "dir="+dir+"&file="+file+'&target='+target,
+ data: "dir="+encodeURIComponent(dir)+"&file="+encodeURIComponent(file)+'&target='+encodeURIComponent(target),
complete: function(data){boolOperationFinished(data, function(){
FileList.remove(file);
});}
From 47f94548ce4c015782ebfe8566f009f5d4091fb3 Mon Sep 17 00:00:00 2001
From: Frank Karlitschek
Date: Tue, 10 Apr 2012 15:05:33 +0200
Subject: [PATCH 128/133] =?UTF-8?q?don=C2=B4t=20enable=20by=20default.=20s?=
=?UTF-8?q?till=20broken?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
apps/files_versioning/appinfo/info.xml | 1 -
apps/files_versioning/lib_granite.php | 20 ++++++++++----------
2 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/apps/files_versioning/appinfo/info.xml b/apps/files_versioning/appinfo/info.xml
index d5546be54a..4c67894f9f 100644
--- a/apps/files_versioning/appinfo/info.xml
+++ b/apps/files_versioning/appinfo/info.xml
@@ -7,7 +7,6 @@
Craig Roberts
3
Versions files using Git repositories, providing a simple backup facility. Currently in *beta* and explicitly without warranty of any kind.
-
diff --git a/apps/files_versioning/lib_granite.php b/apps/files_versioning/lib_granite.php
index 62aebdd99d..571e5cea63 100644
--- a/apps/files_versioning/lib_granite.php
+++ b/apps/files_versioning/lib_granite.php
@@ -1,12 +1,12 @@
Date: Sat, 31 Mar 2012 00:03:21 +0200
Subject: [PATCH 129/133] Silence error for missing appinfo info file
---
lib/app.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/app.php b/lib/app.php
index 7d5e8fa91c..1c81fbd424 100755
--- a/lib/app.php
+++ b/lib/app.php
@@ -319,7 +319,7 @@ class OC_App{
$file=OC::$APPSROOT.'/apps/'.$appid.'/appinfo/info.xml';
}
$data=array();
- $content=file_get_contents($file);
+ $content=@file_get_contents($file);
if(!$content){
return;
}
From fd72556fd16260088ec4a4340b6ea5d9e6a126a3 Mon Sep 17 00:00:00 2001
From: Bart Visscher
Date: Tue, 10 Apr 2012 21:15:38 +0200
Subject: [PATCH 130/133] Contacts: Make part.no_contacts.php translatable
---
apps/contacts/templates/part.no_contacts.php | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/apps/contacts/templates/part.no_contacts.php b/apps/contacts/templates/part.no_contacts.php
index d24f7ae980..89b7575293 100644
--- a/apps/contacts/templates/part.no_contacts.php
+++ b/apps/contacts/templates/part.no_contacts.php
@@ -1,8 +1,8 @@
\ No newline at end of file
+
From 3f6e971571825dd66650348ef84b4e57d4cd15b8 Mon Sep 17 00:00:00 2001
From: Bart Visscher
Date: Tue, 10 Apr 2012 21:19:03 +0200
Subject: [PATCH 131/133] Contacts: Don't lowercase categories value when
saving
---
apps/contacts/ajax/saveproperty.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/contacts/ajax/saveproperty.php b/apps/contacts/ajax/saveproperty.php
index 4cef4d1e7a..99d55e7927 100644
--- a/apps/contacts/ajax/saveproperty.php
+++ b/apps/contacts/ajax/saveproperty.php
@@ -96,7 +96,7 @@ switch($element) {
//$value = getOtherValue();
}
break;
- case 'CATEGORIES':
+ //case 'CATEGORIES':
/* multi autocomplete triggers an save with empty value
if (!$value) {
$value = $vcard->getAsString('CATEGORIES');
From 2dfa02a34647010d26efe61598ff800c94b9c0d3 Mon Sep 17 00:00:00 2001
From: Bart Visscher
Date: Tue, 10 Apr 2012 21:53:36 +0200
Subject: [PATCH 132/133] Contacts: fix function names to coding standard
---
apps/contacts/js/contacts.js | 10 +++++-----
apps/contacts/templates/part.contact.php | 2 +-
apps/contacts/templates/part.no_contacts.php | 2 +-
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js
index b2678e8c52..6f34a42a73 100644
--- a/apps/contacts/js/contacts.js
+++ b/apps/contacts/js/contacts.js
@@ -254,12 +254,12 @@ Contacts={
});
}
},
- do_export:function() {
+ doExport:function() {
document.location.href = OC.linkTo('contacts', 'export.php') + '?contactid=' + this.id;
//$.get(OC.linkTo('contacts', 'export.php'),{'contactid':this.id},function(jsondata){
//});
},
- do_import:function(){
+ doImport:function(){
Contacts.UI.notImplemented();
},
add:function(n, fn, aid, isnew){ // add a new contact
@@ -323,7 +323,7 @@ Contacts={
}
});
},
- do_delete:function() {
+ doDelete:function() {
$('#contacts_deletecard').tipsy('hide');
OC.dialogs.confirm(t('contacts', 'Are you sure you want to delete this contact?'), t('contacts', 'Warning'), function(answer) {
if(answer == true) {
@@ -1264,7 +1264,7 @@ Contacts={
});
}
},
- do_import:function(){
+ doImport:function(){
Contacts.UI.notImplemented();
},
submit:function(button, bookid){
@@ -1364,7 +1364,7 @@ $(document).ready(function(){
});
$('#contacts_deletecard').live('click',function(){
- Contacts.UI.Card.do_delete();
+ Contacts.UI.Card.doDelete();
});
$('#contacts li').bind('inview', function(event, isInView, visiblePartX, visiblePartY) {
diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php
index 03d2fad853..ff1f081c4d 100644
--- a/apps/contacts/templates/part.contact.php
+++ b/apps/contacts/templates/part.contact.php
@@ -17,7 +17,7 @@ $id = isset($_['id']) ? $_['id'] : '';
t('Categories'); ?>
-
+
diff --git a/apps/contacts/templates/part.no_contacts.php b/apps/contacts/templates/part.no_contacts.php
index 89b7575293..7024a142ae 100644
--- a/apps/contacts/templates/part.no_contacts.php
+++ b/apps/contacts/templates/part.no_contacts.php
@@ -1,7 +1,7 @@
t('You have no contacts in your list.') ?>
-
+
From 9f547a1b3987838fda8db238a8999c9f474bb542 Mon Sep 17 00:00:00 2001
From: Bart Visscher
Date: Tue, 10 Apr 2012 21:53:51 +0200
Subject: [PATCH 133/133] VCategories: fix function names to coding standard
---
core/js/oc-vcategories.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/core/js/oc-vcategories.js b/core/js/oc-vcategories.js
index 931ea37edb..e3b1abba08 100644
--- a/core/js/oc-vcategories.js
+++ b/core/js/oc-vcategories.js
@@ -19,7 +19,7 @@ OCCategories={
height: 350, minHeight:200, width: 250, minWidth: 200,
buttons: {
'Delete':function() {
- OCCategories.do_delete();
+ OCCategories.doDelete();
},
'Rescan':function() {
OCCategories.rescan();
@@ -53,7 +53,7 @@ OCCategories={
}
});
},
- do_delete:function(){
+ doDelete:function(){
var categories = $('#categorylist').find('input[type="checkbox"]').serialize();
categories += '&app=' + OCCategories.app;
console.log('OCCategories.delete: ' + categories);