Merge branch 'release/5.1.1'

This commit is contained in:
James Cole
2020-03-13 19:39:59 +01:00
255 changed files with 1962 additions and 1051 deletions

View File

@@ -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();

View File

@@ -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',

View File

@@ -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',

View File

@@ -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;
}
}

View File

@@ -36,6 +36,7 @@ class StoredTransactionGroup extends Event
{
use SerializesModels;
/** @var bool */
public $applyRules;
/** @var TransactionGroup The group that was stored. */
public $transactionGroup;

View File

@@ -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;
}
}

View File

@@ -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)]));
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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

View File

@@ -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) {

View File

@@ -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) {

View 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');
}
}

View File

@@ -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());

View File

@@ -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.

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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'));
}
/**

View File

@@ -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'
)
);
}

View File

@@ -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 :(.');

View File

@@ -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);

View File

@@ -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());
}

View 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';
}
}

View File

@@ -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
View 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));
}
}

View File

@@ -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
{

View File

@@ -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
View File

@@ -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",

View File

@@ -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'],

View File

@@ -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,

View File

@@ -22,6 +22,5 @@
"vue": "^2.6.10",
"vue-i18n": "^8.14.1",
"vue-template-compiler": "^2.6.10"
},
"dependencies": {}
}
}

View File

@@ -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+ */
}

Some files were not shown because too many files have changed in this diff Show More