Merge branch 'develop' into feature/rules-on-existing-transactions
@ -11,13 +11,15 @@ declare(strict_types = 1);
|
||||
namespace FireflyIII\Export\Collector;
|
||||
|
||||
use Amount;
|
||||
use Auth;
|
||||
use Crypt;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use FireflyIII\Models\ExportJob;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Storage;
|
||||
|
||||
/**
|
||||
* Class AttachmentCollector
|
||||
@ -28,6 +30,12 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
|
||||
{
|
||||
/** @var string */
|
||||
private $explanationString = '';
|
||||
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
|
||||
private $exportDisk;
|
||||
/** @var AttachmentRepositoryInterface */
|
||||
private $repository;
|
||||
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
|
||||
private $uploadDisk;
|
||||
|
||||
/**
|
||||
* AttachmentCollector constructor.
|
||||
@ -36,6 +44,11 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
|
||||
*/
|
||||
public function __construct(ExportJob $job)
|
||||
{
|
||||
$this->repository = app('FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface');
|
||||
// make storage:
|
||||
$this->uploadDisk = Storage::disk('upload');
|
||||
$this->exportDisk = Storage::disk('export');
|
||||
|
||||
parent::__construct($job);
|
||||
}
|
||||
|
||||
@ -45,35 +58,18 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
|
||||
public function run()
|
||||
{
|
||||
// grab all the users attachments:
|
||||
$attachments = Auth::user()->attachments()->get();
|
||||
|
||||
Log::debug('Found ' . $attachments->count() . ' attachments.');
|
||||
$attachments = $this->getAttachments();
|
||||
|
||||
/** @var Attachment $attachment */
|
||||
foreach ($attachments as $attachment) {
|
||||
$originalFile = storage_path('upload') . DIRECTORY_SEPARATOR . 'at-' . $attachment->id . '.data';
|
||||
if (file_exists($originalFile)) {
|
||||
Log::debug('Stored 1 attachment');
|
||||
try {
|
||||
$decrypted = Crypt::decrypt(file_get_contents($originalFile));
|
||||
$newFile = storage_path('export') . DIRECTORY_SEPARATOR . $this->job->key . '-Attachment nr. ' . $attachment->id . ' - '
|
||||
. $attachment->filename;
|
||||
file_put_contents($newFile, $decrypted);
|
||||
$this->getFiles()->push($newFile);
|
||||
|
||||
// explain:
|
||||
$this->explain($attachment);
|
||||
} catch (DecryptException $e) {
|
||||
Log::error('Catchable error: could not decrypt attachment #' . $attachment->id);
|
||||
}
|
||||
|
||||
}
|
||||
$this->exportAttachment($attachment);
|
||||
}
|
||||
|
||||
// put the explanation string in a file and attach it as well.
|
||||
$explanationFile = storage_path('export') . DIRECTORY_SEPARATOR . $this->job->key . '-Source of all your attachments explained.txt';
|
||||
file_put_contents($explanationFile, $this->explanationString);
|
||||
$this->getFiles()->push($explanationFile);
|
||||
$file = $this->job->key . '-Source of all your attachments explained.txt';
|
||||
$this->exportDisk->put($file, $this->explanationString);
|
||||
Log::debug('Also put explanation file "' . $file . '" in the zip.');
|
||||
$this->getFiles()->push($file);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,4 +92,57 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
|
||||
$this->explanationString .= $string;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Attachment $attachment
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function exportAttachment(Attachment $attachment): bool
|
||||
{
|
||||
$file = $attachment->fileName();
|
||||
Log::debug('Original file is at "' . $file . '".');
|
||||
if ($this->uploadDisk->exists($file)) {
|
||||
try {
|
||||
$decrypted = Crypt::decrypt($this->uploadDisk->get($file));
|
||||
$exportFile = $this->exportFileName($attachment);
|
||||
$this->exportDisk->put($exportFile, $decrypted);
|
||||
$this->getFiles()->push($exportFile);
|
||||
Log::debug('Stored file content in new file "' . $exportFile . '", which will be in the final zip file.');
|
||||
|
||||
// explain:
|
||||
$this->explain($attachment);
|
||||
} catch (DecryptException $e) {
|
||||
Log::error('Catchable error: could not decrypt attachment #' . $attachment->id . ' because: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new file name for the export file.
|
||||
*
|
||||
* @param $attachment
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function exportFileName($attachment): string
|
||||
{
|
||||
|
||||
return sprintf('%s-Attachment nr. %s - %s', $this->job->key, strval($attachment->id), $attachment->filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getAttachments(): Collection
|
||||
{
|
||||
$attachments = $this->repository->get();
|
||||
|
||||
Log::debug('Found ' . $attachments->count() . ' attachments.');
|
||||
|
||||
return $attachments;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ use Crypt;
|
||||
use FireflyIII\Models\ExportJob;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Log;
|
||||
use Storage;
|
||||
|
||||
/**
|
||||
* Class UploadCollector
|
||||
*
|
||||
@ -22,6 +24,12 @@ use Log;
|
||||
*/
|
||||
class UploadCollector extends BasicCollector implements CollectorInterface
|
||||
{
|
||||
/** @var string */
|
||||
private $expected;
|
||||
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
|
||||
private $exportDisk;
|
||||
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
|
||||
private $uploadDisk;
|
||||
|
||||
/**
|
||||
* AttachmentCollector constructor.
|
||||
@ -31,6 +39,11 @@ class UploadCollector extends BasicCollector implements CollectorInterface
|
||||
public function __construct(ExportJob $job)
|
||||
{
|
||||
parent::__construct($job);
|
||||
|
||||
// make storage:
|
||||
$this->uploadDisk = Storage::disk('upload');
|
||||
$this->exportDisk = Storage::disk('export');
|
||||
$this->expected = 'csv-upload-' . Auth::user()->id . '-';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -39,31 +52,68 @@ class UploadCollector extends BasicCollector implements CollectorInterface
|
||||
public function run()
|
||||
{
|
||||
// grab upload directory.
|
||||
$path = storage_path('upload');
|
||||
$files = scandir($path);
|
||||
// only allow old uploads for this user:
|
||||
$expected = 'csv-upload-' . Auth::user()->id . '-';
|
||||
$len = strlen($expected);
|
||||
$files = $this->uploadDisk->files();
|
||||
Log::debug('Found ' . count($files) . ' files in the upload directory.');
|
||||
|
||||
foreach ($files as $entry) {
|
||||
if (substr($entry, 0, $len) === $expected) {
|
||||
try {
|
||||
// this is an original upload.
|
||||
$parts = explode('-', str_replace(['.csv.encrypted', $expected], '', $entry));
|
||||
$originalUpload = intval($parts[1]);
|
||||
$date = date('Y-m-d \a\t H-i-s', $originalUpload);
|
||||
$newFileName = 'Old CSV import dated ' . $date . '.csv';
|
||||
$content = Crypt::decrypt(file_get_contents($path . DIRECTORY_SEPARATOR . $entry));
|
||||
$fullPath = storage_path('export') . DIRECTORY_SEPARATOR . $this->job->key . '-' . $newFileName;
|
||||
$this->processOldUpload($entry);
|
||||
}
|
||||
}
|
||||
|
||||
// write to file:
|
||||
file_put_contents($fullPath, $content);
|
||||
/**
|
||||
* @param string $entry
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getOriginalUploadDate(string $entry): string
|
||||
{
|
||||
// this is an original upload.
|
||||
$parts = explode('-', str_replace(['.csv.encrypted', $this->expected], '', $entry));
|
||||
$originalUpload = intval($parts[1]);
|
||||
$date = date('Y-m-d \a\t H-i-s', $originalUpload);
|
||||
|
||||
// add entry to set:
|
||||
$this->getFiles()->push($fullPath);
|
||||
} catch (DecryptException $e) {
|
||||
Log::error('Could not decrypt old CSV import file ' . $entry . '. Skipped.');
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $entry
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isValidFile(string $entry): bool
|
||||
{
|
||||
$len = strlen($this->expected);
|
||||
if (substr($entry, 0, $len) === $this->expected) {
|
||||
Log::debug($entry . ' is part of this users original uploads.');
|
||||
|
||||
return true;
|
||||
}
|
||||
Log::debug($entry . ' is not part of this users original uploads.');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $entry
|
||||
*/
|
||||
private function processOldUpload(string $entry)
|
||||
{
|
||||
$content = '';
|
||||
|
||||
if ($this->isValidFile($entry)) {
|
||||
try {
|
||||
$content = Crypt::decrypt($this->uploadDisk->get($entry));
|
||||
} catch (DecryptException $e) {
|
||||
Log::error('Could not decrypt old CSV import file ' . $entry . '. Skipped because ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
if (strlen($content) > 0) {
|
||||
// continue with file:
|
||||
$date = $this->getOriginalUploadDate($entry);
|
||||
$file = $this->job->key . '-Old CSV import dated ' . $date . '.csv';
|
||||
Log::debug('Will put "' . $file . '" in the zip file.');
|
||||
$this->exportDisk->put($file, $content);
|
||||
$this->getFiles()->push($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ declare(strict_types = 1);
|
||||
namespace FireflyIII\Export;
|
||||
|
||||
use FireflyIII\Models\ExportJob;
|
||||
use Log;
|
||||
use Storage;
|
||||
|
||||
/**
|
||||
* Class ConfigurationFile
|
||||
@ -19,6 +21,8 @@ use FireflyIII\Models\ExportJob;
|
||||
*/
|
||||
class ConfigurationFile
|
||||
{
|
||||
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
|
||||
private $exportDisk;
|
||||
/** @var ExportJob */
|
||||
private $job;
|
||||
|
||||
@ -29,7 +33,8 @@ class ConfigurationFile
|
||||
*/
|
||||
public function __construct(ExportJob $job)
|
||||
{
|
||||
$this->job = $job;
|
||||
$this->job = $job;
|
||||
$this->exportDisk = Storage::disk('export');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,9 +56,10 @@ class ConfigurationFile
|
||||
foreach ($fields as $field) {
|
||||
$configuration['roles'][] = $types[$field];
|
||||
}
|
||||
|
||||
$file = storage_path('export') . DIRECTORY_SEPARATOR . $this->job->key . '-configuration.json';
|
||||
file_put_contents($file, json_encode($configuration, JSON_PRETTY_PRINT));
|
||||
$file = $this->job->key . '-configuration.json';
|
||||
Log::debug('Created JSON config file.');
|
||||
Log::debug('Will put "' . $file . '" in the ZIP file.');
|
||||
$this->exportDisk->put($file, json_encode($configuration, JSON_PRETTY_PRINT));
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ use FireflyIII\Export\Entry;
|
||||
use FireflyIII\Models\ExportJob;
|
||||
use League\Csv\Writer;
|
||||
use SplFileObject;
|
||||
use Storage;
|
||||
|
||||
/**
|
||||
* Class CsvExporter
|
||||
@ -25,9 +26,6 @@ class CsvExporter extends BasicExporter implements ExporterInterface
|
||||
/** @var string */
|
||||
private $fileName;
|
||||
|
||||
/** @var resource */
|
||||
private $handler;
|
||||
|
||||
/**
|
||||
* CsvExporter constructor.
|
||||
*
|
||||
@ -36,6 +34,7 @@ class CsvExporter extends BasicExporter implements ExporterInterface
|
||||
public function __construct(ExportJob $job)
|
||||
{
|
||||
parent::__construct($job);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,9 +53,11 @@ class CsvExporter extends BasicExporter implements ExporterInterface
|
||||
// create temporary file:
|
||||
$this->tempFile();
|
||||
|
||||
// necessary for CSV writer:
|
||||
$fullPath = storage_path('export') . DIRECTORY_SEPARATOR . $this->fileName;
|
||||
|
||||
// create CSV writer:
|
||||
$writer = Writer::createFromPath(new SplFileObject($this->fileName, 'a+'), 'w');
|
||||
//the $writer object open mode will be 'w'!!
|
||||
$writer = Writer::createFromPath(new SplFileObject($fullPath, 'a+'), 'w');
|
||||
|
||||
// all rows:
|
||||
$rows = [];
|
||||
@ -76,8 +77,6 @@ class CsvExporter extends BasicExporter implements ExporterInterface
|
||||
|
||||
private function tempFile()
|
||||
{
|
||||
$fileName = $this->job->key . '-records.csv';
|
||||
$this->fileName = storage_path('export') . DIRECTORY_SEPARATOR . $fileName;
|
||||
$this->handler = fopen($this->fileName, 'w');
|
||||
$this->fileName = $this->job->key . '-records.csv';
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\ExportJob;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Storage;
|
||||
use ZipArchive;
|
||||
|
||||
/**
|
||||
@ -88,6 +90,13 @@ class Processor
|
||||
$args = [$this->accounts, Auth::user(), $this->settings['startDate'], $this->settings['endDate']];
|
||||
$journalCollector = app('FireflyIII\Repositories\Journal\JournalCollector', $args);
|
||||
$this->journals = $journalCollector->collect();
|
||||
Log::debug(
|
||||
'Collected ' .
|
||||
$this->journals->count() . ' journals (between ' .
|
||||
$this->settings['startDate']->format('Y-m-d') . ' and ' .
|
||||
$this->settings['endDate']->format('Y-m-d')
|
||||
. ').'
|
||||
);
|
||||
}
|
||||
|
||||
public function collectOldUploads()
|
||||
@ -103,10 +112,13 @@ class Processor
|
||||
*/
|
||||
public function convertJournals()
|
||||
{
|
||||
$count = 0;
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($this->journals as $journal) {
|
||||
$this->exportEntries->push(Entry::fromJournal($journal));
|
||||
$count++;
|
||||
}
|
||||
Log::debug('Converted ' . $count . ' journals to "Entry" objects.');
|
||||
}
|
||||
|
||||
public function createConfigFile()
|
||||
@ -118,24 +130,32 @@ class Processor
|
||||
public function createZipFile()
|
||||
{
|
||||
$zip = new ZipArchive;
|
||||
$filename = storage_path('export') . DIRECTORY_SEPARATOR . $this->job->key . '.zip';
|
||||
$file = $this->job->key . '.zip';
|
||||
$fullPath = storage_path('export') . '/' . $file;
|
||||
Log::debug('Will create zip file at ' . $fullPath);
|
||||
|
||||
if ($zip->open($filename, ZipArchive::CREATE) !== true) {
|
||||
if ($zip->open($fullPath, ZipArchive::CREATE) !== true) {
|
||||
throw new FireflyException('Cannot store zip file.');
|
||||
}
|
||||
// for each file in the collection, add it to the zip file.
|
||||
$search = storage_path('export') . DIRECTORY_SEPARATOR . $this->job->key . '-';
|
||||
/** @var string $file */
|
||||
foreach ($this->getFiles() as $file) {
|
||||
$zipName = str_replace($search, '', $file);
|
||||
$zip->addFile($file, $zipName);
|
||||
$disk = Storage::disk('export');
|
||||
foreach ($this->getFiles() as $entry) {
|
||||
// is part of this job?
|
||||
$zipFileName = str_replace($this->job->key . '-', '', $entry);
|
||||
$result = $zip->addFromString($zipFileName, $disk->get($entry));
|
||||
if (!$result) {
|
||||
Log::error('Could not add "' . $entry . '" into zip file as "' . $zipFileName . '".');
|
||||
}
|
||||
}
|
||||
|
||||
$zip->close();
|
||||
|
||||
// delete the files:
|
||||
foreach ($this->getFiles() as $file) {
|
||||
unlink($file);
|
||||
Log::debug('Will now delete file "' . $file . '".');
|
||||
$disk->delete($file);
|
||||
}
|
||||
Log::debug('Done!');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,9 +165,11 @@ class Processor
|
||||
{
|
||||
$exporterClass = Config::get('firefly.export_formats.' . $this->exportFormat);
|
||||
$exporter = app($exporterClass, [$this->job]);
|
||||
Log::debug('Going to export ' . $this->exportEntries->count() . ' export entries into ' . $this->exportFormat . ' format.');
|
||||
$exporter->setEntries($this->exportEntries);
|
||||
$exporter->run();
|
||||
$this->files->push($exporter->getFileName());
|
||||
Log::debug('Added "' . $exporter->getFileName() . '" to the list of files to include in the zip.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use Input;
|
||||
use Log;
|
||||
use Storage;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use TypeError;
|
||||
|
||||
@ -30,6 +31,9 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
/** @var int */
|
||||
protected $maxUploadSize;
|
||||
|
||||
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
|
||||
protected $uploadDisk;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ -39,6 +43,7 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
$this->allowedMimes = Config::get('firefly.allowedMimes');
|
||||
$this->errors = new MessageBag;
|
||||
$this->messages = new MessageBag;
|
||||
$this->uploadDisk = Storage::disk('upload');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -148,15 +153,13 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
$attachment->uploaded = 0;
|
||||
$attachment->save();
|
||||
|
||||
$path = $file->getRealPath(); // encrypt and move file to storage.
|
||||
$content = file_get_contents($path);
|
||||
$fileObject = $file->openFile('r');
|
||||
$fileObject->rewind();
|
||||
$content = $fileObject->fread($file->getSize());
|
||||
$encrypted = Crypt::encrypt($content);
|
||||
|
||||
// store it:
|
||||
$upload = $this->getAttachmentLocation($attachment);
|
||||
if (is_writable(dirname($upload))) {
|
||||
file_put_contents($upload, $encrypted);
|
||||
}
|
||||
$this->uploadDisk->put($attachment->fileName(), $encrypted);
|
||||
|
||||
$attachment->uploaded = 1; // update attachment
|
||||
$attachment->save();
|
||||
|
@ -7,6 +7,7 @@ namespace FireflyIII\Http\Controllers\Chart;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface as CRI;
|
||||
use FireflyIII\Repositories\Category\SingleCategoryRepositoryInterface as SCRI;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
@ -153,7 +154,7 @@ class CategoryController extends Controller
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function frontpage(CRI $repository)
|
||||
public function frontpage(CRI $repository, ARI $accountRepository)
|
||||
{
|
||||
|
||||
$start = session('start', Carbon::now()->startOfMonth());
|
||||
@ -170,8 +171,9 @@ class CategoryController extends Controller
|
||||
}
|
||||
|
||||
// get data for categories (and "no category"):
|
||||
$set = $repository->spentForAccountsPerMonth(new Collection, $start, $end);
|
||||
$outside = $repository->sumSpentNoCategory(new Collection, $start, $end);
|
||||
$accounts = $accountRepository->getAccounts(['Default account', 'Asset account', 'Cash account']);
|
||||
$set = $repository->spentForAccountsPerMonth($accounts, $start, $end);
|
||||
$outside = $repository->sumSpentNoCategory($accounts, $start, $end);
|
||||
|
||||
// this is a "fake" entry for the "no category" entry.
|
||||
$entry = new stdClass();
|
||||
|
@ -19,6 +19,7 @@ use FireflyIII\Http\Requests\ExportFormRequest;
|
||||
use FireflyIII\Models\ExportJob;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface as ARI;
|
||||
use FireflyIII\Repositories\ExportJob\ExportJobRepositoryInterface as EJRI;
|
||||
use Log;
|
||||
use Preferences;
|
||||
use Response;
|
||||
use View;
|
||||
@ -51,7 +52,7 @@ class ExportController extends Controller
|
||||
$quoted = sprintf('"%s"', addcslashes($name, '"\\'));
|
||||
|
||||
$job->change('export_downloaded');
|
||||
|
||||
Log::debug('Will send user file "' . $file . '".');
|
||||
|
||||
return response(file_get_contents($file), 200)
|
||||
->header('Content-Description', 'File Transfer')
|
||||
|
@ -36,6 +36,22 @@ class Attachment extends Model
|
||||
|
||||
protected $fillable = ['attachable_id', 'attachable_type', 'user_id', 'md5', 'filename', 'mime', 'title', 'notes', 'description', 'size', 'uploaded'];
|
||||
|
||||
/**
|
||||
* @param Attachment $value
|
||||
*
|
||||
* @return Attachment
|
||||
*/
|
||||
public static function routeBinder(Attachment $value)
|
||||
{
|
||||
if (Auth::check()) {
|
||||
|
||||
if ($value->user_id == Auth::user()->id) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the owning imageable models.
|
||||
*/
|
||||
@ -45,14 +61,30 @@ class Attachment extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
* Returns the expected filename for this attachment.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function user()
|
||||
public function fileName(): string
|
||||
{
|
||||
return $this->belongsTo('FireflyIII\User');
|
||||
return sprintf('at-%s.data', strval($this->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param $value
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getDescriptionAttribute($value)
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Crypt::decrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
@ -70,14 +102,6 @@ class Attachment extends Model
|
||||
return Crypt::decrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*/
|
||||
public function setFilenameAttribute($value)
|
||||
{
|
||||
$this->attributes['filename'] = Crypt::encrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
@ -95,11 +119,19 @@ class Attachment extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param $value
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function setMimeAttribute($value)
|
||||
public function getNotesAttribute($value)
|
||||
{
|
||||
$this->attributes['mime'] = Crypt::encrypt($value);
|
||||
if (is_null($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Crypt::decrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,30 +150,6 @@ class Attachment extends Model
|
||||
return Crypt::decrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*/
|
||||
public function setTitleAttribute($value)
|
||||
{
|
||||
$this->attributes['title'] = Crypt::encrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param $value
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getDescriptionAttribute($value)
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Crypt::decrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*/
|
||||
@ -151,19 +159,19 @@ class Attachment extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param $value
|
||||
*
|
||||
* @return null|string
|
||||
* @param string $value
|
||||
*/
|
||||
public function getNotesAttribute($value)
|
||||
public function setFilenameAttribute($value)
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return null;
|
||||
}
|
||||
$this->attributes['filename'] = Crypt::encrypt($value);
|
||||
}
|
||||
|
||||
return Crypt::decrypt($value);
|
||||
/**
|
||||
* @param string $value
|
||||
*/
|
||||
public function setMimeAttribute($value)
|
||||
{
|
||||
$this->attributes['mime'] = Crypt::encrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -175,19 +183,20 @@ class Attachment extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Attachment $value
|
||||
*
|
||||
* @return Attachment
|
||||
* @param string $value
|
||||
*/
|
||||
public static function routeBinder(Attachment $value)
|
||||
public function setTitleAttribute($value)
|
||||
{
|
||||
if (Auth::check()) {
|
||||
$this->attributes['title'] = Crypt::encrypt($value);
|
||||
}
|
||||
|
||||
if ($value->user_id == Auth::user()->id) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
throw new NotFoundHttpException;
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('FireflyIII\User');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ namespace FireflyIII\Models;
|
||||
|
||||
use Auth;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Log;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
@ -50,6 +51,7 @@ class ExportJob extends Model
|
||||
*/
|
||||
public function change($status)
|
||||
{
|
||||
Log::debug('Job ' . $this->key . ' to status "' . $status . '".');
|
||||
$this->status = $status;
|
||||
$this->save();
|
||||
}
|
||||
|
@ -3,7 +3,9 @@ declare(strict_types = 1);
|
||||
|
||||
namespace FireflyIII\Repositories\Attachment;
|
||||
|
||||
use Auth;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class AttachmentRepository
|
||||
@ -26,9 +28,18 @@ class AttachmentRepository implements AttachmentRepositoryInterface
|
||||
$file = $helper->getAttachmentLocation($attachment);
|
||||
unlink($file);
|
||||
$attachment->delete();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function get(): Collection
|
||||
{
|
||||
return Auth::user()->attachments()->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Attachment $attachment
|
||||
* @param array $data
|
||||
|
@ -4,6 +4,7 @@ declare(strict_types = 1);
|
||||
namespace FireflyIII\Repositories\Attachment;
|
||||
|
||||
use FireflyIII\Models\Attachment;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface AttachmentRepositoryInterface
|
||||
@ -20,6 +21,11 @@ interface AttachmentRepositoryInterface
|
||||
*/
|
||||
public function destroy(Attachment $attachment): bool;
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function get(): Collection;
|
||||
|
||||
/**
|
||||
* @param Attachment $attachment
|
||||
* @param array $attachmentData
|
||||
|
@ -63,8 +63,8 @@ class Amount
|
||||
|
||||
/**
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
* @param bool $coloured
|
||||
* @param \FireflyIII\Models\TransactionJournal $journal
|
||||
* @param bool $coloured
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
@ -48,6 +48,15 @@ return [
|
||||
'root' => storage_path('app'),
|
||||
],
|
||||
|
||||
'upload' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('upload'),
|
||||
],
|
||||
'export' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('export'),
|
||||
],
|
||||
|
||||
'ftp' => [
|
||||
'driver' => 'ftp',
|
||||
'host' => 'ftp.example.com',
|
||||
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 933 B After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.2 KiB |
@ -2,11 +2,11 @@
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square70x70logo src="/mstile-70x70.png?v=Lb54KlrQnz"/>
|
||||
<square150x150logo src="/mstile-150x150.png?v=Lb54KlrQnz"/>
|
||||
<square310x310logo src="/mstile-310x310.png?v=Lb54KlrQnz"/>
|
||||
<wide310x150logo src="/mstile-310x150.png?v=Lb54KlrQnz"/>
|
||||
<TileColor>#2d89ef</TileColor>
|
||||
<square70x70logo src="mstile-70x70.png"/>
|
||||
<square150x150logo src="mstile-150x150.png"/>
|
||||
<square310x310logo src="mstile-310x310.png"/>
|
||||
<wide310x150logo src="mstile-310x150.png"/>
|
||||
<TileColor>#da532c</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
|
Before Width: | Height: | Size: 509 B After Width: | Height: | Size: 608 B |
BIN
public/favicon-194x194.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 842 B After Width: | Height: | Size: 941 B |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.4 KiB |
@ -1,43 +1,42 @@
|
||||
{
|
||||
"name": "Firefly III",
|
||||
"short_name": "Firefly III",
|
||||
|
||||
"icons": [
|
||||
{
|
||||
"src": "\/android-chrome-36x36.png?v=Lb54KlrQnz",
|
||||
"src": "\/android-chrome-36x36.png",
|
||||
"sizes": "36x36",
|
||||
"type": "image\/png",
|
||||
"density": "0.75"
|
||||
"density": 0.75
|
||||
},
|
||||
{
|
||||
"src": "\/android-chrome-48x48.png?v=Lb54KlrQnz",
|
||||
"src": "\/android-chrome-48x48.png",
|
||||
"sizes": "48x48",
|
||||
"type": "image\/png",
|
||||
"density": "1.0"
|
||||
"density": 1
|
||||
},
|
||||
{
|
||||
"src": "\/android-chrome-72x72.png?v=Lb54KlrQnz",
|
||||
"src": "\/android-chrome-72x72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image\/png",
|
||||
"density": "1.5"
|
||||
"density": 1.5
|
||||
},
|
||||
{
|
||||
"src": "\/android-chrome-96x96.png?v=Lb54KlrQnz",
|
||||
"src": "\/android-chrome-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image\/png",
|
||||
"density": "2.0"
|
||||
"density": 2
|
||||
},
|
||||
{
|
||||
"src": "\/android-chrome-144x144.png?v=Lb54KlrQnz",
|
||||
"src": "\/android-chrome-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image\/png",
|
||||
"density": "3.0"
|
||||
"density": 3
|
||||
},
|
||||
{
|
||||
"src": "\/android-chrome-192x192.png?v=Lb54KlrQnz",
|
||||
"src": "\/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image\/png",
|
||||
"density": "4.0"
|
||||
"density": 4
|
||||
}
|
||||
],
|
||||
"start_url": "/",
|
||||
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
48
public/safari-pinned-tab.svg
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M4090 5104 c-135 -37 -302 -170 -457 -362 -89 -111 -94 -115 -148
|
||||
-123 -39 -6 -42 -4 -99 54 -113 114 -260 149 -425 101 -321 -93 -472 -354
|
||||
-631 -1088 -22 -104 -45 -196 -49 -205 -22 -39 -102 -95 -231 -160 -25 -12
|
||||
-58 -31 -75 -42 -16 -10 -35 -21 -42 -25 -17 -8 -44 -52 -49 -78 -4 -25 20
|
||||
-66 59 -96 22 -18 46 -23 114 -28 74 -4 90 -9 115 -31 45 -40 51 -87 25 -221
|
||||
-3 -14 -8 -43 -12 -65 -4 -22 -13 -73 -21 -113 -8 -40 -12 -83 -9 -95 4 -13
|
||||
-6 -58 -21 -102 -18 -55 -27 -106 -29 -163 -11 -302 -17 -389 -36 -468 -6 -27
|
||||
-12 -58 -15 -69 -2 -11 -30 -126 -63 -255 -33 -129 -64 -269 -70 -310 -12 -79
|
||||
-19 -92 -131 -235 -95 -122 -177 -189 -345 -282 -132 -73 -141 -76 -224 -70
|
||||
-85 5 -121 19 -235 91 -90 57 -147 74 -223 70 -143 -9 -347 -144 -409 -270
|
||||
-23 -47 -27 -67 -26 -137 3 -151 8 -160 135 -224 76 -39 117 -53 162 -58 33
|
||||
-3 89 -13 125 -22 37 -9 112 -16 175 -17 105 -1 116 1 230 41 77 26 144 43
|
||||
187 46 117 8 179 49 416 281 88 86 246 284 323 406 57 89 126 230 153 310 26
|
||||
80 33 123 41 260 5 75 52 281 101 440 23 77 35 142 39 215 5 83 14 212 20 275
|
||||
3 25 7 81 10 125 3 44 8 103 10 130 3 28 7 73 10 100 2 28 7 77 10 110 3 33 8
|
||||
80 10 104 16 160 28 201 72 231 33 22 43 24 147 22 140 -3 221 -10 268 -24 31
|
||||
-9 44 -22 69 -67 29 -51 31 -62 31 -153 0 -139 -11 -204 -68 -398 -56 -192
|
||||
-64 -231 -70 -330 -3 -52 -13 -131 -21 -175 -9 -44 -18 -129 -19 -190 -2 -92
|
||||
-8 -124 -33 -195 -30 -85 -53 -209 -66 -350 -4 -41 -9 -86 -10 -100 -2 -14 -6
|
||||
-63 -10 -110 -7 -104 -20 -185 -42 -268 -20 -79 -37 -93 -204 -177 -152 -76
|
||||
-235 -130 -305 -200 -44 -43 -54 -61 -64 -108 -13 -66 -9 -85 26 -118 23 -21
|
||||
33 -24 96 -21 39 1 111 11 162 22 50 11 115 22 145 25 66 6 79 10 159 46 35
|
||||
16 66 29 69 29 3 0 19 7 36 15 106 48 181 72 256 81 31 3 63 8 71 9 8 2 44 6
|
||||
80 10 151 16 322 104 331 170 2 11 0 37 -4 57 -13 66 -64 86 -227 94 -140 7
|
||||
-162 13 -177 47 -5 12 -8 38 -7 57 2 35 42 400 49 455 2 17 7 57 10 90 3 33 8
|
||||
79 11 103 3 23 -2 88 -11 144 -25 146 -19 241 35 528 53 282 61 344 64 460 1
|
||||
63 5 124 8 135 4 11 25 76 47 144 23 68 41 129 41 137 0 71 88 104 291 107
|
||||
112 2 141 6 179 24 53 25 86 58 94 93 13 55 14 80 6 85 -5 3 -12 27 -16 53 -7
|
||||
49 -18 78 -40 100 -10 10 -56 13 -183 13 -221 0 -217 -3 -215 137 1 54 4 117
|
||||
7 138 50 340 160 593 324 743 69 64 146 101 207 101 20 0 94 -27 182 -67 114
|
||||
-51 159 -67 194 -67 81 1 257 89 305 152 16 22 19 44 20 137 2 128 -12 185
|
||||
-54 232 -47 51 -100 81 -210 118 -91 30 -118 35 -239 39 -105 5 -150 2 -192
|
||||
-10z m-903 -908 c17 -8 43 -30 58 -48 35 -42 33 -61 -39 -377 -31 -134 -56
|
||||
-251 -56 -261 0 -26 -20 -39 -101 -61 -93 -26 -319 -28 -356 -4 -46 30 -56 69
|
||||
-49 184 8 128 9 134 34 242 55 229 137 317 312 336 101 12 161 8 197 -11z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.1 KiB |
@ -44,6 +44,7 @@ return [
|
||||
'flash_error' => 'Error!',
|
||||
'flash_info_multiple' => 'There is one message|There are :count messages',
|
||||
'flash_error_multiple' => 'There is one error|There are :count errors',
|
||||
'net_worth' => 'Net worth',
|
||||
|
||||
|
||||
// export data:
|
||||
@ -57,6 +58,7 @@ return [
|
||||
'include_config_help' => 'For easy re-import into Firefly III',
|
||||
'include_old_uploads_help' => 'Firefly III does not throw away the original CSV files you have imported in the past. You can include them in your export.',
|
||||
'do_export' => 'Export',
|
||||
'export_status_never_started' => 'The export has not started yet',
|
||||
'export_status_make_exporter' => 'Creating exporter thing...',
|
||||
'export_status_collecting_journals' => 'Collecting your transactions...',
|
||||
'export_status_collected_journals' => 'Collected your transactions!',
|
||||
@ -114,23 +116,23 @@ return [
|
||||
'default_rule_action_prepend' => 'Bought the world from ',
|
||||
'default_rule_action_set_category' => 'Large expenses',
|
||||
|
||||
'trigger' => 'Trigger',
|
||||
'trigger_value' => 'Trigger on value',
|
||||
'stop_processing_other_triggers' => 'Stop processing other triggers',
|
||||
'add_rule_trigger' => 'Add new trigger',
|
||||
'action' => 'Action',
|
||||
'action_value' => 'Action value',
|
||||
'stop_executing_other_actions' => 'Stop executing other actions',
|
||||
'add_rule_action' => 'Add new action',
|
||||
'edit_rule' => 'Edit rule ":title"',
|
||||
'delete_rule' => 'Delete rule ":title"',
|
||||
'update_rule' => 'Update rule',
|
||||
'trigger' => 'Trigger',
|
||||
'trigger_value' => 'Trigger on value',
|
||||
'stop_processing_other_triggers' => 'Stop processing other triggers',
|
||||
'add_rule_trigger' => 'Add new trigger',
|
||||
'action' => 'Action',
|
||||
'action_value' => 'Action value',
|
||||
'stop_executing_other_actions' => 'Stop executing other actions',
|
||||
'add_rule_action' => 'Add new action',
|
||||
'edit_rule' => 'Edit rule ":title"',
|
||||
'delete_rule' => 'Delete rule ":title"',
|
||||
'update_rule' => 'Update rule',
|
||||
|
||||
'test_rule_triggers' => 'See matching transactions',
|
||||
'warning_transaction_subset' => 'For performance reasons this list is limited to :max_num_transactions and may only show a subset of matching transactions',
|
||||
'warning_no_matching_transactions' => 'No matching transactions found. Please note that for performance reasons, only the last :num_transactions transactions have been checked.',
|
||||
'warning_no_valid_triggers' => 'No valid triggers provided.',
|
||||
|
||||
|
||||
// actions and triggers
|
||||
'rule_trigger_user_action' => 'User action is ":trigger_value"',
|
||||
'rule_trigger_from_account_starts' => 'Source account starts with ":trigger_value"',
|
||||
|
@ -44,6 +44,7 @@ return [
|
||||
'flash_error' => 'Fout!',
|
||||
'flash_info_multiple' => 'Er is één melding|Er zijn :count meldingen',
|
||||
'flash_error_multiple' => 'Er is één fout|Er zijn :count fouten',
|
||||
'net_worth' => 'Kapitaal',
|
||||
|
||||
|
||||
// export data:
|
||||
@ -74,7 +75,7 @@ return [
|
||||
'export_status_created_zip_file' => 'Zipbestand gemaakt!',
|
||||
'export_status_finished' => 'Klaar met exportbestand! Hoera!',
|
||||
'export_data_please_wait' => 'Een ogenblik geduld...',
|
||||
'attachment_explanation' => 'Het bestand \':attachment_name\' (#:attachment_id) werd oorspronkelijk geüpload naar :type (Engels) \':description\' (#:journal_id), met datum :datum en bedrag :bedrag.',
|
||||
'attachment_explanation' => 'Het bestand \':attachment_name\' (#:attachment_id) werd oorspronkelijk geüpload naar (Engels) :type \':description\' (#:journal_id), met datum :date en bedrag :amount.',
|
||||
|
||||
// rules
|
||||
'rules' => 'Regels',
|
||||
|
@ -13,24 +13,7 @@
|
||||
<link href="css/firefly.css" rel="stylesheet" type="text/css"/>
|
||||
|
||||
<!-- favicons -->
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png?v=Lb54KlrQnz">
|
||||
<link rel="icon" type="image/png" href="/favicon-32x32.png?v=Lb54KlrQnz" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="/android-chrome-192x192.png?v=Lb54KlrQnz" sizes="192x192">
|
||||
<link rel="icon" type="image/png" href="/favicon-96x96.png?v=Lb54KlrQnz" sizes="96x96">
|
||||
<link rel="icon" type="image/png" href="/favicon-16x16.png?v=Lb54KlrQnz" sizes="16x16">
|
||||
<link rel="manifest" href="/manifest.json?v=Lb54KlrQnz">
|
||||
<link rel="shortcut icon" href="/favicon.ico?v=Lb54KlrQnz">
|
||||
<meta name="msapplication-TileColor" content="#2d89ef">
|
||||
<meta name="msapplication-TileImage" content="/mstile-144x144.png?v=Lb54KlrQnz">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
{% include('partials/favicons.twig') %}
|
||||
|
||||
</head>
|
||||
<body class="ff-error-page">
|
||||
|
@ -30,24 +30,7 @@
|
||||
<![endif]-->
|
||||
|
||||
<!-- favicons -->
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="apple-touch-icon-57x57.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="apple-touch-icon-60x60.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="apple-touch-icon-72x72.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="apple-touch-icon-76x76.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="apple-touch-icon-114x114.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="apple-touch-icon-120x120.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="apple-touch-icon-144x144.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="apple-touch-icon-152x152.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon-180x180.png?v=Lb54KlrQnz">
|
||||
<link rel="icon" type="image/png" href="favicon-32x32.png?v=Lb54KlrQnz" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="android-chrome-192x192.png?v=Lb54KlrQnz" sizes="192x192">
|
||||
<link rel="icon" type="image/png" href="favicon-96x96.png?v=Lb54KlrQnz" sizes="96x96">
|
||||
<link rel="icon" type="image/png" href="favicon-16x16.png?v=Lb54KlrQnz" sizes="16x16">
|
||||
<link rel="manifest" href="manifest.json?v=Lb54KlrQnz">
|
||||
<link rel="shortcut icon" href="favicon.ico?v=Lb54KlrQnz">
|
||||
<meta name="msapplication-TileColor" content="#2d89ef">
|
||||
<meta name="msapplication-TileImage" content="mstile-144x144.png?v=Lb54KlrQnz">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
{% include('partials/favicons.twig') %}
|
||||
|
||||
</head>
|
||||
<body class="skin-blue-light sidebar-mini">
|
||||
|
@ -17,24 +17,7 @@
|
||||
<![endif]-->
|
||||
|
||||
<!-- favicons -->
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="apple-touch-icon-57x57.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="apple-touch-icon-60x60.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="apple-touch-icon-72x72.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="apple-touch-icon-76x76.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="apple-touch-icon-114x114.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="apple-touch-icon-120x120.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="apple-touch-icon-144x144.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="apple-touch-icon-152x152.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon-180x180.png?v=Lb54KlrQnz">
|
||||
<link rel="icon" type="image/png" href="favicon-32x32.png?v=Lb54KlrQnz" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="android-chrome-192x192.png?v=Lb54KlrQnz" sizes="192x192">
|
||||
<link rel="icon" type="image/png" href="favicon-96x96.png?v=Lb54KlrQnz" sizes="96x96">
|
||||
<link rel="icon" type="image/png" href="favicon-16x16.png?v=Lb54KlrQnz" sizes="16x16">
|
||||
<link rel="manifest" href="manifest.json?v=Lb54KlrQnz">
|
||||
<link rel="shortcut icon" href="favicon.ico?v=Lb54KlrQnz">
|
||||
<meta name="msapplication-TileColor" content="#2d89ef">
|
||||
<meta name="msapplication-TileImage" content="mstile-144x144.png?v=Lb54KlrQnz">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
{% include('partials/favicons.twig') %}
|
||||
|
||||
</head>
|
||||
<body class="login-page">
|
||||
|
@ -18,24 +18,7 @@
|
||||
<![endif]-->
|
||||
|
||||
<!-- favicons -->
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="apple-touch-icon-57x57.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="apple-touch-icon-60x60.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="apple-touch-icon-72x72.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="apple-touch-icon-76x76.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="apple-touch-icon-114x114.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="apple-touch-icon-120x120.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="apple-touch-icon-144x144.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="apple-touch-icon-152x152.png?v=Lb54KlrQnz">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon-180x180.png?v=Lb54KlrQnz">
|
||||
<link rel="icon" type="image/png" href="favicon-32x32.png?v=Lb54KlrQnz" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="android-chrome-192x192.png?v=Lb54KlrQnz" sizes="192x192">
|
||||
<link rel="icon" type="image/png" href="favicon-96x96.png?v=Lb54KlrQnz" sizes="96x96">
|
||||
<link rel="icon" type="image/png" href="favicon-16x16.png?v=Lb54KlrQnz" sizes="16x16">
|
||||
<link rel="manifest" href="manifest.json?v=Lb54KlrQnz">
|
||||
<link rel="shortcut icon" href="favicon.ico?v=Lb54KlrQnz">
|
||||
<meta name="msapplication-TileColor" content="#2d89ef">
|
||||
<meta name="msapplication-TileImage" content="mstile-144x144.png?v=Lb54KlrQnz">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
{% include('partials/favicons.twig') %}
|
||||
|
||||
</head>
|
||||
<body class="login-page">
|
||||
|
18
resources/views/partials/favicons.twig
Normal file
@ -0,0 +1,18 @@
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="apple-touch-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="apple-touch-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="apple-touch-icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="apple-touch-icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="apple-touch-icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="apple-touch-icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="apple-touch-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="apple-touch-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon-180x180.png">
|
||||
<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="android-chrome-192x192.png" sizes="192x192">
|
||||
<link rel="icon" type="image/png" href="favicon-96x96.png" sizes="96x96">
|
||||
<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="mask-icon" href="safari-pinned-tab.svg" color="#3c8dbc">
|
||||
<meta name="msapplication-TileColor" content="#da532c">
|
||||
<meta name="msapplication-TileImage" content="mstile-144x144.png">
|
||||
<meta name="theme-color" content="#3c8dbc">
|