Added delete and removed Kohana
This commit is contained in:
parent
e1c5b1e413
commit
3adfcd8d8f
@ -134,20 +134,20 @@ class Import extends Command
|
|||||||
$po->filename = $file;
|
$po->filename = $file;
|
||||||
}
|
}
|
||||||
|
|
||||||
$po->date_taken = strtotime($po->io('exif:DateTime'));
|
$po->date_taken = strtotime($po->property('exif:DateTime'));
|
||||||
$po->subsectime = $po->io('exif:SubSecTimeOriginal');
|
$po->subsectime = $po->property('exif:SubSecTimeOriginal');
|
||||||
|
|
||||||
$po->signature = $po->io()->getImageSignature();
|
$po->signature = $po->property('signature');
|
||||||
|
|
||||||
$po->make = $po->io('exif:Make');
|
$po->make = $po->property('exif:Make');
|
||||||
$po->model = $po->io('exif:Model');
|
$po->model = $po->property('exif:Model');
|
||||||
|
|
||||||
$po->height = $po->io()->getImageheight();
|
$po->height = $po->property('height');
|
||||||
$po->width = $po->io()->getImageWidth();
|
$po->width = $po->property('width');
|
||||||
$po->orientation = $po->io()->getImageOrientation();
|
$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_lat = Photo::latlon(preg_split('/,\s?/',$po->property('exif:GPSLatitude')),$po->property('exif:GPSLatitudeRef'));
|
||||||
$po->gps_lon = Photo::latlon(preg_split('/,\s?/',$po->io()->getImageProperty('exif:GPSLongitude')),$po->io()->getImageProperty('exif:GPSLongitudeRef'));
|
$po->gps_lon = Photo::latlon(preg_split('/,\s?/',$po->property('exif:GPSLongitude')),$po->property('exif:GPSLongitudeRef'));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$po->thumbnail = exif_thumbnail($po->file_path());
|
$po->thumbnail = exif_thumbnail($po->file_path());
|
||||||
@ -156,7 +156,7 @@ class Import extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If this is a duplicate
|
// If this is a duplicate
|
||||||
$x = $po->list_duplicate()->get();
|
$x = Photo::whereIN('id',$po->list_duplicate())->get();
|
||||||
if (count($x)) {
|
if (count($x)) {
|
||||||
$skip = FALSE;
|
$skip = FALSE;
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ use Illuminate\Http\Request;
|
|||||||
|
|
||||||
use App\Http\Requests;
|
use App\Http\Requests;
|
||||||
use App\Model\Photo;
|
use App\Model\Photo;
|
||||||
|
use App\Jobs\PhotoDelete;
|
||||||
|
|
||||||
class PhotoController extends Controller
|
class PhotoController extends Controller
|
||||||
{
|
{
|
||||||
@ -33,9 +34,27 @@ class PhotoController extends Controller
|
|||||||
return redirect()->action('PhotoController@info',[$id]);
|
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)
|
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)
|
public function duplicatesUpdate(Request $request)
|
||||||
|
@ -19,10 +19,12 @@ Route::get('/', function () {
|
|||||||
|
|
||||||
Route::auth();
|
Route::auth();
|
||||||
|
|
||||||
|
Route::get('/deletes/{id?}', 'PhotoController@deletes')->where('id', '[0-9]+');;
|
||||||
Route::get('/duplicates/{id?}', 'PhotoController@duplicates')->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('/info/{id}', 'PhotoController@info')->where('id', '[0-9]+');;
|
||||||
Route::get('/thumbnail/{id}', 'PhotoController@thumbnail')->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::get('/view/{id}', 'PhotoController@view')->where('id', '[0-9]+');;
|
||||||
Route::post('/delete/{id}', 'PhotoController@delete')->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]+');;
|
Route::post('/undelete/{id}', 'PhotoController@undelete')->where('id', '[0-9]+');;
|
||||||
|
58
app/Jobs/PhotoDelete.php
Normal file
58
app/Jobs/PhotoDelete.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use Log;
|
||||||
|
use App\Jobs\Job;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use App\Model\Photo;
|
||||||
|
|
||||||
|
class PhotoDelete extends Job implements ShouldQueue
|
||||||
|
{
|
||||||
|
use InteractsWithQueue, SerializesModels;
|
||||||
|
|
||||||
|
private $photo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Photo $photo)
|
||||||
|
{
|
||||||
|
$this->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();
|
||||||
|
}
|
||||||
|
}
|
@ -57,6 +57,9 @@ class Photo extends Model
|
|||||||
*/
|
*/
|
||||||
public function file_date($type,$format=FALSE)
|
public function file_date($type,$format=FALSE)
|
||||||
{
|
{
|
||||||
|
if (! is_readable($this->file_path()))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
switch ($type)
|
switch ($type)
|
||||||
{
|
{
|
||||||
case 'a': $t = fileatime($this->file_path());
|
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 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
|
* Display the GPS coordinates
|
||||||
*/
|
*/
|
||||||
@ -116,11 +127,6 @@ class Photo extends Model
|
|||||||
return $imo->getImageBlob();
|
return $imo->getImageBlob();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function info()
|
|
||||||
{
|
|
||||||
return $this->io() ? $this->io()->getImageProperties() : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an Imagick object or attribute
|
* Return an Imagick object or attribute
|
||||||
*
|
*
|
||||||
@ -205,6 +211,20 @@ class Photo extends Model
|
|||||||
return $po->first();
|
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
|
* Rotate the image
|
||||||
*
|
*
|
||||||
@ -233,12 +253,25 @@ class Photo extends Model
|
|||||||
return $po->first();
|
return $po->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function property($property)
|
||||||
* Return the photo size
|
|
||||||
*/
|
|
||||||
public function size()
|
|
||||||
{
|
{
|
||||||
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)
|
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'))
|
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);
|
$po->where('id','!=',$this->id);
|
||||||
|
|
||||||
// Ignore photo's pending removal.
|
// Ignore photo's pending removal.
|
||||||
$po->where(function($query)
|
if (! $includeme)
|
||||||
{
|
$po->where(function($query)
|
||||||
$query->where('remove','!=',TRUE)
|
{
|
||||||
->orWhere('remove','=',NULL);
|
$query->where('remove','!=',TRUE)
|
||||||
});
|
->orWhere('remove','=',NULL);
|
||||||
|
});
|
||||||
|
|
||||||
// Where the signature is the same
|
// Where the signature is the same
|
||||||
$po->where(function($query)
|
$po->where(function($query)
|
||||||
|
@ -1,180 +0,0 @@
|
|||||||
<?php defined('SYSPATH') or die('No direct script access.');
|
|
||||||
|
|
||||||
// -- Environment setup --------------------------------------------------------
|
|
||||||
$SERVER_NAMES = array(
|
|
||||||
'xphoto.leenooks.vpn',
|
|
||||||
);
|
|
||||||
|
|
||||||
// Load the core Kohana class
|
|
||||||
require SYSPATH.'classes/Kohana/Core'.EXT;
|
|
||||||
|
|
||||||
if (is_file(APPPATH.'classes/Kohana'.EXT))
|
|
||||||
{
|
|
||||||
// Application extends the core
|
|
||||||
require APPPATH.'classes/Kohana'.EXT;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Load empty core extension
|
|
||||||
require SYSPATH.'classes/Kohana'.EXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the default time zone.
|
|
||||||
*
|
|
||||||
* @link http://kohanaframework.org/guide/using.configuration
|
|
||||||
* @link http://www.php.net/manual/timezones
|
|
||||||
*/
|
|
||||||
date_default_timezone_set('Australia/Melbourne');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the default locale.
|
|
||||||
*
|
|
||||||
* @link http://kohanaframework.org/guide/using.configuration
|
|
||||||
* @link http://www.php.net/manual/function.setlocale
|
|
||||||
*/
|
|
||||||
setlocale(LC_ALL, 'en_US.utf-8');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable the Kohana auto-loader.
|
|
||||||
*
|
|
||||||
* @link http://kohanaframework.org/guide/using.autoloading
|
|
||||||
* @link http://www.php.net/manual/function.spl-autoload-register
|
|
||||||
*/
|
|
||||||
spl_autoload_register(array('Kohana', 'auto_load'));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optionally, you can enable a compatibility auto-loader for use with
|
|
||||||
* older modules that have not been updated for PSR-0.
|
|
||||||
*
|
|
||||||
* It is recommended to not enable this unless absolutely necessary.
|
|
||||||
*/
|
|
||||||
//spl_autoload_register(array('Kohana', 'auto_load_lowercase'));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable the Kohana auto-loader for unserialization.
|
|
||||||
*
|
|
||||||
* @link http://www.php.net/manual/function.spl-autoload-call
|
|
||||||
* @link http://www.php.net/manual/var.configuration#unserialize-callback-func
|
|
||||||
*/
|
|
||||||
ini_set('unserialize_callback_func', 'spl_autoload_call');
|
|
||||||
|
|
||||||
// -- Configuration and initialization -----------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the default language
|
|
||||||
*/
|
|
||||||
I18n::lang('en-us');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set Kohana::$environment if a 'KOHANA_ENV' environment variable has been supplied.
|
|
||||||
*
|
|
||||||
* Note: If you supply an invalid environment name, a PHP warning will be thrown
|
|
||||||
* saying "Couldn't find constant Kohana::<INVALID_ENV_NAME>"
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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', '<directory>/<controller>(/<action>(/<id>(/<sid>)))',
|
|
||||||
array(
|
|
||||||
'directory' => '('.implode('|',array_values(URL::$method_directory)).')'
|
|
||||||
))
|
|
||||||
->defaults(array(
|
|
||||||
'action' => 'index',
|
|
||||||
));
|
|
||||||
|
|
||||||
// Static file serving (CSS, JS, images)
|
|
||||||
Route::set('default/media', 'media(/<file>)', 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', '(<controller>(/<action>(/<id>)))', 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/');
|
|
||||||
?>
|
|
@ -1,50 +0,0 @@
|
|||||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class extends the core Kohana class by adding some core application
|
|
||||||
* specific functions, and configuration.
|
|
||||||
*
|
|
||||||
* @package Photo
|
|
||||||
* @category Helpers
|
|
||||||
* @author Deon George
|
|
||||||
* @copyright (c) 2014 Deon George
|
|
||||||
* @license http://dev.leenooks.net/license.html
|
|
||||||
*/
|
|
||||||
class Config extends Kohana_Config {
|
|
||||||
/**
|
|
||||||
* Some early initialisation
|
|
||||||
*
|
|
||||||
* At this point, KH hasnt been fully initialised either, so we cant rely on
|
|
||||||
* too many KH functions yet.
|
|
||||||
*
|
|
||||||
* NOTE: Kohana doesnt provide a parent construct for the Kohana_Config class.
|
|
||||||
*/
|
|
||||||
public function __construct() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the singleton instance of Config.
|
|
||||||
*
|
|
||||||
* $config = Config::instance();
|
|
||||||
*
|
|
||||||
* @return Config
|
|
||||||
* @compat Restore KH 3.1 functionality
|
|
||||||
*/
|
|
||||||
public static function instance() {
|
|
||||||
if (Config::$_instance === NULL)
|
|
||||||
// Create a new instance
|
|
||||||
Config::$_instance = new Config;
|
|
||||||
|
|
||||||
return Config::$_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function Copywrite() {
|
|
||||||
return '(c) 2014 Deon George';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function version() {
|
|
||||||
// @todo Work out our versioning
|
|
||||||
return 'TBA';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
@ -1,290 +0,0 @@
|
|||||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark all accounts that have no outstanding invoices and active services as disabled.
|
|
||||||
*
|
|
||||||
* @package Photo
|
|
||||||
* @category Controllers
|
|
||||||
* @author Deon George
|
|
||||||
* @copyright (c) 2014 Deon George
|
|
||||||
* @license http://dev.leenooks.net/license.html
|
|
||||||
*/
|
|
||||||
class Controller_Photo extends Controller_TemplateDefault {
|
|
||||||
public function action_index() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function action_delete() {
|
|
||||||
$output = '';
|
|
||||||
|
|
||||||
// Update the current posted photos.
|
|
||||||
if ($this->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 .= '<table class="table table-striped table-condensed table-hover">';
|
|
||||||
|
|
||||||
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 .= '</table>';
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$output .= '<div class="row">';
|
|
||||||
$output .= '<div class="col-md-offset-2">';
|
|
||||||
$output .= '<button type="submit" class="btn btn-primary">Save changes</button>';
|
|
||||||
$output .= '<button type="button" class="btn">Cancel</button>';
|
|
||||||
$output .= '</div>';
|
|
||||||
$output .= '</div>';
|
|
||||||
|
|
||||||
$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.<br/>';
|
|
||||||
|
|
||||||
$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 .= '<table class="table table-striped table-condensed table-hover">';
|
|
||||||
|
|
||||||
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 .= '</table>';
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$output .= '<div class="row">';
|
|
||||||
$output .= '<div class="col-md-offset-2">';
|
|
||||||
$output .= '<button type="submit" class="btn btn-primary">Save changes</button>';
|
|
||||||
$output .= '<button type="button" class="btn">Cancel</button>';
|
|
||||||
$output .= '</div>';
|
|
||||||
$output .= '</div>';
|
|
||||||
|
|
||||||
$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 = '<tr>';
|
|
||||||
|
|
||||||
$output .= sprintf('<th>%s</th>',$title);
|
|
||||||
|
|
||||||
$output .= '<td>'.Form::checkbox($condition.'['.$po->{$param}.']',TRUE,$po->{$condition} ? TRUE : FALSE).'</td>';
|
|
||||||
|
|
||||||
foreach ($dp as $dpo)
|
|
||||||
$output .= '<td>'.Form::checkbox($condition.'['.$dpo->{$param}.']',TRUE,$dpo->{$condition} ? TRUE : FALSE).'</td>';
|
|
||||||
|
|
||||||
$output .= '</tr>';
|
|
||||||
|
|
||||||
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 = '<tr>';
|
|
||||||
|
|
||||||
$v = $this->evaluate($po,$param);
|
|
||||||
|
|
||||||
$output .= sprintf('<th>%s</th>',$title);
|
|
||||||
$output .= sprintf('<td>%s</td>',$content ? str_replace('%VALUE%',$v,$content) : $v);
|
|
||||||
|
|
||||||
foreach ($dp as $dpo) {
|
|
||||||
$d = $this->evaluate($dpo,$param);
|
|
||||||
|
|
||||||
$output .= sprintf('<td class="%s">%s</td>',($d==$v ? 'success' : 'warning'),$content ? str_replace('%VALUE%',$d,$content) : $d);
|
|
||||||
}
|
|
||||||
|
|
||||||
$output .= '</tr>';
|
|
||||||
|
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
@ -1,15 +0,0 @@
|
|||||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class overrides Kohana's Cookie
|
|
||||||
*
|
|
||||||
* @package Photo
|
|
||||||
* @category Modifications
|
|
||||||
* @author Deon George
|
|
||||||
* @copyright (c) 2014 Deon George
|
|
||||||
* @license http://dev.leenooks.net/license.html
|
|
||||||
*/
|
|
||||||
class Cookie extends Kohana_Cookie {
|
|
||||||
public static $salt = 'Photo';
|
|
||||||
}
|
|
||||||
?>
|
|
@ -1,24 +0,0 @@
|
|||||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class extends the core Kohana class by adding some core application
|
|
||||||
* specific functions, and configuration.
|
|
||||||
*
|
|
||||||
* @package Photo
|
|
||||||
* @category Helpers
|
|
||||||
* @author Deon George
|
|
||||||
* @copyright (c) 2014 Deon George
|
|
||||||
* @license http://dev.leenooks.net/license.html
|
|
||||||
*/
|
|
||||||
class File extends Kohana_File {
|
|
||||||
public static function ParentDirExist($path,$create=FALSE) {
|
|
||||||
$isDir = is_dir($path);
|
|
||||||
|
|
||||||
if ($isDir OR ! $create)
|
|
||||||
return $isDir;
|
|
||||||
|
|
||||||
if (File::ParentDirExist(dirname($path),$create))
|
|
||||||
return mkdir($path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
@ -1,277 +0,0 @@
|
|||||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class supports Photos.
|
|
||||||
*
|
|
||||||
* @package Photo
|
|
||||||
* @category Models
|
|
||||||
* @author Deon George
|
|
||||||
* @copyright (c) 2014 Deon George
|
|
||||||
* @license http://dev.leenooks.net/license.html
|
|
||||||
*/
|
|
||||||
class Model_Photo extends ORM {
|
|
||||||
private $_path = '/mnt/net/qnap/Multimedia/Photos';
|
|
||||||
private $_io = NULL;
|
|
||||||
|
|
||||||
protected $_has_many = array(
|
|
||||||
'album'=>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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
@ -1,6 +0,0 @@
|
|||||||
<?php defined('SYSPATH') OR die('No direct access allowed.');
|
|
||||||
|
|
||||||
return array
|
|
||||||
(
|
|
||||||
'appname' => 'Photo',
|
|
||||||
);
|
|
@ -1,31 +0,0 @@
|
|||||||
<?php defined('SYSPATH') OR die('No direct access allowed.');
|
|
||||||
|
|
||||||
return array
|
|
||||||
(
|
|
||||||
'default' => 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,
|
|
||||||
),
|
|
||||||
);
|
|
@ -1,16 +0,0 @@
|
|||||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Photo system default configurable items.
|
|
||||||
*
|
|
||||||
* @package Photo
|
|
||||||
* @category Configuration
|
|
||||||
* @author Deon George
|
|
||||||
* @copyright (c) 2010-2013 Deon George
|
|
||||||
* @license http://dev.leenooks.net/license.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
return array(
|
|
||||||
'Duplicates' => array('icon'=>'icon-edit','url'=>URL::site('photo/duplicate')),
|
|
||||||
);
|
|
||||||
?>
|
|
@ -1 +0,0 @@
|
|||||||
Subproject commit 5ffa395307a3b26f901dde5f3064c48a15979f0d
|
|
@ -1 +0,0 @@
|
|||||||
Subproject commit 9a41635025206453cf05a092b5f3b981d5635d7a
|
|
@ -47,6 +47,7 @@
|
|||||||
<div class="collapse navbar-collapse" id="app-navbar-collapse">
|
<div class="collapse navbar-collapse" id="app-navbar-collapse">
|
||||||
<!-- Left Side Of Navbar -->
|
<!-- Left Side Of Navbar -->
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
|
<li><a href="{{ url('/deletes') }}">Deletes</a></li>
|
||||||
<li><a href="{{ url('/duplicates') }}">Duplicates</a></li>
|
<li><a href="{{ url('/duplicates') }}">Duplicates</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
74
resources/views/photo/deletereview.blade.php
Normal file
74
resources/views/photo/deletereview.blade.php
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
@extends('layouts.app')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<?php $data = [
|
||||||
|
'ID'=>'id',
|
||||||
|
'Thumbnail'=>'thumbnail',
|
||||||
|
'Signature'=>'signature',
|
||||||
|
'Date Taken'=>'datetaken',
|
||||||
|
'File Created'=>'created',
|
||||||
|
'File Modified'=>'modified',
|
||||||
|
'Filename'=>'filepath',
|
||||||
|
'Filesize'=>'filesize',
|
||||||
|
'Width'=>'width',
|
||||||
|
'Height'=>'height',
|
||||||
|
'Orientation'=>'orientation',
|
||||||
|
'Make'=>'make',
|
||||||
|
'Model'=>'model',
|
||||||
|
'Duplicates'=>'duplicates',
|
||||||
|
'Is Duplicate'=>'duplicate',
|
||||||
|
'Flagged'=>'flag',
|
||||||
|
'Delete'=>'remove',
|
||||||
|
];?>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-11 col-md-offset-1">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
Permanently Delete Photos
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center">{{ $photos->links() }}</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form action="{{ url('/deletes') }}" method="POST">
|
||||||
|
<table class="table table-striped table-condensed table-hover">
|
||||||
|
@foreach ($data as $k=>$v)
|
||||||
|
<tr>
|
||||||
|
<th>{{ $k }}</th>
|
||||||
|
@foreach ($photos as $o)
|
||||||
|
<?php
|
||||||
|
switch ($v) :
|
||||||
|
case 'id': $x=$o->id; $y=sprintf('<input type="hidden" name="photo[]" value="%s"><a href="%s">%s</a>',$o->id,url('/info/'.$o->id),$o->id); break;
|
||||||
|
case 'thumbnail': $x=md5($o->thumbnail); $y=sprintf('<a href="%s"><img src="%s" width="200px"></a>',url('/view/'.$o->id),url('/thumbnail/'.$o->id)); break;
|
||||||
|
case 'signature': $x=$y=$o->signature(TRUE); break;
|
||||||
|
case 'datetaken': $x=$y=$o->date_taken(); break;
|
||||||
|
case 'created': $x=$y=$o->file_date('c',TRUE); break;
|
||||||
|
case 'modified': $x=$y=$o->file_date('m',TRUE); break;
|
||||||
|
case 'filepath': $x=$y=$o->file_path(TRUE); break;
|
||||||
|
case 'filesize': $x=$y=$o->file_size(); break;
|
||||||
|
case 'width':
|
||||||
|
case 'height':
|
||||||
|
case 'orientation':
|
||||||
|
case 'make':
|
||||||
|
case 'model': $y=$o->{$v}; break;
|
||||||
|
case 'duplicates': $x=$y='';foreach($o->list_duplicate() as $id) $y.=($y ? '|' : '').sprintf('<a href="%s">%s</a>',url('/info/'.$id),$id); break;
|
||||||
|
case 'flag':
|
||||||
|
case 'remove':
|
||||||
|
case 'duplicate': $y=sprintf('<input type="checkbox" name="%s[%s]" value="1"%s>',$v,$o->id,$o->{$v} ? ' checked="checked"' : ''); break;
|
||||||
|
endswitch ?>
|
||||||
|
<td><?php echo $y; ?></td>
|
||||||
|
@endforeach {{-- photo --}}
|
||||||
|
</tr>
|
||||||
|
@endforeach {{-- data --}}
|
||||||
|
</table>
|
||||||
|
<input type="hidden" name="pagenext" value="{{ $photos->hasMorePages() ? $photos->currentPage()+1 : NULL }}">
|
||||||
|
<button class="btn btn-default">Confirm Delete</button>
|
||||||
|
{{ csrf_field() }}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
@ -17,13 +17,13 @@
|
|||||||
'Model'=>'model',
|
'Model'=>'model',
|
||||||
'Exif Diff'=>'exif',
|
'Exif Diff'=>'exif',
|
||||||
];
|
];
|
||||||
|
|
||||||
$form = [
|
$form = [
|
||||||
'duplicate',
|
'duplicate',
|
||||||
'flag',
|
'flag',
|
||||||
'remove',
|
'remove',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
function changed($k,$v,$l=0)
|
function changed($k,$v,$l=0)
|
||||||
{
|
{
|
||||||
static $changed = [];
|
static $changed = [];
|
||||||
@ -31,7 +31,7 @@ function changed($k,$v,$l=0)
|
|||||||
if (! isset($changed[$l][$k]))
|
if (! isset($changed[$l][$k]))
|
||||||
$changed[$l][$k] = $v;
|
$changed[$l][$k] = $v;
|
||||||
|
|
||||||
return $changed[$l][$k] == $v;
|
return $changed[$l][$k] === $v;
|
||||||
} ?>
|
} ?>
|
||||||
|
|
||||||
@foreach ($photos as $photo)
|
@foreach ($photos as $photo)
|
||||||
@ -62,13 +62,13 @@ case 'datetaken': $x=$y=$o->date_taken(); break;
|
|||||||
case 'created': $x=$y=$o->file_date('c',TRUE); break;
|
case 'created': $x=$y=$o->file_date('c',TRUE); break;
|
||||||
case 'modified': $x=$y=$o->file_date('m',TRUE); break;
|
case 'modified': $x=$y=$o->file_date('m',TRUE); break;
|
||||||
case 'filepath': $x=$y=$o->file_path(TRUE); break;
|
case 'filepath': $x=$y=$o->file_path(TRUE); break;
|
||||||
case 'filesize': $x=$y=$o->size(); break;
|
case 'filesize': $x=$y=$o->file_size(); break;
|
||||||
case 'width': $x=$y=$o->width; break;
|
case 'width': $x=$y=$o->width; break;
|
||||||
case 'height': $x=$y=$o->height; break;
|
case 'height': $x=$y=$o->height; break;
|
||||||
case 'orientation': $x=$y=$o->orientation; break;
|
case 'orientation': $x=$y=$o->orientation; break;
|
||||||
case 'make': $x=$y=$o->make; break;
|
case 'make': $x=$y=$o->make; break;
|
||||||
case 'model': $x=$y=$o->model; break;
|
case 'model': $x=$y=$o->model; break;
|
||||||
case 'exif': $y='<table class="table table-striped table-condensed">'; foreach ($o->info() as $a => $b) $y.=sprintf('<tr class="%s"><th>%s<><td>%s<td></tr>',(changed($a,$b,1) ? '' : 'warning'),$a,$b); $y.='</table>';$x=md5($y); break;
|
case 'exif': $y='<table class="table table-striped table-condensed">'; foreach ($o->properties() as $a => $b) $y.=sprintf('<tr class="%s"><th>%s<><td>%s<td></tr>',(changed($a,$b,1) ? '' : 'warning'),$a,$b); $y.='</table>';$x=md5($y); break;
|
||||||
endswitch ?>
|
endswitch ?>
|
||||||
<td class="{{ changed($v,$x) ? '' : 'danger' }}"><?php echo $y; ?></td>
|
<td class="{{ changed($v,$x) ? '' : 'danger' }}"><?php echo $y; ?></td>
|
||||||
@endforeach {{-- photo --}}
|
@endforeach {{-- photo --}}
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
<?php if ($photo->shouldMove()) : ?>
|
<?php if ($photo->shouldMove()) : ?>
|
||||||
<dt>NEW Filename</dt><dd>{{ $photo->file_path(TRUE,TRUE) }}<dd>
|
<dt>NEW Filename</dt><dd>{{ $photo->file_path(TRUE,TRUE) }}<dd>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<dt>Size</dt><dd>{{ $photo->size() }}<dd>
|
<dt>Size</dt><dd>{{ $photo->file_size() }}<dd>
|
||||||
<dt>Dimensions</dt><dd>{{ $photo->width }} x {{ $photo->height }} @ {{ $photo->orientation }}<dd>
|
<dt>Dimensions</dt><dd>{{ $photo->width }} x {{ $photo->height }} @ {{ $photo->orientation }}<dd>
|
||||||
<br/>
|
<br/>
|
||||||
<dt>Date Taken</dt><dd>{{ $photo->date_taken() }}<dd>
|
<dt>Date Taken</dt><dd>{{ $photo->date_taken() }}<dd>
|
||||||
@ -57,7 +57,7 @@
|
|||||||
<br/>
|
<br/>
|
||||||
<dt>Exif Data</dt><dd>
|
<dt>Exif Data</dt><dd>
|
||||||
<table>
|
<table>
|
||||||
<?php foreach ($photo->info() as $k => $v) : ?>
|
<?php foreach ($photo->properties() as $k => $v) : ?>
|
||||||
<tr><th>{{ $k }}<><td>{{ $v }}<td></tr>
|
<tr><th>{{ $k }}<><td>{{ $v }}<td></tr>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</table>
|
</table>
|
||||||
|
Loading…
Reference in New Issue
Block a user