Merge branch 'release/5.2.7'

This commit is contained in:
James Cole
2020-06-06 07:18:36 +02:00
424 changed files with 9518 additions and 9138 deletions

View File

@@ -58,13 +58,24 @@ APP_LOG_LEVEL=notice
# For other database types, please see the FAQ: https://docs.firefly-iii.org/support/faq
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
# Use "mysql" for MySQL and MariaDB. Use "sqlite" for SQLite.
DB_CONNECTION=pgsql
DB_CONNECTION=mysql
DB_HOST=fireflyiiidb
DB_PORT=5432
DB_PORT=3306
DB_DATABASE=firefly
DB_USERNAME=firefly
DB_PASSWORD=secret_firefly_password
# MySQL supports SSL. You can configure it here.
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
MYSQL_USE_SSL=false
MYSQL_SSL_VERIFY_SERVER_CERT=true
# You need to set at least of these options
MYSQL_SSL_CAPATH=/etc/ssl/certs/
MYSQL_SSL_CA=
MYSQL_SSL_CERT=
MYSQL_SSL_KEY=
MYSQL_SSL_CIPHER=
# PostgreSQL supports SSL. You can configure it here.
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
PGSQL_SSL_MODE=prefer
@@ -170,8 +181,16 @@ ADLDAP_PORT=389
ADLDAP_TIMEOUT=5
ADLDAP_BASEDN=""
ADLDAP_FOLLOW_REFFERALS=false
# SSL/TLS settings
ADLDAP_USE_SSL=false
ADLDAP_USE_TLS=false
ADLDAP_SSL_CACERTDIR=
ADLDAP_SSL_CACERTFILE=
ADLDAP_SSL_CERTFILE=
ADLDAP_SSL_KEYFILE=
ADLDAP_SSL_CIPHER_SUITE=
ADLDAP_SSL_REQUIRE_CERT=
# You can set the following variables from a file by appending them with _FILE:
ADLDAP_ADMIN_USERNAME=
@@ -219,8 +238,9 @@ TRACKER_SITE_ID=
TRACKER_URL=
#
# Firefly III could (in the future) collect telemetry on how you use Firefly III.
# In order to allow this, change the following variable to true:
# Firefly III can collect telemetry on how you use Firefly III. This is opt-in.
# In order to allow this, change the following variable to true.
# To read more about this feature, go to this page: https://docs.firefly-iii.org/support/telemetry
SEND_TELEMETRY=false
# You can fine tune the start-up of a Docker container by editing these environment variables.
@@ -268,7 +288,6 @@ DEMO_USERNAME=
DEMO_PASSWORD=
USE_ENCRYPTION=false
IS_SANDSTORM=false
IS_DOCKER=false
IS_HEROKU=false
BUNQ_USE_SANDBOX=false

2
.github/lock.yml vendored
View File

@@ -32,4 +32,4 @@ setLockReason: true
# daysUntilLock: 30
# Repository to extend settings from
# _extends: repo
# _extends: repo

View File

@@ -83,8 +83,6 @@ class CorrectDatabase extends Command
echo $result;
}
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}
}

View File

@@ -77,8 +77,6 @@ class CorrectOpeningBalanceCurrencies extends Command
$this->info('There was nothing to fix in the opening balance transactions.');
}
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -78,8 +78,6 @@ class CreateAccessTokens extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verify access tokens in %s seconds.', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}
}

View File

@@ -79,8 +79,6 @@ class CreateLinkTypes extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified link types in %s seconds', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}
}

View File

@@ -76,8 +76,6 @@ class DeleteEmptyGroups extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified empty groups in %s seconds', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}
}

View File

@@ -58,8 +58,6 @@ class DeleteEmptyJournals extends Command
$this->deleteUnevenJournals();
$this->deleteEmptyJournals();
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -62,7 +62,6 @@ class DeleteOrphanedTransactions extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified orphans in %s seconds', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -78,8 +78,6 @@ class DeleteZeroAmount extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified zero-amount integrity in %s seconds', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}
}

View File

@@ -101,8 +101,6 @@ class EnableCurrencies extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified currencies in %s seconds.', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}
}

View File

@@ -106,7 +106,6 @@ class FixAccountTypes extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verifying account types took %s seconds', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -75,7 +75,6 @@ class FixLongDescriptions extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified all transaction group and journal title lengths in %s seconds.', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}
}

View File

@@ -98,7 +98,6 @@ class FixPiggies extends Command
$end = round(microtime(true) - $start, 2);
$this->line(sprintf('Verified the content of %d piggy bank events in %s seconds.', $set->count(), $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}
}

View File

@@ -67,7 +67,6 @@ class FixRecurringTransactions extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Corrected recurring transactions %s seconds.', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -75,7 +75,6 @@ class FixUnevenAmount extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified amount integrity in %s seconds', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -71,7 +71,6 @@ class RemoveBills extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified bills / journals in %s seconds', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}
}

View File

@@ -83,7 +83,6 @@ class RenameMetaFields extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Renamed meta fields in %s seconds', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -74,7 +74,6 @@ class TransferBudgets extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified budget/journals in %s seconds.', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}
}

View File

