mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-18 18:44:16 +00:00
Merge branch 'release/5.1.1'
This commit is contained in:
@@ -29,6 +29,7 @@ use FireflyIII\Api\V1\Requests\TransactionUpdateRequest;
|
||||
use FireflyIII\Events\StoredTransactionGroup;
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
@@ -294,10 +295,23 @@ class TransactionController extends Controller
|
||||
],
|
||||
];
|
||||
|
||||
return response()->json($response, 422);
|
||||
} catch(FireflyException $e) {
|
||||
Log::warning('Caught an exception. Return error message.');
|
||||
Log::error($e->getMessage());
|
||||
// return bad validation message.
|
||||
// TODO use Laravel's internal validation thing to do this.
|
||||
$response = [
|
||||
'message' => 'The given data was invalid.',
|
||||
'errors' => [
|
||||
'transactions.0.description' => [sprintf('Internal exception: %s',$e->getMessage())],
|
||||
],
|
||||
];
|
||||
|
||||
return response()->json($response, 422);
|
||||
}
|
||||
app('preferences')->mark();
|
||||
event(new StoredTransactionGroup($transactionGroup));
|
||||
event(new StoredTransactionGroup($transactionGroup, $data['apply_rules'] ?? true));
|
||||
|
||||
$manager = $this->getManager();
|
||||
/** @var User $admin */
|
||||
@@ -341,7 +355,7 @@ class TransactionController extends Controller
|
||||
$manager = $this->getManager();
|
||||
|
||||
app('preferences')->mark();
|
||||
event(new UpdatedTransactionGroup($transactionGroup));
|
||||
event(new UpdatedTransactionGroup($transactionGroup, $data['apply_rules'] ?? true));
|
||||
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
|
@@ -47,6 +47,7 @@ class TransactionStoreRequest extends Request
|
||||
public function authorize(): bool
|
||||
{
|
||||
Log::debug('Authorize TransactionStoreRequest');
|
||||
|
||||
// Only allow authenticated users
|
||||
return auth()->check();
|
||||
}
|
||||
@@ -62,6 +63,7 @@ class TransactionStoreRequest extends Request
|
||||
$data = [
|
||||
'group_title' => $this->string('group_title'),
|
||||
'error_if_duplicate_hash' => $this->boolean('error_if_duplicate_hash'),
|
||||
'apply_rules' => $this->boolean('apply_rules', true),
|
||||
'transactions' => $this->getTransactionData(),
|
||||
];
|
||||
|
||||
@@ -80,6 +82,7 @@ class TransactionStoreRequest extends Request
|
||||
// basic fields for group:
|
||||
'group_title' => 'between:1,1000|nullable',
|
||||
'error_if_duplicate_hash' => [new IsBoolean],
|
||||
'apply_rules' => [new IsBoolean],
|
||||
|
||||
// transaction rules (in array for splits):
|
||||
'transactions.*.type' => 'required|in:withdrawal,deposit,transfer,opening-balance,reconciliation',
|
||||
|
@@ -138,6 +138,7 @@ class TransactionUpdateRequest extends Request
|
||||
|
||||
$data = [
|
||||
'transactions' => $this->getTransactionData(),
|
||||
'apply_rules' => $this->boolean('apply_rules', true),
|
||||
];
|
||||
if ($this->has('group_title')) {
|
||||
$data['group_title'] = $this->string('group_title');
|
||||
@@ -156,6 +157,7 @@ class TransactionUpdateRequest extends Request
|
||||
$rules = [
|
||||
// basic fields for group:
|
||||
'group_title' => 'between:1,1000',
|
||||
'apply_rules' => [new IsBoolean],
|
||||
|
||||
// transaction rules (in array for splits):
|
||||
'transactions.*.type' => 'in:withdrawal,deposit,transfer,opening-balance,reconciliation',
|
||||
|
@@ -25,6 +25,9 @@ namespace FireflyIII\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
/**
|
||||
* Class SetLatestVersion
|
||||
*/
|
||||
class SetLatestVersion extends Command
|
||||
{
|
||||
/**
|
||||
@@ -53,19 +56,22 @@ class SetLatestVersion extends Command
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
public function handle(): int
|
||||
{
|
||||
if (!$this->option('james-is-cool')) {
|
||||
$this->error('Am too!');
|
||||
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
app('fireflyconfig')->set('db_version', config('firefly.db_version'));
|
||||
app('fireflyconfig')->set('ff3_version', config('firefly.version'));
|
||||
$this->line('Updated version.');
|
||||
|
||||
//Telemetry::string('db_version', config('firefly.db_version'));
|
||||
//Telemetry::string('ff3_version', config('firefly.version'));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@@ -36,6 +36,7 @@ class StoredTransactionGroup extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/** @var bool */
|
||||
public $applyRules;
|
||||
/** @var TransactionGroup The group that was stored. */
|
||||
public $transactionGroup;
|
||||
|
@@ -37,6 +37,8 @@ class UpdatedTransactionGroup extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/** @var bool */
|
||||
public $applyRules;
|
||||
/** @var TransactionGroup The group that was stored. */
|
||||
public $transactionGroup;
|
||||
|
||||
@@ -45,8 +47,9 @@ class UpdatedTransactionGroup extends Event
|
||||
*
|
||||
* @param TransactionGroup $transactionGroup
|
||||
*/
|
||||
public function __construct(TransactionGroup $transactionGroup)
|
||||
public function __construct(TransactionGroup $transactionGroup, bool $applyRules = true)
|
||||
{
|
||||
$this->transactionGroup = $transactionGroup;
|
||||
$this->applyRules = $applyRules;
|
||||
}
|
||||
}
|
||||
|
@@ -30,6 +30,7 @@ use FireflyIII\Models\Attachment;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -225,6 +226,10 @@ class GracefulNotFoundHandler extends ExceptionHandler
|
||||
$type = $journal->transactionType->type;
|
||||
$request->session()->reflash();
|
||||
|
||||
if (TransactionType::RECONCILIATION === $type) {
|
||||
return redirect(route('accounts.index', ['asset']));
|
||||
}
|
||||
|
||||
return redirect(route('transactions.index', [strtolower($type)]));
|
||||
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
@@ -102,12 +103,17 @@ class TransactionFactory
|
||||
/**
|
||||
* Create transaction with negative amount (for source accounts).
|
||||
*
|
||||
* @param string $amount
|
||||
* @param string $amount
|
||||
* @param string|null $foreignAmount
|
||||
* @return Transaction|null
|
||||
*
|
||||
* @return Transaction
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function createNegative(string $amount, ?string $foreignAmount): ?Transaction
|
||||
public function createNegative(string $amount, ?string $foreignAmount): Transaction
|
||||
{
|
||||
if ('' === $foreignAmount) {
|
||||
$foreignAmount = null;
|
||||
}
|
||||
if (null !== $foreignAmount) {
|
||||
$foreignAmount = app('steam')->negative($foreignAmount);
|
||||
}
|
||||
@@ -118,16 +124,20 @@ class TransactionFactory
|
||||
/**
|
||||
* Create transaction with positive amount (for destination accounts).
|
||||
*
|
||||
* @param string $amount
|
||||
* @param string $amount
|
||||
* @param string|null $foreignAmount
|
||||
* @return Transaction|null
|
||||
*
|
||||
* @return Transaction
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function createPositive(string $amount, ?string $foreignAmount): ?Transaction
|
||||
public function createPositive(string $amount, ?string $foreignAmount): Transaction
|
||||
{
|
||||
if ('' === $foreignAmount) {
|
||||
$foreignAmount = null;
|
||||
}
|
||||
if (null !== $foreignAmount) {
|
||||
$foreignAmount = app('steam')->positive($foreignAmount);
|
||||
}
|
||||
|
||||
return $this->create(app('steam')->positive($amount), $foreignAmount);
|
||||
}
|
||||
|
||||
@@ -151,14 +161,19 @@ class TransactionFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $amount
|
||||
* @param string $amount
|
||||
* @param string|null $foreignAmount
|
||||
* @return Transaction|null
|
||||
*
|
||||
* @return Transaction
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function create(string $amount, ?string $foreignAmount): ?Transaction
|
||||
private function create(string $amount, ?string $foreignAmount): Transaction
|
||||
{
|
||||
$result = null;
|
||||
$data = [
|
||||
if ('' === $foreignAmount) {
|
||||
$foreignAmount = null;
|
||||
}
|
||||
$data = [
|
||||
'reconciled' => $this->reconciled,
|
||||
'account_id' => $this->account->id,
|
||||
'transaction_journal_id' => $this->journal->id,
|
||||
@@ -174,6 +189,12 @@ class TransactionFactory
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (QueryException $e) {
|
||||
Log::error(sprintf('Could not create transaction: %s', $e->getMessage()), $data);
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException('Query exception when creating transaction.');
|
||||
}
|
||||
if (null === $result) {
|
||||
throw new FireflyException('Transaction is NULL.');
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
if (null !== $result) {
|
||||
@@ -185,7 +206,7 @@ class TransactionFactory
|
||||
);
|
||||
|
||||
// do foreign currency thing: add foreign currency info to $one and $two if necessary.
|
||||
if (null !== $this->foreignCurrency && null !== $foreignAmount && $this->foreignCurrency->id !== $this->currency->id) {
|
||||
if (null !== $this->foreignCurrency && null !== $foreignAmount && $this->foreignCurrency->id !== $this->currency->id && '' !== $foreignAmount) {
|
||||
$result->foreign_currency_id = $this->foreignCurrency->id;
|
||||
$result->foreign_amount = $foreignAmount;
|
||||
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\User;
|
||||
use Log;
|
||||
@@ -60,7 +61,6 @@ class TransactionGroupFactory
|
||||
{
|
||||
$this->journalFactory->setUser($this->user);
|
||||
$this->journalFactory->setErrorOnHash($data['error_if_duplicate_hash'] ?? false);
|
||||
|
||||
try {
|
||||
$collection = $this->journalFactory->create($data);
|
||||
} catch(DuplicateTransactionException $e) {
|
||||
|
@@ -29,6 +29,7 @@ use Exception;
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionJournalMeta;
|
||||
@@ -40,6 +41,7 @@ use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface;
|
||||
use FireflyIII\Services\Internal\Destroy\JournalDestroyService;
|
||||
use FireflyIII\Services\Internal\Support\JournalServiceTrait;
|
||||
use FireflyIII\Support\NullArrayObject;
|
||||
use FireflyIII\User;
|
||||
@@ -125,6 +127,7 @@ class TransactionJournalFactory
|
||||
*
|
||||
* @return Collection
|
||||
* @throws DuplicateTransactionException
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function create(array $data): Collection
|
||||
{
|
||||
@@ -139,24 +142,30 @@ class TransactionJournalFactory
|
||||
|
||||
return new Collection;
|
||||
}
|
||||
|
||||
/** @var array $row */
|
||||
foreach ($transactions as $index => $row) {
|
||||
Log::debug(sprintf('Now creating journal %d/%d', $index + 1, count($transactions)));
|
||||
|
||||
Log::debug('Going to call createJournal', $row);
|
||||
try {
|
||||
try {
|
||||
/** @var array $row */
|
||||
foreach ($transactions as $index => $row) {
|
||||
Log::debug(sprintf('Now creating journal %d/%d', $index + 1, count($transactions)));
|
||||
$journal = $this->createJournal(new NullArrayObject($row));
|
||||
} catch (DuplicateTransactionException|Exception $e) {
|
||||
Log::warning('TransactionJournalFactory::create() caught a duplicate journal in createJournal()');
|
||||
throw new DuplicateTransactionException($e->getMessage());
|
||||
}
|
||||
if (null !== $journal) {
|
||||
$collection->push($journal);
|
||||
}
|
||||
if (null === $journal) {
|
||||
Log::error('The createJournal() method returned NULL. This may indicate an error.');
|
||||
if (null !== $journal) {
|
||||
$collection->push($journal);
|
||||
}
|
||||
if (null === $journal) {
|
||||
Log::error('The createJournal() method returned NULL. This may indicate an error.');
|
||||
}
|
||||
}
|
||||
} catch (DuplicateTransactionException $e) {
|
||||
Log::warning('TransactionJournalFactory::create() caught a duplicate journal in createJournal()');
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
$this->forceDeleteOnError($collection);
|
||||
throw new DuplicateTransactionException($e->getMessage());
|
||||
} catch (FireflyException $e) {
|
||||
Log::warning('TransactionJournalFactory::create() caught an exception.');
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
$this->forceDeleteOnError($collection);
|
||||
throw new FireflyException($e->getMessage());
|
||||
}
|
||||
|
||||
return $collection;
|
||||
@@ -204,7 +213,7 @@ class TransactionJournalFactory
|
||||
* @param NullArrayObject $row
|
||||
*
|
||||
* @return TransactionJournal|null
|
||||
* @throws Exception
|
||||
* @throws FireflyException
|
||||
* @throws DuplicateTransactionException
|
||||
*/
|
||||
private function createJournal(NullArrayObject $row): ?TransactionJournal
|
||||
@@ -232,36 +241,33 @@ class TransactionJournalFactory
|
||||
try {
|
||||
// validate source and destination using a new Validator.
|
||||
$this->validateAccounts($row);
|
||||
/** create or get source and destination accounts */
|
||||
|
||||
$sourceInfo = [
|
||||
'id' => (int)$row['source_id'],
|
||||
'name' => $row['source_name'],
|
||||
'iban' => $row['source_iban'],
|
||||
'number' => $row['source_number'],
|
||||
'bic' => $row['source_bic'],
|
||||
];
|
||||
|
||||
$destInfo = [
|
||||
'id' => (int)$row['destination_id'],
|
||||
'name' => $row['destination_name'],
|
||||
'iban' => $row['destination_iban'],
|
||||
'number' => $row['destination_number'],
|
||||
'bic' => $row['destination_bic'],
|
||||
];
|
||||
Log::debug('Source info:', $sourceInfo);
|
||||
Log::debug('Destination info:', $destInfo);
|
||||
|
||||
$sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo);
|
||||
$destinationAccount = $this->getAccount($type->type, 'destination', $destInfo);
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (FireflyException $e) {
|
||||
Log::error('Could not validate source or destination.');
|
||||
Log::error($e->getMessage());
|
||||
|
||||
return null;
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
/** create or get source and destination accounts */
|
||||
$sourceInfo = [
|
||||
'id' => (int)$row['source_id'],
|
||||
'name' => $row['source_name'],
|
||||
'iban' => $row['source_iban'],
|
||||
'number' => $row['source_number'],
|
||||
'bic' => $row['source_bic'],
|
||||
];
|
||||
|
||||
$destInfo = [
|
||||
'id' => (int)$row['destination_id'],
|
||||
'name' => $row['destination_name'],
|
||||
'iban' => $row['destination_iban'],
|
||||
'number' => $row['destination_number'],
|
||||
'bic' => $row['destination_bic'],
|
||||
];
|
||||
Log::debug('Source info:', $sourceInfo);
|
||||
Log::debug('Destination info:', $destInfo);
|
||||
|
||||
$sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo);
|
||||
$destinationAccount = $this->getAccount($type->type, 'destination', $destInfo);
|
||||
|
||||
// TODO AFTER 4.8,0 better handling below:
|
||||
|
||||
@@ -337,7 +343,15 @@ class TransactionJournalFactory
|
||||
$transactionFactory->setCurrency($sourceCurrency);
|
||||
$transactionFactory->setForeignCurrency($sourceForeignCurrency);
|
||||
$transactionFactory->setReconciled($row['reconciled'] ?? false);
|
||||
$transactionFactory->createNegative((string)$row['amount'], (string)$row['foreign_amount']);
|
||||
try {
|
||||
$negative = $transactionFactory->createNegative((string)$row['amount'], (string)$row['foreign_amount']);
|
||||
} catch (FireflyException $e) {
|
||||
Log::error('Exception creating negative transaction.');
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
$this->forceDeleteOnError(new Collection([$journal]));
|
||||
throw new FireflyException($e->getMessage());
|
||||
}
|
||||
|
||||
// and the destination one:
|
||||
/** @var TransactionFactory $transactionFactory */
|
||||
@@ -348,7 +362,18 @@ class TransactionJournalFactory
|
||||
$transactionFactory->setCurrency($destCurrency);
|
||||
$transactionFactory->setForeignCurrency($destForeignCurrency);
|
||||
$transactionFactory->setReconciled($row['reconciled'] ?? false);
|
||||
$transactionFactory->createPositive((string)$row['amount'], (string)$row['foreign_amount']);
|
||||
try {
|
||||
$transactionFactory->createPositive((string)$row['amount'], (string)$row['foreign_amount']);
|
||||
} catch (FireflyException $e) {
|
||||
Log::error('Exception creating positive transaction.');
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
Log::warning('Delete negative transaction.');
|
||||
$this->forceTrDelete($negative);
|
||||
$this->forceDeleteOnError(new Collection([$journal]));
|
||||
throw new FireflyException($e->getMessage());
|
||||
}
|
||||
|
||||
|
||||
// verify that journal has two transactions. Otherwise, delete and cancel.
|
||||
// TODO this can't be faked so it can't be tested.
|
||||
@@ -418,6 +443,37 @@ class TransactionJournalFactory
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the deletion of an entire set of transaction journals and their meta object in case of
|
||||
* an error creating a group.
|
||||
*
|
||||
* @param Collection $collection
|
||||
*/
|
||||
private function forceDeleteOnError(Collection $collection): void
|
||||
{
|
||||
Log::debug(sprintf('forceDeleteOnError on collection size %d item(s)', $collection->count()));
|
||||
$service = app(JournalDestroyService::class);
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($collection as $journal) {
|
||||
Log::debug(sprintf('forceDeleteOnError on journal #%d', $journal->id));
|
||||
$service->destroy($journal);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Transaction $transaction
|
||||
*/
|
||||
private function forceTrDelete(Transaction $transaction): void
|
||||
{
|
||||
try {
|
||||
$transaction->delete();
|
||||
} catch (Exception $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
Log::error('Could not delete negative transaction.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency|null $currency
|
||||
* @param Account $account
|
||||
|
@@ -35,21 +35,23 @@ class StoredGroupEventHandler
|
||||
/**
|
||||
* This method grabs all the users rules and processes them.
|
||||
*
|
||||
* @param StoredTransactionGroup $storedJournalEvent
|
||||
* @param StoredTransactionGroup $storedGroupEvent
|
||||
*/
|
||||
public function processRules(StoredTransactionGroup $storedJournalEvent): void
|
||||
public function processRules(StoredTransactionGroup $storedGroupEvent): void
|
||||
{
|
||||
if (false === $storedJournalEvent->applyRules) {
|
||||
if (false === $storedGroupEvent->applyRules) {
|
||||
Log::info(sprintf('Will not run rules on group #%d', $storedGroupEvent->transactionGroup->id));
|
||||
|
||||
return;
|
||||
}
|
||||
Log::debug('Now in StoredGroupEventHandler::processRules()');
|
||||
|
||||
/** @var RuleEngine $ruleEngine */
|
||||
$ruleEngine = app(RuleEngine::class);
|
||||
$ruleEngine->setUser($storedJournalEvent->transactionGroup->user);
|
||||
$ruleEngine->setUser($storedGroupEvent->transactionGroup->user);
|
||||
$ruleEngine->setAllRules(true);
|
||||
$ruleEngine->setTriggerMode(RuleEngine::TRIGGER_STORE);
|
||||
$journals = $storedJournalEvent->transactionGroup->transactionJournals;
|
||||
$journals = $storedGroupEvent->transactionGroup->transactionJournals;
|
||||
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($journals as $journal) {
|
||||
|
@@ -35,16 +35,22 @@ class UpdatedGroupEventHandler
|
||||
/**
|
||||
* This method will check all the rules when a journal is updated.
|
||||
*
|
||||
* @param UpdatedTransactionGroup $updatedJournalEvent
|
||||
* @param UpdatedTransactionGroup $updatedGroupEvent
|
||||
*/
|
||||
public function processRules(UpdatedTransactionGroup $updatedJournalEvent): void
|
||||
public function processRules(UpdatedTransactionGroup $updatedGroupEvent): void
|
||||
{
|
||||
if (false === $updatedGroupEvent->applyRules) {
|
||||
Log::info(sprintf('Will not run rules on group #%d', $updatedGroupEvent->transactionGroup->id));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var RuleEngine $ruleEngine */
|
||||
$ruleEngine = app(RuleEngine::class);
|
||||
$ruleEngine->setUser($updatedJournalEvent->transactionGroup->user);
|
||||
$ruleEngine->setUser($updatedGroupEvent->transactionGroup->user);
|
||||
$ruleEngine->setAllRules(true);
|
||||
$ruleEngine->setTriggerMode(RuleEngine::TRIGGER_UPDATE);
|
||||
$journals = $updatedJournalEvent->transactionGroup->transactionJournals;
|
||||
$journals = $updatedGroupEvent->transactionGroup->transactionJournals;
|
||||
|
||||
/** @var TransactionJournal $journal */
|
||||
foreach ($journals as $journal) {
|
||||
|
78
app/Http/Controllers/Admin/TelemetryController.php
Normal file
78
app/Http/Controllers/Admin/TelemetryController.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
/**
|
||||
* TelemetryController.php
|
||||
* Copyright (c) 2020 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Admin;
|
||||
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
|
||||
/**
|
||||
* Class TelemetryController
|
||||
*/
|
||||
class TelemetryController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->middleware(
|
||||
static function ($request, $next) {
|
||||
app('view')->share('title', (string)trans('firefly.administration'));
|
||||
app('view')->share('mainTitleIcon', 'fa-hand-spock-o');
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
session()->flash('info', 'No telemetry to delete. Does not work yet.');
|
||||
|
||||
return redirect(route('admin.telemetry.index'));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
app('view')->share('subTitleIcon', 'fa-eye');
|
||||
app('view')->share('subTitle', (string)trans('firefly.telemetry_admin_index'));
|
||||
$version = config('firefly.version');
|
||||
$enabled = config('firefly.telemetry', false);
|
||||
$count = 1;
|
||||
|
||||
return view('admin.telemetry.index', compact('version', 'enabled', 'count'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function view()
|
||||
{
|
||||
return view('admin.telemetry.view');
|
||||
}
|
||||
|
||||
}
|
@@ -78,7 +78,7 @@ class ResetPasswordController extends Controller
|
||||
$rules = [
|
||||
'token' => 'required',
|
||||
'email' => 'required|email',
|
||||
'password' => 'required|confirmed|min:6|secure_password',
|
||||
'password' => 'required|confirmed|min:16|secure_password',
|
||||
];
|
||||
|
||||
$this->validate($request, $rules, $this->validationErrorMessages());
|
||||
|
@@ -34,6 +34,20 @@ use Preferences;
|
||||
*/
|
||||
class TwoFactorController extends Controller
|
||||
{
|
||||
/**
|
||||
* What to do if 2FA lost?
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function lostTwoFactor()
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
$siteOwner = config('firefly.site_owner');
|
||||
$title = (string)trans('firefly.two_factor_forgot_title');
|
||||
return view('auth.lost-two-factor', compact('user', 'siteOwner', 'title'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
@@ -118,27 +132,6 @@ class TwoFactorController extends Controller
|
||||
Preferences::set('mfa_history', $newHistory);
|
||||
}
|
||||
|
||||
/**
|
||||
* What to do if 2FA lost?
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function lostTwoFactor()
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
$siteOwner = config('firefly.site_owner');
|
||||
$title = (string)trans('firefly.two_factor_forgot_title');
|
||||
|
||||
Log::info(
|
||||
'To reset the two factor authentication for user #' . $user->id .
|
||||
' (' . $user->email . '), simply open the "preferences" table and delete the entries with the names "twoFactorAuthEnabled" and' .
|
||||
' "twoFactorAuthSecret" for user_id ' . $user->id . '. That will take care of it.'
|
||||
);
|
||||
|
||||
return view('auth.lost-two-factor', compact('user', 'siteOwner', 'title'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Each MFA history has a timestamp and a code, saving the MFA entries for 5 minutes. So if the
|
||||
* submitted MFA code has been submitted in the last 5 minutes, it won't work despite being valid.
|
||||
|
@@ -59,8 +59,6 @@ class BoxController extends Controller
|
||||
*/
|
||||
public function available(): JsonResponse
|
||||
{
|
||||
/** @var BudgetRepositoryInterface $repository */
|
||||
$repository = app(BudgetRepositoryInterface::class);
|
||||
/** @var OperationsRepositoryInterface $opsRepository */
|
||||
$opsRepository = app(OperationsRepositoryInterface::class);
|
||||
/** @var AvailableBudgetRepositoryInterface $abRepository */
|
||||
@@ -102,13 +100,12 @@ class BoxController extends Controller
|
||||
$spent = $opsRepository->sumExpenses($start, $end, null, null, $currency);
|
||||
$spentAmount = $spent[(int)$currency->id]['sum'] ?? '0';
|
||||
$spentPerDay = '-1';
|
||||
if (1 === $availableBudgets->count()) {
|
||||
if ($availableBudgets->count() > 0) {
|
||||
$display = 0; // assume user overspent
|
||||
$boxTitle = (string)trans('firefly.overspent');
|
||||
/** @var AvailableBudget $availableBudget */
|
||||
$availableBudget = $availableBudgets->first();
|
||||
$totalAvailableSum = (string)$availableBudgets->sum('amount');
|
||||
// calculate with available budget.
|
||||
$leftToSpendAmount = bcadd($availableBudget->amount, $spentAmount);
|
||||
$leftToSpendAmount = bcadd($totalAvailableSum, $spentAmount);
|
||||
if (1 === bccomp($leftToSpendAmount, '0')) {
|
||||
$boxTitle = (string)trans('firefly.left_to_spend');
|
||||
$days = $today->diffInDays($end) + 1;
|
||||
|
@@ -22,6 +22,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
@@ -59,10 +60,29 @@ class PreferencesController extends Controller
|
||||
*/
|
||||
public function index(AccountRepositoryInterface $repository)
|
||||
{
|
||||
$accounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
|
||||
$accounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
|
||||
|
||||
// group accounts
|
||||
$groupedAccounts = [];
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$type = $account->accountType->type;
|
||||
$role = sprintf('opt_group_%s', $repository->getMetaValue($account, 'account_role'));
|
||||
|
||||
if (in_array($type, [AccountType::MORTGAGE, AccountType::DEBT, AccountType::LOAN], true)) {
|
||||
$role = sprintf('opt_group_l_%s',$type);
|
||||
}
|
||||
|
||||
if ('' === $role || 'opt_group_' === $role) {
|
||||
$role = 'opt_group_defaultAsset';
|
||||
}
|
||||
$groupedAccounts[trans(sprintf('firefly.%s',$role))][$account->id] = $account->name;
|
||||
}
|
||||
ksort($groupedAccounts);
|
||||
|
||||
$accountIds = $accounts->pluck('id')->toArray();
|
||||
$viewRangePref = app('preferences')->get('viewRange', '1M');
|
||||
/** @noinspection NullPointerExceptionInspection */
|
||||
|
||||
$viewRange = $viewRangePref->data;
|
||||
$frontPageAccounts = app('preferences')->get('frontPageAccounts', $accountIds);
|
||||
$language = app('preferences')->get('language', config('firefly.default_language', 'en_US'))->data;
|
||||
@@ -82,7 +102,7 @@ class PreferencesController extends Controller
|
||||
'preferences.index',
|
||||
compact(
|
||||
'language',
|
||||
'accounts',
|
||||
'groupedAccounts',
|
||||
'frontPageAccounts',
|
||||
'tjOptionalFields',
|
||||
'viewRange',
|
||||
@@ -135,7 +155,7 @@ class PreferencesController extends Controller
|
||||
// language:
|
||||
/** @var Preference $currentLang */
|
||||
$currentLang = app('preferences')->get('language', 'en_US');
|
||||
$lang = $request->get('language');
|
||||
$lang = $request->get('language');
|
||||
if (array_key_exists($lang, config('firefly.languages'))) {
|
||||
app('preferences')->set('language', $lang);
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Generator\Report\ReportGeneratorFactory;
|
||||
use FireflyIII\Helpers\Report\ReportHelperInterface;
|
||||
use FireflyIII\Http\Requests\ReportFormRequest;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
@@ -262,11 +263,32 @@ class ReportController extends Controller
|
||||
$start = clone session('first');
|
||||
$months = $this->helper->listOfMonths($start);
|
||||
$customFiscalYear = app('preferences')->get('customFiscalYear', 0)->data;
|
||||
$accounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
|
||||
$accounts = $repository->getAccountsByType(
|
||||
[AccountType::DEFAULT, AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE]
|
||||
);
|
||||
|
||||
// group accounts by role:
|
||||
$groupedAccounts = [];
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$type = $account->accountType->type;
|
||||
$role = sprintf('opt_group_%s', $repository->getMetaValue($account, 'account_role'));
|
||||
|
||||
if (in_array($type, [AccountType::MORTGAGE, AccountType::DEBT, AccountType::LOAN], true)) {
|
||||
$role = sprintf('opt_group_l_%s',$type);
|
||||
}
|
||||
|
||||
if ('' === $role || 'opt_group_' === $role) {
|
||||
$role = 'opt_group_defaultAsset';
|
||||
}
|
||||
$groupedAccounts[trans(sprintf('firefly.%s',$role))][$account->id] = $account;
|
||||
}
|
||||
ksort($groupedAccounts);
|
||||
|
||||
$accountList = implode(',', $accounts->pluck('id')->toArray());
|
||||
$this->repository->cleanupBudgets();
|
||||
|
||||
return view('reports.index', compact('months', 'accounts', 'start', 'accountList', 'customFiscalYear'));
|
||||
return view('reports.index', compact('months', 'accounts', 'start', 'accountList','groupedAccounts', 'customFiscalYear'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -90,6 +90,9 @@ class CreateController extends Controller
|
||||
{
|
||||
app('preferences')->mark();
|
||||
|
||||
$sourceId = (int)request()->get('source');
|
||||
$destinationId = (int)request()->get('destination');
|
||||
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$cash = $repository->getCashAccount();
|
||||
@@ -112,7 +115,7 @@ class CreateController extends Controller
|
||||
'transactions.create', compact(
|
||||
'subTitleIcon', 'cash', 'objectType', 'subTitle', 'defaultCurrency', 'previousUri', 'optionalFields', 'preFilled',
|
||||
'allowedOpposingTypes',
|
||||
'accountToTypes'
|
||||
'accountToTypes','sourceId','destinationId'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@@ -81,8 +81,8 @@ class ShowController extends Controller
|
||||
public function show(Request $request, TransactionGroup $transactionGroup)
|
||||
{
|
||||
/** @var TransactionJournal $first */
|
||||
$first = $transactionGroup->transactionJournals->first();
|
||||
$splits = $transactionGroup->transactionJournals->count();
|
||||
$first = $transactionGroup->transactionJournals()->first(['transaction_journals.*']);
|
||||
$splits = $transactionGroup->transactionJournals()->count();
|
||||
|
||||
if(null === $first) {
|
||||
throw new FireflyException('This transaction is broken :(.');
|
||||
|
@@ -58,6 +58,7 @@ use FireflyIII\Support\Form\RuleForm;
|
||||
use FireflyIII\Support\Navigation;
|
||||
use FireflyIII\Support\Preferences;
|
||||
use FireflyIII\Support\Steam;
|
||||
use FireflyIII\Support\Telemetry;
|
||||
use FireflyIII\Validation\FireflyValidator;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Validator;
|
||||
@@ -91,33 +92,33 @@ class FireflyServiceProvider extends ServiceProvider
|
||||
{
|
||||
$this->app->bind(
|
||||
'preferences',
|
||||
function () {
|
||||
static function () {
|
||||
return new Preferences;
|
||||
}
|
||||
);
|
||||
|
||||
$this->app->bind(
|
||||
'fireflyconfig',
|
||||
function () {
|
||||
static function () {
|
||||
return new FireflyConfig;
|
||||
}
|
||||
);
|
||||
$this->app->bind(
|
||||
'navigation',
|
||||
function () {
|
||||
static function () {
|
||||
return new Navigation;
|
||||
}
|
||||
);
|
||||
$this->app->bind(
|
||||
'amount',
|
||||
function () {
|
||||
static function () {
|
||||
return new Amount;
|
||||
}
|
||||
);
|
||||
|
||||
$this->app->bind(
|
||||
'steam',
|
||||
function () {
|
||||
static function () {
|
||||
return new Steam;
|
||||
}
|
||||
);
|
||||
@@ -155,6 +156,13 @@ class FireflyServiceProvider extends ServiceProvider
|
||||
}
|
||||
);
|
||||
|
||||
$this->app->bind(
|
||||
'telemetry',
|
||||
static function () {
|
||||
return new Telemetry;
|
||||
}
|
||||
);
|
||||
|
||||
// chart generator:
|
||||
$this->app->bind(GeneratorInterface::class, ChartJsGenerator::class);
|
||||
|
||||
|
@@ -332,6 +332,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
||||
*
|
||||
* @return TransactionGroup
|
||||
* @throws DuplicateTransactionException
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): TransactionGroup
|
||||
{
|
||||
@@ -343,6 +344,10 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
||||
} catch (DuplicateTransactionException $e) {
|
||||
Log::warning('Group repository caught group factory with a duplicate exception!');
|
||||
throw new DuplicateTransactionException($e->getMessage());
|
||||
} catch(FireflyException $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException($e->getMessage());
|
||||
}
|
||||
|
||||
|
||||
|
41
app/Support/Facades/Telemetry.php
Normal file
41
app/Support/Facades/Telemetry.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/**
|
||||
* Amount.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\Facades;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
/**
|
||||
* Class Telemetry
|
||||
*/
|
||||
class Telemetry extends Facade
|
||||
{
|
||||
/**
|
||||
* Get the registered name of the component.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getFacadeAccessor(): string
|
||||
{
|
||||
return 'telemetry';
|
||||
}
|
||||
}
|
@@ -312,7 +312,7 @@ class Search implements SearchInterface
|
||||
{
|
||||
$parts = explode(':', $string);
|
||||
if (2 === count($parts) && '' !== trim((string)$parts[1]) && '' !== trim((string)$parts[0])) {
|
||||
$type = trim((string)$parts[0]);
|
||||
$type = strtolower(trim((string)$parts[0]));
|
||||
$value = trim((string)$parts[1]);
|
||||
$value = trim(trim($value, '"\''));
|
||||
if (in_array($type, $this->validModifiers, true)) {
|
||||
|
81
app/Support/Telemetry.php
Normal file
81
app/Support/Telemetry.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* Telemetry.php
|
||||
* Copyright (c) 2020 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Support;
|
||||
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class Telemetry
|
||||
*/
|
||||
class Telemetry
|
||||
{
|
||||
/**
|
||||
* Feature telemetry stores a boolean "true" for the given $flag.
|
||||
*
|
||||
* Examples:
|
||||
* - use-help-pages
|
||||
* - has-created-bill
|
||||
* - do-big-import
|
||||
* - first-time-install
|
||||
* - more
|
||||
*
|
||||
* Its use should be limited to exotic and strange use cases in Firefly III.
|
||||
* Because time and date are logged as well, useful to track users' evolution in Firefly III.
|
||||
*
|
||||
* Any meta-data stored is strictly non-financial.
|
||||
*
|
||||
* @param string $flag
|
||||
*/
|
||||
public function feature(string $flag): void
|
||||
{
|
||||
if (false === config('firefly.send_telemetry')) {
|
||||
// hard stop if not allowed to do telemetry.
|
||||
// do nothing!
|
||||
return;
|
||||
}
|
||||
Log::info(sprintf('Logged telemetry feature flag "%s".', $flag));
|
||||
|
||||
// no storage backend yet, do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* String telemetry stores a string value as a telemetry entry. Values could include:
|
||||
*
|
||||
* - "php-version", "php7.3"
|
||||
* - "os-version", "linux"
|
||||
*
|
||||
* Any meta-data stored is strictly non-financial.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
*/
|
||||
public function string(string $name, string $value): void
|
||||
{
|
||||
if (false === config('firefly.send_telemetry')) {
|
||||
// hard stop if not allowed to do telemetry.
|
||||
// do nothing!
|
||||
return;
|
||||
}
|
||||
Log::info(sprintf('Logged telemetry string "%s" with value "%s".', $name, $value));
|
||||
}
|
||||
|
||||
}
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Transformers;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Transaction;
|
||||
@@ -32,6 +33,7 @@ use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
|
||||
use FireflyIII\Support\NullArrayObject;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class TransactionGroupTransformer
|
||||
@@ -98,9 +100,11 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
* @param TransactionGroup $group
|
||||
*
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function transformObject(TransactionGroup $group): array
|
||||
{
|
||||
try {
|
||||
$result = [
|
||||
'id' => (int)$group->id,
|
||||
'created_at' => $group->created_at->toAtomString(),
|
||||
@@ -115,7 +119,11 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
} catch(FireflyException $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException(sprintf('Transaction group #%d is broken. Please check out your log files.', $group->id));
|
||||
}
|
||||
// do something else.
|
||||
|
||||
return $result;
|
||||
@@ -125,36 +133,47 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return Transaction
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getDestinationTransaction(TransactionJournal $journal): Transaction
|
||||
{
|
||||
|
||||
return $journal->transactions->first(
|
||||
$result = $journal->transactions->first(
|
||||
static function (Transaction $transaction) {
|
||||
return (float)$transaction->amount > 0;
|
||||
}
|
||||
);
|
||||
if (null === $result) {
|
||||
throw new FireflyException(sprintf('Journal #%d unexpectedly has no destination transaction.', $journal->id));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
*
|
||||
* @return Transaction
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getSourceTransaction(TransactionJournal $journal): Transaction
|
||||
{
|
||||
|
||||
return $journal->transactions->first(
|
||||
$result = $journal->transactions->first(
|
||||
static function (Transaction $transaction) {
|
||||
return (float)$transaction->amount < 0;
|
||||
}
|
||||
);
|
||||
if (null === $result) {
|
||||
throw new FireflyException(sprintf('Journal #%d unexpectedly has no source transaction.', $journal->id));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $transactionJournals
|
||||
*
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function transformJournals(Collection $transactionJournals): array
|
||||
{
|
||||
|
26
changelog.md
26
changelog.md
@@ -2,7 +2,31 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [5.1.0 (API 1.0.0)] - 2020-03-06
|
||||
## [5.1.1 (API 1.0.2)] - 2020-03-xx
|
||||
|
||||
### Added
|
||||
- [Issue 2672](https://github.com/firefly-iii/firefly-iii/issues/2672) Buttons to create transactions from the list of accounts is back.
|
||||
|
||||
### Changed
|
||||
- [Issue 3176](https://github.com/firefly-iii/firefly-iii/issues/3176) Greek language support is enabled again!
|
||||
|
||||
### Fixed
|
||||
- [Issue 3160](https://github.com/firefly-iii/firefly-iii/issues/3160) Deleting a reconciliation won't send you to a 404.
|
||||
- [Issue 3172](https://github.com/firefly-iii/firefly-iii/issues/3172) Remaining amount left calculation is wrong over multiple months.
|
||||
- [Issue 3173](https://github.com/firefly-iii/firefly-iii/issues/3173) Amount is invisible when viewing transactions.
|
||||
- [Issue 3177](https://github.com/firefly-iii/firefly-iii/issues/3177) Fix attachment breadcrumb.
|
||||
- [Issue 3180](https://github.com/firefly-iii/firefly-iii/issues/3180) Improve instructions for when the user loses MFA info.
|
||||
- [Issue 3182](https://github.com/firefly-iii/firefly-iii/issues/3182) Better fallback when transaction errors out.
|
||||
- Search modifiers are now case insensitive.
|
||||
|
||||
### Security
|
||||
- The minimal password length for new users is now 16 characters.
|
||||
- Have I Been Pwnd check is now enabled by default.
|
||||
|
||||
### API
|
||||
- A new call to `apply_rules` is available when submitting transactions.
|
||||
|
||||
## [5.1.0 (API 1.0.1)] - 2020-03-06
|
||||
|
||||
Before this release came out, several alpha and beta versions had been released already:
|
||||
|
||||
|
122
composer.lock
generated
122
composer.lock
generated
@@ -8,26 +8,26 @@
|
||||
"packages": [
|
||||
{
|
||||
"name": "adldap2/adldap2",
|
||||
"version": "v10.2.2",
|
||||
"version": "v10.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Adldap2/Adldap2.git",
|
||||
"reference": "f09ca4ae3a65dbf123b56dc7e4ace8682ea16cdb"
|
||||
"reference": "2baffac2dfef308f0a94afa360b6a77540730fd2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Adldap2/Adldap2/zipball/f09ca4ae3a65dbf123b56dc7e4ace8682ea16cdb",
|
||||
"reference": "f09ca4ae3a65dbf123b56dc7e4ace8682ea16cdb",
|
||||
"url": "https://api.github.com/repos/Adldap2/Adldap2/zipball/2baffac2dfef308f0a94afa360b6a77540730fd2",
|
||||
"reference": "2baffac2dfef308f0a94afa360b6a77540730fd2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"ext-ldap": "*",
|
||||
"illuminate/contracts": "~5.0|~6.0",
|
||||
"illuminate/contracts": "~5.0|~6.0|~7.0",
|
||||
"php": ">=7.0",
|
||||
"psr/log": "~1.0",
|
||||
"psr/simple-cache": "~1.0",
|
||||
"tightenco/collect": "~5.0|~6.0"
|
||||
"tightenco/collect": "~5.0|~6.0|~7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "~1.0",
|
||||
@@ -63,25 +63,25 @@
|
||||
"ldap",
|
||||
"windows"
|
||||
],
|
||||
"time": "2019-12-18T15:07:31+00:00"
|
||||
"time": "2020-03-08T23:04:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "adldap2/adldap2-laravel",
|
||||
"version": "v6.0.8",
|
||||
"version": "v6.0.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Adldap2/Adldap2-Laravel.git",
|
||||
"reference": "c2809bcca39bd51fe3fbe426c5dc32e89a868a42"
|
||||
"reference": "0c828772333936f4c26c1ce27bd372008eae7e6e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Adldap2/Adldap2-Laravel/zipball/c2809bcca39bd51fe3fbe426c5dc32e89a868a42",
|
||||
"reference": "c2809bcca39bd51fe3fbe426c5dc32e89a868a42",
|
||||
"url": "https://api.github.com/repos/Adldap2/Adldap2-Laravel/zipball/0c828772333936f4c26c1ce27bd372008eae7e6e",
|
||||
"reference": "0c828772333936f4c26c1ce27bd372008eae7e6e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"adldap2/adldap2": "^10.1",
|
||||
"illuminate/support": "~5.5|~6.0",
|
||||
"illuminate/support": "~5.5|~6.0|~7.0",
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
@@ -117,7 +117,7 @@
|
||||
"laravel",
|
||||
"ldap"
|
||||
],
|
||||
"time": "2019-09-03T16:03:04+00:00"
|
||||
"time": "2020-03-08T23:15:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
@@ -1239,7 +1239,7 @@
|
||||
},
|
||||
{
|
||||
"name": "James Cole",
|
||||
"email": "thegrumpydictator@gmail.com",
|
||||
"email": "james@firefly-iii.org",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
@@ -1390,16 +1390,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v6.18.0",
|
||||
"version": "v6.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "077b895d935b7fbcfb1d1eb34217fa4f80a130d8"
|
||||
"reference": "367c2c8dfdfe83cb2ddbc029c0222174098d093a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/077b895d935b7fbcfb1d1eb34217fa4f80a130d8",
|
||||
"reference": "077b895d935b7fbcfb1d1eb34217fa4f80a130d8",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/367c2c8dfdfe83cb2ddbc029c0222174098d093a",
|
||||
"reference": "367c2c8dfdfe83cb2ddbc029c0222174098d093a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1532,7 +1532,7 @@
|
||||
"framework",
|
||||
"laravel"
|
||||
],
|
||||
"time": "2020-03-03T13:14:27+00:00"
|
||||
"time": "2020-03-10T14:11:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/passport",
|
||||
@@ -1925,16 +1925,16 @@
|
||||
},
|
||||
{
|
||||
"name": "league/flysystem",
|
||||
"version": "1.0.64",
|
||||
"version": "1.0.65",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/flysystem.git",
|
||||
"reference": "d13c43dbd4b791f815215959105a008515d1a2e0"
|
||||
"reference": "8f17b3ba67097aafb8318cd5c553b1acf7c891c8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/d13c43dbd4b791f815215959105a008515d1a2e0",
|
||||
"reference": "d13c43dbd4b791f815215959105a008515d1a2e0",
|
||||
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/8f17b3ba67097aafb8318cd5c553b1acf7c891c8",
|
||||
"reference": "8f17b3ba67097aafb8318cd5c553b1acf7c891c8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2005,7 +2005,7 @@
|
||||
"sftp",
|
||||
"storage"
|
||||
],
|
||||
"time": "2020-02-05T18:14:17+00:00"
|
||||
"time": "2020-03-08T18:53:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/flysystem-replicate-adapter",
|
||||
@@ -2989,8 +2989,8 @@
|
||||
"authors": [
|
||||
{
|
||||
"name": "Antonio Carlos Ribeiro",
|
||||
"email": "acr@antoniocarlosribeiro.com",
|
||||
"role": "Creator & Designer"
|
||||
"role": "Creator & Designer",
|
||||
"email": "acr@antoniocarlosribeiro.com"
|
||||
}
|
||||
],
|
||||
"description": "QR Code package for Google2FA",
|
||||
@@ -3049,9 +3049,9 @@
|
||||
"authors": [
|
||||
{
|
||||
"name": "Antonio Carlos Ribeiro",
|
||||
"role": "Developer",
|
||||
"email": "acr@antoniocarlosribeiro.com",
|
||||
"homepage": "https://antoniocarlosribeiro.com",
|
||||
"role": "Developer"
|
||||
"homepage": "https://antoniocarlosribeiro.com"
|
||||
}
|
||||
],
|
||||
"description": "Create random chars, numbers, strings",
|
||||
@@ -3111,9 +3111,9 @@
|
||||
"authors": [
|
||||
{
|
||||
"name": "Antonio Carlos Ribeiro",
|
||||
"role": "Developer",
|
||||
"email": "acr@antoniocarlosribeiro.com",
|
||||
"homepage": "https://antoniocarlosribeiro.com",
|
||||
"role": "Developer"
|
||||
"homepage": "https://antoniocarlosribeiro.com"
|
||||
}
|
||||
],
|
||||
"description": "Create recovery codes for two factor auth",
|
||||
@@ -5230,16 +5230,16 @@
|
||||
},
|
||||
{
|
||||
"name": "tightenco/collect",
|
||||
"version": "v6.17.0",
|
||||
"version": "v7.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/tightenco/collect.git",
|
||||
"reference": "bc554bfb79fc02b4e6e1dd463a7fa8470119e9ab"
|
||||
"reference": "306a4def08c9781ff74fcf1e012f22cbf8686348"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/tightenco/collect/zipball/bc554bfb79fc02b4e6e1dd463a7fa8470119e9ab",
|
||||
"reference": "bc554bfb79fc02b4e6e1dd463a7fa8470119e9ab",
|
||||
"url": "https://api.github.com/repos/tightenco/collect/zipball/306a4def08c9781ff74fcf1e012f22cbf8686348",
|
||||
"reference": "306a4def08c9781ff74fcf1e012f22cbf8686348",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5276,7 +5276,7 @@
|
||||
"collection",
|
||||
"laravel"
|
||||
],
|
||||
"time": "2020-02-25T19:45:47+00:00"
|
||||
"time": "2020-03-09T16:52:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "tijsverkoyen/css-to-inline-styles",
|
||||
@@ -5394,16 +5394,16 @@
|
||||
},
|
||||
{
|
||||
"name": "vlucas/phpdotenv",
|
||||
"version": "v3.6.0",
|
||||
"version": "v3.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vlucas/phpdotenv.git",
|
||||
"reference": "1bdf24f065975594f6a117f0f1f6cabf1333b156"
|
||||
"reference": "8f7961f7b9deb3b432452c18093cf16f88205902"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/1bdf24f065975594f6a117f0f1f6cabf1333b156",
|
||||
"reference": "1bdf24f065975594f6a117f0f1f6cabf1333b156",
|
||||
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/8f7961f7b9deb3b432452c18093cf16f88205902",
|
||||
"reference": "8f7961f7b9deb3b432452c18093cf16f88205902",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5412,8 +5412,12 @@
|
||||
"symfony/polyfill-ctype": "^1.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-filter": "*",
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.0 || ^6.0 || ^7.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-filter": "Required to use the boolean validator."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@@ -5447,7 +5451,7 @@
|
||||
"env",
|
||||
"environment"
|
||||
],
|
||||
"time": "2019-09-10T21:37:39+00:00"
|
||||
"time": "2020-03-12T13:44:00+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
@@ -5629,16 +5633,16 @@
|
||||
},
|
||||
{
|
||||
"name": "composer/composer",
|
||||
"version": "1.9.3",
|
||||
"version": "1.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/composer.git",
|
||||
"reference": "1291a16ce3f48bfdeca39d64fca4875098af4d7b"
|
||||
"reference": "472c917b2a083ec7d2fa25c55fd099d1300e2515"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/composer/zipball/1291a16ce3f48bfdeca39d64fca4875098af4d7b",
|
||||
"reference": "1291a16ce3f48bfdeca39d64fca4875098af4d7b",
|
||||
"url": "https://api.github.com/repos/composer/composer/zipball/472c917b2a083ec7d2fa25c55fd099d1300e2515",
|
||||
"reference": "472c917b2a083ec7d2fa25c55fd099d1300e2515",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5651,17 +5655,17 @@
|
||||
"psr/log": "^1.0",
|
||||
"seld/jsonlint": "^1.4",
|
||||
"seld/phar-utils": "^1.0",
|
||||
"symfony/console": "^2.7 || ^3.0 || ^4.0",
|
||||
"symfony/filesystem": "^2.7 || ^3.0 || ^4.0",
|
||||
"symfony/finder": "^2.7 || ^3.0 || ^4.0",
|
||||
"symfony/process": "^2.7 || ^3.0 || ^4.0"
|
||||
"symfony/console": "^2.7 || ^3.0 || ^4.0 || ^5.0",
|
||||
"symfony/filesystem": "^2.7 || ^3.0 || ^4.0 || ^5.0",
|
||||
"symfony/finder": "^2.7 || ^3.0 || ^4.0 || ^5.0",
|
||||
"symfony/process": "^2.7 || ^3.0 || ^4.0 || ^5.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/console": "2.8.38"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7",
|
||||
"phpunit/phpunit-mock-objects": "^2.3 || ^3.0"
|
||||
"phpspec/prophecy": "^1.10",
|
||||
"symfony/phpunit-bridge": "^3.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages",
|
||||
@@ -5674,7 +5678,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
"dev-master": "1.10-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -5705,7 +5709,7 @@
|
||||
"dependency",
|
||||
"package"
|
||||
],
|
||||
"time": "2020-02-04T11:58:49+00:00"
|
||||
"time": "2020-03-10T13:08:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/semver",
|
||||
@@ -7935,26 +7939,26 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v4.4.5",
|
||||
"version": "v5.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "266c9540b475f26122b61ef8b23dd9198f5d1cfd"
|
||||
"reference": "3afadc0f57cd74f86379d073e694b0f2cda2a88c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/266c9540b475f26122b61ef8b23dd9198f5d1cfd",
|
||||
"reference": "266c9540b475f26122b61ef8b23dd9198f5d1cfd",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/3afadc0f57cd74f86379d073e694b0f2cda2a88c",
|
||||
"reference": "3afadc0f57cd74f86379d073e694b0f2cda2a88c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"php": "^7.2.5",
|
||||
"symfony/polyfill-ctype": "~1.8"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.4-dev"
|
||||
"dev-master": "5.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -7981,7 +7985,7 @@
|
||||
],
|
||||
"description": "Symfony Filesystem Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2020-01-21T08:20:44+00:00"
|
||||
"time": "2020-01-21T08:40:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
|
@@ -134,11 +134,12 @@ return [
|
||||
],
|
||||
'feature_flags' => [
|
||||
'export' => true,
|
||||
'telemetry' => false,
|
||||
],
|
||||
|
||||
'encryption' => null === env('USE_ENCRYPTION') || true === env('USE_ENCRYPTION'),
|
||||
'version' => '5.1.0',
|
||||
'api_version' => '1.0.1',
|
||||
'version' => '5.1.1',
|
||||
'api_version' => '1.0.2',
|
||||
'db_version' => 12,
|
||||
'maxUploadSize' => 15242880,
|
||||
'send_error_message' => env('SEND_ERROR_MESSAGE', true),
|
||||
@@ -160,6 +161,7 @@ return [
|
||||
'login_provider' => envNonEmpty('LOGIN_PROVIDER', 'eloquent'),
|
||||
'cer_provider' => envNonEmpty('CER_PROVIDER', 'fixer'),
|
||||
'update_endpoint' => 'https://version.firefly-iii.org/index.json',
|
||||
'send_telemetry' => env('SEND_TELEMETRY', false),
|
||||
'update_minimum_age' => 6,
|
||||
'default_location' => [
|
||||
'longitude' => env('MAP_DEFAULT_LONG', '5.916667'),
|
||||
@@ -317,6 +319,7 @@ return [
|
||||
// currently enabled languages
|
||||
'en_US' => ['name_locale' => 'English', 'name_english' => 'English'],
|
||||
'cs_CZ' => ['name_locale' => 'Czech', 'name_english' => 'Czech'],
|
||||
'el_GR' => ['name_locale' => 'Ελληνικά', 'name_english' => 'Greek'],
|
||||
'es_ES' => ['name_locale' => 'Español', 'name_english' => 'Spanish'],
|
||||
'de_DE' => ['name_locale' => 'Deutsch', 'name_english' => 'German'],
|
||||
'fr_FR' => ['name_locale' => 'Français', 'name_english' => 'French'],
|
||||
@@ -345,7 +348,7 @@ return [
|
||||
// 'pt_PT' => ['name_locale' => 'Portuguese', 'name_english' => 'Portuguese'],
|
||||
// 'sl_SI' => ['name_locale' => 'Slovenian', 'name_english' => 'Slovenian'],
|
||||
// 'tlh_AA' => ['name_locale' => 'tlhIngan Hol', 'name_english' => 'Klingon'],
|
||||
// 'el_GR' => ['name_locale' => 'Ελληνικά', 'name_english' => 'Greek'],
|
||||
//
|
||||
// 'tr_TR' => ['name_locale' => 'Türkçe', 'name_english' => 'Turkish'],
|
||||
// 'sr_CS' => ['name_locale' => 'Serbian (Latin)', 'name_english' => 'Serbian (Latin)'],
|
||||
// 'uk_UA' => ['name_locale' => 'Ukranian', 'name_english' => 'Ukranian'],
|
||||
|
@@ -70,7 +70,7 @@ return [
|
||||
'allowed_for_user' => [
|
||||
'fake' => false,
|
||||
'file' => true,
|
||||
'bunq' => true,
|
||||
'bunq' => false,
|
||||
'spectre' => true,
|
||||
'ynab' => true,
|
||||
'plaid' => true,
|
||||
@@ -82,7 +82,7 @@ return [
|
||||
'has_prereq' => [
|
||||
'fake' => true,
|
||||
'file' => false,
|
||||
'bunq' => true,
|
||||
'bunq' => false,
|
||||
'spectre' => true,
|
||||
'ynab' => true,
|
||||
'plaid' => true,
|
||||
|
@@ -22,6 +22,5 @@
|
||||
"vue": "^2.6.10",
|
||||
"vue-i18n": "^8.14.1",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
}
|
||||
|
536
public/v1/css/gf-source.css
vendored
536
public/v1/css/gf-source.css
vendored
@@ -1,523 +1,59 @@
|
||||
/*
|
||||
* gf-source.css
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightItalic'), url('../fonts/SourceSansPro-LightItalic-cyrillic-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-LightItalic-cyrillic-ext.woff') format('woff');
|
||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||
}
|
||||
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightItalic'), url('../fonts/SourceSansPro-LightItalic-cyrillic.woff2') format('woff2'), url('../fonts/SourceSansPro-LightItalic-cyrillic.woff') format('woff');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightItalic'), url('../fonts/SourceSansPro-LightItalic-greek-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-LightItalic-greek-ext.woff') format('woff');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightItalic'), url('../fonts/SourceSansPro-LightItalic-greek.woff2') format('woff2'), url('../fonts/SourceSansPro-LightItalic-greek.woff') format('woff');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightItalic'), url('../fonts/SourceSansPro-LightItalic-vietnamese.woff2') format('woff2'), url('../fonts/SourceSansPro-LightItalic-vietnamese.woff') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightItalic'), url('../fonts/SourceSansPro-LightItalic-latin-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-LightItalic-latin-ext.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightItalic'), url('../fonts/SourceSansPro-LightItalic-latin.woff2') format('woff2'), url('../fonts/SourceSansPro-LightItalic-latin.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
||||
}
|
||||
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url('../fonts/SourceSansPro-Italic-cyrillic-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-Italic-cyrillic-ext.woff') format('woff');
|
||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||
}
|
||||
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url('../fonts/SourceSansPro-Italic-cyrillic.woff2') format('woff2'), url('../fonts/SourceSansPro-Italic-cyrillic.woff') format('woff');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url('../fonts/SourceSansPro-Italic-greek-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-Italic-greek-ext.woff') format('woff');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url('../fonts/SourceSansPro-Italic-greek.woff2') format('woff2'), url('../fonts/SourceSansPro-Italic-greek.woff') format('woff');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url('../fonts/SourceSansPro-Italic-vietnamese.woff2') format('woff2'), url('../fonts/SourceSansPro-Italic-vietnamese.woff') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url('../fonts/SourceSansPro-Italic-latin-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-Italic-latin-ext.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url('../fonts/SourceSansPro-Italic-latin.woff2') format('woff2'), url('../fonts/SourceSansPro-Italic-latin.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
||||
}
|
||||
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro SemiBold Italic'), local('SourceSansPro-SemiBoldItalic'), url('../fonts/SourceSansPro-SemiBoldItalic-cyrillic-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-SemiBoldItalic-cyrillic-ext.woff') format('woff');
|
||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||
}
|
||||
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro SemiBold Italic'), local('SourceSansPro-SemiBoldItalic'), url('../fonts/SourceSansPro-SemiBoldItalic-cyrillic.woff2') format('woff2'), url('../fonts/SourceSansPro-SemiBoldItalic-cyrillic.woff') format('woff');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro SemiBold Italic'), local('SourceSansPro-SemiBoldItalic'), url('../fonts/SourceSansPro-SemiBoldItalic-greek-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-SemiBoldItalic-greek-ext.woff') format('woff');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro SemiBold Italic'), local('SourceSansPro-SemiBoldItalic'), url('../fonts/SourceSansPro-SemiBoldItalic-greek.woff2') format('woff2'), url('../fonts/SourceSansPro-SemiBoldItalic-greek.woff') format('woff');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro SemiBold Italic'), local('SourceSansPro-SemiBoldItalic'), url('../fonts/SourceSansPro-SemiBoldItalic-vietnamese.woff2') format('woff2'), url('../fonts/SourceSansPro-SemiBoldItalic-vietnamese.woff') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro SemiBold Italic'), local('SourceSansPro-SemiBoldItalic'), url('../fonts/SourceSansPro-SemiBoldItalic-latin-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-SemiBoldItalic-latin-ext.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro SemiBold Italic'), local('SourceSansPro-SemiBoldItalic'), url('../fonts/SourceSansPro-SemiBoldItalic-latin.woff2') format('woff2'), url('../fonts/SourceSansPro-SemiBoldItalic-latin.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
||||
}
|
||||
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold Italic'), local('SourceSansPro-BoldItalic'), url('../fonts/SourceSansPro-BoldItalic-cyrillic-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-BoldItalic-cyrillic-ext.woff') format('woff');
|
||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||
}
|
||||
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold Italic'), local('SourceSansPro-BoldItalic'), url('../fonts/SourceSansPro-BoldItalic-cyrillic.woff2') format('woff2'), url('../fonts/SourceSansPro-BoldItalic-cyrillic.woff') format('woff');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold Italic'), local('SourceSansPro-BoldItalic'), url('../fonts/SourceSansPro-BoldItalic-greek-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-BoldItalic-greek-ext.woff') format('woff');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold Italic'), local('SourceSansPro-BoldItalic'), url('../fonts/SourceSansPro-BoldItalic-greek.woff2') format('woff2'), url('../fonts/SourceSansPro-BoldItalic-greek.woff') format('woff');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold Italic'), local('SourceSansPro-BoldItalic'), url('../fonts/SourceSansPro-BoldItalic-vietnamese.woff2') format('woff2'), url('../fonts/SourceSansPro-BoldItalic-vietnamese.woff') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold Italic'), local('SourceSansPro-BoldItalic'), url('../fonts/SourceSansPro-BoldItalic-latin-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-BoldItalic-latin-ext.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold Italic'), local('SourceSansPro-BoldItalic'), url('../fonts/SourceSansPro-BoldItalic-latin.woff2') format('woff2'), url('../fonts/SourceSansPro-BoldItalic-latin.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
||||
}
|
||||
|
||||
/* cyrillic-ext */
|
||||
/* source-sans-pro-300 - greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url('../fonts/SourceSansPro-Light-cyrillic-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-Light-cyrillic-ext.woff') format('woff');
|
||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'),
|
||||
url('../fonts/source-sans-pro-v13-greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
||||
url('../fonts/source-sans-pro-v13-greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||
}
|
||||
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url('../fonts/SourceSansPro-Light-cyrillic.woff2') format('woff2'), url('../fonts/SourceSansPro-Light-cyrillic.woff') format('woff');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url('../fonts/SourceSansPro-Light-greek-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-Light-greek-ext.woff') format('woff');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url('../fonts/SourceSansPro-Light-greek.woff2') format('woff2'), url('../fonts/SourceSansPro-Light-greek.woff') format('woff');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url('../fonts/SourceSansPro-Light-vietnamese.woff2') format('woff2'), url('../fonts/SourceSansPro-Light-vietnamese.woff') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url('../fonts/SourceSansPro-Light-latin-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-Light-latin-ext.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url('../fonts/SourceSansPro-Light-latin.woff2') format('woff2'), url('../fonts/SourceSansPro-Light-latin.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
||||
}
|
||||
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url('../fonts/SourceSansPro-Regular-cyrillic-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-Regular-cyrillic-ext.woff') format('woff');
|
||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||
}
|
||||
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url('../fonts/SourceSansPro-Regular-cyrillic.woff2') format('woff2'), url('../fonts/SourceSansPro-Regular-cyrillic.woff') format('woff');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url('../fonts/SourceSansPro-Regular-greek-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-Regular-greek-ext.woff') format('woff');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url('../fonts/SourceSansPro-Regular-greek.woff2') format('woff2'), url('../fonts/SourceSansPro-Regular-greek.woff') format('woff');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url('../fonts/SourceSansPro-Regular-vietnamese.woff2') format('woff2'), url('../fonts/SourceSansPro-Regular-vietnamese.woff') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url('../fonts/SourceSansPro-Regular-latin-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-Regular-latin-ext.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url('../fonts/SourceSansPro-Regular-latin.woff2') format('woff2'), url('../fonts/SourceSansPro-Regular-latin.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
||||
}
|
||||
|
||||
/* cyrillic-ext */
|
||||
/* source-sans-pro-600 - greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url('../fonts/SourceSansPro-SemiBold-cyrillic-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-SemiBold-cyrillic-ext.woff') format('woff');
|
||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||
src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'),
|
||||
url('../fonts/source-sans-pro-v13-greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin-600.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
||||
url('../fonts/source-sans-pro-v13-greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin-600.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||
}
|
||||
|
||||
/* cyrillic */
|
||||
/* source-sans-pro-regular - greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'),
|
||||
url('../fonts/source-sans-pro-v13-greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
||||
url('../fonts/source-sans-pro-v13-greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||
}
|
||||
|
||||
/* source-sans-pro-italic - greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'),
|
||||
url('../fonts/source-sans-pro-v13-greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin-italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
||||
url('../fonts/source-sans-pro-v13-greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin-italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||
}
|
||||
|
||||
/* source-sans-pro-600italic - greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url('../fonts/SourceSansPro-SemiBold-cyrillic.woff2') format('woff2'), url('../fonts/SourceSansPro-SemiBold-cyrillic.woff') format('woff');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
src: local('Source Sans Pro SemiBold Italic'), local('SourceSansPro-SemiBoldItalic'),
|
||||
url('../fonts/source-sans-pro-v13-greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin-600italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
||||
url('../fonts/source-sans-pro-v13-greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin-600italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||
}
|
||||
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url('../fonts/SourceSansPro-SemiBold-greek-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-SemiBold-greek-ext.woff') format('woff');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url('../fonts/SourceSansPro-SemiBold-greek.woff2') format('woff2'), url('../fonts/SourceSansPro-SemiBold-greek.woff') format('woff');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url('../fonts/SourceSansPro-SemiBold-vietnamese.woff2') format('woff2'), url('../fonts/SourceSansPro-SemiBold-vietnamese.woff') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url('../fonts/SourceSansPro-SemiBold-latin-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-SemiBold-latin-ext.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url('../fonts/SourceSansPro-SemiBold-latin.woff2') format('woff2'), url('../fonts/SourceSansPro-SemiBold-latin.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
||||
}
|
||||
|
||||
/* cyrillic-ext */
|
||||
/* source-sans-pro-700 - greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url('../fonts/SourceSansPro-Bold-cyrillic-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-Bold-cyrillic-ext.woff') format('woff');
|
||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||
}
|
||||
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url('../fonts/SourceSansPro-Bold-cyrillic.woff2') format('woff2'), url('../fonts/SourceSansPro-Bold-cyrillic.woff') format('woff');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url('../fonts/SourceSansPro-Bold-greek-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-Bold-greek-ext.woff') format('woff');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url('../fonts/SourceSansPro-Bold-greek.woff2') format('woff2'), url('../fonts/SourceSansPro-Bold-greek.woff') format('woff');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url('../fonts/SourceSansPro-Bold-vietnamese.woff2') format('woff2'), url('../fonts/SourceSansPro-Bold-vietnamese.woff') format('woff');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url('../fonts/SourceSansPro-Bold-latin-ext.woff2') format('woff2'), url('../fonts/SourceSansPro-Bold-latin-ext.woff') format('woff');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Source Sans Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url('../fonts/SourceSansPro-Bold-latin.woff2') format('woff2'), url('../fonts/SourceSansPro-Bold-latin.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
||||
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'),
|
||||
url('../fonts/source-sans-pro-v13-greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
||||
url('../fonts/source-sans-pro-v13-greek_cyrillic-ext_vietnamese_greek-ext_latin-ext_cyrillic_latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user