Coverted script import to laravel

This commit is contained in:
Deon George 2016-06-22 15:49:20 +10:00
parent a2357435e1
commit b1d7cfe616
36 changed files with 1619 additions and 299 deletions

View File

@ -0,0 +1,221 @@
<?php
namespace App\Console\Commands;
use Log;
use Illuminate\Console\Command;
use App\Model\Person;
use App\Model\PhotoPerson;
use App\Model\Photo;
use App\Model\PhotoTag;
use App\Model\Tag;
class Import extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'photo:import
{--dir= : Directory to Parse}
{--file= : File to import}
{--ignoredupe : Ignore duplicate files}
{--deletedupe : Delete duplicate files}
{--people= : People to reference in photo}
{--tags= : Add tag to photo}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Import photos into the database';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
// Make sure we got a directory or a file to import
if (is_null($this->option('file')) AND is_null($this->option('dir')))
abort(500,'Missing filename, please use --file= OR --dir=');
Log::info('Processing: '.($this->option('file') ? $this->option('file') : $this->option('dir')));
$files = [];
if ($this->option('dir'))
{
// Remove our trailing slash from the directory.
$dir = preg_replace('/\/$/','',$this->option('dir'));
// Exclude . & .. from the path.
$files = array_diff(scandir($dir),array('.','..'));
// Determine if our dir is releative to where we store data
$dir = preg_replace('/^\//','',str_replace(config('photo.dir'),'',$dir));
// Add our path
if ($dir)
array_walk($files,function(&$value,$key,$path='') {
if ($path) {
$value = sprintf('%s/%s',$path,$value);
}
},$dir);
}
elseif ($this->option('file'))
{
$files = array($this->option('file'));
}
// Show a progress bar
$bar = $this->output->createProgressBar(count($files));
$bar->setFormat("%current%/%max% [%bar%] %percent:3s%% (%memory%) (%remaining%) ");
$tags = NULL;
$t = $p = array();
// Tags
if ($this->option('tags'))
{
$tags = explode(',',$this->option('tags'));
$t = Tag::whereIn('tag',$tags)->get();
}
// People
if ($this->option('people'))
{
$tags = explode(',',$this->option('people'));
$p = Person::whereIn('tag',$tags)->get();
}
$c = 0;
foreach ($files as $file)
{
$bar->advance();
if (preg_match('/@__thumb/',$file) OR preg_match('/\/._/',$file))
{
$this->warn(sprintf('Ignoring file [%s]',$file));
continue;
}
if (! in_array(strtolower(pathinfo($file,PATHINFO_EXTENSION)),config('photo.import.accepted')))
{
$this->warn(sprintf('Ignoring [%s]',$file));
continue;
}
if ($this->option('verbose'))
$this->info(sprintf('Processing file [%s]',$file));
$c++;
$po = Photo::where('filename',$file)->first();
if (is_null($po))
{
$po = new Photo;
$po->filename = $file;
}
$po->date_taken = strtotime($po->io('exif:DateTime'));
$po->subsectime = $po->io('exif:SubSecTimeOriginal');
$po->signature = $po->io()->getImageSignature();
$po->make = $po->io('exif:Make');
$po->model = $po->io('exif:Model');
$po->height = $po->io()->getImageheight();
$po->width = $po->io()->getImageWidth();
$po->orientation = $po->io()->getImageOrientation();
$po->gps_lat = $po->gps(preg_split('/,\s?/',$po->io()->getImageProperty('exif:GPSLatitude')),$po->io()->getImageProperty('exif:GPSLatitudeRef'));
$po->gps_lon = $po->gps(preg_split('/,\s?/',$po->io()->getImageProperty('exif:GPSLongitude')),$po->io()->getImageProperty('exif:GPSLongitudeRef'));
try {
$po->thumbnail = exif_thumbnail($po->file_path());
} catch (Exception $e) {
// @todo Couldnt get the thumbnail, so we should create one.
}
// If this is a duplicate
$x = $po->list_duplicate()->get();
if (count($x)) {
$skip = FALSE;
foreach ($x as $o) {
// We'll only ignore based on the same signature.
if ($po->signature != $o->signature AND ! $po->exists)
continue;
if ($this->option('ignoredupe'))
{
$skip = TRUE;
$this->warn(sprintf("Ignoring file [%s], it's the same as [%s] with id %s",$po->file_path(),$o->filename,$o->id));
break;
}
elseif ($this->option('deletedupe') AND ($po->filename != $o->filename))
{
$skip = TRUE;
$this->error(sprintf("Deleting file [%s], it's the same as [%s] with id %s and signature [%s]\n",$po->file_path(),$o->filename,$o->id,$po->signature));
unlink($po->file_path());
}
}
if ($skip)
continue;
$po->duplicate = '1';
$this->warn(sprintf('Image [%s] marked as a duplicate',$file));
}
if ($po->exists)
$this->warn(sprintf('Image [%s] already in DB: %s',$file,$po->id));
$po->save();
if ($po->wasRecentlyCreated)
$this->info(sprintf('Image [%s] stored in DB: %s',$file,$po->id));
// Record our tags
foreach ($t as $o)
if (! (new PhotoTag)->where('tag_id','=',$o->id)->where('photo_id','=',$po->id)->count())
{
$x = new PhotoTag;
$x->tag_id = $o->id;
$x->photo_id = $po->id;
$x->save();
}
// Record our people
foreach ($p as $o)
if (! (new PhotoPerson)->where('people_id','=',$o->id)->where('photo_id','=',$po->id)->count())
{
$x = new PhotoPerson;
$x->people_id = $o->id;
$x->photo_id = $po->id;
$x->save();
}
}
$bar->finish();
return $this->info(sprintf('Images processed: %s',$c));
}
}