@@ -123,7 +123,6 @@ class DecryptDatabase extends Command
}
$this->info('Done!');
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -137,11 +137,11 @@ class ExportData extends Command
} catch (FireflyException $e) {
$this->error(sprintf('Could not store data: %s', $e->getMessage()));
// app('telemetry')->feature('executed-command-with-error', $this->signature);
app('telemetry')->feature('system.command.errored', $this->signature);
return 1;
}
// app('telemetry')->feature('executed-command', $this->signature);
app('telemetry')->feature('system.command.executed', $this->signature);
return 0;
}

View File

@@ -63,279 +63,14 @@ class CreateCSVImport extends Command
{configuration? : The configuration file to use for the import.}
{--user=1 : The user ID that the import should import for.}
{--token= : The user\'s access token.}';
/** @var ImportJob */
private $importJob;
/** @var ImportJobRepositoryInterface */
private $importRepository;
/** @var UserRepositoryInterface */
private $userRepository;
/**
* Run the command.
*/
public function handle(): int
{
$this->stupidLaravel();
// @codeCoverageIgnoreStart
if (!$this->verifyAccessToken()) {
$this->errorLine('Invalid access token.');
return 1;
}
if (!$this->validArguments()) {
$this->errorLine('Invalid arguments.');
return 1;
}
// @codeCoverageIgnoreEnd
/** @var User $user */
$user = $this->userRepository->findNull((int) $this->option('user'));
$file = (string) $this->argument('file');
$configuration = (string) $this->argument('configuration');
$this->importRepository->setUser($user);
$configurationData = json_decode(file_get_contents($configuration), true, 512, JSON_THROW_ON_ERROR);
$this->importJob = $this->importRepository->create('file');
// inform user (and log it)
$this->infoLine(sprintf('Import file : %s', $file));
$this->infoLine(sprintf('Configuration file : %s', $configuration));
$this->infoLine(sprintf('User : #%d (%s)', $user->id, $user->email));
$this->infoLine(sprintf('Job : %s', $this->importJob->key));
try {
$this->storeFile($file);
} catch (FireflyException $e) {
$this->errorLine($e->getMessage());
return 1;
}
// job is ready to go
$this->importRepository->setConfiguration($this->importJob, $configurationData);
$this->importRepository->setStatus($this->importJob, 'ready_to_run');
$this->infoLine('The import routine has started. The process is not visible. Please wait.');
Log::debug('Go for import!');
// keep repeating this call until job lands on "provider_finished"
try {
$this->processFile();
} catch (FireflyException $e) {
$this->errorLine($e->getMessage());
// app('telemetry')->feature('executed-command-with-error', $this->signature);
return 1;
}
// then store data:
try {
$this->storeData();
} catch (FireflyException $e) {
$this->errorLine($e->getMessage());
// app('telemetry')->feature('executed-command-with-error', $this->signature);
return 1;
}
// give feedback:
$this->giveFeedback();
// clear cache for user:
app('preferences')->setForUser($user, 'lastActivity', microtime());
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
$this->error('This command is disabled.');
return 1;
}
/**
* @param string $message
* @param array|null $data
*
* @codeCoverageIgnore
*/
private function errorLine(string $message, array $data = null): void
{
Log::error($message, $data ?? []);
$this->error($message);
}
/**
*
*/
private function giveFeedback(): void
{
$this->infoLine('Job has finished.');
if (null !== $this->importJob->tag) {
$this->infoLine(sprintf('%d transaction(s) have been imported.', $this->importJob->tag->transactionJournals->count()));
$this->infoLine(sprintf('You can find your transactions under tag "%s"', $this->importJob->tag->tag));
}
if (null === $this->importJob->tag) {
$this->errorLine('No transactions have been imported :(.');
}
if (count($this->importJob->errors) > 0) {
$this->infoLine(sprintf('%d error(s) occurred:', count($this->importJob->errors)));
foreach ($this->importJob->errors as $err) {
$this->errorLine('- ' . $err);
}
}
}
/**
* @param string $message
* @param array $data
*
* @codeCoverageIgnore
*/
private function infoLine(string $message, array $data = null): void
{
Log::info($message, $data ?? []);
$this->line($message);
}
/**
* Keep repeating import call until job lands on "provider_finished".
*
* @throws FireflyException
*/
private function processFile(): void
{
$className = config('import.routine.file');
$valid = ['provider_finished'];
$count = 0;
while (!in_array($this->importJob->status, $valid, true) && $count < 6) {
Log::debug(sprintf('Now in loop #%d.', $count + 1));
/** @var RoutineInterface $routine */
$routine = app($className);
$routine->setImportJob($this->importJob);
try {
$routine->run();
} catch (FireflyException|Exception $e) {
$message = 'The import routine crashed: ' . $e->getMessage();
Log::error($message);
Log::error($e->getTraceAsString());
// set job errored out:
$this->importRepository->setStatus($this->importJob, 'error');
throw new FireflyException($message);
}
$count++;
}
$this->importRepository->setStatus($this->importJob, 'provider_finished');
$this->importJob->status = 'provider_finished';
}
/**
*
* @throws FireflyException
*/
private function storeData(): void
{
if ('provider_finished' === $this->importJob->status) {
$this->infoLine('Import has finished. Please wait for storage of data.');
// set job to be storing data:
$this->importRepository->setStatus($this->importJob, 'storing_data');
/** @var ImportArrayStorage $storage */
$storage = app(ImportArrayStorage::class);
$storage->setImportJob($this->importJob);
try {
$storage->store();
} catch (FireflyException|Exception $e) {
$message = 'The import routine crashed: ' . $e->getMessage();
Log::error($message);
Log::error($e->getTraceAsString());
// set job errored out:
$this->importRepository->setStatus($this->importJob, 'error');
throw new FireflyException($message);
}
// set storage to be finished:
$this->importRepository->setStatus($this->importJob, 'storage_finished');
}
}
/**
* Store the supplied file as an attachment to this job.
*
* @param string $file
*
* @throws FireflyException
*/
private function storeFile(string $file): void
{
// store file as attachment.
if ('' !== $file) {
$messages = $this->importRepository->storeCLIUpload($this->importJob, 'import_file', $file);
if ($messages->count() > 0) {
throw new FireflyException($messages->first());
}
}
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* @codeCoverageIgnore
*/
private function stupidLaravel(): void
{
$this->userRepository = app(UserRepositoryInterface::class);
$this->importRepository = app(ImportJobRepositoryInterface::class);
}
/**
* Verify user inserts correct arguments.
*
* @noinspection MultipleReturnStatementsInspection
* @return bool
* @codeCoverageIgnore
*/
private function validArguments(): bool
{
$file = (string) $this->argument('file');
$configuration = (string) $this->argument('configuration');
$cwd = getcwd();
$enabled = (bool) config('import.enabled.file');
if (false === $enabled) {
$this->errorLine('CSV Provider is not enabled.');
return false;
}
if (!file_exists($file)) {
$this->errorLine(sprintf('Firefly III cannot find file "%s" (working directory: "%s").', $file, $cwd));
return false;
}
if (!file_exists($configuration)) {
$this->errorLine(sprintf('Firefly III cannot find configuration file "%s" (working directory: "%s").', $configuration, $cwd));
return false;
}
$configurationData = json_decode(file_get_contents($configuration), true, 512, JSON_THROW_ON_ERROR);
if (null === $configurationData) {
$this->errorLine(sprintf('Firefly III cannot read the contents of configuration file "%s" (working directory: "%s").', $configuration, $cwd));
return false;
}
return true;
}
}

View File

@@ -64,7 +64,6 @@ class ReportEmptyObjects extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Report on empty objects finished in %s seconds', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -69,7 +69,6 @@ class ReportIntegrity extends Command
echo $result;
}
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}
}

