Merge branch 'release/4.7.5'

This commit is contained in:
James Cole 2018-07-03 20:33:34 +02:00
commit c2216843d8
470 changed files with 39245 additions and 5621 deletions

View File

@ -1,8 +1,23 @@
#!/bin/bash
# make sure the correct directories exists (suggested by @chrif):
mkdir -p $FIREFLY_PATH/storage/app
mkdir -p $FIREFLY_PATH/storage/app/public
mkdir -p $FIREFLY_PATH/storage/build
mkdir -p $FIREFLY_PATH/storage/database
mkdir -p $FIREFLY_PATH/storage/debugbar
mkdir -p $FIREFLY_PATH/storage/export
mkdir -p $FIREFLY_PATH/storage/framework/cache
mkdir -p $FIREFLY_PATH/storage/framework/sessions
mkdir -p $FIREFLY_PATH/storage/framework/testing
mkdir -p $FIREFLY_PATH/storage/framework/views
mkdir -p $FIREFLY_PATH/storage/logs
mkdir -p $FIREFLY_PATH/storage/upload
# make sure we own the volumes:
chown -R www-data:www-data -R $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/logs $FIREFLY_PATH/storage/cache
chmod -R 775 $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/logs $FIREFLY_PATH/storage/cache
chown -R www-data:www-data -R $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/logs $FIREFLY_PATH/storage/framework/cache
chmod -R 775 $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/upload $FIREFLY_PATH/storage/logs $FIREFLY_PATH/storage/framework/cache
# remove any lingering files that may break upgrades:
rm -f $FIREFLY_PATH/storage/logs/laravel.log

View File

@ -50,6 +50,7 @@ COOKIE_DOMAIN=
COOKIE_SECURE=false
# If you want Firefly III to mail you, update these settings
# For instructions, see: https://firefly-iii.readthedocs.io/en/latest/installation/mail.html
MAIL_DRIVER=${MAIL_DRIVER}
MAIL_HOST=${MAIL_HOST}
MAIL_PORT=${MAIL_PORT}
@ -58,6 +59,12 @@ MAIL_USERNAME=${MAIL_USERNAME}
MAIL_PASSWORD=${MAIL_PASSWORD}
MAIL_ENCRYPTION=${MAIL_ENCRYPTION}
# Other mail drivers:
MAILGUN_DOMAIN=${MAILGUN_DOMAIN}
MAILGUN_SECRET=${MAILGUN_SECRET}
MANDRILL_SECRET=${MANDRILL_SECRET}
SPARKPOST_SECRET=${SPARKPOST_SECRET}
# Firefly III can send you the following messages
SEND_REGISTRATION_MAIL=true
SEND_ERROR_MESSAGE=false

View File

@ -54,6 +54,7 @@ COOKIE_DOMAIN=
COOKIE_SECURE=false
# If you want Firefly III to mail you, update these settings
# For instructions, see: https://firefly-iii.readthedocs.io/en/latest/installation/mail.html
MAIL_DRIVER=log
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
@ -62,6 +63,12 @@ MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
# Other mail drivers:
MAILGUN_DOMAIN=
MAILGUN_SECRET=
MANDRILL_SECRET=
SPARKPOST_SECRET=
# Firefly III can send you the following messages
SEND_REGISTRATION_MAIL=true
SEND_ERROR_MESSAGE=true
@ -100,3 +107,5 @@ IS_DOCKER=false
IS_SANDSTORM=false
BUNQ_USE_SANDBOX=false
IS_HEROKU=false
MAILGUN_DOMAIN=
MAILGUN_SECRET=

View File

@ -54,6 +54,7 @@ COOKIE_DOMAIN=
COOKIE_SECURE=false
# If you want Firefly III to mail you, update these settings
# For instructions, see: https://firefly-iii.readthedocs.io/en/latest/installation/mail.html
MAIL_DRIVER=log
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
@ -62,6 +63,12 @@ MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
# Other mail drivers:
MAILGUN_DOMAIN=
MAILGUN_SECRET=
MANDRILL_SECRET=
SPARKPOST_SECRET=
# Firefly III can send you the following messages
SEND_REGISTRATION_MAIL=true
SEND_ERROR_MESSAGE=true
@ -100,3 +107,5 @@ IS_DOCKER=false
IS_SANDSTORM=false
BUNQ_USE_SANDBOX=false
IS_HEROKU=true
MAILGUN_DOMAIN=
MAILGUN_SECRET=

View File

@ -54,6 +54,7 @@ COOKIE_DOMAIN=
COOKIE_SECURE=false
# If you want Firefly III to mail you, update these settings
# For instructions, see: https://firefly-iii.readthedocs.io/en/latest/installation/mail.html
MAIL_DRIVER=log
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
@ -62,6 +63,12 @@ MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
# Other mail drivers:
MAILGUN_DOMAIN=
MAILGUN_SECRET=
MANDRILL_SECRET=
SPARKPOST_SECRET=
# Firefly III can send you the following messages
SEND_REGISTRATION_MAIL=true
SEND_ERROR_MESSAGE=true
@ -100,3 +107,5 @@ IS_DOCKER=false
IS_SANDSTORM=true
BUNQ_USE_SANDBOX=false
IS_HEROKU=false
MAILGUN_DOMAIN=
MAILGUN_SECRET=

View File

@ -49,6 +49,7 @@ COOKIE_DOMAIN=
COOKIE_SECURE=false
# If you want Firefly III to mail you, update these settings
# For instructions, see: https://firefly-iii.readthedocs.io/en/latest/installation/mail.html
MAIL_DRIVER=log
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
@ -57,9 +58,11 @@ MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
# Firefly III can send you the following messages
SEND_REGISTRATION_MAIL=true
SEND_ERROR_MESSAGE=false
# Other mail drivers:
MAILGUN_DOMAIN=
MAILGUN_SECRET=
MANDRILL_SECRET=
SPARKPOST_SECRET=
# Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places.
@ -96,3 +99,5 @@ IS_DOCKER=false
IS_SANDSTORM=false
BUNQ_USE_SANDBOX=true
IS_HEROKU=false
MAILGUN_DOMAIN=
MAILGUN_SECRET=

View File

@ -13,7 +13,7 @@ I am running Firefly III version x.x.x
What do you need to do to trigger this bug?
**Extra info**
Please add extra info here, such as OS, browser, and the output from the `/debug`-page of your Firefly III installation (click the version at the bottom).
Please add extra info here, such as OS, browser, and the output from the /debug page of your Firefly III installation (click the version at the bottom).
**Bonus points**
Earn bonus points by:

View File