View File

@ -13,7 +13,7 @@ class Kernel extends ConsoleKernel
* @var array * @var array
*/ */
protected $commands = [ protected $commands = [
// Commands\Inspire::class, Commands\Import::class,
]; ];
/** /**

View File

@ -0,0 +1,31 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Response;
use App\Http\Requests;
use App\Model\Photo;
class PhotoController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
public function info($id)
{
return view('photo.view', ['photo'=> Photo::findOrFail($id)]);
}
public function thumbnail($id)
{
return (new Response(Photo::findOrFail($id)->thumbnail()))->header('Content-Type','image/jpg');
}
}

View File

@ -1,5 +1,7 @@
<?php <?php
use Illuminate\Http\Request;
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Application Routes | Application Routes
@ -14,3 +16,8 @@
Route::get('/', function () { Route::get('/', function () {
return view('welcome'); return view('welcome');
}); });
Route::auth();
Route::get('/info/{id}', 'PhotoController@info')->where('id', '[0-9]+');;
Route::get('/thumbnail/{id}', 'PhotoController@thumbnail')->where('id', '[0-9]+');;

9
app/Model/Person.php Normal file
View File

@ -0,0 +1,9 @@
<?php
namespace App\Model;
use Illuminate\Database\Eloquent\Model;
class Person extends Model
{
}

135
app/Model/Photo.php Normal file
View File

@ -0,0 +1,135 @@
<?php
namespace App\Model;
use DB;
use Illuminate\Database\Eloquent\Model;
class Photo extends Model
{
protected $table = 'photo';
// Imagick Object
private $_io;
// How should the image be rotated, based on the value of orientation
private $_rotate = [
3=>180,
6=>90,
8=>-90,
];
/**
* Determine the new name for the image
*/
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)) ? '' : config('photo.dir').DIRECTORY_SEPARATOR).$file;
}
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);
}
/**
* Return an Imagick object or attribute
*
*/
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);
}
/**
* Rotate the image
*
*/
private function rotate(\Imagick $imo)
{
if (array_key_exists($this->orientation,$this->_rotate))
$imo->rotateImage(new \ImagickPixel('none'),$this->_rotate[$this->orientation]);
return $imo->getImageBlob();
}
/**
* Return the image's thumbnail
*
*/
public function thumbnail($rotate=TRUE)
{
if (! $this->thumbnail)
return NULL;
if (! $rotate OR ! array_key_exists($this->orientation,$this->_rotate) OR ! extension_loaded('imagick'))
return $this->thumbnail;
$imo = new \Imagick();
$imo->readImageBlob($this->thumbnail);
return $this->rotate($imo);
}
public function list_duplicate() {
$po = DB::table('photo');
if ($this->id)
$po->where('id','!=',$this->id);
// Ignore photo's pending removal.
$po->where(function($query) {
$query->where('remove','!=',TRUE)
->orWhere('remove','=',NULL);
});
// Where the signature is the same
$po->where(function($query) {
$query->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)) {
$query->orWhere(function($query) {
$query->where('date_taken','=',$this->date_taken ? $this->date_taken : NULL);
$query->where('subsectime','=',$this->subsectime ? $this->subsectime : NULL);
if (! is_null($this->model))
$query->where('model','=',$this->model);
if (! is_null($this->make))
$query->where('make','=',$this->make);
});
}
});
return $po;
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace App\Model;
use Illuminate\Database\Eloquent\Model;
class PhotoPerson extends Model
{
}