View File

@@ -54,7 +54,6 @@ class ReportSum extends Command
{
$this->reportSum();
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -24,6 +24,7 @@ namespace FireflyIII\Console\Commands\Integrity;
use FireflyIII\Support\System\OAuthKeys;
use Illuminate\Console\Command;
use Log;
/**
* Class RestoreOAuthKeys
@@ -52,7 +53,6 @@ class RestoreOAuthKeys extends Command
{
$this->restoreOAuthKeys();
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}
@@ -93,7 +93,9 @@ class RestoreOAuthKeys extends Command
*/
private function restoreOAuthKeys(): void
{
Log::debug('Going to restoreOAuthKeys()');
if (!$this->keysInDatabase() && !$this->keysOnDrive()) {
Log::debug('Keys are not in DB and keys are not on the drive.');
$this->generateKeys();
$this->storeKeysInDB();
$this->line('Generated and stored new keys.');
@@ -101,12 +103,14 @@ class RestoreOAuthKeys extends Command
return;
}
if ($this->keysInDatabase() && !$this->keysOnDrive()) {
Log::debug('Keys are in DB and keys are not on the drive. Restore.');
$this->restoreKeysFromDB();
$this->line('Restored OAuth keys from database.');
return;
}
if (!$this->keysInDatabase() && $this->keysOnDrive()) {
Log::debug('Keys are not in DB and keys are on the drive. Save in DB.');
$this->storeKeysInDB();
$this->line('Stored OAuth keys in database.');

View File

@@ -86,7 +86,7 @@ class ScanAttachments extends Command
$this->line(sprintf('Fixed attachment #%d', $attachment->id));
}
// app('telemetry')->feature('executed-command', $this->signature);
app('telemetry')->feature('system.command.executed', $this->signature);
return 0;
}
}

View File

@@ -59,7 +59,7 @@ class SetLatestVersion extends Command
app('fireflyconfig')->set('ff3_version', config('firefly.version'));
$this->line('Updated version.');
// app('telemetry')->feature('executed-command', $this->signature);
app('telemetry')->feature('system.command.executed', $this->signature);
return 0;
}

View File

@@ -112,7 +112,7 @@ class ApplyRules extends Command
$result = $this->verifyInput();
if (false === $result) {
// app('telemetry')->feature('executed-command-with-error', $this->signature);
app('telemetry')->feature('system.command.errored', $this->signature);
return 1;
}
@@ -131,7 +131,7 @@ class ApplyRules extends Command
$this->warn(' --rule_groups=1,2,...');
$this->warn(' --all_rules');
// app('telemetry')->feature('executed-command-with-error', $this->signature);
app('telemetry')->feature('system.command.errored', $this->signature);
return 1;
}
@@ -167,7 +167,7 @@ class ApplyRules extends Command
$this->line('');
$this->line('Done!');
// app('telemetry')->feature('executed-command', $this->signature);
app('telemetry')->feature('system.command.executed', $this->signature);
return 0;
}

View File

