diff --git a/.github/code_of_conduct.md b/.github/code_of_conduct.md index 9e6b350466..61940de18d 100644 --- a/.github/code_of_conduct.md +++ b/.github/code_of_conduct.md @@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at thegrumpydictator@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at james@firefly-iii.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. diff --git a/.github/contributing.md b/.github/contributing.md index 86cdf14950..19d1dd073d 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -4,7 +4,7 @@ ## Feature requests -I am always interested in expanding Firefly III's many features. Just open a ticket or [drop me a line](mailto:thegrumpydictator@gmail.com). +I am always interested in expanding Firefly III's many features. Just open a ticket or [drop me a line](mailto:james@firefly-iii.org). ## Pull requests diff --git a/.github/security.md b/.github/security.md index ef5a3f808b..54944644aa 100644 --- a/.github/security.md +++ b/.github/security.md @@ -6,7 +6,7 @@ Only the latest version of Firefly III is supported. If you're not running the l ## Reporting a Vulnerability -If you find something that compromises the security of Firefly III, you should [send me a message](mailto:thegrumpydictator@gmail.com) as soon as possible. These issues will be fixed immediately. You can also open an issue, but if you feel the issue is sensitive, please drop me a message instead. +If you find something that compromises the security of Firefly III, you should [send me a message](mailto:james@firefly-iii.org) as soon as possible. These issues will be fixed immediately. You can also open an issue, but if you feel the issue is sensitive, please drop me a message instead. You can use my [GPG key](https://keybase.io/jc5) for extra security. My [GitHub commits](https://github.com/firefly-iii/firefly-iii/commits/master) are almost always signed with this key. diff --git a/app/Api/V1/Controllers/Search/AccountController.php b/app/Api/V1/Controllers/Search/AccountController.php index 24feebcea8..6fcea80239 100644 --- a/app/Api/V1/Controllers/Search/AccountController.php +++ b/app/Api/V1/Controllers/Search/AccountController.php @@ -32,6 +32,7 @@ use Illuminate\Http\Response; use Illuminate\Pagination\LengthAwarePaginator; use League\Fractal\Pagination\IlluminatePaginatorAdapter; use League\Fractal\Resource\Collection as FractalCollection; +use Log; /** * Class AccountController @@ -62,6 +63,7 @@ class AccountController extends Controller */ public function search(Request $request) { + Log::debug('Now in account search()'); $manager = $this->getManager(); $query = $request->get('query'); $field = $request->get('field'); @@ -70,6 +72,8 @@ class AccountController extends Controller return response(null, 422); } $types = $this->mapAccountTypes($type); + Log::debug(sprintf('Going to search for "%s" in types', $query), $types); + /** @var AccountSearch $search */ $search = app(AccountSearch::class); $search->setUser(auth()->user()); @@ -79,6 +83,8 @@ class AccountController extends Controller $accounts = $search->search(); + Log::debug(sprintf('Found %d accounts', $accounts->count())); + /** @var AccountTransformer $transformer */ $transformer = app(AccountTransformer::class); $transformer->setParameters($this->parameters); diff --git a/app/Api/V1/Controllers/TransactionController.php b/app/Api/V1/Controllers/TransactionController.php index ae764b6a73..728e3f0e8b 100644 --- a/app/Api/V1/Controllers/TransactionController.php +++ b/app/Api/V1/Controllers/TransactionController.php @@ -274,6 +274,7 @@ class TransactionController extends Controller */ public function store(TransactionStoreRequest $request): JsonResponse { + Log::debug('Now in API TransactionController::store()'); $data = $request->getAll(); $data['user'] = auth()->user()->id; @@ -283,6 +284,7 @@ class TransactionController extends Controller try { $transactionGroup = $this->groupRepository->store($data); } catch (DuplicateTransactionException $e) { + Log::warning('Caught a duplicate. Return error message.'); // return bad validation message. // TODO use Laravel's internal validation thing to do this. $response = [ @@ -294,7 +296,7 @@ class TransactionController extends Controller return response()->json($response, 422); } - + app('preferences')->mark(); event(new StoredTransactionGroup($transactionGroup)); $manager = $this->getManager(); @@ -338,6 +340,7 @@ class TransactionController extends Controller $transactionGroup = $this->groupRepository->update($transactionGroup, $data); $manager = $this->getManager(); + app('preferences')->mark(); event(new UpdatedTransactionGroup($transactionGroup)); /** @var User $admin */ diff --git a/app/Api/V1/Requests/TransactionStoreRequest.php b/app/Api/V1/Requests/TransactionStoreRequest.php index 967fae17e8..15d8bcfae8 100644 --- a/app/Api/V1/Requests/TransactionStoreRequest.php +++ b/app/Api/V1/Requests/TransactionStoreRequest.php @@ -30,7 +30,7 @@ use FireflyIII\Rules\IsDateOrTime; use FireflyIII\Support\NullArrayObject; use FireflyIII\Validation\TransactionValidation; use Illuminate\Validation\Validator; - +use Log; /** * Class TransactionStoreRequest @@ -46,6 +46,7 @@ class TransactionStoreRequest extends Request */ public function authorize(): bool { + Log::debug('Authorize TransactionStoreRequest'); // Only allow authenticated users return auth()->check(); } @@ -57,6 +58,7 @@ class TransactionStoreRequest extends Request */ public function getAll(): array { + Log::debug('get all data in TransactionStoreRequest'); $data = [ 'group_title' => $this->string('group_title'), 'error_if_duplicate_hash' => $this->boolean('error_if_duplicate_hash'), @@ -73,6 +75,7 @@ class TransactionStoreRequest extends Request */ public function rules(): array { + Log::debug('Collect rules of TransactionStoreRequest'); $rules = [ // basic fields for group: 'group_title' => 'between:1,1000|nullable', diff --git a/app/Exceptions/GracefulNotFoundHandler.php b/app/Exceptions/GracefulNotFoundHandler.php index 5b7de43a1c..6c93d16d12 100644 --- a/app/Exceptions/GracefulNotFoundHandler.php +++ b/app/Exceptions/GracefulNotFoundHandler.php @@ -65,6 +65,7 @@ class GracefulNotFoundHandler extends ExceptionHandler return parent::render($request, $exception); case 'accounts.show': + case 'accounts.show.all': return $this->handleAccount($request, $exception); case 'transactions.show': return $this->handleGroup($request, $exception); diff --git a/app/Factory/AccountFactory.php b/app/Factory/AccountFactory.php index 296220e176..e572e3a1ec 100644 --- a/app/Factory/AccountFactory.php +++ b/app/Factory/AccountFactory.php @@ -2,7 +2,7 @@ /** * AccountFactory.php - * Copyright (c) 2019 thegrumpydictator@gmail.com + * Copyright (c) 2019 james@firefly-iii.org * * This file is part of Firefly III (https://github.com/firefly-iii). * diff --git a/app/Factory/AccountMetaFactory.php b/app/Factory/AccountMetaFactory.php index b5ae6b1b7c..c88239511c 100644 --- a/app/Factory/AccountMetaFactory.php +++ b/app/Factory/AccountMetaFactory.php @@ -2,7 +2,7 @@ /** * AccountMetaFactory.php - * Copyright (c) 2019 thegrumpydictator@gmail.com + * Copyright (c) 2019 james@firefly-iii.org * * This file is part of Firefly III (https://github.com/firefly-iii). * diff --git a/app/Factory/AttachmentFactory.php b/app/Factory/AttachmentFactory.php index eb3d87d347..bf4c225768 100644 --- a/app/Factory/AttachmentFactory.php +++ b/app/Factory/AttachmentFactory.php @@ -1,7 +1,7 @@ journalFactory->setUser($this->user); $this->journalFactory->setErrorOnHash($data['error_if_duplicate_hash'] ?? false); - $collection = $this->journalFactory->create($data); + try { + $collection = $this->journalFactory->create($data); + } catch(DuplicateTransactionException $e) { + Log::warning('GroupFactory::create() caught journalFactory::create() with a duplicate!'); + throw new DuplicateTransactionException($e->getMessage()); + } $title = $data['group_title'] ?? null; $title = '' === $title ? null : $title; diff --git a/app/Factory/TransactionJournalFactory.php b/app/Factory/TransactionJournalFactory.php index 95c25af707..e1db66c70f 100644 --- a/app/Factory/TransactionJournalFactory.php +++ b/app/Factory/TransactionJournalFactory.php @@ -2,7 +2,7 @@ /** * TransactionJournalFactory.php - * Copyright (c) 2019 thegrumpydictator@gmail.com + * Copyright (c) 2019 james@firefly-iii.org * * This file is part of Firefly III (https://github.com/firefly-iii). * @@ -129,11 +129,11 @@ class TransactionJournalFactory public function create(array $data): Collection { // convert to special object. - $data = new NullArrayObject($data); + $dataObject = new NullArrayObject($data); Log::debug('Start of TransactionJournalFactory::create()'); $collection = new Collection; - $transactions = $data['transactions'] ?? []; + $transactions = $dataObject['transactions'] ?? []; if (0 === count($transactions)) { Log::error('There are no transactions in the array, the TransactionJournalFactory cannot continue.'); @@ -145,7 +145,12 @@ class TransactionJournalFactory Log::debug(sprintf('Now creating journal %d/%d', $index + 1, count($transactions))); Log::debug('Going to call createJournal', $row); - $journal = $this->createJournal(new NullArrayObject($row)); + try { + $journal = $this->createJournal(new NullArrayObject($row)); + } catch (DuplicateTransactionException|Exception $e) { + Log::warning('TransactionJournalFactory::create() caught a duplicate journal in createJournal()'); + throw new DuplicateTransactionException($e->getMessage()); + } if (null !== $journal) { $collection->push($journal); } @@ -395,17 +400,20 @@ class TransactionJournalFactory */ private function errorIfDuplicate(string $hash): void { + Log::debug(sprintf('In errorIfDuplicate(%s)', $hash)); if (false === $this->errorOnHash) { return; } $result = null; if ($this->errorOnHash) { + Log::debug('Will verify duplicate!'); /** @var TransactionJournalMeta $result */ $result = TransactionJournalMeta::where('data', json_encode($hash, JSON_THROW_ON_ERROR)) ->with(['transactionJournal', 'transactionJournal.transactionGroup']) ->first(); } if (null !== $result) { + Log::warning('Found a duplicate!'); throw new DuplicateTransactionException(sprintf('Duplicate of transaction #%d.', $result->transactionJournal->transaction_group_id)); } } @@ -526,6 +534,9 @@ class TransactionJournalFactory public function setErrorOnHash(bool $errorOnHash): void { $this->errorOnHash = $errorOnHash; + if (true === $errorOnHash) { + Log::info('Will trigger duplication alert for this journal.'); + } } diff --git a/app/Factory/TransactionJournalMetaFactory.php b/app/Factory/TransactionJournalMetaFactory.php index 126c2b7db5..6e696196e4 100644 --- a/app/Factory/TransactionJournalMetaFactory.php +++ b/app/Factory/TransactionJournalMetaFactory.php @@ -1,7 +1,7 @@ hasBudgetInformation = false; $this->hasBillInformation = false; $this->hasJoinedTagTables = false; - $this->integerFields = [ + $this->hasJoinedAttTables = false; + $this->integerFields = [ 'transaction_group_id', 'user_id', 'transaction_journal_id', @@ -101,10 +104,10 @@ class GroupCollector implements GroupCollectorInterface 'destination_transaction_id', 'destination_account_id', 'category_id', - 'budget_id' + 'budget_id', ]; - $this->total = 0; - $this->fields = [ + $this->total = 0; + $this->fields = [ # group 'transaction_groups.id as transaction_group_id', 'transaction_groups.user_id as user_id', @@ -281,11 +284,10 @@ class GroupCollector implements GroupCollectorInterface */ public function getGroups(): Collection { - $start = microtime(true); + //$start = microtime(true); /** @var Collection $result */ $result = $this->query->get($this->fields); - $end = round(microtime(true) - $start, 5); - + //$end = round(microtime(true) - $start, 5); // log info about query time. //Log::info(sprintf('Query took Firefly III %s seconds', $end)); //Log::info($this->query->toSql(), $this->query->getBindings()); @@ -950,6 +952,24 @@ class GroupCollector implements GroupCollectorInterface } } + /** + * Join table to get attachment information. + */ + private function joinAttachmentTables(): void + { + if (false === $this->hasJoinedAttTables) { + // join some extra tables: + $this->hasJoinedAttTables = true; + $this->query->leftJoin('attachments', 'attachments.attachable_id', '=', 'transaction_journals.id') + ->where( + static function (EloquentBuilder $q1) { + $q1->where('attachments.attachable_type', TransactionJournal::class); + $q1->orWhereNull('attachments.attachable_type'); + } + ); + } + } + /** * @param array $existingJournal * @param TransactionJournal $newJournal @@ -980,6 +1000,26 @@ class GroupCollector implements GroupCollectorInterface return $existingJournal; } + /** + * @param array $existingJournal + * @param TransactionJournal $newJournal + * + * @return array + */ + private function mergeAttachments(array $existingJournal, TransactionJournal $newJournal): array + { + $newArray = $newJournal->toArray(); + if (isset($newArray['attachment_id'])) { + $attachmentId = (int)$newJournal['tag_id']; + $existingJournal['attachments'][$attachmentId] = [ + 'id' => $attachmentId, + ]; + } + + return $existingJournal; + } + + /** * @param Collection $collection * @@ -994,7 +1034,7 @@ class GroupCollector implements GroupCollectorInterface if (!isset($groups[$groupId])) { // make new array - $parsedGroup = $this->parseAugmentedGroup($augumentedJournal); + $parsedGroup = $this->parseAugmentedJournal($augumentedJournal); $groupArray = [ 'id' => (int)$augumentedJournal->transaction_group_id, 'user_id' => (int)$augumentedJournal->user_id, @@ -1014,11 +1054,14 @@ class GroupCollector implements GroupCollectorInterface $groups[$groupId]['count']++; if (isset($groups[$groupId]['transactions'][$journalId])) { + // append data to existing group + journal (for multiple tags or multiple attachments) $groups[$groupId]['transactions'][$journalId] = $this->mergeTags($groups[$groupId]['transactions'][$journalId], $augumentedJournal); + $groups[$groupId]['transactions'][$journalId] = $this->mergeAttachments($groups[$groupId]['transactions'][$journalId], $augumentedJournal); } if (!isset($groups[$groupId]['transactions'][$journalId])) { - $groups[$groupId]['transactions'][$journalId] = $this->parseAugmentedGroup($augumentedJournal); + // create second, third, fourth split: + $groups[$groupId]['transactions'][$journalId] = $this->parseAugmentedJournal($augumentedJournal); } @@ -1034,10 +1077,11 @@ class GroupCollector implements GroupCollectorInterface * * @return array */ - private function parseAugmentedGroup(TransactionJournal $augumentedJournal): array + private function parseAugmentedJournal(TransactionJournal $augumentedJournal): array { - $result = $augumentedJournal->toArray(); - $result['tags'] = []; + $result = $augumentedJournal->toArray(); + $result['tags'] = []; + $result['attachments'] = []; try { $result['date'] = new Carbon($result['date']); $result['created_at'] = new Carbon($result['created_at']); @@ -1067,6 +1111,14 @@ class GroupCollector implements GroupCollectorInterface ]; } + // also merge attachments: + if (isset($augumentedJournal['attachment_id'])) { + $attachmentId = (int)$augumentedJournal['attachment_id']; + $result['attachments'][$attachmentId] = [ + 'id' => $attachmentId, + ]; + } + return $result; } @@ -1230,4 +1282,15 @@ class GroupCollector implements GroupCollectorInterface return $this; } + + /** + * @inheritDoc + */ + public function withAttachmentInformation(): GroupCollectorInterface + { + $this->fields[] = 'attachments.id as attachment_id'; + $this->joinAttachmentTables(); + + return $this; + } } diff --git a/app/Helpers/Collector/GroupCollectorInterface.php b/app/Helpers/Collector/GroupCollectorInterface.php index c0beab69df..df69fc4439 100644 --- a/app/Helpers/Collector/GroupCollectorInterface.php +++ b/app/Helpers/Collector/GroupCollectorInterface.php @@ -57,6 +57,13 @@ interface GroupCollectorInterface */ public function amountLess(string $amount): GroupCollectorInterface; + /** + * Add basic info on attachments of transactions. + * + * @return GroupCollectorInterface + */ + public function withAttachmentInformation(): GroupCollectorInterface; + /** * Get transactions where the amount is more than. * diff --git a/app/Http/Controllers/DebugController.php b/app/Http/Controllers/DebugController.php index cd25ce80d8..d0e2dd61e3 100644 --- a/app/Http/Controllers/DebugController.php +++ b/app/Http/Controllers/DebugController.php @@ -118,6 +118,7 @@ class DebugController extends Controller $search = ['~', '#']; $replace = ['\~', '# ']; + $installationId = app('fireflyconfig')->get('installation_id', '')->data; $phpVersion = str_replace($search, $replace, PHP_VERSION); $phpOs = str_replace($search, $replace, PHP_OS); $interface = PHP_SAPI; @@ -126,8 +127,6 @@ class DebugController extends Controller $drivers = implode(', ', DB::availableDrivers()); $currentDriver = DB::getDriverName(); $userAgent = $request->header('user-agent'); - $isSandstorm = var_export(config('firefly.is_sandstorm'), true); - $toSandbox = var_export(config('firefly.bunq_use_sandbox'), true); $trustedProxies = config('firefly.trusted_proxies'); $displayErrors = ini_get('display_errors'); $errorReporting = $this->errorReporting((int)ini_get('error_reporting')); @@ -174,9 +173,10 @@ class DebugController extends Controller return view( 'debug', compact( - 'phpVersion', 'extensions', 'localeAttempts', 'appEnv', 'appDebug', 'logChannel', 'appLogLevel', 'now', 'drivers', 'currentDriver', 'loginProvider', - 'userAgent', 'displayErrors', 'errorReporting', 'phpOs', 'interface', 'logContent', 'cacheDriver', 'isSandstorm', 'trustedProxies', 'toSandbox' - ) + 'phpVersion', 'extensions', 'localeAttempts', 'appEnv', 'appDebug', 'logChannel', 'appLogLevel', 'now', 'drivers', 'currentDriver', + 'loginProvider', + 'userAgent', 'displayErrors', 'installationId', 'errorReporting', 'phpOs', 'interface', 'logContent', 'cacheDriver', 'trustedProxies' + ) ); } diff --git a/app/Http/Controllers/Transaction/CreateController.php b/app/Http/Controllers/Transaction/CreateController.php index 490a1ba802..766489b8e8 100644 --- a/app/Http/Controllers/Transaction/CreateController.php +++ b/app/Http/Controllers/Transaction/CreateController.php @@ -70,6 +70,12 @@ class CreateController extends Controller $service = app(GroupCloneService::class); $newGroup = $service->cloneGroup($group); + app('preferences')->mark(); + + $title = $newGroup->title ?? $newGroup->transactionJournals->first()->description; + + session()->flash('success', trans('firefly.stored_journal', ['description' => $title])); + return redirect(route('transactions.show', [$newGroup->id])); } diff --git a/app/Http/Controllers/Transaction/IndexController.php b/app/Http/Controllers/Transaction/IndexController.php index 73156ea651..3f2ffa3704 100644 --- a/app/Http/Controllers/Transaction/IndexController.php +++ b/app/Http/Controllers/Transaction/IndexController.php @@ -107,7 +107,8 @@ class IndexController extends Controller ->setPage($page) ->withBudgetInformation() ->withCategoryInformation() - ->withAccountInformation(); + ->withAccountInformation() + ->withAttachmentInformation(); $groups = $collector->getPaginatedGroups(); $groups->setPath($path); @@ -147,7 +148,8 @@ class IndexController extends Controller ->setPage($page) ->withAccountInformation() ->withBudgetInformation() - ->withCategoryInformation(); + ->withCategoryInformation() + ->withAttachmentInformation(); $groups = $collector->getPaginatedGroups(); $groups->setPath($path); diff --git a/app/Models/Account.php b/app/Models/Account.php index 8d659a27fd..74ba6610cb 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -1,7 +1,7 @@ setUser($this->user); + try { + return $factory->create($data); + } catch (DuplicateTransactionException $e) { + Log::warning('Group repository caught group factory with a duplicate exception!'); + throw new DuplicateTransactionException($e->getMessage()); + } + - return $factory->create($data); } /** diff --git a/app/Repositories/TransactionGroup/TransactionGroupRepositoryInterface.php b/app/Repositories/TransactionGroup/TransactionGroupRepositoryInterface.php index a4b39a8d06..ce0a7e0be1 100644 --- a/app/Repositories/TransactionGroup/TransactionGroupRepositoryInterface.php +++ b/app/Repositories/TransactionGroup/TransactionGroupRepositoryInterface.php @@ -1,7 +1,7 @@ name = $data['name'] ?? $account->name; $account->active = $data['active'] ?? $account->active; - $account->iban = $data['iban'] ?? $account->iban; + $account->iban = $data['iban'] ?? $account->iban; + + // if account type is a liability, the liability type (account type) + // can be updated to another one. + if ($this->isLiability($account) && $this->isLiabilityTypeId((int)($data['account_type_id'] ?? 0))) { + $account->account_type_id = (int)$data['account_type_id']; + } // update virtual balance (could be set to zero if empty string). if (null !== $data['virtual_balance']) { @@ -118,8 +123,8 @@ class AccountUpdateService $location->locatable()->associate($account); } - $location->latitude = $data['latitude'] ?? config('firefly.default_location.latitude'); - $location->longitude = $data['longitude'] ?? config('firefly.default_location.longitude'); + $location->latitude = $data['latitude'] ?? config('firefly.default_location.latitude'); + $location->longitude = $data['longitude'] ?? config('firefly.default_location.longitude'); $location->zoom_level = $data['zoom_level'] ?? config('firefly.default_location.zoom_level'); $location->save(); } @@ -147,4 +152,30 @@ class AccountUpdateService return $account; } + + /** + * @param Account $account + * + * @return bool + */ + private function isLiability(Account $account): bool + { + $type = $account->accountType->type; + + return in_array($type, [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE], true); + } + + /** + * @param int $accountTypeId + * + * @return bool + */ + private function isLiabilityTypeId(int $accountTypeId): bool + { + if (0 === $accountTypeId) { + return false; + } + + return 1 === AccountType::whereIn('type', [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE])->where('id', $accountTypeId)->count(); + } } diff --git a/app/Services/Internal/Update/BillUpdateService.php b/app/Services/Internal/Update/BillUpdateService.php index 2b79a6e44d..16171dd1ce 100644 --- a/app/Services/Internal/Update/BillUpdateService.php +++ b/app/Services/Internal/Update/BillUpdateService.php @@ -1,7 +1,7 @@ [AccountType::DEFAULT, AccountType::CASH, AccountType::ASSET, AccountType::EXPENSE, AccountType::REVENUE, + 'all' => [AccountType::DEFAULT, AccountType::CASH, + AccountType::ASSET, AccountType::EXPENSE, AccountType::REVENUE, AccountType::INITIAL_BALANCE, AccountType::BENEFICIARY, AccountType::IMPORT, AccountType::RECONCILIATION, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE], 'asset' => [AccountType::DEFAULT, AccountType::ASSET,], diff --git a/app/Support/Http/Api/ApiSupport.php b/app/Support/Http/Api/ApiSupport.php index 1c33a686a2..1f33b3074c 100644 --- a/app/Support/Http/Api/ApiSupport.php +++ b/app/Support/Http/Api/ApiSupport.php @@ -1,7 +1,7 @@ $importable->note, 'tags' => $importable->tags, - 'internal_reference' => $importable->meta['internal-reference'] ?? null, + 'internal_reference' => $importable->meta['internal_reference'] ?? null, 'external_id' => $importable->externalId, - 'original_source' => $importable->meta['original-source'] ?? null, + 'original_source' => $importable->meta['original_source'] ?? null, 'sepa_cc' => $importable->meta['sepa_cc'] ?? null, 'sepa_ct_op' => $importable->meta['sepa_ct_op'] ?? null, @@ -280,12 +281,12 @@ class ImportableConverter 'sepa_ci' => $importable->meta['sepa_ci'] ?? null, 'sepa_batch_id' => $importable->meta['sepa_batch_id'] ?? null, - 'interest_date' => $this->convertDateValue($importable->meta['date-interest'] ?? null), - 'book_date' => $this->convertDateValue($importable->meta['date-book'] ?? null), - 'process_date' => $this->convertDateValue($importable->meta['date-process'] ?? null), - 'due_date' => $this->convertDateValue($importable->meta['date-due'] ?? null), - 'payment_date' => $this->convertDateValue($importable->meta['date-payment'] ?? null), - 'invoice_date' => $this->convertDateValue($importable->meta['date-invoice'] ?? null), + 'interest_date' => $this->convertDateValue($importable->meta['date_interest'] ?? null), + 'book_date' => $this->convertDateValue($importable->meta['date_book'] ?? null), + 'process_date' => $this->convertDateValue($importable->meta['date_process'] ?? null), + 'due_date' => $this->convertDateValue($importable->meta['date_due'] ?? null), + 'payment_date' => $this->convertDateValue($importable->meta['date_payment'] ?? null), + 'invoice_date' => $this->convertDateValue($importable->meta['date_invoice'] ?? null), ], ], ]; diff --git a/app/Support/Import/Routine/File/ImportableCreator.php b/app/Support/Import/Routine/File/ImportableCreator.php index 1b0bb83703..9730c2eb95 100644 --- a/app/Support/Import/Routine/File/ImportableCreator.php +++ b/app/Support/Import/Routine/File/ImportableCreator.php @@ -1,7 +1,7 @@ orWhere( static function (Builder $q) use ($originalQuery) { $json = json_encode($originalQuery, JSON_THROW_ON_ERROR); - $q->where('account_meta.name', 'account_number'); - $q->where('account_meta.data', $json); + $q->where('account_meta.name', '=', 'account_number'); + $q->where('account_meta.data', 'LIKE', $json); } ); break; @@ -107,7 +107,6 @@ class AccountSearch implements GenericSearchInterface ); break; } - return $query->distinct()->get(['accounts.*']); } diff --git a/app/Support/Search/GenericSearchInterface.php b/app/Support/Search/GenericSearchInterface.php index c14e59d57e..c28b0d093f 100644 --- a/app/Support/Search/GenericSearchInterface.php +++ b/app/Support/Search/GenericSearchInterface.php @@ -1,7 +1,7 @@ cleanString($query); $this->originalQuery = $filteredQuery; - $pattern = '/[[:alpha:]_]*:"?[\P{C}_-]*"?/ui'; + $pattern = '/[[:alpha:]_]*:(".*"|[\P{Zs}_-]*)/ui'; $matches = []; preg_match_all($pattern, $filteredQuery, $matches); diff --git a/app/Support/Search/SearchInterface.php b/app/Support/Search/SearchInterface.php index f9431dfecc..38db8dc383 100644 --- a/app/Support/Search/SearchInterface.php +++ b/app/Support/Search/SearchInterface.php @@ -1,7 +1,7 @@ sourceError = (string)trans('validation.transfer_source_need_data'); - + Log::warning('Not a valid source, need more data.'); return false; } @@ -567,10 +567,11 @@ class AccountValidator $search = $this->findExistingAccount($validTypes, (int)$accountId, (string)$accountName); if (null === $search) { $this->sourceError = (string)trans('validation.transfer_source_bad_data', ['id' => $accountId, 'name' => $accountName]); - + Log::warning('Not a valid source, cant find it.', $validTypes); return false; } $this->source = $search; + Log::debug('Valid source!'); return true; } @@ -634,6 +635,7 @@ class AccountValidator // if both values are NULL we return false, // because the source of a withdrawal can't be created. $this->sourceError = (string)trans('validation.withdrawal_source_need_data'); + Log::warning('Not a valid source. Need more data.'); return false; } @@ -642,10 +644,11 @@ class AccountValidator $search = $this->findExistingAccount($validTypes, (int)$accountId, (string)$accountName); if (null === $search) { $this->sourceError = (string)trans('validation.withdrawal_source_bad_data', ['id' => $accountId, 'name' => $accountName]); - + Log::warning('Not a valid source. Cant find it.', $validTypes); return false; } $this->source = $search; + Log::debug('Valid source account!'); return true; } diff --git a/app/Validation/FireflyValidator.php b/app/Validation/FireflyValidator.php index 32880b31bc..e8c50939d9 100644 --- a/app/Validation/FireflyValidator.php +++ b/app/Validation/FireflyValidator.php @@ -1,7 +1,7 @@ getTransactionsArray($validator); $data = $validator->getData(); @@ -88,6 +89,7 @@ trait TransactionValidation */ public function validateAccountInformationUpdate(Validator $validator): void { + Log::debug('Now in validateAccountInformationUpdate()'); $transactions = $this->getTransactionsArray($validator); /** @var AccountValidator $accountValidator */ @@ -141,9 +143,10 @@ trait TransactionValidation */ public function validateDescriptions(Validator $validator): void { + Log::debug('Now in validateDescriptions()'); $transactions = $this->getTransactionsArray($validator); $validDescriptions = 0; - foreach ($transactions as $index => $transaction) { + foreach ($transactions as $transaction) { if ('' !== (string)($transaction['description'] ?? null)) { $validDescriptions++; } @@ -164,6 +167,7 @@ trait TransactionValidation */ public function validateForeignCurrencyInformation(Validator $validator): void { + Log::debug('Now in validateForeignCurrencyInformation()'); $transactions = $this->getTransactionsArray($validator); foreach ($transactions as $index => $transaction) { @@ -191,6 +195,7 @@ trait TransactionValidation */ public function validateGroupDescription(Validator $validator): void { + Log::debug('Now in validateGroupDescription()'); $data = $validator->getData(); $transactions = $this->getTransactionsArray($validator); @@ -207,6 +212,7 @@ trait TransactionValidation */ public function validateOneRecurrenceTransaction(Validator $validator): void { + Log::debug('Now in validateOneRecurrenceTransaction()'); $transactions = $this->getTransactionsArray($validator); // need at least one transaction @@ -222,6 +228,7 @@ trait TransactionValidation */ public function validateOneRecurrenceTransactionUpdate(Validator $validator): void { + Log::debug('Now in validateOneRecurrenceTransactionUpdate()'); $transactions = $this->getTransactionsArray($validator); // need at least one transaction if (0 === count($transactions)) { @@ -236,11 +243,15 @@ trait TransactionValidation */ public function validateOneTransaction(Validator $validator): void { + Log::debug('Now in validateOneTransaction()'); $transactions = $this->getTransactionsArray($validator); // need at least one transaction if (0 === count($transactions)) { $validator->errors()->add('transactions.0.description', (string)trans('validation.at_least_one_transaction')); + Log::debug('Added error: at_least_one_transaction.'); + return; } + Log::debug('Added NO errors.'); } /** @@ -250,6 +261,7 @@ trait TransactionValidation */ public function validateTransactionTypes(Validator $validator): void { + Log::debug('Now in validateTransactionTypes()'); $transactions = $this->getTransactionsArray($validator); $types = []; @@ -276,6 +288,7 @@ trait TransactionValidation */ public function validateTransactionTypesForUpdate(Validator $validator): void { + Log::debug('Now in validateTransactionTypesForUpdate()'); $transactions = $this->getTransactionsArray($validator); $types = []; foreach ($transactions as $index => $transaction) { @@ -383,6 +396,7 @@ trait TransactionValidation */ private function validateEqualAccounts(Validator $validator): void { + Log::debug('Now in validateEqualAccounts()'); $data = $validator->getData(); $transactions = $data['transactions'] ?? []; @@ -433,6 +447,7 @@ trait TransactionValidation */ private function validateEqualAccountsForUpdate(Validator $validator, TransactionGroup $transactionGroup): void { + Log::debug('Now in validateEqualAccountsForUpdate()'); $data = $validator->getData(); $transactions = $data['transactions'] ?? []; @@ -525,6 +540,7 @@ trait TransactionValidation */ private function validateJournalIds(Validator $validator, TransactionGroup $transactionGroup): void { + Log::debug('Now in validateJournalIds()'); $data = $validator->getData(); $transactions = $data['transactions'] ?? []; diff --git a/bootstrap/app.php b/bootstrap/app.php index 79783c3441..1f310951ec 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -1,7 +1,7 @@ =5.4.0" }, "require-dev": { - "illuminate/http": "^5.0|^6.0|^7.0", + "illuminate/http": "^5.0|^6.0|^7.0|^8.0", "mockery/mockery": "^1.0", "phpunit/phpunit": "^6.0" }, @@ -938,7 +938,7 @@ "proxy", "trusted proxy" ], - "time": "2019-12-20T13:11:11+00:00" + "time": "2020-02-22T01:51:47+00:00" }, { "name": "firebase/php-jwt", @@ -1239,7 +1239,7 @@ }, { "name": "James Cole", - "email": "thegrumpydictator@gmail.com", + "email": "james@firefly-iii.org", "role": "Developer" } ], @@ -1390,16 +1390,16 @@ }, { "name": "laravel/framework", - "version": "v6.15.1", + "version": "v6.16.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "b7c152e3327c03428fb68d5abb63ca8b3eca8422" + "reference": "b47217e41868d3049ec545cbb713aa94c6f39e55" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/b7c152e3327c03428fb68d5abb63ca8b3eca8422", - "reference": "b7c152e3327c03428fb68d5abb63ca8b3eca8422", + "url": "https://api.github.com/repos/laravel/framework/zipball/b47217e41868d3049ec545cbb713aa94c6f39e55", + "reference": "b47217e41868d3049ec545cbb713aa94c6f39e55", "shasum": "" }, "require": { @@ -1467,7 +1467,7 @@ "aws/aws-sdk-php": "^3.0", "doctrine/dbal": "^2.6", "filp/whoops": "^2.4", - "guzzlehttp/guzzle": "^6.3", + "guzzlehttp/guzzle": "^6.3|^7.0", "league/flysystem-cached-adapter": "^1.0", "mockery/mockery": "^1.3.1", "moontoast/math": "^1.1", @@ -1487,7 +1487,7 @@ "ext-redis": "Required to use the Redis cache and queue drivers.", "filp/whoops": "Required for friendly error pages in development (^2.4).", "fzaninotto/faker": "Required to use the eloquent factory builder (^1.9.1).", - "guzzlehttp/guzzle": "Required to use the Mailgun mail driver and the ping methods on schedules (^6.0).", + "guzzlehttp/guzzle": "Required to use the Mailgun mail driver and the ping methods on schedules (^6.0|^7.0).", "laravel/tinker": "Required to use the tinker console command (^2.0).", "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).", "league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).", @@ -1532,7 +1532,7 @@ "framework", "laravel" ], - "time": "2020-02-12T21:56:14+00:00" + "time": "2020-02-18T15:17:52+00:00" }, { "name": "laravel/passport", @@ -2687,16 +2687,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "2.0.23", + "version": "2.0.24", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "c78eb5058d5bb1a183133c36d4ba5b6675dfa099" + "reference": "40998159a0907cc523e1f2d1904d45765613a617" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/c78eb5058d5bb1a183133c36d4ba5b6675dfa099", - "reference": "c78eb5058d5bb1a183133c36d4ba5b6675dfa099", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/40998159a0907cc523e1f2d1904d45765613a617", + "reference": "40998159a0907cc523e1f2d1904d45765613a617", "shasum": "" }, "require": { @@ -2775,7 +2775,7 @@ "x.509", "x509" ], - "time": "2019-09-17T03:41:22+00:00" + "time": "2020-02-04T12:15:04+00:00" }, { "name": "pragmarx/google2fa", @@ -3356,16 +3356,16 @@ }, { "name": "ramsey/uuid", - "version": "3.9.2", + "version": "3.9.3", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "7779489a47d443f845271badbdcedfe4df8e06fb" + "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/7779489a47d443f845271badbdcedfe4df8e06fb", - "reference": "7779489a47d443f845271badbdcedfe4df8e06fb", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/7e1633a6964b48589b142d60542f9ed31bd37a92", + "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92", "shasum": "" }, "require": { @@ -3439,7 +3439,7 @@ "identifier", "uuid" ], - "time": "2019-12-17T08:18:51+00:00" + "time": "2020-02-21T04:36:14+00:00" }, { "name": "rcrowe/twigbridge", @@ -5118,16 +5118,16 @@ }, { "name": "tightenco/collect", - "version": "v6.15.0", + "version": "v6.16.0", "source": { "type": "git", "url": "https://github.com/tightenco/collect.git", - "reference": "17046ff310e1c6a70c8c1cd3743b3631b7e76aee" + "reference": "75e997d1803c2e979ce6f314a5df8a97a8af93b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tightenco/collect/zipball/17046ff310e1c6a70c8c1cd3743b3631b7e76aee", - "reference": "17046ff310e1c6a70c8c1cd3743b3631b7e76aee", + "url": "https://api.github.com/repos/tightenco/collect/zipball/75e997d1803c2e979ce6f314a5df8a97a8af93b0", + "reference": "75e997d1803c2e979ce6f314a5df8a97a8af93b0", "shasum": "" }, "require": { @@ -5164,7 +5164,7 @@ "collection", "laravel" ], - "time": "2020-01-28T19:25:21+00:00" + "time": "2020-02-18T17:25:13+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -6860,12 +6860,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "0365bf26eddd4a8be9980d7dabf05ceb2aba2f02" + "reference": "1df6b9d09d2b074fd3f0f10a7696d9f797d4772c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/0365bf26eddd4a8be9980d7dabf05ceb2aba2f02", - "reference": "0365bf26eddd4a8be9980d7dabf05ceb2aba2f02", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/1df6b9d09d2b074fd3f0f10a7696d9f797d4772c", + "reference": "1df6b9d09d2b074fd3f0f10a7696d9f797d4772c", "shasum": "" }, "conflict": { @@ -6884,6 +6884,7 @@ "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.5.18|>=3.6,<3.6.15|>=3.7,<3.7.7", "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", + "centreon/centreon": "<18.10.8|>=19,<19.4.5", "cesnet/simplesamlphp-module-proxystatistics": "<3.1", "codeigniter/framework": "<=3.0.6", "composer/composer": "<=1-alpha.11", @@ -6950,7 +6951,7 @@ "monolog/monolog": ">=1.8,<1.12", "namshi/jose": "<2.2", "onelogin/php-saml": "<2.10.4", - "oneup/uploader-bundle": ">=1,<1.9.3|>=2,<2.1.5", + "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", "openid/php-openid": "<2.3", "oro/crm": ">=1.7,<1.7.4", "oro/platform": ">=1.7,<1.7.4", @@ -6986,7 +6987,7 @@ "silverstripe/cms": "<4.3.6|>=4.4,<4.4.4", "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<4.4.4", + "silverstripe/framework": "<4.4.5|>=4.5,<4.5.2", "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.1.2", "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", @@ -7110,7 +7111,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2020-02-10T16:13:40+00:00" + "time": "2020-02-19T06:23:50+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", diff --git a/config/app.php b/config/app.php index 01b40384a7..6f482eaba1 100644 --- a/config/app.php +++ b/config/app.php @@ -1,7 +1,7 @@ null === env('USE_ENCRYPTION') || true === env('USE_ENCRYPTION'), - 'version' => '5.1.0-alpha.1', + 'version' => '5.1.0-beta.1', 'api_version' => '1.0.1', 'db_version' => 12, 'maxUploadSize' => 15242880, diff --git a/config/google2fa.php b/config/google2fa.php index 6c7a4a3dc6..5f65f69f59 100644 --- a/config/google2fa.php +++ b/config/google2fa.php @@ -1,7 +1,7 @@ envNonEmpty('LOG_CHANNEL', 'stack'), - + 'level' => envNonEmpty('APP_LOG_LEVEL', 'info'), /* |-------------------------------------------------------------------------- | Log Channels diff --git a/config/mail.php b/config/mail.php index 1d3df1977c..b4c40e74e7 100644 --- a/config/mail.php +++ b/config/mail.php @@ -1,7 +1,7 @@