@ -1,25 +1,27 @@
---
name: I have a question or a problem
about: Ask away
about: Ask away!
---
I am running Firefly III version x.x.x
**Description of my issue:**
**Description**
**Steps to reproduce**
(if relevant of course)
(please include if this problem also exists on the demo site: https://demo.firefly-iii.org/ )
**Extra info**
Please add extra info here, such as OS, browser, and the output from the `/debug`-page of your Firefly III installation (click the version at the bottom).
**Bonus points**
Earn bonus points by:
- Post a stacktrace from your log files
- Add a screenshot
- Post nginx or Apache configuration
- Replicate the problem on the demo site https://demo.firefly-iii.org/

View File

@ -8,7 +8,8 @@ about: Suggest an idea or feature for Firefly III
Please describe your feature request:
- I would like Firefly III to do X.
- What if you would add Y?
- What if you would add feature Y?
- Firefly III doesn't do Z.
**Solution**
Describe what your feature would add to Firefly III.

3
.github/stale.yml vendored
View File

@ -1,7 +1,7 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 30
daysUntilStale: 14
# Number of days of inactivity before a stale Issue or Pull Request is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
@ -12,6 +12,7 @@ daysUntilClose: 7
exemptLabels:
- enhancement
- feature
- bug
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false

View File

@ -1,3 +1,22 @@
# 4.7.5
- A new feature called "recurring transactions" that will make Firefly III automatically create transactions for you.
- New API end points for attachments, available budgets, budgets, budget limits, categories, configuration, currency exchange rates, journal links, link types, piggy banks, preferences, recurring transactions, rules, rule groups and tags.
- Added support for YunoHost.
- The 2FA secret is visible so you can type it into 2FA apps.
- Bunq and Spectre imports will now ask to apply rules.
- Sandstorm users can now make API keys.
- Various typo's in the English translations. [issue 1493](https://github.com/firefly-iii/firefly-iii/issues/1493)
- Bug where Spectre was never called [issue 1492](https://github.com/firefly-iii/firefly-iii/issues/1492)
- Clear cache after journal is created through API [issue 1483](https://github.com/firefly-iii/firefly-iii/issues/1483)
- Make sure docker directories exist [issue 1500](https://github.com/firefly-iii/firefly-iii/issues/1500)
- Broken link to bill edit [issue 1505](https://github.com/firefly-iii/firefly-iii/issues/1505)
- Several bugs in the editing of split transactions [issue 1509](https://github.com/firefly-iii/firefly-iii/issues/1509)
- Import routine ignored formatting of several date fields [issue 1510](https://github.com/firefly-iii/firefly-iii/issues/1510)
- Piggy bank events now show the correct currency [issue 1446](https://github.com/firefly-iii/firefly-iii/issues/1446)
- Inactive accounts are no longer suggested [issue 1463](https://github.com/firefly-iii/firefly-iii/issues/1463)
- Some income / expense charts are less confusing [issue 1518](https://github.com/firefly-iii/firefly-iii/issues/1518)
- Validation bug in multi-currency create view [issue 1521](https://github.com/firefly-iii/firefly-iii/issues/1521)
# 4.7.4
- [Issue 1409](https://github.com/firefly-iii/firefly-iii/issues/1409), add Indian Rupee and explain that users can do this themselves [issue 1413](https://github.com/firefly-iii/firefly-iii/issues/1413)
- [Issue 1445](https://github.com/firefly-iii/firefly-iii/issues/1445), upgrade Curl in Docker image.

File diff suppressed because it is too large Load Diff

View File

@ -15,8 +15,8 @@ const pkgdef :Spk.PackageDefinition = (
manifest = (
appTitle = (defaultText = "Firefly III"),
appVersion = 13,
appMarketingVersion = (defaultText = "4.7.4"),
appVersion = 14,
appMarketingVersion = (defaultText = "4.7.5"),
actions = [
# Define your "new document" handlers here.
@ -65,9 +65,9 @@ const pkgdef :Spk.PackageDefinition = (
# Sizes are given in device-independent pixels, so if you took these
# screenshots on a Retina-style high DPI screen, divide each dimension by two.
(width = 1291, height = 800, png = embed "screenshots/screenshot-1.png"),
(width = 1291, height = 800, png = embed "screenshots/screenshot-2.png"),
(width = 1291, height = 800, png = embed "screenshots/screenshot-3.png"),
(width = 1290, height = 800, png = embed "screenshots/screenshot-1.png"),
(width = 1290, height = 800, png = embed "screenshots/screenshot-2.png"),
(width = 1290, height = 800, png = embed "screenshots/screenshot-3.png"),
],
changeLog = (defaultText = embed "changelog.md"),

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 163 KiB

View File

@ -1,7 +1,6 @@
language: php
php:
- 7.1
- 7.2
- 7.1.18
cache:
directories:
@ -14,7 +13,6 @@ install:
- cp .env.testing .env
- php artisan clear-compiled
- php artisan env
- cp .env.testing .env
- wget -q https://github.com/firefly-iii/test-data/raw/master/storage/database.sqlite -O storage/database/database.sqlite
- mkdir -p build/logs

View File

@ -23,6 +23,7 @@ RUN apt-get update -y && \
libpq-dev \
libbz2-dev \
gettext-base \
cron \
locales && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
@ -47,6 +48,13 @@ RUN cd /tmp && \
make && \
make install
# Create the log file to be able to run tail
RUN touch /var/log/cron.log
# Setup cron job
RUN (crontab -l ; echo "* * * * * root $FIREFLY_PATH/artisan schedule:run >> /var/log/cron.log") | crontab
# Install PHP exentions.
RUN docker-php-ext-install -j$(nproc) curl gd intl json readline tidy zip bcmath xml mbstring pdo_sqlite pdo_mysql bz2 pdo_pgsql
@ -77,6 +85,9 @@ RUN composer install --prefer-dist --no-dev --no-scripts --no-suggest
# Expose port 80
EXPOSE 80
# Run the command on container startup
CMD cron
# Run entrypoint thing
ENTRYPOINT [".deploy/docker/entrypoint.sh"]

View File

@ -26,20 +26,25 @@ namespace FireflyIII\Api\V1\Controllers;
use DB;
use FireflyIII\Transformers\UserTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use League\Fractal\Manager;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Returns basic information about this installation.
*
* Class AboutController
*/
class AboutController extends Controller
{
/**
* @return \Illuminate\Http\JsonResponse
* Returns system information.
*
* @return JsonResponse
*/
public function about()
public function about(): JsonResponse
{
$search = ['~', '#'];
$replace = ['\~', '# '];
@ -59,11 +64,13 @@ class AboutController extends Controller
}
/**
* Returns information about the user.
*
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function user(Request $request)
public function user(Request $request): JsonResponse
{
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';

View File

@ -30,6 +30,8 @@ use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Manager;
@ -37,7 +39,6 @@ use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
use Preferences;
/**
* Class AccountController
@ -51,20 +52,20 @@ class AccountController extends Controller
/**
* AccountController constructor.
*
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
// @var AccountRepositoryInterface repository
$this->repository = app(AccountRepositoryInterface::class);
$this->repository->setUser(auth()->user());
$this->repository->setUser($user);
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
$this->currencyRepository->setUser(auth()->user());
$this->currencyRepository->setUser($user);
return $next($request);
}
@ -76,9 +77,9 @@ class AccountController extends Controller
*
* @param \FireflyIII\Models\Account $account
*
* @return \Illuminate\Http\Response
* @return JsonResponse
*/
public function delete(Account $account)
public function delete(Account $account): JsonResponse
{
$this->repository->destroy($account, null);
@ -90,12 +91,12 @@ class AccountController extends Controller
*
* @param Request $request
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function index(Request $request)
public function index(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager();
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// read type from URI
@ -104,7 +105,7 @@ class AccountController extends Controller
// types to get, page size:
$types = $this->mapTypes($this->parameters->get('type'));
$pageSize = (int)Preferences::getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of accounts. Count it and split it.
$collection = $this->repository->getAccountsByType($types);
@ -129,9 +130,9 @@ class AccountController extends Controller
*
* @return \Illuminate\Http\JsonResponse
*/
public function show(Request $request, Account $account)
public function show(Request $request, Account $account): JsonResponse
{
$manager = new Manager();
$manager = new Manager;
// add include parameter:
$include = $request->get('include') ?? '';
@ -149,7 +150,7 @@ class AccountController extends Controller
*
* @return \Illuminate\Http\JsonResponse
*/
public function store(AccountRequest $request)
public function store(AccountRequest $request): JsonResponse
{
$data = $request->getAll();
// if currency ID is 0, find the currency by the code:
@ -158,7 +159,7 @@ class AccountController extends Controller
$data['currency_id'] = null === $currency ? 0 : $currency->id;
}
$account = $this->repository->store($data);
$manager = new Manager();
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
@ -175,7 +176,7 @@ class AccountController extends Controller
*
* @return \Illuminate\Http\JsonResponse
*/
public function update(AccountRequest $request, Account $account)
public function update(AccountRequest $request, Account $account): JsonResponse
{
$data = $request->getAll();
// if currency ID is 0, find the currency by the code:
@ -186,7 +187,7 @@ class AccountController extends Controller
// set correct type:
$data['type'] = config('firefly.shortNamesByFullName.' . $account->accountType->type);
$this->repository->update($account, $data);
$manager = new Manager();
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));

View File

@ -0,0 +1,229 @@
<?php
/**
* AttachmentController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\AttachmentRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
use FireflyIII\Models\Attachment;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response as LaravelResponse;
use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class AttachmentController
*/
class AttachmentController extends Controller
{
/** @var AttachmentRepositoryInterface */
private $repository;
/**
* AccountController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->repository = app(AttachmentRepositoryInterface::class);
$this->repository->setUser($user);
return $next($request);
}
);
}
/**
* Remove the specified resource from storage.
*
* @param Attachment $attachment
*
* @return JsonResponse
*/
public function delete(Attachment $attachment): JsonResponse
{
$this->repository->destroy($attachment);
return response()->json([], 204);
}
/**
* @param Attachment $attachment
*
* @return LaravelResponse
* @throws FireflyException
*/
public function download(Attachment $attachment): LaravelResponse
{
if ($attachment->uploaded === false) {
throw new FireflyException('No file has been uploaded for this attachment (yet).');
}
if ($this->repository->exists($attachment)) {
$content = $this->repository->getContent($attachment);
$quoted = sprintf('"%s"', addcslashes(basename($attachment->filename), '"\\'));
/** @var LaravelResponse $response */
$response = response($content, 200);
$response
->header('Content-Description', 'File Transfer')
->header('Content-Type', 'application/octet-stream')
->header('Content-Disposition', 'attachment; filename=' . $quoted)
->header('Content-Transfer-Encoding', 'binary')
->header('Connection', 'Keep-Alive')
->header('Expires', '0')
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public')
->header('Content-Length', \strlen($content));
return $response;
}
throw new FireflyException('Could not find the indicated attachment. The file is no longer there.');
}
/**
* Display a listing of the resource.
*
* @param Request $request
*
* @return JsonResponse
*/
public function index(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of accounts. Count it and split it.
$collection = $this->repository->get();
$count = $collection->count();
$attachments = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($attachments, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.attachments.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($attachments, new AttachmentTransformer($this->parameters), 'attachments');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Display the specified resource.
*
* @param Request $request
* @param Attachment $attachment
*
* @return JsonResponse
*/
public function show(Request $request, Attachment $attachment): JsonResponse
{
$manager = new Manager;
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($attachment, new AttachmentTransformer($this->parameters), 'attachments');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Store a newly created resource in storage.
*
* @param AttachmentRequest $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function store(AttachmentRequest $request): JsonResponse
{
$data = $request->getAll();
$attachment = $this->repository->store($data);
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($attachment, new AttachmentTransformer($this->parameters), 'attachments');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Update the specified resource in storage.
*
* @param AttachmentRequest $request
* @param Attachment $attachment
*
* @return JsonResponse
*/
public function update(AttachmentRequest $request, Attachment $attachment): JsonResponse
{
$data = $request->getAll();
$this->repository->update($attachment, $data);
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($attachment, new AttachmentTransformer($this->parameters), 'attachments');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param Request $request
* @param Attachment $attachment
*
* @return JsonResponse
*/
public function upload(Request $request, Attachment $attachment): JsonResponse
{
/** @var AttachmentHelperInterface $helper */
$helper = app(AttachmentHelperInterface::class);
$body = $request->getContent();
$helper->saveAttachmentFromApi($attachment, $body);
return response()->json([], 204);
}
}

View File

@ -0,0 +1,183 @@
<?php
/**
* AvailableBudgetController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\AvailableBudgetRequest;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Transformers\AvailableBudgetTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class AvailableBudgetController
*/
class AvailableBudgetController extends Controller
{
/** @var CurrencyRepositoryInterface */
private $currencyRepository;
/** @var BudgetRepositoryInterface */
private $repository;
/**
* AccountController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->repository = app(BudgetRepositoryInterface::class);
$this->currencyRepository = app(CurrencyRepositoryInterface::class);
$this->repository->setUser($user);
return $next($request);
}
);
}
/**
* Remove the specified resource from storage.
*
* @param AvailableBudget $availableBudget
*
* @return JsonResponse
*/
public function delete(AvailableBudget $availableBudget): JsonResponse
{
$this->repository->destroyAvailableBudget($availableBudget);
return response()->json([], 204);
}
/**
* Display a listing of the resource.
*
* @param Request $request
*
* @return JsonResponse
*/
public function index(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of available budgets. Count it and split it.
$collection = $this->repository->getAvailableBudgets();
$count = $collection->count();
$availableBudgets = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($availableBudgets, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.available_budgets.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($availableBudgets, new AvailableBudgetTransformer($this->parameters), 'available_budgets');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Display the specified resource.
*
* @param Request $request
* @param AvailableBudget $availableBudget
*
* @return JsonResponse
*/
public function show(Request $request, AvailableBudget $availableBudget): JsonResponse
{
$manager = new Manager;
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($availableBudget, new AvailableBudgetTransformer($this->parameters), 'available_budgets');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Store a newly created resource in storage.
*
* @param AvailableBudgetRequest $request
*
* @return JsonResponse
*/
public function store(AvailableBudgetRequest $request): JsonResponse
{
$data = $request->getAll();
$currency = $this->currencyRepository->findNull($data['transaction_currency_id']);
$availableBudget = $this->repository->setAvailableBudget($currency, $data['start_date'], $data['end_date'], $data['amount']);
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($availableBudget, new AvailableBudgetTransformer($this->parameters), 'available_budgets');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Update the specified resource in storage.
*
* @param AvailableBudgetRequest $request
* @param AvailableBudget $availableBudget
*
* @return JsonResponse
*/
public function update(AvailableBudgetRequest $request, AvailableBudget $availableBudget): JsonResponse
{
$data = $request->getAll();
$this->repository->updateAvailableBudget($availableBudget, $data);
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($availableBudget, new AvailableBudgetTransformer($this->parameters), 'available_budgets');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@ -37,7 +37,6 @@ use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
use Preferences;
/**
* Class BillController
@ -49,8 +48,6 @@ class BillController extends Controller
/**
* BillController constructor.
*
* @throws FireflyException
*/
public function __construct()
{
@ -89,7 +86,7 @@ class BillController extends Controller
*/
public function index(Request $request): JsonResponse
{
$pageSize = (int)Preferences::getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$paginator = $this->repository->getPaginator($pageSize);
/** @var Collection $bills */
$bills = $paginator->getCollection();

View File

@ -0,0 +1,176 @@
<?php
/**
* BudgetController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\BudgetRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Transformers\BudgetTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class BudgetController
*/
class BudgetController extends Controller
{
/** @var BudgetRepositoryInterface */
private $repository;
/**
* BudgetController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var BudgetRepositoryInterface repository */
$this->repository = app(BudgetRepositoryInterface::class);
$this->repository->setUser(auth()->user());
return $next($request);
}
);
}
/**
* Remove the specified resource from storage.
*
* @param Budget $budget
*
* @return JsonResponse
*/
public function delete(Budget $budget): JsonResponse
{
$this->repository->destroy($budget);
return response()->json([], 204);
}
/**
* Display a listing of the resource.
*
* @param Request $request
*
* @return JsonResponse
*/
public function index(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budgets. Count it and split it.
$collection = $this->repository->getBudgets();
$count = $collection->count();
$budgets = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($budgets, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.budgets.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($budgets, new BudgetTransformer($this->parameters), 'budgets');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param Request $request
* @param Budget $budget
*
* @return JsonResponse
*/
public function show(Request $request, Budget $budget): JsonResponse
{
$manager = new Manager();
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($budget, new BudgetTransformer($this->parameters), 'budgets');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param BudgetRequest $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function store(BudgetRequest $request): JsonResponse
{
$budget = $this->repository->store($request->getAll());
if (null !== $budget) {
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($budget, new BudgetTransformer($this->parameters), 'budgets');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
throw new FireflyException('Could not store new budget.'); // @codeCoverageIgnore
}
/**
* @param BudgetRequest $request
* @param Budget $budget
*
* @return JsonResponse
*/
public function update(BudgetRequest $request, Budget $budget): JsonResponse
{
$data = $request->getAll();
$budget = $this->repository->update($budget, $data);
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($budget, new BudgetTransformer($this->parameters), 'budgets');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@ -0,0 +1,232 @@
<?php
/**
* BudgetLimitController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use Carbon\Carbon;
use Exception;
use FireflyIII\Api\V1\Requests\AvailableBudgetRequest;
use FireflyIII\Api\V1\Requests\BudgetLimitRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Transformers\BudgetLimitTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use InvalidArgumentException;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
use Log;
use Throwable;
/**
* Class BudgetLimitController
*/
class BudgetLimitController extends Controller
{
///** @var CurrencyRepositoryInterface */
//private $currencyRepository;
/** @var BudgetRepositoryInterface */
private $repository;
/**
* AccountController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->repository = app(BudgetRepositoryInterface::class);
//$this->currencyRepository = app(CurrencyRepositoryInterface::class);
$this->repository->setUser($user);
return $next($request);
}
);
}
/**
* Remove the specified resource from storage.
*
* @param BudgetLimit $budgetLimit
*
* @return JsonResponse
*/
public function delete(BudgetLimit $budgetLimit): JsonResponse
{
$this->repository->destroyBudgetLimit($budgetLimit);
return response()->json([], 204);
}
/**
* Display a listing of the resource.
*
* @param Request $request
*
* @return JsonResponse
*/
public function index(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// read budget from request
$budgetId = (int)($request->get('budget_id') ?? 0);
$budget = null;
if ($budgetId > 0) {
$budget = $this->repository->findNull($budgetId);
}
// read start date from request
$start = null;
try {
$start = Carbon::createFromFormat('Y-m-d', $request->get('start'));
$this->parameters->set('start', $start->format('Y-m-d'));
} catch (InvalidArgumentException $e) {
Log::debug(sprintf('Could not parse start date "%s": %s', $request->get('start'), $e->getMessage()));
}
// read end date from request
$end = null;
try {
$end = Carbon::createFromFormat('Y-m-d', $request->get('end'));
$this->parameters->set('end', $end->format('Y-m-d'));
} catch (InvalidArgumentException $e) {
Log::debug(sprintf('Could not parse end date "%s": %s', $request->get('end'), $e->getMessage()));
}
$this->parameters->set('budget_id', $budgetId);
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budget limits. Count it and split it.
$collection = new Collection;
if (null === $budget) {
$collection = $this->repository->getAllBudgetLimits($start, $end);
}
if (null !== $budget) {
$collection = $this->repository->getBudgetLimits($budget, $start, $end);
}
$count = $collection->count();
$budgetLimits = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.budget_limits.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($budgetLimits, new BudgetLimitTransformer($this->parameters), 'budget_limits');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Display the specified resource.
*
* @param Request $request
* @param BudgetLimit $budgetLimit
*
* @return JsonResponse
*/
public function show(Request $request, BudgetLimit $budgetLimit): JsonResponse
{
$manager = new Manager;
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($budgetLimit, new BudgetLimitTransformer($this->parameters), 'budget_limits');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Store a newly created resource in storage.
*
* @param BudgetLimitRequest $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function store(BudgetLimitRequest $request): JsonResponse
{
$data = $request->getAll();
$budget = $this->repository->findNull($data['budget_id']);
if (null === $budget) {
throw new FireflyException('Unknown budget.');
}
$data['budget'] = $budget;
$budgetLimit = $this->repository->storeBudgetLimit($data);
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($budgetLimit, new BudgetLimitTransformer($this->parameters), 'budget_limits');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Update the specified resource in storage.
*
* @param AvailableBudgetRequest $request
* @param BudgetLimit $budgetLimit
*
* @return JsonResponse
*/
public function update(BudgetLimitRequest $request, BudgetLimit $budgetLimit): JsonResponse
{
$data = $request->getAll();
$budget = $this->repository->findNull($data['budget_id']);
if (null === $budget) {
$budget = $budgetLimit->budget;
}
$data['budget'] = $budget;
$budgetLimit = $this->repository->updateBudgetLimit($budgetLimit, $data);
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($budgetLimit, new BudgetLimitTransformer($this->parameters), 'budget_limits');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@ -0,0 +1,176 @@
<?php
/**
* CategoryController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\CategoryRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Transformers\CategoryTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class CategoryController
*/
class CategoryController extends Controller
{
/** @var CategoryRepositoryInterface */
private $repository;
/**
* CategoryController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var CategoryRepositoryInterface repository */
$this->repository = app(CategoryRepositoryInterface::class);
$this->repository->setUser(auth()->user());
return $next($request);
}
);
}
/**
* Remove the specified resource from storage.
*
* @param Category $category
*
* @return JsonResponse
*/
public function delete(Category $category): JsonResponse
{
$this->repository->destroy($category);
return response()->json([], 204);
}
/**
* Display a listing of the resource.
*
* @param Request $request
*
* @return JsonResponse
*/
public function index(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budgets. Count it and split it.
$collection = $this->repository->getCategories();
$count = $collection->count();
$categories = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($categories, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.categories.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($categories, new CategoryTransformer($this->parameters), 'categories');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param Request $request
* @param Category $category
*
* @return JsonResponse
*/
public function show(Request $request, Category $category): JsonResponse
{
$manager = new Manager();
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($category, new CategoryTransformer($this->parameters), 'categories');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param CategoryRequest $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function store(CategoryRequest $request): JsonResponse
{
$category = $this->repository->store($request->getAll());
if (null !== $category) {
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($category, new CategoryTransformer($this->parameters), 'categories');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
throw new FireflyException('Could not store new category.'); // @codeCoverageIgnore
}
/**
* @param CategoryRequest $request
* @param Category $category
*
* @return JsonResponse
*/
public function update(CategoryRequest $request, Category $category): JsonResponse
{
$data = $request->getAll();
$category = $this->repository->update($category, $data);
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($category, new CategoryTransformer($this->parameters), 'categories');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@ -0,0 +1,105 @@
<?php
/**
* ConfigurationController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Configuration;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
/**
* Class ConfigurationController
*/
class ConfigurationController extends Controller
{
/**
* @throws FireflyException
*/
public function index()
{
if (!auth()->user()->hasRole('owner')) {
throw new FireflyException('No access to method.'); // @codeCoverageIgnore
}
$configData = $this->getConfigData();
return response()->json(['data' => $configData], 200)->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param Request $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function update(Request $request): JsonResponse
{
if (!auth()->user()->hasRole('owner')) {
throw new FireflyException('No access to method.'); // @codeCoverageIgnore
}
$name = $request->get('name');
$value = $request->get('value');
$valid = ['is_demo_site', 'permission_update_check', 'single_user_mode'];
if (!\in_array($name, $valid, true)) {
throw new FireflyException('You cannot edit this configuration value.');
}
$configValue = '';
switch ($name) {
case 'is_demo_site':
case 'single_user_mode':
$configValue = $value === 'true';
break;
case 'permission_update_check':
$configValue = (int)$value >= -1 && (int)$value <= 1 ? (int)$value : -1;
break;
}
app('fireflyconfig')->set($name, $configValue);
$configData = $this->getConfigData();
return response()->json(['data' => $configData], 200)->header('Content-Type', 'application/vnd.api+json');
}
/**
* @return array
*/
private function getConfigData(): array
{
/** @var Configuration $isDemoSite */
$isDemoSite = app('fireflyconfig')->get('is_demo_site');
/** @var Configuration $updateCheck */
$updateCheck = app('fireflyconfig')->get('permission_update_check');
/** @var Configuration $lastCheck */
$lastCheck = app('fireflyconfig')->get('last_update_check');
/** @var Configuration $singleUser */
$singleUser = app('fireflyconfig')->get('single_user_mode');
$data = [
'is_demo_site' => null === $isDemoSite ? null : $isDemoSite->data,
'permission_update_check' => null === $updateCheck ? null : (int)$updateCheck->data,
'last_update_check' => null === $lastCheck ? null : (int)$lastCheck->data,
'single_user_mode' => null === $singleUser ? null : $singleUser->data,
];
return $data;
}
}

View File

@ -26,8 +26,6 @@ namespace FireflyIII\Api\V1\Controllers;
use Carbon\Carbon;
use Carbon\Exceptions\InvalidDateException;
use FireflyConfig;
use FireflyIII\Exceptions\FireflyException;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\BillRequest;
use FireflyIII\Api\V1\Requests\CurrencyRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionCurrency;
@ -39,7 +38,6 @@ use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
use Preferences;
/**
* Class CurrencyController
@ -102,7 +100,7 @@ class CurrencyController extends Controller
*/
public function index(Request $request): JsonResponse
{
$pageSize = (int)Preferences::getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$collection = $this->repository->get();
$count = $collection->count();
// slice them:
@ -158,8 +156,8 @@ class CurrencyController extends Controller
$currency = $this->repository->store($request->getAll());
if ($request->boolean('default') === true) {
Preferences::set('currencyPreference', $currency->code);
Preferences::mark();
app('preferences')->set('currencyPreference', $currency->code);
app('preferences')->mark();
}
if (null !== $currency) {
$manager = new Manager();
@ -178,7 +176,7 @@ class CurrencyController extends Controller
/**
* @param CurrencyRequest $request
* @param CurrencyRequest $request
* @param TransactionCurrency $currency
*
* @return JsonResponse
@ -189,8 +187,8 @@ class CurrencyController extends Controller
$currency = $this->repository->update($currency, $data);
if ($request->boolean('default') === true) {
Preferences::set('currencyPreference', $currency->code);
Preferences::mark();
app('preferences')->set('currencyPreference', $currency->code);
app('preferences')->mark();
}
$manager = new Manager();

View File

@ -0,0 +1,115 @@
<?php
/**
* CurrencyExchangeRateController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Services\Currency\ExchangeRateInterface;
use FireflyIII\Transformers\CurrencyExchangeRateTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use InvalidArgumentException;
use League\Fractal\Manager;
use League\Fractal\Resource\Item;
use Log;
/**
*
* Class CurrencyExchangeRateController
*/
class CurrencyExchangeRateController extends Controller
{
/** @var CurrencyRepositoryInterface */
private $repository;
/**
* CurrencyExchangeRateController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(CurrencyRepositoryInterface::class);
$this->repository->setUser(auth()->user());
return $next($request);
}
);
}
/**
* @param Request $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function index(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// currencies
$fromCurrency = $this->repository->findByCodeNull($request->get('from') ?? 'EUR');
$toCurrency = $this->repository->findByCodeNull($request->get('to') ?? 'USD');
if (null === $fromCurrency) {
throw new FireflyException('Unknown source currency.');
}
if (null === $toCurrency) {
throw new FireflyException('Unknown destination currency.');
}
$dateObj = new Carbon;
try {
$dateObj = Carbon::createFromFormat('Y-m-d', $request->get('date') ?? date('Y-m-d'));
} catch (InvalidArgumentException $e) {
Log::debug($e->getMessage());
}
$this->parameters->set('from', $fromCurrency->code);
$this->parameters->set('to', $toCurrency->code);
$this->parameters->set('date', $dateObj->format('Y-m-d'));
// get the exchange rate.
$rate = $this->repository->getExchangeRate($fromCurrency, $toCurrency, $dateObj);
if (null === $rate) {
// create service:
/** @var ExchangeRateInterface $service */
$service = app(ExchangeRateInterface::class);
$service->setUser(auth()->user());
// get rate:
$rate = $service->getRate($fromCurrency, $toCurrency, $dateObj);
}
$resource = new Item($rate, new CurrencyExchangeRateTransformer($this->parameters), 'currency_exchange_rates');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@ -0,0 +1,207 @@
<?php
/**
* JournalLinkController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\JournalLinkRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionJournalLink;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
use FireflyIII\Transformers\JournalLinkTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
class JournalLinkController extends Controller
{
/** @var JournalRepositoryInterface */
private $journalRepository;
/** @var LinkTypeRepositoryInterface */
private $repository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->repository = app(LinkTypeRepositoryInterface::class);
$this->journalRepository = app(JournalRepositoryInterface::class);
$this->repository->setUser($user);
$this->journalRepository->setUser($user);
return $next($request);
}
);
}
/**
* Delete the resource.
*
* @param TransactionJournalLink $link
*
* @return JsonResponse
*/
public function delete(TransactionJournalLink $link): JsonResponse
{
$this->repository->destroyLink($link);
return response()->json([], 204);
}
/**
* List all of them.
*
* @param Request $request
*
* @return JsonResponse]
*/
public function index(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// read type from URI
$name = $request->get('name') ?? null;
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$linkType = $this->repository->findByName($name);
// get list of accounts. Count it and split it.
$collection = $this->repository->getJournalLinks($linkType);
$count = $collection->count();
$journalLinks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($journalLinks, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.journal_links.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($journalLinks, new JournalLinkTransformer($this->parameters), 'journal_links');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List single resource.
*
* @param Request $request
* @param TransactionJournalLink $journalLink
*
* @return JsonResponse
*/
public function show(Request $request, TransactionJournalLink $journalLink): JsonResponse
{
$manager = new Manager;
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($journalLink, new JournalLinkTransformer($this->parameters), 'journal_links');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Store new object.
*
* @param JournalLinkRequest $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function store(JournalLinkRequest $request): JsonResponse
{
$manager = new Manager;
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$data = $request->getAll();
$inward = $this->journalRepository->findNull($data['inward_id'] ?? 0);
$outward = $this->journalRepository->findNull($data['outward_id'] ?? 0);
if (null === $inward || null === $outward) {
throw new FireflyException('Source or destination is NULL.');
}
$data['direction'] = 'inward';
$journalLink = $this->repository->storeLink($data, $inward, $outward);
$resource = new Item($journalLink, new JournalLinkTransformer($this->parameters), 'journal_links');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param JournalLinkRequest $request
* @param TransactionJournalLink $journalLink
*
* @return JsonResponse
* @throws FireflyException
*/
public function update(JournalLinkRequest $request, TransactionJournalLink $journalLink): JsonResponse
{
$manager = new Manager;
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$data = $request->getAll();
$data['inward'] = $this->journalRepository->findNull($data['inward_id'] ?? 0);
$data['outward'] = $this->journalRepository->findNull($data['outward_id'] ?? 0);
if (null === $data['inward'] || null === $data['outward']) {
throw new FireflyException('Source or destination is NULL.');
}
$data['direction'] = 'inward';
$journalLink = $this->repository->updateLink($journalLink, $data);
$resource = new Item($journalLink, new JournalLinkTransformer($this->parameters), 'journal_links');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@ -0,0 +1,197 @@
<?php
/**
* LinkTypeController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\LinkTypeRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\LinkType;
use FireflyIII\Repositories\LinkType\LinkTypeRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Transformers\LinkTypeTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
*
* Class LinkTypeController
*/
class LinkTypeController extends Controller
{
/** @var LinkTypeRepositoryInterface */
private $repository;
/** @var UserRepositoryInterface */
private $userRepository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->repository = app(LinkTypeRepositoryInterface::class);
$this->userRepository = app(UserRepositoryInterface::class);
$this->repository->setUser($user);
return $next($request);
}
);
}
/**
* Delete the resource.
*
* @param LinkType $linkType
*
* @return JsonResponse
* @throws FireflyException
*/
public function delete(LinkType $linkType): JsonResponse
{
if ($linkType->editable === false) {
throw new FireflyException(sprintf('You cannot delete this link type (#%d, "%s")', $linkType->id, $linkType->name));
}
$this->repository->destroy($linkType, null);
return response()->json([], 204);
}
/**
* List all of them.
*
* @param Request $request
*
* @return JsonResponse]
*/
public function index(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of accounts. Count it and split it.
$collection = $this->repository->get();
$count = $collection->count();
$linkTypes = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($linkTypes, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.link_types.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($linkTypes, new LinkTypeTransformer($this->parameters), 'link_types');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List single resource.
*
* @param Request $request
* @param LinkType $linkType
*
* @return JsonResponse
*/
public function show(Request $request, LinkType $linkType): JsonResponse
{
$manager = new Manager;
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($linkType, new LinkTypeTransformer($this->parameters), 'link_types');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Store new object.
*
* @param LinkTypeRequest $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function store(LinkTypeRequest $request): JsonResponse
{
if (!$this->userRepository->hasRole(auth()->user(), 'owner')) {
throw new FireflyException('You need the "owner"-role to do this.');
}
$data = $request->getAll();
// if currency ID is 0, find the currency by the code:
$linkType = $this->repository->store($data);
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($linkType, new LinkTypeTransformer($this->parameters), 'link_types');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param LinkTypeRequest $request
* @param LinkType $linkType
*
* @return JsonResponse
* @throws FireflyException
*/
public function update(LinkTypeRequest $request, LinkType $linkType): JsonResponse
{
if ($linkType->editable === false) {
throw new FireflyException(sprintf('You cannot edit this link type (#%d, "%s")', $linkType->id, $linkType->name));
}
if (!$this->userRepository->hasRole(auth()->user(), 'owner')) {
throw new FireflyException('You need the "owner"-role to do this.');
}
$data = $request->getAll();
$this->repository->update($linkType, $data);
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($linkType, new LinkTypeTransformer($this->parameters), 'link_types');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@ -0,0 +1,180 @@
<?php
/**
* PiggyBankController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\PiggyBankRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Transformers\PiggyBankTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* TODO order up and down.
* Class PiggyBankController
*/
class PiggyBankController extends Controller
{
/** @var PiggyBankRepositoryInterface */
private $repository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->repository = app(PiggyBankRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Delete the resource.
*
* @param PiggyBank $piggyBank
*
* @return JsonResponse
*/
public function delete(PiggyBank $piggyBank): JsonResponse
{
$this->repository->destroy($piggyBank);
return response()->json([], 204);
}
/**
* List all of them.
*
* @param Request $request
*
* @return JsonResponse]
*/
public function index(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budgets. Count it and split it.
$collection = $this->repository->getPiggyBanks();
$count = $collection->count();
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.piggy_banks.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($piggyBanks, new PiggyBankTransformer($this->parameters), 'piggy_banks');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List single resource.
*
* @param Request $request
* @param PiggyBank $piggyBank
*
* @return JsonResponse
*/
public function show(Request $request, PiggyBank $piggyBank): JsonResponse
{
$manager = new Manager();
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($piggyBank, new PiggyBankTransformer($this->parameters), 'piggy_banks');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Store new object.
*
* @param PiggyBankRequest $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function store(PiggyBankRequest $request): JsonResponse
{
$piggyBank = $this->repository->store($request->getAll());
if (null !== $piggyBank) {
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($piggyBank, new PiggyBankTransformer($this->parameters), 'piggy_banks');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
throw new FireflyException('Could not store new piggy bank.'); // @codeCoverageIgnore
}
/**
* @param PiggyBankRequest $request
* @param PiggyBank $piggyBank
*
* @return JsonResponse
*/
public function update(PiggyBankRequest $request, PiggyBank $piggyBank): JsonResponse
{
$piggyBank = $this->repository->update($piggyBank, $request->getAll());
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($piggyBank, new PiggyBankTransformer($this->parameters), 'piggy_banks');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@ -0,0 +1,157 @@
<?php
/**
* PreferencesController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\PreferenceRequest;
use FireflyIII\Models\Preference;
use FireflyIII\Transformers\PreferenceTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use League\Fractal\Manager;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
use Preferences;
/**
*
* Class PreferenceController
*/
class PreferenceController extends Controller
{
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
// todo add local repositories.
return $next($request);
}
);
}
/**
* List all of them.
*
* @param Request $request
*
* @return JsonResponse]
*/
public function index(Request $request): JsonResponse
{
/** @var User $user */
$user = auth()->user();
$available = [
'language', 'customFiscalYear', 'fiscalYearStart', 'currencyPreference',
'transaction_journal_optional_fields', 'frontPageAccounts', 'viewRange',
'listPageSize, twoFactorAuthEnabled',
];
$preferences = new Collection;
foreach ($available as $name) {
$pref = Preferences::getForUser($user, $name);
if (null !== $pref) {
$preferences->push($pref);
}
}
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($preferences, new PreferenceTransformer($this->parameters), 'preferences');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List single resource.
*
* @param Request $request
* @param Preference $preference
*
* @return JsonResponse
*/
public function show(Request $request, Preference $preference): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($preference, new PreferenceTransformer($this->parameters), 'preferences');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param PreferenceRequest $request
* @param Preference $preference
*
* @return JsonResponse
*/
public function update(PreferenceRequest $request, Preference $preference): JsonResponse
{
$data = $request->getAll();
$newValue = $data['data'];
switch ($preference->name) {
default:
break;
case 'transaction_journal_optional_fields':
case 'frontPageAccounts':
$newValue = explode(',', $data['data']);
break;
case 'listPageSize':
$newValue = (int)$data['data'];
break;
case 'customFiscalYear':
case 'twoFactorAuthEnabled':
$newValue = (int)$data['data'] === 1;
break;
}
$result = Preferences::set($preference->name, $newValue);
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($result, new PreferenceTransformer($this->parameters), 'preferences');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@ -0,0 +1,179 @@
<?php
/**
* RecurrenceController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\RecurrenceRequest;
use FireflyIII\Models\Recurrence;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use FireflyIII\Transformers\RecurrenceTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
*
* Class RecurrenceController
*/
class RecurrenceController extends Controller
{
/** @var RecurringRepositoryInterface */
private $repository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
/** @var RecurringRepositoryInterface repository */
$this->repository = app(RecurringRepositoryInterface::class);
$this->repository->setUser($user);
return $next($request);
}
);
}
/**
* Delete the resource.
*
* @param Recurrence $recurrence
*
* @return JsonResponse
*/
public function delete(Recurrence $recurrence): JsonResponse
{
$this->repository->destroy($recurrence);
return response()->json([], 204);
}
/**
* List all of them.
*
* @param Request $request
*
* @return JsonResponse]
*/
public function index(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budgets. Count it and split it.
$collection = $this->repository->getAll();
$count = $collection->count();
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.recurrences.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($piggyBanks, new RecurrenceTransformer($this->parameters), 'recurrences');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List single resource.
*
* @param Request $request
* @param Recurrence $recurrence
*
* @return JsonResponse
*/
public function show(Request $request, Recurrence $recurrence): JsonResponse
{
$manager = new Manager();
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($recurrence, new RecurrenceTransformer($this->parameters), 'recurrences');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Store new object.
*
* @param RecurrenceRequest $request
*
* @return JsonResponse
*/
public function store(RecurrenceRequest $request): JsonResponse
{
$recurrence = $this->repository->store($request->getAll());
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($recurrence, new RecurrenceTransformer($this->parameters), 'recurrences');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param RecurrenceRequest $request
* @param Recurrence $recurrence
*
* @return JsonResponse
*/
public function update(RecurrenceRequest $request, Recurrence $recurrence): JsonResponse
{
$data = $request->getAll();
//
$category = $this->repository->update($recurrence, $data);
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($category, new RecurrenceTransformer($this->parameters), 'recurrences');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@ -0,0 +1,173 @@
<?php
/**
* RuleController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\RuleRequest;
use FireflyIII\Models\Rule;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Transformers\RuleTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class RuleController
*/
class RuleController extends Controller
{
/** @var RuleRepositoryInterface */
private $ruleRepository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->ruleRepository = app(RuleRepositoryInterface::class);
$this->ruleRepository->setUser($user);
return $next($request);
}
);
}
/**
* Delete the resource.
*
* @param Rule $rule
*
* @return JsonResponse
*/
public function delete(Rule $rule): JsonResponse
{
$this->ruleRepository->destroy($rule);
return response()->json([], 204);
}
/**
* List all of them.
*
* @param Request $request
*
* @return JsonResponse]
*/
public function index(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budgets. Count it and split it.
$collection = $this->ruleRepository->getAll();
$count = $collection->count();
$rules = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($rules, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.piggy_banks.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($rules, new RuleTransformer($this->parameters), 'rules');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List single resource.
*
* @param Request $request
* @param Rule $rule
*
* @return JsonResponse
*/
public function show(Request $request, Rule $rule): JsonResponse
{
$manager = new Manager();
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($rule, new RuleTransformer($this->parameters), 'rules');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Store new object.
*
* @param Request $request
*
* @return JsonResponse
*/
public function store(RuleRequest $request): JsonResponse
{
$rule = $this->ruleRepository->store($request->getAll());
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($rule, new RuleTransformer($this->parameters), 'rules');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param RuleRequest $request
* @param Rule $rule
*
* @return JsonResponse
*/
public function update(RuleRequest $request, Rule $rule): JsonResponse
{
$rule = $this->ruleRepository->update($rule, $request->getAll());
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($rule, new RuleTransformer($this->parameters), 'rules');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@ -0,0 +1,171 @@
<?php
/**
* RuleGroupController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\RuleGroupRequest;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\Transformers\RuleGroupTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
class RuleGroupController extends Controller
{
/** @var RuleGroupRepositoryInterface */
private $ruleGroupRepository;
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->ruleGroupRepository = app(RuleGroupRepositoryInterface::class);
$this->ruleGroupRepository->setUser($user);
return $next($request);
}
);
}
/**
* Delete the resource.
*
* @param string $object
*
* @return JsonResponse
*/
public function delete(RuleGroup $ruleGroup): JsonResponse
{
$this->ruleGroupRepository->destroy($ruleGroup, null);
return response()->json([], 204);
}
/**
* List all of them.
*
* @param Request $request
*
* @return JsonResponse]
*/
public function index(Request $request): JsonResponse
{
// create some objects:
$manager = new Manager;
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of budgets. Count it and split it.
$collection = $this->ruleGroupRepository->get();
$count = $collection->count();
$ruleGroups = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($ruleGroups, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.rule_groups.index') . $this->buildParams());
// present to user.
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new FractalCollection($ruleGroups, new RuleGroupTransformer($this->parameters), 'rule_groups');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List single resource.
*
* @param Request $request
* @param RuleGroup $ruleGroup
*
* @return JsonResponse
*/
public function show(Request $request, RuleGroup $ruleGroup): JsonResponse
{
$manager = new Manager();
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($ruleGroup, new RuleGroupTransformer($this->parameters), 'rule_groups');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Store new object.
*
* @param RuleGroupRequest $request
*
* @return JsonResponse
*/
public function store(RuleGroupRequest $request): JsonResponse
{
$ruleGroup = $this->ruleGroupRepository->store($request->getAll());
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($ruleGroup, new RuleGroupTransformer($this->parameters), 'rule_groups');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param Request $request
* @param string $object
*
* @return JsonResponse
*/
public function update(RuleGroupRequest $request, RuleGroup $ruleGroup): JsonResponse
{
$ruleGroup = $this->ruleGroupRepository->update($ruleGroup, $request->getAll());
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($ruleGroup, new RuleGroupTransformer($this->parameters), 'rule_groups');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@ -40,7 +40,6 @@ use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Serializer\JsonApiSerializer;
use Log;
use Preferences;
/**
* Class TransactionController
@ -92,7 +91,7 @@ class TransactionController extends Controller
*/
public function index(Request $request)
{
$pageSize = (int)Preferences::getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// read type from URI
$type = $request->get('type') ?? 'default';
@ -136,17 +135,19 @@ class TransactionController extends Controller
/**
* @param Request $request
* @param Transaction $transaction
* @param string $include
*
* @return \Illuminate\Http\JsonResponse
*/
public function show(Request $request, Transaction $transaction)
public function show(Request $request, Transaction $transaction, string $include = null)
{
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
// add include parameter:
$include = $request->get('include') ?? '';
$include = $include ?? '';
$include = $request->get('include') ?? $include;
$manager->parseIncludes($include);
// collect transactions using the journal collector

View File

@ -36,7 +36,6 @@ use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
use Preferences;
/**
@ -94,7 +93,7 @@ class UserController extends Controller
public function index(Request $request)
{
// user preferences
$pageSize = (int)Preferences::getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// make manager
$manager = new Manager();

View File

@ -0,0 +1,92 @@
<?php
/**
* AttachmentRequest.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Models\Bill;
use FireflyIII\Models\ImportJob;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Rules\IsBase64;
use FireflyIII\Rules\IsValidAttachmentModel;
/**
* Class AttachmentRequest
*/
class AttachmentRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* @return array
*/
public function getAll(): array
{
return [
'filename' => $this->string('filename'),
'title' => $this->string('title'),
'notes' => $this->string('notes'),
'model' => $this->string('model'),
'model_id' => $this->integer('model_id'),
];
}
/**
* @return array
*/
public function rules(): array
{
$models = implode(
',', [
Bill::class,
ImportJob::class,
TransactionJournal::class,
]
);
$model = $this->string('model');
$rules = [
'filename' => 'required|between:1,255',
'title' => 'between:1,255',
'notes' => 'between:1,65000',
'model' => sprintf('required|in:%s', $models),
'model_id' => ['required', 'numeric', new IsValidAttachmentModel($model)],
];
switch ($this->method()) {
default:
break;
case 'PUT':
case 'PATCH':
unset($rules['model'], $rules['model_id']);
$rules['filename'] = 'between:1,255';
break;
}
return $rules;
}
}

View File

@ -0,0 +1,69 @@
<?php
/**
* AvailableBudgetRequest.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
/**
* Class AvailableBudgetRequest
*/
class AvailableBudgetRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* @return array
*/
public function getAll(): array
{
return [
'transaction_currency_id' => $this->integer('transaction_currency_id'),
'amount' => $this->string('amount'),
'start_date' => $this->date('start_date'),
'end_date' => $this->date('end_date'),
];
}
/**
* @return array
*/
public function rules(): array
{
$rules = [
'transaction_currency_id' => 'required|numeric|exists:transaction_currencies,id',
'amount' => 'required|numeric|more:0',
'start_date' => 'required|date|before:end_date',
'end_date' => 'required|date|after:start_date',
];
return $rules;
}
}

View File

@ -86,8 +86,8 @@ class BillRequest extends Request
break;
case 'PUT':
case 'PATCH':
$bill = $this->route()->parameter('bill');
$rules['name'] .= ',' . $bill->id;
$bill = $this->route()->parameter('bill');
$rules['name'] .= ',' . $bill->id;
break;
}

View File

@ -0,0 +1,77 @@
<?php
/**
* BudgetLimitRequest.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
/**
* Class BudgetLimitRequest
*/
class BudgetLimitRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* @return array
*/
public function getAll(): array
{
return [
'budget_id' => $this->integer('budget_id'),
'start_date' => $this->date('start_date'),
'end_date' => $this->date('end_date'),
'amount' => $this->string('amount'),
];
}
/**
* @return array
*/
public function rules(): array
{
$rules = [
'budget_id' => 'required|exists:budgets,id|belongsToUser:budgets,id',
'start_date' => 'required|before:end_date|date',
'end_date' => 'required|after:start_date|date',
'amount' => 'required|more:0',
];
switch ($this->method()) {
default:
break;
case 'PUT':
case 'PATCH':
$rules['budget_id'] = 'required|exists:budgets,id|belongsToUser:budgets,id';
break;
}
return $rules;
}
}

View File

@ -0,0 +1,76 @@
<?php
/**
* BudgetRequest.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Models\Budget;
/**
* Class BudgetRequest
*/
class BudgetRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* @return array
*/
public function getAll(): array
{
return [
'name' => $this->string('name'),
'active' => $this->boolean('active'),
'order' => 0,
];
}
/**
* @return array
*/
public function rules(): array
{
$rules = [
'name' => 'required|between:1,100|uniqueObjectForUser:budgets,name',
'active' => 'required|boolean',
];
switch ($this->method()) {
default:
break;
case 'PUT':
case 'PATCH':
/** @var Budget $budget */
$budget = $this->route()->parameter('budget');
$rules['name'] = sprintf('required|between:1,100|uniqueObjectForUser:budgets,name,%d', $budget->id);
break;
}
return $rules;
}
}

View File

@ -0,0 +1,75 @@
<?php
/**
* CategoryRequest.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Models\Category;
/**
* Class CategoryRequest
*/
class CategoryRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* @return array
*/
public function getAll(): array
{
return [
'name' => $this->string('name'),
'active' => $this->boolean('active'),
];
}
/**
* @return array
*/
public function rules(): array
{
$rules = [
'name' => 'required|between:1,100|uniqueObjectForUser:categories,name',
'active' => 'required|boolean',
];
switch ($this->method()) {
default:
break;
case 'PUT':
case 'PATCH':
/** @var Category $category */
$category = $this->route()->parameter('category');
$rules['name'] = sprintf('required|between:1,100|uniqueObjectForUser:categories,name,%d', $category->id);
break;
}
return $rules;
}
}

View File

@ -41,7 +41,7 @@ class CurrencyRequest extends Request
/**
* @return array
*/
public function getAll()
public function getAll(): array
{
return [
'name' => $this->string('name'),

View File

@ -0,0 +1,68 @@
<?php
/**
* JournalLinkRequest.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
/**
*
* Class JournalLinkRequest
*/
class JournalLinkRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* @return array
*/
public function getAll(): array
{
return [
'link_type_id' => $this->integer('link_type_id'),
'inward_id' => $this->integer('inward_id'),
'outward_id' => $this->integer('outward_id'),
'notes' => $this->string('notes'),
];
}
/**
* @return array
*/
public function rules(): array
{
return [
'link_type_id' => 'required|exists:link_types,id',
'inward_id' => 'required|belongsToUser:transaction_journals,id',
'outward_id' => 'required|belongsToUser:transaction_journals,id',
'notes' => 'between:0,65000',
];
}
}

View File

@ -0,0 +1,86 @@
<?php
/**
* LinkTypeRequest.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Models\LinkType;
use Illuminate\Validation\Rule;
/**
*
* Class LinkTypeRequest
*/
class LinkTypeRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* @return array
*/
public function getAll(): array
{
return [
'name' => $this->string('name'),
'outward' => $this->string('outward'),
'inward' => $this->string('inward'),
];
}
/**
* @return array
*/
public function rules(): array
{
$rules = [
'name' => 'required|unique:link_types,name|min:1',
'outward' => 'required|unique:link_types,outward|min:1|different:inward',
'inward' => 'required|unique:link_types,inward|min:1|different:outward',
];
// Rule::unique('users')->ignore($user->id),
switch ($this->method()) {
default:
break;
case 'PUT':
case 'PATCH':
/** @var LinkType $linkType */
$linkType = $this->route()->parameter('linkType');
$rules['name'] = ['required', Rule::unique('link_types', 'name')->ignore($linkType->id), 'min:1'];
$rules['outward'] = ['required', 'different:inward', Rule::unique('link_types', 'outward')->ignore($linkType->id), 'min:1'];
$rules['inward'] = ['required', 'different:outward', Rule::unique('link_types', 'inward')->ignore($linkType->id), 'min:1'];
break;
}
return $rules;
}
}

View File

@ -0,0 +1,90 @@
<?php
/**
* PiggyBankRequest.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Rules\IsAssetAccountId;
/**
*
* Class PiggyBankRequest
*/
class PiggyBankRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* @return array
*/
public function getAll(): array
{
return [
'name' => $this->string('name'),
'account_id' => $this->integer('account_id'),
'targetamount' => $this->string('target_amount'),
'current_amount' => $this->string('current_amount'),
'start_date' => $this->date('start_date'),
'target_date' => $this->date('target_date'),
'note' => $this->string('notes'),
];
}
/**
* @return array
*/
public function rules(): array
{
$rules = [
'name' => 'required|between:1,255|uniquePiggyBankForUser',
'account_id' => ['required', 'belongsToUser:accounts', new IsAssetAccountId],
'target_amount' => 'required|numeric|more:0',
'current_amount' => 'numeric|more:0|lte:target_amount',
'start_date' => 'date|nullable',
'target_date' => 'date|nullable',
'notes' => 'max:65000',
];
switch ($this->method()) {
default:
break;
case 'PUT':
case 'PATCH':
/** @var PiggyBank $piggyBank */
$piggyBank = $this->route()->parameter('piggyBank');
$rules['name'] = 'required|between:1,255|uniquePiggyBankForUser:' . $piggyBank->id;
break;
}
return $rules;
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* PreferenceRequest.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
/**
*
* Class PreferenceRequest
*/
class PreferenceRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
public function getAll(): array
{
return [
'data' => $this->get('data'),
];
}
public function rules(): array
{
return [
'data' => 'required|between:1,65000',
];
}
}

View File

@ -0,0 +1,482 @@
<?php
/**
* RecurrenceRequest.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use Carbon\Carbon;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Rules\BelongsUser;
use Illuminate\Validation\Validator;
use InvalidArgumentException;
use Log;
/**
* Class RecurrenceRequest
*/
class RecurrenceRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* @return array
*/
public function getAll(): array
{
$return = [
'recurrence' => [
'type' => $this->string('type'),
'title' => $this->string('title'),
'description' => $this->string('description'),
'first_date' => $this->date('first_date'),
'repeat_until' => $this->date('repeat_until'),
'repetitions' => $this->integer('nr_of_repetitions'),
'apply_rules' => $this->boolean('apply_rules'),
'active' => $this->boolean('active'),
],
'meta' => [
'piggy_bank_id' => $this->integer('piggy_bank_id'),
'piggy_bank_name' => $this->string('piggy_bank_name'),
'tags' => explode(',', $this->string('tags')),
],
'transactions' => [],
'repetitions' => [],
];
// repetition data:
/** @var array $repetitions */
$repetitions = $this->get('repetitions');
/** @var array $repetition */
foreach ($repetitions as $repetition) {
$return['repetitions'][] = [
'type' => $repetition['type'],
'moment' => $repetition['moment'],
'skip' => (int)$repetition['skip'],
'weekend' => (int)$repetition['weekend'],
];
}
// transaction data:
/** @var array $transactions */
$transactions = $this->get('transactions');
/** @var array $transaction */
foreach ($transactions as $transaction) {
$return['transactions'][] = [
'amount' => $transaction['amount'],
'currency_id' => isset($transaction['currency_id']) ? (int)$transaction['currency_id'] : null,
'currency_code' => $transaction['currency_code'] ?? null,
'foreign_amount' => $transaction['foreign_amount'] ?? null,
'foreign_currency_id' => isset($transaction['foreign_currency_id']) ? (int)$transaction['foreign_currency_id'] : null,
'foreign_currency_code' => $transaction['foreign_currency_code'] ?? null,
'budget_id' => isset($transaction['budget_id']) ? (int)$transaction['budget_id'] : null,
'budget_name' => $transaction['budget_name'] ?? null,
'category_id' => isset($transaction['category_id']) ? (int)$transaction['category_id'] : null,
'category_name' => $transaction['category_name'] ?? null,
'source_id' => isset($transaction['source_id']) ? (int)$transaction['source_id'] : null,
'source_name' => isset($transaction['source_name']) ? (string)$transaction['source_name'] : null,
'destination_id' => isset($transaction['destination_id']) ? (int)$transaction['destination_id'] : null,
'destination_name' => isset($transaction['destination_name']) ? (string)$transaction['destination_name'] : null,
'description' => $transaction['description'],
];
}
return $return;
}
/**
* @return array
*/
public function rules(): array
{
$today = new Carbon;
$today->addDay();
return [
'type' => 'required|in:withdrawal,transfer,deposit',
'title' => 'required|between:1,255|uniqueObjectForUser:recurrences,title',
'description' => 'between:1,65000',
'first_date' => sprintf('required|date|after:%s', $today->format('Y-m-d')),
'repeat_until' => sprintf('date|after:%s', $today->format('Y-m-d')),
'nr_of_repetitions' => 'numeric|between:1,31',
'apply_rules' => 'required|boolean',
'active' => 'required|boolean',
// rules for meta values:
'tags' => 'between:1,64000',
'piggy_bank_id' => 'numeric',
// rules for repetitions.
'repetitions.*.type' => 'required|in:daily,weekly,ndom,monthly,yearly',
'repetitions.*.moment' => 'between:0,10',
'repetitions.*.skip' => 'required|numeric|between:0,31',
'repetitions.*.weekend' => 'required|numeric|min:1|max:4',
// rules for transactions.
'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id|required_without:transactions.*.currency_code',
'transactions.*.currency_code' => 'min:3|max:3|exists:transaction_currencies,code|required_without:transactions.*.currency_id',
'transactions.*.foreign_amount' => 'numeric|more:0',
'transactions.*.foreign_currency_id' => 'numeric|exists:transaction_currencies,id',
'transactions.*.foreign_currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
'transactions.*.budget_id' => ['mustExist:budgets,id', new BelongsUser],
'transactions.*.category_name' => 'between:1,255|nullable',
'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUser],
'transactions.*.source_name' => 'between:1,255|nullable',
'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUser],
'transactions.*.destination_name' => 'between:1,255|nullable',
'transactions.*.amount' => 'required|numeric|more:0',
'transactions.*.description' => 'required|between:1,255',
];
}
/**
* Configure the validator instance.
*
* @param Validator $validator
*
* @return void
*/
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator) {
$this->atLeastOneTransaction($validator);
$this->atLeastOneRepetition($validator);
$this->validRepeatsUntil($validator);
$this->validRepetitionMoment($validator);
$this->foreignCurrencyInformation($validator);
$this->validateAccountInformation($validator);
}
);
}
/**
* Throws an error when this asset account is invalid.
*
* @noinspection MoreThanThreeArgumentsInspection
*
* @param Validator $validator
* @param int|null $accountId
* @param null|string $accountName
* @param string $idField
* @param string $nameField
*
* @return null|Account
*/
protected function assetAccountExists(Validator $validator, ?int $accountId, ?string $accountName, string $idField, string $nameField): ?Account
{
$accountId = (int)$accountId;
$accountName = (string)$accountName;
// both empty? hard exit.
if ($accountId < 1 && '' === $accountName) {
$validator->errors()->add($idField, trans('validation.filled', ['attribute' => $idField]));
return null;
}
// ID belongs to user and is asset account:
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user());
$set = $repository->getAccountsById([$accountId]);
Log::debug(sprintf('Count of accounts found by ID %d is: %d', $accountId, $set->count()));
if ($set->count() === 1) {
/** @var Account $first */
$first = $set->first();
if ($first->accountType->type !== AccountType::ASSET) {
$validator->errors()->add($idField, trans('validation.belongs_user'));
return null;
}
// we ignore the account name at this point.
return $first;
}
$account = $repository->findByName($accountName, [AccountType::ASSET]);
if (null === $account) {
$validator->errors()->add($nameField, trans('validation.belongs_user'));
return null;
}
return $account;
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneRepetition(Validator $validator): void
{
$data = $validator->getData();
$repetitions = $data['repetitions'] ?? [];
// need at least one transaction
if (\count($repetitions) === 0) {
$validator->errors()->add('description', trans('validation.at_least_one_repetition'));
}
}
/**
* Adds an error to the validator when there are no transactions in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneTransaction(Validator $validator): void
{
$data = $validator->getData();
$transactions = $data['transactions'] ?? [];
// need at least one transaction
if (\count($transactions) === 0) {
$validator->errors()->add('description', trans('validation.at_least_one_transaction'));
}
}
/**
* TODO can be made a rule?
* If the transactions contain foreign amounts, there must also be foreign currency information.
*
* @param Validator $validator
*/
protected function foreignCurrencyInformation(Validator $validator): void
{
$data = $validator->getData();
$transactions = $data['transactions'] ?? [];
foreach ($transactions as $index => $transaction) {
// must have currency info.
if (isset($transaction['foreign_amount'])
&& !(isset($transaction['foreign_currency_id'])
|| isset($transaction['foreign_currency_code']))) {
$validator->errors()->add(
'transactions.' . $index . '.foreign_amount',
trans('validation.require_currency_info')
);
}
}
}
/**
* Throws an error when the given opposing account (of type $type) is invalid.
* Empty data is allowed, system will default to cash.
*
* @noinspection MoreThanThreeArgumentsInspection
*
* @param Validator $validator
* @param string $type
* @param int|null $accountId
* @param null|string $accountName
* @param string $idField
*
* @return null|Account
*/
protected function opposingAccountExists(Validator $validator, string $type, ?int $accountId, ?string $accountName, string $idField): ?Account
{
$accountId = (int)$accountId;
$accountName = (string)$accountName;
// both empty? done!
if ($accountId < 1 && \strlen($accountName) === 0) {
return null;
}
if ($accountId !== 0) {
// ID belongs to user and is $type account:
/** @var AccountRepositoryInterface $repository */
$repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user());
$set = $repository->getAccountsById([$accountId]);
if ($set->count() === 1) {
/** @var Account $first */
$first = $set->first();
if ($first->accountType->type !== $type) {
$validator->errors()->add($idField, trans('validation.belongs_user'));
return null;
}
// we ignore the account name at this point.
return $first;
}
}
// not having an opposing account by this name is NOT a problem.
return null;
}
/**
* TODO can be a rule?
*
* Validates the given account information. Switches on given transaction type.
*
* @param Validator $validator
*/
protected function validateAccountInformation(Validator $validator): void
{
$data = $validator->getData();
$transactions = $data['transactions'] ?? [];
$idField = 'description';
$transactionType = $data['type'] ?? 'false';
foreach ($transactions as $index => $transaction) {
$sourceId = isset($transaction['source_id']) ? (int)$transaction['source_id'] : null;
$sourceName = $transaction['source_name'] ?? null;
$destinationId = isset($transaction['destination_id']) ? (int)$transaction['destination_id'] : null;
$destinationName = $transaction['destination_name'] ?? null;
$sourceAccount = null;
$destinationAccount = null;
switch ($transactionType) {
case 'withdrawal':
$idField = 'transactions.' . $index . '.source_id';
$nameField = 'transactions.' . $index . '.source_name';
$sourceAccount = $this->assetAccountExists($validator, $sourceId, $sourceName, $idField, $nameField);
$idField = 'transactions.' . $index . '.destination_id';
$destinationAccount = $this->opposingAccountExists($validator, AccountType::EXPENSE, $destinationId, $destinationName, $idField);
break;
case 'deposit':
$idField = 'transactions.' . $index . '.source_id';
$sourceAccount = $this->opposingAccountExists($validator, AccountType::REVENUE, $sourceId, $sourceName, $idField);
$idField = 'transactions.' . $index . '.destination_id';
$nameField = 'transactions.' . $index . '.destination_name';
$destinationAccount = $this->assetAccountExists($validator, $destinationId, $destinationName, $idField, $nameField);
break;
case 'transfer':
$idField = 'transactions.' . $index . '.source_id';
$nameField = 'transactions.' . $index . '.source_name';
$sourceAccount = $this->assetAccountExists($validator, $sourceId, $sourceName, $idField, $nameField);
$idField = 'transactions.' . $index . '.destination_id';
$nameField = 'transactions.' . $index . '.destination_name';
$destinationAccount = $this->assetAccountExists($validator, $destinationId, $destinationName, $idField, $nameField);
break;
default:
$validator->errors()->add($idField, trans('validation.invalid_account_info'));
return;
}
// add some errors in case of same account submitted:
if (null !== $sourceAccount && null !== $destinationAccount && $sourceAccount->id === $destinationAccount->id) {
$validator->errors()->add($idField, trans('validation.source_equals_destination'));
}
}
}
/**
* @param Validator $validator
*/
private function validRepeatsUntil(Validator $validator): void
{
$data = $validator->getData();
$repetitions = $data['nr_of_repetitions'] ?? null;
$repeatUntil = $data['repeat_until'] ?? null;
if (null !== $repetitions && null !== $repeatUntil) {
// expect a date OR count:
$validator->errors()->add('repeat_until', trans('validation.require_repeat_until'));
$validator->errors()->add('nr_of_repetitions', trans('validation.require_repeat_until'));
return;
}
}
/**
* TODO merge this in a rule somehow.
*
* @param Validator $validator
*/
private function validRepetitionMoment(Validator $validator): void
{
$data = $validator->getData();
$repetitions = $data['repetitions'] ?? [];
/**
* @var int $index
* @var array $repetition
*/
foreach ($repetitions as $index => $repetition) {
switch ($repetition['type']) {
default:
$validator->errors()->add(sprintf('repetitions.%d.type', $index), trans('validation.valid_recurrence_rep_type'));
return;
case 'daily':
if ('' !== (string)$repetition['moment']) {
$validator->errors()->add(sprintf('repetitions.%d.moment', $index), trans('validation.valid_recurrence_rep_moment'));
}
return;
case 'monthly':
$dayOfMonth = (int)$repetition['moment'];
if ($dayOfMonth < 1 || $dayOfMonth > 31) {
$validator->errors()->add(sprintf('repetitions.%d.moment', $index), trans('validation.valid_recurrence_rep_moment'));
}
return;
case 'ndom':
$parameters = explode(',', $repetition['moment']);
if (\count($parameters) !== 2) {
$validator->errors()->add(sprintf('repetitions.%d.moment', $index), trans('validation.valid_recurrence_rep_moment'));
return;
}
$nthDay = (int)($parameters[0] ?? 0.0);
$dayOfWeek = (int)($parameters[1] ?? 0.0);
if ($nthDay < 1 || $nthDay > 5) {
$validator->errors()->add(sprintf('repetitions.%d.moment', $index), trans('validation.valid_recurrence_rep_moment'));
return;
}
if ($dayOfWeek < 1 || $dayOfWeek > 7) {
$validator->errors()->add(sprintf('repetitions.%d.moment', $index), trans('validation.valid_recurrence_rep_moment'));
return;
}
return;
case 'weekly':
$dayOfWeek = (int)$repetition['moment'];
if ($dayOfWeek < 1 || $dayOfWeek > 7) {
$validator->errors()->add(sprintf('repetitions.%d.moment', $index), trans('validation.valid_recurrence_rep_moment'));
return;
}
break;
case 'yearly':
try {
Carbon::createFromFormat('Y-m-d', $repetition['moment']);
} catch (InvalidArgumentException $e) {
$validator->errors()->add(sprintf('repetitions.%d.moment', $index), trans('validation.valid_recurrence_rep_moment'));
return;
}
}
}
}
}

View File

@ -0,0 +1,79 @@
<?php
/**
* RuleGroupRequest.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Models\RuleGroup;
/**
*
* Class RuleGroupRequest
*/
class RuleGroupRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* @return array
*/
public function getAll(): array
{
return [
'title' => $this->string('title'),
'description' => $this->string('description'),
'active' => $this->boolean('active'),
];
}
/**
* @return array
*/
public function rules(): array
{
$rules = [
'title' => 'required|between:1,100|uniqueObjectForUser:rule_groups,title',
'description' => 'between:1,5000|nullable',
'active' => 'required|boolean',
];
switch ($this->method()) {
default:
break;
case 'PUT':
case 'PATCH':
/** @var RuleGroup $ruleGroup */
$ruleGroup = $this->route()->parameter('ruleGroup');
$rules['title'] = 'required|between:1,100|uniqueObjectForUser:rule_groups,title,' . $ruleGroup->id;
break;
}
return $rules;
}
}

View File

@ -0,0 +1,156 @@
<?php
/**
* RuleRequest.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use Illuminate\Validation\Validator;
/**
* Class RuleRequest
*/
class RuleRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* @return array
*/
public function getAll(): array
{
$data = [
'title' => $this->string('title'),
'description' => $this->string('description'),
'rule_group_id' => $this->integer('rule_group_id'),
'rule_group_title' => $this->string('rule_group_title'),
'trigger' => $this->string('trigger'),
'strict' => $this->boolean('strict'),
'stop-processing' => $this->boolean('stop_processing'),
'active' => $this->boolean('active'),
'rule-triggers' => [],
'rule-actions' => [],
];
foreach ($this->get('rule-triggers') as $trigger) {
$data['rule-triggers'][] = [
'name' => $trigger['name'],
'value' => $trigger['value'],
'stop-processing' => (int)($trigger['stop-processing'] ?? 0) === 1,
];
}
foreach ($this->get('rule-actions') as $action) {
$data['rule-actions'][] = [
'name' => $action['name'],
'value' => $action['value'],
'stop-processing' => (int)($action['stop-processing'] ?? 0) === 1,
];
}
return $data;
}
/**
* @return array
*/
public function rules(): array
{
$validTriggers = array_keys(config('firefly.rule-triggers'));
$validActions = array_keys(config('firefly.rule-actions'));
// some actions require text:
$contextActions = implode(',', config('firefly.rule-actions-text'));
$rules = [
'title' => 'required|between:1,100|uniqueObjectForUser:rules,title',
'description' => 'between:1,5000|nullable',
'rule_group_id' => 'required|belongsToUser:rule_groups|required_without:rule_group_title',
'rule_group_title' => 'nullable|between:1,255|required_without:rule_group_id|belongsToUser:rule_groups,title',
'trigger' => 'required|in:store-journal,update-journal',
'rule-triggers.*.name' => 'required|in:' . implode(',', $validTriggers),
'rule-triggers.*.stop-processing' => 'boolean',
'rule-triggers.*.value' => 'required|min:1|ruleTriggerValue', //
'rule-actions.*.name' => 'required|in:' . implode(',', $validActions),
'rule-actions.*.value' => 'required_if:rule-action.*.type,' . $contextActions . '|ruleActionValue',
'rule-actions.*.stop-processing' => 'boolean',
'strict' => 'required|boolean',
'stop_processing' => 'required|boolean',
'active' => 'required|boolean',
];
return $rules;
}
/**
* Configure the validator instance.
*
* @param Validator $validator
*
* @return void
*/
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator) {
$this->atLeastOneTrigger($validator);
$this->atLeastOneAction($validator);
}
);
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneAction(Validator $validator): void
{
$data = $validator->getData();
$repetitions = $data['rule-actions'] ?? [];
// need at least one transaction
if (\count($repetitions) === 0) {
$validator->errors()->add('title', trans('validation.at_least_one_action'));
}
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneTrigger(Validator $validator): void
{
$data = $validator->getData();
$repetitions = $data['rule-triggers'] ?? [];
// need at least one transaction
if (\count($repetitions) === 0) {
$validator->errors()->add('title', trans('validation.at_least_one_trigger'));
}
}
}

View File

@ -188,6 +188,8 @@ class TransactionRequest extends Request
/**
* Throws an error when this asset account is invalid.
*
* @noinspection MoreThanThreeArgumentsInspection
*
* @param Validator $validator
* @param int|null $accountId
* @param null|string $accountName
@ -256,7 +258,7 @@ class TransactionRequest extends Request
*
* @param Validator $validator
*/
protected function checkValidDescriptions(Validator $validator)
protected function checkValidDescriptions(Validator $validator): void
{
$data = $validator->getData();
$transactions = $data['transactions'] ?? [];
@ -317,6 +319,8 @@ class TransactionRequest extends Request
}
/**
* TODO can be made a rule?
*
* If the transactions contain foreign amounts, there must also be foreign currency information.
*
* @param Validator $validator
@ -342,6 +346,8 @@ class TransactionRequest extends Request
* Throws an error when the given opposing account (of type $type) is invalid.
* Empty data is allowed, system will default to cash.
*
* @noinspection MoreThanThreeArgumentsInspection
*
* @param Validator $validator
* @param string $type
* @param int|null $accountId
@ -454,7 +460,7 @@ class TransactionRequest extends Request
*
* @throws FireflyException
*/
protected function validateSplitAccounts(Validator $validator)
protected function validateSplitAccounts(Validator $validator): void
{
$data = $validator->getData();
$count = isset($data['transactions']) ? \count($data['transactions']) : 0;

View File

@ -184,7 +184,7 @@ class UpgradeDatabase extends Command
]
);
}
if($bill->amount_max === $bill->amount_min) {
if ($bill->amount_max === $bill->amount_min) {
RuleTrigger::create(
[
'rule_id' => $rule->id,

View File

@ -90,6 +90,7 @@ class VerifyDatabase extends Command
$this->createAccessTokens();
$this->fixDoubleAmounts();
$this->fixBadMeta();
$this->removeBills();
}
/**
@ -164,7 +165,8 @@ class VerifyDatabase extends Command
if (isset($results[$key]) && $results[$key] !== $category) {
$this->error(
sprintf(
'Transaction #%d referred to the wrong category. Was category #%d but is fixed to be category #%d.', $obj->transaction_journal_id, $category, $results[$key]
'Transaction #%d referred to the wrong category. Was category #%d but is fixed to be category #%d.', $obj->transaction_journal_id,
$category, $results[$key]
)
);
DB::table('category_transaction')->where('id', $obj->ct_id)->update(['category_id' => $results[$key]]);
@ -184,14 +186,15 @@ class VerifyDatabase extends Command
->get(['transactions.id', 'transaction_journal_id', 'identifier', 'budget_transaction.budget_id', 'budget_transaction.id as ct_id']);
$results = [];
foreach ($set as $obj) {
$key = $obj->transaction_journal_id . '-' . $obj->identifier;
$key = $obj->transaction_journal_id . '-' . $obj->identifier;
$budget = (int)$obj->budget_id;
// value exists and is not budget:
if (isset($results[$key]) && $results[$key] !== $budget) {
$this->error(
sprintf(
'Transaction #%d referred to the wrong budget. Was budget #%d but is fixed to be budget #%d.', $obj->transaction_journal_id, $budget, $results[$key]
'Transaction #%d referred to the wrong budget. Was budget #%d but is fixed to be budget #%d.', $obj->transaction_journal_id, $budget,
$results[$key]
)
);
DB::table('budget_transaction')->where('id', $obj->ct_id)->update(['budget_id' => $results[$key]]);
@ -253,6 +256,23 @@ class VerifyDatabase extends Command
}
}
/**
*
*/
private function removeBills(): void
{
/** @var TransactionType $withdrawal */
$withdrawal = TransactionType::where('type', TransactionType::WITHDRAWAL)->first();
$journals = TransactionJournal::whereNotNull('bill_id')
->where('transaction_type_id', '!=', $withdrawal->id)->get();
/** @var TransactionJournal $journal */
foreach ($journals as $journal) {
$this->line(sprintf('Transaction journal #%d should not be linked to bill #%d.', $journal->id, $journal->bill_id));
$journal->bill_id = null;
$journal->save();
}
}
/**
* Eeport (and fix) piggy banks. Make sure there are only transfers linked to piggy bank events.
*/

View File

@ -24,11 +24,13 @@ declare(strict_types=1);
namespace FireflyIII\Console;
use Carbon\Carbon;
use FireflyIII\Jobs\CreateRecurringTransactions;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
/**
* File to make sure commnds work.
* File to make sure commands work.
*/
class Kernel extends ConsoleKernel
{
@ -44,7 +46,7 @@ class Kernel extends ConsoleKernel
/**
* Register the commands for the application.
*/
protected function commands()
protected function commands(): void
{
$this->load(__DIR__ . '/Commands');
@ -55,10 +57,9 @@ class Kernel extends ConsoleKernel
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
protected function schedule(Schedule $schedule)
protected function schedule(Schedule $schedule): void
{
$schedule->job(new CreateRecurringTransactions(new Carbon))->daily();
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace FireflyIII\Events;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Collection;
use Log;
/**
* Class RequestedReportOnJournals
*/
class RequestedReportOnJournals
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/** @var Collection */
public $journals;
/** @var int */
public $userId;
/**
* Create a new event instance.
*
* @param int $userId
* @param Collection $journals
*/
public function __construct(int $userId, Collection $journals)
{
Log::debug('In event RequestedReportOnJournals.');
$this->userId = $userId;
$this->journals = $journals;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}

View File

@ -132,20 +132,15 @@ class Handler extends ExceptionHandler
$doMailError = env('SEND_ERROR_MESSAGE', true);
if (
// if the user wants us to mail:
$doMailError === true &&
((
$doMailError === true
&& (
// and if is one of these error instances
$exception instanceof FireflyException
|| $exception instanceof ErrorException
|| $exception instanceof OAuthServerException
$exception instanceof FireflyException
|| $exception instanceof ErrorException
|| $exception instanceof OAuthServerException
)
|| (
// or this one, but it's a JSON exception.
$exception instanceof AuthenticationException
&& Request::expectsJson() === true
))
) {
)
) {
// then, send email
$userData = [
'id' => 0,

View File

@ -36,12 +36,12 @@ use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\ExportJob;
use FireflyIII\Models\Note;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
use Storage;
use ZipArchive;
use FireflyIII\Models\TransactionJournal;
/**
* Class ExpandedProcessor.

View File

@ -0,0 +1,79 @@
<?php
/**
* AttachmentFactory.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Factory;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Note;
use FireflyIII\User;
/**
* Class AttachmentFactory
*/
class AttachmentFactory
{
/** @var User */
private $user;
/**
* @param array $data
*
* @return Attachment|null
*/
public function create(array $data): ?Attachment
{
// create attachment:
$attachment = Attachment::create(
[
'user_id' => $this->user->id,
'attachable_id' => $data['model_id'],
'attachable_type' => $data['model'],
'md5' => '',
'filename' => $data['filename'],
'title' => '' === $data['title'] ? null : $data['title'],
'description' => null,
'mime' => '',
'size' => 0,
'uploaded' => 0,
]
);
$notes = (string)($data['notes'] ?? '');
if ('' !== $notes) {
$note = new Note;
$note->noteable()->associate($attachment);
$note->text = $notes;
$note->save();
}
return $attachment;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
}

View File

@ -58,8 +58,8 @@ class BillFactory
'date' => $data['date'],
'repeat_freq' => $data['repeat_freq'],
'skip' => $data['skip'],
'automatch' => true,
'active' => $data['active'],
'automatch' => $data['automatch'] ?? true,
'active' => $data['active'] ?? true,
]
);

View File

@ -72,7 +72,7 @@ class CategoryFactory
Log::debug(sprintf('Going to find category with ID %d and name "%s"', $categoryId, $categoryName));
if (\strlen($categoryName) === 0 && $categoryId === 0) {
if ('' === $categoryName && $categoryId === 0) {
return null;
}
// first by ID:

View File

@ -0,0 +1,91 @@
<?php
/**
* RecurrenceFactory.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Factory;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Recurrence;
use FireflyIII\Services\Internal\Support\RecurringTransactionTrait;
use FireflyIII\Services\Internal\Support\TransactionServiceTrait;
use FireflyIII\Services\Internal\Support\TransactionTypeTrait;
use FireflyIII\User;
use Log;
/**
* Class RecurrenceFactory
*/
class RecurrenceFactory
{
use TransactionTypeTrait, TransactionServiceTrait, RecurringTransactionTrait;
/** @var User */
private $user;
/**
* @param array $data
*
* @return Recurrence
*/
public function create(array $data): ?Recurrence
{
try {
$type = $this->findTransactionType(ucfirst($data['recurrence']['type']));
} catch (FireflyException $e) {
Log::error($e->getMessage());
return null;
}
$repetitions = (int)$data['recurrence']['repetitions'];
$recurrence = new Recurrence(
[
'user_id' => $this->user->id,
'transaction_type_id' => $type->id,
'title' => $data['recurrence']['title'],
'description' => $data['recurrence']['description'],
'first_date' => $data['recurrence']['first_date']->format('Y-m-d'),
'repeat_until' => $repetitions > 0 ? null : $data['recurrence']['repeat_until'],
'latest_date' => null,
'repetitions' => $data['recurrence']['repetitions'],
'apply_rules' => $data['recurrence']['apply_rules'],
'active' => $data['recurrence']['active'],
]
);
$recurrence->save();
$this->updateMetaData($recurrence, $data);
$this->createRepetitions($recurrence, $data['repetitions'] ?? []);
$this->createTransactions($recurrence, $data['transactions'] ?? []);
return $recurrence;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
}

View File

@ -71,6 +71,7 @@ class TransactionCurrencyFactory
if ('' === $currencyCode && $currencyId === 0) {
Log::warning('Cannot find anything on empty currency code and empty currency ID!');
return null;
}

View File

@ -26,6 +26,7 @@ namespace FireflyIII\Factory;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
@ -56,6 +57,7 @@ class TransactionFactory
$currencyId = $data['currency_id'] ?? null;
$currencyId = isset($data['currency']) ? $data['currency']->id : $currencyId;
if ('' === $data['amount']) {
Log::error('Empty string in data.', $data);
throw new FireflyException('Amount is an empty string, which Firefly III cannot handle. Apologies.'); // @codeCoverageIgnore
}
if (null === $currencyId) {
@ -96,14 +98,27 @@ class TransactionFactory
$description = $journal->description === $data['description'] ? null : $data['description'];
// type of source account depends on journal type:
$sourceType = $this->accountType($journal, 'source');
$sourceType = $this->accountType($journal, 'source');
Log::debug(sprintf('Expect source account to be of type %s', $sourceType));
$sourceAccount = $this->findAccount($sourceType, $data['source_id'], $data['source_name']);
// same for destination account:
$destinationType = $this->accountType($journal, 'destination');
$destinationType = $this->accountType($journal, 'destination');
Log::debug(sprintf('Expect source destination to be of type %s', $destinationType));
$destinationAccount = $this->findAccount($destinationType, $data['destination_id'], $data['destination_name']);
Log::debug(sprintf('Source type is "%s", destination type is "%s"', $sourceAccount->accountType->type, $destinationAccount->accountType->type));
// throw big fat error when source type === dest type
if ($sourceAccount->accountType->type === $destinationAccount->accountType->type
&& ($journal->transactionType->type !== TransactionType::TRANSFER
&& $journal->transactionType->type !== TransactionType::RECONCILIATION)
) {
throw new FireflyException(sprintf('Source and destination account cannot be both of the type "%s"', $destinationAccount->accountType->type));
}
if ($sourceAccount->accountType->type !== AccountType::ASSET && $destinationAccount->accountType->type !== AccountType::ASSET) {
throw new FireflyException('At least one of the accounts must be an asset account.');
}
// first make a "negative" (source) transaction based on the data in the array.
$source = $this->create(
[

View File

@ -26,8 +26,8 @@ namespace FireflyIII\Factory;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Services\Internal\Support\JournalServiceTrait;
use FireflyIII\Services\Internal\Support\TransactionTypeTrait;
use FireflyIII\User;
use Log;
@ -36,7 +36,7 @@ use Log;
*/
class TransactionJournalFactory
{
use JournalServiceTrait;
use JournalServiceTrait, TransactionTypeTrait;
/** @var User */
private $user;
@ -53,7 +53,7 @@ class TransactionJournalFactory
$type = $this->findTransactionType($data['type']);
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($this->user);
Log::debug(sprintf('Going to store a %s', $type->type));
$journal = TransactionJournal::create(
$journal = TransactionJournal::create(
[
'user_id' => $data['user'],
'transaction_type_id' => $type->id,
@ -67,6 +67,10 @@ class TransactionJournalFactory
]
);
if (isset($data['transactions'][0]['amount']) && '' === $data['transactions'][0]['amount']) {
Log::error('Empty amount in data', $data);
}
// store basic transactions:
/** @var TransactionFactory $factory */
$factory = app(TransactionFactory::class);
@ -95,13 +99,17 @@ class TransactionJournalFactory
// store date meta fields (if present):
$fields = ['sepa-cc', 'sepa-ct-op', 'sepa-ct-id', 'sepa-db', 'sepa-country', 'sepa-ep', 'sepa-ci', 'interest_date', 'book_date', 'process_date',
'due_date', 'payment_date', 'invoice_date', 'internal_reference', 'bunq_payment_id', 'importHash','importHashV2', 'external_id'];
'due_date', 'recurrence_id', 'payment_date', 'invoice_date', 'internal_reference', 'bunq_payment_id', 'importHash', 'importHashV2',
'external_id'];
foreach ($fields as $field) {
$this->storeMeta($journal, $data, $field);
}
Log::debug('End of TransactionJournalFactory::create()');
// invalidate cache.
app('preferences')->mark();
return $journal;
}
@ -133,25 +141,4 @@ class TransactionJournalFactory
}
}
/**
* Get the transaction type. Since this is mandatory, will throw an exception when nothing comes up. Will always
* use TransactionType repository.
*
* @param string $type
*
* @return TransactionType
* @throws FireflyException
*/
protected function findTransactionType(string $type): TransactionType
{
$factory = app(TransactionTypeFactory::class);
$transactionType = $factory->find($type);
if (null === $transactionType) {
Log::error(sprintf('Could not find transaction type for "%s"', $type)); // @codeCoverageIgnore
throw new FireflyException(sprintf('Could not find transaction type for "%s"', $type)); // @codeCoverageIgnore
}
return $transactionType;
}
}

View File

@ -90,7 +90,9 @@ class ChartJsGenerator implements GeneratorInterface
if (isset($set['currency_symbol'])) {
$currentSet['currency_symbol'] = $set['currency_symbol'];
}
if(isset($set['backgroundColor'])) {
$currentSet['backgroundColor'] = $set['backgroundColor'];
}
$chartData['datasets'][] = $currentSet;
}

View File

@ -28,7 +28,6 @@ use Exception;
use FireflyIII\Mail\AccessTokenCreatedMail;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use Laravel\Passport\Events\AccessTokenCreated;
use Laravel\Passport\Token;
use Log;
use Mail;
use Request;

View File

@ -0,0 +1,73 @@
<?php
/**
* AutomationHandler.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Handlers\Events;
use Exception;
use FireflyIII\Events\RequestedReportOnJournals;
use FireflyIII\Mail\ReportNewJournalsMail;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use Log;
use Mail;
/**
* Class AutomationHandler
*/
class AutomationHandler
{
/**
* @param RequestedReportOnJournals $event
*
* @return bool
*/
public function reportJournals(RequestedReportOnJournals $event): bool
{
Log::debug('In reportJournals.');
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
$user = $repository->findNull($event->userId);
if (null === $user) {
Log::debug('User is NULL');
return true;
}
if ($event->journals->count() === 0) {
Log::debug('No journals.');
return true;
}
try {
Log::debug('Trying to mail...');
Mail::to($user->email)->send(new ReportNewJournalsMail($user->email, '127.0.0.1', $event->journals));
// @codeCoverageIgnoreStart
} catch (Exception $e) {
Log::error($e->getMessage());
}
Log::debug('Done!');
// @codeCoverageIgnoreEnd
return true;
}
}

View File

@ -108,6 +108,27 @@ class UserEventHandler
return true;
}
/**
* @param Login $event
*
* @return bool
*/
public function demoUserBackToEnglish(Login $event): bool
{
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
/** @var User $user */
$user = $event->user;
if ($repository->hasRole($user, 'demo')) {
// set user back to English.
app('preferences')->setForUser($user, 'language', 'en_US');
app('preferences')->mark();
}
return true;
}
/**
* @param UserChangedEmail $event
*

View File

@ -41,7 +41,7 @@ class VersionCheckEventHandler
/**
* @param RequestedVersionCheckStatus $event
*/
public function checkForUpdates(RequestedVersionCheckStatus $event)
public function checkForUpdates(RequestedVersionCheckStatus $event): void
{
// in Sandstorm, cannot check for updates:
$sandstorm = 1 === (int)getenv('SANDSTORM');

View File

@ -122,6 +122,46 @@ class AttachmentHelper implements AttachmentHelperInterface
return $this->messages;
}
/**
* Uploads a file as a string.
*
* @param Attachment $attachment
* @param string $content
*
* @return bool
*/
public function saveAttachmentFromApi(Attachment $attachment, string $content): bool
{
$resource = tmpfile();
if (false === $resource) {
Log::error('Cannot create temp-file for file upload.');
return false;
}
$path = stream_get_meta_data($resource)['uri'];
fwrite($resource, $content);
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $path);
$allowedMime = config('firefly.allowedMimes');
if (!\in_array($mime, $allowedMime, true)) {
Log::error(sprintf('Mime type %s is not allowed for API file upload.', $mime));
return false;
}
// is allowed? Save the file!
$encrypted = Crypt::encrypt($content);
$this->uploadDisk->put($attachment->fileName(), $encrypted);
// update attachment.
$attachment->md5 = md5_file($path);
$attachment->mime = $mime;
$attachment->size = \strlen($content);
$attachment->uploaded = 1;
$attachment->save();
return true;
}
/**
* @param Model $model
* @param array|null $files
@ -232,7 +272,7 @@ class AttachmentHelper implements AttachmentHelperInterface
Log::debug(sprintf('Name is %s, and mime is %s', $name, $mime));
Log::debug('Valid mimes are', $this->allowedMimes);
if (!\in_array($mime, $this->allowedMimes)) {
if (!\in_array($mime, $this->allowedMimes, true)) {
$msg = (string)trans('validation.file_invalid_mime', ['name' => $name, 'mime' => $mime]);
$this->errors->add('attachments', $msg);
Log::error($msg);

View File

@ -37,14 +37,14 @@ interface AttachmentHelperInterface
*
* @return string
*/
public function getAttachmentLocation(Attachment $attachment): string;
public function getAttachmentContent(Attachment $attachment): string;
/**
* @param Attachment $attachment
*
* @return string
*/
public function getAttachmentContent(Attachment $attachment): string;
public function getAttachmentLocation(Attachment $attachment): string;
/**
* @return Collection
@ -61,6 +61,16 @@ interface AttachmentHelperInterface
*/
public function getMessages(): MessageBag;
/**
* Uploads a file as a string.
*
* @param Attachment $attachment
* @param string $content
*
* @return bool
*/
public function saveAttachmentFromApi(Attachment $attachment, string $content): bool;
/**
* @param Model $model
* @param null|array $files

View File

@ -40,10 +40,6 @@ class BalanceLine
*
*/
public const ROLE_TAGROLE = 2;
/**
*
*/
public const ROLE_DIFFROLE = 3;
/** @var Collection */
protected $balanceEntries;
@ -167,9 +163,6 @@ class BalanceLine
if (self::ROLE_TAGROLE === $this->getRole()) {
return (string)trans('firefly.coveredWithTags');
}
if (self::ROLE_DIFFROLE === $this->getRole()) {
return (string)trans('firefly.leftUnbalanced');
}
return '';
}

View File

@ -321,6 +321,14 @@ class JournalCollector implements JournalCollectorInterface
return $journals;
}
/**
* @return EloquentBuilder
*/
public function getQuery(): EloquentBuilder
{
return $this->query;
}
/**
* @return JournalCollectorInterface
*/

View File

@ -27,6 +27,7 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Tag;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
@ -35,6 +36,7 @@ use Illuminate\Support\Collection;
*/
interface JournalCollectorInterface
{
/**
* @param string $filter
*
@ -78,6 +80,11 @@ interface JournalCollectorInterface
*/
public function getPaginatedJournals(): LengthAwarePaginator;
/**
* @return EloquentBuilder
*/
public function getQuery(): EloquentBuilder;
/**
* @return JournalCollectorInterface
*/

View File

@ -24,9 +24,10 @@ namespace FireflyIII\Helpers\Help;
use Cache;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use League\CommonMark\CommonMarkConverter;
use Log;
use Requests;
use Route;
/**
@ -64,20 +65,21 @@ class Help implements HelpInterface
{
$uri = sprintf('https://raw.githubusercontent.com/firefly-iii/help/master/%s/%s.md', $language, $route);
Log::debug(sprintf('Trying to get %s...', $uri));
$opt = ['useragent' => $this->userAgent];
$opt = ['headers' => ['User-Agent' => $this->userAgent]];
$content = '';
try {
$result = Requests::get($uri, [], $opt);
} catch (Exception $e) {
$client = new Client;
$res = $client->request('GET', $uri, $opt);
} catch (GuzzleException|Exception $e) {
Log::error($e);
return '';
}
Log::debug(sprintf('Status code is %d', $result->status_code));
Log::debug(sprintf('Status code is %d', $res->getStatusCode()));
if (200 === $result->status_code) {
$content = trim($result->body);
if (200 === $res->getStatusCode()) {
$content = trim($res->getBody()->getContents());
}
if (\strlen($content) > 0) {

View File

@ -36,33 +36,6 @@ use Illuminate\Support\Collection;
*/
class PopupReport implements PopupReportInterface
{
/**
* @param $account
* @param $attributes
*
* @return Collection
*/
public function balanceDifference($account, $attributes): Collection
{
// row that displays difference
/** @var JournalCollectorInterface $collector */
$collector = app(JournalCollectorInterface::class);
$collector
->setAccounts(new Collection([$account]))
->setTypes([TransactionType::WITHDRAWAL])
->setRange($attributes['startDate'], $attributes['endDate'])
->withoutBudget();
$journals = $collector->getJournals();
return $journals->filter(
function (Transaction $transaction) {
$tags = $transaction->transactionJournal->tags()->where('tagMode', 'balancingAct')->count();
return 0 === $tags;
}
);
}
/**
* @param Budget $budget
* @param Account $account

View File

@ -32,14 +32,6 @@ use Illuminate\Support\Collection;
*/
interface PopupReportInterface
{
/**
* @param $account
* @param $attributes
*
* @return Collection
*/
public function balanceDifference($account, $attributes): Collection;
/**
* @param Budget $budget
* @param Account $account

View File

@ -34,7 +34,6 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
@ -52,8 +51,6 @@ class AccountController extends Controller
{
/** @var CurrencyRepositoryInterface */
private $currencyRepos;
/** @var JournalRepositoryInterface */
private $journalRepos;
/** @var AccountRepositoryInterface */
private $repository;
@ -72,7 +69,6 @@ class AccountController extends Controller
$this->repository = app(AccountRepositoryInterface::class);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
$this->journalRepos = app(JournalRepositoryInterface::class);
return $next($request);
}
@ -188,7 +184,9 @@ class AccountController extends Controller
$currency = $default;
}
$preFilled = [
// code to handle active-checkboxes
$hasOldInput = null !== $request->old('_token');
$preFilled = [
'accountNumber' => $repository->getMetaValue($account, 'accountNumber'),
'accountRole' => $repository->getMetaValue($account, 'accountRole'),
'ccType' => $repository->getMetaValue($account, 'ccType'),
@ -199,7 +197,7 @@ class AccountController extends Controller
'virtualBalance' => $account->virtual_balance,
'currency_id' => $currency->id,
'notes' => '',
'active' => $account->active,
'active' => $hasOldInput ? (bool)$request->old('active') : $account->active,
];
/** @var Note $note */
$note = $this->repository->getNote($account);
@ -207,7 +205,6 @@ class AccountController extends Controller
$preFilled['notes'] = $note->text;
}
$request->session()->flash('preFilled', $preFilled);
return view('accounts.edit', compact('account', 'currency', 'subTitle', 'subTitleIcon', 'what', 'roles', 'preFilled'));

View File

@ -51,8 +51,9 @@ class HomeController extends Controller
{
$title = (string)trans('firefly.administration');
$mainTitleIcon = 'fa-hand-spock-o';
$sandstorm = 1 === (int)getenv('SANDSTORM');
return view('admin.index', compact('title', 'mainTitleIcon'));
return view('admin.index', compact('title', 'mainTitleIcon', 'sandstorm'));
}
/**

View File

@ -112,7 +112,7 @@ class LinkController extends Controller
public function destroy(Request $request, LinkTypeRepositoryInterface $repository, LinkType $linkType)
{
$name = $linkType->name;
$moveTo = $repository->find((int)$request->get('move_link_type_before_delete'));
$moveTo = $repository->findNull((int)$request->get('move_link_type_before_delete'));
$repository->destroy($linkType, $moveTo);
$request->session()->flash('success', (string)trans('firefly.deleted_link_type', ['name' => $name]));

View File

@ -161,10 +161,13 @@ class BillController extends Controller
$bill->amount_max = round($bill->amount_max, $currency->decimal_places);
$defaultCurrency = app('amount')->getDefaultCurrency();
// code to handle active-checkboxes
$hasOldInput = null !== $request->old('_token');
$preFilled = [
'notes' => $this->billRepository->getNoteText($bill),
'transaction_currency_id' => $bill->transaction_currency_id,
'active' => $bill->active,
'active' => $hasOldInput ? (bool)$request->old('active') : $bill->active,
];
$request->session()->flash('preFilled', $preFilled);

View File

@ -96,7 +96,7 @@ class BudgetController extends Controller
// if today is between start and end, use the diff in days between end and today (days left)
// otherwise, use diff between start and end.
$today = new Carbon;
Log::debug(sprintf('Start is %s, end is %s, today is %s', $start->format('Y-m-d'), $end->format('Y-m-d'),$today->format('Y-m-d')));
Log::debug(sprintf('Start is %s, end is %s, today is %s', $start->format('Y-m-d'), $end->format('Y-m-d'), $today->format('Y-m-d')));
if ($today->gte($start) && $today->lte($end)) {
$days = $end->diffInDays($today);
$daysInMonth = $start->diffInDays($today);
@ -216,11 +216,18 @@ class BudgetController extends Controller
{
$subTitle = trans('firefly.edit_budget', ['name' => $budget->name]);
// code to handle active-checkboxes
$hasOldInput = null !== $request->old('_token');
$preFilled = [
'active' => $hasOldInput ? (bool)$request->old('active') : $budget->active,
];
// put previous url in session if not redirect from store (not "return_to_edit").
if (true !== session('budgets.edit.fromUpdate')) {
$this->rememberPreviousUri('budgets.edit.uri');
}
$request->session()->forget('budgets.edit.fromUpdate');
$request->session()->flash('preFilled', $preFilled);
return view('budgets.edit', compact('budget', 'subTitle'));
}

View File

@ -27,6 +27,7 @@ use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Repositories\Account\AccountTaskerInterface;
use FireflyIII\Support\CacheProperties;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
use Log;
use Steam;
@ -57,9 +58,9 @@ class ReportController extends Controller
* @param Carbon $start
* @param Carbon $end
*
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function netWorth(Collection $accounts, Carbon $start, Carbon $end)
public function netWorth(Collection $accounts, Carbon $start, Carbon $end): JsonResponse
{
// chart properties for cache:
$cache = new CacheProperties;
@ -111,14 +112,16 @@ class ReportController extends Controller
$source = $this->getChartData($accounts, $start, $end);
$chartData = [
[
'label' => trans('firefly.income'),
'type' => 'bar',
'entries' => [],
'label' => trans('firefly.income'),
'type' => 'bar',
'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green
'entries' => [],
],
[
'label' => trans('firefly.expenses'),
'type' => 'bar',
'entries' => [],
'label' => trans('firefly.expenses'),
'type' => 'bar',
'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red
'entries' => [],
],
];
@ -188,17 +191,19 @@ class ReportController extends Controller
$chartData = [
[
'label' => (string)trans('firefly.income'),
'type' => 'bar',
'entries' => [
'label' => (string)trans('firefly.income'),
'type' => 'bar',
'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green
'entries' => [
(string)trans('firefly.sum_of_period') => $numbers['sum_earned'],
(string)trans('firefly.average_in_period') => $numbers['avg_earned'],
],
],
[
'label' => trans('firefly.expenses'),
'type' => 'bar',
'entries' => [
'label' => trans('firefly.expenses'),
'type' => 'bar',
'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red
'entries' => [
(string)trans('firefly.sum_of_period') => $numbers['sum_spent'],
(string)trans('firefly.average_in_period') => $numbers['avg_spent'],
],

View File

@ -23,13 +23,18 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
use Artisan;
use Carbon\Carbon;
use DB;
use Exception;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Middleware\IsDemoUser;
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
use Log;
use Monolog\Handler\RotatingFileHandler;
use Preferences;
use Route as RouteFacade;
/**
* Class DebugController
@ -45,6 +50,52 @@ class DebugController extends Controller
$this->middleware(IsDemoUser::class);
}
/**
* @throws FireflyException
*/
public function displayError()
{
Log::debug('This is a test message at the DEBUG level.');
Log::info('This is a test message at the INFO level.');
Log::notice('This is a test message at the NOTICE level.');
Log::warning('This is a test message at the WARNING level.');
Log::error('This is a test message at the ERROR level.');
Log::critical('This is a test message at the CRITICAL level.');
Log::alert('This is a test message at the ALERT level.');
Log::emergency('This is a test message at the EMERGENCY level.');
throw new FireflyException('A very simple test error.');
}
/**
* @param Request $request
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function flush(Request $request)
{
Preferences::mark();
$request->session()->forget(['start', 'end', '_previous', 'viewRange', 'range', 'is_custom_range']);
Log::debug('Call cache:clear...');
Artisan::call('cache:clear');
Log::debug('Call config:clear...');
Artisan::call('config:clear');
Log::debug('Call route:clear...');
Artisan::call('route:clear');
Log::debug('Call twig:clean...');
try {
Artisan::call('twig:clean');
// @codeCoverageIgnoreStart
} catch (Exception $e) {
// don't care
Log::debug('Called twig:clean.');
}
// @codeCoverageIgnoreEnd
Log::debug('Call view:clear...');
Artisan::call('view:clear');
Log::debug('Done! Redirecting...');
return redirect(route('index'));
}
/**
* @param Request $request
@ -111,13 +162,70 @@ class DebugController extends Controller
return view(
'debug', compact(
'phpVersion', 'extensions', 'localeAttempts', 'appEnv', 'appDebug', 'appLog', 'appLogLevel', 'now', 'packages', 'drivers', 'currentDriver',
'userAgent', 'displayErrors', 'errorReporting', 'phpOs', 'interface', 'logContent', 'cacheDriver', 'isDocker', 'isSandstorm', 'trustedProxies',
'toSandbox'
)
'phpVersion', 'extensions', 'localeAttempts', 'appEnv', 'appDebug', 'appLog', 'appLogLevel', 'now', 'packages', 'drivers',
'currentDriver',
'userAgent', 'displayErrors', 'errorReporting', 'phpOs', 'interface', 'logContent', 'cacheDriver', 'isDocker', 'isSandstorm',
'trustedProxies',
'toSandbox'
)
);
}
/**
* @return string
*/
public function routes(): string
{
$set = RouteFacade::getRoutes();
$ignore = ['chart.', 'javascript.', 'json.', 'report-data.', 'popup.', 'debugbar.', 'attachments.download', 'attachments.preview',
'bills.rescan', 'budgets.income', 'currencies.def', 'error', 'flush', 'help.show', 'import.file',
'login', 'logout', 'password.reset', 'profile.confirm-email-change', 'profile.undo-email-change',
'register', 'report.options', 'routes', 'rule-groups.down', 'rule-groups.up', 'rules.up', 'rules.down',
'rules.select', 'search.search', 'test-flash', 'transactions.link.delete', 'transactions.link.switch',
'two-factor.lost', 'reports.options', 'debug', 'import.create-job', 'import.download', 'import.start', 'import.status.json',
'preferences.delete-code', 'rules.test-triggers', 'piggy-banks.remove-money', 'piggy-banks.add-money',
'accounts.reconcile.transactions', 'accounts.reconcile.overview', 'export.download',
'transactions.clone', 'two-factor.index', 'api.v1', 'installer.', 'attachments.view', 'import.create',
'import.job.download', 'import.job.start', 'import.job.status.json', 'import.job.store', 'recurring.events',
'recurring.suggest',
];
$return = '&nbsp;';
/** @var Route $route */
foreach ($set as $route) {
$name = $route->getName();
if (null !== $name && \strlen($name) > 0 && \in_array('GET', $route->methods(), true)) {
$found = false;
foreach ($ignore as $string) {
if (!(false === stripos($name, $string))) {
$found = true;
break;
}
}
if ($found === false) {
$return .= 'touch ' . $route->getName() . '.md;';
}
}
}
return $return;
}
/**
* @param Request $request
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function testFlash(Request $request)
{
$request->session()->flash('success', 'This is a success message.');
$request->session()->flash('info', 'This is an info message.');
$request->session()->flash('warning', 'This is a warning.');
$request->session()->flash('error', 'This is an error!');
return redirect(route('home'));
}
/**
* Some common combinations.
*
@ -149,7 +257,7 @@ class DebugController extends Controller
private function collectPackages(): array
{
$packages = [];
$file = realpath(__DIR__ . '/../../../vendor/composer/installed.json');
$file = \dirname(__DIR__, 3) . '/vendor/composer/installed.json';
if (!($file === false) && file_exists($file)) {
// file exists!
$content = file_get_contents($file);

View File

@ -22,11 +22,8 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
use Artisan;
use Carbon\Carbon;
use Exception;
use FireflyIII\Events\RequestedVersionCheckStatus;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Http\Middleware\Installer;
use FireflyIII\Http\Middleware\IsDemoUser;
@ -35,11 +32,9 @@ use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
use Illuminate\Support\Collection;
use Log;
use Preferences;
use Route as RouteFacade;
use View;
/**
@ -99,53 +94,6 @@ class HomeController extends Controller
}
/**
* @throws FireflyException
*/
public function displayError()
{
Log::debug('This is a test message at the DEBUG level.');
Log::info('This is a test message at the INFO level.');
Log::notice('This is a test message at the NOTICE level.');
Log::warning('This is a test message at the WARNING level.');
Log::error('This is a test message at the ERROR level.');
Log::critical('This is a test message at the CRITICAL level.');
Log::alert('This is a test message at the ALERT level.');
Log::emergency('This is a test message at the EMERGENCY level.');
throw new FireflyException('A very simple test error.');
}
/**
* @param Request $request
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function flush(Request $request)
{
Preferences::mark();
$request->session()->forget(['start', 'end', '_previous', 'viewRange', 'range', 'is_custom_range']);
Log::debug('Call cache:clear...');
Artisan::call('cache:clear');
Log::debug('Call config:clear...');
Artisan::call('config:clear');
Log::debug('Call route:clear...');
Artisan::call('route:clear');
Log::debug('Call twig:clean...');
try {
Artisan::call('twig:clean');
// @codeCoverageIgnoreStart
} catch (Exception $e) {
// don't care
Log::debug('Called twig:clean.');
}
// @codeCoverageIgnoreEnd
Log::debug('Call view:clear...');
Artisan::call('view:clear');
Log::debug('Done! Redirecting...');
return redirect(route('index'));
}
/**
* @param AccountRepositoryInterface $repository
*
@ -193,56 +141,4 @@ class HomeController extends Controller
);
}
/**
* @return string
*/
public function routes()
{
$set = RouteFacade::getRoutes();
$ignore = ['chart.', 'javascript.', 'json.', 'report-data.', 'popup.', 'debugbar.', 'attachments.download', 'attachments.preview',
'bills.rescan', 'budgets.income', 'currencies.def', 'error', 'flush', 'help.show', 'import.file',
'login', 'logout', 'password.reset', 'profile.confirm-email-change', 'profile.undo-email-change',
'register', 'report.options', 'routes', 'rule-groups.down', 'rule-groups.up', 'rules.up', 'rules.down',
'rules.select', 'search.search', 'test-flash', 'transactions.link.delete', 'transactions.link.switch',
'two-factor.lost', 'reports.options', 'debug', 'import.create-job', 'import.download', 'import.start', 'import.status.json',
'preferences.delete-code', 'rules.test-triggers', 'piggy-banks.remove-money', 'piggy-banks.add-money',
'accounts.reconcile.transactions', 'accounts.reconcile.overview', 'export.download',
'transactions.clone', 'two-factor.index',
];
$return = '&nbsp;';
/** @var Route $route */
foreach ($set as $route) {
$name = $route->getName();
if (null !== $name && \in_array('GET', $route->methods()) && \strlen($name) > 0) {
$found = false;
foreach ($ignore as $string) {
if (!(false === stripos($name, $string))) {
$found = true;
break;
}
}
if ($found === false) {
$return .= 'touch ' . $route->getName() . '.md;';
}
}
}
return $return;
}
/**
* @param Request $request
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function testFlash(Request $request)
{
$request->session()->flash('success', 'This is a success message.');
$request->session()->flash('info', 'This is an info message.');
$request->session()->flash('warning', 'This is a warning.');
$request->session()->flash('error', 'This is an error!');
return redirect(route('home'));
}
}

View File

@ -161,10 +161,8 @@ class IndexController extends Controller
$config['delimiter'] = $config['delimiter'] ?? ',';
$config['delimiter'] = "\t" === $config['delimiter'] ? 'tab' : $config['delimiter'];
// this prevents private information from escaping
$config['column-mapping-config'] = [];
$result = json_encode($config, JSON_PRETTY_PRINT);
$name = sprintf('"%s"', addcslashes('import-configuration-' . date('Y-m-d') . '.json', '"\\'));
$result = json_encode($config, JSON_PRETTY_PRINT);
$name = sprintf('"%s"', addcslashes('import-configuration-' . date('Y-m-d') . '.json', '"\\'));
/** @var LaravelResponse $response */
$response = response($result, 200);
$response->header('Content-disposition', 'attachment; filename=' . $name)

View File

@ -127,7 +127,7 @@ class JobStatusController extends Controller
public function start(ImportJob $importJob): JsonResponse
{
// catch impossible status:
$allowed = ['ready_to_run', 'need_job_config', 'error']; // todo remove error
$allowed = ['ready_to_run', 'need_job_config'];
if (null !== $importJob && !\in_array($importJob->status, $allowed, true)) {
Log::error('Job is not ready.');

View File

@ -153,6 +153,12 @@ class BoxController extends Controller
$incomes[$currencyId] = Amount::formatAnything($currency, $incomes[$currencyId] ?? '0', false);
$expenses[$currencyId] = Amount::formatAnything($currency, $expenses[$currencyId] ?? '0', false);
}
if (\count($sums) === 0) {
$currency = app('amount')->getDefaultCurrency();
$sums[$currency->id] = Amount::formatAnything($currency, '0', false);
$incomes[$currency->id] = Amount::formatAnything($currency, '0', false);
$expenses[$currency->id] = Amount::formatAnything($currency, '0', false);
}
$response = [
'incomes' => $incomes,
@ -161,6 +167,7 @@ class BoxController extends Controller
'size' => \count($sums),
];
$cache->store($response);
return response()->json($response);

View File

@ -50,7 +50,7 @@ class ExchangeController extends Controller
$rate = $repository->getExchangeRate($fromCurrency, $toCurrency, $date);
if (null === $rate->id) {
if (null === $rate) {
Log::debug(sprintf('No cached exchange rate in database for %s to %s on %s', $fromCurrency->code, $toCurrency->code, $date->format('Y-m-d')));
// create service:

View File

@ -127,6 +127,7 @@ class ReportController extends Controller
$budget = $this->budgetRepository->findNull((int)$attributes['budgetId']);
$account = $this->accountRepository->findNull((int)$attributes['accountId']);
switch (true) {
case BalanceLine::ROLE_DEFAULTROLE === $role && null !== $budget->id:
// normal row with a budget:
@ -137,10 +138,6 @@ class ReportController extends Controller
$journals = $this->popupHelper->balanceForNoBudget($account, $attributes);
$budget->name = (string)trans('firefly.no_budget');
break;
case BalanceLine::ROLE_DIFFROLE === $role:
$journals = $this->popupHelper->balanceDifference($account, $attributes);
$budget->name = (string)trans('firefly.leftUnbalanced');
break;
case BalanceLine::ROLE_TAGROLE === $role:
// row with tag info.
throw new FireflyException('Firefly cannot handle this type of info-button (BalanceLine::TagRole)');

View File

@ -107,9 +107,10 @@ class ProfileController extends Controller
$domain = $this->getDomain();
$secret = Google2FA::generateSecretKey();
session()->flash('two-factor-secret', $secret);
$image = Google2FA::getQRCodeInline($domain, auth()->user()->email, $secret, 200);
return view('profile.code', compact('image'));
return view('profile.code', compact('image', 'secret'));
}
/**

View File

@ -0,0 +1,142 @@
<?php
/**
* CreateController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Recurring;
use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\RecurrenceFormRequest;
use FireflyIII\Models\RecurrenceRepetition;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use Illuminate\Http\Request;
/**
*
* Class CreateController
*/
class CreateController extends Controller
{
/** @var BudgetRepositoryInterface */
private $budgets;
/** @var RecurringRepositoryInterface */
private $recurring;
/**
*
*/
public function __construct()
{
parent::__construct();
// translations:
$this->middleware(
function ($request, $next) {
app('view')->share('mainTitleIcon', 'fa-paint-brush');
app('view')->share('title', trans('firefly.recurrences'));
app('view')->share('subTitle', trans('firefly.create_new_recurrence'));
$this->recurring = app(RecurringRepositoryInterface::class);
$this->budgets = app(BudgetRepositoryInterface::class);
return $next($request);
}
);
}
/**
* @param Request $request
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function create(Request $request)
{
$budgets = app('expandedform')->makeSelectListWithEmpty($this->budgets->getActiveBudgets());
$defaultCurrency = app('amount')->getDefaultCurrency();
$tomorrow = new Carbon;
$oldRepetitionType = $request->old('repetition_type');
$tomorrow->addDay();
// put previous url in session if not redirect from store (not "create another").
if (true !== session('recurring.create.fromStore')) {
$this->rememberPreviousUri('recurring.create.uri');
}
$request->session()->forget('recurring.create.fromStore');
// when will it end?
$repetitionEnds = [
'forever' => trans('firefly.repeat_forever'),
'until_date' => trans('firefly.repeat_until_date'),
'times' => trans('firefly.repeat_times'),
];
// what to do in the weekend?
$weekendResponses = [
RecurrenceRepetition::WEEKEND_DO_NOTHING => trans('firefly.do_nothing'),
RecurrenceRepetition::WEEKEND_SKIP_CREATION => trans('firefly.skip_transaction'),
RecurrenceRepetition::WEEKEND_TO_FRIDAY => trans('firefly.jump_to_friday'),
RecurrenceRepetition::WEEKEND_TO_MONDAY => trans('firefly.jump_to_monday'),
];
// flash some data:
$hasOldInput = null !== $request->old('_token');
$preFilled = [
'first_date' => $tomorrow->format('Y-m-d'),
'transaction_type' => $hasOldInput ? $request->old('transaction_type') : 'withdrawal',
'active' => $hasOldInput ? (bool)$request->old('active') : true,
'apply_rules' => $hasOldInput ? (bool)$request->old('apply_rules') : true,
];
$request->session()->flash('preFilled', $preFilled);
return view(
'recurring.create', compact('tomorrow', 'oldRepetitionType', 'weekendResponses', 'preFilled', 'repetitionEnds', 'defaultCurrency', 'budgets')
);
}
/**
* @param RecurrenceFormRequest $request
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function store(RecurrenceFormRequest $request)
{
$data = $request->getAll();
$recurrence = $this->recurring->store($data);
$request->session()->flash('success', (string)trans('firefly.stored_new_recurrence', ['title' => $recurrence->title]));
app('preferences')->mark();
if (1 === (int)$request->get('create_another')) {
// set value so create routine will not overwrite URL:
$request->session()->put('recurring.create.fromStore', true);
return redirect(route('recurring.create'))->withInput();
}
// redirect to previous URL.
return redirect($this->getPreviousUri('recurring.create.uri'));
}
}

View File

@ -0,0 +1,93 @@
<?php
/**
* DeleteController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Recurring;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Recurrence;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use Illuminate\Http\Request;
/**
* Class DeleteController
*/
class DeleteController extends Controller
{
/** @var RecurringRepositoryInterface */
private $recurring;
/**
*
*/
public function __construct()
{
parent::__construct();
// translations:
$this->middleware(
function ($request, $next) {
app('view')->share('mainTitleIcon', 'fa-paint-brush');
app('view')->share('title', trans('firefly.recurrences'));
$this->recurring = app(RecurringRepositoryInterface::class);
return $next($request);
}
);
}
/**
* @param Recurrence $recurrence
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function delete(Recurrence $recurrence)
{
$subTitle = trans('firefly.delete_recurring', ['title' => $recurrence->title]);
// put previous url in session
$this->rememberPreviousUri('recurrences.delete.uri');
// todo actual number.
$journalsCreated = $this->recurring->getTransactions($recurrence)->count();
return view('recurring.delete', compact('recurrence', 'subTitle', 'journalsCreated'));
}
/**
* @param RecurringRepositoryInterface $repository
* @param Request $request
* @param Recurrence $recurrence
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function destroy(RecurringRepositoryInterface $repository, Request $request, Recurrence $recurrence)
{
$repository->destroy($recurrence);
$request->session()->flash('success', (string)trans('firefly.' . 'recurrence_deleted', ['title' => $recurrence->title]));
app('preferences')->mark();
return redirect($this->getPreviousUri('recurrences.delete.uri'));
}
}

View File

@ -0,0 +1,169 @@
<?php
/**
* EditController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Recurring;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\RecurrenceFormRequest;
use FireflyIII\Models\Recurrence;
use FireflyIII\Models\RecurrenceRepetition;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use FireflyIII\Transformers\RecurrenceTransformer;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\ParameterBag;
/**
*
* Class EditController
*/
class EditController extends Controller
{
/** @var BudgetRepositoryInterface */
private $budgets;
/** @var RecurringRepositoryInterface */
private $recurring;
/**
*
*/
public function __construct()
{
parent::__construct();
// translations:
$this->middleware(
function ($request, $next) {
app('view')->share('mainTitleIcon', 'fa-paint-brush');
app('view')->share('title', trans('firefly.recurrences'));
app('view')->share('subTitle', trans('firefly.recurrences'));
$this->recurring = app(RecurringRepositoryInterface::class);
$this->budgets = app(BudgetRepositoryInterface::class);
return $next($request);
}
);
}
/**
* @param Request $request
* @param Recurrence $recurrence
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function edit(Request $request, Recurrence $recurrence)
{
// use transformer:
$transformer = new RecurrenceTransformer(new ParameterBag);
$array = $transformer->transform($recurrence);
$budgets = app('expandedform')->makeSelectListWithEmpty($this->budgets->getActiveBudgets());
// get recurrence type:
// todo move to repository
// todo handle old repetition type as well.
/** @var RecurrenceRepetition $repetition */
$repetition = $recurrence->recurrenceRepetitions()->first();
$currentRepetitionType = $repetition->repetition_type;
if ('' !== $repetition->repetition_moment) {
$currentRepetitionType .= ',' . $repetition->repetition_moment;
}
// put previous url in session if not redirect from store (not "return_to_edit").
if (true !== session('recurrences.edit.fromUpdate')) {
$this->rememberPreviousUri('recurrences.edit.uri');
}
$request->session()->forget('recurrences.edit.fromUpdate');
// assume repeats forever:
$repetitionEnd = 'forever';
// types of repetitions:
$repetitionEnds = [
'forever' => trans('firefly.repeat_forever'),
'until_date' => trans('firefly.repeat_until_date'),
'times' => trans('firefly.repeat_times'),
];
if (null !== $recurrence->repeat_until) {
$repetitionEnd = 'until_date';
}
if ($recurrence->repetitions > 0) {
$repetitionEnd = 'times';
}
// what to do in the weekend?
$weekendResponses = [
RecurrenceRepetition::WEEKEND_DO_NOTHING => trans('firefly.do_nothing'),
RecurrenceRepetition::WEEKEND_SKIP_CREATION => trans('firefly.skip_transaction'),
RecurrenceRepetition::WEEKEND_TO_FRIDAY => trans('firefly.jump_to_friday'),
RecurrenceRepetition::WEEKEND_TO_MONDAY => trans('firefly.jump_to_monday'),
];
// code to handle active-checkboxes
$hasOldInput = null !== $request->old('_token');
// $hasOldInput = false;
$preFilled = [
'transaction_type' => strtolower($recurrence->transactionType->type),
'active' => $hasOldInput ? (bool)$request->old('active') : $recurrence->active,
'apply_rules' => $hasOldInput ? (bool)$request->old('apply_rules') : $recurrence->apply_rules,
];
return view(
'recurring.edit',
compact('recurrence', 'array', 'weekendResponses', 'budgets', 'preFilled', 'currentRepetitionType', 'repetitionEnd', 'repetitionEnds')
);
}
/**
* @param RecurrenceFormRequest $request
* @param Recurrence $recurrence
*
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function update(RecurrenceFormRequest $request, Recurrence $recurrence)
{
$data = $request->getAll();
$this->recurring->update($recurrence, $data);
$request->session()->flash('success', (string)trans('firefly.updated_recurrence', ['title' => $recurrence->title]));
app('preferences')->mark();
if (1 === (int)$request->get('return_to_edit')) {
// set value so edit routine will not overwrite URL:
$request->session()->put('recurrences.edit.fromUpdate', true);
return redirect(route('recurring.edit', [$recurrence->id]))->withInput(['return_to_edit' => 1]);
}
// redirect to previous URL.
return redirect($this->getPreviousUri('recurrences.edit.uri'));
}
}

View File

@ -0,0 +1,240 @@
<?php
/**
* IndexController.php
* Copyright (c) 2018 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Recurring;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Recurrence;
use FireflyIII\Models\RecurrenceRepetition;
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
use FireflyIII\Transformers\RecurrenceTransformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\ParameterBag;
/**
*
* Class IndexController
*/
class IndexController extends Controller
{
/** @var RecurringRepositoryInterface */
private $recurring;
/**
*
*/
public function __construct()
{
parent::__construct();
// translations:
$this->middleware(
function ($request, $next) {
app('view')->share('mainTitleIcon', 'fa-paint-brush');
app('view')->share('title', trans('firefly.recurrences'));
$this->recurring = app(RecurringRepositoryInterface::class);
return $next($request);
}
);
}
/**
* @param Request $request
*
* @throws FireflyException
* @return JsonResponse
*/
function events(Request $request): JsonResponse
{
$return = [];
$start = Carbon::createFromFormat('Y-m-d', $request->get('start'));
$end = Carbon::createFromFormat('Y-m-d', $request->get('end'));
$firstDate = Carbon::createFromFormat('Y-m-d', $request->get('first_date'));
$endDate = '' !== (string)$request->get('end_date') ? Carbon::createFromFormat('Y-m-d', $request->get('end_date')) : null;
$endsAt = (string)$request->get('ends');
$repetitionType = explode(',', $request->get('type'))[0];
$repetitions = (int)$request->get('reps');
$repetitionMoment = '';
$start->startOfDay();
// if $firstDate is beyond $end, simply return an empty array.
if ($firstDate->gt($end)) {
return response()->json([]);
}
// if $firstDate is beyond start, use that one:
$actualStart = clone $firstDate;
switch ($repetitionType) {
default:
throw new FireflyException(sprintf('Cannot handle repetition type "%s"', $repetitionType));
case 'daily':
break;
case 'weekly':
case 'monthly':
$repetitionMoment = explode(',', $request->get('type'))[1] ?? '1';
break;
case 'ndom':
$repetitionMoment = str_ireplace('ndom,', '', $request->get('type'));
break;
case 'yearly':
$repetitionMoment = explode(',', $request->get('type'))[1] ?? '2018-01-01';
break;
}
$repetition = new RecurrenceRepetition;
$repetition->repetition_type = $repetitionType;
$repetition->repetition_moment = $repetitionMoment;
$repetition->repetition_skip = (int)$request->get('skip');
$repetition->weekend = (int)$request->get('weekend');
$actualEnd = clone $end;
switch ($endsAt) {
default:
throw new FireflyException(sprintf('Cannot generate events for type that ends at "%s".', $endsAt));
case 'forever':
// simply generate up until $end. No change from default behavior.
$occurrences = $this->recurring->getOccurrencesInRange($repetition, $actualStart, $actualEnd);
break;
case 'until_date':
$actualEnd = $endDate ?? clone $end;
$occurrences = $this->recurring->getOccurrencesInRange($repetition, $actualStart, $actualEnd);
break;
case 'times':
$occurrences = $this->recurring->getXOccurrences($repetition, $actualStart, $repetitions);
break;
}
/** @var Carbon $current */
foreach ($occurrences as $current) {
if ($current->gte($start)) {
$event = [
'id' => $repetitionType . $firstDate->format('Ymd'),
'title' => 'X',
'allDay' => true,
'start' => $current->format('Y-m-d'),
'end' => $current->format('Y-m-d'),
'editable' => false,
'rendering' => 'background',
];
$return[] = $event;
}
}
return response()->json($return);
}
/**
* @param Request $request
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @throws \FireflyIII\Exceptions\FireflyException
*/
public function index(Request $request)
{
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page');
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
$collection = $this->recurring->get();
// TODO: split collection into pages
$transformer = new RecurrenceTransformer(new ParameterBag);
$recurring = [];
/** @var Recurrence $recurrence */
foreach ($collection as $recurrence) {
$array = $transformer->transform($recurrence);
$array['first_date'] = new Carbon($array['first_date']);
$array['repeat_until'] = null === $array['repeat_until'] ? null : new Carbon($array['repeat_until']);
$array['latest_date'] = null === $array['latest_date'] ? null : new Carbon($array['latest_date']);
$recurring[] = $array;
}
return view('recurring.index', compact('recurring', 'page', 'pageSize'));
}
/**
* @param Request $request
* @param Recurrence $recurrence
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
* @throws FireflyException
*/
public function show(Request $request, Recurrence $recurrence)
{
$transformer = new RecurrenceTransformer(new ParameterBag);
$array = $transformer->transform($recurrence);
$page = (int)$request->get('page');
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
$transactions = $this->recurring->getTransactions($recurrence, $page, $pageSize);
// transform dates back to Carbon objects:
foreach ($array['recurrence_repetitions'] as $index => $repetition) {
foreach ($repetition['occurrences'] as $item => $occurrence) {
$array['recurrence_repetitions'][$index]['occurrences'][$item] = new Carbon($occurrence);
}
}
$subTitle = trans('firefly.overview_for_recurrence', ['title' => $recurrence->title]);
return view('recurring.show', compact('recurrence', 'subTitle', 'array','transactions'));
}
/**
* @param Request $request
*
* @return JsonResponse
*/
public function suggest(Request $request): JsonResponse
{
$today = new Carbon;
$date = Carbon::createFromFormat('Y-m-d', $request->get('date'));
$preSelected = (string)$request->get('pre_select');
$result = [];
if ($date > $today || (string)$request->get('past') === 'true') {
$weekly = sprintf('weekly,%s', $date->dayOfWeekIso);
$monthly = sprintf('monthly,%s', $date->day);
$dayOfWeek = trans(sprintf('config.dow_%s', $date->dayOfWeekIso));
$ndom = sprintf('ndom,%s,%s', $date->weekOfMonth, $date->dayOfWeekIso);
$yearly = sprintf('yearly,%s', $date->format('Y-m-d'));
$yearlyDate = $date->formatLocalized(trans('config.month_and_day_no_year'));
$result = [
'daily' => ['label' => trans('firefly.recurring_daily'), 'selected' => 0 === strpos($preSelected, 'daily')],
$weekly => ['label' => trans('firefly.recurring_weekly', ['weekday' => $dayOfWeek]), 'selected' => 0 === strpos($preSelected, 'weekly')],
$monthly => ['label' => trans('firefly.recurring_monthly', ['dayOfMonth' => $date->day]), 'selected' => 0 === strpos($preSelected, 'monthly')],
$ndom => ['label' => trans('firefly.recurring_ndom', ['weekday' => $dayOfWeek, 'dayOfMonth' => $date->weekOfMonth]),
'selected' => 0 === strpos($preSelected, 'ndom')],
$yearly => ['label' => trans('firefly.recurring_yearly', ['date' => $yearlyDate]), 'selected' => 0 === strpos($preSelected, 'yearly')],
];
}
return response()->json($result);
}
}

View File

@ -23,13 +23,11 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
use Carbon\Carbon;
use ExpandedForm;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Requests\RuleFormRequest;
use FireflyIII\Http\Requests\SelectTransactionsRequest;
use FireflyIII\Http\Requests\TestRuleFormRequest;
use FireflyIII\Jobs\ExecuteRuleOnExistingTransactions;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleAction;
@ -231,6 +229,14 @@ class RuleController extends Controller
$actionCount = \count($oldActions);
}
$hasOldInput = null !== $request->old('_token');
$preFilled = [
'active' => $hasOldInput ? (bool)$request->old('active') : $rule->active,
'stop_processing' => $hasOldInput ? (bool)$request->old('stop_processing') : $rule->stop_processing,
'strict' => $hasOldInput ? (bool)$request->old('strict') : $rule->strict,
];
// get rule trigger for update / store-journal:
$primaryTrigger = $this->ruleRepos->getPrimaryTrigger($rule);
$subTitle = trans('firefly.edit_rule', ['title' => $rule->title]);
@ -241,6 +247,8 @@ class RuleController extends Controller
}
session()->forget('rules.edit.fromUpdate');
$request->session()->flash('preFilled', $preFilled);
return view('rules.rule.edit', compact('rule', 'subTitle', 'primaryTrigger', 'oldTriggers', 'oldActions', 'triggerCount', 'actionCount'));
}
@ -331,11 +339,11 @@ class RuleController extends Controller
public function selectTransactions(Rule $rule)
{
// does the user have shared accounts?
$first = session('first')->format('Y-m-d');
$today = Carbon::create()->format('Y-m-d');
$subTitle = (string)trans('firefly.apply_rule_selection', ['title' => $rule->title]);
$first = session('first')->format('Y-m-d');
$today = Carbon::create()->format('Y-m-d');
$subTitle = (string)trans('firefly.apply_rule_selection', ['title' => $rule->title]);
return view('rules.rule.select-transactions', compact( 'first', 'today', 'rule', 'subTitle'));
return view('rules.rule.select-transactions', compact('first', 'today', 'rule', 'subTitle'));
}
/**
@ -429,6 +437,7 @@ class RuleController extends Controller
Log::error(sprintf('Could not render view in testTriggers(): %s', $exception->getMessage()));
Log::error($exception->getTraceAsString());
}
// @codeCoverageIgnoreEnd
return response()->json(['html' => $view, 'warning' => $warning]);
@ -490,6 +499,7 @@ class RuleController extends Controller
Log::error(sprintf('Could not render view in testTriggersByRule(): %s', $exception->getMessage()));
Log::error($exception->getTraceAsString());
}
// @codeCoverageIgnoreEnd
return response()->json(['html' => $view, 'warning' => $warning]);
@ -539,23 +549,39 @@ class RuleController extends Controller
{
if (0 === $this->ruleRepos->count()) {
$data = [
'rule_group_id' => $this->ruleRepos->getFirstRuleGroup()->id,
'stop_processing' => 0,
'title' => trans('firefly.default_rule_name'),
'description' => trans('firefly.default_rule_description'),
'trigger' => 'store-journal',
'strict' => true,
'rule-trigger-values' => [
trans('firefly.default_rule_trigger_description'),
trans('firefly.default_rule_trigger_from_account'),
],
'rule-action-values' => [
trans('firefly.default_rule_action_prepend'),
trans('firefly.default_rule_action_set_category'),
],
'rule_group_id' => $this->ruleRepos->getFirstRuleGroup()->id,
'stop-processing' => 0,
'title' => trans('firefly.default_rule_name'),
'description' => trans('firefly.default_rule_description'),
'trigger' => 'store-journal',
'strict' => true,
'rule-triggers' => [
[
'name' => 'description_is',
'value' => trans('firefly.default_rule_trigger_description'),
'stop-processing' => false,
'rule-triggers' => ['description_is', 'from_account_is'],
'rule-actions' => ['prepend_description', 'set_category'],
],
[
'name' => 'from_account_is',
'value' => trans('firefly.default_rule_trigger_from_account'),
'stop-processing' => false,
],
],
'rule-actions' => [
[
'name' => 'prepend_description',
'value' => trans('firefly.default_rule_action_prepend'),
'stop-processing' => false,
],
[
'name' => 'set_category',
'value' => trans('firefly.default_rule_action_set_category'),
'stop-processing' => false,
],
],
];
$this->ruleRepos->store($data);
@ -600,6 +626,7 @@ class RuleController extends Controller
Log::error(sprintf('Throwable was thrown in getActionsForBill(): %s', $e->getMessage()));
Log::error($e->getTraceAsString());
}
// @codeCoverageIgnoreEnd
return $actions;
@ -809,6 +836,7 @@ class RuleController extends Controller
Log::debug(sprintf('Throwable was thrown in getTriggersForBill(): %s', $e->getMessage()));
Log::debug($e->getTraceAsString());
}
// @codeCoverageIgnoreEnd
return $triggers;

View File

@ -121,16 +121,18 @@ class RuleGroupController extends Controller
}
/**
* @param Request $request
* @param RuleGroup $ruleGroup
*
* @return View
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function edit(RuleGroup $ruleGroup)
public function edit(Request $request, RuleGroup $ruleGroup)
{
$subTitle = trans('firefly.edit_rule_group', ['title' => $ruleGroup->title]);
$preFilled = [
'active' => $ruleGroup->active,
$hasOldInput = null !== $request->old('_token');
$preFilled = [
'active' => $hasOldInput ? (bool)$request->old('active') : $ruleGroup->active,
];

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