@@ -94,10 +94,10 @@ class Cron extends Command
}
/*
* Fire telemetry cron job (disabled):
* Fire telemetry cron job
*/
try {
//$this->telemetryCronJob($force, $date);
$this->telemetryCronJob($force, $date);
} catch (FireflyException $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
@@ -106,7 +106,7 @@ class Cron extends Command
$this->info('More feedback on the cron jobs can be found in the log files.');
// app('telemetry')->feature('executed-command', $this->signature);
app('telemetry')->feature('system.command.executed', $this->signature);
return 0;
}

View File

@@ -87,7 +87,6 @@ class AccountCurrencies extends Command
$this->info(sprintf('Verified and fixed account currencies in %s seconds.', $end));
$this->markAsExecuted();
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -78,8 +78,6 @@ class BackToJournals extends Command
$this->info(sprintf('Updated category and budget info for all transaction journals in %s seconds.', $end));
$this->markAsExecuted();
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -92,8 +92,6 @@ class BudgetLimitCurrency extends Command
$this->markAsExecuted();
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -91,8 +91,6 @@ class CCLiabilities extends Command
$this->info(sprintf('Verified credit card liabilities in %s seconds', $end));
$this->markAsExecuted();
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -101,8 +101,6 @@ class MigrateAttachments extends Command
$this->info(sprintf('Migrated attachment notes in %s seconds.', $end));
$this->markAsExecuted();
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -100,8 +100,6 @@ class MigrateJournalNotes extends Command
$this->info(sprintf('Migrated notes in %s seconds.', $end));
$this->markAsExecuted();
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -72,8 +72,6 @@ class MigrateRecurrenceMeta extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Migrated recurrence meta data in %s seconds.', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -65,7 +65,6 @@ class MigrateTagLocations extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Migrated tag locations in %s seconds.', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -112,8 +112,6 @@ class MigrateToGroups extends Command
$this->markAsMigrated();
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -99,7 +99,6 @@ class MigrateToRules extends Command
$this->info(sprintf('Verified and fixed bills in %s seconds.', $end));
$this->markAsExecuted();
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -90,7 +90,6 @@ class OtherCurrenciesCorrections extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified and fixed transaction currencies in %s seconds.', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -91,7 +91,6 @@ class RenameAccountMeta extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Fixed account meta data in %s seconds.', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -101,7 +101,6 @@ class TransactionIdentifier extends Command
$this->info(sprintf('Verified and fixed transaction identifiers in %s seconds.', $end));
$this->markAsExecuted();
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -111,7 +111,6 @@ class TransferCurrenciesCorrections extends Command
$end = round(microtime(true) - $start, 2);
$this->info(sprintf('Verified and fixed currency information for transfers in %s seconds.', $end));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -117,7 +117,6 @@ class UpgradeDatabase extends Command
// index will set FF3 version.
app('fireflyconfig')->set('ff3_version', (string) config('firefly.version'));
// app('telemetry')->feature('executed-command', $this->signature);
return 0;
}

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands;
use FireflyIII\Support\System\GeneratesInstallationId;
use Illuminate\Console\Command;
/**
@@ -32,6 +33,8 @@ use Illuminate\Console\Command;
*/
class UpgradeFireflyInstructions extends Command
{
use GeneratesInstallationId;
/**
* The console command description.
*
@@ -50,6 +53,7 @@ class UpgradeFireflyInstructions extends Command
*/
public function handle(): int
{
$this->generateInstallationId();
if ('update' === (string) $this->argument('task')) {
$this->updateInstructions();
}
@@ -57,7 +61,14 @@ class UpgradeFireflyInstructions extends Command
$this->installInstructions();
}
// app('telemetry')->feature('executed-command', $this->signature);
// collect system telemetry
$isDocker = true === env('IS_DOCKER', false) ? 'true' : 'false';
app('telemetry')->feature('system.php.version', PHP_VERSION);
app('telemetry')->feature('system.os.version', PHP_OS);
app('telemetry')->feature('system.database.driver', env('DB_CONNECTION', '(unknown)'));
app('telemetry')->feature('system.os.is_docker', $isDocker);
app('telemetry')->feature('system.command.executed', $this->signature);
return 0;
}

View File

@@ -230,4 +230,4 @@ trait AccountCollection
return $this;
}
}
}

View File

@@ -84,4 +84,4 @@ trait AmountCollection
return $this;
}
}
}

View File

@@ -56,4 +56,4 @@ trait CollectorProperties
private $total;
/** @var User The user object. */
private $user;
}
}

View File

@@ -288,4 +288,4 @@ trait MetaCollection
}
}
}

View File

@@ -131,6 +131,7 @@ class LoginController extends Controller
return redirect(route('register')); // @codeCoverageIgnore
}
// is allowed to?
$singleUserMode = app('fireflyconfig')->get('single_user_mode', config('firefly.configuration.single_user_mode'))->data;
$allowRegistration = true;
@@ -148,6 +149,9 @@ class LoginController extends Controller
$email = $request->old('email');
$remember = $request->old('remember');
// todo must forget 2FA if user ends up here.
return view('auth.login', compact('allowRegistration', 'email', 'remember', 'allowReset', 'title'));
}

View File

@@ -104,6 +104,9 @@ class RegisterController extends Controller
$this->registered($request, $user);
// telemetry
\Telemetry::feature('system.users.count', User::count());
return redirect($this->redirectPath());
}

View File

