diff --git a/app/Console/Commands/Import.php b/app/Console/Commands/Import.php index 9a052fd..44fc3e9 100644 --- a/app/Console/Commands/Import.php +++ b/app/Console/Commands/Import.php @@ -134,20 +134,20 @@ class Import extends Command $po->filename = $file; } - $po->date_taken = strtotime($po->io('exif:DateTime')); - $po->subsectime = $po->io('exif:SubSecTimeOriginal'); + $po->date_taken = strtotime($po->property('exif:DateTime')); + $po->subsectime = $po->property('exif:SubSecTimeOriginal'); - $po->signature = $po->io()->getImageSignature(); + $po->signature = $po->property('signature'); - $po->make = $po->io('exif:Make'); - $po->model = $po->io('exif:Model'); + $po->make = $po->property('exif:Make'); + $po->model = $po->property('exif:Model'); - $po->height = $po->io()->getImageheight(); - $po->width = $po->io()->getImageWidth(); - $po->orientation = $po->io()->getImageOrientation(); + $po->height = $po->property('height'); + $po->width = $po->property('width'); + $po->orientation = $po->property('orientation'); - $po->gps_lat = Photo::latlon(preg_split('/,\s?/',$po->io()->getImageProperty('exif:GPSLatitude')),$po->io()->getImageProperty('exif:GPSLatitudeRef')); - $po->gps_lon = Photo::latlon(preg_split('/,\s?/',$po->io()->getImageProperty('exif:GPSLongitude')),$po->io()->getImageProperty('exif:GPSLongitudeRef')); + $po->gps_lat = Photo::latlon(preg_split('/,\s?/',$po->property('exif:GPSLatitude')),$po->property('exif:GPSLatitudeRef')); + $po->gps_lon = Photo::latlon(preg_split('/,\s?/',$po->property('exif:GPSLongitude')),$po->property('exif:GPSLongitudeRef')); try { $po->thumbnail = exif_thumbnail($po->file_path()); @@ -156,7 +156,7 @@ class Import extends Command } // If this is a duplicate - $x = $po->list_duplicate()->get(); + $x = Photo::whereIN('id',$po->list_duplicate())->get(); if (count($x)) { $skip = FALSE; diff --git a/app/Http/Controllers/PhotoController.php b/app/Http/Controllers/PhotoController.php index 81881b5..241157e 100644 --- a/app/Http/Controllers/PhotoController.php +++ b/app/Http/Controllers/PhotoController.php @@ -7,6 +7,7 @@ use Illuminate\Http\Request; use App\Http\Requests; use App\Model\Photo; +use App\Jobs\PhotoDelete; class PhotoController extends Controller { @@ -33,9 +34,27 @@ class PhotoController extends Controller return redirect()->action('PhotoController@info',[$id]); } + public function deletes() + { + return view('photo.deletereview',['photos'=>Photo::where('remove',1)->paginate(2)]); + } + + public function deletesUpdate(Request $request) + { + foreach ($request->input('photo') as $id) + { + $photo = Photo::findOrFail($id); + + if ($photo->remove AND $request->input('remove.'.$id)) + $this->dispatch((new PhotoDelete($photo))->onQueue('delete')); + } + + return $request->input('pagenext') ? redirect()->action('PhotoController@deletes','?page='.$request->input('pagenext')) : redirect('/'); + } + public function duplicates($id=NULL) { - return view('photo.duplicates', ['photos'=> Photo::notRemove()->where('duplicate',1)->paginate(1)]); + return view('photo.duplicates',['photos'=>is_null($id) ? Photo::notRemove()->where('duplicate',1)->paginate(1) : Photo::where('id',$id)->paginate(1)]); } public function duplicatesUpdate(Request $request) diff --git a/app/Http/routes.php b/app/Http/routes.php index e05b620..ae1a634 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -19,10 +19,12 @@ Route::get('/', function () { Route::auth(); +Route::get('/deletes/{id?}', 'PhotoController@deletes')->where('id', '[0-9]+');; Route::get('/duplicates/{id?}', 'PhotoController@duplicates')->where('id', '[0-9]+');; Route::get('/info/{id}', 'PhotoController@info')->where('id', '[0-9]+');; Route::get('/thumbnail/{id}', 'PhotoController@thumbnail')->where('id', '[0-9]+');; Route::get('/view/{id}', 'PhotoController@view')->where('id', '[0-9]+');; Route::post('/delete/{id}', 'PhotoController@delete')->where('id', '[0-9]+');; -Route::post('/duplicates', 'PhotoController@duplicatesUpdate')->where('id', '[0-9]+');; +Route::post('/duplicates', 'PhotoController@duplicatesUpdate'); +Route::post('/deletes', 'PhotoController@deletesUpdate'); Route::post('/undelete/{id}', 'PhotoController@undelete')->where('id', '[0-9]+');; diff --git a/app/Jobs/PhotoDelete.php b/app/Jobs/PhotoDelete.php new file mode 100644 index 0000000..db57d9c --- /dev/null +++ b/app/Jobs/PhotoDelete.php @@ -0,0 +1,58 @@ +photo = $photo; + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + if (! $this->photo->remove) + { + Log::warning(__METHOD__.' NOT Deleting: '.$this->photo->file_path().', not marked for deletion'); + exit; + } + + // Remove tags; + // @todo + + // Remove People; + // @todo + + // Make sure our parent is writable + if (! is_writable(dirname($this->photo->file_path()))) + Log::warning(__METHOD__.' NOT Deleting: '.$this->photo->file_path().', parent directory not writable'); + + // Perform delete + if (file_exists($this->photo->file_path())) + unlink($this->photo->file_path()); + + Log::info(sprintf('%s: Deleted (%s): %s',__METHOD__,$this->photo->id,$this->photo->file_path())); + $this->photo->delete(); + } +} diff --git a/app/Model/Photo.php b/app/Model/Photo.php index 584b090..40a44d3 100644 --- a/app/Model/Photo.php +++ b/app/Model/Photo.php @@ -57,6 +57,9 @@ class Photo extends Model */ public function file_date($type,$format=FALSE) { + if (! is_readable($this->file_path())) + return NULL; + switch ($type) { case 'a': $t = fileatime($this->file_path()); @@ -93,6 +96,14 @@ class Photo extends Model return trim(chunk_split(sprintf("%0{$depth}s",$this->id),$sep,'/'),'/'); } + /** + * Return the photo size + */ + public function file_size() + { + return (! is_readable($this->file_path())) ? NULL : filesize($this->file_path()); + } + /** * Display the GPS coordinates */ @@ -116,11 +127,6 @@ class Photo extends Model return $imo->getImageBlob(); } - public function info() - { - return $this->io() ? $this->io()->getImageProperties() : []; - } - /** * Return an Imagick object or attribute * @@ -205,6 +211,20 @@ class Photo extends Model return $po->first(); } + /** + * Display the orientation of a photo + */ + public function orientation() { + switch ($this->orientation) { + case 1: return 'None!'; + case 3: return 'Upside Down'; + case 6: return 'Rotate Right'; + case 8: return 'Rotate Left'; + default: + return 'unknown?'; + } + } + /** * Rotate the image * @@ -233,12 +253,25 @@ class Photo extends Model return $po->first(); } - /** - * Return the photo size - */ - public function size() + public function property($property) { - return filesize($this->file_path()); + if (! $this->io()) + return NULL; + + switch ($property) + { + case 'height': return $this->_io->getImageHeight(); break; + case 'orientation': return $this->_io->getImageOrientation(); break; + case 'signature': return $this->_io->getImageSignature(); break; + case 'width': return $this->_io->getImageWidth(); break; + default: + return $this->_io->getImageProperty($property); + } + } + + public function properties() + { + return $this->io() ? $this->_io->getImageProperties() : []; } /** @@ -270,7 +303,7 @@ class Photo extends Model { if (! $this->thumbnail) { - return $this->io()->thumbnailimage(200,200,true,true) ? $this->io()->getImageBlob() : NULL; + return $this->io()->thumbnailimage(200,200,true,true) ? $this->_io->getImageBlob() : NULL; } if (! $rotate OR ! array_key_exists($this->orientation,$this->_rotate) OR ! extension_loaded('imagick')) @@ -301,11 +334,12 @@ class Photo extends Model $po->where('id','!=',$this->id); // Ignore photo's pending removal. - $po->where(function($query) - { - $query->where('remove','!=',TRUE) - ->orWhere('remove','=',NULL); - }); + if (! $includeme) + $po->where(function($query) + { + $query->where('remove','!=',TRUE) + ->orWhere('remove','=',NULL); + }); // Where the signature is the same $po->where(function($query) diff --git a/application/bootstrap.php b/application/bootstrap.php deleted file mode 100644 index 2b6e1b9..0000000 --- a/application/bootstrap.php +++ /dev/null @@ -1,180 +0,0 @@ -" - */ - -/** - * Set the environment status by the domain. - */ -Kohana::$environment = (! isset($_SERVER['SERVER_NAME']) OR in_array($_SERVER['SERVER_NAME'],$SERVER_NAMES)) ? Kohana::PRODUCTION : Kohana::DEVELOPMENT; - -if (isset($_SERVER['KOHANA_ENV'])) -{ - Kohana::$environment = constant('Kohana::'.strtoupper($_SERVER['KOHANA_ENV'])); -} - -/** - * Initialize Kohana, setting the default options. - * - * The following options are available: - * - * - string base_url path, and optionally domain, of your application NULL - * - string index_file name of your index file, usually "index.php" index.php - * - string charset internal character set used for input and output utf-8 - * - string cache_dir set the internal cache directory APPPATH/cache - * - integer cache_life lifetime, in seconds, of items cached 60 - * - boolean errors enable or disable error handling TRUE - * - boolean profile enable or disable internal profiling TRUE - * - boolean caching enable or disable internal caching FALSE - * - boolean expose set the X-Powered-By header FALSE - */ -Kohana::init(array( - 'base_url' => Kohana::$environment === Kohana::PRODUCTION ? '/' : '/', - 'caching' => Kohana::$environment === Kohana::PRODUCTION, - 'profile' => Kohana::$environment !== Kohana::PRODUCTION, - 'index_file' => FALSE, -)); - -/** - * Attach the file write to logging. Multiple writers are supported. - */ -Kohana::$log->attach(new Log_File(APPPATH.'logs')); - -/** - * Attach a file reader to config. Multiple readers are supported. - */ -Kohana::$config->attach(new Config_File); - -/** - * Enable modules. Modules are referenced by a relative or absolute path. - */ -Kohana::modules(array( - 'lnapp' => MODPATH.'lnapp', // lnApp Base Application Tools - // 'oauth' => MODPATH.'oauth', // OAuth Module for External Authentication - // 'auth' => SMDPATH.'auth', // Basic authentication - // 'cache' => SMDPATH.'cache', // Caching with multiple backends - // 'cron' => SMDPATH.'cron', // Kohana Cron Module - // 'codebench' => SMDPATH.'codebench', // Benchmarking tool - 'database' => SMDPATH.'database', // Database access - // 'gchart' => MODPATH.'gchart', // Google Chart Module - // 'highchart' => MODPATH.'highchart', // Highcharts Chart Module - // 'image' => SMDPATH.'image', // Image manipulation - // 'khemail' => SMDPATH.'khemail', // Email module for Kohana 3 PHP Framework - 'minion' => SMDPATH.'minion', // CLI Tasks - 'orm' => SMDPATH.'orm', // Object Relationship Mapping - // 'pagination' => SMDPATH.'pagination', // Kohana Pagination module for Kohana 3 PHP Framework - // 'unittest' => SMDPATH.'unittest', // Unit testing - // 'userguide' => SMDPATH.'userguide', // User guide and API documentation - // 'xml' => SMDPATH.'xml', // XML module for Kohana 3 PHP Framework - )); - -/** - * Enable specalised interfaces - */ -Route::set('sections', '/(/(/(/)))', - array( - 'directory' => '('.implode('|',array_values(URL::$method_directory)).')' - )) - ->defaults(array( - 'action' => 'index', - )); - -// Static file serving (CSS, JS, images) -Route::set('default/media', 'media(/)', array('file' => '.+')) - ->defaults(array( - 'controller' => 'media', - 'action' => 'get', - )); - -/** - * Set the routes. Each route must have a minimum of a name, a URI and a set of - * defaults for the URI. - */ -Route::set('default', '((/(/)))', array('id'=>'[a-zA-Z0-9_.-]+')) - ->defaults(array( - 'controller' => 'welcome', - 'action' => 'index', - )); - -/** - * If APC is enabled, and we need to clear the cache - */ -if (file_exists(APPPATH.'cache/CLEAR_APC_CACHE') AND function_exists('apc_clear_cache') AND (PHP_SAPI !== 'cli')) { - if (! apc_clear_cache() OR ! unlink(APPPATH.'cache/CLEAR_APC_CACHE')) - throw new Kohana_Exception('Unable to clear the APC cache.'); -} - -// If we are a CLI, set our session dir -if (PHP_SAPI === 'cli') - session_save_path('tmp/'); -?> diff --git a/application/classes/Config.php b/application/classes/Config.php deleted file mode 100644 index 989e54b..0000000 --- a/application/classes/Config.php +++ /dev/null @@ -1,50 +0,0 @@ - diff --git a/application/classes/Controller/Photo.php b/application/classes/Controller/Photo.php deleted file mode 100644 index 7fe3973..0000000 --- a/application/classes/Controller/Photo.php +++ /dev/null @@ -1,290 +0,0 @@ -request->post()) - foreach ($this->request->post('process') as $pid) { - $po = ORM::factory('Photo',$pid); - $po->remove = Arr::get($this->request->post('remove'),$pid); - $po->save(); - - // If the photo is not marked as remove, or flagged, dont do it. - if (! $po->loaded() OR $po->flag OR ! $po->remove) - continue; - - if (! is_writable(dirname($po->file_path()))) - $output .= sprintf('Dont have write permissions on %s',dirname($po->file_path())); - - $output .= sprintf('Removing %s (%s)',$po->id,$po->file_path()); - - // Delete it - $po->delete(); - } - - $p = ORM::factory('Photo'); - - // Review a specific photo, or the next one marked remove - if ($x=$this->request->param('id')) - $p->where('id','=',$x); - - else - $p->where('remove','=',TRUE) - ->where_open() - ->where('flag','!=',TRUE) - ->or_where('flag','is',NULL) - ->where_close(); - - $output .= Form::open(sprintf('%s/%s',strtolower($this->request->controller()),$this->request->action())); - - foreach ($p->find_all() as $po) { - $dp = $po->list_duplicate()->find_all(); - - $output .= Form::hidden('process[]',$po->id); - foreach ($dp as $dpo) - $output .= Form::hidden('process[]',$dpo->id); - - $output .= ''; - - foreach (array( - 'ID'=>array('key'=>'id','value'=>HTML::anchor('/photo/details/%VALUE%','%VALUE%')), - 'Thumbnail'=>array('key'=>'id','value'=>HTML::anchor('/photo/view/%VALUE%',HTML::image('photo/thumbnail/%VALUE%'))), - 'Signature'=>array('key'=>'signature'), - 'Date Taken'=>array('key'=>'date_taken()'), - 'File Modified'=>array('key'=>'date_file("m",TRUE)'), - 'File Created'=>array('key'=>'date_file("c",TRUE)'), - 'Filename'=>array('key'=>'file_path(TRUE,FALSE)'), - 'Filesize'=>array('key'=>'file_size()'), - 'Width'=>array('key'=>'width'), - 'Height'=>array('key'=>'height'), - 'Orientation'=>array('key'=>'orientation'), - 'Orientate'=>array('key'=>'rotation()'), - 'Make'=>array('key'=>'make'), - 'Model'=>array('key'=>'model'), - ) as $k=>$v) - $output .= $this->table_duplicate_details($dp,$po,$v['key'],$k,Arr::get($v,'value','%VALUE%')); - - foreach (array( - 'Delete'=>array('key'=>'id','value'=>'remove'), - ) as $k=>$v) - $output .= $this->table_duplicate_checkbox($dp,$po,$v['key'],$k,Arr::get($v,'value','%VALUE%')); - - $output .= '
'; - - break; - } - - $output .= '
'; - $output .= '
'; - $output .= ''; - $output .= ''; - $output .= '
'; - $output .= '
'; - - $output .= Form::close(); - - Block::factory() - ->title('Delete Photo:'.$po->id) - ->title_icon('icon-delete') - ->body($output); - } - - public function action_details() { - $po = ORM::factory('Photo',$this->request->param('id')); - if (! $po->loaded()) - HTTP::redirect('index'); - - Block::factory() - ->title('Details for Photo:'.$po->id) - ->body(Debug::vars($po->info())); - } - - public function action_duplicate() { - $output = ''; - - // Update the current posted photos. - if ($this->request->post()) - foreach ($this->request->post('process') as $pid) { - $po = ORM::factory('Photo',$pid); - - $po->duplicate = Arr::get($this->request->post('duplicate'),$pid); - $po->remove = Arr::get($this->request->post('remove'),$pid); - $po->flag = Arr::get($this->request->post('flag'),$pid); - - if ($po->changed()) - $output .= HTML::anchor(URL::link('','photo/duplicate/'.$po->id),$po->id).' updated.
'; - - $po->save(); - - } - - $p = ORM::factory('Photo'); - - // Review a specific photo, or the next one marked duplicate - if ($x=$this->request->param('id')) - $p->where('id','=',$x); - - else - $p->where('duplicate','=',TRUE) - ->where_open() - ->where('remove','!=',TRUE) - ->or_where('remove','is',NULL) - ->where_close(); - - $output .= Form::open(sprintf('%s/%s',strtolower($this->request->controller()),$this->request->action())); - - foreach ($p->find_all() as $po) { - $dp = $po->list_duplicate()->find_all(); - - // Check that there are still duplicates - if ($dp->count() == 0) { - $po->duplicate = NULL; - $po->save(); - continue; - } - - $output .= Form::hidden('process[]',$po->id); - foreach ($dp as $dpo) - $output .= Form::hidden('process[]',$dpo->id); - - $output .= ''; - - foreach (array( - 'ID'=>array('key'=>'id','value'=>HTML::anchor('/photo/details/%VALUE%','%VALUE%')), - 'Thumbnail'=>array('key'=>'id','value'=>HTML::anchor('/photo/view/%VALUE%',HTML::image('photo/thumbnail/%VALUE%'))), - 'ThumbSig'=>array('key'=>'thumbnail_sig()'), - 'Signature'=>array('key'=>'signature'), - 'Date Taken'=>array('key'=>'date_taken()'), - 'File Modified'=>array('key'=>'date_file("m",TRUE)'), - 'File Created'=>array('key'=>'date_file("c",TRUE)'), - 'Filename'=>array('key'=>'file_path(TRUE,FALSE)'), - 'Filesize'=>array('key'=>'file_size()'), - 'Width'=>array('key'=>'width'), - 'Height'=>array('key'=>'height'), - 'Orientation'=>array('key'=>'orientation'), - 'Orientate'=>array('key'=>'rotation()'), - 'Make'=>array('key'=>'make'), - 'Model'=>array('key'=>'model'), - 'Exif Diff'=>array('key'=>"propertydiff({$po->id})"), - ) as $k=>$v) - $output .= $this->table_duplicate_details($dp,$po,$v['key'],$k,Arr::get($v,'value','%VALUE%')); - - foreach (array( - 'Flag'=>array('key'=>'id','value'=>'flag'), - 'Duplicate'=>array('key'=>'id','value'=>'duplicate'), - 'Delete'=>array('key'=>'id','value'=>'remove'), - ) as $k=>$v) - $output .= $this->table_duplicate_checkbox($dp,$po,$v['key'],$k,Arr::get($v,'value','%VALUE%')); - - $output .= '
'; - - break; - } - - $output .= '
'; - $output .= '
'; - $output .= ''; - $output .= ''; - $output .= '
'; - $output .= '
'; - - $output .= Form::close(); - - Block::factory() - ->title('Duplicate Photo:'.$po->id) - ->title_icon('icon-edit') - ->body($output); - } - - public function action_thumbnail() { - // Get the file path from the request - $po = ORM::factory('Photo',$this->request->param('id')); - - return $this->image($po->thumbnail(),$po->date_taken,$po->type(TRUE)); - } - - public function action_view() { - $po = ORM::factory('Photo',$this->request->param('id')); - - return $this->image($po->image(),$po->date_taken,$po->type(TRUE)); - } - - private function image($content,$modified,$type) { - // Send the file content as the response - if ($content) - $this->response->body($content); - // Return a 404 status - else - $this->response->status(404); - - // Generate and check the ETag for this file - if (Kohana::$environment < Kohana::TESTING OR Kohana::$config->load('debug')->etag) - $this->check_cache(sha1($this->response->body())); - - // Set the proper headers to allow caching - $this->response->headers('Content-Type',$type); - $this->response->headers('Content-Length',(string)$this->response->content_length()); - $this->response->headers('Last-Modified',date('r',$modified)); - $this->auto_render = FALSE; - } - - private function table_duplicate_checkbox(Database_MySQL_Result $dp,Model_Photo $po,$param,$title,$condition) { - $output = ''; - - $output .= sprintf('%s',$title); - - $output .= ''.Form::checkbox($condition.'['.$po->{$param}.']',TRUE,$po->{$condition} ? TRUE : FALSE).''; - - foreach ($dp as $dpo) - $output .= ''.Form::checkbox($condition.'['.$dpo->{$param}.']',TRUE,$dpo->{$condition} ? TRUE : FALSE).''; - - $output .= ''; - - return $output; - } - - private function evaluate(Model $o,$param) { - $result = NULL; - - if (preg_match('/\(/',$param) OR preg_match('/-\>/',$param)) - eval("\$result = \$o->$param;"); - else - $result = $o->display($param); - - return $result; - } - - private function table_duplicate_details(Database_MySQL_Result $dp,Model_Photo $po,$param,$title='',$content='') { - $output = ''; - - $v = $this->evaluate($po,$param); - - $output .= sprintf('%s',$title); - $output .= sprintf('%s',$content ? str_replace('%VALUE%',$v,$content) : $v); - - foreach ($dp as $dpo) { - $d = $this->evaluate($dpo,$param); - - $output .= sprintf('%s',($d==$v ? 'success' : 'warning'),$content ? str_replace('%VALUE%',$d,$content) : $d); - } - - $output .= ''; - - return $output; - } -} -?> diff --git a/application/classes/Cookie.php b/application/classes/Cookie.php deleted file mode 100644 index b71a771..0000000 --- a/application/classes/Cookie.php +++ /dev/null @@ -1,15 +0,0 @@ - diff --git a/application/classes/File.php b/application/classes/File.php deleted file mode 100644 index 1d329fb..0000000 --- a/application/classes/File.php +++ /dev/null @@ -1,24 +0,0 @@ - diff --git a/application/classes/Model/Photo.php b/application/classes/Model/Photo.php deleted file mode 100644 index 2aa8b61..0000000 --- a/application/classes/Model/Photo.php +++ /dev/null @@ -1,277 +0,0 @@ -array('through'=>'album_photo'), - 'people'=>array('through'=>'photo_people','far_key'=>'people_id'), - 'tags'=>array('through'=>'photo_tag','far_key'=>'tag_id'), - 'photo_tag'=>array('far_key'=>'id'), - 'photo_people'=>array('far_key'=>'id'), - ); - - /** - * Filters used to format the display of values into friendlier values - */ - protected $_display_filters = array( - 'date_orig'=>array( - array('Site::Datetime',array(':value')), - ), - 'date_taken'=>array( - array('Site::Datetime',array(':value')), - ), - 'signature'=>array( - array('Model_Photo::Signaturetrim',array(':value')), - ), - ); - - public function date_file($type,$format=FALSE) { - switch ($type) { - case 'a': $t = fileatime($this->file_path()); - break; - case 'c': $t = filectime($this->file_path()); - break; - case 'm': $t = filemtime($this->file_path()); - break; - } - - return $format ? Site::Datetime($t) : $t; - } - - public function date_taken() { - return $this->display('date_taken').($this->subsectime ? '.'.$this->subsectime : ''); - } - - public function file_path($short=FALSE,$new=FALSE) { - $file = $this->filename; - - if ($new) - $file = sprintf('%s.%s',((is_null($this->date_taken) OR ! $this->date_taken) - ? sprintf('UNKNOWN/%07s',$this->file_path_id()) - : sprintf('%s_%03s',date('Y/m/d-His',$this->date_taken),$this->subsectime).($this->subsectime ? '' : sprintf('-%05s',$this->id))),$this->type()); - - return (($short OR preg_match('/^\//',$file)) ? '' : $this->_path.DIRECTORY_SEPARATOR).$file; - } - - public function file_path_id($sep=3,$depth=9) { - return trim(chunk_split(sprintf("%0{$depth}s",$this->id),$sep,'/'),'/'); - } - - public function file_path_short($path) { - return preg_replace(":^{$this->_path}".DIRECTORY_SEPARATOR.":",'',$path); - } - - public function delete() { - if (unlink($this->file_path())) { - // Remove any tags - foreach ($this->photo_tag->find_all() as $o) - $o->delete(); - - // Remove any people - foreach ($this->photo_people->find_all() as $o) - $o->delete(); - - return parent::delete(); - } - - // If unlink failed... - return FALSE; - } - - public function file_size() { - return filesize($this->file_path()); - } - - public function gps(array $coordinate,$hemisphere) { - if (! $coordinate OR ! $hemisphere) - return NULL; - - for ($i=0; $i<3; $i++) { - $part = explode('/', $coordinate[$i]); - - if (count($part) == 1) - $coordinate[$i] = $part[0]; - - elseif (count($part) == 2) - $coordinate[$i] = floatval($part[0])/floatval($part[1]); - - else - $coordinate[$i] = 0; - } - - list($degrees, $minutes, $seconds) = $coordinate; - - $sign = ($hemisphere == 'W' || $hemisphere == 'S') ? -1 : 1; - - return round($sign*($degrees+$minutes/60+$seconds/3600),$degrees > 100 ? 3 : 4); - } - - public function image() { - $imo = $this->io(); - - if (array_key_exists('exif',$imo->getImageProfiles())) - $imo->removeImageProfile('exif'); - - $this->rotate($imo); - - return $imo->getImageBlob(); - } - - public function info() { - $imo = $this->io(); - - return $imo->getImageProperties(); - } - - public function io($attr=NULL) { - if (is_nulL($this->_io)) - $this->_io = new Imagick($this->file_path()); - - return is_null($attr) ? $this->_io : $this->_io->getImageProperty($attr); - } - - public function move($path='') { - if (! $path) - $path = $this->file_path(FALSE,TRUE); - - // Check if there is already a phoot here - and if it is pending delete. - $po = ORM::factory('Photo',array('filename'=>$this->file_path_short($path))); - - // @todo Move any tags if we are replacing an existing photo. - if ($po->loaded() AND (! $po->remove OR ($po->remove AND ! $po->delete()))) - return FALSE; - - unset($po); - - // If the file already exists, or we cant create the dir structure, we'll ignore the move - if (file_exists($path) OR ! File::ParentDirExist(dirname($path),TRUE)) - return FALSE; - - if (rename($this->file_path(),$path)) { - // Convert the path to a relative one. - $this->filename = $this->file_path_short($path); - - // If the DB update failed, move it back. - if (! $this->save() AND ! rename($path,$this->file_path())) - throw new Kohana_Exception('Error: Unable to move file, ID: :id, OLD: :oldname, NEW: :newname', - array(':id'=>$this->id,':oldname'=>$this->file_path(),':newname'=>$path)); - - chmod($this->file_path(),0444); - - return TRUE; - } - } - - public function propertydiff($id) { - if ($id == $this->id) - return; - - $po = ORM::factory($this->_object_name,$id); - if (! $po->loaded()) - return; - - $result = array_diff_assoc($this->info(),$po->info()); - - return join('|',array_keys($result)); - } - -/* - private function rotate(Imagick $imo) { - switch ($this->orientation) { - case 3: $imo->rotateImage(new ImagickPixel('none'),180); - break; - case 6: $imo->rotateImage(new ImagickPixel('none'),90); - break; - case 8: $imo->rotateImage(new ImagickPixel('none'),-90); - break; - } - } -*/ - - public function rotation() { - switch ($this->orientation) { - case 1: return 'None!'; - case 3: return 'Upside Down'; - case 6: return 'Rotate Right'; - case 8: return 'Rotate Left'; - default: - return 'unknown?'; - } - } - - public static function SignatureTrim($signature,$chars=6) { - return sprintf('%s...%s',substr($signature,0,$chars),substr($signature,-1*$chars)); - } - -/* - public function thumbnail($rotate=TRUE) { - if (! $this->thumbnail) - return NULL; - - $imo = new Imagick(); - - $imo->readImageBlob($this->thumbnail); - - if ($rotate) - $this->rotate($imo); - - return $imo->getImageBlob(); - } -*/ - - public function thumbnail_sig() { - return md5($this->thumbnail()).':'.strlen($this->thumbnail()); - } - - public function type($mime=FALSE) { - return strtolower($mime ? File::mime_by_ext(pathinfo($this->filename,PATHINFO_EXTENSION)) : pathinfo($this->filename,PATHINFO_EXTENSION)); - } - - public function list_duplicate() { - $po = ORM::factory($this->_object_name); - - if ($this->loaded()) - $po->where('id','!=',$this->id); - - // Ignore photo's pending removal. - $po->where_open(); - $po->where('remove','!=',TRUE); - $po->or_where('remove','is',NULL); - $po->where_close(); - - // Where the signature is the same - $po->where_open(); - $po->where('signature','=',$this->signature); - - // Or they have the same time taken with the same camera - if ($this->date_taken AND ($this->model OR $this->make)) { - $po->or_where_open(); - $po->where('date_taken','=',$this->date_taken); - $po->where('subsectime','=',$this->subsectime); - - if (! is_null($this->model)) - $po->and_where('model','=',$this->model); - - if (! is_null($this->make)) - $po->and_where('make','=',$this->make); - - $po->where_close(); - } - - $po->where_close(); - - return $po; - } -} -?> diff --git a/application/config/config.php b/application/config/config.php deleted file mode 100644 index bcd856e..0000000 --- a/application/config/config.php +++ /dev/null @@ -1,6 +0,0 @@ - 'Photo', -); diff --git a/application/config/database.php b/application/config/database.php deleted file mode 100644 index c57afc1..0000000 --- a/application/config/database.php +++ /dev/null @@ -1,31 +0,0 @@ - array - ( - 'type' => 'MySQL', - 'connection' => array( - /** - * The following options are available for MySQL: - * - * string hostname server hostname, or socket - * string database database name - * string username database username - * string password database password - * boolean persistent use persistent connections? - * array variables system variables as "key => value" pairs - * - * Ports and sockets may be appended to the hostname. - */ - 'hostname' => 'mysql.leenooks.vpn', - 'database' => 'weblnphoto', - 'username' => 'ln-photo', - 'password' => 'Ph0T0!', - 'persistent' => TRUE, - ), - 'table_prefix' => '', - 'charset' => 'utf8', - 'caching' => FALSE, - ), -); diff --git a/application/config/mainnav.php b/application/config/mainnav.php deleted file mode 100644 index f453c95..0000000 --- a/application/config/mainnav.php +++ /dev/null @@ -1,16 +0,0 @@ - array('icon'=>'icon-edit','url'=>URL::site('photo/duplicate')), -); -?> diff --git a/includes/kohana b/includes/kohana deleted file mode 160000 index 5ffa395..0000000 --- a/includes/kohana +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5ffa395307a3b26f901dde5f3064c48a15979f0d diff --git a/modules/lnapp b/modules/lnapp deleted file mode 160000 index 9a41635..0000000 --- a/modules/lnapp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9a41635025206453cf05a092b5f3b981d5635d7a diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index f83ab19..91b5987 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -47,6 +47,7 @@