mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-12-24 04:01:27 +00:00
Compare commits
216 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb9aefc489 | ||
|
|
a9c83beb4f | ||
|
|
4a64a1bd46 | ||
|
|
4152179f10 | ||
|
|
400219a9fc | ||
|
|
933105a721 | ||
|
|
bb39781848 | ||
|
|
f90b7bed5e | ||
|
|
80bf94c009 | ||
|
|
f46904c644 | ||
|
|
057619b157 | ||
|
|
fd505b77b2 | ||
|
|
81a23b5b22 | ||
|
|
c0ab0b5af5 | ||
|
|
970cc91938 | ||
|
|
749d373c95 | ||
|
|
3a427dd0f4 | ||
|
|
e1402d5d8a | ||
|
|
864a6883d4 | ||
|
|
9b58c28be8 | ||
|
|
69fe6ecb7d | ||
|
|
321676c97f | ||
|
|
d2e1493530 | ||
|
|
1c8375d0c2 | ||
|
|
e164e22e13 | ||
|
|
c1c4c96918 | ||
|
|
742e03944d | ||
|
|
60f2c19d9d | ||
|
|
21a8d9a109 | ||
|
|
9abedf3160 | ||
|
|
4e48961c2b | ||
|
|
78cd1629de | ||
|
|
dd0cc2d173 | ||
|
|
8f00d2b616 | ||
|
|
c26d98b308 | ||
|
|
913774850b | ||
|
|
43c9737e6e | ||
|
|
67cd3b6f81 | ||
|
|
d0d2189d55 | ||
|
|
b12773bc99 | ||
|
|
da5a1fe264 | ||
|
|
ea48c23535 | ||
|
|
8cd0d5e1ef | ||
|
|
9b46e62eb6 | ||
|
|
1653152dad | ||
|
|
db7e3d725e | ||
|
|
329b34f7d1 | ||
|
|
d624f20107 | ||
|
|
20bebeb7de | ||
|
|
4e9456b33b | ||
|
|
26c03552c6 | ||
|
|
ac6c3496d4 | ||
|
|
2f1760f358 | ||
|
|
53db8912d6 | ||
|
|
91ef21a665 | ||
|
|
5b1153ab65 | ||
|
|
5196bb9281 | ||
|
|
8fd6f8177f | ||
|
|
7b68716a3d | ||
|
|
d8ecc63e66 | ||
|
|
2575f61828 | ||
|
|
c6370ebe48 | ||
|
|
3bc38570a2 | ||
|
|
0d36d43eda | ||
|
|
a5a012738e | ||
|
|
7cce6504e3 | ||
|
|
f696353e2c | ||
|
|
cf11dfe73b | ||
|
|
940323c0b7 | ||
|
|
9f768396c2 | ||
|
|
160e57bfde | ||
|
|
429bec66f2 | ||
|
|
7f9b5e1e5e | ||
|
|
8088c28235 | ||
|
|
2ec310da18 | ||
|
|
d8addc3175 | ||
|
|
7887655077 | ||
|
|
209c42b316 | ||
|
|
011d8a2b9a | ||
|
|
6f70791239 | ||
|
|
7ac439fd0e | ||
|
|
0cda098b4f | ||
|
|
aaff40c4ad | ||
|
|
306e1081e3 | ||
|
|
a1e2dac658 | ||
|
|
07382d5c6d | ||
|
|
56fdb57d24 | ||
|
|
336a9a97f9 | ||
|
|
88083c5b38 | ||
|
|
7e590fb6b3 | ||
|
|
4bb4ffbac4 | ||
|
|
7de3c7f80a | ||
|
|
84d0e44a08 | ||
|
|
d7ca7e4cd8 | ||
|
|
3ba41d712f | ||
|
|
ce917298ed | ||
|
|
91e0e33a04 | ||
|
|
c32e9fabd9 | ||
|
|
dc73db2a07 | ||
|
|
89cc01ce44 | ||
|
|
efa3eb1981 | ||
|
|
50ab1fa3f0 | ||
|
|
e50641e969 | ||
|
|
d4c763df84 | ||
|
|
c0669c158a | ||
|
|
e33bbc6f16 | ||
|
|
ea5ab54c3a | ||
|
|
3c18ea1e14 | ||
|
|
25ba86b5d8 | ||
|
|
ecdf59ee3e | ||
|
|
cc1f3bba7e | ||
|
|
b501c47187 | ||
|
|
791b028dc4 | ||
|
|
ab5b7f7893 | ||
|
|
4b1aa29269 | ||
|
|
de34538d96 | ||
|
|
53eb93fc4d | ||
|
|
a3841855e4 | ||
|
|
b1e742c26c | ||
|
|
2c2814c998 | ||
|
|
214c7a6f3e | ||
|
|
6c4f967c39 | ||
|
|
e0152d3df4 | ||
|
|
989ffc2f07 | ||
|
|
f87a4c1e7c | ||
|
|
fea5510700 | ||
|
|
aa1ae18dbb | ||
|
|
b5efd38ded | ||
|
|
2a457c40db | ||
|
|
e38b64547f | ||
|
|
bafa96b9c0 | ||
|
|
d49a13b091 | ||
|
|
0bd818956f | ||
|
|
c119b9cc7b | ||
|
|
958c7e7939 | ||
|
|
254a46b54c | ||
|
|
6ed31dc4c9 | ||
|
|
fe8f5573d2 | ||
|
|
51dfb8ebf1 | ||
|
|
8fd64791d6 | ||
|
|
82e7202ad2 | ||
|
|
1f70782f7e | ||
|
|
eefb1c4a47 | ||
|
|
069015c9b1 | ||
|
|
c1583d19fb | ||
|
|
0556433ce4 | ||
|
|
ec072cee23 | ||
|
|
e29e6c147c | ||
|
|
972721b183 | ||
|
|
9bf43ce80d | ||
|
|
5941b5c07e | ||
|
|
3d91a186d5 | ||
|
|
744d45fb04 | ||
|
|
f76fdedd25 | ||
|
|
93ca07d812 | ||
|
|
d69042daee | ||
|
|
d9f515900c | ||
|
|
57b4a5be08 | ||
|
|
fa347f5f75 | ||
|
|
35e3404ced | ||
|
|
f7344ec6c9 | ||
|
|
63a1e560ee | ||
|
|
98463f8258 | ||
|
|
2c95bfa701 | ||
|
|
2de3a2c98e | ||
|
|
314c0c9e3f | ||
|
|
4377627332 | ||
|
|
71d3f452ed | ||
|
|
e117222dc2 | ||
|
|
6286daa881 | ||
|
|
0b3b9af623 | ||
|
|
1492f5611e | ||
|
|
efeffaa49f | ||
|
|
d77112955d | ||
|
|
9a34bb7e7a | ||
|
|
b30445a5f3 | ||
|
|
0bf5c6ee3d | ||
|
|
155480b335 | ||
|
|
34202dea1d | ||
|
|
38d58f0354 | ||
|
|
d4b82a33c5 | ||
|
|
06f3463dbc | ||
|
|
9df2d86ac2 | ||
|
|
c83d93971f | ||
|
|
7e3ba3c27f | ||
|
|
c7043dffc2 | ||
|
|
d2c1e30979 | ||
|
|
d5679c372f | ||
|
|
b33f8b70d4 | ||
|
|
d5773ab5d0 | ||
|
|
1903292202 | ||
|
|
c3a9415208 | ||
|
|
9ece209c72 | ||
|
|
03956af88a | ||
|
|
013c8707ac | ||
|
|
32ed9c59ea | ||
|
|
4ef663669c | ||
|
|
b855c54e81 | ||
|
|
8b65c8b909 | ||
|
|
28e7440726 | ||
|
|
7bca2298a0 | ||
|
|
b1cc17d96e | ||
|
|
2afbef63aa | ||
|
|
f0d2caec67 | ||
|
|
ac2a317fd2 | ||
|
|
bc4ac303e2 | ||
|
|
0e9fbecbe4 | ||
|
|
226b3cfdd8 | ||
|
|
d43fa3790d | ||
|
|
ca04113aa7 | ||
|
|
817c157db4 | ||
|
|
07edbe758a | ||
|
|
46ba0a5a5a | ||
|
|
480b636c7e | ||
|
|
20340dff7b | ||
|
|
cfbabb500f |
@@ -1,12 +0,0 @@
|
||||
---
|
||||
exclude_patterns:
|
||||
- public/lib/
|
||||
- public/js/lib/
|
||||
- public/fonts/
|
||||
- public/css/jquery-ui/
|
||||
- public/css/bootstrap-multiselect.css
|
||||
- public/css/bootstrap-sortable.css
|
||||
- public/css/bootstrap-tagsinput.css
|
||||
- public/css/daterangepicker.css
|
||||
- public/css/google-fonts.css
|
||||
- .sandstorm/
|
||||
3314
.deploy/docker/cacert.pem
Normal file
3314
.deploy/docker/cacert.pem
Normal file
File diff suppressed because it is too large
Load Diff
64
.env.docker
64
.env.docker
@@ -43,12 +43,25 @@ DB_HOST=${FF_DB_HOST}
|
||||
DB_PORT=${FF_DB_PORT}
|
||||
DB_DATABASE=${FF_DB_NAME}
|
||||
DB_USERNAME=${FF_DB_USER}
|
||||
DB_PASSWORD=${FF_DB_PASSWORD}
|
||||
DB_PASSWORD="${FF_DB_PASSWORD}"
|
||||
|
||||
# If you're looking for performance improvements, you could install memcached.
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
|
||||
# You can configure another file storage backend if you cannot use the local storage option.
|
||||
# To set this up, fill in the following variables. The upload path is used to store uploaded
|
||||
# files and the export path is to store exported data (before download).
|
||||
SFTP_HOST=${SFTP_HOST}
|
||||
SFTP_PORT=${SFTP_PORT}
|
||||
SFTP_UPLOAD_PATH=${SFTP_UPLOAD_PATH}
|
||||
SFTP_EXPORT_PATH=${SFTP_EXPORT_PATH}
|
||||
|
||||
# SFTP uses either the username/password combination or the private key to authenticate.
|
||||
SFTP_USERNAME=${SFTP_USERNAME}
|
||||
SFTP_PASSWORD="${SFTP_PASSWORD}"
|
||||
SFTP_PRIV_KEY=${SFTP_PRIV_KEY}
|
||||
|
||||
# Cookie settings. Should not be necessary to change these.
|
||||
COOKIE_PATH="/"
|
||||
COOKIE_DOMAIN=
|
||||
@@ -61,7 +74,7 @@ MAIL_HOST=${MAIL_HOST}
|
||||
MAIL_PORT=${MAIL_PORT}
|
||||
MAIL_FROM=${MAIL_FROM}
|
||||
MAIL_USERNAME=${MAIL_USERNAME}
|
||||
MAIL_PASSWORD=${MAIL_PASSWORD}
|
||||
MAIL_PASSWORD="${MAIL_PASSWORD}"
|
||||
MAIL_ENCRYPTION=${MAIL_ENCRYPTION}
|
||||
|
||||
# Other mail drivers:
|
||||
@@ -74,6 +87,9 @@ SPARKPOST_SECRET=${SPARKPOST_SECRET}
|
||||
SEND_REGISTRATION_MAIL=true
|
||||
SEND_ERROR_MESSAGE=false
|
||||
|
||||
# These messages contain (sensitive) transaction information:
|
||||
SEND_REPORT_JOURNALS=${SEND_REPORT_JOURNALS}
|
||||
|
||||
# Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places.
|
||||
MAPBOX_API_KEY=${MAPBOX_API_KEY}
|
||||
|
||||
@@ -89,9 +105,51 @@ ANALYTICS_ID=${ANALYTICS_ID}
|
||||
# This makes it easier to migrate your database. Not that some fields will never be decrypted.
|
||||
USE_ENCRYPTION=true
|
||||
|
||||
# Firefly III has two options for user authentication. "eloquent" is the default,
|
||||
# and "adldap" for LDAP servers.
|
||||
# For full instructions on these settings please visit:
|
||||
# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html
|
||||
LOGIN_PROVIDER=${LOGIN_PROVIDER}
|
||||
|
||||
# LDAP connection configuration
|
||||
ADLDAP_CONNECTION_SCHEME=${ADLDAP_CONNECTION_SCHEME}
|
||||
ADLDAP_AUTO_CONNECT=${ADLDAP_AUTO_CONNECT}
|
||||
|
||||
# LDAP connection settings
|
||||
ADLDAP_CONTROLLERS=${ADLDAP_CONTROLLERS}
|
||||
ADLDAP_PORT=${ADLDAP_PORT}
|
||||
ADLDAP_TIMEOUT=${ADLDAP_TIMEOUT}
|
||||
ADLDAP_BASEDN="${ADLDAP_BASEDN}"
|
||||
ADLDAP_FOLLOW_REFFERALS=${ADLDAP_FOLLOW_REFFERALS}
|
||||
ADLDAP_USE_SSL=${ADLDAP_USE_SSL}
|
||||
ADLDAP_USE_TLS=${ADLDAP_USE_TLS}
|
||||
|
||||
ADLDAP_ADMIN_USERNAME=${ADLDAP_ADMIN_USERNAME}
|
||||
ADLDAP_ADMIN_PASSWORD="${ADLDAP_ADMIN_PASSWORD}"
|
||||
|
||||
ADLDAP_ACCOUNT_PREFIX="${ADLDAP_ACCOUNT_PREFIX}"
|
||||
ADLDAP_ACCOUNT_SUFFIX="${ADLDAP_ACCOUNT_SUFFIX}"
|
||||
ADLDAP_ADMIN_ACCOUNT_PREFIX="${ADLDAP_ADMIN_ACCOUNT_PREFIX}"
|
||||
ADLDAP_ADMIN_ACCOUNT_SUFFIX="${ADLDAP_ADMIN_ACCOUNT_SUFFIX}"
|
||||
|
||||
# LDAP authentication settings.
|
||||
ADLDAP_PASSWORD_SYNC=${ADLDAP_PASSWORD_SYNC}
|
||||
ADLDAP_LOGIN_FALLBACK=${ADLDAP_LOGIN_FALLBACK}
|
||||
|
||||
ADLDAP_DISCOVER_FIELD=${ADLDAP_DISCOVER_FIELD}
|
||||
ADLDAP_AUTH_FIELD=${ADLDAP_AUTH_FIELD}
|
||||
|
||||
# Will allow SSO if your server provides an AUTH_USER field.
|
||||
WINDOWS_SSO_DISCOVER=${WINDOWS_SSO_DISCOVER}
|
||||
WINDOWS_SSO_KEY=${WINDOWS_SSO_KEY}
|
||||
|
||||
# field to sync as local username.
|
||||
ADLDAP_SYNC_FIELD=${ADLDAP_SYNC_FIELD}
|
||||
|
||||
# Leave the following configuration vars as is.
|
||||
# Unless you like to tinker and know what you're doing.
|
||||
APP_NAME=FireflyIII
|
||||
ADLDAP_CONNECTION=default
|
||||
BROADCAST_DRIVER=log
|
||||
QUEUE_DRIVER=sync
|
||||
REDIS_HOST=127.0.0.1
|
||||
@@ -108,5 +166,3 @@ IS_DOCKER=true
|
||||
IS_SANDSTORM=false
|
||||
IS_HEROKU=false
|
||||
BUNQ_USE_SANDBOX=false
|
||||
MAILGUN_DOMAIN=
|
||||
MAILGUN_SECRET=
|
||||
|
||||
61
.env.example
61
.env.example
@@ -49,6 +49,19 @@ DB_PASSWORD=secret
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
|
||||
# You can configure another file storage backend if you cannot use the local storage option.
|
||||
# To set this up, fill in the following variables. The upload path is used to store uploaded
|
||||
# files and the export path is to store exported data (before download).
|
||||
SFTP_HOST=
|
||||
SFTP_PORT=
|
||||
SFTP_UPLOAD_PATH=
|
||||
SFTP_EXPORT_PATH=
|
||||
|
||||
# SFTP uses either the username/password combination or the private key to authenticate.
|
||||
SFTP_USERNAME=
|
||||
SFTP_PASSWORD=
|
||||
SFTP_PRIV_KEY=
|
||||
|
||||
# Cookie settings. Should not be necessary to change these.
|
||||
COOKIE_PATH="/"
|
||||
COOKIE_DOMAIN=
|
||||
@@ -74,6 +87,9 @@ SPARKPOST_SECRET=
|
||||
SEND_REGISTRATION_MAIL=true
|
||||
SEND_ERROR_MESSAGE=true
|
||||
|
||||
# These messages contain (sensitive) transaction information:
|
||||
SEND_REPORT_JOURNALS=true
|
||||
|
||||
# Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places.
|
||||
MAPBOX_API_KEY=
|
||||
|
||||
@@ -89,9 +105,52 @@ ANALYTICS_ID=
|
||||
# This makes it easier to migrate your database. Not that some fields will never be decrypted.
|
||||
USE_ENCRYPTION=true
|
||||
|
||||
# Firefly III has two options for user authentication. "eloquent" is the default,
|
||||
# and "adldap" for LDAP servers.
|
||||
# For full instructions on these settings please visit:
|
||||
# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html
|
||||
LOGIN_PROVIDER=eloquent
|
||||
|
||||
# LDAP connection configuration
|
||||
# OpenLDAP, FreeIPA or ActiveDirectory
|
||||
ADLDAP_CONNECTION_SCHEME=OpenLDAP
|
||||
ADLDAP_AUTO_CONNECT=true
|
||||
|
||||
# LDAP connection settings
|
||||
ADLDAP_CONTROLLERS=
|
||||
ADLDAP_PORT=389
|
||||
ADLDAP_TIMEOUT=5
|
||||
ADLDAP_BASEDN=""
|
||||
ADLDAP_FOLLOW_REFFERALS=false
|
||||
ADLDAP_USE_SSL=false
|
||||
ADLDAP_USE_TLS=false
|
||||
|
||||
ADLDAP_ADMIN_USERNAME=
|
||||
ADLDAP_ADMIN_PASSWORD=
|
||||
|
||||
ADLDAP_ACCOUNT_PREFIX=
|
||||
ADLDAP_ACCOUNT_SUFFIX=
|
||||
ADLDAP_ADMIN_ACCOUNT_PREFIX=
|
||||
ADLDAP_ADMIN_ACCOUNT_SUFFIX=
|
||||
|
||||
# LDAP authentication settings.
|
||||
ADLDAP_PASSWORD_SYNC=false
|
||||
ADLDAP_LOGIN_FALLBACK=false
|
||||
|
||||
ADLDAP_DISCOVER_FIELD=distinguishedname
|
||||
ADLDAP_AUTH_FIELD=distinguishedname
|
||||
|
||||
# Will allow SSO if your server provides an AUTH_USER field.
|
||||
WINDOWS_SSO_DISCOVER=samaccountname
|
||||
WINDOWS_SSO_KEY=AUTH_USER
|
||||
|
||||
# field to sync as local username.
|
||||
ADLDAP_SYNC_FIELD=userprincipalname
|
||||
|
||||
# Leave the following configuration vars as is.
|
||||
# Unless you like to tinker and know what you're doing.
|
||||
APP_NAME=FireflyIII
|
||||
ADLDAP_CONNECTION=default
|
||||
BROADCAST_DRIVER=log
|
||||
QUEUE_DRIVER=sync
|
||||
REDIS_HOST=127.0.0.1
|
||||
@@ -108,5 +167,3 @@ IS_DOCKER=false
|
||||
IS_SANDSTORM=false
|
||||
IS_HEROKU=false
|
||||
BUNQ_USE_SANDBOX=false
|
||||
MAILGUN_DOMAIN=
|
||||
MAILGUN_SECRET=
|
||||
|
||||
61
.env.heroku
61
.env.heroku
@@ -49,6 +49,19 @@ DB_CONNECTION=pgsql
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
|
||||
# You can configure another file storage backend if you cannot use the local storage option.
|
||||
# To set this up, fill in the following variables. The upload path is used to store uploaded
|
||||
# files and the export path is to store exported data (before download).
|
||||
SFTP_HOST=
|
||||
SFTP_PORT=
|
||||
SFTP_UPLOAD_PATH=
|
||||
SFTP_EXPORT_PATH=
|
||||
|
||||
# SFTP uses either the username/password combination or the private key to authenticate.
|
||||
SFTP_USERNAME=
|
||||
SFTP_PASSWORD=
|
||||
SFTP_PRIV_KEY=
|
||||
|
||||
# Cookie settings. Should not be necessary to change these.
|
||||
COOKIE_PATH="/"
|
||||
COOKIE_DOMAIN=
|
||||
@@ -74,6 +87,9 @@ SPARKPOST_SECRET=
|
||||
SEND_REGISTRATION_MAIL=true
|
||||
SEND_ERROR_MESSAGE=true
|
||||
|
||||
# These messages contain (sensitive) transaction information:
|
||||
SEND_REPORT_JOURNALS=true
|
||||
|
||||
# Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places.
|
||||
MAPBOX_API_KEY=
|
||||
|
||||
@@ -89,9 +105,52 @@ ANALYTICS_ID=
|
||||
# This makes it easier to migrate your database. Not that some fields will never be decrypted.
|
||||
USE_ENCRYPTION=true
|
||||
|
||||
# Firefly III has two options for user authentication. "eloquent" is the default,
|
||||
# and "adldap" for LDAP servers.
|
||||
# For full instructions on these settings please visit:
|
||||
# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html
|
||||
LOGIN_PROVIDER=eloquent
|
||||
|
||||
# LDAP connection configuration
|
||||
# OpenLDAP, FreeIPA or ActiveDirectory
|
||||
ADLDAP_CONNECTION_SCHEME=OpenLDAP
|
||||
ADLDAP_AUTO_CONNECT=true
|
||||
|
||||
# LDAP connection settings
|
||||
ADLDAP_CONTROLLERS=
|
||||
ADLDAP_PORT=389
|
||||
ADLDAP_TIMEOUT=5
|
||||
ADLDAP_BASEDN=""
|
||||
ADLDAP_FOLLOW_REFFERALS=false
|
||||
ADLDAP_USE_SSL=false
|
||||
ADLDAP_USE_TLS=false
|
||||
|
||||
ADLDAP_ADMIN_USERNAME=
|
||||
ADLDAP_ADMIN_PASSWORD=
|
||||
|
||||
ADLDAP_ACCOUNT_PREFIX=
|
||||
ADLDAP_ACCOUNT_SUFFIX=
|
||||
ADLDAP_ADMIN_ACCOUNT_PREFIX=
|
||||
ADLDAP_ADMIN_ACCOUNT_SUFFIX=
|
||||
|
||||
# LDAP authentication settings.
|
||||
ADLDAP_PASSWORD_SYNC=false
|
||||
ADLDAP_LOGIN_FALLBACK=false
|
||||
|
||||
ADLDAP_DISCOVER_FIELD=distinguishedname
|
||||
ADLDAP_AUTH_FIELD=distinguishedname
|
||||
|
||||
# Will allow SSO if your server provides an AUTH_USER field.
|
||||
WINDOWS_SSO_DISCOVER=samaccountname
|
||||
WINDOWS_SSO_KEY=AUTH_USER
|
||||
|
||||
# field to sync as local username.
|
||||
ADLDAP_SYNC_FIELD=userprincipalname
|
||||
|
||||
# Leave the following configuration vars as is.
|
||||
# Unless you like to tinker and know what you're doing.
|
||||
APP_NAME=FireflyIII
|
||||
ADLDAP_CONNECTION=default
|
||||
BROADCAST_DRIVER=log
|
||||
QUEUE_DRIVER=sync
|
||||
REDIS_HOST=127.0.0.1
|
||||
@@ -108,5 +167,3 @@ IS_DOCKER=false
|
||||
IS_SANDSTORM=false
|
||||
IS_HEROKU=true
|
||||
BUNQ_USE_SANDBOX=false
|
||||
MAILGUN_DOMAIN=
|
||||
MAILGUN_SECRET=
|
||||
|
||||
@@ -49,6 +49,19 @@ DB_PASSWORD=firefly
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
|
||||
# You can configure another file storage backend if you cannot use the local storage option.
|
||||
# To set this up, fill in the following variables. The upload path is used to store uploaded
|
||||
# files and the export path is to store exported data (before download).
|
||||
SFTP_HOST=
|
||||
SFTP_PORT=
|
||||
SFTP_UPLOAD_PATH=
|
||||
SFTP_EXPORT_PATH=
|
||||
|
||||
# SFTP uses either the username/password combination or the private key to authenticate.
|
||||
SFTP_USERNAME=
|
||||
SFTP_PASSWORD=
|
||||
SFTP_PRIV_KEY=
|
||||
|
||||
# Cookie settings. Should not be necessary to change these.
|
||||
COOKIE_PATH="/"
|
||||
COOKIE_DOMAIN=
|
||||
@@ -74,6 +87,9 @@ SPARKPOST_SECRET=
|
||||
SEND_REGISTRATION_MAIL=true
|
||||
SEND_ERROR_MESSAGE=true
|
||||
|
||||
# These messages contain (sensitive) transaction information:
|
||||
SEND_REPORT_JOURNALS=true
|
||||
|
||||
# Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places.
|
||||
MAPBOX_API_KEY=
|
||||
|
||||
@@ -89,9 +105,52 @@ ANALYTICS_ID=
|
||||
# This makes it easier to migrate your database. Not that some fields will never be decrypted.
|
||||
USE_ENCRYPTION=true
|
||||
|
||||
# Firefly III has two options for user authentication. "eloquent" is the default,
|
||||
# and "adldap" for LDAP servers.
|
||||
# For full instructions on these settings please visit:
|
||||
# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html
|
||||
LOGIN_PROVIDER=eloquent
|
||||
|
||||
# LDAP connection configuration
|
||||
# or FreeIPA or ActiveDirectory
|
||||
ADLDAP_CONNECTION_SCHEME=OpenLDAP
|
||||
ADLDAP_AUTO_CONNECT=true
|
||||
|
||||
# LDAP connection settings
|
||||
ADLDAP_CONTROLLERS=
|
||||
ADLDAP_PORT=389
|
||||
ADLDAP_TIMEOUT=5
|
||||
ADLDAP_BASEDN=""
|
||||
ADLDAP_FOLLOW_REFFERALS=false
|
||||
ADLDAP_USE_SSL=false
|
||||
ADLDAP_USE_TLS=false
|
||||
|
||||
ADLDAP_ADMIN_USERNAME=
|
||||
ADLDAP_ADMIN_PASSWORD=
|
||||
|
||||
ADLDAP_ACCOUNT_PREFIX=
|
||||
ADLDAP_ACCOUNT_SUFFIX=
|
||||
ADLDAP_ADMIN_ACCOUNT_PREFIX=
|
||||
ADLDAP_ADMIN_ACCOUNT_SUFFIX=
|
||||
|
||||
# LDAP authentication settings.
|
||||
ADLDAP_PASSWORD_SYNC=false
|
||||
ADLDAP_LOGIN_FALLBACK=false
|
||||
|
||||
ADLDAP_DISCOVER_FIELD=distinguishedname
|
||||
ADLDAP_AUTH_FIELD=distinguishedname
|
||||
|
||||
# Will allow SSO if your server provides an AUTH_USER field.
|
||||
WINDOWS_SSO_DISCOVER=samaccountname
|
||||
WINDOWS_SSO_KEY=AUTH_USER
|
||||
|
||||
# field to sync as local username.
|
||||
ADLDAP_SYNC_FIELD=userprincipalname
|
||||
|
||||
# Leave the following configuration vars as is.
|
||||
# Unless you like to tinker and know what you're doing.
|
||||
APP_NAME=FireflyIII
|
||||
ADLDAP_CONNECTION=default
|
||||
BROADCAST_DRIVER=log
|
||||
QUEUE_DRIVER=sync
|
||||
REDIS_HOST=127.0.0.1
|
||||
@@ -108,5 +167,3 @@ IS_DOCKER=false
|
||||
IS_SANDSTORM=true
|
||||
IS_HEROKU=false
|
||||
BUNQ_USE_SANDBOX=false
|
||||
MAILGUN_DOMAIN=
|
||||
MAILGUN_SECRET=
|
||||
|
||||
63
.env.testing
63
.env.testing
@@ -34,7 +34,7 @@ LOG_CHANNEL=dailytest
|
||||
# debug, info, notice, warning, error, critical, alert, emergency
|
||||
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably
|
||||
# nothing will get logged, ever.
|
||||
APP_LOG_LEVEL=debug
|
||||
APP_LOG_LEVEL=info
|
||||
|
||||
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
|
||||
# For other database types, please see the FAQ: http://firefly-iii.readthedocs.io/en/latest/support/faq.html
|
||||
@@ -49,6 +49,19 @@ DB_CONNECTION=sqlite
|
||||
CACHE_DRIVER=file
|
||||
SESSION_DRIVER=file
|
||||
|
||||
# You can configure another file storage backend if you cannot use the local storage option.
|
||||
# To set this up, fill in the following variables. The upload path is used to store uploaded
|
||||
# files and the export path is to store exported data (before download).
|
||||
SFTP_HOST=
|
||||
SFTP_PORT=
|
||||
SFTP_UPLOAD_PATH=
|
||||
SFTP_EXPORT_PATH=
|
||||
|
||||
# SFTP uses either the username/password combination or the private key to authenticate.
|
||||
SFTP_USERNAME=
|
||||
SFTP_PASSWORD=
|
||||
SFTP_PRIV_KEY=
|
||||
|
||||
# Cookie settings. Should not be necessary to change these.
|
||||
COOKIE_PATH="/"
|
||||
COOKIE_DOMAIN=
|
||||
@@ -74,6 +87,9 @@ SPARKPOST_SECRET=
|
||||
SEND_REGISTRATION_MAIL=true
|
||||
SEND_ERROR_MESSAGE=false
|
||||
|
||||
# These messages contain (sensitive) transaction information:
|
||||
SEND_REPORT_JOURNALS=true
|
||||
|
||||
# Set a Mapbox API key here (see mapbox.com) so there might be a map available at various places.
|
||||
MAPBOX_API_KEY=
|
||||
|
||||
@@ -89,9 +105,52 @@ ANALYTICS_ID=
|
||||
# This makes it easier to migrate your database. Not that some fields will never be decrypted.
|
||||
USE_ENCRYPTION=false
|
||||
|
||||
# Firefly III has two options for user authentication. "eloquent" is the default,
|
||||
# and "adldap" for LDAP servers.
|
||||
# For full instructions on these settings please visit:
|
||||
# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html
|
||||
LOGIN_PROVIDER=eloquent
|
||||
|
||||
# LDAP connection configuration
|
||||
# or FreeIPA or ActiveDirectory
|
||||
ADLDAP_CONNECTION_SCHEME=OpenLDAP
|
||||
ADLDAP_AUTO_CONNECT=true
|
||||
|
||||
# LDAP connection settings
|
||||
ADLDAP_CONTROLLERS=
|
||||
ADLDAP_PORT=389
|
||||
ADLDAP_TIMEOUT=5
|
||||
ADLDAP_BASEDN=""
|
||||
ADLDAP_FOLLOW_REFFERALS=false
|
||||
ADLDAP_USE_SSL=false
|
||||
ADLDAP_USE_TLS=false
|
||||
|
||||
ADLDAP_ADMIN_USERNAME=
|
||||
ADLDAP_ADMIN_PASSWORD=
|
||||
|
||||
ADLDAP_ACCOUNT_PREFIX=
|
||||
ADLDAP_ACCOUNT_SUFFIX=
|
||||
ADLDAP_ADMIN_ACCOUNT_PREFIX=
|
||||
ADLDAP_ADMIN_ACCOUNT_SUFFIX=
|
||||
|
||||
# LDAP authentication settings.
|
||||
ADLDAP_PASSWORD_SYNC=false
|
||||
ADLDAP_LOGIN_FALLBACK=false
|
||||
|
||||
ADLDAP_DISCOVER_FIELD=distinguishedname
|
||||
ADLDAP_AUTH_FIELD=distinguishedname
|
||||
|
||||
# Will allow SSO if your server provides an AUTH_USER field.
|
||||
WINDOWS_SSO_DISCOVER=samaccountname
|
||||
WINDOWS_SSO_KEY=AUTH_USER
|
||||
|
||||
# field to sync as local username.
|
||||
ADLDAP_SYNC_FIELD=userprincipalname
|
||||
|
||||
# Leave the following configuration vars as is.
|
||||
# Unless you like to tinker and know what you're doing.
|
||||
APP_NAME=FireflyIII
|
||||
ADLDAP_CONNECTION=default
|
||||
BROADCAST_DRIVER=log
|
||||
QUEUE_DRIVER=sync
|
||||
REDIS_HOST=127.0.0.1
|
||||
@@ -108,5 +167,3 @@ IS_DOCKER=false
|
||||
IS_SANDSTORM=false
|
||||
IS_HEROKU=false
|
||||
BUNQ_USE_SANDBOX=true
|
||||
MAILGUN_DOMAIN=
|
||||
MAILGUN_SECRET=
|
||||
|
||||
5
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
5
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
@@ -12,6 +12,9 @@ I am running Firefly III version x.x.x
|
||||
**Steps to reproduce**
|
||||
What do you need to do to trigger this bug?
|
||||
|
||||
**Expected behavior**
|
||||
What do you expect to see after those steps?
|
||||
|
||||
**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).
|
||||
|
||||
@@ -19,4 +22,4 @@ Please add extra info here, such as OS, browser, and the output from the /debug
|
||||
Earn bonus points by:
|
||||
|
||||
- Post a stacktrace from your log files
|
||||
- Add a screenshot
|
||||
- Add a screenshot
|
||||
|
||||
9
.locales
Normal file
9
.locales
Normal file
@@ -0,0 +1,9 @@
|
||||
en_US
|
||||
de_DE
|
||||
fr_FR
|
||||
it_IT
|
||||
nl_NL
|
||||
pl_PL
|
||||
pt_BR
|
||||
ru_RU
|
||||
tr_TR
|
||||
@@ -1,3 +1,82 @@
|
||||
$ 4.7.8
|
||||
|
||||
- [Issue 1005](https://github.com/firefly-iii/firefly-iii/issues/1005) You can now configure Firefly III to use LDAP.
|
||||
- [Issue 1071](https://github.com/firefly-iii/firefly-iii/issues/1071) You can execute transaction rules using the command line (so you can cronjob it)
|
||||
- [Issue 1108](https://github.com/firefly-iii/firefly-iii/issues/1108) You can now reorder budgets.
|
||||
- [Issue 1159](https://github.com/firefly-iii/firefly-iii/issues/1159) The ability to import transactions from FinTS-enabled banks.
|
||||
- [Issue 1727](https://github.com/firefly-iii/firefly-iii/issues/1727) You can now use SFTP as storage for uploads and exports.
|
||||
- [Issue 1733](https://github.com/firefly-iii/firefly-iii/issues/1733) You can configure Firefly III not to send emails with transaction information in them.
|
||||
- [Issue 1040](https://github.com/firefly-iii/firefly-iii/issues/1040) Fixed various things that would not scale properly in the past.
|
||||
- [Issue 1771](https://github.com/firefly-iii/firefly-iii/issues/1771) A link to the transaction that fits the bill.
|
||||
- [Issue 1800](https://github.com/firefly-iii/firefly-iii/issues/1800) Icon updated to match others.
|
||||
- MySQL database connection now forces the InnoDB to be used.
|
||||
- [Issue 1583](https://github.com/firefly-iii/firefly-iii/issues/1583) Some times recurring transactions would not fire.
|
||||
- [Issue 1607](https://github.com/firefly-iii/firefly-iii/issues/1607) Problems with the bunq API, finally solved?! (I feel like a clickbait YouTube video now)
|
||||
- [Issue 1698](https://github.com/firefly-iii/firefly-iii/issues/1698) Certificate problems in the Docker container
|
||||
- [Issue 1751](https://github.com/firefly-iii/firefly-iii/issues/1751) Bug in autocomplete
|
||||
- [Issue 1760](https://github.com/firefly-iii/firefly-iii/issues/1760) Tag report bad math
|
||||
- [Issue 1765](https://github.com/firefly-iii/firefly-iii/issues/1765) API inconsistencies for piggy banks.
|
||||
- [Issue 1774](https://github.com/firefly-iii/firefly-iii/issues/1774) Integer exception in SQLite databases
|
||||
- [Issue 1775](https://github.com/firefly-iii/firefly-iii/issues/1775) Heroku now supports all locales
|
||||
- [Issue 1778](https://github.com/firefly-iii/firefly-iii/issues/1778) More autocomplete problems fixed
|
||||
- [Issue 1747](https://github.com/firefly-iii/firefly-iii/issues/1747) Rules now stop at the right moment.
|
||||
- [Issue 1781](https://github.com/firefly-iii/firefly-iii/issues/1781) Problems when creating new rules.
|
||||
- [Issue 1784](https://github.com/firefly-iii/firefly-iii/issues/1784) Can now create a liability with an empty balance.
|
||||
- [Issue 1785](https://github.com/firefly-iii/firefly-iii/issues/1785) Redirect error
|
||||
- [Issue 1790](https://github.com/firefly-iii/firefly-iii/issues/1790) Show attachments for bills.
|
||||
- [Issue 1792](https://github.com/firefly-iii/firefly-iii/issues/1792) Mention excluded accounts.
|
||||
- [Issue 1798](https://github.com/firefly-iii/firefly-iii/issues/1798) Could not recreate deleted piggy banks
|
||||
- [Issue 1805](https://github.com/firefly-iii/firefly-iii/issues/1805) Fixes when handling foreign currencies
|
||||
- [Issue 1807](https://github.com/firefly-iii/firefly-iii/issues/1807) Also decrypt deleted records.
|
||||
- [Issue 1812](https://github.com/firefly-iii/firefly-iii/issues/1812) Fix in transactions API
|
||||
- [Issue 1815](https://github.com/firefly-iii/firefly-iii/issues/1815) Opening balance account name can now be translated.
|
||||
- [Issue 1830](https://github.com/firefly-iii/firefly-iii/issues/1830) Multi-user in a single browser could leak autocomplete data.
|
||||
|
||||
# 4.7.7
|
||||
- [Issue 954](https://github.com/firefly-iii/firefly-iii/issues/954) Some additional view chart ranges
|
||||
- [Issue 1710](https://github.com/firefly-iii/firefly-iii/issues/1710) Added a new currency ([hamuz](https://github.com/hamuz))
|
||||
- Transactions will now store (in the database) how they were created.
|
||||
- [Issue 907](https://github.com/firefly-iii/firefly-iii/issues/907) Better and more options on the transaction list.
|
||||
- [Issue 1450](https://github.com/firefly-iii/firefly-iii/issues/1450) Add a rule to change the type of a transaction automagically
|
||||
- [Issue 1701](https://github.com/firefly-iii/firefly-iii/issues/1701) Fix reference to PHP executable ([hertzg](https://github.com/hertzg))
|
||||
- Budget limits have currency information, for future expansion.
|
||||
- Some charts and pages can handle multiple currencies better.
|
||||
- New GA code for those who use it.
|
||||
- The credit card liability type has been removed.
|
||||
- [Issue 896](https://github.com/firefly-iii/firefly-iii/issues/896) Better redirection when coming from deleted objects.
|
||||
- [Issue 1519](https://github.com/firefly-iii/firefly-iii/issues/1519) Fix autocomplete tags
|
||||
- [Issue 1607](https://github.com/firefly-iii/firefly-iii/issues/1607) Some fixes for the bunq api calls
|
||||
- [Issue 1650](https://github.com/firefly-iii/firefly-iii/issues/1650) Add a negated amount column for CSV imports ([hamuz](https://github.com/hamuz))
|
||||
- [Issue 1658](https://github.com/firefly-iii/firefly-iii/issues/1658) Make font heavy again.
|
||||
- [Issue 1660](https://github.com/firefly-iii/firefly-iii/issues/1660) Add a negated amount column for CSV imports ([hamuz](https://github.com/hamuz))
|
||||
- [Issue 1667](https://github.com/firefly-iii/firefly-iii/issues/1667) Fix pie charts
|
||||
- [Issue 1668](https://github.com/firefly-iii/firefly-iii/issues/1668) YNAB iso_code fix
|
||||
- [Issue 1670](https://github.com/firefly-iii/firefly-iii/issues/1670) Fix piggy bank API error
|
||||
- [Issue 1671](https://github.com/firefly-iii/firefly-iii/issues/1671) More options for liability accounts.
|
||||
- [Issue 1673](https://github.com/firefly-iii/firefly-iii/issues/1673) Fix reconciliation issues.
|
||||
- [Issue 1675](https://github.com/firefly-iii/firefly-iii/issues/1675) Wrong sum in tag report.
|
||||
- [Issue 1679](https://github.com/firefly-iii/firefly-iii/issues/1679) Change type of a transaction wouldn't trigger rules.
|
||||
- [Issue 1682](https://github.com/firefly-iii/firefly-iii/issues/1682) Add liability accounts to transaction conversion
|
||||
- [Issue 1683](https://github.com/firefly-iii/firefly-iii/issues/1683) See matching transaction showed transfers twice.
|
||||
- [Issue 1685](https://github.com/firefly-iii/firefly-iii/issues/1685) fix autocomplete for rules
|
||||
- [Issue 1690](https://github.com/firefly-iii/firefly-iii/issues/1690) Missing highlighted button in intro popup
|
||||
- [Issue 1691](https://github.com/firefly-iii/firefly-iii/issues/1691) No mention of liabilities in demo text
|
||||
- [Issue 1695](https://github.com/firefly-iii/firefly-iii/issues/1695) Small fixes in bills pages.
|
||||
- [Issue 1708](https://github.com/firefly-iii/firefly-iii/issues/1708) Fix by [mathieupost](https://github.com/mathieupost) for bunq
|
||||
- [Issue 1709](https://github.com/firefly-iii/firefly-iii/issues/1709) Fix oauth buttons
|
||||
- [Issue 1712](https://github.com/firefly-iii/firefly-iii/issues/1712) Double slash fix by [hamuz](https://github.com/hamuz)
|
||||
- [Issue 1719](https://github.com/firefly-iii/firefly-iii/issues/1719) Add missing accounts to API
|
||||
- [Issue 1720](https://github.com/firefly-iii/firefly-iii/issues/1720) Fix validation for transaction type.
|
||||
- [Issue 1723](https://github.com/firefly-iii/firefly-iii/issues/1723) API broken for currency exchange rates.
|
||||
- [Issue 1728](https://github.com/firefly-iii/firefly-iii/issues/1728) Fix problem with transaction factory.
|
||||
- [Issue 1729](https://github.com/firefly-iii/firefly-iii/issues/1729) Fix bulk transaction editor
|
||||
- [Issue 1731](https://github.com/firefly-iii/firefly-iii/issues/1731) API failure for budget limits.
|
||||
- Secure headers now allow Mapbox and the 2FA QR code.
|
||||
|
||||
# 4.7.6.2
|
||||
- Docker file builds again.
|
||||
- Fix CSS of OAuth2 authorization view.
|
||||
|
||||
# 4.7.6.1
|
||||
- An issue where I switched variables from the Docker `.env` file to the normal `.env` file and vice versa -- breaking both.
|
||||
- [Issue 1649](https://github.com/firefly-iii/firefly-iii/issues/1649) 2FA QR code would not show up due to very strict security policy headers
|
||||
@@ -40,11 +119,12 @@
|
||||
- [Issue 1639](https://github.com/firefly-iii/firefly-iii/issues/1639) Firefly III trusts the Heroku load balancer, fixing deployment on Heroku.
|
||||
- [Issue 1642](https://github.com/firefly-iii/firefly-iii/issues/1642) Fix issue with split journals.
|
||||
- [Issue 1643](https://github.com/firefly-iii/firefly-iii/issues/1643) Fix reconciliation issue.
|
||||
- Users can no longer give expenses a budget.
|
||||
- Users can no longer give income a budget.
|
||||
- Fix bug in Spectre import.
|
||||
- Heroku would not make you owner.
|
||||
- Add `.htaccess` files to all public directories.
|
||||
- New secure headers will make Firefly III slightly more secure.
|
||||
- The rule "tester" will now also take the "strict"-checkbox into account.
|
||||
|
||||
# 4.7.5.3
|
||||
- [Issue 1527](https://github.com/firefly-iii/firefly-iii/issues/1527), fixed views for transactions without a budget.
|
||||
|
||||
@@ -37,15 +37,15 @@ HOME=/etc/mysql /usr/bin/mysql_install_db --force
|
||||
# Spawn mysqld, php
|
||||
HOME=/etc/mysql /usr/sbin/mysqld &
|
||||
|
||||
/usr/sbin/php-fpm7.1 --nodaemonize --fpm-config /etc/php/7.1/fpm/php-fpm.conf &
|
||||
/usr/sbin/php-fpm7.2 --nodaemonize --fpm-config /etc/php/7.2/fpm/php-fpm.conf &
|
||||
|
||||
# Wait until mysql and php have bound their sockets, indicating readiness
|
||||
while [ ! -e /var/run/mysqld/mysqld.sock ] ; do
|
||||
echo "waiting for mysql to be available at /var/run/mysqld/mysqld.sock"
|
||||
sleep .5
|
||||
done
|
||||
while [ ! -e /var/run/php7.1-fpm.sock ] ; do
|
||||
echo "waiting for php7.1-fpm to be available at /var/run/php7.1-fpm.sock"
|
||||
while [ ! -e /var/run/php7.2-fpm.sock ] ; do
|
||||
echo "waiting for php7.2-fpm to be available at /var/run/php7.2-fpm.sock"
|
||||
sleep .5
|
||||
done
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,8 +15,8 @@ const pkgdef :Spk.PackageDefinition = (
|
||||
|
||||
manifest = (
|
||||
appTitle = (defaultText = "Firefly III"),
|
||||
appVersion = 16,
|
||||
appMarketingVersion = (defaultText = "4.7.6.1"),
|
||||
appVersion = 18,
|
||||
appMarketingVersion = (defaultText = "4.7.8"),
|
||||
|
||||
actions = [
|
||||
# Define your "new document" handlers here.
|
||||
|
||||
@@ -53,7 +53,7 @@ http {
|
||||
}
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
fastcgi_pass unix:/var/run/php7.1-fpm.sock;
|
||||
fastcgi_pass unix:/var/run/php7.2-fpm.sock;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
|
||||
@@ -38,37 +38,37 @@ echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sou
|
||||
|
||||
# install packages.
|
||||
apt-get update
|
||||
apt-get install -y nginx php7.1-fpm php7.1-mysql php7.1-gd php7.1-cli php7.1-curl git php7.1-dev php7.1-zip php7.1-intl php7.1-dom php7.1-mbstring php7.1-bcmath mysql-server
|
||||
apt-get install -y nginx php7.2-fpm php7.2-mysql php7.2-gd php7.2-cli php7.2-curl git php7.2-dev php7.2-zip php7.2-intl php7.2-dom php7.2-mbstring php7.2-bcmath mysql-server
|
||||
service nginx stop
|
||||
service php7.1-fpm stop
|
||||
service php7.2-fpm stop
|
||||
service mysql stop
|
||||
systemctl disable nginx
|
||||
systemctl disable php7.1-fpm
|
||||
systemctl disable php7.2-fpm
|
||||
systemctl disable mysql
|
||||
|
||||
# make php.ini display errors:
|
||||
sed -i 's/display_errors = Off/display_errors = On/g' /etc/php/7.1/fpm/php.ini
|
||||
sed -i 's/display_errors = Off/display_errors = On/g' /etc/php/7.2/fpm/php.ini
|
||||
|
||||
# patch /etc/php/7.1/fpm/pool.d/www.conf to not change uid/gid to www-data
|
||||
# patch /etc/php/7.2/fpm/pool.d/www.conf to not change uid/gid to www-data
|
||||
sed --in-place='' \
|
||||
--expression='s/^listen.owner = www-data/;listen.owner = www-data/' \
|
||||
--expression='s/^listen.group = www-data/;listen.group = www-data/' \
|
||||
/etc/php/7.1/fpm/pool.d/www.conf
|
||||
# patch /etc/php/7.1/fpm/php-fpm.conf to not have a pidfile
|
||||
/etc/php/7.2/fpm/pool.d/www.conf
|
||||
# patch /etc/php/7.2/fpm/php-fpm.conf to not have a pidfile
|
||||
sed --in-place='' \
|
||||
--expression='s/^pid =/;pid =/' \
|
||||
/etc/php/7.1/fpm/php-fpm.conf
|
||||
/etc/php/7.2/fpm/php-fpm.conf
|
||||
|
||||
# move sock file to better dir:
|
||||
sed --in-place='' \
|
||||
--expression='s/^listen = \/run\/php\/php7.1-fpm.sock/listen = \/var\/run\/php7.1-fpm.sock/' \
|
||||
/etc/php/7.1/fpm/pool.d/www.conf
|
||||
--expression='s/^listen = \/run\/php\/php7.2-fpm.sock/listen = \/var\/run\/php7.2-fpm.sock/' \
|
||||
/etc/php/7.2/fpm/pool.d/www.conf
|
||||
|
||||
# patch /etc/php/7.1/fpm/pool.d/www.conf to no clear environment variables
|
||||
# patch /etc/php/7.2/fpm/pool.d/www.conf to no clear environment variables
|
||||
# so we can pass in SANDSTORM=1 to apps
|
||||
sed --in-place='' \
|
||||
--expression='s/^;clear_env = no/clear_env=no/' \
|
||||
/etc/php/7.1/fpm/pool.d/www.conf
|
||||
/etc/php/7.2/fpm/pool.d/www.conf
|
||||
# patch mysql conf to not change uid, and to use /var/tmp over /tmp
|
||||
# for secure-file-priv see https://github.com/sandstorm-io/vagrant-spk/issues/195
|
||||
sed --in-place='' \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
language: php
|
||||
php:
|
||||
- 7.1.18
|
||||
- 7.2
|
||||
|
||||
cache:
|
||||
directories:
|
||||
|
||||
21
Dockerfile
21
Dockerfile
@@ -1,4 +1,4 @@
|
||||
FROM php:7.1-apache
|
||||
FROM php:7.2-apache
|
||||
|
||||
# If building on a RPi, use --build-arg cores=3 to use all cores when compiling
|
||||
# to speed up the image build
|
||||
@@ -8,9 +8,9 @@ ENV CORES ${CORES:-1}
|
||||
ENV FIREFLY_PATH /var/www/firefly-iii/
|
||||
ENV CURL_VERSION 7.60.0
|
||||
ENV OPENSSL_VERSION 1.1.1-pre6
|
||||
ENV COMPOSER_ALLOW_SUPERUSER 1
|
||||
|
||||
LABEL version="1.0" maintainer="thegrumpydictator@gmail.com"
|
||||
|
||||
LABEL version="1.1" maintainer="thegrumpydictator@gmail.com"
|
||||
|
||||
# install packages
|
||||
RUN apt-get update -y && \
|
||||
@@ -20,6 +20,7 @@ RUN apt-get update -y && \
|
||||
wget \
|
||||
libpng-dev \
|
||||
libicu-dev \
|
||||
libldap2-dev \
|
||||
libedit-dev \
|
||||
libtidy-dev \
|
||||
libxml2-dev \
|
||||
@@ -35,6 +36,8 @@ RUN apt-get update -y && \
|
||||
locales && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
# LDAP install
|
||||
RUN docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu/ && docker-php-ext-install ldap
|
||||
|
||||
# Install latest curl
|
||||
RUN cd /tmp && \
|
||||
@@ -60,16 +63,15 @@ RUN echo "/usr/local/lib" >> /etc/ld.so.conf.d/00-curl.conf && ldconfig
|
||||
COPY .deploy/docker/supervisord.conf /etc/supervisor/supervisord.conf
|
||||
RUN mkdir -p /etc/supervisor/conf.d /var/log/supervisor
|
||||
|
||||
# Fix the link to curl:
|
||||
RUN rm -rf /usr/local/lib/libcurl.so.4 && ln -s /usr/lib/x86_64-linux-gnu/libcurl.so.4.4.0 /usr/local/lib/libcurl.so.4
|
||||
|
||||
|
||||
# copy Firefly III supervisor conf file.
|
||||
COPY ./.deploy/docker/firefly-iii.conf /etc/supervisor/conf.d/firefly-iii.conf
|
||||
|
||||
# copy cron job supervisor conf file.
|
||||
COPY ./.deploy/docker/cronjob.conf /etc/supervisor/conf.d/cronjob.conf
|
||||
|
||||
# copy ca certs to correct location
|
||||
COPY ./.deploy/docker/cacert.pem /usr/local/ssl/cert.pem
|
||||
|
||||
# test crons added via crontab
|
||||
RUN echo "0 3 * * * /usr/local/bin/php /var/www/firefly-iii/artisan firefly:cron" | crontab -
|
||||
#RUN (crontab -l ; echo "*/1 * * * * free >> /var/www/firefly-iii/public/cron.html") 2>&1 | crontab -
|
||||
@@ -82,7 +84,6 @@ RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local
|
||||
# Generate locales supported by Firefly III
|
||||
RUN echo "en_US.UTF-8 UTF-8\nde_DE.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nit_IT.UTF-8 UTF-8\nnl_NL.UTF-8 UTF-8\npl_PL.UTF-8 UTF-8\npt_BR.UTF-8 UTF-8\nru_RU.UTF-8 UTF-8\ntr_TR.UTF-8 UTF-8\n\n" > /etc/locale.gen && locale-gen
|
||||
|
||||
|
||||
# copy Apache config to correct spot.
|
||||
COPY ./.deploy/docker/apache2.conf /etc/apache2/apache2.conf
|
||||
|
||||
@@ -105,8 +106,10 @@ RUN chown -R www-data:www-data /var/www && chmod -R 775 $FIREFLY_PATH/storage
|
||||
WORKDIR $FIREFLY_PATH
|
||||
ADD . $FIREFLY_PATH
|
||||
|
||||
# Fix the link to curl:
|
||||
RUN rm -rf /usr/local/lib/libcurl.so.4 && ln -s /usr/lib/x86_64-linux-gnu/libcurl.so.4.4.0 /usr/local/lib/libcurl.so.4
|
||||
|
||||
# Run composer
|
||||
ENV COMPOSER_ALLOW_SUPERUSER 1
|
||||
RUN composer install --prefer-dist --no-dev --no-scripts --no-suggest
|
||||
|
||||
# Expose port 80
|
||||
|
||||
3
app.json
3
app.json
@@ -51,6 +51,9 @@
|
||||
"buildpacks": [
|
||||
{
|
||||
"url": "heroku/php"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/heroku/heroku-buildpack-locale"
|
||||
}
|
||||
],
|
||||
"env": {
|
||||
|
||||
@@ -213,14 +213,13 @@ class AccountController extends Controller
|
||||
$types = [
|
||||
'all' => [AccountType::DEFAULT, AccountType::CASH, AccountType::ASSET, AccountType::EXPENSE, AccountType::REVENUE,
|
||||
AccountType::INITIAL_BALANCE, AccountType::BENEFICIARY, AccountType::IMPORT, AccountType::RECONCILIATION,
|
||||
AccountType::LOAN,],
|
||||
AccountType::LOAN,AccountType::DEBT, AccountType::MORTGAGE],
|
||||
'asset' => [AccountType::DEFAULT, AccountType::ASSET,],
|
||||
'cash' => [AccountType::CASH,],
|
||||
'expense' => [AccountType::EXPENSE, AccountType::BENEFICIARY,],
|
||||
'revenue' => [AccountType::REVENUE,],
|
||||
'special' => [AccountType::CASH, AccountType::INITIAL_BALANCE, AccountType::IMPORT, AccountType::RECONCILIATION,
|
||||
AccountType::LOAN,],
|
||||
'hidden' => [AccountType::INITIAL_BALANCE, AccountType::IMPORT, AccountType::RECONCILIATION, AccountType::LOAN,],
|
||||
'special' => [AccountType::CASH, AccountType::INITIAL_BALANCE, AccountType::IMPORT, AccountType::RECONCILIATION,],
|
||||
'hidden' => [AccountType::INITIAL_BALANCE, AccountType::IMPORT, AccountType::RECONCILIATION],
|
||||
'liability' => [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD],
|
||||
'liabilities' => [AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD],
|
||||
'cc' => [AccountType::CREDITCARD],
|
||||
|
||||
@@ -25,6 +25,8 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Api\V1\Controllers;
|
||||
|
||||
use FireflyIII\Api\V1\Requests\TransactionRequest;
|
||||
use FireflyIII\Events\StoredTransactionJournal;
|
||||
use FireflyIII\Events\UpdatedTransactionJournal;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
|
||||
use FireflyIII\Helpers\Filter\InternalTransferFilter;
|
||||
@@ -192,6 +194,8 @@ class TransactionController extends Controller
|
||||
$data['user'] = auth()->user()->id;
|
||||
$journal = $repository->store($data);
|
||||
|
||||
event(new StoredTransactionJournal($journal, 0));
|
||||
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
@@ -241,6 +245,8 @@ class TransactionController extends Controller
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
event(new UpdatedTransactionJournal($journal));
|
||||
|
||||
// add include parameter:
|
||||
$include = $request->get('include') ?? '';
|
||||
$manager->parseIncludes($include);
|
||||
@@ -284,6 +290,7 @@ class TransactionController extends Controller
|
||||
'withdrawal' => [TransactionType::WITHDRAWAL,],
|
||||
'withdrawals' => [TransactionType::WITHDRAWAL,],
|
||||
'expense' => [TransactionType::WITHDRAWAL,],
|
||||
'expenses' => [TransactionType::WITHDRAWAL,],
|
||||
'income' => [TransactionType::DEPOSIT,],
|
||||
'deposit' => [TransactionType::DEPOSIT,],
|
||||
'deposits' => [TransactionType::DEPOSIT,],
|
||||
|
||||
@@ -50,14 +50,17 @@ class PiggyBankRequest extends Request
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$current = $this->string('current_amount');
|
||||
$current = '' === $current ? '0' : $current;
|
||||
|
||||
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'),
|
||||
'notes' => $this->string('notes'),
|
||||
'current_amount' => $current,
|
||||
'startdate' => $this->date('start_date'),
|
||||
'targetdate' => $this->date('target_date'),
|
||||
'notes' => $this->string('notes'),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -74,7 +77,7 @@ class PiggyBankRequest extends Request
|
||||
'target_amount' => 'required|numeric|more:0',
|
||||
'current_amount' => 'numeric|more:0|lte:target_amount',
|
||||
'start_date' => 'date|nullable',
|
||||
'target_date' => 'date|nullable',
|
||||
'target_date' => 'date|nullable|after:start_date',
|
||||
'notes' => 'max:65000',
|
||||
];
|
||||
|
||||
|
||||
@@ -75,8 +75,10 @@ class RuleRequest extends Request
|
||||
$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'));
|
||||
// some triggers and actions require text:
|
||||
$contextTriggers = implode(',', config('firefly.context-rule-triggers'));
|
||||
$contextActions = implode(',', config('firefly.context-rule-actions'));
|
||||
|
||||
|
||||
$rules = [
|
||||
'title' => 'required|between:1,100|uniqueObjectForUser:rules,title',
|
||||
@@ -86,7 +88,7 @@ class RuleRequest extends Request
|
||||
'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_triggers.*.value' => 'required_if:rule_actions.*.type,' . $contextTriggers . '|min:1|ruleTriggerValue',
|
||||
'rule_actions.*.name' => 'required|in:' . implode(',', $validActions),
|
||||
'rule_actions.*.value' => 'required_if:rule_actions.*.type,' . $contextActions . '|ruleActionValue',
|
||||
'rule_actions.*.stop_processing' => 'boolean',
|
||||
|
||||
@@ -73,6 +73,7 @@ class TransactionRequest extends Request
|
||||
'invoice_date' => $this->date('invoice_date'),
|
||||
'internal_reference' => $this->string('internal_reference'),
|
||||
'notes' => $this->string('notes'),
|
||||
'original-source' => sprintf('api-v%s', config('firefly.api_version')),
|
||||
'transactions' => $this->getTransactionData(),
|
||||
];
|
||||
|
||||
|
||||
392
app/Console/Commands/ApplyRules.php
Normal file
392
app/Console/Commands/ApplyRules.php
Normal file
@@ -0,0 +1,392 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Rule;
|
||||
use FireflyIII\Models\RuleGroup;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
|
||||
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
|
||||
use FireflyIII\TransactionRules\Processor;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class ApplyRules
|
||||
*/
|
||||
class ApplyRules extends Command
|
||||
{
|
||||
use VerifiesAccessToken;
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'This command will apply your rules and rule groups on a selection of your transactions.';
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature
|
||||
= 'firefly:apply-rules
|
||||
{--user=1 : The user ID that the import should import for.}
|
||||
{--token= : The user\'s access token.}
|
||||
{--accounts= : A comma-separated list of asset accounts or liabilities to apply your rules to.}
|
||||
{--rule_groups= : A comma-separated list of rule groups to apply. Take the ID\'s of these rule groups from the Firefly III interface.}
|
||||
{--rules= : A comma-separated list of rules to apply. Take the ID\'s of these rules from the Firefly III interface. Using this option overrules the option that selects rule groups.}
|
||||
{--all_rules : If set, will overrule both settings and simply apply ALL of your rules.}
|
||||
{--start_date= : The date of the earliest transaction to be included (inclusive). If omitted, will be your very first transaction ever. Format: YYYY-MM-DD}
|
||||
{--end_date= : The date of the latest transaction to be included (inclusive). If omitted, will be your latest transaction ever. Format: YYYY-MM-DD}';
|
||||
/** @var Collection */
|
||||
private $accounts;
|
||||
/** @var Carbon */
|
||||
private $endDate;
|
||||
/** @var Collection */
|
||||
private $results;
|
||||
/** @var Collection */
|
||||
private $ruleGroups;
|
||||
/** @var Collection */
|
||||
private $rules;
|
||||
/** @var Carbon */
|
||||
private $startDate;
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->accounts = new Collection;
|
||||
$this->rules = new Collection;
|
||||
$this->ruleGroups = new Collection;
|
||||
$this->results = new Collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
* @throws \FireflyIII\Exceptions\FireflyException
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
if (!$this->verifyAccessToken()) {
|
||||
$this->error('Invalid access token.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$result = $this->verifyInput();
|
||||
if (false === $result) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// get transactions from asset accounts.
|
||||
/** @var TransactionCollectorInterface $collector */
|
||||
$collector = app(TransactionCollectorInterface::class);
|
||||
$collector->setUser($this->getUser());
|
||||
$collector->setAccounts($this->accounts);
|
||||
$collector->setRange($this->startDate, $this->endDate);
|
||||
$transactions = $collector->getTransactions();
|
||||
$count = $transactions->count();
|
||||
|
||||
// first run all rule groups:
|
||||
/** @var RuleGroupRepositoryInterface $ruleGroupRepos */
|
||||
$ruleGroupRepos = app(RuleGroupRepositoryInterface::class);
|
||||
$ruleGroupRepos->setUser($this->getUser());
|
||||
|
||||
/** @var RuleGroup $ruleGroup */
|
||||
foreach ($this->ruleGroups as $ruleGroup) {
|
||||
$this->line(sprintf('Going to apply rule group "%s" to %d transaction(s).', $ruleGroup->title, $count));
|
||||
$rules = $ruleGroupRepos->getActiveStoreRules($ruleGroup);
|
||||
$this->applyRuleSelection($rules, $transactions, true);
|
||||
}
|
||||
|
||||
// then run all rules (rule groups should be empty).
|
||||
if ($this->rules->count() > 0) {
|
||||
|
||||
$this->line(sprintf('Will apply %d rule(s) to %d transaction(s)', $this->rules->count(), $transactions->count()));
|
||||
$this->applyRuleSelection($this->rules, $transactions, false);
|
||||
}
|
||||
|
||||
// filter results:
|
||||
$this->results = $this->results->unique(
|
||||
function (Transaction $transaction) {
|
||||
return (int)$transaction->journal_id;
|
||||
}
|
||||
);
|
||||
|
||||
$this->line('');
|
||||
if (0 === $this->results->count()) {
|
||||
$this->line('The rules were fired but did not influence any transactions.');
|
||||
}
|
||||
if ($this->results->count() > 0) {
|
||||
$this->line(sprintf('The rule(s) was/were fired, and influenced %d transaction(s).', $this->results->count()));
|
||||
foreach ($this->results as $result) {
|
||||
$this->line(
|
||||
vsprintf(
|
||||
'Transaction #%d: "%s" (%s %s)',
|
||||
[
|
||||
$result->journal_id,
|
||||
$result->description,
|
||||
$result->transaction_currency_code,
|
||||
round($result->transaction_amount, $result->transaction_currency_dp),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $rules
|
||||
* @param Collection $transactions
|
||||
* @param bool $breakProcessing
|
||||
*
|
||||
* @throws \FireflyIII\Exceptions\FireflyException
|
||||
*/
|
||||
private function applyRuleSelection(Collection $rules, Collection $transactions, bool $breakProcessing): void
|
||||
{
|
||||
$bar = $this->output->createProgressBar($rules->count() * $transactions->count());
|
||||
foreach ($rules as $rule) {
|
||||
/** @var Processor $processor */
|
||||
$processor = app(Processor::class);
|
||||
$processor->make($rule, true);
|
||||
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
/** @var Rule $rule */
|
||||
$bar->advance();
|
||||
$result = $processor->handleTransaction($transaction);
|
||||
if (true === $result) {
|
||||
$this->results->push($transaction);
|
||||
}
|
||||
}
|
||||
if (true === $rule->stop_processing && true === $breakProcessing) {
|
||||
$this->line('');
|
||||
$this->line(sprintf('Rule #%d ("%s") says to stop processing.', $rule->id, $rule->title));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->line('');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function grabAllRules(): void
|
||||
{
|
||||
if (true === $this->option('all_rules')) {
|
||||
/** @var RuleRepositoryInterface $ruleRepos */
|
||||
$ruleRepos = app(RuleRepositoryInterface::class);
|
||||
$ruleRepos->setUser($this->getUser());
|
||||
$this->rules = $ruleRepos->getAll();
|
||||
|
||||
// reset rule groups.
|
||||
$this->ruleGroups = new Collection;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function parseDates(): void
|
||||
{
|
||||
// parse start date.
|
||||
$startDate = Carbon::create()->startOfMonth();
|
||||
$startString = $this->option('start_date');
|
||||
if (null === $startString) {
|
||||
/** @var JournalRepositoryInterface $repository */
|
||||
$repository = app(JournalRepositoryInterface::class);
|
||||
$repository->setUser($this->getUser());
|
||||
$first = $repository->firstNull();
|
||||
if (null !== $first) {
|
||||
$startDate = $first->date;
|
||||
}
|
||||
}
|
||||
if (null !== $startString && '' !== $startString) {
|
||||
$startDate = Carbon::createFromFormat('Y-m-d', $startString);
|
||||
}
|
||||
|
||||
// parse end date
|
||||
$endDate = Carbon::now();
|
||||
$endString = $this->option('end_date');
|
||||
if (null !== $endString && '' !== $endString) {
|
||||
$endDate = Carbon::createFromFormat('Y-m-d', $endString);
|
||||
}
|
||||
|
||||
if ($startDate > $endDate) {
|
||||
[$endDate, $startDate] = [$startDate, $endDate];
|
||||
}
|
||||
|
||||
$this->startDate = $startDate;
|
||||
$this->endDate = $endDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws \FireflyIII\Exceptions\FireflyException
|
||||
*/
|
||||
private function verifyInput(): bool
|
||||
{
|
||||
// verify account.
|
||||
$result = $this->verifyInputAccounts();
|
||||
if (false === $result) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// verify rule groups.
|
||||
$result = $this->verifyRuleGroups();
|
||||
if (false === $result) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// verify rules.
|
||||
$result = $this->verifyRules();
|
||||
if (false === $result) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$this->grabAllRules();
|
||||
$this->parseDates();
|
||||
|
||||
//$this->line('Number of rules found: ' . $this->rules->count());
|
||||
$this->line('Start date is ' . $this->startDate->format('Y-m-d'));
|
||||
$this->line('End date is ' . $this->endDate->format('Y-m-d'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws \FireflyIII\Exceptions\FireflyException
|
||||
*/
|
||||
private function verifyInputAccounts(): bool
|
||||
{
|
||||
$accountString = $this->option('accounts');
|
||||
if (null === $accountString || '' === $accountString) {
|
||||
$this->error('Please use the --accounts to indicate the accounts to apply rules to.');
|
||||
|
||||
return false;
|
||||
}
|
||||
$finalList = new Collection;
|
||||
$accountList = explode(',', $accountString);
|
||||
|
||||
if (0 === \count($accountList)) {
|
||||
$this->error('Please use the --accounts to indicate the accounts to apply rules to.');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var AccountRepositoryInterface $accountRepository */
|
||||
$accountRepository = app(AccountRepositoryInterface::class);
|
||||
$accountRepository->setUser($this->getUser());
|
||||
|
||||
foreach ($accountList as $accountId) {
|
||||
$accountId = (int)$accountId;
|
||||
$account = $accountRepository->findNull($accountId);
|
||||
if (null !== $account
|
||||
&& \in_array(
|
||||
$account->accountType->type, [AccountType::DEFAULT, AccountType::DEBT, AccountType::ASSET, AccountType::LOAN, AccountType::MORTGAGE], true
|
||||
)) {
|
||||
$finalList->push($account);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 === $finalList->count()) {
|
||||
$this->error('Please make sure all accounts in --accounts are asset accounts or liabilities.');
|
||||
|
||||
return false;
|
||||
}
|
||||
$this->accounts = $finalList;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws \FireflyIII\Exceptions\FireflyException
|
||||
*/
|
||||
private function verifyRuleGroups(): bool
|
||||
{
|
||||
$ruleGroupString = $this->option('rule_groups');
|
||||
if (null === $ruleGroupString || '' === $ruleGroupString) {
|
||||
// can be empty.
|
||||
return true;
|
||||
}
|
||||
$ruleGroupList = explode(',', $ruleGroupString);
|
||||
|
||||
if (0 === \count($ruleGroupList)) {
|
||||
// can be empty.
|
||||
|
||||
return true;
|
||||
}
|
||||
/** @var RuleGroupRepositoryInterface $ruleGroupRepos */
|
||||
$ruleGroupRepos = app(RuleGroupRepositoryInterface::class);
|
||||
$ruleGroupRepos->setUser($this->getUser());
|
||||
|
||||
foreach ($ruleGroupList as $ruleGroupId) {
|
||||
$ruleGroupId = (int)$ruleGroupId;
|
||||
$ruleGroup = $ruleGroupRepos->find($ruleGroupId);
|
||||
$this->ruleGroups->push($ruleGroup);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws \FireflyIII\Exceptions\FireflyException
|
||||
*/
|
||||
private function verifyRules(): bool
|
||||
{
|
||||
$ruleString = $this->option('rules');
|
||||
if (null === $ruleString || '' === $ruleString) {
|
||||
// can be empty.
|
||||
return true;
|
||||
}
|
||||
$finalList = new Collection;
|
||||
$ruleList = explode(',', $ruleString);
|
||||
|
||||
if (0 === \count($ruleList)) {
|
||||
// can be empty.
|
||||
|
||||
return true;
|
||||
}
|
||||
/** @var RuleRepositoryInterface $ruleRepos */
|
||||
$ruleRepos = app(RuleRepositoryInterface::class);
|
||||
$ruleRepos->setUser($this->getUser());
|
||||
|
||||
foreach ($ruleList as $ruleId) {
|
||||
$ruleId = (int)$ruleId;
|
||||
$rule = $ruleRepos->find($ruleId);
|
||||
if (null !== $rule) {
|
||||
$finalList->push($rule);
|
||||
}
|
||||
}
|
||||
if ($finalList->count() > 0) {
|
||||
// reset rule groups.
|
||||
$this->ruleGroups = new Collection;
|
||||
$this->rules = $finalList;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -33,7 +33,7 @@ use FireflyIII\Repositories\ExportJob\ExportJobRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use Illuminate\Console\Command;
|
||||
use Storage;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
/**
|
||||
* Class CreateExport.
|
||||
@@ -136,10 +136,14 @@ class CreateExport extends Command
|
||||
$processor->createZipFile();
|
||||
$disk = Storage::disk('export');
|
||||
$fileName = sprintf('export-%s.zip', date('Y-m-d_H-i-s'));
|
||||
$disk->move($job->key . '.zip', $fileName);
|
||||
$localPath = storage_path('export') . '/' . $job->key . '.zip';
|
||||
|
||||
$this->line('The export has finished! You can find the ZIP file in this location:');
|
||||
$this->line(storage_path(sprintf('export/%s', $fileName)));
|
||||
// "move" from local to export disk
|
||||
$disk->put($fileName, file_get_contents($localPath));
|
||||
unlink($localPath);
|
||||
|
||||
$this->line('The export has finished! You can find the ZIP file in export disk with file name:');
|
||||
$this->line($fileName);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ class EncryptFile extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Encrypts a file and places it in the storage/upload directory.';
|
||||
protected $description = 'Encrypts a file and places it in the upload disk.';
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
|
||||
@@ -35,6 +35,7 @@ use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\Rule;
|
||||
@@ -63,6 +64,7 @@ use UnexpectedValueException;
|
||||
* Upgrade user database.
|
||||
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
|
||||
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class UpgradeDatabase extends Command
|
||||
@@ -95,6 +97,8 @@ class UpgradeDatabase extends Command
|
||||
$this->migrateNotes();
|
||||
$this->migrateAttachmentData();
|
||||
$this->migrateBillsToRules();
|
||||
$this->budgetLimitCurrency();
|
||||
$this->removeCCLiabilities();
|
||||
|
||||
$this->info('Firefly III database is up to date.');
|
||||
|
||||
@@ -435,6 +439,31 @@ class UpgradeDatabase extends Command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function budgetLimitCurrency(): void
|
||||
{
|
||||
$budgetLimits = BudgetLimit::get();
|
||||
/** @var BudgetLimit $budgetLimit */
|
||||
foreach ($budgetLimits as $budgetLimit) {
|
||||
if (null === $budgetLimit->transaction_currency_id) {
|
||||
$budget = $budgetLimit->budget;
|
||||
if (null !== $budget) {
|
||||
$user = $budget->user;
|
||||
if (null !== $user) {
|
||||
$currency = \Amount::getDefaultCurrencyByUser($user);
|
||||
$budgetLimit->transaction_currency_id = $currency->id;
|
||||
$budgetLimit->save();
|
||||
$this->line(
|
||||
sprintf('Budget limit #%d (part of budget "%s") now has a currency setting (%s).', $budgetLimit->id, $budget->name, $currency->name)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function createNewTypes(): void
|
||||
{
|
||||
// create transaction type "Reconciliation".
|
||||
@@ -507,6 +536,28 @@ class UpgradeDatabase extends Command
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function removeCCLiabilities(): void
|
||||
{
|
||||
$ccType = AccountType::where('type', AccountType::CREDITCARD)->first();
|
||||
$debtType =AccountType::where('type', AccountType::DEBT)->first();
|
||||
if(null === $ccType || null === $debtType) {
|
||||
return;
|
||||
}
|
||||
/** @var Collection $accounts */
|
||||
$accounts = Account::where('account_type_id', $ccType->id)->get();
|
||||
foreach($accounts as $account) {
|
||||
$account->account_type_id = $debtType->id;
|
||||
$account->save();
|
||||
$this->line(sprintf('Converted credit card liability account "%s" (#%d) to generic debt liability.', $account->name, $account->id));
|
||||
}
|
||||
if($accounts->count() > 0) {
|
||||
$this->info('Credit card liability types are no longer supported and have been converted to generic debts. See: http://bit.ly/FF3-credit-cards');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method makes sure that the transaction journal uses the currency given in the transaction.
|
||||
*
|
||||
|
||||
@@ -79,7 +79,7 @@ class UseEncryption extends Command
|
||||
$fqn = sprintf('FireflyIII\Models\%s', $class);
|
||||
$encrypt = true === config('firefly.encryption') ? 0 : 1;
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$set = $fqn::where($indicator, $encrypt)->get();
|
||||
$set = $fqn::where($indicator, $encrypt)->withTrashed()->get();
|
||||
|
||||
foreach ($set as $entry) {
|
||||
$newName = $entry->$field;
|
||||
|
||||
@@ -23,17 +23,37 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Trait VerifiesAccessToken.
|
||||
*
|
||||
* Verifies user access token for sensitive commands.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
trait VerifiesAccessToken
|
||||
{
|
||||
/**
|
||||
* @return User
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function getUser(): User
|
||||
{
|
||||
$userId = (int)$this->option('user');
|
||||
/** @var UserRepositoryInterface $repository */
|
||||
$repository = app(UserRepositoryInterface::class);
|
||||
$user = $repository->findNull($userId);
|
||||
if (null === $user) {
|
||||
throw new FireflyException('User is unexpectedly NULL');
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract method to make sure trait knows about method "option".
|
||||
*
|
||||
|
||||
@@ -42,7 +42,7 @@ use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
use Storage;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use ZipArchive;
|
||||
|
||||
/**
|
||||
@@ -184,7 +184,7 @@ class ExpandedProcessor implements ProcessorInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ZIP file.
|
||||
* Create a ZIP file locally (!) in storage_path('export').
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
@@ -195,9 +195,9 @@ class ExpandedProcessor implements ProcessorInterface
|
||||
{
|
||||
$zip = new ZipArchive;
|
||||
$file = $this->job->key . '.zip';
|
||||
$fullPath = storage_path('export') . '/' . $file;
|
||||
$localPath = storage_path('export') . '/' . $file;
|
||||
|
||||
if (true !== $zip->open($fullPath, ZipArchive::CREATE)) {
|
||||
if (true !== $zip->open($localPath, ZipArchive::CREATE)) {
|
||||
throw new FireflyException('Cannot store zip file.');
|
||||
}
|
||||
// for each file in the collection, add it to the zip file.
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace FireflyIII\Export\Exporter;
|
||||
|
||||
use FireflyIII\Export\Entry\Entry;
|
||||
use League\Csv\Writer;
|
||||
use Storage;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
/**
|
||||
* Class CsvExporter.
|
||||
@@ -57,15 +57,11 @@ class CsvExporter extends BasicExporter implements ExporterInterface
|
||||
*/
|
||||
public function run(): bool
|
||||
{
|
||||
// create temporary file:
|
||||
$this->tempFile();
|
||||
|
||||
// necessary for CSV writer:
|
||||
$fullPath = storage_path('export') . DIRECTORY_SEPARATOR . $this->fileName;
|
||||
|
||||
// choose file name:
|
||||
$this->fileName = $this->job->key . '-records.csv';
|
||||
|
||||
//we create the CSV into memory
|
||||
$writer = Writer::createFromPath($fullPath);
|
||||
$writer = Writer::createFromString('');
|
||||
$rows = [];
|
||||
|
||||
// get field names for header row:
|
||||
@@ -86,18 +82,9 @@ class CsvExporter extends BasicExporter implements ExporterInterface
|
||||
$rows[] = $line;
|
||||
}
|
||||
$writer->insertAll($rows);
|
||||
$disk = Storage::disk('export');
|
||||
$disk->put($this->fileName, $writer->getContent());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a temp file.
|
||||
*/
|
||||
private function tempFile()
|
||||
{
|
||||
$this->fileName = $this->job->key . '-records.csv';
|
||||
// touch file in export directory:
|
||||
$disk = Storage::disk('export');
|
||||
$disk->put($this->fileName, '');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,10 +41,21 @@ use Log;
|
||||
*/
|
||||
class AccountFactory
|
||||
{
|
||||
use AccountServiceTrait;
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
use AccountServiceTrait;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
@@ -141,17 +152,23 @@ class AccountFactory
|
||||
*/
|
||||
public function findOrCreate(string $accountName, string $accountType): Account
|
||||
{
|
||||
Log::debug(sprintf('Searching for "%s" of type "%s"', $accountName, $accountType));
|
||||
$type = AccountType::whereType($accountType)->first();
|
||||
$accounts = $this->user->accounts()->where('account_type_id', $type->id)->get(['accounts.*']);
|
||||
$return = null;
|
||||
|
||||
Log::debug(sprintf('Account type is #%d', $type->id));
|
||||
|
||||
/** @var Account $object */
|
||||
foreach ($accounts as $object) {
|
||||
if ($object->name === $accountName) {
|
||||
Log::debug(sprintf('Found account #%d "%s".', $object->id, $object->name));
|
||||
$return = $object;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (null === $return) {
|
||||
Log::debug('Found nothing. Will create a new one.');
|
||||
$return = $this->create(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
|
||||
@@ -34,7 +34,15 @@ use Log;
|
||||
*/
|
||||
class AccountMetaFactory
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
|
||||
@@ -26,12 +26,22 @@ namespace FireflyIII\Factory;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\User;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class AttachmentFactory
|
||||
*/
|
||||
class AttachmentFactory
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
|
||||
@@ -36,6 +36,16 @@ use Log;
|
||||
*/
|
||||
class BillFactory
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
use BillServiceTrait;
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
@@ -27,12 +27,23 @@ namespace FireflyIII\Factory;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class BudgetFactory.
|
||||
*/
|
||||
class BudgetFactory
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
|
||||
@@ -34,6 +34,16 @@ use Log;
|
||||
*/
|
||||
class CategoryFactory
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
|
||||
@@ -37,6 +37,16 @@ use Log;
|
||||
*/
|
||||
class PiggyBankEventFactory
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param PiggyBank|null $piggyBank
|
||||
|
||||
@@ -26,12 +26,23 @@ namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\User;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class PiggyBankFactory
|
||||
*/
|
||||
class PiggyBankFactory
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
|
||||
@@ -39,6 +39,16 @@ use Log;
|
||||
*/
|
||||
class RecurrenceFactory
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
use TransactionTypeTrait, TransactionServiceTrait, RecurringTransactionTrait;
|
||||
|
||||
/** @var User */
|
||||
|
||||
@@ -27,12 +27,23 @@ namespace FireflyIII\Factory;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class TagFactory
|
||||
*/
|
||||
class TagFactory
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/** @var Collection */
|
||||
private $tags;
|
||||
/** @var User */
|
||||
|
||||
@@ -36,6 +36,16 @@ use Log;
|
||||
*/
|
||||
class TransactionCurrencyFactory
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
|
||||
@@ -40,6 +40,16 @@ use Log;
|
||||
*/
|
||||
class TransactionFactory
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
use TransactionServiceTrait;
|
||||
|
||||
/** @var User */
|
||||
@@ -98,6 +108,7 @@ class TransactionFactory
|
||||
{
|
||||
Log::debug('Start of TransactionFactory::createPair()', $data);
|
||||
// all this data is the same for both transactions:
|
||||
Log::debug('Searching for currency info.');
|
||||
$currency = $this->findCurrency($data['currency_id'], $data['currency_code']);
|
||||
$description = $journal->description === $data['description'] ? null : $data['description'];
|
||||
|
||||
@@ -109,8 +120,8 @@ class TransactionFactory
|
||||
Log::debug(sprintf('Expect source destination to be of type "%s"', $destinationType));
|
||||
|
||||
// find source and destination account:
|
||||
$sourceAccount = $this->findAccount($sourceType, $data['source_id'], $data['source_name']);
|
||||
$destinationAccount = $this->findAccount($destinationType, $data['destination_id'], $data['destination_name']);
|
||||
$sourceAccount = $this->findAccount($sourceType, (int)$data['source_id'], $data['source_name']);
|
||||
$destinationAccount = $this->findAccount($destinationType, (int)$data['destination_id'], $data['destination_name']);
|
||||
|
||||
if (null === $sourceAccount || null === $destinationAccount) {
|
||||
$debugData = $data;
|
||||
@@ -154,6 +165,7 @@ class TransactionFactory
|
||||
}
|
||||
|
||||
// set foreign currency
|
||||
Log::debug('Trying to find foreign currency information.');
|
||||
$foreign = $this->findCurrency($data['foreign_currency_id'], $data['foreign_currency_code']);
|
||||
$this->setForeignCurrency($source, $foreign);
|
||||
$this->setForeignCurrency($dest, $foreign);
|
||||
@@ -204,10 +216,11 @@ class TransactionFactory
|
||||
throw new FireflyException(sprintf('Source and destination account cannot be both of the type "%s"', $destinationType));
|
||||
}
|
||||
// source must be in this list AND dest must be in this list:
|
||||
$list = [AccountType::DEFAULT, AccountType::ASSET, AccountType::CASH, AccountType::DEBT, AccountType::MORTGAGE, AccountType::LOAN, AccountType::MORTGAGE];
|
||||
$list = [AccountType::DEFAULT, AccountType::ASSET, AccountType::CREDITCARD, AccountType::CASH, AccountType::DEBT, AccountType::MORTGAGE,
|
||||
AccountType::LOAN, AccountType::MORTGAGE];
|
||||
if (
|
||||
!\in_array($sourceType, $list, true) &&
|
||||
!\in_array($destinationType, $list, true)) {
|
||||
!\in_array($sourceType, $list, true)
|
||||
&& !\in_array($destinationType, $list, true)) {
|
||||
throw new FireflyException(sprintf('At least one of the accounts must be an asset account (%s, %s).', $sourceType, $destinationType));
|
||||
}
|
||||
// either of these must be asset or default account.
|
||||
|
||||
@@ -36,10 +36,21 @@ use Log;
|
||||
*/
|
||||
class TransactionJournalFactory
|
||||
{
|
||||
use JournalServiceTrait, TransactionTypeTrait;
|
||||
/** @var User The user */
|
||||
private $user;
|
||||
|
||||
use JournalServiceTrait, TransactionTypeTrait;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new transaction journal.
|
||||
*
|
||||
@@ -57,13 +68,15 @@ 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(
|
||||
$description = app('steam')->cleanString($data['description']);
|
||||
$description = str_replace(["\n", "\t", "\r"], "\x20", $description);
|
||||
$journal = TransactionJournal::create(
|
||||
[
|
||||
'user_id' => $data['user'],
|
||||
'transaction_type_id' => $type->id,
|
||||
'bill_id' => null,
|
||||
'transaction_currency_id' => $defaultCurrency->id,
|
||||
'description' => $data['description'],
|
||||
'description' => $description,
|
||||
'date' => $data['date']->format('Y-m-d'),
|
||||
'order' => 0,
|
||||
'tag_count' => 0,
|
||||
@@ -104,7 +117,7 @@ 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', 'recurrence_id', 'payment_date', 'invoice_date', 'internal_reference', 'bunq_payment_id', 'importHash', 'importHashV2',
|
||||
'external_id', 'sepa-batch-id'];
|
||||
'external_id', 'sepa-batch-id', 'original-source'];
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$this->storeMeta($journal, $data, $field);
|
||||
|
||||
@@ -34,6 +34,16 @@ use Log;
|
||||
*/
|
||||
class TransactionJournalMetaFactory
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
|
||||
@@ -26,12 +26,22 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Models\TransactionType;
|
||||
|
||||
use Log;
|
||||
/**
|
||||
* Class TransactionTypeFactory
|
||||
*/
|
||||
class TransactionTypeFactory
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
|
||||
@@ -23,12 +23,22 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Generator\Chart\Basic;
|
||||
|
||||
use FireflyIII\Support\ChartColour;
|
||||
|
||||
use Log;
|
||||
/**
|
||||
* Class ChartJsGenerator.
|
||||
*/
|
||||
class ChartJsGenerator implements GeneratorInterface
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will generate a Chart JS compatible array from the given input. Expects this format.
|
||||
*
|
||||
|
||||
@@ -29,6 +29,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Generator\Report\ReportGeneratorInterface;
|
||||
use FireflyIII\Generator\Report\Support;
|
||||
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
|
||||
use FireflyIII\Helpers\Filter\DoubleTransactionFilter;
|
||||
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
|
||||
use FireflyIII\Helpers\Filter\OpposingAccountFilter;
|
||||
use FireflyIII\Helpers\Filter\PositiveAmountFilter;
|
||||
@@ -42,6 +43,7 @@ use Throwable;
|
||||
|
||||
/**
|
||||
* Class MonthReportGenerator.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class MonthReportGenerator extends Support implements ReportGeneratorInterface
|
||||
@@ -66,6 +68,7 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
|
||||
{
|
||||
$this->expenses = new Collection;
|
||||
$this->income = new Collection;
|
||||
$this->tags = new Collection;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -214,12 +217,11 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
|
||||
->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
|
||||
->setTags($this->tags)->withOpposingAccount();
|
||||
$collector->removeFilter(TransferFilter::class);
|
||||
|
||||
$collector->addFilter(OpposingAccountFilter::class);
|
||||
$collector->addFilter(PositiveAmountFilter::class);
|
||||
$collector->addFilter(DoubleTransactionFilter::class);
|
||||
|
||||
$transactions = $collector->getTransactions();
|
||||
|
||||
$transactions = $collector->getTransactions();
|
||||
$this->expenses = $transactions;
|
||||
|
||||
return $transactions;
|
||||
@@ -260,6 +262,7 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
|
||||
*/
|
||||
protected function summarizeByTag(Collection $collection): array
|
||||
{
|
||||
$tagIds = array_map('\intval', $this->tags->pluck('id')->toArray());
|
||||
$result = [];
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($collection as $transaction) {
|
||||
@@ -267,9 +270,11 @@ class MonthReportGenerator extends Support implements ReportGeneratorInterface
|
||||
$journalTags = $journal->tags;
|
||||
/** @var Tag $journalTag */
|
||||
foreach ($journalTags as $journalTag) {
|
||||
$journalTagId = $journalTag->id;
|
||||
$result[$journalTagId] = $result[$journalTagId] ?? '0';
|
||||
$result[$journalTagId] = bcadd($transaction->transaction_amount, $result[$journalTagId]);
|
||||
$journalTagId = (int)$journalTag->id;
|
||||
if (\in_array($journalTagId, $tagIds, true)) {
|
||||
$result[$journalTagId] = $result[$journalTagId] ?? '0';
|
||||
$result[$journalTagId] = bcadd($transaction->transaction_amount, $result[$journalTagId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,12 @@ class AutomationHandler
|
||||
*/
|
||||
public function reportJournals(RequestedReportOnJournals $event): bool
|
||||
{
|
||||
$sendReport = envNonEmpty('SEND_REPORT_JOURNALS', true);
|
||||
|
||||
if (false === $sendReport) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Log::debug('In reportJournals.');
|
||||
/** @var UserRepositoryInterface $repository */
|
||||
$repository = app(UserRepositoryInterface::class);
|
||||
|
||||
@@ -23,13 +23,14 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Helpers\Attachments;
|
||||
|
||||
use Crypt;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\MessageBag;
|
||||
use Log;
|
||||
use Storage;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
|
||||
/**
|
||||
@@ -63,8 +64,13 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
$this->messages = new MessageBag;
|
||||
$this->attachments = new Collection;
|
||||
$this->uploadDisk = Storage::disk('upload');
|
||||
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the content of an attachment.
|
||||
*
|
||||
@@ -88,7 +94,7 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file location for an attachment,
|
||||
* Returns the file path relative to upload disk for an attachment,
|
||||
*
|
||||
* @param Attachment $attachment
|
||||
*
|
||||
@@ -96,8 +102,7 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
*/
|
||||
public function getAttachmentLocation(Attachment $attachment): string
|
||||
{
|
||||
$path = sprintf('%s%sat-%d.data', storage_path('upload'), DIRECTORY_SEPARATOR, (int)$attachment->id);
|
||||
|
||||
$path = sprintf('%sat-%d.data', DIRECTORY_SEPARATOR, (int)$attachment->id);
|
||||
return $path;
|
||||
}
|
||||
|
||||
@@ -177,13 +182,17 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
/**
|
||||
* Save attachments that get uploaded with models, through the app.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param object $model
|
||||
* @param array|null $files
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Illuminate\Contracts\Encryption\EncryptException
|
||||
*/
|
||||
public function saveAttachmentsForModel(Model $model, ?array $files): bool
|
||||
public function saveAttachmentsForModel(object $model, ?array $files): bool
|
||||
{
|
||||
if(!($model instanceof Model)) {
|
||||
return false; // @codeCoverageIgnore
|
||||
}
|
||||
Log::debug(sprintf('Now in saveAttachmentsForModel for model %s', \get_class($model)));
|
||||
if (\is_array($files)) {
|
||||
Log::debug('$files is an array.');
|
||||
@@ -236,6 +245,7 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
*
|
||||
* @return Attachment|null
|
||||
* @throws \Illuminate\Contracts\Encryption\EncryptException
|
||||
* @throws FireflyException
|
||||
*/
|
||||
protected function processFile(UploadedFile $file, Model $model): ?Attachment
|
||||
{
|
||||
@@ -257,6 +267,11 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
|
||||
$fileObject = $file->openFile('r');
|
||||
$fileObject->rewind();
|
||||
|
||||
if(0 === $file->getSize()) {
|
||||
throw new FireflyException('Cannot upload empty or non-existent file.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$content = $fileObject->fread($file->getSize());
|
||||
$encrypted = Crypt::encrypt($content);
|
||||
Log::debug(sprintf('Full file length is %d and upload size is %d.', \strlen($content), $file->getSize()));
|
||||
|
||||
@@ -23,7 +23,6 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Helpers\Attachments;
|
||||
|
||||
use FireflyIII\Models\Attachment;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\MessageBag;
|
||||
|
||||
@@ -84,10 +83,10 @@ interface AttachmentHelperInterface
|
||||
/**
|
||||
* Save attachments that got uploaded.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param object $model
|
||||
* @param null|array $files
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function saveAttachmentsForModel(Model $model, ?array $files): bool;
|
||||
public function saveAttachmentsForModel(object $model, ?array $files): bool;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class MetaPieChart.
|
||||
@@ -88,6 +89,11 @@ class MetaPieChart implements MetaPieChartInterface
|
||||
$this->budgets = new Collection;
|
||||
$this->categories = new Collection;
|
||||
$this->tags = new Collection;
|
||||
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace FireflyIII\Helpers\Collection;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Bill as BillModel;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
|
||||
/**
|
||||
* Class BillLine.
|
||||
@@ -42,6 +43,8 @@ class BillLine
|
||||
protected $max;
|
||||
/** @var string What was the min amount. */
|
||||
protected $min;
|
||||
/** @var TransactionCurrency The transaction currency */
|
||||
private $currency;
|
||||
/** @var Carbon Latest date that payment is expected. */
|
||||
private $endOfPayDate;
|
||||
/** @var Carbon Date of last hit */
|
||||
@@ -99,6 +102,22 @@ class BillLine
|
||||
$this->bill = $bill;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TransactionCurrency
|
||||
*/
|
||||
public function getCurrency(): TransactionCurrency
|
||||
{
|
||||
return $this->currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency $currency
|
||||
*/
|
||||
public function setCurrency(TransactionCurrency $currency): void
|
||||
{
|
||||
$this->currency = $currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of pay date getter.
|
||||
*
|
||||
|
||||
@@ -28,6 +28,7 @@ use Carbon\Carbon;
|
||||
use DB;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Filter\CountAttachmentsFilter;
|
||||
use FireflyIII\Helpers\Filter\DoubleTransactionFilter;
|
||||
use FireflyIII\Helpers\Filter\FilterInterface;
|
||||
use FireflyIII\Helpers\Filter\InternalTransferFilter;
|
||||
use FireflyIII\Helpers\Filter\NegativeAmountFilter;
|
||||
@@ -53,16 +54,14 @@ use Log;
|
||||
/**
|
||||
* Class TransactionCollector
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class TransactionCollector implements TransactionCollectorInterface
|
||||
{
|
||||
|
||||
/** @var array */
|
||||
private $accountIds = [];
|
||||
/** @var int */
|
||||
private $count = 0;
|
||||
|
||||
/** @var array */
|
||||
private $fields
|
||||
= [
|
||||
@@ -129,6 +128,16 @@ class TransactionCollector implements TransactionCollectorInterface
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filter
|
||||
*
|
||||
@@ -243,6 +252,30 @@ class TransactionCollector implements TransactionCollectorInterface
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LengthAwarePaginator
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function getPaginatedTransactions(): LengthAwarePaginator
|
||||
{
|
||||
if (true === $this->run) {
|
||||
throw new FireflyException('Cannot getPaginatedTransactions after run in TransactionCollector.');
|
||||
}
|
||||
$this->count();
|
||||
$set = $this->getTransactions();
|
||||
$journals = new LengthAwarePaginator($set, $this->count, $this->limit, $this->page);
|
||||
|
||||
return $journals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EloquentBuilder
|
||||
*/
|
||||
public function getQuery(): EloquentBuilder
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
@@ -299,30 +332,6 @@ class TransactionCollector implements TransactionCollectorInterface
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LengthAwarePaginator
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function getPaginatedTransactions(): LengthAwarePaginator
|
||||
{
|
||||
if (true === $this->run) {
|
||||
throw new FireflyException('Cannot getPaginatedTransactions after run in TransactionCollector.');
|
||||
}
|
||||
$this->count();
|
||||
$set = $this->getTransactions();
|
||||
$journals = new LengthAwarePaginator($set, $this->count, $this->limit, $this->page);
|
||||
|
||||
return $journals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EloquentBuilder
|
||||
*/
|
||||
public function getQuery(): EloquentBuilder
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TransactionCollectorInterface
|
||||
*/
|
||||
@@ -774,14 +783,15 @@ class TransactionCollector implements TransactionCollectorInterface
|
||||
{
|
||||
// create all possible filters:
|
||||
$filters = [
|
||||
InternalTransferFilter::class => new InternalTransferFilter($this->accountIds),
|
||||
OpposingAccountFilter::class => new OpposingAccountFilter($this->accountIds),
|
||||
TransferFilter::class => new TransferFilter,
|
||||
PositiveAmountFilter::class => new PositiveAmountFilter,
|
||||
NegativeAmountFilter::class => new NegativeAmountFilter,
|
||||
SplitIndicatorFilter::class => new SplitIndicatorFilter,
|
||||
CountAttachmentsFilter::class => new CountAttachmentsFilter,
|
||||
TransactionViewFilter::class => new TransactionViewFilter,
|
||||
InternalTransferFilter::class => new InternalTransferFilter($this->accountIds),
|
||||
OpposingAccountFilter::class => new OpposingAccountFilter($this->accountIds),
|
||||
TransferFilter::class => new TransferFilter,
|
||||
PositiveAmountFilter::class => new PositiveAmountFilter,
|
||||
NegativeAmountFilter::class => new NegativeAmountFilter,
|
||||
SplitIndicatorFilter::class => new SplitIndicatorFilter,
|
||||
CountAttachmentsFilter::class => new CountAttachmentsFilter,
|
||||
TransactionViewFilter::class => new TransactionViewFilter,
|
||||
DoubleTransactionFilter::class => new DoubleTransactionFilter,
|
||||
];
|
||||
Log::debug(sprintf('Will run %d filters on the set.', \count($this->filters)));
|
||||
foreach ($this->filters as $enabled) {
|
||||
|
||||
60
app/Helpers/Filter/DoubleTransactionFilter.php
Normal file
60
app/Helpers/Filter/DoubleTransactionFilter.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* DoubleTransactionFilter.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\Helpers\Filter;
|
||||
|
||||
|
||||
use FireflyIII\Models\Transaction;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
*
|
||||
* Used when the final collection contains double transactions, which can happen when viewing the tag report.
|
||||
* Class DoubleTransactionFilter
|
||||
*/
|
||||
class DoubleTransactionFilter implements FilterInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Apply the filter.
|
||||
*
|
||||
* @param Collection $set
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function filter(Collection $set): Collection
|
||||
{
|
||||
$count = [];
|
||||
$result = new Collection;
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($set as $transaction) {
|
||||
$id = (int)$transaction->id;
|
||||
$count[$id] = isset($count[$id]) ? $count[$id] + 1 : 1;
|
||||
if (1 === $count[$id]) {
|
||||
$result->push($transaction);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ namespace FireflyIII\Helpers\Filter;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use Log;
|
||||
/**
|
||||
* Class TransferFilter.
|
||||
*
|
||||
@@ -49,6 +49,7 @@ class TransferFilter implements FilterInterface
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($set as $transaction) {
|
||||
if (TransactionType::TRANSFER !== $transaction->transaction_type_type) {
|
||||
Log::debug(sprintf('Transaction #%d is not a transfer, add it.', $transaction->id));
|
||||
$new->push($transaction);
|
||||
continue;
|
||||
}
|
||||
@@ -60,11 +61,16 @@ class TransferFilter implements FilterInterface
|
||||
sort($accountIds);
|
||||
sort($transactionIds);
|
||||
$key = $journalId . '-' . implode(',', $transactionIds) . '-' . implode(',', $accountIds) . '-' . $amount;
|
||||
Log::debug(sprintf('Current transaction key is "%s"', $key));
|
||||
if (!isset($count[$key])) {
|
||||
Log::debug(sprintf('First instance of transaction #%d, add it.', $transaction->id));
|
||||
// not yet counted? add to new set and count it:
|
||||
$new->push($transaction);
|
||||
$count[$key] = 1;
|
||||
}
|
||||
if (isset($count[$key])) {
|
||||
Log::debug(sprintf('Second instance of transaction #%d, do NOT add it.', $transaction->id));
|
||||
}
|
||||
}
|
||||
|
||||
return $new;
|
||||
|
||||
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Helpers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class FiscalHelper.
|
||||
@@ -38,6 +39,10 @@ class FiscalHelper implements FiscalHelperInterface
|
||||
public function __construct()
|
||||
{
|
||||
$this->useCustomFiscalYear = app('preferences')->get('customFiscalYear', false)->data;
|
||||
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,6 +40,16 @@ class Help implements HelpInterface
|
||||
/** @var string The user agent. */
|
||||
protected $userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get from cache.
|
||||
*
|
||||
|
||||
@@ -51,6 +51,11 @@ class BalanceReportHelper implements BalanceReportHelperInterface
|
||||
public function __construct(BudgetRepositoryInterface $budgetRepository)
|
||||
{
|
||||
$this->budgetRepository = $budgetRepository;
|
||||
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,6 +27,7 @@ use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class BudgetReportHelper.
|
||||
@@ -46,6 +47,11 @@ class BudgetReportHelper implements BudgetReportHelperInterface
|
||||
public function __construct(BudgetRepositoryInterface $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,6 +48,16 @@ class NetWorth implements NetWorthInterface
|
||||
/** @var User */
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user's net worth in an array with the following layout:
|
||||
*
|
||||
|
||||
@@ -30,7 +30,7 @@ use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use Log;
|
||||
/**
|
||||
* Class PopupReport.
|
||||
*
|
||||
@@ -38,6 +38,16 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
class PopupReport implements PopupReportInterface
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the tranactions for one account and one budget.
|
||||
*
|
||||
|
||||
@@ -32,7 +32,7 @@ use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use Log;
|
||||
/**
|
||||
* Class ReportHelper.
|
||||
*
|
||||
@@ -52,6 +52,12 @@ class ReportHelper implements ReportHelperInterface
|
||||
public function __construct(BudgetRepositoryInterface $budgetRepository)
|
||||
{
|
||||
$this->budgetRepository = $budgetRepository;
|
||||
|
||||
if ('testing' === env('APP_ENV')) {
|
||||
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', \get_class($this)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,6 +98,7 @@ class ReportHelper implements ReportHelperInterface
|
||||
|
||||
$billLine = new BillLine;
|
||||
$billLine->setBill($bill);
|
||||
$billLine->setCurrency($bill->transactionCurrency);
|
||||
$billLine->setPayDate($payDate);
|
||||
$billLine->setEndOfPayDate($endOfPayPeriod);
|
||||
$billLine->setMin((string)$bill->amount_min);
|
||||
|
||||
@@ -29,6 +29,7 @@ use FireflyIII\Http\Requests\AccountFormRequest;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use Illuminate\Http\Request;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -82,12 +83,10 @@ class CreateController extends Controller
|
||||
$debt = $this->repository->getAccountTypeByType(AccountType::DEBT);
|
||||
$loan = $this->repository->getAccountTypeByType(AccountType::LOAN);
|
||||
$mortgage = $this->repository->getAccountTypeByType(AccountType::MORTGAGE);
|
||||
$creditCard = $this->repository->getAccountTypeByType(AccountType::CREDITCARD);
|
||||
$liabilityTypes = [
|
||||
$debt->id => (string)trans('firefly.account_type_' . AccountType::DEBT),
|
||||
$loan->id => (string)trans('firefly.account_type_' . AccountType::LOAN),
|
||||
$mortgage->id => (string)trans('firefly.account_type_' . AccountType::MORTGAGE),
|
||||
$creditCard->id => (string)trans('firefly.account_type_' . AccountType::CREDITCARD),
|
||||
];
|
||||
asort($liabilityTypes);
|
||||
|
||||
@@ -132,6 +131,8 @@ class CreateController extends Controller
|
||||
$request->session()->flash('success', (string)trans('firefly.stored_new_account', ['name' => $account->name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
|
||||
|
||||
// update preferences if necessary:
|
||||
$frontPage = app('preferences')->get('frontPageAccounts', [])->data;
|
||||
if (AccountType::ASSET === $account->accountType->type && \count($frontPage) > 0) {
|
||||
|
||||
@@ -90,12 +90,10 @@ class EditController extends Controller
|
||||
$debt = $this->repository->getAccountTypeByType(AccountType::DEBT);
|
||||
$loan = $this->repository->getAccountTypeByType(AccountType::LOAN);
|
||||
$mortgage = $this->repository->getAccountTypeByType(AccountType::MORTGAGE);
|
||||
$creditCard = $this->repository->getAccountTypeByType(AccountType::CREDITCARD);
|
||||
$liabilityTypes = [
|
||||
$debt->id => (string)trans('firefly.account_type_' . AccountType::DEBT),
|
||||
$loan->id => (string)trans('firefly.account_type_' . AccountType::LOAN),
|
||||
$mortgage->id => (string)trans('firefly.account_type_' . AccountType::MORTGAGE),
|
||||
$creditCard->id => (string)trans('firefly.account_type_' . AccountType::CREDITCARD),
|
||||
];
|
||||
asort($liabilityTypes);
|
||||
|
||||
|
||||
@@ -123,7 +123,6 @@ class ReconcileController extends Controller
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Illuminate\View\View
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function reconcile(Account $account, Carbon $start = null, Carbon $end = null)
|
||||
{
|
||||
|
||||
@@ -64,8 +64,8 @@ class LinkController extends Controller
|
||||
$subTitleIcon = 'fa-link';
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (true !== session('link_types.create.fromStore')) {
|
||||
$this->rememberPreviousUri('link_types.create.uri');
|
||||
if (true !== session('link-types.create.fromStore')) {
|
||||
$this->rememberPreviousUri('link-types.create.uri');
|
||||
}
|
||||
|
||||
return view('admin.link.create', compact('subTitle', 'subTitleIcon'));
|
||||
@@ -100,7 +100,7 @@ class LinkController extends Controller
|
||||
}
|
||||
}
|
||||
// put previous url in session
|
||||
$this->rememberPreviousUri('link_types.delete.uri');
|
||||
$this->rememberPreviousUri('link-types.delete.uri');
|
||||
|
||||
return view('admin.link.delete', compact('linkType', 'subTitle', 'moveTo', 'count'));
|
||||
}
|
||||
@@ -123,7 +123,7 @@ class LinkController extends Controller
|
||||
$request->session()->flash('success', (string)trans('firefly.deleted_link_type', ['name' => $name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
return redirect($this->getPreviousUri('link_types.delete.uri'));
|
||||
return redirect($this->getPreviousUri('link-types.delete.uri'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,10 +145,10 @@ class LinkController extends Controller
|
||||
$subTitleIcon = 'fa-link';
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (true !== session('link_types.edit.fromUpdate')) {
|
||||
$this->rememberPreviousUri('link_types.edit.uri'); // @codeCoverageIgnore
|
||||
if (true !== session('link-types.edit.fromUpdate')) {
|
||||
$this->rememberPreviousUri('link-types.edit.uri'); // @codeCoverageIgnore
|
||||
}
|
||||
$request->session()->forget('link_types.edit.fromUpdate');
|
||||
$request->session()->forget('link-types.edit.fromUpdate');
|
||||
|
||||
return view('admin.link.edit', compact('subTitle', 'subTitleIcon', 'linkType'));
|
||||
}
|
||||
@@ -207,10 +207,10 @@ class LinkController extends Controller
|
||||
];
|
||||
$linkType = $repository->store($data);
|
||||
$request->session()->flash('success', (string)trans('firefly.stored_new_link_type', ['name' => $linkType->name]));
|
||||
$redirect = redirect($this->getPreviousUri('link_types.create.uri'));
|
||||
$redirect = redirect($this->getPreviousUri('link-types.create.uri'));
|
||||
if (1 === (int)$request->get('create_another')) {
|
||||
// set value so create routine will not overwrite URL:
|
||||
$request->session()->put('link_types.create.fromStore', true);
|
||||
$request->session()->put('link-types.create.fromStore', true);
|
||||
|
||||
$redirect = redirect(route('admin.links.create'))->withInput();
|
||||
}
|
||||
@@ -245,10 +245,10 @@ class LinkController extends Controller
|
||||
|
||||
$request->session()->flash('success', (string)trans('firefly.updated_link_type', ['name' => $linkType->name]));
|
||||
app('preferences')->mark();
|
||||
$redirect = redirect($this->getPreviousUri('link_types.edit.uri'));
|
||||
$redirect = redirect($this->getPreviousUri('link-types.edit.uri'));
|
||||
if (1 === (int)$request->get('return_to_edit')) {
|
||||
// set value so edit routine will not overwrite URL:
|
||||
$request->session()->put('link_types.edit.fromUpdate', true);
|
||||
$request->session()->put('link-types.edit.fromUpdate', true);
|
||||
|
||||
$redirect = redirect(route('admin.links.edit', [$linkType->id]))->withInput(['return_to_edit' => 1]);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ use FireflyIII\User;
|
||||
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class ForgotPasswordController
|
||||
@@ -58,6 +59,13 @@ class ForgotPasswordController extends Controller
|
||||
*/
|
||||
public function sendResetLinkEmail(Request $request, UserRepositoryInterface $repository)
|
||||
{
|
||||
$loginProvider = envNonEmpty('LOGIN_PROVIDER','eloquent');
|
||||
if ('eloquent' !== $loginProvider) {
|
||||
$message = sprintf('Cannot reset password when authenticating over "%s".', $loginProvider);
|
||||
Log::error($message);
|
||||
return view('error', compact('message'));
|
||||
}
|
||||
|
||||
$this->validateEmail($request);
|
||||
|
||||
// verify if the user is not a demo user. If so, we give him back an error.
|
||||
@@ -90,6 +98,13 @@ class ForgotPasswordController extends Controller
|
||||
*/
|
||||
public function showLinkRequestForm()
|
||||
{
|
||||
$loginProvider = envNonEmpty('LOGIN_PROVIDER','eloquent');
|
||||
if ('eloquent' !== $loginProvider) {
|
||||
$message = sprintf('Cannot reset password when authenticating over "%s".', $loginProvider);
|
||||
|
||||
return view('error', compact('message'));
|
||||
}
|
||||
|
||||
// is allowed to?
|
||||
$singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data;
|
||||
$userCount = User::count();
|
||||
|
||||
@@ -129,8 +129,9 @@ class LoginController extends Controller
|
||||
*/
|
||||
public function showLoginForm(Request $request)
|
||||
{
|
||||
$count = DB::table('users')->count();
|
||||
if (0 === $count) {
|
||||
$count = DB::table('users')->count();
|
||||
$loginProvider = envNonEmpty('LOGIN_PROVIDER','eloquent');
|
||||
if (0 === $count && 'eloquent' === $loginProvider) {
|
||||
return redirect(route('register')); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
@@ -141,13 +142,20 @@ class LoginController extends Controller
|
||||
$singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data;
|
||||
$userCount = User::count();
|
||||
$allowRegistration = true;
|
||||
$allowReset = true;
|
||||
if (true === $singleUserMode && $userCount > 0) {
|
||||
$allowRegistration = false;
|
||||
}
|
||||
|
||||
// single user mode is ignored when the user is not using eloquent:
|
||||
if ('eloquent' !== $loginProvider) {
|
||||
$allowRegistration = false;
|
||||
$allowReset = false;
|
||||
}
|
||||
|
||||
$email = $request->old('email');
|
||||
$remember = $request->old('remember');
|
||||
|
||||
return view('auth.login', compact('allowRegistration', 'email', 'remember'));
|
||||
return view('auth.login', compact('allowRegistration', 'email', 'remember','allowReset'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,9 +71,19 @@ class RegisterController extends Controller
|
||||
public function register(Request $request)
|
||||
{
|
||||
// is allowed to?
|
||||
$singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data;
|
||||
$userCount = User::count();
|
||||
if (true === $singleUserMode && $userCount > 0) {
|
||||
$allowRegistration = true;
|
||||
$loginProvider = envNonEmpty('LOGIN_PROVIDER','eloquent');
|
||||
$singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data;
|
||||
$userCount = User::count();
|
||||
if (true === $singleUserMode && $userCount > 0 && 'eloquent' === $loginProvider) {
|
||||
$allowRegistration = false;
|
||||
}
|
||||
|
||||
if ('eloquent' !== $loginProvider) {
|
||||
$allowRegistration = false;
|
||||
}
|
||||
|
||||
if (false === $allowRegistration) {
|
||||
$message = 'Registration is currently not available.';
|
||||
|
||||
return view('error', compact('message'));
|
||||
@@ -102,13 +112,25 @@ class RegisterController extends Controller
|
||||
*/
|
||||
public function showRegistrationForm(Request $request)
|
||||
{
|
||||
// is demo site?
|
||||
$isDemoSite = FireflyConfig::get('is_demo_site', config('firefly.configuration.is_demo_site'))->data;
|
||||
$allowRegistration = true;
|
||||
$loginProvider = envNonEmpty('LOGIN_PROVIDER','eloquent');
|
||||
$isDemoSite = FireflyConfig::get('is_demo_site', config('firefly.configuration.is_demo_site'))->data;
|
||||
$singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data;
|
||||
$userCount = User::count();
|
||||
|
||||
// is allowed to?
|
||||
$singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data;
|
||||
$userCount = User::count();
|
||||
if (true === $singleUserMode && $userCount > 0) {
|
||||
if (true === $isDemoSite) {
|
||||
$allowRegistration = false;
|
||||
}
|
||||
|
||||
if (true === $singleUserMode && $userCount > 0 && 'eloquent' === $loginProvider) {
|
||||
$allowRegistration = false;
|
||||
}
|
||||
|
||||
if ('eloquent' !== $loginProvider) {
|
||||
$allowRegistration = false;
|
||||
}
|
||||
|
||||
if (false === $allowRegistration) {
|
||||
$message = 'Registration is currently not available.';
|
||||
|
||||
return view('error', compact('message'));
|
||||
|
||||
@@ -28,6 +28,7 @@ use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Foundation\Auth\ResetsPasswords;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Password;
|
||||
|
||||
/**
|
||||
* Class ResetPasswordController
|
||||
@@ -70,7 +71,15 @@ class ResetPasswordController extends Controller
|
||||
*/
|
||||
public function showResetForm(Request $request, $token = null)
|
||||
{
|
||||
// is allowed to?
|
||||
$loginProvider = envNonEmpty('LOGIN_PROVIDER','eloquent');
|
||||
if ('eloquent' !== $loginProvider) {
|
||||
$message = sprintf('Cannot reset password when authenticating over "%s".', $loginProvider);
|
||||
|
||||
return view('error', compact('message'));
|
||||
}
|
||||
|
||||
|
||||
// is allowed to register?
|
||||
$singleUserMode = FireflyConfig::get('single_user_mode', config('firefly.configuration.single_user_mode'))->data;
|
||||
$userCount = User::count();
|
||||
$allowRegistration = true;
|
||||
@@ -83,4 +92,42 @@ class ResetPasswordController extends Controller
|
||||
['token' => $token, 'email' => $request->email, 'allowRegistration' => $allowRegistration]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the given user's password.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function reset(Request $request)
|
||||
{
|
||||
$loginProvider = envNonEmpty('LOGIN_PROVIDER','eloquent');
|
||||
if ('eloquent' !== $loginProvider) {
|
||||
$message = sprintf('Cannot reset password when authenticating over "%s".', $loginProvider);
|
||||
|
||||
return view('error', compact('message'));
|
||||
}
|
||||
|
||||
$this->validate($request, $this->rules(), $this->validationErrorMessages());
|
||||
|
||||
// Here we will attempt to reset the user's password. If it is successful we
|
||||
// will update the password on an actual user model and persist it to the
|
||||
// database. Otherwise we will parse the error and return the response.
|
||||
$response = $this->broker()->reset(
|
||||
$this->credentials($request), function ($user, $password) {
|
||||
$this->resetPassword($user, $password);
|
||||
}
|
||||
);
|
||||
|
||||
// If the password was successfully reset, we will redirect the user back to
|
||||
// the application's home authenticated view. If there is an error we can
|
||||
// redirect them back to where they came from with their error message.
|
||||
return $response === Password::PASSWORD_RESET
|
||||
? $this->sendResetResponse($request, $response)
|
||||
: $this->sendResetFailedResponse($request, $response);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Controllers\DateCalculation;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
|
||||
@@ -63,7 +64,6 @@ class IndexController extends Controller
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show all budgets.
|
||||
*
|
||||
@@ -134,5 +134,29 @@ class IndexController extends Controller
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function reorder(Request $request, BudgetRepositoryInterface $repository): JsonResponse
|
||||
{
|
||||
$budgetIds = $request->get('budgetIds');
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
|
||||
$currentOrder = (($page - 1) * $pageSize) + 1;
|
||||
foreach ($budgetIds as $budgetId) {
|
||||
$budgetId = (int)$budgetId;
|
||||
$budget = $repository->findNull($budgetId);
|
||||
if (null !== $budget) {
|
||||
$repository->setBudgetOrder($budget, $currentOrder);
|
||||
}
|
||||
$currentOrder++;
|
||||
}
|
||||
|
||||
return response()->json(['OK']);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ class ShowController extends Controller
|
||||
'firefly.without_budget_between',
|
||||
['start' => $start->formatLocalized($this->monthAndDayFormat), 'end' => $end->formatLocalized($this->monthAndDayFormat)]
|
||||
);
|
||||
$periods = $this->getBudgetPeriodOverview();
|
||||
$periods = $this->getNoBudgetPeriodOverview($end);
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ class ShowController extends Controller
|
||||
$subTitleIcon = 'fa-bar-chart';
|
||||
$page = (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$periods = $this->getCategoryPeriodOverview($category, $start);
|
||||
$periods = $this->getCategoryPeriodOverview($category, $end);
|
||||
$path = route('categories.show', [$category->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
|
||||
$subTitle = trans(
|
||||
'firefly.journals_in_period_for_category',
|
||||
|
||||
@@ -210,23 +210,25 @@ class AccountController extends Controller
|
||||
$budgetIds[] = $budgetId;
|
||||
if (!isset($result[$combi])) {
|
||||
$result[$combi] = [
|
||||
'total' => '0',
|
||||
'budget_id' => $budgetId,
|
||||
'currency' => $currencyName,
|
||||
'total' => '0',
|
||||
'budget_id' => $budgetId,
|
||||
'currency' => $currencyName,
|
||||
'currency_symbol' => $transaction->transaction_currency_symbol,
|
||||
];
|
||||
}
|
||||
$result[$combi]['total'] = bcadd($transaction->transaction_amount, $result[$combi]['total']);
|
||||
}
|
||||
|
||||
$names = $this->getBudgetNames($budgetIds);
|
||||
|
||||
foreach ($result as $row) {
|
||||
$budgetId = $row['budget_id'];
|
||||
$name = $names[$budgetId];
|
||||
$label = (string)trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency']]);
|
||||
$chartData[$label] = $row['total'];
|
||||
$chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol']];
|
||||
}
|
||||
|
||||
$data = $this->generator->pieChart($chartData);
|
||||
$data = $this->generator->multiCurrencyPieChart($chartData);
|
||||
$cache->store($data);
|
||||
|
||||
return response()->json($data);
|
||||
@@ -276,6 +278,7 @@ class AccountController extends Controller
|
||||
$result = [];
|
||||
$chartData = [];
|
||||
$categoryIds = [];
|
||||
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$jrnlCatId = (int)$transaction->transaction_journal_category_id;
|
||||
@@ -286,24 +289,25 @@ class AccountController extends Controller
|
||||
$categoryIds[] = $categoryId;
|
||||
if (!isset($result[$combi])) {
|
||||
$result[$combi] = [
|
||||
'total' => '0',
|
||||
'category_id' => $categoryId,
|
||||
'currency' => $currencyName,
|
||||
'total' => '0',
|
||||
'category_id' => $categoryId,
|
||||
'currency' => $currencyName,
|
||||
'currency_symbol' => $transaction->transaction_currency_symbol,
|
||||
];
|
||||
}
|
||||
$result[$combi]['total'] = bcadd($transaction->transaction_amount, $result[$combi]['total']);
|
||||
}
|
||||
|
||||
$names = $this->getCategoryNames(array_keys($result));
|
||||
$names = $this->getCategoryNames($categoryIds);
|
||||
|
||||
foreach ($result as $row) {
|
||||
$categoryId = $row['category_id'];
|
||||
$name = $names[$categoryId] ?? '(unknown)';
|
||||
$label = (string)trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency']]);
|
||||
$chartData[$label] = $row['total'];
|
||||
$chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol']];
|
||||
}
|
||||
|
||||
$data = $this->generator->pieChart($chartData);
|
||||
$data = $this->generator->multiCurrencyPieChart($chartData);
|
||||
$cache->store($data);
|
||||
|
||||
return response()->json($data);
|
||||
@@ -381,6 +385,7 @@ class AccountController extends Controller
|
||||
$transactions = $collector->getTransactions();
|
||||
$result = [];
|
||||
$chartData = [];
|
||||
$categoryIds = [];
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$jrnlCatId = (int)$transaction->transaction_journal_category_id;
|
||||
@@ -391,22 +396,23 @@ class AccountController extends Controller
|
||||
$categoryIds[] = $categoryId;
|
||||
if (!isset($result[$combi])) {
|
||||
$result[$combi] = [
|
||||
'total' => '0',
|
||||
'category_id' => $categoryId,
|
||||
'currency' => $currencyName,
|
||||
'total' => '0',
|
||||
'category_id' => $categoryId,
|
||||
'currency' => $currencyName,
|
||||
'currency_symbol' => $transaction->transaction_currency_symbol,
|
||||
];
|
||||
}
|
||||
$result[$combi]['total'] = bcadd($transaction->transaction_amount, $result[$combi]['total']);
|
||||
}
|
||||
|
||||
$names = $this->getCategoryNames(array_keys($result));
|
||||
$names = $this->getCategoryNames($categoryIds);
|
||||
foreach ($result as $row) {
|
||||
$categoryId = $row['category_id'];
|
||||
$name = $names[$categoryId] ?? '(unknown)';
|
||||
$label = (string)trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency']]);
|
||||
$chartData[$label] = $row['total'];
|
||||
$chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol']];
|
||||
}
|
||||
$data = $this->generator->pieChart($chartData);
|
||||
$data = $this->generator->multiCurrencyPieChart($chartData);
|
||||
$cache->store($data);
|
||||
|
||||
return response()->json($data);
|
||||
@@ -525,7 +531,7 @@ class AccountController extends Controller
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('chart.account.revenue-accounts');
|
||||
if ($cache->has()) {
|
||||
//return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
$start->subDay();
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class BillController extends Controller
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('chart.bill.frontpage');
|
||||
if ($cache->has()) {
|
||||
//return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
/** @var CurrencyRepositoryInterface $currencyRepository */
|
||||
$currencyRepository = app(CurrencyRepositoryInterface::class);
|
||||
|
||||
@@ -32,6 +32,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use FireflyIII\Support\Http\Controllers\DateCalculation;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
@@ -40,6 +41,7 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
use DateCalculation;
|
||||
/** @var GeneratorInterface Chart generation methods. */
|
||||
protected $generator;
|
||||
|
||||
@@ -97,17 +99,36 @@ class CategoryController extends Controller
|
||||
'entries' => [], 'type' => 'line', 'fill' => false,
|
||||
],
|
||||
];
|
||||
|
||||
while ($start <= $end) {
|
||||
$currentEnd = app('navigation')->endOfPeriod($start, $range);
|
||||
$spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $start, $currentEnd);
|
||||
$earned = $repository->earnedInPeriod(new Collection([$category]), $accounts, $start, $currentEnd);
|
||||
$sum = bcadd($spent, $earned);
|
||||
$label = app('navigation')->periodShow($start, $range);
|
||||
$chartData[0]['entries'][$label] = round(bcmul($spent, '-1'), 12);
|
||||
$chartData[1]['entries'][$label] = round($earned, 12);
|
||||
$chartData[2]['entries'][$label] = round($sum, 12);
|
||||
$start = app('navigation')->addPeriod($start, $range, 0);
|
||||
$step = $this->calculateStep($start, $end);
|
||||
$current = clone $start;
|
||||
switch ($step) {
|
||||
case '1D':
|
||||
while ($current <= $end) {
|
||||
$spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $current, $current);
|
||||
$earned = $repository->earnedInPeriod(new Collection([$category]), $accounts, $current, $current);
|
||||
$sum = bcadd($spent, $earned);
|
||||
$label = app('navigation')->periodShow($current, $step);
|
||||
$chartData[0]['entries'][$label] = round(bcmul($spent, '-1'), 12);
|
||||
$chartData[1]['entries'][$label] = round($earned, 12);
|
||||
$chartData[2]['entries'][$label] = round($sum, 12);
|
||||
$current->addDay();
|
||||
}
|
||||
break;
|
||||
case '1W':
|
||||
case '1M':
|
||||
case '1Y':
|
||||
while ($current <= $end) {
|
||||
$currentEnd = app('navigation')->endOfPeriod($current, $range);
|
||||
$spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $current, $currentEnd);
|
||||
$earned = $repository->earnedInPeriod(new Collection([$category]), $accounts, $current, $currentEnd);
|
||||
$sum = bcadd($spent, $earned);
|
||||
$label = app('navigation')->periodShow($current, $step);
|
||||
$chartData[0]['entries'][$label] = round(bcmul($spent, '-1'), 12);
|
||||
$chartData[1]['entries'][$label] = round($earned, 12);
|
||||
$chartData[2]['entries'][$label] = round($sum, 12);
|
||||
$current= app('navigation')->addPeriod($current, $step, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$data = $this->generator->multiSet($chartData);
|
||||
@@ -135,7 +156,7 @@ class CategoryController extends Controller
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('chart.category.frontpage');
|
||||
if ($cache->has()) {
|
||||
//return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// currency repos:
|
||||
@@ -168,7 +189,7 @@ class CategoryController extends Controller
|
||||
$noCategory = $repository->spentInPeriodPcWoCategory(new Collection, $start, $end);
|
||||
foreach ($noCategory as $currencyId => $spent) {
|
||||
$currencies[$currencyId] = $currencies[$currencyId] ?? $currencyRepository->findNull($currencyId);
|
||||
$tempData[] = [
|
||||
$tempData[] = [
|
||||
'name' => trans('firefly.no_category'),
|
||||
'spent' => bcmul($spent, '-1'),
|
||||
'spent_float' => (float)bcmul($spent, '-1'),
|
||||
|
||||
@@ -47,6 +47,8 @@ class JobStatusController extends Controller
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
// set time limit to zero to prevent timeouts.
|
||||
set_time_limit(0);
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
@@ -83,7 +85,7 @@ class JobStatusController extends Controller
|
||||
*/
|
||||
public function json(ImportJob $importJob): JsonResponse
|
||||
{
|
||||
$count = \count($importJob->transactions);
|
||||
$count = $this->repository->countTransactions($importJob);
|
||||
$json = [
|
||||
'status' => $importJob->status,
|
||||
'errors' => $importJob->errors,
|
||||
|
||||
@@ -48,7 +48,9 @@ class JavascriptController extends Controller
|
||||
*/
|
||||
public function accounts(AccountRepositoryInterface $repository, CurrencyRepositoryInterface $currencyRepository): Response
|
||||
{
|
||||
$accounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::DEBT,AccountType::LOAN,AccountType::MORTGAGE, AccountType::CREDITCARD]);
|
||||
$accounts = $repository->getAccountsByType(
|
||||
[AccountType::DEFAULT, AccountType::ASSET, AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE, AccountType::CREDITCARD]
|
||||
);
|
||||
$preference = app('preferences')->get('currencyPreference', config('firefly.default_currency', 'EUR'));
|
||||
/** @noinspection NullPointerExceptionInspection */
|
||||
$default = $currencyRepository->findByCodeNull($preference->data);
|
||||
@@ -124,6 +126,7 @@ class JavascriptController extends Controller
|
||||
/** @noinspection NullPointerExceptionInspection */
|
||||
$lang = $pref->data;
|
||||
$dateRange = $this->getDateRangeConfig();
|
||||
$uid = substr(hash('sha256', auth()->user()->id . auth()->user()->email), 0, 12);
|
||||
|
||||
$data = [
|
||||
'currencyCode' => $currency->code,
|
||||
@@ -133,6 +136,7 @@ class JavascriptController extends Controller
|
||||
'language' => $lang,
|
||||
'dateRangeTitle' => $dateRange['title'],
|
||||
'dateRangeConfig' => $dateRange['configuration'],
|
||||
'uid' => $uid,
|
||||
];
|
||||
$request->session()->keep(['two-factor-secret']);
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Json;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Account;
|
||||
@@ -36,157 +37,153 @@ use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Class AutoCompleteController.
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.TooManyPublicMethods)
|
||||
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
||||
*/
|
||||
class AutoCompleteController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns a JSON list of all accounts.
|
||||
*
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function allAccounts(AccountRepositoryInterface $repository): JsonResponse
|
||||
{
|
||||
$return = array_unique(
|
||||
$repository->getAccountsByType(
|
||||
[AccountType::REVENUE, AccountType::EXPENSE, AccountType::BENEFICIARY, AccountType::DEFAULT, AccountType::ASSET]
|
||||
)->pluck('name')->toArray()
|
||||
);
|
||||
sort($return);
|
||||
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* List of all journals.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param TransactionCollectorInterface $collector
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function allTransactionJournals(TransactionCollectorInterface $collector): JsonResponse
|
||||
public function allTransactionJournals(Request $request, TransactionCollectorInterface $collector): JsonResponse
|
||||
{
|
||||
$search = (string)$request->get('search');
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('ac-all-journals');
|
||||
// very unlikely a user will actually search for this string.
|
||||
$key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search;
|
||||
$cache->addProperty($key);
|
||||
if ($cache->has()) {
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
// find everything:
|
||||
$collector->setLimit(250)->setPage(1);
|
||||
$return = array_unique($collector->getTransactions()->pluck('description')->toArray());
|
||||
sort($return);
|
||||
$return = array_values(array_unique($collector->getTransactions()->pluck('description')->toArray()));
|
||||
|
||||
if ('' !== $search) {
|
||||
$return = array_values(
|
||||
array_unique(
|
||||
array_filter(
|
||||
$return, function (string $value) use ($search) {
|
||||
return !(false === stripos($value, $search));
|
||||
}, ARRAY_FILTER_USE_BOTH
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
$cache->store($return);
|
||||
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON list of all bills.
|
||||
*
|
||||
* @param BillRepositoryInterface $repository
|
||||
* @param Request $request
|
||||
* @param string $subject
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function bills(BillRepositoryInterface $repository): JsonResponse
|
||||
public function autoComplete(Request $request, string $subject): JsonResponse
|
||||
{
|
||||
$return = array_unique(
|
||||
$repository->getActiveBills()->pluck('name')->toArray()
|
||||
);
|
||||
sort($return);
|
||||
$search = (string)$request->get('search');
|
||||
$unfiltered = null;
|
||||
$filtered = null;
|
||||
|
||||
return response()->json($return);
|
||||
// search for all accounts.
|
||||
if ('all-accounts' === $subject) {
|
||||
$unfiltered = $this->getAccounts(
|
||||
[AccountType::REVENUE, AccountType::EXPENSE, AccountType::BENEFICIARY, AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN,
|
||||
AccountType::DEBT, AccountType::MORTGAGE]
|
||||
);
|
||||
}
|
||||
|
||||
// search for expense accounts.
|
||||
if ('expense-accounts' === $subject) {
|
||||
$unfiltered = $this->getAccounts([AccountType::EXPENSE, AccountType::BENEFICIARY]);
|
||||
}
|
||||
|
||||
// search for revenue accounts.
|
||||
if ('revenue-accounts' === $subject) {
|
||||
$unfiltered = $this->getAccounts([AccountType::REVENUE]);
|
||||
}
|
||||
|
||||
// search for asset accounts.
|
||||
if ('asset-accounts' === $subject) {
|
||||
$unfiltered = $this->getAccounts([AccountType::ASSET, AccountType::DEFAULT]);
|
||||
}
|
||||
|
||||
// search for categories.
|
||||
if ('categories' === $subject) {
|
||||
$unfiltered = $this->getCategories();
|
||||
}
|
||||
|
||||
// search for budgets.
|
||||
if ('budgets' === $subject) {
|
||||
$unfiltered = $this->getBudgets();
|
||||
}
|
||||
|
||||
// search for tags
|
||||
if ('tags' === $subject) {
|
||||
$unfiltered = $this->getTags();
|
||||
}
|
||||
|
||||
// search for bills
|
||||
if ('bills' === $subject) {
|
||||
$unfiltered = $this->getBills();
|
||||
}
|
||||
// search for currency names.
|
||||
if ('currency-names' === $subject) {
|
||||
$unfiltered = $this->getCurrencyNames();
|
||||
}
|
||||
if ('transaction_types' === $subject) {
|
||||
$unfiltered = $this->getTransactionTypes();
|
||||
}
|
||||
if ('transaction-types' === $subject) {
|
||||
$unfiltered = $this->getTransactionTypes();
|
||||
}
|
||||
|
||||
// filter results
|
||||
$filtered = $this->filterResult($unfiltered, $search);
|
||||
|
||||
if (null === $filtered) {
|
||||
throw new FireflyException(sprintf('Auto complete handler cannot handle "%s"', $subject)); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return response()->json($filtered);
|
||||
}
|
||||
|
||||
/**
|
||||
* List of budgets.
|
||||
*
|
||||
* @param BudgetRepositoryInterface $repository
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function budgets(BudgetRepositoryInterface $repository): JsonResponse
|
||||
{
|
||||
$return = array_unique($repository->getBudgets()->pluck('name')->toArray());
|
||||
sort($return);
|
||||
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of categories.
|
||||
*
|
||||
* @param CategoryRepositoryInterface $repository
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function categories(CategoryRepositoryInterface $repository): JsonResponse
|
||||
{
|
||||
$return = array_unique($repository->getCategories()->pluck('name')->toArray());
|
||||
sort($return);
|
||||
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* List of currency names.
|
||||
*
|
||||
* @param CurrencyRepositoryInterface $repository
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function currencyNames(CurrencyRepositoryInterface $repository): JsonResponse
|
||||
{
|
||||
$return = $repository->get()->pluck('name')->toArray();
|
||||
sort($return);
|
||||
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON list of all beneficiaries.
|
||||
*
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function expenseAccounts(AccountRepositoryInterface $repository): JsonResponse
|
||||
{
|
||||
$set = $repository->getAccountsByType([AccountType::EXPENSE, AccountType::BENEFICIARY]);
|
||||
$filtered = $set->filter(
|
||||
function (Account $account) {
|
||||
if (true === $account->active) {
|
||||
return $account;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
$return = array_unique($filtered->pluck('name')->toArray());
|
||||
|
||||
sort($return);
|
||||
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* List of journals with their ID.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param TransactionCollectorInterface $collector
|
||||
* @param TransactionJournal $except
|
||||
* @param TransactionJournal $except
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function journalsWithId(TransactionCollectorInterface $collector, TransactionJournal $except): JsonResponse
|
||||
public function journalsWithId(Request $request, TransactionCollectorInterface $collector, TransactionJournal $except): JsonResponse
|
||||
{
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('recent-journals-id');
|
||||
|
||||
$search = (string)$request->get('search');
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('ac-expense-accounts');
|
||||
// very unlikely a user will actually search for this string.
|
||||
$key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search;
|
||||
$cache->addProperty($key);
|
||||
if ($cache->has()) {
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// find everything:
|
||||
$collector->setLimit(400)->setPage(1);
|
||||
$set = $collector->getTransactions()->pluck('description', 'journal_id')->toArray();
|
||||
$return = [];
|
||||
@@ -200,47 +197,19 @@ class AutoCompleteController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
$cache->store($return);
|
||||
sort($return);
|
||||
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* List of revenue accounts.
|
||||
*
|
||||
* @param AccountRepositoryInterface $repository
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function revenueAccounts(AccountRepositoryInterface $repository): JsonResponse
|
||||
{
|
||||
$set = $repository->getAccountsByType([AccountType::REVENUE]);
|
||||
$filtered = $set->filter(
|
||||
function (Account $account) {
|
||||
if (true === $account->active) {
|
||||
return $account;
|
||||
}
|
||||
|
||||
return false;
|
||||
if ('' !== $search) {
|
||||
$return = array_filter(
|
||||
$return, function (array $array) use ($search) {
|
||||
$haystack = $array['name'];
|
||||
$result = stripos($haystack, $search);
|
||||
return !(false === $result);
|
||||
}
|
||||
);
|
||||
$return = array_unique($filtered->pluck('name')->toArray());
|
||||
sort($return);
|
||||
);
|
||||
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON list of all beneficiaries.
|
||||
*
|
||||
* @param TagRepositoryInterface $tagRepository
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function tags(TagRepositoryInterface $tagRepository): JsonResponse
|
||||
{
|
||||
$return = array_unique($tagRepository->get()->pluck('tag')->toArray());
|
||||
sort($return);
|
||||
}
|
||||
$cache->store($return);
|
||||
|
||||
return response()->json($return);
|
||||
}
|
||||
@@ -248,13 +217,24 @@ class AutoCompleteController extends Controller
|
||||
/**
|
||||
* List of journals by type.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param TransactionCollectorInterface $collector
|
||||
* @param string $what
|
||||
* @param string $what
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function transactionJournals(TransactionCollectorInterface $collector, string $what): JsonResponse
|
||||
public function transactionJournals(Request $request, TransactionCollectorInterface $collector, string $what): JsonResponse
|
||||
{
|
||||
$search = (string)$request->get('search');
|
||||
$cache = new CacheProperties;
|
||||
$cache->addProperty('ac-revenue-accounts');
|
||||
// very unlikely a user will actually search for this string.
|
||||
$key = '' === $search ? 'skjf0893j89fj2398hd89dh289h2398hr7isd8900828u209ujnxs88929282u' : $search;
|
||||
$cache->addProperty($key);
|
||||
if ($cache->has()) {
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
// find everything:
|
||||
$type = config('firefly.transactionTypesByWhat.' . $what);
|
||||
$types = [$type];
|
||||
|
||||
@@ -262,21 +242,136 @@ class AutoCompleteController extends Controller
|
||||
$return = array_unique($collector->getTransactions()->pluck('description')->toArray());
|
||||
sort($return);
|
||||
|
||||
if ('' !== $search) {
|
||||
$return = array_values(
|
||||
array_unique(
|
||||
array_filter(
|
||||
$return, function (string $value) use ($search) {
|
||||
return !(false === stripos($value, $search));
|
||||
}, ARRAY_FILTER_USE_BOTH
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
$cache->store($return);
|
||||
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* List if transaction types.
|
||||
* @param array $unfiltered
|
||||
* @param string $query
|
||||
*
|
||||
* @param JournalRepositoryInterface $repository
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @return array|null
|
||||
*/
|
||||
public function transactionTypes(JournalRepositoryInterface $repository): JsonResponse
|
||||
private function filterResult(?array $unfiltered, string $query): ?array
|
||||
{
|
||||
$return = array_unique($repository->getTransactionTypes()->pluck('type')->toArray());
|
||||
if (null === $unfiltered) {
|
||||
return null; // @codeCoverageIgnore
|
||||
}
|
||||
if ('' === $query) {
|
||||
sort($unfiltered);
|
||||
|
||||
return $unfiltered;
|
||||
}
|
||||
$return = [];
|
||||
if ('' !== $query) {
|
||||
$return = array_values(
|
||||
array_filter(
|
||||
$unfiltered, function (string $value) use ($query) {
|
||||
return !(false === stripos($value, $query));
|
||||
}, ARRAY_FILTER_USE_BOTH
|
||||
)
|
||||
);
|
||||
}
|
||||
sort($return);
|
||||
|
||||
return response()->json($return);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param array $types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getAccounts(array $types): array
|
||||
{
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
// find everything:
|
||||
/** @var Collection $collection */
|
||||
$collection = $repository->getAccountsByType($types);
|
||||
$filtered = $collection->filter(
|
||||
function (Account $account) {
|
||||
return $account->active === true;
|
||||
}
|
||||
);
|
||||
$return = array_values(array_unique($filtered->pluck('name')->toArray()));
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getBills(): array
|
||||
{
|
||||
$repository = app(BillRepositoryInterface::class);
|
||||
|
||||
return array_unique($repository->getActiveBills()->pluck('name')->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getBudgets(): array
|
||||
{
|
||||
$repository = app(BudgetRepositoryInterface::class);
|
||||
|
||||
return array_unique($repository->getBudgets()->pluck('name')->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getCategories(): array
|
||||
{
|
||||
$repository = app(CategoryRepositoryInterface::class);
|
||||
|
||||
return array_unique($repository->getCategories()->pluck('name')->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getCurrencyNames(): array
|
||||
{
|
||||
/** @var CurrencyRepositoryInterface $repository */
|
||||
$repository = app(CurrencyRepositoryInterface::class);
|
||||
|
||||
return $repository->get()->pluck('name')->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getTags(): array
|
||||
{
|
||||
/** @var TagRepositoryInterface $repository */
|
||||
$repository = app(TagRepositoryInterface::class);
|
||||
|
||||
return array_unique($repository->get()->pluck('tag')->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getTransactionTypes(): array
|
||||
{
|
||||
$repository = app(JournalRepositoryInterface::class);
|
||||
|
||||
return array_unique($repository->getTransactionTypes()->pluck('type')->toArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,15 +111,49 @@ class ReconcileController extends Controller
|
||||
$cleared = $this->repository->getTransactionsById($clearedIds);
|
||||
$countCleared = 0;
|
||||
|
||||
Log::debug('Start transaction loop');
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$amount = bcadd($amount, $transaction->amount);
|
||||
}
|
||||
// find the account and opposing account for this transaction
|
||||
Log::debug(sprintf('Now at transaction #%d: %s', $transaction->journal_id, $transaction->description));
|
||||
$srcAccount = $this->accountRepos->findNull((int)$transaction->account_id);
|
||||
$dstAccount = $this->accountRepos->findNull((int)$transaction->opposing_account_id);
|
||||
$srcCurrency = (int)$this->accountRepos->getMetaValue($srcAccount, 'currency_id');
|
||||
$dstCurrency = (int)$this->accountRepos->getMetaValue($dstAccount, 'currency_id');
|
||||
|
||||
// is $account source or destination?
|
||||
if ($account->id === $srcAccount->id) {
|
||||
// source, and it matches the currency id or is 0
|
||||
if ($srcCurrency === $transaction->transaction_currency_id || 0 === $srcCurrency) {
|
||||
Log::debug(sprintf('Source matches currency: %s', $transaction->transaction_amount));
|
||||
$amount = bcadd($amount, $transaction->transaction_amount);
|
||||
}
|
||||
// destination, and it matches the foreign currency ID.
|
||||
if ($srcCurrency === $transaction->foreign_currency_id) {
|
||||
Log::debug(sprintf('Source matches foreign currency: %s', $transaction->transaction_foreign_amount));
|
||||
$amount = bcadd($amount, $transaction->transaction_foreign_amount);
|
||||
}
|
||||
}
|
||||
|
||||
if ($account->id === $dstAccount->id) {
|
||||
// destination, and it matches the currency id or is 0
|
||||
if ($dstCurrency === $transaction->transaction_currency_id || 0 === $dstCurrency) {
|
||||
Log::debug(sprintf('Destination matches currency: %s', app('steam')->negative($transaction->transaction_amount)));
|
||||
$amount = bcadd($amount, app('steam')->negative($transaction->transaction_amount));
|
||||
}
|
||||
// destination, and it matches the foreign currency ID.
|
||||
if ($dstCurrency === $transaction->foreign_currency_id) {
|
||||
Log::debug(sprintf('Destination matches foreign currency: %s', $transaction->transaction_foreign_amount));
|
||||
$amount = bcadd($amount, $transaction->transaction_foreign_amount);
|
||||
}
|
||||
}
|
||||
Log::debug(sprintf('Amount is now %s', $amount));
|
||||
}
|
||||
Log::debug('End transaction loop');
|
||||
/** @var Transaction $transaction */
|
||||
foreach ($cleared as $transaction) {
|
||||
if ($transaction->transactionJournal->date <= $end) {
|
||||
$clearedAmount = bcadd($clearedAmount, $transaction->amount); // @codeCoverageIgnore
|
||||
if ($transaction->date <= $end) {
|
||||
$clearedAmount = bcadd($clearedAmount, $transaction->transaction_amount); // @codeCoverageIgnore
|
||||
++$countCleared;
|
||||
}
|
||||
}
|
||||
@@ -201,6 +235,7 @@ class ReconcileController extends Controller
|
||||
Log::debug(sprintf('Could not render: %s', $e->getMessage()));
|
||||
$html = 'Could not render accounts.reconcile.transactions';
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return response()->json(['html' => $html, 'startBalance' => $startBalance, 'endBalance' => $endBalance]);
|
||||
|
||||
@@ -41,6 +41,7 @@ use FireflyIII\User;
|
||||
use Google2FA;
|
||||
use Hash;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Laravel\Passport\ClientRepository;
|
||||
use Log;
|
||||
@@ -71,6 +72,7 @@ class ProfileController extends Controller
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
|
||||
$this->middleware(IsDemoUser::class)->except(['index']);
|
||||
$this->middleware(IsSandStormUser::class)->except('index');
|
||||
}
|
||||
@@ -80,8 +82,15 @@ class ProfileController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function changeEmail()
|
||||
public function changeEmail(Request $request)
|
||||
{
|
||||
$loginProvider = config('firefly.login_provider');
|
||||
if ('eloquent' !== $loginProvider) {
|
||||
$request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => $loginProvider]));
|
||||
|
||||
return redirect(route('profile.index'));
|
||||
}
|
||||
|
||||
$title = auth()->user()->email;
|
||||
$email = auth()->user()->email;
|
||||
$subTitle = (string)trans('firefly.change_your_email');
|
||||
@@ -95,8 +104,15 @@ class ProfileController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function changePassword()
|
||||
public function changePassword(Request $request)
|
||||
{
|
||||
$loginProvider = config('firefly.login_provider');
|
||||
if ('eloquent' !== $loginProvider) {
|
||||
$request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => $loginProvider]));
|
||||
|
||||
return redirect(route('profile.index'));
|
||||
}
|
||||
|
||||
$title = auth()->user()->email;
|
||||
$subTitle = (string)trans('firefly.change_your_password');
|
||||
$subTitleIcon = 'fa-key';
|
||||
@@ -132,6 +148,10 @@ class ProfileController extends Controller
|
||||
*/
|
||||
public function confirmEmailChange(UserRepositoryInterface $repository, string $token)
|
||||
{
|
||||
$loginProvider = config('firefly.login_provider');
|
||||
if ('eloquent' !== $loginProvider) {
|
||||
throw new FireflyException('Cannot confirm email change when authentication provider is not local.');
|
||||
}
|
||||
// find preference with this token value.
|
||||
/** @var Collection $set */
|
||||
$set = app('preferences')->findByName('email_change_confirm_token');
|
||||
@@ -163,8 +183,12 @@ class ProfileController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function deleteAccount()
|
||||
public function deleteAccount(Request $request)
|
||||
{
|
||||
$loginProvider = config('firefly.login_provider');
|
||||
if ('eloquent' !== $loginProvider) {
|
||||
$request->session()->flash('warning', trans('firefly.delete_local_info_only', ['login_provider' => $loginProvider]));
|
||||
}
|
||||
$title = auth()->user()->email;
|
||||
$subTitle = (string)trans('firefly.delete_account');
|
||||
$subTitleIcon = 'fa-trash';
|
||||
@@ -216,6 +240,7 @@ class ProfileController extends Controller
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$loginProvider = config('firefly.login_provider');
|
||||
// check if client token thing exists (default one)
|
||||
$count = DB::table('oauth_clients')
|
||||
->where('personal_access_client', 1)
|
||||
@@ -241,7 +266,7 @@ class ProfileController extends Controller
|
||||
$accessToken = app('preferences')->set('access_token', $token);
|
||||
}
|
||||
|
||||
return view('profile.index', compact('subTitle', 'userId', 'accessToken', 'enabled2FA'));
|
||||
return view('profile.index', compact('subTitle', 'userId', 'accessToken', 'enabled2FA', 'loginProvider'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -254,6 +279,13 @@ class ProfileController extends Controller
|
||||
*/
|
||||
public function postChangeEmail(EmailFormRequest $request, UserRepositoryInterface $repository)
|
||||
{
|
||||
$loginProvider = config('firefly.login_provider');
|
||||
if ('eloquent' !== $loginProvider) {
|
||||
$request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => $loginProvider]));
|
||||
|
||||
return redirect(route('profile.index'));
|
||||
}
|
||||
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
$newEmail = $request->string('email');
|
||||
@@ -299,6 +331,13 @@ class ProfileController extends Controller
|
||||
*/
|
||||
public function postChangePassword(ProfileFormRequest $request, UserRepositoryInterface $repository)
|
||||
{
|
||||
$loginProvider = config('firefly.login_provider');
|
||||
if ('eloquent' !== $loginProvider) {
|
||||
$request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => $loginProvider]));
|
||||
|
||||
return redirect(route('profile.index'));
|
||||
}
|
||||
|
||||
// the request has already validated both new passwords must be equal.
|
||||
$current = $request->get('current_password');
|
||||
$new = $request->get('new_password');
|
||||
@@ -396,6 +435,11 @@ class ProfileController extends Controller
|
||||
*/
|
||||
public function undoEmailChange(UserRepositoryInterface $repository, string $token, string $hash)
|
||||
{
|
||||
$loginProvider = config('firefly.login_provider');
|
||||
if ('eloquent' !== $loginProvider) {
|
||||
throw new FireflyException('Cannot confirm email change when authentication provider is not local.');
|
||||
}
|
||||
|
||||
// find preference with this token value.
|
||||
$set = app('preferences')->findByName('email_change_undo_token');
|
||||
$user = null;
|
||||
|
||||
@@ -152,7 +152,7 @@ class SelectController extends Controller
|
||||
$limit = (int)config('firefly.test-triggers.limit');
|
||||
$range = (int)config('firefly.test-triggers.range');
|
||||
$matchingTransactions = new Collection;
|
||||
$strict = $request->get('strict') === '1';
|
||||
$strict = '1' === $request->get('strict');
|
||||
/** @var TransactionMatcher $matcher */
|
||||
$matcher = app(TransactionMatcher::class);
|
||||
$matcher->setLimit($limit);
|
||||
|
||||
@@ -192,7 +192,7 @@ class TagController extends Controller
|
||||
'firefly.journals_in_period_for_tag', ['tag' => $tag->tag, 'start' => $start->formatLocalized($this->monthAndDayFormat),
|
||||
'end' => $end->formatLocalized($this->monthAndDayFormat),]
|
||||
);
|
||||
$periods = $this->getTagPeriodOverview($tag);
|
||||
$periods = $this->getTagPeriodOverview($tag, $start);
|
||||
$path = route('tags.show', [$tag->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
|
||||
|
||||
/** @var TransactionCollectorInterface $collector */
|
||||
|
||||
@@ -22,6 +22,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Transaction;
|
||||
|
||||
use FireflyIII\Events\UpdatedTransactionJournal;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Account;
|
||||
@@ -161,9 +162,14 @@ class ConvertController extends Controller
|
||||
$errors = $this->repository->convert($journal, $destinationType, $source, $destination);
|
||||
|
||||
if ($errors->count() > 0) {
|
||||
Log::error('Errors while converting: ', $errors->toArray());
|
||||
return redirect(route('transactions.convert.index', [strtolower($destinationType->type), $journal->id]))->withErrors($errors)->withInput();
|
||||
}
|
||||
|
||||
// Success? Fire rules!
|
||||
event(new UpdatedTransactionJournal($journal));
|
||||
|
||||
|
||||
session()->flash('success', (string)trans('firefly.converted_to_' . $destinationType->type));
|
||||
|
||||
return redirect(route('transactions.show', [$journal->id]));
|
||||
|
||||
@@ -24,7 +24,9 @@ namespace FireflyIII\Http\Controllers\Transaction;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
|
||||
use FireflyIII\Helpers\Filter\InternalTransferFilter;
|
||||
use FireflyIII\Helpers\Filter\TransactionViewFilter;
|
||||
use FireflyIII\Helpers\Filter\TransferFilter;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\MassDeleteJournalRequest;
|
||||
use FireflyIII\Http\Requests\MassEditJournalRequest;
|
||||
@@ -147,6 +149,9 @@ class MassController extends Controller
|
||||
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
|
||||
$collector->setJournals($journals);
|
||||
$collector->addFilter(TransactionViewFilter::class);
|
||||
$collector->addFilter(TransferFilter::class);
|
||||
|
||||
|
||||
$collection = $collector->getTransactions();
|
||||
$transactions = $collection->map(
|
||||
function (Transaction $transaction) use ($transformer) {
|
||||
|
||||
@@ -68,7 +68,7 @@ class Authenticate
|
||||
*/
|
||||
public function handle($request, Closure $next, ...$guards)
|
||||
{
|
||||
$this->authenticate($guards);
|
||||
$this->authenticate($request, $guards);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
@@ -86,7 +86,7 @@ class Authenticate
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
*/
|
||||
protected function authenticate(array $guards)
|
||||
protected function authenticate($request, array $guards)
|
||||
{
|
||||
|
||||
if (empty($guards)) {
|
||||
|
||||
@@ -33,6 +33,8 @@ use Log;
|
||||
|
||||
/**
|
||||
* Class Installer
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
*/
|
||||
class Installer
|
||||
{
|
||||
@@ -48,6 +50,7 @@ class Installer
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||
*
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
|
||||
@@ -60,7 +60,7 @@ class IsDemoUser
|
||||
return response()->redirectTo($previous);
|
||||
}
|
||||
|
||||
return response()->redirectTo(route('index'));
|
||||
return response()->redirectTo(route('index')); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
|
||||
@@ -108,9 +108,11 @@ class Range
|
||||
private function loseItAll(Request $request): void
|
||||
{
|
||||
if ('sqlite' === getenv('DB_CONNECTION') && true === getenv('IS_DOCKER')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->flash(
|
||||
'error', 'You seem to be using SQLite in a Docker container. Don\'t do this. If the container restarts all your data will be gone.'
|
||||
);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ class Sandstorm
|
||||
* @param string $email
|
||||
*
|
||||
* @return User
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function createUser(string $email): User
|
||||
{
|
||||
|
||||
@@ -37,7 +37,6 @@ class SecureHeaders
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param string|null $guard
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -47,17 +46,18 @@ class SecureHeaders
|
||||
$google = '';
|
||||
$analyticsId = env('ANALYTICS_ID', '');
|
||||
if ('' !== $analyticsId) {
|
||||
$google = 'https://www.google-analytics.com/analytics.js';
|
||||
$google = 'www.googletagmanager.com/gtag/js'; // @codeCoverageIgnore
|
||||
}
|
||||
$csp = [
|
||||
"default-src 'none'",
|
||||
"object-src 'self'",
|
||||
sprintf("script-src 'self' 'unsafe-eval' 'unsafe-inline' %s", $google),
|
||||
"style-src 'self' 'unsafe-inline'",
|
||||
"base-uri 'self'",
|
||||
"form-action 'self'",
|
||||
"font-src 'self'",
|
||||
"connect-src 'self'",
|
||||
"img-src 'self' data:",
|
||||
"img-src 'self' data: https://api.tiles.mapbox.com",
|
||||
];
|
||||
|
||||
$featurePolicies = [
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace FireflyIII\Http\Requests;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Rules\UniqueIban;
|
||||
use FireflyIII\Rules\ZeroOrMore;
|
||||
|
||||
/**
|
||||
* Class AccountFormRequest.
|
||||
@@ -116,7 +117,7 @@ class AccountFormRequest extends Request
|
||||
];
|
||||
|
||||
if ('liabilities' === $this->get('what')) {
|
||||
$rules['openingBalance'] = 'numeric|required|more:0';
|
||||
$rules['openingBalance'] = ['numeric', 'required', new ZeroOrMore];
|
||||
$rules['openingBalanceDate'] = 'date|required';
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ class JournalFormRequest extends Request
|
||||
'piggy_bank_name' => null,
|
||||
'bill_id' => null,
|
||||
'bill_name' => null,
|
||||
'original-source' => sprintf('gui-v%s', config('firefly.version')),
|
||||
|
||||
// transaction data:
|
||||
'transactions' => [
|
||||
@@ -274,7 +275,12 @@ class JournalFormRequest extends Request
|
||||
$selectedCurrency = (int)($data['amount_currency_id_amount'] ?? 0);
|
||||
$accountCurrency = (int)($data['destination_account_currency'] ?? 0);
|
||||
$nativeAmount = (string)($data['native_amount'] ?? '');
|
||||
|
||||
Log::debug('Now in validateDeposit.');
|
||||
Log::debug(sprintf('SelectedCurrency is "%s", accountCurrency is "%s", native amount is "%s".', $selectedCurrency, $accountCurrency, $nativeAmount));
|
||||
|
||||
if ($selectedCurrency !== $accountCurrency && '' === $nativeAmount && 0 !== $selectedCurrency && 0 !== $accountCurrency) {
|
||||
Log::debug('Adding an error about missing native amount.');
|
||||
$validator->errors()->add('native_amount', (string)trans('validation.numeric_native'));
|
||||
|
||||
return;
|
||||
|
||||
@@ -208,8 +208,10 @@ class ReportFormRequest extends Request
|
||||
$repository = app(TagRepositoryInterface::class);
|
||||
$set = $this->get('tag');
|
||||
$collection = new Collection;
|
||||
Log::debug('Set is:', $set ?? []);
|
||||
if (\is_array($set)) {
|
||||
foreach ($set as $tagTag) {
|
||||
Log::debug(sprintf('Now searching for "%s"', $tagTag));
|
||||
$tag = $repository->findByTag($tagTag);
|
||||
if (null !== $tag) {
|
||||
$collection->push($tag);
|
||||
|
||||
@@ -27,6 +27,7 @@ use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* Class Request.
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @SuppressWarnings(PHPMD.NumberOfChildren)
|
||||
*/
|
||||
@@ -91,58 +92,7 @@ class Request extends FormRequest
|
||||
*/
|
||||
public function string(string $field): string
|
||||
{
|
||||
$string = $this->get($field) ?? '';
|
||||
$search = [
|
||||
"\u{0001}", // start of heading
|
||||
"\u{0002}", // start of text
|
||||
"\u{0003}", // end of text
|
||||
"\u{0004}", // end of transmission
|
||||
"\u{0005}", // enquiry
|
||||
"\u{0006}", // ACK
|
||||
"\u{0007}", // BEL
|
||||
"\u{0008}", // backspace
|
||||
"\u{000E}", // shift out
|
||||
"\u{000F}", // shift in
|
||||
"\u{0010}", // data link escape
|
||||
"\u{0011}", // DC1
|
||||
"\u{0012}", // DC2
|
||||
"\u{0013}", // DC3
|
||||
"\u{0014}", // DC4
|
||||
"\u{0015}", // NAK
|
||||
"\u{0016}", // SYN
|
||||
"\u{0017}", // ETB
|
||||
"\u{0018}", // CAN
|
||||
"\u{0019}", // EM
|
||||
"\u{001A}", // SUB
|
||||
"\u{001B}", // escape
|
||||
"\u{001C}", // file separator
|
||||
"\u{001D}", // group separator
|
||||
"\u{001E}", // record separator
|
||||
"\u{001F}", // unit separator
|
||||
"\u{007F}", // DEL
|
||||
"\u{00A0}", // non-breaking space
|
||||
"\u{1680}", // ogham space mark
|
||||
"\u{180E}", // mongolian vowel separator
|
||||
"\u{2000}", // en quad
|
||||
"\u{2001}", // em quad
|
||||
"\u{2002}", // en space
|
||||
"\u{2003}", // em space
|
||||
"\u{2004}", // three-per-em space
|
||||
"\u{2005}", // four-per-em space
|
||||
"\u{2006}", // six-per-em space
|
||||
"\u{2007}", // figure space
|
||||
"\u{2008}", // punctuation space
|
||||
"\u{2009}", // thin space
|
||||
"\u{200A}", // hair space
|
||||
"\u{200B}", // zero width space
|
||||
"\u{202F}", // narrow no-break space
|
||||
"\u{3000}", // ideographic space
|
||||
"\u{FEFF}", // zero width no -break space
|
||||
];
|
||||
$replace = "\x20"; // plain old normal space
|
||||
$string = str_replace($search, $replace, $string);
|
||||
|
||||
return trim($string);
|
||||
return app('steam')->cleanString((string)($this->get($field) ?? ''));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -75,32 +75,31 @@ class RuleFormRequest extends Request
|
||||
$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'));
|
||||
// some actions require text (aka context):
|
||||
$contextActions = implode(',', config('firefly.context-rule-actions'));
|
||||
|
||||
$titleRule = 'required|between:1,100|uniqueObjectForUser:rules,title';
|
||||
/** @var Rule $rule */
|
||||
$rule = $this->route()->parameter('rule');
|
||||
// some triggers require text (aka context):
|
||||
$contextTriggers = implode(',', config('firefly.context-rule-triggers'));
|
||||
|
||||
if (null !== $rule) {
|
||||
$titleRule = 'required|between:1,100|uniqueObjectForUser:rules,title,' . $rule->id;
|
||||
}
|
||||
// initial set of rules:
|
||||
$rules = [
|
||||
'title' => $titleRule,
|
||||
'title' => 'required|between:1,100|uniqueObjectForUser:rules,title',
|
||||
'description' => 'between:1,5000|nullable',
|
||||
'stop_processing' => 'boolean',
|
||||
'rule_group_id' => 'required|belongsToUser:rule_groups',
|
||||
'trigger' => 'required|in:store-journal,update-journal',
|
||||
'rule_triggers.*.name' => 'required|in:' . implode(',', $validTriggers),
|
||||
'rule_triggers.*.value' => 'required|min:1|ruleTriggerValue',
|
||||
'rule_triggers.*.value' => sprintf('required_if:rule_triggers.*.name,%s|min:1|ruleTriggerValue', $contextTriggers),
|
||||
'rule-actions.*.name' => 'required|in:' . implode(',', $validActions),
|
||||
'rule_actions.*.value' => sprintf('required_if:rule_actions.*.name,%s|min:1|ruleActionValue', $contextActions),
|
||||
'strict' => 'in:0,1',
|
||||
];
|
||||
// since Laravel does not support this stuff yet, here's a trick.
|
||||
for ($i = 0; $i < 10; ++$i) {
|
||||
$key = sprintf('rule_actions.%d.value', $i);
|
||||
$rule = sprintf('required-if:rule_actions.%d.name,%s|ruleActionValue', $i, $contextActions);
|
||||
$rules[$key] = $rule;
|
||||
|
||||
/** @var Rule $rule */
|
||||
$rule = $this->route()->parameter('rule');
|
||||
|
||||
if (null !== $rule) {
|
||||
$rules['title'] = 'required|between:1,100|uniqueObjectForUser:rules,title,' . $rule->id;
|
||||
}
|
||||
|
||||
return $rules;
|
||||
|
||||
@@ -168,8 +168,10 @@ class SplitJournalFormRequest extends Request
|
||||
/** @var array $array */
|
||||
foreach ($transactions as $array) {
|
||||
if (null !== $array['destination_id'] && null !== $array['source_id'] && $array['destination_id'] === $array['source_id']) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$validator->errors()->add('journal_source_id', (string)trans('validation.source_equals_destination'));
|
||||
$validator->errors()->add('journal_destination_id', (string)trans('validation.source_equals_destination'));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
/**
|
||||
* Class RuleFormRequest.
|
||||
* Class TestRuleFormRequest.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
|
||||
@@ -91,11 +91,13 @@ class Amount implements ConverterInterface
|
||||
|
||||
return $value;
|
||||
}
|
||||
// @codeCoverageIgnoreStart
|
||||
Log::debug(sprintf('Final value is: "%s"', $value));
|
||||
$formatted = sprintf('%01.12f', $value);
|
||||
Log::debug(sprintf('Is formatted to : "%s"', $formatted));
|
||||
|
||||
return $formatted;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user