@@ -284,7 +284,7 @@ class BillController extends Controller
}
$request->session()->flash('success', (string) trans('firefly.rescanned_bill', ['total' => $total]));
$request->session()->flash('success', (string) trans_choice('firefly.rescanned_bill', $total));
app('preferences')->mark();
return redirect(route('bills.show', [$bill->id]));

View File

@@ -177,12 +177,26 @@ class AvailableBudgetController extends Controller
$end = session()->get('end');
Log::info($e->getMessage());
}
// validate amount
$amount = (string) $request->get('amount');
if ('' === $amount) {
session()->flash('error', trans('firefly.invalid_amount'));
return redirect(route('budgets.index', [$start->format('Y-m-d'), $end->format('Y-m-d')]));
}
if (0 === bccomp('0', $amount)) {
session()->flash('error', trans('firefly.invalid_amount'));
return redirect(route('budgets.index', [$start->format('Y-m-d'), $end->format('Y-m-d')]));
}
// find currency
$currency = $this->currencyRepos->find((int) $request->get('currency_id'));
if (null === $currency) {
session()->flash('error', trans('firefly.invalid_currency'));
return redirect(route('budgets.index'));
return redirect(route('budgets.index', [$start->format('Y-m-d'), $end->format('Y-m-d')]));
}
// find existing AB
@@ -190,7 +204,7 @@ class AvailableBudgetController extends Controller
if (null === $existing) {
$this->abRepository->store(
[
'amount' => $request->get('amount'),
'amount' => $amount,
'currency' => $currency,
'start' => $start,
'end' => $end,
@@ -199,7 +213,7 @@ class AvailableBudgetController extends Controller
}
if (null !== $existing) {
// update amount:
$this->abRepository->update($existing, ['amount' => $request->get('amount')]);
$this->abRepository->update($existing, ['amount' => $amount]);
}
session()->flash('success', trans('firefly.set_ab'));
@@ -217,7 +231,21 @@ class AvailableBudgetController extends Controller
*/
public function update(Request $request, AvailableBudget $availableBudget, Carbon $start, Carbon $end)
{
$this->abRepository->update($availableBudget, ['amount' => $request->get('amount')]);
// validate amount
$amount = (string) $request->get('amount');
if ('' === $amount) {
session()->flash('error', trans('firefly.invalid_amount'));
return redirect(route('budgets.index', [$start->format('Y-m-d'), $end->format('Y-m-d')]));
}
if (0 === bccomp('0', $amount)) {
session()->flash('error', trans('firefly.invalid_amount'));
return redirect(route('budgets.index', [$start->format('Y-m-d'), $end->format('Y-m-d')]));
}
$this->abRepository->update($availableBudget, ['amount' => $amount]);
session()->flash('success', trans('firefly.updated_ab'));
return redirect(route('budgets.index', [$start->format('Y-m-d'), $end->format('Y-m-d')]));

View File

@@ -132,6 +132,7 @@ class BudgetLimitController extends Controller
*/
public function store(Request $request)
{
Log::debug('Going to store new budget-limit.', $request->all());
// first search for existing one and update it if necessary.
$currency = $this->currencyRepos->find((int) $request->get('transaction_currency_id'));
$budget = $this->repository->findNull((int) $request->get('budget_id'));
@@ -143,7 +144,6 @@ class BudgetLimitController extends Controller
$start->startOfDay();
$end->endOfDay();
Log::debug(sprintf('Start: %s, end: %s', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
$limit = $this->blRepository->find($budget, $currency, $start, $end);

View File

@@ -121,11 +121,11 @@ class DebugController extends Controller
$search = ['~', '#'];
$replace = ['\~', '# '];
$now = Carbon::now()->format('Y-m-d H:i:s e');
$installationId = app('fireflyconfig')->get('installation_id', '')->data;
$phpVersion = str_replace($search, $replace, PHP_VERSION);
$phpOs = str_replace($search, $replace, PHP_OS);
$interface = PHP_SAPI;
$now = Carbon::now()->format('Y-m-d H:i:s e');
$drivers = implode(', ', DB::availableDrivers());
$currentDriver = DB::getDriverName();
$userAgent = $request->header('user-agent');
@@ -137,14 +137,23 @@ class DebugController extends Controller
$logChannel = config('logging.default');
$appLogLevel = config('logging.level');
$cacheDriver = config('cache.default');
$loginProvider = config('auth.driver');
$loginProvider = config('auth.providers.users.driver');
// some new vars.
$telemetry = true === config('firefly.send_telemetry') && true === config('firefly.feature_flags.telemetry');
$defaultLanguage = (string) config('firefly.default_language');
$defaultLocale = (string) config('firefly.default_locale');
$userLanguage = app('steam')->getLanguage();
$userLocale = app('steam')->getLocale();
$isDocker = env('IS_DOCKER', false);
// set languages, see what happens:
$original = setlocale(LC_ALL, 0);
$localeAttempts = [];
$parts = app('steam')->getLocaleArray(app('steam')->getLocale());
foreach ($parts as $code) {
$code = trim($code);
$code = trim($code);
Log::debug(sprintf('Trying to set %s', $code));
$localeAttempts[$code] = var_export(setlocale(LC_ALL, $code), true);
}
setlocale(LC_ALL, $original);
@@ -194,7 +203,14 @@ class DebugController extends Controller
'interface',
'logContent',
'cacheDriver',
'trustedProxies'
'trustedProxies',
'telemetry',
'userLanguage',
'userLocale',
'defaultLanguage',
'defaultLocale',
'isDocker'
)
);
}

View File

@@ -117,7 +117,7 @@ class HomeController extends Controller
if (0 === $count) {
return redirect(route('new-user.index'));
}
$subTitle = (string) trans('firefly.welcomeBack');
$subTitle = (string) trans('firefly.welcome_back');
$transactions = [];
$frontPage = app('preferences')->get(
'frontPageAccounts',

View File

@@ -108,4 +108,4 @@ class BudgetController extends Controller
);
}
}
}