15
app/Model/PhotoTag.php Normal file
View File

@ -0,0 +1,15 @@
<?php
namespace App\Model;
use Illuminate\Database\Eloquent\Model;
class PhotoTag extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'photo_tag';
}

9
app/Model/Tag.php Normal file
View File

@ -0,0 +1,9 @@
<?php
namespace App\Model;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
}

View File

@ -1,10 +0,0 @@
<?php defined('SYSPATH') or die('No direct script access.');
class Controller_Welcome extends Controller {
public function action_index()
{
HTTP::redirect('photo');
}
} // End Welcome

View File

@ -1,14 +0,0 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class supports Albums.
*
* @package Photo
* @category Models
* @author Deon George
* @copyright (c) 2014 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Model_Album extends ORM {
}
?>

View File

@ -185,6 +185,8 @@ class Model_Photo extends ORM {
return join('|',array_keys($result)); return join('|',array_keys($result));
} }
/*
private function rotate(Imagick $imo) { private function rotate(Imagick $imo) {
switch ($this->orientation) { switch ($this->orientation) {
case 3: $imo->rotateImage(new ImagickPixel('none'),180); case 3: $imo->rotateImage(new ImagickPixel('none'),180);
@ -195,6 +197,7 @@ class Model_Photo extends ORM {
break; break;
} }
} }
*/
public function rotation() { public function rotation() {
switch ($this->orientation) { switch ($this->orientation) {
@ -211,6 +214,7 @@ class Model_Photo extends ORM {
return sprintf('%s...%s',substr($signature,0,$chars),substr($signature,-1*$chars)); return sprintf('%s...%s',substr($signature,0,$chars),substr($signature,-1*$chars));
} }
/*
public function thumbnail($rotate=TRUE) { public function thumbnail($rotate=TRUE) {
if (! $this->thumbnail) if (! $this->thumbnail)
return NULL; return NULL;
@ -224,6 +228,7 @@ class Model_Photo extends ORM {
return $imo->getImageBlob(); return $imo->getImageBlob();
} }
*/
public function thumbnail_sig() { public function thumbnail_sig() {
return md5($this->thumbnail()).':'.strlen($this->thumbnail()); return md5($this->thumbnail()).':'.strlen($this->thumbnail());

View File

@ -1,14 +0,0 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class supports Tags.
*
* @package Photo
* @category Models
* @author Deon George
* @copyright (c) 2014 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Model_Photo_People extends ORM {
}
?>

View File

@ -1,14 +0,0 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class supports Tags.
*
* @package Photo
* @category Models
* @author Deon George
* @copyright (c) 2014 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Model_Photo_Tag extends ORM {
}
?>

View File

@ -1,14 +0,0 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class supports Tags.
*
* @package Photo
* @category Models
* @author Deon George
* @copyright (c) 2014 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Model_Tags extends ORM {
}
?>

View File

@ -1,186 +0,0 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* Import photo to the database
*
* @package Photo
* @category Tasks
* @author Deon George
* @copyright (c) 2014 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Task_Photo_Import extends Minion_Task {
private $_log = '/tmp/photo_import.txt';
private $_accepted = array(
'jpg',
);
protected $_options = array(
'dir'=>NULL, // Directory of Photos to Import
'file'=>NULL, // Photo File to Import
'tags'=>NULL,
'people'=>NULL,
'ignoredupe'=>FALSE, // Skip duplicate photos
'deletedupe'=>FALSE, // Skip duplicate photos
'verbose'=>FALSE, // Photo File to Import
);
private function _adddir(&$value,$key,$path='') {
if ($path)
$value = sprintf('%s/%s',$path,$value);
}
protected function _execute(array $params) {
$tags = NULL;
$t = $p = array();
if (is_null($params['file']) AND is_null($params['dir']) OR ($params['file'] AND $params['dir']))
throw new Kohana_Exception('Missing filename, please use --file= OR --dir=');
if ($params['dir']) {
$files = array_diff(scandir($params['dir']),array('.','..'));
array_walk($files,'static::_adddir',$params['dir']);
} else
$files = array($params['file']);
// Tags
if ($params['tags']) {
$tags = explode(',',$params['tags']);
$t = ORM::factory('Tags')->where('tag','IN',$tags)->find_all();
}
// People
if ($params['people']) {
$tags = explode(',',$params['people']);
$p = ORM::factory('People')->where('tag','IN',$tags)->find_all();
}
$c = 0;
foreach ($files as $file) {
if ($params['verbose'])
printf("Processing file [%s]\n",$file);
if (preg_match('/@__thumb/',$file) OR preg_match('/\/._/',$file)) {
$this->writelog(sprintf("Ignoring file [%s]\n",$file));
continue;
}
if (! in_array(strtolower(pathinfo($file,PATHINFO_EXTENSION)),$this->_accepted)) {
$this->writelog(sprintf("Ignoring file [%s]\n",$file));
continue;
}
$c++;
$po = ORM::factory('Photo',array('filename'=>$file));
if (! $po->loaded())
$po->filename = realpath($file);
$po->date_taken = $this->dbcol(strtotime($po->io('exif:DateTime')));
$po->signature = $this->dbcol($po->io()->getImageSignature());
$po->make = $this->dbcol($po->io('exif:Make'));
$po->model = $this->dbcol($po->io('exif:Model'));
$po->height = $this->dbcol($po->io()->getImageheight());
$po->width = $this->dbcol($po->io()->getImageWidth());
$po->orientation = $this->dbcol($po->io()->getImageOrientation());
$po->subsectime = $this->dbcol($po->io('exif:SubSecTimeOriginal'));
$po->gps_lat = $this->dbcol($po->gps(preg_split('/,\s?/',$po->io()->getImageProperty('exif:GPSLatitude')),$po->io()->getImageProperty('exif:GPSLatitudeRef')));
$po->gps_lon = $this->dbcol($po->gps(preg_split('/,\s?/',$po->io()->getImageProperty('exif:GPSLongitude')),$po->io()->getImageProperty('exif:GPSLongitudeRef')));
try {
$po->thumbnail = $this->dbcol(exif_thumbnail($po->filename));
} catch (Exception $e) {
}
switch ($params['verbose']) {
case 1:
print_r($po->what_changed());
break;
case 2:
print_r($po->io()->getImageProperties());
break;
}
$x = $po->list_duplicate()->find_all();
if (count($x)) {
$skip = FALSE;
foreach ($x as $o) {
# We'll only ignore based on the same signature.
if ($params['ignoredupe'] AND ($po->signature == $o->signature)) {
$skip = TRUE;
$this->writelog(sprintf("Ignore file [%s], it's the same as [%s (%s)]\n",$po->filename,$o->id,$o->file_path()));
break;
} elseif ($params['deletedupe'] AND ($po->signature == $o->signature) AND ($po->filename != $o->filename)) {
$skip = TRUE;
$this->writelog(sprintf("Delete file [%s], it's the same as [%s (%s)] with signature [%s]\n",$po->filename,$o->id,$o->file_path(),$po->signature));
unlink($file);
}
}
unset($x);
if ($skip)
continue;
else
$po->duplicate = '1';
}
if (! $po->changed())
$this->writelog(sprintf("Image [%s] already in DB: %s\n",$file,$po->id));
$po->save();
if ($po->saved())
$this->writelog(sprintf("Image [%s] stored in DB: %s\n",$file,$po->id));
// Record our tags
foreach ($t as $o) {
$x = ORM::factory('Photo_Tag')->where('tag_id','=',$o->id)->where('photo_id','=',$po->id)->find();
$x->tag_id = $o->id;
$x->photo_id = $po->id;
$x->save();
}
// Record our people
foreach ($p as $o) {
$x = ORM::factory('Photo_People',array('people_id'=>$o->id,'photo_id'=>$po->id));
$x->people_id = $o->id;
$x->photo_id = $po->id;
$x->save();
}
unset($po);
unset($x);
unset($o);
}
if ($c > 1)
return sprintf("Images processed: %s\n",$c);
}
// Force the return of a string or NULL
private function dbcol($val,$noval=NULL) {
return $val ? (string)$val : $noval;
}
private function writelog($msg) {
if (! $this->_log)
return;
static $fh = NULL;
if (is_null($fh))
$fh = fopen($this->_log,'a+');
fwrite($fh,$msg);
}
}
?>

View File

@ -13,7 +13,9 @@
"mockery/mockery": "0.9.*", "mockery/mockery": "0.9.*",
"phpunit/phpunit": "~4.0", "phpunit/phpunit": "~4.0",
"symfony/css-selector": "2.8.*|3.0.*", "symfony/css-selector": "2.8.*|3.0.*",
"symfony/dom-crawler": "2.8.*|3.0.*" "symfony/dom-crawler": "2.8.*|3.0.*",
"xethron/migrations-generator": "dev-l5",
"way/generators": "dev-feature/laravel-five-stable"
}, },
"autoload": { "autoload": {
"classmap": [ "classmap": [
@ -46,5 +48,11 @@
}, },
"config": { "config": {
"preferred-install": "dist" "preferred-install": "dist"
},
"repositories": {
"repo-name": {
"type": "git",
"url": "git@github.com:jamisonvalenta/Laravel-4-Generators.git"
}
} }
} }

502
composer.lock generated
View File

@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "c284a9c122da36c99a8b6597bdce7aa6", "hash": "06f9a4d19eda3cf3c92386077c05117c",
"content-hash": "8b1485987e7c5949da82435d403e52e8", "content-hash": "e32614d49ea2fa40cc882537b7125da4",
"packages": [ "packages": [
{ {
"name": "classpreloader/classpreloader", "name": "classpreloader/classpreloader",
@ -1780,6 +1780,354 @@
} }
], ],
"packages-dev": [ "packages-dev": [
{
"name": "doctrine/annotations",
"version": "v1.2.7",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/f25c8aab83e0c3e976fd7d19875f198ccf2f7535",
"reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535",
"shasum": ""
},
"require": {
"doctrine/lexer": "1.*",
"php": ">=5.3.2"
},
"require-dev": {
"doctrine/cache": "1.*",
"phpunit/phpunit": "4.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Annotations\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Docblock Annotations Parser",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"annotations",
"docblock",
"parser"
],
"time": "2015-08-31 12:32:49"
},
{
"name": "doctrine/cache",
"version": "v1.6.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/f8af318d14bdb0eff0336795b428b547bd39ccb6",
"reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6",
"shasum": ""
},
"require": {
"php": "~5.5|~7.0"
},
"conflict": {
"doctrine/common": ">2.2,<2.4"
},
"require-dev": {
"phpunit/phpunit": "~4.8|~5.0",
"predis/predis": "~1.0",
"satooshi/php-coveralls": "~0.6"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.6.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Caching library offering an object-oriented API for many cache backends",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"cache",
"caching"
],
"time": "2015-12-31 16:37:02"
},
{
"name": "doctrine/collections",
"version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/collections.git",
"reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/collections/zipball/6c1e4eef75f310ea1b3e30945e9f06e652128b8a",
"reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Collections\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Collections Abstraction library",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"array",
"collections",
"iterator"
],
"time": "2015-04-14 22:21:58"
},
{
"name": "doctrine/common",
"version": "v2.6.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/common.git",
"reference": "a579557bc689580c19fee4e27487a67fe60defc0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/common/zipball/a579557bc689580c19fee4e27487a67fe60defc0",
"reference": "a579557bc689580c19fee4e27487a67fe60defc0",
"shasum": ""
},
"require": {
"doctrine/annotations": "1.*",
"doctrine/cache": "1.*",
"doctrine/collections": "1.*",
"doctrine/inflector": "1.*",
"doctrine/lexer": "1.*",
"php": "~5.5|~7.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8|~5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.7.x-dev"
}
},
"autoload": {
"psr-4": {
"Doctrine\\Common\\": "lib/Doctrine/Common"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Common Library for Doctrine projects",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"annotations",
"collections",
"eventmanager",
"persistence",
"spl"
],
"time": "2015-12-25 13:18:31"
},
{
"name": "doctrine/dbal",
"version": "v2.5.4",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
"reference": "abbdfd1cff43a7b99d027af3be709bc8fc7d4769"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/abbdfd1cff43a7b99d027af3be709bc8fc7d4769",
"reference": "abbdfd1cff43a7b99d027af3be709bc8fc7d4769",
"shasum": ""
},
"require": {
"doctrine/common": ">=2.4,<2.7-dev",
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "4.*",
"symfony/console": "2.*"
},
"suggest": {
"symfony/console": "For helpful console commands such as SQL execution and import of files."
},
"bin": [
"bin/doctrine-dbal"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.5.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\DBAL\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
}
],
"description": "Database Abstraction Layer",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"database",
"dbal",
"persistence",
"queryobject"
],
"time": "2016-01-05 22:11:12"
},
{ {
"name": "doctrine/instantiator", "name": "doctrine/instantiator",
"version": "1.0.5", "version": "1.0.5",
@ -1834,6 +2182,60 @@
], ],
"time": "2015-06-14 21:17:01" "time": "2015-06-14 21:17:01"
}, },
{
"name": "doctrine/lexer",
"version": "v1.0.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Lexer\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"lexer",
"parser"
],
"time": "2014-09-09 13:34:57"
},
{ {
"name": "fzaninotto/faker", "name": "fzaninotto/faker",
"version": "v1.6.0", "version": "v1.6.0",
@ -3101,6 +3503,45 @@
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2016-06-14 11:18:07" "time": "2016-06-14 11:18:07"
}, },
{
"name": "way/generators",
"version": "dev-feature/laravel-five-stable",
"source": {
"type": "git",
"url": "git@github.com:jamisonvalenta/Laravel-4-Generators.git",
"reference": "a358bb44f517e2b3c1fd4f848f2646857c75b3a4"
},
"require": {
"illuminate/support": "~5.0",
"php": ">=5.4.0"
},
"require-dev": {
"behat/behat": "~2.5.1",
"behat/mink": "~1.5.0",
"behat/mink-extension": "~1.2.0",
"behat/mink-goutte-driver": "~1.0.9",
"behat/mink-selenium2-driver": "~1.1.1",
"phpspec/phpspec": "~2.0",
"phpunit/phpunit": "~3.7"
},
"type": "library",
"autoload": {
"psr-0": {
"Way\\Generators": "src/"
}
},
"license": [
"MIT"
],
"authors": [
{
"name": "Jeffrey Way",
"email": "jeffrey@jeffrey-way.com"
}
],
"description": "Rapidly generate resources, migrations, models, and much more.",
"time": "2015-02-17 06:26:25"
},
{ {
"name": "webmozart/assert", "name": "webmozart/assert",
"version": "1.0.2", "version": "1.0.2",
@ -3149,11 +3590,66 @@
"validate" "validate"
], ],
"time": "2015-08-24 13:29:44" "time": "2015-08-24 13:29:44"
},
{
"name": "xethron/migrations-generator",
"version": "dev-l5",
"source": {
"type": "git",
"url": "https://github.com/Xethron/migrations-generator.git",
"reference": "e5e86efb5731e6859ea0d96a806159f9f2c26ce1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Xethron/migrations-generator/zipball/e5e86efb5731e6859ea0d96a806159f9f2c26ce1",
"reference": "e5e86efb5731e6859ea0d96a806159f9f2c26ce1",
"shasum": ""
},
"require": {
"doctrine/dbal": "~2.4",
"illuminate/support": ">=4.1",
"php": ">=5.4.0",
"way/generators": "dev-feature/laravel-five-stable"
},
"require-dev": {
"illuminate/cache": ">=4.1.0",
"illuminate/console": ">=4.1.0",
"mockery/mockery": ">=0.9.0",
"phpunit/phpunit": ">=4.0.0"
},
"type": "library",
"autoload": {
"psr-0": {
"Xethron\\MigrationsGenerator": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Bernhard Breytenbach",
"email": "bernhard@coffeecode.co.za"
}
],
"description": "Generates Laravel Migrations from an existing database",
"keywords": [
"artisan",
"generator",
"laravel",
"migration",
"migrations"
],
"time": "2015-02-23 05:43:08"
} }
], ],
"aliases": [], "aliases": [],
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": [], "stability-flags": {
"xethron/migrations-generator": 20,
"way/generators": 20
},
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {

View File

@ -52,7 +52,7 @@ return [
| |
*/ */
'timezone' => 'UTC', 'timezone' => 'Australia/Melbourne',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -158,6 +158,8 @@ return [
App\Providers\EventServiceProvider::class, App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class, App\Providers\RouteServiceProvider::class,
Way\Generators\GeneratorsServiceProvider::class,
Xethron\MigrationsGenerator\MigrationsGeneratorServiceProvider::class,
], ],
/* /*

9
config/photo.php Normal file
View File

@ -0,0 +1,9 @@
<?php
return [
'dir'=>'/var/www/sites/co.dlcm.p/store',
'import'=>[
'accepted'=>['jpg'],
'log'=>'/tmp/import.log',
],
];

View File

@ -0,0 +1,48 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreatePhotoTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('photo', function(Blueprint $table)
{
$table->bigInteger('id', true);
$table->timestamps();
$table->integer('date_taken')->nullable();
$table->smallInteger('subsectime')->nullable();
$table->string('filename', 128);
$table->string('signature', 64)->nullable();
$table->string('make', 32)->nullable();
$table->string('model', 32)->nullable();
$table->integer('height')->nullable();
$table->integer('width')->nullable();
$table->integer('orientation')->nullable();
$table->float('gps_lat', 10, 0)->nullable();
$table->float('gps_lon', 10, 0)->nullable();
$table->binary('thumbnail', 65535)->nullable();
$table->boolean('duplicate')->nullable();
$table->boolean('remove')->nullable();
$table->boolean('flag')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('photo');
}
}

View File

@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreatePeopleTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('people', function(Blueprint $table)
{
$table->integer('id', true);
$table->string('tag', 16)->unique('tag_UNIQUE');
$table->string('name', 64)->nullable();
$table->integer('date_birth')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('people');
}
}

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreatePhotoPeopleTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('photo_people', function(Blueprint $table)
{
$table->bigInteger('id', true);
$table->timestamps();
$table->integer('people_id');
$table->bigInteger('photo_id')->index('fk_pp_ph_idx');
$table->unique(['people_id','photo_id'], 'UNIQUE');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('photo_people');
}
}

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreatePhotoTagTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('photo_tag', function(Blueprint $table)
{
$table->bigInteger('id', true);
$table->timestamps();
$table->bigInteger('photo_id');
$table->bigInteger('tag_id')->index('pt_t_idx');
$table->unique(['photo_id','tag_id'], 'UNIQUE');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('photo_tag');
}
}

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreateTagsTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('tags', function(Blueprint $table)
{
$table->bigInteger('id', true);
$table->string('tag', 16)->unique('tag_UNIQUE');
$table->string('description', 45)->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('tags');
}
}

View File

@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class AddForeignKeysToPhotoPeopleTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('photo_people', function(Blueprint $table)
{
$table->foreign('people_id', 'fk_pp_p')->references('id')->on('people')->onUpdate('NO ACTION')->onDelete('NO ACTION');
$table->foreign('photo_id', 'fk_pp_ph')->references('id')->on('photo')->onUpdate('NO ACTION')->onDelete('NO ACTION');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('photo_people', function(Blueprint $table)
{
$table->dropForeign('fk_pp_p');
$table->dropForeign('fk_pp_ph');
});
}
}

View File

@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class AddForeignKeysToPhotoTagTable extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('photo_tag', function(Blueprint $table)
{
$table->foreign('photo_id', 'fk_pt_p')->references('id')->on('photo')->onUpdate('NO ACTION')->onDelete('NO ACTION');
$table->foreign('tag_id', 'fk_pt_t')->references('id')->on('tags')->onUpdate('NO ACTION')->onDelete('NO ACTION');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('photo_tag', function(Blueprint $table)
{
$table->dropForeign('fk_pt_p');
$table->dropForeign('fk_pt_t');
});
}
}

View File

@ -0,0 +1 @@
Click here to reset your password: <a href="{{ $link = url('password/reset', $token).'?email='.urlencode($user->getEmailForPasswordReset()) }}"> {{ $link }} </a>

View File

@ -0,0 +1,66 @@
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Login</div>
<div class="panel-body">
<form class="form-horizontal" role="form" method="POST" action="{{ url('/login') }}">
{{ csrf_field() }}
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}">
@if ($errors->has('email'))
<span class="help-block">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
<label for="password" class="col-md-4 control-label">Password</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control" name="password">
@if ($errors->has('password'))
<span class="help-block">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<div class="checkbox">
<label>
<input type="checkbox" name="remember"> Remember Me
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary">
<i class="fa fa-btn fa-sign-in"></i> Login
</button>
<a class="btn btn-link" href="{{ url('/password/reset') }}">Forgot Your Password?</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@ -0,0 +1,47 @@
@extends('layouts.app')
<!-- Main Content -->
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Reset Password</div>
<div class="panel-body">
@if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
<form class="form-horizontal" role="form" method="POST" action="{{ url('/password/email') }}">
{{ csrf_field() }}
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}">
@if ($errors->has('email'))
<span class="help-block">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary">
<i class="fa fa-btn fa-envelope"></i> Send Password Reset Link
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@ -0,0 +1,70 @@
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Reset Password</div>
<div class="panel-body">
<form class="form-horizontal" role="form" method="POST" action="{{ url('/password/reset') }}">
{{ csrf_field() }}
<input type="hidden" name="token" value="{{ $token }}">
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control" name="email" value="{{ $email or old('email') }}">
@if ($errors->has('email'))
<span class="help-block">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
<label for="password" class="col-md-4 control-label">Password</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control" name="password">
@if ($errors->has('password'))
<span class="help-block">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password_confirmation') ? ' has-error' : '' }}">
<label for="password-confirm" class="col-md-4 control-label">Confirm Password</label>
<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation">
@if ($errors->has('password_confirmation'))
<span class="help-block">
<strong>{{ $errors->first('password_confirmation') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary">
<i class="fa fa-btn fa-refresh"></i> Reset Password
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@ -0,0 +1,82 @@
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Register</div>
<div class="panel-body">
<form class="form-horizontal" role="form" method="POST" action="{{ url('/register') }}">
{{ csrf_field() }}
<div class="form-group{{ $errors->has('name') ? ' has-error' : '' }}">
<label for="name" class="col-md-4 control-label">Name</label>
<div class="col-md-6">
<input id="name" type="text" class="form-control" name="name" value="{{ old('name') }}">
@if ($errors->has('name'))
<span class="help-block">
<strong>{{ $errors->first('name') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}">
@if ($errors->has('email'))
<span class="help-block">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
<label for="password" class="col-md-4 control-label">Password</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control" name="password">
@if ($errors->has('password'))
<span class="help-block">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password_confirmation') ? ' has-error' : '' }}">
<label for="password-confirm" class="col-md-4 control-label">Confirm Password</label>
<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation">
@if ($errors->has('password_confirmation'))
<span class="help-block">
<strong>{{ $errors->first('password_confirmation') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary">
<i class="fa fa-btn fa-user"></i> Register
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@ -0,0 +1,16 @@
<!-- resources/views/common/errors.blade.php -->
@if (count($errors) > 0)
<!-- Form Error List -->
<div class="alert alert-danger">
<strong>Whoops! Something went wrong!</strong>
<br><br>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif

View File

@ -0,0 +1,82 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
<!-- Fonts -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css" integrity="sha384-XdYbMnZ/QjLh6iI4ogqCTaIjrFk87ip+ekIjefZch0Y+PvJ8CDYtEs1ipDmPorQ+" crossorigin="anonymous">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:100,300,400,700">
<!-- Styles -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
{{-- <link href="{{ elixir('css/app.css') }}" rel="stylesheet"> --}}
<style>
body {
font-family: 'Lato';
}
.fa-btn {
margin-right: 6px;
}
</style>
</head>
<body id="app-layout">
<nav class="navbar navbar-default navbar-static-top">
<div class="container">
<div class="navbar-header">
<!-- Collapsed Hamburger -->
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#app-navbar-collapse">
<span class="sr-only">Toggle Navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<!-- Branding Image -->
<a class="navbar-brand" href="{{ url('/') }}">
Laravel
</a>
</div>
<div class="collapse navbar-collapse" id="app-navbar-collapse">
<!-- Left Side Of Navbar -->
<ul class="nav navbar-nav">
<li><a href="{{ url('/home') }}">Home</a></li>
</ul>
<!-- Right Side Of Navbar -->
<ul class="nav navbar-nav navbar-right">
<!-- Authentication Links -->
@if (Auth::guest())
<li><a href="{{ url('/login') }}">Login</a></li>
<li><a href="{{ url('/register') }}">Register</a></li>
@else
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
{{ Auth::user()->name }} <span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu">
<li><a href="{{ url('/logout') }}"><i class="fa fa-btn fa-sign-out"></i>Logout</a></li>
</ul>
</li>
@endif
</ul>
</div>
</div>
</nav>
@yield('content')
<!-- JavaScripts -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.min.js" integrity="sha384-I6F5OKECLVtK/BL+8iSLDEHowSAfUo76ZL9+kGAgTRdiByINKJaqTPH/QVNS1VDb" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
{{-- <script src="{{ elixir('js/app.js') }}"></script> --}}
</body>
</html>

View File

@ -0,0 +1,17 @@
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="panel panel-default">
<div class="panel-heading">Photo <?php echo $photo->id; ?></div>
<div class="panel-body">
<img src="/thumbnail/<?php echo $photo->id; ?>">
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@ -1,45 +1,17 @@
<!DOCTYPE html> @extends('layouts.app')
<html>
<head>
<title>Laravel</title>
<link href="https://fonts.googleapis.com/css?family=Lato:100" rel="stylesheet" type="text/css"> @section('content')
<div class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="panel panel-default">
<div class="panel-heading">Welcome</div>
<style> <div class="panel-body">
html, body { Your Application's Landing Page.
height: 100%;
}
body {
margin: 0;
padding: 0;
width: 100%;
display: table;
font-weight: 100;
font-family: 'Lato';
}
.container {
text-align: center;
display: table-cell;
vertical-align: middle;
}
.content {
text-align: center;
display: inline-block;
}
.title {
font-size: 96px;
}
</style>
</head>
<body>
<div class="container">
<div class="content">
<div class="title">Laravel 5</div>
</div> </div>
</div> </div>
</body> </div>
</html> </div>
</div>
@endsection