mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-30 02:26:58 +00:00
Merge branch 'pluralization' of https://github.com/sephrat/firefly-iii into pluralization
This commit is contained in:
26
.env.example
26
.env.example
@@ -65,6 +65,17 @@ DB_DATABASE=firefly
|
|||||||
DB_USERNAME=firefly
|
DB_USERNAME=firefly
|
||||||
DB_PASSWORD=secret_firefly_password
|
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.
|
# 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
|
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
|
||||||
PGSQL_SSL_MODE=prefer
|
PGSQL_SSL_MODE=prefer
|
||||||
@@ -170,8 +181,16 @@ ADLDAP_PORT=389
|
|||||||
ADLDAP_TIMEOUT=5
|
ADLDAP_TIMEOUT=5
|
||||||
ADLDAP_BASEDN=""
|
ADLDAP_BASEDN=""
|
||||||
ADLDAP_FOLLOW_REFFERALS=false
|
ADLDAP_FOLLOW_REFFERALS=false
|
||||||
|
|
||||||
|
# SSL/TLS settings
|
||||||
ADLDAP_USE_SSL=false
|
ADLDAP_USE_SSL=false
|
||||||
ADLDAP_USE_TLS=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:
|
# You can set the following variables from a file by appending them with _FILE:
|
||||||
ADLDAP_ADMIN_USERNAME=
|
ADLDAP_ADMIN_USERNAME=
|
||||||
@@ -191,6 +210,7 @@ ADLDAP_AUTH_FIELD=distinguishedname
|
|||||||
|
|
||||||
# Will allow SSO if your server provides an AUTH_USER field.
|
# Will allow SSO if your server provides an AUTH_USER field.
|
||||||
# You can set the following variables from a file by appending them with _FILE:
|
# You can set the following variables from a file by appending them with _FILE:
|
||||||
|
WINDOWS_SSO_ENABLED=false
|
||||||
WINDOWS_SSO_DISCOVER=samaccountname
|
WINDOWS_SSO_DISCOVER=samaccountname
|
||||||
WINDOWS_SSO_KEY=AUTH_USER
|
WINDOWS_SSO_KEY=AUTH_USER
|
||||||
|
|
||||||
@@ -218,8 +238,9 @@ TRACKER_SITE_ID=
|
|||||||
TRACKER_URL=
|
TRACKER_URL=
|
||||||
|
|
||||||
#
|
#
|
||||||
# Firefly III could (in the future) collect telemetry on how you use Firefly III.
|
# 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:
|
# 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
|
SEND_TELEMETRY=false
|
||||||
|
|
||||||
# You can fine tune the start-up of a Docker container by editing these environment variables.
|
# You can fine tune the start-up of a Docker container by editing these environment variables.
|
||||||
@@ -267,7 +288,6 @@ DEMO_USERNAME=
|
|||||||
DEMO_PASSWORD=
|
DEMO_PASSWORD=
|
||||||
USE_ENCRYPTION=false
|
USE_ENCRYPTION=false
|
||||||
IS_SANDSTORM=false
|
IS_SANDSTORM=false
|
||||||
IS_DOCKER=false
|
|
||||||
IS_HEROKU=false
|
IS_HEROKU=false
|
||||||
BUNQ_USE_SANDBOX=false
|
BUNQ_USE_SANDBOX=false
|
||||||
|
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,7 +5,6 @@
|
|||||||
/storage/*.key
|
/storage/*.key
|
||||||
/vendor
|
/vendor
|
||||||
/.vagrant
|
/.vagrant
|
||||||
/.vscode
|
|
||||||
Homestead.json
|
Homestead.json
|
||||||
Homestead.yaml
|
Homestead.yaml
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
|
@@ -269,6 +269,7 @@ class TransactionController extends Controller
|
|||||||
*
|
*
|
||||||
* @param TransactionStoreRequest $request
|
* @param TransactionStoreRequest $request
|
||||||
*
|
*
|
||||||
|
* @throws FireflyException
|
||||||
* @return JsonResponse
|
* @return JsonResponse
|
||||||
*/
|
*/
|
||||||
public function store(TransactionStoreRequest $request): JsonResponse
|
public function store(TransactionStoreRequest $request): JsonResponse
|
||||||
@@ -283,7 +284,7 @@ class TransactionController extends Controller
|
|||||||
try {
|
try {
|
||||||
$transactionGroup = $this->groupRepository->store($data);
|
$transactionGroup = $this->groupRepository->store($data);
|
||||||
} catch (DuplicateTransactionException $e) {
|
} catch (DuplicateTransactionException $e) {
|
||||||
Log::warning('Caught a duplicate. Return error message.');
|
Log::warning('Caught a duplicate transaction. Return error message.');
|
||||||
// return bad validation message.
|
// return bad validation message.
|
||||||
// TODO use Laravel's internal validation thing to do this.
|
// TODO use Laravel's internal validation thing to do this.
|
||||||
$response = [
|
$response = [
|
||||||
@@ -326,7 +327,7 @@ class TransactionController extends Controller
|
|||||||
|
|
||||||
$selectedGroup = $collector->getGroups()->first();
|
$selectedGroup = $collector->getGroups()->first();
|
||||||
if (null === $selectedGroup) {
|
if (null === $selectedGroup) {
|
||||||
throw new NotFoundHttpException(); // @codeCoverageIgnore
|
throw new FireflyException('Cannot find transaction. Possibly, a rule deleted this transaction after its creation.');
|
||||||
}
|
}
|
||||||
/** @var TransactionGroupTransformer $transformer */
|
/** @var TransactionGroupTransformer $transformer */
|
||||||
$transformer = app(TransactionGroupTransformer::class);
|
$transformer = app(TransactionGroupTransformer::class);
|
||||||
|
@@ -83,8 +83,6 @@ class CorrectDatabase extends Command
|
|||||||
echo $result;
|
echo $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -77,8 +77,6 @@ class CorrectOpeningBalanceCurrencies extends Command
|
|||||||
$this->info('There was nothing to fix in the opening balance transactions.');
|
$this->info('There was nothing to fix in the opening balance transactions.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -78,8 +78,6 @@ class CreateAccessTokens extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Verify access tokens in %s seconds.', $end));
|
$this->info(sprintf('Verify access tokens in %s seconds.', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -79,8 +79,6 @@ class CreateLinkTypes extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Verified link types in %s seconds', $end));
|
$this->info(sprintf('Verified link types in %s seconds', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -76,8 +76,6 @@ class DeleteEmptyGroups extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Verified empty groups in %s seconds', $end));
|
$this->info(sprintf('Verified empty groups in %s seconds', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -58,8 +58,6 @@ class DeleteEmptyJournals extends Command
|
|||||||
$this->deleteUnevenJournals();
|
$this->deleteUnevenJournals();
|
||||||
$this->deleteEmptyJournals();
|
$this->deleteEmptyJournals();
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -62,7 +62,6 @@ class DeleteOrphanedTransactions extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Verified orphans in %s seconds', $end));
|
$this->info(sprintf('Verified orphans in %s seconds', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -78,8 +78,6 @@ class DeleteZeroAmount extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Verified zero-amount integrity in %s seconds', $end));
|
$this->info(sprintf('Verified zero-amount integrity in %s seconds', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -101,8 +101,6 @@ class EnableCurrencies extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Verified currencies in %s seconds.', $end));
|
$this->info(sprintf('Verified currencies in %s seconds.', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -106,7 +106,6 @@ class FixAccountTypes extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Verifying account types took %s seconds', $end));
|
$this->info(sprintf('Verifying account types took %s seconds', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -75,7 +75,6 @@ class FixLongDescriptions extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Verified all transaction group and journal title lengths in %s seconds.', $end));
|
$this->info(sprintf('Verified all transaction group and journal title lengths in %s seconds.', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -98,7 +98,6 @@ class FixPiggies extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->line(sprintf('Verified the content of %d piggy bank events in %s seconds.', $set->count(), $end));
|
$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;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -67,7 +67,6 @@ class FixRecurringTransactions extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Corrected recurring transactions %s seconds.', $end));
|
$this->info(sprintf('Corrected recurring transactions %s seconds.', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -75,7 +75,6 @@ class FixUnevenAmount extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Verified amount integrity in %s seconds', $end));
|
$this->info(sprintf('Verified amount integrity in %s seconds', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -71,7 +71,6 @@ class RemoveBills extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Verified bills / journals in %s seconds', $end));
|
$this->info(sprintf('Verified bills / journals in %s seconds', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -83,7 +83,6 @@ class RenameMetaFields extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Renamed meta fields in %s seconds', $end));
|
$this->info(sprintf('Renamed meta fields in %s seconds', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -74,7 +74,6 @@ class TransferBudgets extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Verified budget/journals in %s seconds.', $end));
|
$this->info(sprintf('Verified budget/journals in %s seconds.', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -123,7 +123,6 @@ class DecryptDatabase extends Command
|
|||||||
}
|
}
|
||||||
$this->info('Done!');
|
$this->info('Done!');
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -137,11 +137,11 @@ class ExportData extends Command
|
|||||||
} catch (FireflyException $e) {
|
} catch (FireflyException $e) {
|
||||||
$this->error(sprintf('Could not store data: %s', $e->getMessage()));
|
$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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
app('telemetry')->feature('system.command.executed', $this->signature);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -63,279 +63,14 @@ class CreateCSVImport extends Command
|
|||||||
{configuration? : The configuration file to use for the import.}
|
{configuration? : The configuration file to use for the import.}
|
||||||
{--user=1 : The user ID that the import should import for.}
|
{--user=1 : The user ID that the import should import for.}
|
||||||
{--token= : The user\'s access token.}';
|
{--token= : The user\'s access token.}';
|
||||||
/** @var ImportJob */
|
|
||||||
private $importJob;
|
|
||||||
/** @var ImportJobRepositoryInterface */
|
|
||||||
private $importRepository;
|
|
||||||
/** @var UserRepositoryInterface */
|
|
||||||
private $userRepository;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the command.
|
* Run the command.
|
||||||
*/
|
*/
|
||||||
public function handle(): int
|
public function handle(): int
|
||||||
{
|
{
|
||||||
$this->stupidLaravel();
|
$this->error('This command is disabled.');
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
if (!$this->verifyAccessToken()) {
|
|
||||||
$this->errorLine('Invalid access token.');
|
|
||||||
|
|
||||||
return 1;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -64,7 +64,6 @@ class ReportEmptyObjects extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Report on empty objects finished in %s seconds', $end));
|
$this->info(sprintf('Report on empty objects finished in %s seconds', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -69,7 +69,6 @@ class ReportIntegrity extends Command
|
|||||||
echo $result;
|
echo $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -54,7 +54,6 @@ class ReportSum extends Command
|
|||||||
{
|
{
|
||||||
$this->reportSum();
|
$this->reportSum();
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -24,6 +24,7 @@ namespace FireflyIII\Console\Commands\Integrity;
|
|||||||
|
|
||||||
use FireflyIII\Support\System\OAuthKeys;
|
use FireflyIII\Support\System\OAuthKeys;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class RestoreOAuthKeys
|
* Class RestoreOAuthKeys
|
||||||
@@ -52,7 +53,6 @@ class RestoreOAuthKeys extends Command
|
|||||||
{
|
{
|
||||||
$this->restoreOAuthKeys();
|
$this->restoreOAuthKeys();
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +93,9 @@ class RestoreOAuthKeys extends Command
|
|||||||
*/
|
*/
|
||||||
private function restoreOAuthKeys(): void
|
private function restoreOAuthKeys(): void
|
||||||
{
|
{
|
||||||
|
Log::debug('Going to restoreOAuthKeys()');
|
||||||
if (!$this->keysInDatabase() && !$this->keysOnDrive()) {
|
if (!$this->keysInDatabase() && !$this->keysOnDrive()) {
|
||||||
|
Log::debug('Keys are not in DB and keys are not on the drive.');
|
||||||
$this->generateKeys();
|
$this->generateKeys();
|
||||||
$this->storeKeysInDB();
|
$this->storeKeysInDB();
|
||||||
$this->line('Generated and stored new keys.');
|
$this->line('Generated and stored new keys.');
|
||||||
@@ -101,12 +103,14 @@ class RestoreOAuthKeys extends Command
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($this->keysInDatabase() && !$this->keysOnDrive()) {
|
if ($this->keysInDatabase() && !$this->keysOnDrive()) {
|
||||||
|
Log::debug('Keys are in DB and keys are not on the drive. Restore.');
|
||||||
$this->restoreKeysFromDB();
|
$this->restoreKeysFromDB();
|
||||||
$this->line('Restored OAuth keys from database.');
|
$this->line('Restored OAuth keys from database.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!$this->keysInDatabase() && $this->keysOnDrive()) {
|
if (!$this->keysInDatabase() && $this->keysOnDrive()) {
|
||||||
|
Log::debug('Keys are not in DB and keys are on the drive. Save in DB.');
|
||||||
$this->storeKeysInDB();
|
$this->storeKeysInDB();
|
||||||
$this->line('Stored OAuth keys in database.');
|
$this->line('Stored OAuth keys in database.');
|
||||||
|
|
||||||
|
@@ -86,7 +86,7 @@ class ScanAttachments extends Command
|
|||||||
$this->line(sprintf('Fixed attachment #%d', $attachment->id));
|
$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;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -59,7 +59,7 @@ class SetLatestVersion extends Command
|
|||||||
app('fireflyconfig')->set('ff3_version', config('firefly.version'));
|
app('fireflyconfig')->set('ff3_version', config('firefly.version'));
|
||||||
$this->line('Updated version.');
|
$this->line('Updated version.');
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
app('telemetry')->feature('system.command.executed', $this->signature);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -112,7 +112,7 @@ class ApplyRules extends Command
|
|||||||
|
|
||||||
$result = $this->verifyInput();
|
$result = $this->verifyInput();
|
||||||
if (false === $result) {
|
if (false === $result) {
|
||||||
// app('telemetry')->feature('executed-command-with-error', $this->signature);
|
app('telemetry')->feature('system.command.errored', $this->signature);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ class ApplyRules extends Command
|
|||||||
$this->warn(' --rule_groups=1,2,...');
|
$this->warn(' --rule_groups=1,2,...');
|
||||||
$this->warn(' --all_rules');
|
$this->warn(' --all_rules');
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command-with-error', $this->signature);
|
app('telemetry')->feature('system.command.errored', $this->signature);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ class ApplyRules extends Command
|
|||||||
$this->line('');
|
$this->line('');
|
||||||
$this->line('Done!');
|
$this->line('Done!');
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
app('telemetry')->feature('system.command.executed', $this->signature);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -94,10 +94,10 @@ class Cron extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fire telemetry cron job (disabled):
|
* Fire telemetry cron job
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
//$this->telemetryCronJob($force, $date);
|
$this->telemetryCronJob($force, $date);
|
||||||
} catch (FireflyException $e) {
|
} catch (FireflyException $e) {
|
||||||
Log::error($e->getMessage());
|
Log::error($e->getMessage());
|
||||||
Log::error($e->getTraceAsString());
|
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.');
|
$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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -87,7 +87,6 @@ class AccountCurrencies extends Command
|
|||||||
$this->info(sprintf('Verified and fixed account currencies in %s seconds.', $end));
|
$this->info(sprintf('Verified and fixed account currencies in %s seconds.', $end));
|
||||||
$this->markAsExecuted();
|
$this->markAsExecuted();
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -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->info(sprintf('Updated category and budget info for all transaction journals in %s seconds.', $end));
|
||||||
$this->markAsExecuted();
|
$this->markAsExecuted();
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -92,8 +92,6 @@ class BudgetLimitCurrency extends Command
|
|||||||
|
|
||||||
$this->markAsExecuted();
|
$this->markAsExecuted();
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -91,8 +91,6 @@ class CCLiabilities extends Command
|
|||||||
$this->info(sprintf('Verified credit card liabilities in %s seconds', $end));
|
$this->info(sprintf('Verified credit card liabilities in %s seconds', $end));
|
||||||
$this->markAsExecuted();
|
$this->markAsExecuted();
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -101,8 +101,6 @@ class MigrateAttachments extends Command
|
|||||||
$this->info(sprintf('Migrated attachment notes in %s seconds.', $end));
|
$this->info(sprintf('Migrated attachment notes in %s seconds.', $end));
|
||||||
$this->markAsExecuted();
|
$this->markAsExecuted();
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -100,8 +100,6 @@ class MigrateJournalNotes extends Command
|
|||||||
$this->info(sprintf('Migrated notes in %s seconds.', $end));
|
$this->info(sprintf('Migrated notes in %s seconds.', $end));
|
||||||
$this->markAsExecuted();
|
$this->markAsExecuted();
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -72,8 +72,6 @@ class MigrateRecurrenceMeta extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Migrated recurrence meta data in %s seconds.', $end));
|
$this->info(sprintf('Migrated recurrence meta data in %s seconds.', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -65,7 +65,6 @@ class MigrateTagLocations extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Migrated tag locations in %s seconds.', $end));
|
$this->info(sprintf('Migrated tag locations in %s seconds.', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -112,8 +112,6 @@ class MigrateToGroups extends Command
|
|||||||
|
|
||||||
$this->markAsMigrated();
|
$this->markAsMigrated();
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -99,7 +99,6 @@ class MigrateToRules extends Command
|
|||||||
$this->info(sprintf('Verified and fixed bills in %s seconds.', $end));
|
$this->info(sprintf('Verified and fixed bills in %s seconds.', $end));
|
||||||
$this->markAsExecuted();
|
$this->markAsExecuted();
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -90,7 +90,6 @@ class OtherCurrenciesCorrections extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Verified and fixed transaction currencies in %s seconds.', $end));
|
$this->info(sprintf('Verified and fixed transaction currencies in %s seconds.', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -91,7 +91,6 @@ class RenameAccountMeta extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Fixed account meta data in %s seconds.', $end));
|
$this->info(sprintf('Fixed account meta data in %s seconds.', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -101,7 +101,6 @@ class TransactionIdentifier extends Command
|
|||||||
$this->info(sprintf('Verified and fixed transaction identifiers in %s seconds.', $end));
|
$this->info(sprintf('Verified and fixed transaction identifiers in %s seconds.', $end));
|
||||||
$this->markAsExecuted();
|
$this->markAsExecuted();
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -111,7 +111,6 @@ class TransferCurrenciesCorrections extends Command
|
|||||||
$end = round(microtime(true) - $start, 2);
|
$end = round(microtime(true) - $start, 2);
|
||||||
$this->info(sprintf('Verified and fixed currency information for transfers in %s seconds.', $end));
|
$this->info(sprintf('Verified and fixed currency information for transfers in %s seconds.', $end));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -117,7 +117,6 @@ class UpgradeDatabase extends Command
|
|||||||
// index will set FF3 version.
|
// index will set FF3 version.
|
||||||
app('fireflyconfig')->set('ff3_version', (string) config('firefly.version'));
|
app('fireflyconfig')->set('ff3_version', (string) config('firefly.version'));
|
||||||
|
|
||||||
// app('telemetry')->feature('executed-command', $this->signature);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -57,7 +57,12 @@ class UpgradeFireflyInstructions extends Command
|
|||||||
$this->installInstructions();
|
$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.os.is_docker', $isDocker);
|
||||||
|
app('telemetry')->feature('system.command.executed', $this->signature);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -87,7 +87,7 @@ class Handler extends ExceptionHandler
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response()->json(['message' => 'Internal Firefly III Exception. See log files.', 'exception' => get_class($exception)], 500);
|
return response()->json(['message' => sprintf('Internal Firefly III Exception: %s', $exception->getMessage()), 'exception' => get_class($exception)], 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($exception instanceof NotFoundHttpException) {
|
if ($exception instanceof NotFoundHttpException) {
|
||||||
|
@@ -428,7 +428,7 @@ class TransactionJournalFactory
|
|||||||
->first();
|
->first();
|
||||||
}
|
}
|
||||||
if (null !== $result) {
|
if (null !== $result) {
|
||||||
Log::warning('Found a duplicate!');
|
Log::warning(sprintf('Found a duplicate in errorIfDuplicate because hash %s is not unique!', $hash));
|
||||||
throw new DuplicateTransactionException(sprintf('Duplicate of transaction #%d.', $result->transactionJournal->transaction_group_id));
|
throw new DuplicateTransactionException(sprintf('Duplicate of transaction #%d.', $result->transactionJournal->transaction_group_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -118,6 +118,7 @@ class UserEventHandler
|
|||||||
if ($repository->hasRole($user, 'demo')) {
|
if ($repository->hasRole($user, 'demo')) {
|
||||||
// set user back to English.
|
// set user back to English.
|
||||||
app('preferences')->setForUser($user, 'language', 'en_US');
|
app('preferences')->setForUser($user, 'language', 'en_US');
|
||||||
|
app('preferences')->setForUser($user, 'locale', 'equal');
|
||||||
app('preferences')->mark();
|
app('preferences')->mark();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -54,6 +54,7 @@ class VersionCheckEventHandler
|
|||||||
$value = (int) $permission->data;
|
$value = (int) $permission->data;
|
||||||
if (1 !== $value) {
|
if (1 !== $value) {
|
||||||
Log::info('Update check is not enabled.');
|
Log::info('Update check is not enabled.');
|
||||||
|
$this->warnToCheckForUpdates($event);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -85,4 +86,36 @@ class VersionCheckEventHandler
|
|||||||
session()->flash($release['level'], $release['message']);
|
session()->flash($release['level'], $release['message']);
|
||||||
app('fireflyconfig')->set('last_update_check', time());
|
app('fireflyconfig')->set('last_update_check', time());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param RequestedVersionCheckStatus $event
|
||||||
|
*/
|
||||||
|
protected function warnToCheckForUpdates(RequestedVersionCheckStatus $event): void
|
||||||
|
{
|
||||||
|
/** @var UserRepositoryInterface $repository */
|
||||||
|
$repository = app(UserRepositoryInterface::class);
|
||||||
|
/** @var User $user */
|
||||||
|
$user = $event->user;
|
||||||
|
if (!$repository->hasRole($user, 'owner')) {
|
||||||
|
Log::debug('User is not admin, done.');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var Configuration $lastCheckTime */
|
||||||
|
$lastCheckTime = app('fireflyconfig')->get('last_update_warning', time());
|
||||||
|
$now = time();
|
||||||
|
$diff = $now - $lastCheckTime->data;
|
||||||
|
Log::debug(sprintf('Last warning time is %d, current time is %d, difference is %d', $lastCheckTime->data, $now, $diff));
|
||||||
|
if ($diff < 604800 * 4) {
|
||||||
|
Log::debug(sprintf('Warned about updates less than four weeks ago (on %s).', date('Y-m-d H:i:s', $lastCheckTime->data)));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// last check time was more than a week ago.
|
||||||
|
Log::debug('Have warned about a new version in four weeks!');
|
||||||
|
|
||||||
|
session()->flash('info', (string) trans('firefly.disabled_but_check'));
|
||||||
|
app('fireflyconfig')->set('last_update_warning', time());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,16 +31,11 @@ use FireflyIII\Helpers\Collector\Extensions\AmountCollection;
|
|||||||
use FireflyIII\Helpers\Collector\Extensions\CollectorProperties;
|
use FireflyIII\Helpers\Collector\Extensions\CollectorProperties;
|
||||||
use FireflyIII\Helpers\Collector\Extensions\MetaCollection;
|
use FireflyIII\Helpers\Collector\Extensions\MetaCollection;
|
||||||
use FireflyIII\Helpers\Collector\Extensions\TimeCollection;
|
use FireflyIII\Helpers\Collector\Extensions\TimeCollection;
|
||||||
use FireflyIII\Models\Bill;
|
|
||||||
use FireflyIII\Models\Budget;
|
|
||||||
use FireflyIII\Models\Category;
|
|
||||||
use FireflyIII\Models\Tag;
|
|
||||||
use FireflyIII\Models\TransactionCurrency;
|
use FireflyIII\Models\TransactionCurrency;
|
||||||
use FireflyIII\Models\TransactionGroup;
|
use FireflyIII\Models\TransactionGroup;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
||||||
use Illuminate\Database\Query\JoinClause;
|
use Illuminate\Database\Query\JoinClause;
|
||||||
use Illuminate\Pagination\LengthAwarePaginator;
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -526,7 +521,7 @@ class GroupCollector implements GroupCollectorInterface
|
|||||||
}
|
}
|
||||||
// or parse the rest.
|
// or parse the rest.
|
||||||
$journalId = (int) $augumentedJournal->transaction_journal_id;
|
$journalId = (int) $augumentedJournal->transaction_journal_id;
|
||||||
$groups[$groupId]['count']++;
|
|
||||||
|
|
||||||
if (isset($groups[$groupId]['transactions'][$journalId])) {
|
if (isset($groups[$groupId]['transactions'][$journalId])) {
|
||||||
// append data to existing group + journal (for multiple tags or multiple attachments)
|
// append data to existing group + journal (for multiple tags or multiple attachments)
|
||||||
@@ -536,6 +531,7 @@ class GroupCollector implements GroupCollectorInterface
|
|||||||
|
|
||||||
if (!isset($groups[$groupId]['transactions'][$journalId])) {
|
if (!isset($groups[$groupId]['transactions'][$journalId])) {
|
||||||
// create second, third, fourth split:
|
// create second, third, fourth split:
|
||||||
|
$groups[$groupId]['count']++;
|
||||||
$groups[$groupId]['transactions'][$journalId] = $this->parseAugmentedJournal($augumentedJournal);
|
$groups[$groupId]['transactions'][$journalId] = $this->parseAugmentedJournal($augumentedJournal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -109,15 +109,13 @@ class NetWorth implements NetWorthInterface
|
|||||||
|
|
||||||
Log::debug(sprintf('Balance is %s', $balance));
|
Log::debug(sprintf('Balance is %s', $balance));
|
||||||
|
|
||||||
// if the account is a credit card, subtract the virtual balance from the balance,
|
// always subtract virtual balance.
|
||||||
// to better reflect that this is not money that is actually "yours".
|
|
||||||
$role = (string) $this->accountRepository->getMetaValue($account, 'account_role');
|
|
||||||
$virtualBalance = (string) $account->virtual_balance;
|
$virtualBalance = (string) $account->virtual_balance;
|
||||||
if ('ccAsset' === $role && '' !== $virtualBalance && (float) $virtualBalance > 0) {
|
if ('' !== $virtualBalance) {
|
||||||
$balance = bcsub($balance, $virtualBalance);
|
$balance = bcsub($balance, $virtualBalance);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::debug(sprintf('Balance corrected to %s', $balance));
|
Log::debug(sprintf('Balance corrected to %s because of virtual balance (%s)', $balance, $virtualBalance));
|
||||||
|
|
||||||
if (!isset($netWorth[$currencyId])) {
|
if (!isset($netWorth[$currencyId])) {
|
||||||
$netWorth[$currencyId] = '0';
|
$netWorth[$currencyId] = '0';
|
||||||
|
@@ -101,7 +101,8 @@ class TelemetryController extends Controller
|
|||||||
app('view')->share('subTitleIcon', 'fa-eye');
|
app('view')->share('subTitleIcon', 'fa-eye');
|
||||||
app('view')->share('subTitle', (string) trans('firefly.telemetry_admin_index'));
|
app('view')->share('subTitle', (string) trans('firefly.telemetry_admin_index'));
|
||||||
$version = config('firefly.version');
|
$version = config('firefly.version');
|
||||||
$enabled = config('firefly.telemetry', false);
|
$enabled = config('firefly.send_telemetry', false) && config('firefly.feature_flags.telemetry');
|
||||||
|
|
||||||
$count = $this->repository->count();
|
$count = $this->repository->count();
|
||||||
|
|
||||||
return view('admin.telemetry.index', compact('version', 'enabled', 'count'));
|
return view('admin.telemetry.index', compact('version', 'enabled', 'count'));
|
||||||
|
@@ -82,14 +82,8 @@ class LoginController extends Controller
|
|||||||
Log::channel('audit')->info(sprintf('User is trying to login using "%s"', $request->get('email')));
|
Log::channel('audit')->info(sprintf('User is trying to login using "%s"', $request->get('email')));
|
||||||
Log::info(sprintf('User is trying to login.'));
|
Log::info(sprintf('User is trying to login.'));
|
||||||
if ('ldap' === config('auth.providers.users.driver')) {
|
if ('ldap' === config('auth.providers.users.driver')) {
|
||||||
/**
|
|
||||||
* Temporary bug fix for something that doesn't seem to work in
|
|
||||||
* AdLdap.
|
|
||||||
*/
|
|
||||||
$schema = config('ldap.connections.default.schema');
|
|
||||||
|
|
||||||
/** @var Adldap\Connections\Provider $provider */
|
/** @var Adldap\Connections\Provider $provider */
|
||||||
Adldap::getProvider('default')->setSchema(new $schema);
|
Adldap::getProvider('default');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->validateLogin($request);
|
$this->validateLogin($request);
|
||||||
@@ -137,6 +131,7 @@ class LoginController extends Controller
|
|||||||
return redirect(route('register')); // @codeCoverageIgnore
|
return redirect(route('register')); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// is allowed to?
|
// is allowed to?
|
||||||
$singleUserMode = app('fireflyconfig')->get('single_user_mode', config('firefly.configuration.single_user_mode'))->data;
|
$singleUserMode = app('fireflyconfig')->get('single_user_mode', config('firefly.configuration.single_user_mode'))->data;
|
||||||
$allowRegistration = true;
|
$allowRegistration = true;
|
||||||
@@ -154,6 +149,9 @@ class LoginController extends Controller
|
|||||||
$email = $request->old('email');
|
$email = $request->old('email');
|
||||||
$remember = $request->old('remember');
|
$remember = $request->old('remember');
|
||||||
|
|
||||||
|
// todo must forget 2FA if user ends up here.
|
||||||
|
|
||||||
|
|
||||||
return view('auth.login', compact('allowRegistration', 'email', 'remember', 'allowReset', 'title'));
|
return view('auth.login', compact('allowRegistration', 'email', 'remember', 'allowReset', 'title'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -104,6 +104,9 @@ class RegisterController extends Controller
|
|||||||
|
|
||||||
$this->registered($request, $user);
|
$this->registered($request, $user);
|
||||||
|
|
||||||
|
// telemetry
|
||||||
|
\Telemetry::feature('system.users.count', User::count());
|
||||||
|
|
||||||
return redirect($this->redirectPath());
|
return redirect($this->redirectPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -157,6 +157,7 @@ class AvailableBudgetController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function edit(AvailableBudget $availableBudget, Carbon $start, Carbon $end)
|
public function edit(AvailableBudget $availableBudget, Carbon $start, Carbon $end)
|
||||||
{
|
{
|
||||||
|
$availableBudget->amount = round($availableBudget->amount, $availableBudget->transactionCurrency->decimal_places);
|
||||||
return view('budgets.available-budgets.edit', compact('availableBudget', 'start', 'end'));
|
return view('budgets.available-budgets.edit', compact('availableBudget', 'start', 'end'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -132,6 +132,7 @@ class BudgetLimitController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
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.
|
// first search for existing one and update it if necessary.
|
||||||
$currency = $this->currencyRepos->find((int) $request->get('transaction_currency_id'));
|
$currency = $this->currencyRepos->find((int) $request->get('transaction_currency_id'));
|
||||||
$budget = $this->repository->findNull((int) $request->get('budget_id'));
|
$budget = $this->repository->findNull((int) $request->get('budget_id'));
|
||||||
@@ -143,7 +144,6 @@ class BudgetLimitController extends Controller
|
|||||||
$start->startOfDay();
|
$start->startOfDay();
|
||||||
$end->endOfDay();
|
$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')));
|
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);
|
$limit = $this->blRepository->find($budget, $currency, $start, $end);
|
||||||
|
@@ -97,6 +97,7 @@ class IndexController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function index(Request $request, Carbon $start = null, Carbon $end = null)
|
public function index(Request $request, Carbon $start = null, Carbon $end = null)
|
||||||
{
|
{
|
||||||
|
Log::debug('Start of IndexController::index()');
|
||||||
// collect some basic vars:
|
// collect some basic vars:
|
||||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||||
$start = $start ?? session('start', Carbon::now()->startOfMonth());
|
$start = $start ?? session('start', Carbon::now()->startOfMonth());
|
||||||
@@ -104,15 +105,18 @@ class IndexController extends Controller
|
|||||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||||
$budgeted = '0';
|
$budgeted = '0';
|
||||||
$spent = '0';
|
$spent = '0';
|
||||||
|
Log::debug(sprintf('1) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
|
|
||||||
// new period stuff:
|
// new period stuff:
|
||||||
$periodTitle = app('navigation')->periodShow($start, $range);
|
$periodTitle = app('navigation')->periodShow($start, $range);
|
||||||
$prevLoop = $this->getPreviousPeriods($start, $range);
|
$prevLoop = $this->getPreviousPeriods($start, $range);
|
||||||
$nextLoop = $this->getNextPeriods($start, $range);
|
$nextLoop = $this->getNextPeriods($start, $range);
|
||||||
|
Log::debug(sprintf('2) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
|
|
||||||
// get all available budgets.
|
// get all available budgets.
|
||||||
$ab = $this->abRepository->get($start, $end);
|
$ab = $this->abRepository->get($start, $end);
|
||||||
$availableBudgets = [];
|
$availableBudgets = [];
|
||||||
|
Log::debug(sprintf('3) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
// for each, complement with spent amount:
|
// for each, complement with spent amount:
|
||||||
/** @var AvailableBudget $entry */
|
/** @var AvailableBudget $entry */
|
||||||
foreach ($ab as $entry) {
|
foreach ($ab as $entry) {
|
||||||
@@ -129,6 +133,7 @@ class IndexController extends Controller
|
|||||||
$array['budgeted'] = $budgeted;
|
$array['budgeted'] = $budgeted;
|
||||||
$availableBudgets[] = $array;
|
$availableBudgets[] = $array;
|
||||||
unset($spentArr);
|
unset($spentArr);
|
||||||
|
Log::debug(sprintf('4) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 === count($availableBudgets)) {
|
if (0 === count($availableBudgets)) {
|
||||||
@@ -137,6 +142,7 @@ class IndexController extends Controller
|
|||||||
$spentArr = $this->opsRepository->sumExpenses($start, $end, null, null, $defaultCurrency);
|
$spentArr = $this->opsRepository->sumExpenses($start, $end, null, null, $defaultCurrency);
|
||||||
$spent = $spentArr[$defaultCurrency->id]['sum'] ?? '0';
|
$spent = $spentArr[$defaultCurrency->id]['sum'] ?? '0';
|
||||||
unset($spentArr);
|
unset($spentArr);
|
||||||
|
Log::debug(sprintf('5) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
}
|
}
|
||||||
|
|
||||||
// count the number of enabled currencies. This determines if we display a "+" button.
|
// count the number of enabled currencies. This determines if we display a "+" button.
|
||||||
@@ -146,11 +152,12 @@ class IndexController extends Controller
|
|||||||
// number of days for consistent budgeting.
|
// number of days for consistent budgeting.
|
||||||
$activeDaysPassed = $this->activeDaysPassed($start, $end); // see method description.
|
$activeDaysPassed = $this->activeDaysPassed($start, $end); // see method description.
|
||||||
$activeDaysLeft = $this->activeDaysLeft($start, $end); // see method description.
|
$activeDaysLeft = $this->activeDaysLeft($start, $end); // see method description.
|
||||||
Log::debug(sprintf('Start: %s, end: %s', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
Log::debug(sprintf('6) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
|
|
||||||
// get all budgets, and paginate them into $budgets.
|
// get all budgets, and paginate them into $budgets.
|
||||||
$collection = $this->repository->getActiveBudgets();
|
$collection = $this->repository->getActiveBudgets();
|
||||||
$budgets = [];
|
$budgets = [];
|
||||||
|
Log::debug(sprintf('7) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
|
|
||||||
// complement budget with budget limits in range, and expenses in currency X in range.
|
// complement budget with budget limits in range, and expenses in currency X in range.
|
||||||
/** @var Budget $current */
|
/** @var Budget $current */
|
||||||
@@ -161,18 +168,22 @@ class IndexController extends Controller
|
|||||||
$array['attachments'] = $this->repository->getAttachments($current);
|
$array['attachments'] = $this->repository->getAttachments($current);
|
||||||
$array['auto_budget'] = $this->repository->getAutoBudget($current);
|
$array['auto_budget'] = $this->repository->getAutoBudget($current);
|
||||||
$budgetLimits = $this->blRepository->getBudgetLimits($current, $start, $end);
|
$budgetLimits = $this->blRepository->getBudgetLimits($current, $start, $end);
|
||||||
|
Log::debug(sprintf('8) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
/** @var BudgetLimit $limit */
|
/** @var BudgetLimit $limit */
|
||||||
foreach ($budgetLimits as $limit) {
|
foreach ($budgetLimits as $limit) {
|
||||||
$currency = $limit->transactionCurrency ?? $defaultCurrency;
|
$currency = $limit->transactionCurrency ?? $defaultCurrency;
|
||||||
$array['budgeted'][] = [
|
$array['budgeted'][] = [
|
||||||
'id' => $limit->id,
|
'id' => $limit->id,
|
||||||
'amount' => round($limit->amount, $currency->decimal_places),
|
'amount' => round($limit->amount, $currency->decimal_places),
|
||||||
|
'start_date' => $limit->start_date->formatLocalized($this->monthAndDayFormat),
|
||||||
|
'end_date' => $limit->end_date->formatLocalized($this->monthAndDayFormat),
|
||||||
|
'in_range' => $limit->start_date->isSameDay($start) && $limit->end_date->isSameDay($end),
|
||||||
'currency_id' => $currency->id,
|
'currency_id' => $currency->id,
|
||||||
'currency_symbol' => $currency->symbol,
|
'currency_symbol' => $currency->symbol,
|
||||||
'currency_name' => $currency->name,
|
'currency_name' => $currency->name,
|
||||||
'currency_decimal_places' => $currency->decimal_places,
|
'currency_decimal_places' => $currency->decimal_places,
|
||||||
];
|
];
|
||||||
|
Log::debug(sprintf('9) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var TransactionCurrency $currency */
|
/** @var TransactionCurrency $currency */
|
||||||
@@ -183,6 +194,7 @@ class IndexController extends Controller
|
|||||||
$array['spent'][$currency->id]['currency_id'] = $currency->id;
|
$array['spent'][$currency->id]['currency_id'] = $currency->id;
|
||||||
$array['spent'][$currency->id]['currency_symbol'] = $currency->symbol;
|
$array['spent'][$currency->id]['currency_symbol'] = $currency->symbol;
|
||||||
$array['spent'][$currency->id]['currency_decimal_places'] = $currency->decimal_places;
|
$array['spent'][$currency->id]['currency_decimal_places'] = $currency->decimal_places;
|
||||||
|
Log::debug(sprintf('10) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$budgets[] = $array;
|
$budgets[] = $array;
|
||||||
@@ -190,7 +202,7 @@ class IndexController extends Controller
|
|||||||
|
|
||||||
// get all inactive budgets, and simply list them:
|
// get all inactive budgets, and simply list them:
|
||||||
$inactive = $this->repository->getInactiveBudgets();
|
$inactive = $this->repository->getInactiveBudgets();
|
||||||
|
Log::debug(sprintf('11) Start is "%s", end is "%s"', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||||
|
|
||||||
return view(
|
return view(
|
||||||
'budgets.index',
|
'budgets.index',
|
||||||
|
@@ -121,11 +121,11 @@ class DebugController extends Controller
|
|||||||
$search = ['~', '#'];
|
$search = ['~', '#'];
|
||||||
$replace = ['\~', '# '];
|
$replace = ['\~', '# '];
|
||||||
|
|
||||||
|
$now = Carbon::now()->format('Y-m-d H:i:s e');
|
||||||
$installationId = app('fireflyconfig')->get('installation_id', '')->data;
|
$installationId = app('fireflyconfig')->get('installation_id', '')->data;
|
||||||
$phpVersion = str_replace($search, $replace, PHP_VERSION);
|
$phpVersion = str_replace($search, $replace, PHP_VERSION);
|
||||||
$phpOs = str_replace($search, $replace, PHP_OS);
|
$phpOs = str_replace($search, $replace, PHP_OS);
|
||||||
$interface = PHP_SAPI;
|
$interface = PHP_SAPI;
|
||||||
$now = Carbon::now()->format('Y-m-d H:i:s e');
|
|
||||||
$drivers = implode(', ', DB::availableDrivers());
|
$drivers = implode(', ', DB::availableDrivers());
|
||||||
$currentDriver = DB::getDriverName();
|
$currentDriver = DB::getDriverName();
|
||||||
$userAgent = $request->header('user-agent');
|
$userAgent = $request->header('user-agent');
|
||||||
@@ -137,7 +137,15 @@ class DebugController extends Controller
|
|||||||
$logChannel = config('logging.default');
|
$logChannel = config('logging.default');
|
||||||
$appLogLevel = config('logging.level');
|
$appLogLevel = config('logging.level');
|
||||||
$cacheDriver = config('cache.default');
|
$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:
|
// set languages, see what happens:
|
||||||
$original = setlocale(LC_ALL, 0);
|
$original = setlocale(LC_ALL, 0);
|
||||||
@@ -145,6 +153,7 @@ class DebugController extends Controller
|
|||||||
$parts = app('steam')->getLocaleArray(app('steam')->getLocale());
|
$parts = app('steam')->getLocaleArray(app('steam')->getLocale());
|
||||||
foreach ($parts as $code) {
|
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);
|
$localeAttempts[$code] = var_export(setlocale(LC_ALL, $code), true);
|
||||||
}
|
}
|
||||||
setlocale(LC_ALL, $original);
|
setlocale(LC_ALL, $original);
|
||||||
@@ -194,7 +203,14 @@ class DebugController extends Controller
|
|||||||
'interface',
|
'interface',
|
||||||
'logContent',
|
'logContent',
|
||||||
'cacheDriver',
|
'cacheDriver',
|
||||||
'trustedProxies'
|
'trustedProxies',
|
||||||
|
'telemetry',
|
||||||
|
'userLanguage',
|
||||||
|
'userLocale',
|
||||||
|
'defaultLanguage',
|
||||||
|
'defaultLocale',
|
||||||
|
'isDocker'
|
||||||
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -124,6 +124,11 @@ class NewUserController extends Controller
|
|||||||
'invoice_date' => false, 'internal_reference' => false, 'notes' => true, 'attachments' => true,];
|
'invoice_date' => false, 'internal_reference' => false, 'notes' => true, 'attachments' => true,];
|
||||||
app('preferences')->set('transaction_journal_optional_fields', $visibleFields);
|
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'));
|
session()->flash('success', (string) trans('firefly.stored_new_accounts_new_user'));
|
||||||
app('preferences')->mark();
|
app('preferences')->mark();
|
||||||
|
|
||||||
|
@@ -186,9 +186,11 @@ class PreferencesController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
// same for locale:
|
// same for locale:
|
||||||
|
if (!auth()->user()->hasRole('demo')) {
|
||||||
/** @var Preference $currentLocale */
|
/** @var Preference $currentLocale */
|
||||||
$locale = $request->get('locale');
|
$locale = $request->get('locale');
|
||||||
app('preferences')->set('locale', $locale);
|
app('preferences')->set('locale', $locale);
|
||||||
|
}
|
||||||
|
|
||||||
// optional fields for transactions:
|
// optional fields for transactions:
|
||||||
$setOptions = $request->get('tj');
|
$setOptions = $request->get('tj');
|
||||||
@@ -208,6 +210,11 @@ class PreferencesController extends Controller
|
|||||||
session()->flash('success', (string) trans('firefly.saved_preferences'));
|
session()->flash('success', (string) trans('firefly.saved_preferences'));
|
||||||
app('preferences')->mark();
|
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'));
|
return redirect(route('preferences.index'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -91,6 +91,7 @@ class IndexController extends Controller
|
|||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
$this->createDefaultRuleGroup();
|
$this->createDefaultRuleGroup();
|
||||||
$this->createDefaultRule();
|
$this->createDefaultRule();
|
||||||
|
$this->ruleGroupRepos->resetRuleGroupOrder();
|
||||||
$ruleGroups = $this->ruleGroupRepos->getRuleGroupsWithRules($user);
|
$ruleGroups = $this->ruleGroupRepos->getRuleGroupsWithRules($user);
|
||||||
|
|
||||||
return view('rules.index', compact('ruleGroups'));
|
return view('rules.index', compact('ruleGroups'));
|
||||||
|
@@ -42,6 +42,7 @@ class CronController
|
|||||||
$results = [];
|
$results = [];
|
||||||
$results[] = $this->runRecurring();
|
$results[] = $this->runRecurring();
|
||||||
$results[] = $this->runAutoBudget();
|
$results[] = $this->runAutoBudget();
|
||||||
|
$results[] = $this->runTelemetry();
|
||||||
|
|
||||||
return implode("<br>\n", $results);
|
return implode("<br>\n", $results);
|
||||||
}
|
}
|
||||||
|
@@ -28,6 +28,7 @@ use Closure;
|
|||||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||||
use FireflyIII\Support\Http\Controllers\RequestInformation;
|
use FireflyIII\Support\Http\Controllers\RequestInformation;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class SessionFilter.
|
* Class SessionFilter.
|
||||||
@@ -87,6 +88,7 @@ class Range
|
|||||||
|
|
||||||
// send error to view if could not set money format
|
// send error to view if could not set money format
|
||||||
if (false === $moneyResult) {
|
if (false === $moneyResult) {
|
||||||
|
Log::error('Could not set locale. The following array doesnt work: ', $localeArray);
|
||||||
app('view')->share('invalidMonetaryLocale', true); // @codeCoverageIgnore
|
app('view')->share('invalidMonetaryLocale', true); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -84,7 +84,7 @@ class MailError extends Job implements ShouldQueue
|
|||||||
$args,
|
$args,
|
||||||
function (Message $message) use ($email) {
|
function (Message $message) use ($email) {
|
||||||
if ('mail@example.com' !== $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'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@@ -24,6 +24,7 @@ namespace FireflyIII\Jobs;
|
|||||||
|
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Models\Telemetry;
|
use FireflyIII\Models\Telemetry;
|
||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Client;
|
||||||
use GuzzleHttp\Exception\GuzzleException;
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
@@ -33,7 +34,9 @@ use Illuminate\Foundation\Bus\Dispatchable;
|
|||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use JsonException;
|
||||||
use Log;
|
use Log;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class SubmitTelemetryData
|
* Class SubmitTelemetryData
|
||||||
@@ -61,7 +64,7 @@ class SubmitTelemetryData implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @throws FireflyException
|
||||||
*/
|
*/
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
@@ -77,9 +80,17 @@ class SubmitTelemetryData implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
$json = $this->parseJson($telemetry);
|
$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;
|
$client = new Client;
|
||||||
$options = [
|
$options = [
|
||||||
'body' => json_encode($json, JSON_THROW_ON_ERROR, 512),
|
'body' => $body,
|
||||||
'headers' => [
|
'headers' => [
|
||||||
'Content-Type' => 'application/json',
|
'Content-Type' => 'application/json',
|
||||||
'Accept' => 'application/json',
|
'Accept' => 'application/json',
|
||||||
@@ -89,11 +100,11 @@ class SubmitTelemetryData implements ShouldQueue
|
|||||||
];
|
];
|
||||||
try {
|
try {
|
||||||
$result = $client->post($url, $options);
|
$result = $client->post($url, $options);
|
||||||
} catch (GuzzleException $e) {
|
} catch (GuzzleException|Exception $e) {
|
||||||
Log::error($e->getMessage());
|
Log::error($e->getMessage());
|
||||||
Log::error($e->getTraceAsString());
|
Log::error($e->getTraceAsString());
|
||||||
Log::error('Could not submit telemetry.');
|
Log::error('Could not submit telemetry.');
|
||||||
return;
|
throw new FireflyException(sprintf('Could not submit telemetry: %s', $e->getMessage()));
|
||||||
}
|
}
|
||||||
$body = (string) $result->getBody();
|
$body = (string) $result->getBody();
|
||||||
$statusCode = $result->getStatusCode();
|
$statusCode = $result->getStatusCode();
|
||||||
@@ -156,6 +167,7 @@ class SubmitTelemetryData implements ShouldQueue
|
|||||||
foreach ($telemetry as $entry) {
|
foreach ($telemetry as $entry) {
|
||||||
$array[] = [
|
$array[] = [
|
||||||
'installation_id' => $entry->installation_id,
|
'installation_id' => $entry->installation_id,
|
||||||
|
'collected_at' => $entry->created_at->format('r'),
|
||||||
'type' => $entry->type,
|
'type' => $entry->type,
|
||||||
'key' => $entry->key,
|
'key' => $entry->key,
|
||||||
'value' => $entry->value,
|
'value' => $entry->value,
|
||||||
|
@@ -63,6 +63,6 @@ class AccessTokenCreatedMail extends Mailable
|
|||||||
public function build(): self
|
public function build(): self
|
||||||
{
|
{
|
||||||
return $this->view('emails.access-token-created-html')->text('emails.access-token-created-text')
|
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'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -62,6 +62,6 @@ class AdminTestMail extends Mailable
|
|||||||
public function build(): self
|
public function build(): self
|
||||||
{
|
{
|
||||||
return $this->view('emails.admin-test-html')->text('emails.admin-test-text')
|
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'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -70,6 +70,6 @@ class ConfirmEmailChangeMail extends Mailable
|
|||||||
public function build(): self
|
public function build(): self
|
||||||
{
|
{
|
||||||
return $this->view('emails.confirm-email-change-html')->text('emails.confirm-email-change-text')
|
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'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -67,6 +67,6 @@ class OAuthTokenCreatedMail extends Mailable
|
|||||||
public function build(): self
|
public function build(): self
|
||||||
{
|
{
|
||||||
return $this->view('emails.oauth-client-created-html')->text('emails.oauth-client-created-text')
|
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'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -61,6 +61,6 @@ class RegisteredUser extends Mailable
|
|||||||
*/
|
*/
|
||||||
public function build(): self
|
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'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -79,7 +79,7 @@ class ReportNewJournalsMail extends Mailable
|
|||||||
$this->transform();
|
$this->transform();
|
||||||
|
|
||||||
return $this->view('emails.report-new-journals-html')->text('emails.report-new-journals-text')
|
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
|
private function transform(): void
|
||||||
|
@@ -60,6 +60,6 @@ class RequestedNewPassword extends Mailable
|
|||||||
*/
|
*/
|
||||||
public function build(): self
|
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'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -68,6 +68,6 @@ class UndoEmailChangeMail extends Mailable
|
|||||||
public function build(): self
|
public function build(): self
|
||||||
{
|
{
|
||||||
return $this->view('emails.undo-email-change-html')->text('emails.undo-email-change-text')
|
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'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -26,6 +26,7 @@ use Illuminate\Support\Facades\Schema;
|
|||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
use Laravel\Passport\Passport;
|
use Laravel\Passport\Passport;
|
||||||
use URL;
|
use URL;
|
||||||
|
use Adldap\Laravel\Middleware\WindowsAuthenticate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
@@ -44,6 +45,9 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
if ('heroku' === config('app.env')) {
|
if ('heroku' === config('app.env')) {
|
||||||
URL::forceScheme('https');
|
URL::forceScheme('https');
|
||||||
}
|
}
|
||||||
|
if (config('ldap_auth.identifiers.windows.enabled', false)) {
|
||||||
|
$this->app['router']->pushMiddlewareToGroup('web', WindowsAuthenticate::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -330,7 +330,7 @@ class BudgetRepository implements BudgetRepositoryInterface
|
|||||||
// create initial budget limit.
|
// create initial budget limit.
|
||||||
$today = new Carbon;
|
$today = new Carbon;
|
||||||
$start = app('navigation')->startOfPeriod($today, $autoBudget->period);
|
$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 = app(BudgetLimitRepositoryInterface::class);
|
||||||
$limitRepos->setUser($this->user);
|
$limitRepos->setUser($this->user);
|
||||||
|
@@ -92,12 +92,18 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
|
|||||||
{
|
{
|
||||||
$this->user->ruleGroups()->whereNotNull('deleted_at')->update(['order' => 0]);
|
$this->user->ruleGroups()->whereNotNull('deleted_at')->update(['order' => 0]);
|
||||||
|
|
||||||
$set = $this->user->ruleGroups()->where('active', 1)->orderBy('order', 'ASC')->get();
|
$set = $this->user
|
||||||
|
->ruleGroups()
|
||||||
|
->orderBy('order', 'ASC')->get();
|
||||||
$count = 1;
|
$count = 1;
|
||||||
/** @var RuleGroup $entry */
|
/** @var RuleGroup $entry */
|
||||||
foreach ($set as $entry) {
|
foreach ($set as $entry) {
|
||||||
$entry->order = $count;
|
$entry->order = $count;
|
||||||
$entry->save();
|
$entry->save();
|
||||||
|
|
||||||
|
// also update rules in group.
|
||||||
|
$this->resetRulesInGroupOrder($entry);
|
||||||
|
|
||||||
++$count;
|
++$count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,18 +215,16 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
|
|||||||
public function getRuleGroupsWithRules(User $user): Collection
|
public function getRuleGroupsWithRules(User $user): Collection
|
||||||
{
|
{
|
||||||
return $user->ruleGroups()
|
return $user->ruleGroups()
|
||||||
->orderBy('active', 'DESC')
|
|
||||||
->orderBy('order', 'ASC')
|
->orderBy('order', 'ASC')
|
||||||
->with(
|
->with(
|
||||||
[
|
[
|
||||||
'rules' => function (HasMany $query) {
|
'rules' => static function (HasMany $query) {
|
||||||
$query->orderBy('active', 'DESC');
|
|
||||||
$query->orderBy('order', 'ASC');
|
$query->orderBy('order', 'ASC');
|
||||||
},
|
},
|
||||||
'rules.ruleTriggers' => function (HasMany $query) {
|
'rules.ruleTriggers' => static function (HasMany $query) {
|
||||||
$query->orderBy('order', 'ASC');
|
$query->orderBy('order', 'ASC');
|
||||||
},
|
},
|
||||||
'rules.ruleActions' => function (HasMany $query) {
|
'rules.ruleActions' => static function (HasMany $query) {
|
||||||
$query->orderBy('order', 'ASC');
|
$query->orderBy('order', 'ASC');
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -353,4 +357,5 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
|
|||||||
{
|
{
|
||||||
return $this->user->ruleGroups()->where('title', $title)->first();
|
return $this->user->ruleGroups()->where('title', $title)->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -346,6 +346,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
|||||||
Log::warning('Group repository caught group factory with a duplicate exception!');
|
Log::warning('Group repository caught group factory with a duplicate exception!');
|
||||||
throw new DuplicateTransactionException($e->getMessage());
|
throw new DuplicateTransactionException($e->getMessage());
|
||||||
} catch(FireflyException $e) {
|
} catch(FireflyException $e) {
|
||||||
|
Log::warning('Group repository caught group factory with an exception!');
|
||||||
Log::error($e->getMessage());
|
Log::error($e->getMessage());
|
||||||
Log::error($e->getTraceAsString());
|
Log::error($e->getTraceAsString());
|
||||||
throw new FireflyException($e->getMessage());
|
throw new FireflyException($e->getMessage());
|
||||||
|
@@ -95,8 +95,6 @@ class JournalDestroyService
|
|||||||
// update events
|
// update events
|
||||||
$journal->piggyBankEvents()->update(['transaction_journal_id' => null]);
|
$journal->piggyBankEvents()->update(['transaction_journal_id' => null]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$journal->delete();
|
$journal->delete();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Log::error(sprintf('Could not delete bill: %s', $e->getMessage())); // @codeCoverageIgnore
|
Log::error(sprintf('Could not delete bill: %s', $e->getMessage())); // @codeCoverageIgnore
|
||||||
|
@@ -52,11 +52,10 @@ class AccountList implements BinderInterface
|
|||||||
/** @var Collection $collection */
|
/** @var Collection $collection */
|
||||||
$collection = auth()->user()->accounts()
|
$collection = auth()->user()->accounts()
|
||||||
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
|
->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id')
|
||||||
->where('account_types.type', AccountType::ASSET)
|
->whereIn('account_types.type', [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE])
|
||||||
->orderBy('accounts.name', 'ASC')
|
->orderBy('accounts.name', 'ASC')
|
||||||
->get(['accounts.*']);
|
->get(['accounts.*']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('allAssetAccounts' !== $value) {
|
if ('allAssetAccounts' !== $value) {
|
||||||
$incoming = array_map('\intval', explode(',', $value));
|
$incoming = array_map('\intval', explode(',', $value));
|
||||||
$list = array_merge(array_unique($incoming), [0]);
|
$list = array_merge(array_unique($incoming), [0]);
|
||||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
|||||||
namespace FireflyIII\Support\Cronjobs;
|
namespace FireflyIII\Support\Cronjobs;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Jobs\SubmitTelemetryData;
|
use FireflyIII\Jobs\SubmitTelemetryData;
|
||||||
use FireflyIII\Models\Configuration;
|
use FireflyIII\Models\Configuration;
|
||||||
use Log;
|
use Log;
|
||||||
@@ -35,9 +36,17 @@ class TelemetryCronjob extends AbstractCronjob
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
|
* @throws FireflyException
|
||||||
*/
|
*/
|
||||||
public function fire(): bool
|
public function fire(): bool
|
||||||
{
|
{
|
||||||
|
// do not fire if telemetry is disabled.
|
||||||
|
if (false === config('firefly.send_telemetry') || false === config('firefly.feature_flags.telemetry')) {
|
||||||
|
Log::warning('Telemetry is disabled. The cron job will do nothing.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** @var Configuration $config */
|
/** @var Configuration $config */
|
||||||
$config = app('fireflyconfig')->get('last_tm_job', 0);
|
$config = app('fireflyconfig')->get('last_tm_job', 0);
|
||||||
$lastTime = (int) $config->data;
|
$lastTime = (int) $config->data;
|
||||||
@@ -46,8 +55,8 @@ class TelemetryCronjob extends AbstractCronjob
|
|||||||
if (0 === $lastTime) {
|
if (0 === $lastTime) {
|
||||||
Log::info('Telemetry cron-job has never fired before.');
|
Log::info('Telemetry cron-job has never fired before.');
|
||||||
}
|
}
|
||||||
// less than half a day ago:
|
// less than a week ago:
|
||||||
if ($lastTime > 0 && $diff <= 43200) {
|
if ($lastTime > 0 && $diff <= 604800) {
|
||||||
Log::info(sprintf('It has been %s since the telemetry cron-job has fired.', $diffForHumans));
|
Log::info(sprintf('It has been %s since the telemetry cron-job has fired.', $diffForHumans));
|
||||||
if (false === $this->force) {
|
if (false === $this->force) {
|
||||||
Log::info('The cron-job will not fire now.');
|
Log::info('The cron-job will not fire now.');
|
||||||
@@ -60,8 +69,8 @@ class TelemetryCronjob extends AbstractCronjob
|
|||||||
Log::info('Execution of the telemetry cron-job has been FORCED.');
|
Log::info('Execution of the telemetry cron-job has been FORCED.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// more than a week ago.
|
||||||
if ($lastTime > 0 && $diff > 43200) {
|
if ($lastTime > 0 && $diff > 604799) {
|
||||||
Log::info(sprintf('It has been %s since the telemetry cron-job has fired. It will fire now!', $diffForHumans));
|
Log::info(sprintf('It has been %s since the telemetry cron-job has fired. It will fire now!', $diffForHumans));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +83,7 @@ class TelemetryCronjob extends AbstractCronjob
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @throws FireflyException
|
||||||
*/
|
*/
|
||||||
private function fireTelemetry(): void
|
private function fireTelemetry(): void
|
||||||
{
|
{
|
||||||
@@ -84,6 +93,9 @@ class TelemetryCronjob extends AbstractCronjob
|
|||||||
$job->setDate($this->date);
|
$job->setDate($this->date);
|
||||||
$job->setForce($this->force);
|
$job->setForce($this->force);
|
||||||
$job->handle();
|
$job->handle();
|
||||||
|
|
||||||
|
// TODO remove old, submitted telemetry data.
|
||||||
|
|
||||||
app('fireflyconfig')->set('last_tm_job', (int) $this->date->format('U'));
|
app('fireflyconfig')->set('last_tm_job', (int) $this->date->format('U'));
|
||||||
Log::info('Done with telemetry cron job task.');
|
Log::info('Done with telemetry cron job task.');
|
||||||
}
|
}
|
||||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Support\Http\Controllers;
|
|||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Support\Cronjobs\AutoBudgetCronjob;
|
use FireflyIII\Support\Cronjobs\AutoBudgetCronjob;
|
||||||
use FireflyIII\Support\Cronjobs\RecurringCronjob;
|
use FireflyIII\Support\Cronjobs\RecurringCronjob;
|
||||||
|
use FireflyIII\Support\Cronjobs\TelemetryCronjob;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trait CronRunner
|
* Trait CronRunner
|
||||||
@@ -51,6 +52,24 @@ trait CronRunner
|
|||||||
return 'The recurring transaction cron job fired successfully.';
|
return 'The recurring transaction cron job fired successfully.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function runTelemetry(): string {
|
||||||
|
/** @var TelemetryCronjob $telemetry */
|
||||||
|
$telemetry = app(TelemetryCronjob::class);
|
||||||
|
try {
|
||||||
|
$result = $telemetry->fire();
|
||||||
|
} catch (FireflyException $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
if (false === $result) {
|
||||||
|
return 'The telemetry cron job did not fire.';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'The telemetry cron job fired successfully.';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
157
app/Support/ParseDateString.php
Normal file
157
app/Support/ParseDateString.php
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
|
||||||
|
namespace FireflyIII\Support;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
|
use Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ParseDateString
|
||||||
|
*/
|
||||||
|
class ParseDateString
|
||||||
|
{
|
||||||
|
private $keywords
|
||||||
|
= [
|
||||||
|
'today',
|
||||||
|
'yesterday',
|
||||||
|
'tomorrow',
|
||||||
|
'start of this week',
|
||||||
|
'end of this week',
|
||||||
|
'start of this month',
|
||||||
|
'end of this month',
|
||||||
|
'start of this quarter',
|
||||||
|
'end of this quarter',
|
||||||
|
'start of this year',
|
||||||
|
'end of this year',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $date
|
||||||
|
*
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
public function parseDate(string $date): Carbon
|
||||||
|
{
|
||||||
|
// parse keywords:
|
||||||
|
if (in_array($date, $this->keywords, true)) {
|
||||||
|
return $this->parseKeyword($date);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if regex for YYYY-MM-DD:
|
||||||
|
$pattern = '/^(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][\d]|3[01])$/';
|
||||||
|
if (preg_match($pattern, $date)) {
|
||||||
|
return $this->parseDefaultDate($date);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if + or -:
|
||||||
|
if (0 === strpos($date, '+') || 0 === strpos($date, '-')) {
|
||||||
|
return $this->parseRelativeDate($date);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FireflyException('Not recognised.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $date
|
||||||
|
*
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
private function parseDefaultDate(string $date): Carbon
|
||||||
|
{
|
||||||
|
return Carbon::createFromFormat('Y-m-d', $date);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $keyword
|
||||||
|
*
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
private function parseKeyword(string $keyword): Carbon
|
||||||
|
{
|
||||||
|
$today = Carbon::today()->startOfDay();
|
||||||
|
switch ($keyword) {
|
||||||
|
default:
|
||||||
|
case 'today':
|
||||||
|
return $today;
|
||||||
|
case 'yesterday':
|
||||||
|
return $today->subDay();
|
||||||
|
case 'tomorrow':
|
||||||
|
return $today->addDay();
|
||||||
|
case 'start of this week':
|
||||||
|
return $today->startOfWeek();
|
||||||
|
case 'end of this week':
|
||||||
|
return $today->endOfWeek();
|
||||||
|
case 'start of this month':
|
||||||
|
return $today->startOfMonth();
|
||||||
|
case 'end of this month':
|
||||||
|
return $today->endOfMonth();
|
||||||
|
case 'start of this quarter':
|
||||||
|
return $today->startOfQuarter();
|
||||||
|
case 'end of this quarter':
|
||||||
|
return $today->endOfQuarter();
|
||||||
|
case 'start of this year':
|
||||||
|
return $today->startOfYear();
|
||||||
|
case 'end of this year':
|
||||||
|
return $today->endOfYear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $date
|
||||||
|
*
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
private function parseRelativeDate(string $date): Carbon
|
||||||
|
{
|
||||||
|
Log::debug(sprintf('Now in parseRelativeDate("%s")', $date));
|
||||||
|
$parts = explode(' ', $date);
|
||||||
|
$today = Carbon::today()->startOfDay();
|
||||||
|
$functions = [
|
||||||
|
[
|
||||||
|
'd' => 'subDays',
|
||||||
|
'w' => 'subWeeks',
|
||||||
|
'm' => 'subMonths',
|
||||||
|
'q' => 'subQuarters',
|
||||||
|
'y' => 'subYears',
|
||||||
|
], [
|
||||||
|
'd' => 'addDays',
|
||||||
|
'w' => 'addWeeks',
|
||||||
|
'm' => 'addMonths',
|
||||||
|
'q' => 'addQuarters',
|
||||||
|
'y' => 'addYears',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var string $part */
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
Log::debug(sprintf('Now parsing part "%s"', $part));
|
||||||
|
$part = trim($part);
|
||||||
|
|
||||||
|
// verify if correct
|
||||||
|
$pattern = '/[+-]\d+[wqmdy]/';
|
||||||
|
$res = preg_match($pattern, $part);
|
||||||
|
if (0 === $res || false === $res) {
|
||||||
|
Log::error(sprintf('Part "%s" does not match regular expression. Will be skipped.', $part));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$direction = 0 === strpos($part, '+') ? 1 : 0;
|
||||||
|
$period = $part[strlen($part) - 1];
|
||||||
|
$number = (int) substr($part, 1, -1);
|
||||||
|
if (!isset($functions[$direction][$period])) {
|
||||||
|
Log::error(sprintf('No method for direction %d and period "%s".', $direction, $period));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$func = $functions[$direction][$period];
|
||||||
|
Log::debug(sprintf('Will now do %s(%d) on %s', $func, $number, $today->format('Y-m-d')));
|
||||||
|
$today->$func($number);
|
||||||
|
Log::debug(sprintf('Resulting date is %s', $today->format('Y-m-d')));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $today;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -22,7 +22,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Support;
|
namespace FireflyIII\Support;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Models\Telemetry as TelemetryModel;
|
use FireflyIII\Models\Telemetry as TelemetryModel;
|
||||||
|
use JsonException;
|
||||||
use Log;
|
use Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,6 +67,25 @@ class Telemetry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $key
|
||||||
|
* @param string $value
|
||||||
|
* @param int $days
|
||||||
|
*/
|
||||||
|
public function recurring(string $key, string $value, int $days): void
|
||||||
|
{
|
||||||
|
if (false === config('firefly.send_telemetry') || false === config('firefly.feature_flags.telemetry')) {
|
||||||
|
// hard stop if not allowed to do telemetry.
|
||||||
|
// do nothing!
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cutoffDate = Carbon::today()->subDays($days);
|
||||||
|
if (!$this->hasRecentEntry('recurring', $key, $value, $cutoffDate)) {
|
||||||
|
$this->storeEntry('recurring', $key, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String telemetry stores a string value as a telemetry entry. Values could include:
|
* String telemetry stores a string value as a telemetry entry. Values could include:
|
||||||
*
|
*
|
||||||
@@ -85,7 +106,6 @@ class Telemetry
|
|||||||
}
|
}
|
||||||
Log::info(sprintf('Logged telemetry string "%s" with value "%s".', $name, $value));
|
Log::info(sprintf('Logged telemetry string "%s" with value "%s".', $name, $value));
|
||||||
|
|
||||||
// no storage backend yet, do nothing.
|
|
||||||
$this->storeEntry('string', $name, $value);
|
$this->storeEntry('string', $name, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,16 +118,49 @@ class Telemetry
|
|||||||
*/
|
*/
|
||||||
private function hasEntry(string $type, string $key, string $value): bool
|
private function hasEntry(string $type, string $key, string $value): bool
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
|
$jsonEncoded = json_encode($value, JSON_THROW_ON_ERROR, 512);
|
||||||
|
} catch (JsonException $e) {
|
||||||
|
Log::error(sprintf('JSON Exception encoding the following value: %s: %s', $value, $e->getMessage()));
|
||||||
|
$jsonEncoded = [];
|
||||||
|
}
|
||||||
|
|
||||||
return TelemetryModel
|
return TelemetryModel
|
||||||
::where('type', $type)
|
::where('type', $type)
|
||||||
->where('key', $key)
|
->where('key', $key)
|
||||||
->where('value', json_encode($value, JSON_THROW_ON_ERROR, 512))
|
->where('value', $jsonEncoded)
|
||||||
|
->count() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $type
|
||||||
|
* @param string $key
|
||||||
|
* @param string $value
|
||||||
|
* @param Carbon $date
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function hasRecentEntry(string $type, string $key, string $value, Carbon $date): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$jsonEncoded = json_encode($value, JSON_THROW_ON_ERROR, 512);
|
||||||
|
} catch (JsonException $e) {
|
||||||
|
Log::error(sprintf('JSON Exception encoding the following value: %s: %s', $value, $e->getMessage()));
|
||||||
|
$jsonEncoded = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return TelemetryModel
|
||||||
|
::where('type', $type)
|
||||||
|
->where('key', $key)
|
||||||
|
->where('created_at', '>=', $date->format('Y-m-d H:i:s'))
|
||||||
|
->where('value', $jsonEncoded)
|
||||||
->count() > 0;
|
->count() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store new entry in DB.
|
* Store new entry in DB.
|
||||||
*
|
*
|
||||||
|
* @param string $type
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param string $value
|
* @param string $value
|
||||||
*/
|
*/
|
||||||
|
81
app/TransactionRules/Actions/DeleteTransaction.php
Normal file
81
app/TransactionRules/Actions/DeleteTransaction.php
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* DeleteTransaction.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\TransactionRules\Actions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use FireflyIII\Models\RuleAction;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Services\Internal\Destroy\JournalDestroyService;
|
||||||
|
use FireflyIII\Services\Internal\Destroy\TransactionGroupDestroyService;
|
||||||
|
use Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class DeleteTransaction.
|
||||||
|
*/
|
||||||
|
class DeleteTransaction implements ActionInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* TriggerInterface constructor.
|
||||||
|
*
|
||||||
|
* @param RuleAction $action
|
||||||
|
*/
|
||||||
|
public function __construct(RuleAction $action)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will delete transaction journal. Also the group if no other journals are in the group.
|
||||||
|
*
|
||||||
|
* @param TransactionJournal $journal
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function act(TransactionJournal $journal): bool
|
||||||
|
{
|
||||||
|
|
||||||
|
$count = $journal->transactionGroup->transactionJournals()->count();
|
||||||
|
|
||||||
|
// destroy entire group.
|
||||||
|
if (1 === $count) {
|
||||||
|
Log::debug(
|
||||||
|
sprintf(
|
||||||
|
'RuleAction DeleteTransaction DELETED the entire transaction group of journal #%d ("%s").',
|
||||||
|
$journal->id, $journal->description
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$service = app(TransactionGroupDestroyService::class);
|
||||||
|
$service->destroy($journal->transactionGroup);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Log::debug(sprintf('RuleAction DeleteTransaction DELETED transaction journal #%d ("%s").', $journal->id, $journal->description));
|
||||||
|
|
||||||
|
// trigger delete factory:
|
||||||
|
/** @var JournalDestroyService $service */
|
||||||
|
$service = app(JournalDestroyService::class);
|
||||||
|
$service->destroy($journal);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@@ -22,7 +22,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\TransactionRules\Triggers;
|
namespace FireflyIII\TransactionRules\Triggers;
|
||||||
|
|
||||||
use FireflyIII\Models\Transaction;
|
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use Log;
|
use Log;
|
||||||
|
|
||||||
@@ -76,31 +75,6 @@ final class BudgetIs extends AbstractTrigger implements TriggerInterface
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $budget) {
|
|
||||||
// perhaps transactions have this budget?
|
|
||||||
/** @var Transaction $transaction */
|
|
||||||
foreach ($journal->transactions as $transaction) {
|
|
||||||
$budget = $transaction->budgets()->first();
|
|
||||||
if (null !== $budget) {
|
|
||||||
$name = strtolower($budget->name);
|
|
||||||
if ($name === strtolower($this->triggerValue)) {
|
|
||||||
Log::debug(
|
|
||||||
sprintf(
|
|
||||||
'RuleTrigger BudgetIs for journal #%d (transaction #%d): "%s" is "%s", return true.',
|
|
||||||
$journal->id,
|
|
||||||
$transaction->id,
|
|
||||||
$name,
|
|
||||||
$this->triggerValue
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log::debug(sprintf('RuleTrigger BudgetIs for journal #%d: does not have budget "%s", return false.', $journal->id, $this->triggerValue));
|
Log::debug(sprintf('RuleTrigger BudgetIs for journal #%d: does not have budget "%s", return false.', $journal->id, $this->triggerValue));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@@ -22,7 +22,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\TransactionRules\Triggers;
|
namespace FireflyIII\TransactionRules\Triggers;
|
||||||
|
|
||||||
use FireflyIII\Models\Transaction;
|
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use Log;
|
use Log;
|
||||||
|
|
||||||
@@ -76,31 +75,6 @@ final class CategoryIs extends AbstractTrigger implements TriggerInterface
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $category) {
|
|
||||||
// perhaps transactions have this category?
|
|
||||||
/** @var Transaction $transaction */
|
|
||||||
foreach ($journal->transactions as $transaction) {
|
|
||||||
$category = $transaction->categories()->first();
|
|
||||||
if (null !== $category) {
|
|
||||||
$name = strtolower($category->name);
|
|
||||||
if ($name === strtolower($this->triggerValue)) {
|
|
||||||
Log::debug(
|
|
||||||
sprintf(
|
|
||||||
'RuleTrigger CategoryIs for journal #%d (transaction #%d): "%s" is "%s", return true.',
|
|
||||||
$journal->id,
|
|
||||||
$transaction->id,
|
|
||||||
$name,
|
|
||||||
$this->triggerValue
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log::debug(sprintf('RuleTrigger CategoryIs for journal #%d: does not have category "%s", return false.', $journal->id, $this->triggerValue));
|
Log::debug(sprintf('RuleTrigger CategoryIs for journal #%d: does not have category "%s", return false.', $journal->id, $this->triggerValue));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
107
app/TransactionRules/Triggers/DateAfter.php
Normal file
107
app/TransactionRules/Triggers/DateAfter.php
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* DateAfter.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\TransactionRules\Triggers;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Support\ParseDateString;
|
||||||
|
use Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class DateAfter.
|
||||||
|
*/
|
||||||
|
final class DateAfter extends AbstractTrigger implements TriggerInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A trigger is said to "match anything", or match any given transaction,
|
||||||
|
* when the trigger value is very vague or has no restrictions. Easy examples
|
||||||
|
* are the "AmountMore"-trigger combined with an amount of 0: any given transaction
|
||||||
|
* has an amount of more than zero! Other examples are all the "Description"-triggers
|
||||||
|
* which have hard time handling empty trigger values such as "" or "*" (wild cards).
|
||||||
|
*
|
||||||
|
* If the user tries to create such a trigger, this method MUST return true so Firefly III
|
||||||
|
* can stop the storing / updating the trigger. If the trigger is in any way restrictive
|
||||||
|
* (even if it will still include 99.9% of the users transactions), this method MUST return
|
||||||
|
* false.
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function willMatchEverything($value = null): bool
|
||||||
|
{
|
||||||
|
if (null !== $value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Log::error(sprintf('Cannot use %s with a null value.', self::class));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true when category is X.
|
||||||
|
*
|
||||||
|
* @param TransactionJournal $journal
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function triggered(TransactionJournal $journal): bool
|
||||||
|
{
|
||||||
|
/** @var Carbon $date */
|
||||||
|
$date = $journal->date;
|
||||||
|
Log::debug(sprintf('Found date on journal: %s', $date->format('Y-m-d')));
|
||||||
|
$dateParser = new ParseDateString();
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
$ruleDate = $dateParser->parseDate($this->triggerValue);
|
||||||
|
} catch (FireflyException $e) {
|
||||||
|
Log::error('Cannot execute rule trigger.');
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($date->isAfter($ruleDate)) {
|
||||||
|
Log::debug(
|
||||||
|
sprintf(
|
||||||
|
'%s is after %s, so return true.',
|
||||||
|
$date->format('Y-m-d H:i:s'),
|
||||||
|
$ruleDate->format('Y-m-d H:i:s'),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::debug(
|
||||||
|
sprintf(
|
||||||
|
'%s is NOT after %s, so return true.',
|
||||||
|
$date->format('Y-m-d H:i:s'),
|
||||||
|
$ruleDate->format('Y-m-d H:i:s'),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
107
app/TransactionRules/Triggers/DateBefore.php
Normal file
107
app/TransactionRules/Triggers/DateBefore.php
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* DateBefore.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\TransactionRules\Triggers;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Support\ParseDateString;
|
||||||
|
use Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class DateBefore.
|
||||||
|
*/
|
||||||
|
final class DateBefore extends AbstractTrigger implements TriggerInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A trigger is said to "match anything", or match any given transaction,
|
||||||
|
* when the trigger value is very vague or has no restrictions. Easy examples
|
||||||
|
* are the "AmountMore"-trigger combined with an amount of 0: any given transaction
|
||||||
|
* has an amount of more than zero! Other examples are all the "Description"-triggers
|
||||||
|
* which have hard time handling empty trigger values such as "" or "*" (wild cards).
|
||||||
|
*
|
||||||
|
* If the user tries to create such a trigger, this method MUST return true so Firefly III
|
||||||
|
* can stop the storing / updating the trigger. If the trigger is in any way restrictive
|
||||||
|
* (even if it will still include 99.9% of the users transactions), this method MUST return
|
||||||
|
* false.
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function willMatchEverything($value = null): bool
|
||||||
|
{
|
||||||
|
if (null !== $value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Log::error(sprintf('Cannot use %s with a null value.', self::class));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true when category is X.
|
||||||
|
*
|
||||||
|
* @param TransactionJournal $journal
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function triggered(TransactionJournal $journal): bool
|
||||||
|
{
|
||||||
|
/** @var Carbon $date */
|
||||||
|
$date = $journal->date;
|
||||||
|
Log::debug(sprintf('Found date on journal: %s', $date->format('Y-m-d')));
|
||||||
|
$dateParser = new ParseDateString();
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
$ruleDate = $dateParser->parseDate($this->triggerValue);
|
||||||
|
} catch (FireflyException $e) {
|
||||||
|
Log::error('Cannot execute rule trigger.');
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($date->isBefore($ruleDate)) {
|
||||||
|
Log::debug(
|
||||||
|
sprintf(
|
||||||
|
'%s is before %s, so return true.',
|
||||||
|
$date->format('Y-m-d H:i:s'),
|
||||||
|
$ruleDate->format('Y-m-d H:i:s'),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::debug(
|
||||||
|
sprintf(
|
||||||
|
'%s is NOT before %s, so return true.',
|
||||||
|
$date->format('Y-m-d H:i:s'),
|
||||||
|
$ruleDate->format('Y-m-d H:i:s'),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
107
app/TransactionRules/Triggers/DateIs.php
Normal file
107
app/TransactionRules/Triggers/DateIs.php
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* DateIs.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\TransactionRules\Triggers;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
|
use FireflyIII\Models\TransactionJournal;
|
||||||
|
use FireflyIII\Support\ParseDateString;
|
||||||
|
use Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class DateIs.
|
||||||
|
*/
|
||||||
|
final class DateIs extends AbstractTrigger implements TriggerInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A trigger is said to "match anything", or match any given transaction,
|
||||||
|
* when the trigger value is very vague or has no restrictions. Easy examples
|
||||||
|
* are the "AmountMore"-trigger combined with an amount of 0: any given transaction
|
||||||
|
* has an amount of more than zero! Other examples are all the "Description"-triggers
|
||||||
|
* which have hard time handling empty trigger values such as "" or "*" (wild cards).
|
||||||
|
*
|
||||||
|
* If the user tries to create such a trigger, this method MUST return true so Firefly III
|
||||||
|
* can stop the storing / updating the trigger. If the trigger is in any way restrictive
|
||||||
|
* (even if it will still include 99.9% of the users transactions), this method MUST return
|
||||||
|
* false.
|
||||||
|
*
|
||||||
|
* @param mixed $value
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function willMatchEverything($value = null): bool
|
||||||
|
{
|
||||||
|
if (null !== $value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Log::error(sprintf('Cannot use %s with a null value.', self::class));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true when category is X.
|
||||||
|
*
|
||||||
|
* @param TransactionJournal $journal
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function triggered(TransactionJournal $journal): bool
|
||||||
|
{
|
||||||
|
/** @var Carbon $date */
|
||||||
|
$date = $journal->date;
|
||||||
|
Log::debug(sprintf('Found date on journal: %s', $date->format('Y-m-d')));
|
||||||
|
$dateParser = new ParseDateString();
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
$ruleDate = $dateParser->parseDate($this->triggerValue);
|
||||||
|
} catch (FireflyException $e) {
|
||||||
|
Log::error('Cannot execute rule trigger.');
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($ruleDate->isSameDay($date)) {
|
||||||
|
Log::debug(
|
||||||
|
sprintf(
|
||||||
|
'%s is on the same day as %s, so return true.',
|
||||||
|
$date->format('Y-m-d H:i:s'),
|
||||||
|
$ruleDate->format('Y-m-d H:i:s'),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::debug(
|
||||||
|
sprintf(
|
||||||
|
'%s is NOT on the same day as %s, so return true.',
|
||||||
|
$date->format('Y-m-d H:i:s'),
|
||||||
|
$ruleDate->format('Y-m-d H:i:s'),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@@ -24,6 +24,7 @@ namespace FireflyIII\Validation;
|
|||||||
|
|
||||||
use Config;
|
use Config;
|
||||||
use DB;
|
use DB;
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Models\AccountMeta;
|
use FireflyIII\Models\AccountMeta;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
@@ -34,11 +35,13 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
|||||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
use FireflyIII\Services\Password\Verifier;
|
use FireflyIII\Services\Password\Verifier;
|
||||||
|
use FireflyIII\Support\ParseDateString;
|
||||||
use FireflyIII\TransactionRules\Triggers\TriggerInterface;
|
use FireflyIII\TransactionRules\Triggers\TriggerInterface;
|
||||||
use FireflyIII\User;
|
use FireflyIII\User;
|
||||||
use Google2FA;
|
use Google2FA;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Validation\Validator;
|
use Illuminate\Validation\Validator;
|
||||||
|
use Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class FireflyValidator.
|
* Class FireflyValidator.
|
||||||
@@ -333,6 +336,20 @@ class FireflyValidator extends Validator
|
|||||||
return 1 === $count;
|
return 1 === $count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the type is date, the simply try to parse it and throw error when it's bad.
|
||||||
|
if (in_array($triggerType, ['date_is'], true)) {
|
||||||
|
/** @var ParseDateString $parser */
|
||||||
|
$parser = app(ParseDateString::class);
|
||||||
|
try {
|
||||||
|
$parser->parseDate($value);
|
||||||
|
} catch (FireflyException $e) {
|
||||||
|
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// and finally a "will match everything check":
|
// and finally a "will match everything check":
|
||||||
$classes = app('config')->get('firefly.rule-triggers');
|
$classes = app('config')->get('firefly.rule-triggers');
|
||||||
/** @var TriggerInterface $class */
|
/** @var TriggerInterface $class */
|
||||||
|
45
changelog.md
45
changelog.md
@@ -2,6 +2,51 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## [5.2.7 (API 1.1.0) - 2020-06-01
|
||||||
|
|
||||||
|
- Firefly III v5.2.7 is the first version of Firefly III with the ability to opt-in to usage telemetry. This entirely optional of course.
|
||||||
|
- New translations have been added for the emails that Firefly III can send. Despite your preferences, these emails may still be in English. See the bottom of this changelog.
|
||||||
|
- New translations have been added for error screens that Firefly III may display. Despite your preferences, these error pages may still be in English. See the bottom of this changelog.
|
||||||
|
|
||||||
|
About translating errors and email messages.
|
||||||
|
|
||||||
|
The translated text is generated outside of what's called the user's "session". When Firefly
|
||||||
|
III operates outside of your session, it can't access your preferences or your data. So it may not be possible for
|
||||||
|
Firefly III to know which language you would have preferred. You can set the `DEFAULT_LANGUAGE`-environment variable
|
||||||
|
if you want. But user specific preferences may be ignored.
|
||||||
|
|
||||||
|
|
||||||
|
Translation of email and errors. May not be perfect. (1) error does not read user pref. 2: email does not read user pref. 3: stringsnot translated yet.
|
||||||
|
|
||||||
|
## [5.2.6 (API 1.1.0)] - 2020-05-22
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- [Issue 3049](https://github.com/firefly-iii/firefly-iii/issues/3049) New transaction triggers for dates.
|
||||||
|
- Warning if recurring transactions no longer run.
|
||||||
|
- View fixed for recurring transactions.
|
||||||
|
- A new rule action that will DELETE transactions.
|
||||||
|
- Four-week reminder to check for updates if you disabled updates.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- [Issue 3011](https://github.com/firefly-iii/firefly-iii/issues/3011) Reconciliation page has "select all"-button and remembers checkboxes even when you refresh the page.
|
||||||
|
- [Issue 3348](https://github.com/firefly-iii/firefly-iii/issues/3348) Smarter menu for accounts on the dashboard
|
||||||
|
- Demo user can't upload attachments.
|
||||||
|
- Demo user can't set locale.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- [Issue 3339](https://github.com/firefly-iii/firefly-iii/issues/3339) Could not mass-delete reconciliation transactions.
|
||||||
|
- [Issue 3344](https://github.com/firefly-iii/firefly-iii/issues/3344) Could not attach files to accounts.
|
||||||
|
- [Issue 3335](https://github.com/firefly-iii/firefly-iii/issues/3335) Fix reconciliation currency account, thanks to @maksimkurb
|
||||||
|
- [Issue 3350](https://github.com/firefly-iii/firefly-iii/issues/3350) Better charts in account overview
|
||||||
|
- [Issue 3355](https://github.com/firefly-iii/firefly-iii/issues/3355) Better sorting for bills in reports.
|
||||||
|
- [Issue 3363](https://github.com/firefly-iii/firefly-iii/issues/3363) New strings translated, thanks to @sephrat
|
||||||
|
- [Issue 3367](https://github.com/firefly-iii/firefly-iii/issues/3367) Error in views when uploading > 1 attachments
|
||||||
|
- [Issue 3368](https://github.com/firefly-iii/firefly-iii/issues/3368) Wrong hover-text
|
||||||
|
- [Issue 3374](https://github.com/firefly-iii/firefly-iii/issues/3374) Inconsistent net worth calculation. You may seem to lose money.
|
||||||
|
- [Issue 3376](https://github.com/firefly-iii/firefly-iii/issues/3376) Better rule ordering when cloning rules.
|
||||||
|
- [Issue 3381](https://github.com/firefly-iii/firefly-iii/issues/3381) Fix for LDAP
|
||||||
|
- Better rounding for budget amounts.
|
||||||
|
|
||||||
## [5.2.5 (API 1.1.0)] - 2020-05-04
|
## [5.2.5 (API 1.1.0)] - 2020-05-04
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@@ -94,11 +94,7 @@
|
|||||||
"laravelcollective/html": "6.*",
|
"laravelcollective/html": "6.*",
|
||||||
"league/commonmark": "1.*",
|
"league/commonmark": "1.*",
|
||||||
"league/csv": "9.*",
|
"league/csv": "9.*",
|
||||||
"league/flysystem-replicate-adapter": "1.*",
|
|
||||||
"league/flysystem-sftp": "1.*",
|
|
||||||
"league/fractal": "0.*",
|
"league/fractal": "0.*",
|
||||||
"litipk/flysystem-fallback-adapter": "0.*",
|
|
||||||
"mschindler83/fints-hbci-php": "1.*",
|
|
||||||
"pragmarx/google2fa": "^7.0",
|
"pragmarx/google2fa": "^7.0",
|
||||||
"pragmarx/recovery": "^0.1.0",
|
"pragmarx/recovery": "^0.1.0",
|
||||||
"predis/predis": "^1.1",
|
"predis/predis": "^1.1",
|
||||||
|
543
composer.lock
generated
543
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -39,6 +39,38 @@ if (!(false === $databaseUrl)) {
|
|||||||
$database = substr($options['path'] ?? '/firefly', 1);
|
$database = substr($options['path'] ?? '/firefly', 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get SSL parameters from .env file.
|
||||||
|
*/
|
||||||
|
$mysql_ssl_ca_dir = envNonEmpty('MYSQL_SSL_CAPATH', null);
|
||||||
|
$mysql_ssl_ca_file = envNonEmpty('MYSQL_SSL_CA', null);
|
||||||
|
$mysql_ssl_cert = envNonEmpty('MYSQL_SSL_CERT', null);
|
||||||
|
$mysql_ssl_key = envNonEmpty('MYSQL_SSL_KEY', null);
|
||||||
|
$mysql_ssl_ciphers = envNonEmpty('MYSQL_SSL_CIPHER', null);
|
||||||
|
$mysql_ssl_verify = envNonEmpty('MYSQL_SSL_VERIFY_SERVER_CERT', null);
|
||||||
|
|
||||||
|
$mySqlSSLOptions = [];
|
||||||
|
if (false !== envNonEmpty('MYSQL_USE_SSL', false)) {
|
||||||
|
if (null !== $mysql_ssl_ca_dir) {
|
||||||
|
$mySqlSSLOptions[PDO::MYSQL_ATTR_SSL_CAPATH] = $mysql_ssl_ca_dir;
|
||||||
|
}
|
||||||
|
if (null !== $mysql_ssl_ca_file) {
|
||||||
|
$mySqlSSLOptions[PDO::MYSQL_ATTR_SSL_CA] = $mysql_ssl_ca_file;
|
||||||
|
}
|
||||||
|
if (null !== $mysql_ssl_cert) {
|
||||||
|
$mySqlSSLOptions[PDO::MYSQL_ATTR_SSL_CERT] = $mysql_ssl_cert;
|
||||||
|
}
|
||||||
|
if (null !== $mysql_ssl_key) {
|
||||||
|
$mySqlSSLOptions[PDO::MYSQL_ATTR_SSL_KEY] = $mysql_ssl_key;
|
||||||
|
}
|
||||||
|
if (null !== $mysql_ssl_ciphers) {
|
||||||
|
$mySqlSSLOptions[PDO::MYSQL_ATTR_SSL_CIPHER] = $mysql_ssl_ciphers;
|
||||||
|
}
|
||||||
|
if (null !== $mysql_ssl_verify) {
|
||||||
|
$mySqlSSLOptions[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = $mysql_ssl_verify;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'default' => envNonEmpty('DB_CONNECTION', 'pgsql'),
|
'default' => envNonEmpty('DB_CONNECTION', 'pgsql'),
|
||||||
'connections' => [
|
'connections' => [
|
||||||
@@ -60,6 +92,7 @@ return [
|
|||||||
'prefix' => '',
|
'prefix' => '',
|
||||||
'strict' => true,
|
'strict' => true,
|
||||||
'engine' => 'InnoDB',
|
'engine' => 'InnoDB',
|
||||||
|
'options' => $mySqlSSLOptions,
|
||||||
],
|
],
|
||||||
'pgsql' => [
|
'pgsql' => [
|
||||||
'driver' => 'pgsql',
|
'driver' => 'pgsql',
|
||||||
|
@@ -66,24 +66,28 @@ use FireflyIII\TransactionRules\Actions\ClearNotes;
|
|||||||
use FireflyIII\TransactionRules\Actions\ConvertToDeposit;
|
use FireflyIII\TransactionRules\Actions\ConvertToDeposit;
|
||||||
use FireflyIII\TransactionRules\Actions\ConvertToTransfer;
|
use FireflyIII\TransactionRules\Actions\ConvertToTransfer;
|
||||||
use FireflyIII\TransactionRules\Actions\ConvertToWithdrawal;
|
use FireflyIII\TransactionRules\Actions\ConvertToWithdrawal;
|
||||||
|
use FireflyIII\TransactionRules\Actions\DeleteTransaction;
|
||||||
use FireflyIII\TransactionRules\Actions\LinkToBill;
|
use FireflyIII\TransactionRules\Actions\LinkToBill;
|
||||||
use FireflyIII\TransactionRules\Actions\PrependDescription;
|
use FireflyIII\TransactionRules\Actions\PrependDescription;
|
||||||
use FireflyIII\TransactionRules\Actions\PrependNotes;
|
use FireflyIII\TransactionRules\Actions\PrependNotes;
|
||||||
use FireflyIII\TransactionRules\Actions\RemoveAllTags;
|
use FireflyIII\TransactionRules\Actions\RemoveAllTags;
|
||||||
use FireflyIII\TransactionRules\Actions\RemoveTag;
|
use FireflyIII\TransactionRules\Actions\RemoveTag;
|
||||||
use FireflyIII\TransactionRules\Actions\SetBudget;
|
use FireflyIII\TransactionRules\Actions\SetBudget;
|
||||||
use FireflyIII\TransactionRules\Actions\UpdatePiggybank;
|
|
||||||
use FireflyIII\TransactionRules\Actions\SetCategory;
|
use FireflyIII\TransactionRules\Actions\SetCategory;
|
||||||
use FireflyIII\TransactionRules\Actions\SetDescription;
|
use FireflyIII\TransactionRules\Actions\SetDescription;
|
||||||
use FireflyIII\TransactionRules\Actions\SetDestinationAccount;
|
use FireflyIII\TransactionRules\Actions\SetDestinationAccount;
|
||||||
use FireflyIII\TransactionRules\Actions\SetNotes;
|
use FireflyIII\TransactionRules\Actions\SetNotes;
|
||||||
use FireflyIII\TransactionRules\Actions\SetSourceAccount;
|
use FireflyIII\TransactionRules\Actions\SetSourceAccount;
|
||||||
|
use FireflyIII\TransactionRules\Actions\UpdatePiggybank;
|
||||||
use FireflyIII\TransactionRules\Triggers\AmountExactly;
|
use FireflyIII\TransactionRules\Triggers\AmountExactly;
|
||||||
use FireflyIII\TransactionRules\Triggers\AmountLess;
|
use FireflyIII\TransactionRules\Triggers\AmountLess;
|
||||||
use FireflyIII\TransactionRules\Triggers\AmountMore;
|
use FireflyIII\TransactionRules\Triggers\AmountMore;
|
||||||
use FireflyIII\TransactionRules\Triggers\BudgetIs;
|
use FireflyIII\TransactionRules\Triggers\BudgetIs;
|
||||||
use FireflyIII\TransactionRules\Triggers\CategoryIs;
|
use FireflyIII\TransactionRules\Triggers\CategoryIs;
|
||||||
use FireflyIII\TransactionRules\Triggers\CurrencyIs;
|
use FireflyIII\TransactionRules\Triggers\CurrencyIs;
|
||||||
|
use FireflyIII\TransactionRules\Triggers\DateIs;
|
||||||
|
use FireflyIII\TransactionRules\Triggers\DateBefore;
|
||||||
|
use FireflyIII\TransactionRules\Triggers\DateAfter;
|
||||||
use FireflyIII\TransactionRules\Triggers\DescriptionContains;
|
use FireflyIII\TransactionRules\Triggers\DescriptionContains;
|
||||||
use FireflyIII\TransactionRules\Triggers\DescriptionEnds;
|
use FireflyIII\TransactionRules\Triggers\DescriptionEnds;
|
||||||
use FireflyIII\TransactionRules\Triggers\DescriptionIs;
|
use FireflyIII\TransactionRules\Triggers\DescriptionIs;
|
||||||
@@ -135,11 +139,11 @@ return [
|
|||||||
],
|
],
|
||||||
'feature_flags' => [
|
'feature_flags' => [
|
||||||
'export' => true,
|
'export' => true,
|
||||||
'telemetry' => false,
|
'telemetry' => true,
|
||||||
],
|
],
|
||||||
|
|
||||||
'encryption' => null === env('USE_ENCRYPTION') || true === env('USE_ENCRYPTION'),
|
'encryption' => null === env('USE_ENCRYPTION') || true === env('USE_ENCRYPTION'),
|
||||||
'version' => '5.2.5',
|
'version' => '5.2.6',
|
||||||
'api_version' => '1.1.0',
|
'api_version' => '1.1.0',
|
||||||
'db_version' => 13,
|
'db_version' => 13,
|
||||||
'maxUploadSize' => 15242880,
|
'maxUploadSize' => 15242880,
|
||||||
@@ -467,6 +471,9 @@ return [
|
|||||||
'description_ends' => DescriptionEnds::class,
|
'description_ends' => DescriptionEnds::class,
|
||||||
'description_contains' => DescriptionContains::class,
|
'description_contains' => DescriptionContains::class,
|
||||||
'description_is' => DescriptionIs::class,
|
'description_is' => DescriptionIs::class,
|
||||||
|
'date_is' => DateIs::class,
|
||||||
|
'date_before' => DateBefore::class,
|
||||||
|
'date_after' => DateAfter::class,
|
||||||
'transaction_type' => TransactionType::class,
|
'transaction_type' => TransactionType::class,
|
||||||
'category_is' => CategoryIs::class,
|
'category_is' => CategoryIs::class,
|
||||||
'budget_is' => BudgetIs::class,
|
'budget_is' => BudgetIs::class,
|
||||||
@@ -508,6 +515,7 @@ return [
|
|||||||
'convert_deposit' => ConvertToDeposit::class,
|
'convert_deposit' => ConvertToDeposit::class,
|
||||||
'convert_transfer' => ConvertToTransfer::class,
|
'convert_transfer' => ConvertToTransfer::class,
|
||||||
'update_piggy' => UpdatePiggybank::class,
|
'update_piggy' => UpdatePiggybank::class,
|
||||||
|
'delete_transaction' => DeleteTransaction::class,
|
||||||
],
|
],
|
||||||
'context-rule-actions' => [
|
'context-rule-actions' => [
|
||||||
'set_category',
|
'set_category',
|
||||||
@@ -552,6 +560,9 @@ return [
|
|||||||
'notes_start',
|
'notes_start',
|
||||||
'notes_end',
|
'notes_end',
|
||||||
'notes_are',
|
'notes_are',
|
||||||
|
'date_is',
|
||||||
|
'date_before',
|
||||||
|
'date_after',
|
||||||
],
|
],
|
||||||
|
|
||||||
'test-triggers' => [
|
'test-triggers' => [
|
||||||
|
@@ -38,6 +38,36 @@ if ('ActiveDirectory' === envNonEmpty('ADLDAP_CONNECTION_SCHEME', 'OpenLDAP')) {
|
|||||||
$schema = ActiveDirectory::class;
|
$schema = ActiveDirectory::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get SSL parameters from .env file.
|
||||||
|
*/
|
||||||
|
$ssl_ca_dir = envNonEmpty('ADLDAP_SSL_CACERTDIR', null);
|
||||||
|
$ssl_ca_file = envNonEmpty('ADLDAP_SSL_CACERTFILE', null);
|
||||||
|
$ssl_cert = envNonEmpty('ADLDAP_SSL_CERTFILE', null);
|
||||||
|
$ssl_key = envNonEmpty('ADLDAP_SSL_KEYFILE', null);
|
||||||
|
$ssl_ciphers = envNonEmpty('ADLDAP_SSL_CIPHER_SUITE', null);
|
||||||
|
$ssl_require = envNonEmpty('ADLDAP_SSL_REQUIRE_CERT', null);
|
||||||
|
|
||||||
|
$sslOptions = [];
|
||||||
|
if (null !== $ssl_ca_dir) {
|
||||||
|
$sslOptions[LDAP_OPT_X_TLS_CACERTDIR] = $ssl_ca_dir;
|
||||||
|
}
|
||||||
|
if (null !== $ssl_ca_file) {
|
||||||
|
$sslOptions[LDAP_OPT_X_TLS_CACERTFILE] = $ssl_ca_file;
|
||||||
|
}
|
||||||
|
if (null !== $ssl_cert) {
|
||||||
|
$sslOptions[LDAP_OPT_X_TLS_CERTFILE] = $ssl_cert;
|
||||||
|
}
|
||||||
|
if (null !== $ssl_key) {
|
||||||
|
$sslOptions[LDAP_OPT_X_TLS_KEYFILE] = $ssl_key;
|
||||||
|
}
|
||||||
|
if (null !== $ssl_ciphers) {
|
||||||
|
$sslOptions[LDAP_OPT_X_TLS_CIPHER_SUITE] = $ssl_ciphers;
|
||||||
|
}
|
||||||
|
if (null !== $ssl_require) {
|
||||||
|
$sslOptions[LDAP_OPT_X_TLS_REQUIRE_CERT] = $ssl_require;
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -87,6 +117,19 @@ return [
|
|||||||
|
|
||||||
'connection' => Adldap\Connections\Ldap::class,
|
'connection' => Adldap\Connections\Ldap::class,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Connection Settings
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This connection settings array is directly passed into the Adldap constructor.
|
||||||
|
|
|
||||||
|
| Feel free to add or remove settings you don't need.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'settings' => [
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Schema
|
| Schema
|
||||||
@@ -110,19 +153,6 @@ return [
|
|||||||
|
|
||||||
'schema' => $schema,
|
'schema' => $schema,
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Connection Settings
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This connection settings array is directly passed into the Adldap constructor.
|
|
||||||
|
|
|
||||||
| Feel free to add or remove settings you don't need.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'settings' => [
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Account Prefix
|
| Account Prefix
|
||||||
@@ -254,6 +284,7 @@ return [
|
|||||||
'use_ssl' => env('ADLDAP_USE_SSL', false),
|
'use_ssl' => env('ADLDAP_USE_SSL', false),
|
||||||
'use_tls' => env('ADLDAP_USE_TLS', false),
|
'use_tls' => env('ADLDAP_USE_TLS', false),
|
||||||
|
|
||||||
|
'custom_options' => $sslOptions,
|
||||||
],
|
],
|
||||||
|
|
||||||
],
|
],
|
||||||
|
@@ -217,10 +217,16 @@ return [
|
|||||||
| Windows Authentication Middleware (SSO)
|
| Windows Authentication Middleware (SSO)
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
|
||||||
| Discover:
|
| Enabled:
|
||||||
|
|
|
|
||||||
| The 'discover' value is the users attribute you would
|
| The middleware will be registered only if enabled is set to true.
|
||||||
| like to locate LDAP users by in your directory.
|
| If you update this file, beware, this is not a standard
|
||||||
|
| AdLdap2-Laravel configuration key.
|
||||||
|
|
|
||||||
|
| Locate Users By:
|
||||||
|
|
|
||||||
|
| This value is the users attribute you would like to locate LDAP
|
||||||
|
| users by in your directory.
|
||||||
|
|
|
|
||||||
| For example, if 'samaccountname' is the value, then your LDAP server is
|
| For example, if 'samaccountname' is the value, then your LDAP server is
|
||||||
| queried for a user with the 'samaccountname' equal to the value of
|
| queried for a user with the 'samaccountname' equal to the value of
|
||||||
@@ -229,9 +235,9 @@ return [
|
|||||||
| If a user is found, they are imported (if using the DatabaseUserProvider)
|
| If a user is found, they are imported (if using the DatabaseUserProvider)
|
||||||
| into your local database, then logged in.
|
| into your local database, then logged in.
|
||||||
|
|
|
|
||||||
| Key:
|
| Server Key:
|
||||||
|
|
|
|
||||||
| The 'key' value represents the 'key' of the $_SERVER
|
| This value represents the 'key' of the $_SERVER
|
||||||
| array to pull the users account name from.
|
| array to pull the users account name from.
|
||||||
|
|
|
|
||||||
| For example, $_SERVER['AUTH_USER'].
|
| For example, $_SERVER['AUTH_USER'].
|
||||||
@@ -239,8 +245,9 @@ return [
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
'windows' => [
|
'windows' => [
|
||||||
'discover' => envNonEmpty('WINDOWS_SSO_DISCOVER', 'samaccountname'),
|
'enabled' => envNonEmpty('WINDOWS_SSO_ENABLED', false),
|
||||||
'key' => envNonEmpty('WINDOWS_SSO_KEY', 'AUTH_USER'),
|
'locate_users_by' => envNonEmpty('WINDOWS_SSO_DISCOVER', 'samaccountname'),
|
||||||
|
'server_key' => envNonEmpty('WINDOWS_SSO_KEY', 'AUTH_USER'),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
|
2
public/v1/js/app.js
vendored
2
public/v1/js/app.js
vendored
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user