View File

@@ -124,6 +124,11 @@ class NewUserController extends Controller
'invoice_date' => false, 'internal_reference' => false, 'notes' => true, 'attachments' => true,];
app('preferences')->set('transaction_journal_optional_fields', $visibleFields);
// telemetry: user language preference + default language.
app('telemetry')->feature('config.firefly.default_language', config('firefly.default_language', 'en_US'));
app('telemetry')->feature('user.preferences.language', app('steam')->getLanguage());
app('telemetry')->feature('user.preferences.locale', app('steam')->getLocale());
session()->flash('success', (string) trans('firefly.stored_new_accounts_new_user'));
app('preferences')->mark();

View File

@@ -92,9 +92,7 @@ class PiggyBankController extends Controller
*/
public function add(PiggyBank $piggyBank)
{
/** @var Carbon $date */
$date = session('end', Carbon::now()->endOfMonth());
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $date);
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, new Carbon);
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank);
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
$maxAmount = min($leftOnAccount, $leftToSave);
@@ -113,7 +111,7 @@ class PiggyBankController extends Controller
public function addMobile(PiggyBank $piggyBank)
{
/** @var Carbon $date */
$date = session('end', Carbon::now()->endOfMonth());
$date = session('end', new Carbon);
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $date);
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank);
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);

View File

@@ -210,6 +210,11 @@ class PreferencesController extends Controller
session()->flash('success', (string) trans('firefly.saved_preferences'));
app('preferences')->mark();
// telemetry: user language preference + default language.
app('telemetry')->feature('config.firefly.default_language', config('firefly.default_language', 'en_US'));
app('telemetry')->feature('user.preferences.language', app('steam')->getLanguage());
app('telemetry')->feature('user.preferences.locale', app('steam')->getLocale());
return redirect(route('preferences.index'));
}
}

View File

@@ -42,6 +42,7 @@ class CronController
$results = [];
$results[] = $this->runRecurring();
$results[] = $this->runAutoBudget();
$results[] = $this->runTelemetry();
return implode("<br>\n", $results);
}

View File

@@ -217,7 +217,7 @@ class TagController extends Controller
$count++;
}
}
session()->flash('success', (string) trans('firefly.deleted_x_tags', ['count' => $count]));
session()->flash('success', (string) trans_choice('firefly.deleted_x_tags', $count));
return redirect(route('tags.index'));
}

View File

@@ -118,7 +118,7 @@ class BulkController extends Controller
}
}
app('preferences')->mark();
$request->session()->flash('success', (string) trans('firefly.mass_edited_transactions_success', ['amount' => $count]));
$request->session()->flash('success', (string) trans_choice('firefly.mass_edited_transactions_success', $count));
// redirect to previous URL:
return redirect($this->getPreviousUri('transactions.bulk-edit.uri'));

View File

@@ -114,7 +114,7 @@ class MassController extends Controller
app('preferences')->mark();
session()->flash('success', (string) trans('firefly.mass_deleted_transactions_success', ['amount' => $count]));
session()->flash('success', (string) trans_choice('firefly.mass_deleted_transactions_success', $count));
// redirect to previous URL:
return redirect($this->getPreviousUri('transactions.mass-delete.uri'));
@@ -188,7 +188,7 @@ class MassController extends Controller
}
app('preferences')->mark();
session()->flash('success', (string) trans('firefly.mass_edited_transactions_success', ['amount' => $count]));
session()->flash('success', (string) trans_choice('firefly.mass_edited_transactions_success', $count ));
// redirect to previous URL:
return redirect($this->getPreviousUri('transactions.mass-edit.uri'));

View File

@@ -99,8 +99,9 @@ class ShowController extends Controller
$transformer->setParameters(new ParameterBag);
$groupArray = $transformer->transformObject($transactionGroup);
// do some amount calculations:
// do some calculations:
$amounts = $this->getAmounts($groupArray);
$accounts = $this->getAccounts($groupArray);
// make sure notes are escaped but not double escaped.
foreach ($groupArray['transactions'] as $index => $transaction) {
@@ -127,7 +128,8 @@ class ShowController extends Controller
'groupArray',
'events',
'attachments',
'links'
'links',
'accounts',
)
);
}
@@ -166,4 +168,31 @@ class ShowController extends Controller
return $amounts;
}
/**
* @param array $group
*
* @return array
*/
private function getAccounts(array $group): array
{
$accounts = [];
foreach ($group['transactions'] as $index => $transaction) {
$accounts['source'][] = [
'type' => $transaction['source_type'],
'id' => $transaction['source_id'],
'name' => $transaction['source_name'],
'iban' => $transaction['source_iban'] ];
$accounts['destination'][] = [
'type' => $transaction['destination_type'],
'id' => $transaction['destination_id'],
'name' => $transaction['destination_name'],
'iban' => $transaction['destination_iban'] ];
}
$accounts['source'] = array_unique($accounts['source'], SORT_REGULAR);
$accounts['destination'] = array_unique($accounts['destination'], SORT_REGULAR);
return $accounts;
}
}

View File

@@ -26,8 +26,7 @@ namespace FireflyIII\Http\Middleware;
use Closure;
use FireflyIII\Exceptions\FireflyException;
use Log;
use Ramsey\Uuid\Uuid;
use FireflyIII\Support\System\GeneratesInstallationId;
/**
*
@@ -35,6 +34,7 @@ use Ramsey\Uuid\Uuid;
*/
class InstallationId
{
use GeneratesInstallationId;
/**
* Handle an incoming request.
*
@@ -48,13 +48,7 @@ class InstallationId
*/
public function handle($request, Closure $next)
{
$config = app('fireflyconfig')->get('installation_id', null);
if (null === $config) {
$uuid5 = Uuid::uuid5(Uuid::NAMESPACE_URL, 'firefly-iii.org');
$uniqueId = (string) $uuid5;
Log::info(sprintf('Created Firefly III installation ID %s', $uniqueId));
app('fireflyconfig')->set('installation_id', $uniqueId);
}
$this->generateInstallationId();
return $next($request);
}

View File

@@ -28,6 +28,7 @@ use Closure;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\Http\Controllers\RequestInformation;
use Illuminate\Http\Request;
use Log;
/**
* Class SessionFilter.
@@ -87,6 +88,7 @@ class Range
// send error to view if could not set money format
if (false === $moneyResult) {
Log::error('Could not set locale. The following array doesnt work: ', $localeArray);
app('view')->share('invalidMonetaryLocale', true); // @codeCoverageIgnore
}

View File

@@ -84,7 +84,7 @@ class MailError extends Job implements ShouldQueue
$args,
function (Message $message) use ($email) {
if ('mail@example.com' !== $email) {
$message->to($email, $email)->subject('Caught an error in Firefly III');
$message->to($email, $email)->subject((string) trans('email.error_subject'));
}
}
);

View File

@@ -24,6 +24,7 @@ namespace FireflyIII\Jobs;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Telemetry;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
@@ -33,7 +34,9 @@ use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Collection;
use JsonException;
use Log;
use Exception;
/**
* Class SubmitTelemetryData
@@ -61,7 +64,7 @@ class SubmitTelemetryData implements ShouldQueue
}
/**
*
* @throws FireflyException
*/
public function handle(): void
{
@@ -77,9 +80,17 @@ class SubmitTelemetryData implements ShouldQueue
}
$json = $this->parseJson($telemetry);
try {
$body = json_encode($json, JSON_THROW_ON_ERROR, 512);
} catch (JsonException $e) {
Log::error($e->getMessage());
Log::error('Could not parse JSON.');
throw new FireflyException(sprintf('Could not parse telemetry JSON: %s', $e->getMessage()));
}
$client = new Client;
$options = [
'body' => json_encode($json, JSON_THROW_ON_ERROR, 512),
'body' => $body,
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
@@ -89,11 +100,11 @@ class SubmitTelemetryData implements ShouldQueue
];
try {
$result = $client->post($url, $options);
} catch (GuzzleException $e) {
} catch (GuzzleException|Exception $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
Log::error('Could not submit telemetry.');
return;
throw new FireflyException(sprintf('Could not submit telemetry: %s', $e->getMessage()));
}
$body = (string) $result->getBody();
$statusCode = $result->getStatusCode();
@@ -156,6 +167,7 @@ class SubmitTelemetryData implements ShouldQueue
foreach ($telemetry as $entry) {
$array[] = [
'installation_id' => $entry->installation_id,
'collected_at' => $entry->created_at->format('r'),
'type' => $entry->type,
'key' => $entry->key,
'value' => $entry->value,
@@ -165,4 +177,4 @@ class SubmitTelemetryData implements ShouldQueue
return $array;
}
}
}

View File

@@ -63,6 +63,6 @@ class AccessTokenCreatedMail extends Mailable
public function build(): self
{
return $this->view('emails.access-token-created-html')->text('emails.access-token-created-text')
->subject('A new access token was created');
->subject((string) trans('email.access_token_created_subject'));
}
}

View File

@@ -62,6 +62,6 @@ class AdminTestMail extends Mailable
public function build(): self
{
return $this->view('emails.admin-test-html')->text('emails.admin-test-text')
->subject('A test message from your Firefly III installation');
->subject((string) trans('email.admin_test_subject'));
}
}

View File

@@ -70,6 +70,6 @@ class ConfirmEmailChangeMail extends Mailable
public function build(): self
{
return $this->view('emails.confirm-email-change-html')->text('emails.confirm-email-change-text')
->subject('Your Firefly III email address has changed');
->subject((string) trans('email.email_change_subject'));
}
}

View File

@@ -67,6 +67,6 @@ class OAuthTokenCreatedMail extends Mailable
public function build(): self
{
return $this->view('emails.oauth-client-created-html')->text('emails.oauth-client-created-text')
->subject('A new OAuth client has been created');
->subject((string) trans('email.oauth_created_subject'));
}
}

View File

@@ -61,6 +61,6 @@ class RegisteredUser extends Mailable
*/
public function build(): self
{
return $this->view('emails.registered-html')->text('emails.registered-text')->subject('Welcome to Firefly III!');
return $this->view('emails.registered-html')->text('emails.registered-text')->subject((string) trans('email.registered_subject'));
}
}

View File

@@ -79,7 +79,7 @@ class ReportNewJournalsMail extends Mailable
$this->transform();
return $this->view('emails.report-new-journals-html')->text('emails.report-new-journals-text')
->subject($subject);
->subject((string) trans_choice('email.new_journals_subject', $this->groups->count()));
}
private function transform(): void

View File

@@ -60,6 +60,6 @@ class RequestedNewPassword extends Mailable
*/
public function build(): self
{
return $this->view('emails.password-html')->text('emails.password-text')->subject('Your password reset request');
return $this->view('emails.password-html')->text('emails.password-text')->subject((string) trans('email.reset_pw_subject'));
}
}

View File

@@ -68,6 +68,6 @@ class UndoEmailChangeMail extends Mailable
public function build(): self
{
return $this->view('emails.undo-email-change-html')->text('emails.undo-email-change-text')
->subject('Your Firefly III email address has changed');
->subject((string) trans('email.email_change_subject'));
}
}

View File

@@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Models;
use Illuminate\Database\Eloquent\Model;
/**
* Class ObjectGroup
*/
class ObjectGroup extends Model
{
/**
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
*/
public function piggyBanks()
{
return $this->morphedByMany(PiggyBank::class, 'object_groupable');
}
}

View File

@@ -126,6 +126,14 @@ class PiggyBank extends Model
throw new NotFoundHttpException;
}
/**
* Get all of the tags for the post.
*/
public function objectGroups()
{
return $this->morphToMany(ObjectGroup::class, 'object_groupable');
}
/**
* @codeCoverageIgnore
* @return MorphMany

View File

@@ -72,4 +72,4 @@ class Telemetry extends Model
'value' => 'array',
];
}
}

View File

@@ -198,4 +198,4 @@ class OperationsRepository implements OperationsRepositoryInterface
{
throw new FireflyException(sprintf('%s is not yet implemented', __METHOD__));
}
}
}

View File

@@ -84,4 +84,4 @@ interface OperationsRepositoryInterface
* @return array
*/
public function sumIncome(Carbon $start, Carbon $end, ?Collection $accounts = null): array;
}
}

View File

@@ -302,4 +302,4 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
->where('start_date', $start->format('Y-m-d 00:00:00'))
->where('end_date', $end->format('Y-m-d 00:00:00'))->first();
}
}
}

View File

@@ -154,4 +154,4 @@ interface AvailableBudgetRepositoryInterface
*/
public function updateAvailableBudget(AvailableBudget $availableBudget, array $data): AvailableBudget;
}
}

View File

@@ -463,4 +463,4 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface
$budget->budgetlimits()->delete();
}
}
}
}

View File

@@ -146,4 +146,4 @@ interface BudgetLimitRepositoryInterface
*/
public function updateLimitAmount(Budget $budget, Carbon $start, Carbon $end, string $amount): ?BudgetLimit;
}
}

View File

@@ -330,7 +330,7 @@ class BudgetRepository implements BudgetRepositoryInterface
// create initial budget limit.
$today = new Carbon;
$start = app('navigation')->startOfPeriod($today, $autoBudget->period);
$end = app('navigation')->startOfPeriod($start, $autoBudget->period);
$end = app('navigation')->endOfPeriod($start, $autoBudget->period);
$limitRepos = app(BudgetLimitRepositoryInterface::class);
$limitRepos->setUser($this->user);

View File

@@ -200,4 +200,4 @@ class NoBudgetRepository implements NoBudgetRepositoryInterface
return $array;
}
}
}

View File

@@ -70,4 +70,4 @@ interface NoBudgetRepositoryInterface
*/
public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?TransactionCurrency $currency = null): array;
}
}

View File

@@ -433,4 +433,4 @@ class OperationsRepository implements OperationsRepositoryInterface
return $repos->getActiveBudgets();
}
}
}

View File

@@ -123,4 +123,4 @@ interface OperationsRepositoryInterface
*/
public function listExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $budgets = null): array;
}
}

View File

@@ -240,4 +240,4 @@ class NoCategoryRepository implements NoCategoryRepositoryInterface
return $array;
}
}
}

View File

@@ -88,4 +88,4 @@ interface NoCategoryRepositoryInterface
public function sumIncome(Carbon $start, Carbon $end, ?Collection $accounts = null): array;
}
}

View File

@@ -317,4 +317,4 @@ class OperationsRepository implements OperationsRepositoryInterface
return $set;
}
}
}

View File

@@ -89,4 +89,4 @@ interface OperationsRepositoryInterface
* @return array
*/
public function sumIncome(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array;
}
}

View File

@@ -251,4 +251,4 @@ class OperationsRepository implements OperationsRepositoryInterface
return $repository->get();
}
}
}

View File

@@ -90,4 +90,4 @@ interface OperationsRepositoryInterface
* @return array
*/
public function sumIncome(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $tags = null): array;
}
}

View File

@@ -64,4 +64,4 @@ class TelemetryRepository implements TelemetryRepositoryInterface
// created_at is never NULL.
Telemetry::whereNotNull('submitted')->delete();
}
}
}

View File

@@ -56,4 +56,4 @@ interface TelemetryRepositoryInterface
*/
public function deleteSubmitted(): void;
}
}

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