mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-08-22 13:19:29 +00:00
Compare commits
167 Commits
4.8.1.3
...
4.8.2-beta
Author | SHA1 | Date | |
---|---|---|---|
|
6b2b2aa1e1 | ||
|
55e2f31531 | ||
|
99c9a0fec5 | ||
|
075c06fb86 | ||
|
9293674131 | ||
|
e9172033bb | ||
|
e54dc4c1b4 | ||
|
fcd6b89a43 | ||
|
67db25b2cf | ||
|
68863abbc7 | ||
|
26a4b6844e | ||
|
292fb3fbc8 | ||
|
501efe507f | ||
|
adc48ce094 | ||
|
2a934edf4f | ||
|
4b9d1d23ca | ||
|
8a9e12c2b9 | ||
|
88f1adf650 | ||
|
8ce156cf93 | ||
|
6843c81114 | ||
|
f82d0dda0a | ||
|
d2a8f969d9 | ||
|
c79ded2012 | ||
|
765e4e3c3b | ||
|
3c25148f3f | ||
|
dc0e8528c8 | ||
|
34e7455d67 | ||
|
9332808d7f | ||
|
16a4adcd07 | ||
|
140ccbce3f | ||
|
97c8594dc4 | ||
|
adc4b00f5d | ||
|
c1bdb629a8 | ||
|
d8807e6ab7 | ||
|
e3418b1bd2 | ||
|
a7a76e32d6 | ||
|
1294705809 | ||
|
bb449e1940 | ||
|
828b9d32aa | ||
|
a67b0f78a4 | ||
|
5177f2bc87 | ||
|
f06e947706 | ||
|
380f59dab2 | ||
|
c558bc3247 | ||
|
25378b3f9a | ||
|
abf84e94b1 | ||
|
8baf29b835 | ||
|
d709a9489d | ||
|
33ce7c0767 | ||
|
ec54ec22f6 | ||
|
706e722c6f | ||
|
58ec0c4add | ||
|
88692f0058 | ||
|
a8af0fa678 | ||
|
0bdd48ffec | ||
|
766a82a983 | ||
|
d749d550ee | ||
|
2ea1852a94 | ||
|
4f44a42655 | ||
|
26ed00e7b5 | ||
|
51f25b2dce | ||
|
3fc653687c | ||
|
4cd824f3b7 | ||
|
a6af263b50 | ||
|
0844278eca | ||
|
1b63bfc3db | ||
|
a4906a2d21 | ||
|
c4256dd25b | ||
|
091ab17fdb | ||
|
02ddb95cf2 | ||
|
f2d43d71ad | ||
|
af611b78de | ||
|
724a1b8b08 | ||
|
34e70c7446 | ||
|
01f869f1b6 | ||
|
73a6db8eda | ||
|
0bbc008848 | ||
|
5e61fa785e | ||
|
c131e6ad9b | ||
|
cbc92d89e1 | ||
|
9a028d5002 | ||
|
bed182cf13 | ||
|
d5afba6137 | ||
|
6b4b69b695 | ||
|
b528fa2e5d | ||
|
f4b9f81e71 | ||
|
ca37d782ed | ||
|
f7c34db39b | ||
|
0d072b4ed9 | ||
|
13a29a66c8 | ||
|
cfd9828438 | ||
|
b4d565400e | ||
|
be0e2bf6a7 | ||
|
64a2f22b13 | ||
|
778e0bcbae | ||
|
92a1f12f6c | ||
|
ea0a440de0 | ||
|
92271ffe66 | ||
|
0499433cea | ||
|
dcdecfbc64 | ||
|
8b11afb83f | ||
|
6823adc976 | ||
|
7cfa916c61 | ||
|
2cf000a9fd | ||
|
b7862b7d69 | ||
|
4a11d65589 | ||
|
67ff88b24c | ||
|
d963ba0a2e | ||
|
b8c8aabbf4 | ||
|
a39bdc9cb0 | ||
|
18310641aa | ||
|
8386ab79f6 | ||
|
ffdeae91d7 | ||
|
73e3b9fe67 | ||
|
6a981fb691 | ||
|
576f2f2530 | ||
|
27668769cb | ||
|
def6ae6167 | ||
|
9f1fc0c2b8 | ||
|
5456a64d9f | ||
|
0e636e1ec1 | ||
|
bc469e8d52 | ||
|
4ba650afd7 | ||
|
54b42f0e46 | ||
|
516f2a1232 | ||
|
4b10cff5c2 | ||
|
50d3c36b6a | ||
|
3e40a6cf3d | ||
|
004d4a2d22 | ||
|
516ef79130 | ||
|
0135ae425f | ||
|
6c8a6e6823 | ||
|
6efe5cfd4d | ||
|
2d720f72bd | ||
|
0708ea875a | ||
|
0d924990c8 | ||
|
4d67b4d118 | ||
|
d57c5d3a20 | ||
|
8ee1b08c57 | ||
|
ee625a9c3f | ||
|
3e3729982b | ||
|
49933dae17 | ||
|
05a5782d5d | ||
|
4ad601f29d | ||
|
79debe4941 | ||
|
98ca25ebea | ||
|
004f725993 | ||
|
9ed32ad227 | ||
|
1ac5c4f670 | ||
|
24e7260fe7 | ||
|
5e9e749179 | ||
|
460906fdfe | ||
|
22f63fd951 | ||
|
de19bfe448 | ||
|
378bbf20de | ||
|
32ecac3b1f | ||
|
fee0eb68d5 | ||
|
bb6aa568ba | ||
|
2580927439 | ||
|
46afdc5418 | ||
|
9d82e3cfac | ||
|
2e265edec6 | ||
|
9ef1af176d | ||
|
49de827a49 | ||
|
c7d918499d | ||
|
3ace0d6f84 | ||
|
89d31ca71f |
@@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# build image
|
||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
|
||||
if [ "$TRAVIS_BRANCH" == "develop" ]; then
|
||||
echo "Build develop amd64"
|
||||
docker build -t jc5x/firefly-iii:develop-amd64 -f Dockerfile.amd64 .
|
||||
docker tag jc5x/firefly-iii:develop-amd64 jc5x/firefly-iii:develop-$VERSION-amd64
|
||||
docker push jc5x/firefly-iii:develop-amd64
|
||||
docker push jc5x/firefly-iii:develop-$VERSION-amd64
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_BRANCH" == "master" ]; then
|
||||
echo "Build master amd64"
|
||||
docker build -t jc5x/firefly-iii:latest-amd64 -f Dockerfile.amd64 .
|
||||
docker tag jc5x/firefly-iii:latest-amd64 jc5x/firefly-iii:release-$VERSION-amd64
|
||||
docker push jc5x/firefly-iii:latest-amd64
|
||||
docker push jc5x/firefly-iii:release-$VERSION-amd64
|
||||
fi
|
@@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||
|
||||
# get qemu-arm-static binary
|
||||
mkdir tmp
|
||||
pushd tmp && \
|
||||
curl -L -o qemu-arm-static.tar.gz https://github.com/multiarch/qemu-user-static/releases/download/v2.6.0/qemu-arm-static.tar.gz && \
|
||||
tar xzf qemu-arm-static.tar.gz && \
|
||||
popd
|
||||
|
||||
# build image
|
||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
|
||||
if [ "$TRAVIS_BRANCH" == "develop" ]; then
|
||||
echo "Build develop arm"
|
||||
docker build --tag jc5x/firefly-iii:develop-arm --file Dockerfile.arm .
|
||||
docker tag jc5x/firefly-iii:develop-arm jc5x/firefly-iii:develop-$VERSION-arm
|
||||
docker push jc5x/firefly-iii:develop-arm
|
||||
docker push jc5x/firefly-iii:develop-$VERSION-arm
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_BRANCH" == "master" ]; then
|
||||
echo "Build master arm"
|
||||
docker build --tag jc5x/firefly-iii:latest-arm --file Dockerfile.arm .
|
||||
docker tag jc5x/firefly-iii:latest-arm jc5x/firefly-iii:release-$VERSION-arm
|
||||
docker push jc5x/firefly-iii:latest-arm
|
||||
docker push jc5x/firefly-iii:release-$VERSION-arm
|
||||
fi
|
@@ -93,6 +93,7 @@ php artisan firefly-iii:fix-long-descriptions
|
||||
php artisan firefly-iii:report-empty-objects
|
||||
php artisan firefly-iii:report-sum
|
||||
php artisan firefly-iii:restore-oauth-keys
|
||||
php artisan firefly-iii:set-latest-version --james-is-cool
|
||||
|
||||
php artisan passport:install
|
||||
php artisan cache:clear
|
||||
|
@@ -1,35 +1,162 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ "$TRAVIS_BRANCH" == "develop" ]; then
|
||||
echo '{"experimental":true}' | sudo tee /etc/docker/daemon.json
|
||||
mkdir $HOME/.docker
|
||||
touch $HOME/.docker/config.json
|
||||
echo '{"experimental":"enabled"}' | sudo tee $HOME/.docker/config.json
|
||||
sudo service docker restart
|
||||
|
||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
|
||||
VERSION_TARGET=jc5x/firefly-iii:release-$VERSION
|
||||
|
||||
# if the github branch is develop, only push the 'develop' tag
|
||||
if [ $TRAVIS_BRANCH == "develop" ]; then
|
||||
TARGET=jc5x/firefly-iii:develop
|
||||
ARM=jc5x/firefly-iii:develop-arm
|
||||
AMD=jc5x/firefly-iii:develop-amd64
|
||||
ARM32=jc5x/firefly-iii:develop-arm
|
||||
ARM64=jc5x/firefly-iii:develop-arm64
|
||||
AMD64=jc5x/firefly-iii:develop-amd64
|
||||
|
||||
docker manifest create $TARGET $AMD $ARM
|
||||
docker manifest annotate $TARGET $ARM --arch arm --os linux
|
||||
docker manifest annotate $TARGET $AMD --arch amd64 --os linux
|
||||
echo "GitHub branch is $TRAVIS_BRANCH."
|
||||
echo "Push develop-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
fi
|
||||
|
||||
echo "The version is $VERSION"
|
||||
# if branch = master AND channel = alpha, push 'alpha'
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "alpha" ]; then
|
||||
TARGET=jc5x/firefly-iii:alpha
|
||||
ARM32=jc5x/firefly-iii:alpha-arm
|
||||
ARM64=jc5x/firefly-iii:alpha-arm64
|
||||
AMD64=jc5x/firefly-iii:alpha-amd64
|
||||
|
||||
echo "GitHub branch is $TRAVIS_BRANCH."
|
||||
echo "Channel is $CHANNEL."
|
||||
echo "Push alpha-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
|
||||
echo "Push alpha-* builds to $VERSION_TARGET"
|
||||
|
||||
docker manifest create $VERSION_TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $VERSION_TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $VERSION_TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $VERSION_TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $VERSION_TARGET
|
||||
|
||||
fi
|
||||
|
||||
# if branch is master and channel is alpha, push 'alpha' and 'beta'.
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "beta" ]; then
|
||||
TARGET=jc5x/firefly-iii:alpha
|
||||
ARM32=jc5x/firefly-iii:beta-arm
|
||||
ARM64=jc5x/firefly-iii:beta-arm64
|
||||
AMD64=jc5x/firefly-iii:beta-amd64
|
||||
|
||||
echo "GitHub branch is $TRAVIS_BRANCH."
|
||||
echo "Channel is $CHANNEL."
|
||||
echo "Push beta-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
|
||||
TARGET=jc5x/firefly-iii:beta
|
||||
ARM32=jc5x/firefly-iii:beta-arm
|
||||
ARM64=jc5x/firefly-iii:beta-arm64
|
||||
AMD64=jc5x/firefly-iii:beta-amd64
|
||||
|
||||
echo "Push beta-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
|
||||
echo "Push beta-* builds to $VERSION_TARGET"
|
||||
|
||||
docker manifest create $VERSION_TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $VERSION_TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $VERSION_TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $VERSION_TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $VERSION_TARGET
|
||||
fi
|
||||
|
||||
# if branch is master and channel is stable, push 'alpha' and 'beta' and 'stable'.
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "stable" ]; then
|
||||
TARGET=jc5x/firefly-iii:alpha
|
||||
ARM32=jc5x/firefly-iii:stable-arm
|
||||
ARM64=jc5x/firefly-iii:stable-arm64
|
||||
AMD64=jc5x/firefly-iii:stable-amd64
|
||||
|
||||
echo "GitHub branch is $TRAVIS_BRANCH."
|
||||
echo "Channel is $CHANNEL."
|
||||
echo "Push stable-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
|
||||
TARGET=jc5x/firefly-iii:beta
|
||||
ARM32=jc5x/firefly-iii:stable-arm
|
||||
ARM64=jc5x/firefly-iii:stable-arm64
|
||||
AMD64=jc5x/firefly-iii:stable-amd64
|
||||
|
||||
echo "Push stable-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
|
||||
TARGET=jc5x/firefly-iii:stable
|
||||
ARM32=jc5x/firefly-iii:stable-arm
|
||||
ARM64=jc5x/firefly-iii:stable-arm64
|
||||
AMD64=jc5x/firefly-iii:stable-amd64
|
||||
|
||||
echo "Push stable-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
|
||||
if [ "$TRAVIS_BRANCH" == "master" ]; then
|
||||
TARGET=jc5x/firefly-iii:latest
|
||||
ARM=jc5x/firefly-iii:latest-arm
|
||||
AMD=jc5x/firefly-iii:latest-amd64
|
||||
ARM32=jc5x/firefly-iii:stable-arm
|
||||
ARM64=jc5x/firefly-iii:stable-arm64
|
||||
AMD64=jc5x/firefly-iii:stable-amd64
|
||||
|
||||
docker manifest create $TARGET $AMD $ARM
|
||||
docker manifest annotate $TARGET $ARM --arch arm --os linux
|
||||
docker manifest annotate $TARGET $AMD --arch amd64 --os linux
|
||||
echo "Push stable-* builds to $TARGET"
|
||||
|
||||
docker manifest create $TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
|
||||
# and another one for version specific:
|
||||
TARGET=jc5x/firefly-iii:release-$VERSION
|
||||
ARM=jc5x/firefly-iii:release-$VERSION-arm
|
||||
AMD=jc5x/firefly-iii:release-$VERSION-amd64
|
||||
echo "Push stable-* builds to $VERSION_TARGET"
|
||||
|
||||
docker manifest create $TARGET $AMD $ARM
|
||||
docker manifest annotate $TARGET $ARM --arch arm --os linux
|
||||
docker manifest annotate $TARGET $AMD --arch amd64 --os linux
|
||||
docker manifest push $TARGET
|
||||
docker manifest create $VERSION_TARGET $ARM32 $ARM64 $AMD64
|
||||
docker manifest annotate $VERSION_TARGET $ARM32 --arch arm --os linux
|
||||
docker manifest annotate $VERSION_TARGET $ARM64 --arch arm64 --os linux
|
||||
docker manifest annotate $VERSION_TARGET $AMD64 --arch amd64 --os linux
|
||||
docker manifest push $VERSION_TARGET
|
||||
fi
|
||||
|
||||
echo 'Done!'
|
||||
# done!
|
103
.deploy/docker/travis.sh
Executable file
103
.deploy/docker/travis.sh
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "travis.sh: I am building channel ${CHANNEL} for version ${VERSION} on architecture ${ARCH}, branch $TRAVIS_BRANCH."
|
||||
|
||||
echo '{"experimental":true}' | sudo tee /etc/docker/daemon.json
|
||||
mkdir $HOME/.docker
|
||||
touch $HOME/.docker/config.json
|
||||
echo '{"experimental":"enabled"}' | sudo tee $HOME/.docker/config.json
|
||||
sudo service docker restart
|
||||
|
||||
# First build amd64 image:
|
||||
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
|
||||
|
||||
if [ $ARCH == "arm" ]; then
|
||||
echo "Because architecture is $ARCH running some extra commands."
|
||||
docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||
|
||||
# get qemu-arm-static binary
|
||||
mkdir tmp
|
||||
pushd tmp && \
|
||||
curl -L -o qemu-arm-static.tar.gz https://github.com/multiarch/qemu-user-static/releases/download/v2.6.0/qemu-arm-static.tar.gz && \
|
||||
tar xzf qemu-arm-static.tar.gz && \
|
||||
popd
|
||||
fi
|
||||
|
||||
# if the github branch is develop, build and push develop. Don't push a version tag anymore.
|
||||
if [ $TRAVIS_BRANCH == "develop" ]; then
|
||||
LABEL=jc5x/firefly-iii:develop-$ARCH
|
||||
echo "GitHub branch is $TRAVIS_BRANCH. Will build and push $LABEL"
|
||||
docker build -t $LABEL -f Dockerfile.$ARCH .
|
||||
docker push $LABEL
|
||||
fi
|
||||
|
||||
# if branch = master AND channel = alpha, build and push 'alpha'
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "alpha" ]; then
|
||||
LABEL=jc5x/firefly-iii:alpha-$ARCH
|
||||
echo "GitHub branch is $TRAVIS_BRANCH and channel is $CHANNEL. Will build and push $LABEL"
|
||||
docker build -t $LABEL -f Dockerfile.$ARCH .
|
||||
docker push $LABEL
|
||||
fi
|
||||
|
||||
# if branch is master and channel is alpha, build and push 'alpha' and 'beta'.
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "beta" ]; then
|
||||
LABEL=jc5x/firefly-iii:beta-$ARCH
|
||||
echo "GitHub branch is $TRAVIS_BRANCH and channel is $CHANNEL. Will build and push $LABEL"
|
||||
docker build -t $LABEL -f Dockerfile.$ARCH .
|
||||
docker push $LABEL
|
||||
|
||||
# then tag as alpha and push:
|
||||
docker tag $LABEL jc5x/firefly-iii:alpha-$ARCH
|
||||
docker push jc5x/firefly-iii:alpha-$ARCH
|
||||
echo "Also tagged $LABEL as jc5x/firefly-iii:alpha-$ARCH and pushed"
|
||||
fi
|
||||
|
||||
# if branch is master and channel is stable, push 'alpha' and 'beta' and 'stable'.
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "stable" ]; then
|
||||
# first build stable
|
||||
LABEL=jc5x/firefly-iii:stable-$ARCH
|
||||
echo "GitHub branch is $TRAVIS_BRANCH and channel is $CHANNEL. Will build and push $LABEL"
|
||||
docker build -t $LABEL -f Dockerfile.$ARCH .
|
||||
docker push $LABEL
|
||||
|
||||
# then tag as beta and push:
|
||||
docker tag $LABEL jc5x/firefly-iii:beta-$ARCH
|
||||
docker push jc5x/firefly-iii:beta-$ARCH
|
||||
echo "Also tagged $LABEL as jc5x/firefly-iii:beta-$ARCH and pushed"
|
||||
|
||||
# then tag as alpha and push:
|
||||
docker tag $LABEL jc5x/firefly-iii:alpha-$ARCH
|
||||
docker push jc5x/firefly-iii:alpha-$ARCH
|
||||
echo "Also tagged $LABEL as jc5x/firefly-iii:alpha-$ARCH and pushed"
|
||||
|
||||
# then tag as latest and push:
|
||||
docker tag $LABEL jc5x/firefly-iii:latest-$ARCH
|
||||
docker push jc5x/firefly-iii:latest-$ARCH
|
||||
echo "Also tagged $LABEL as jc5x/firefly-iii:latest-$ARCH and pushed"
|
||||
fi
|
||||
|
||||
# push to channel 'version' if master + alpha
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "alpha"]; then
|
||||
LABEL=jc5x/firefly-iii:version-$VERSION-$ARCH
|
||||
echo "GitHub branch is $TRAVIS_BRANCH and channel is $CHANNEL. Will also push alpha as $LABEL"
|
||||
docker tag jc5x/firefly-iii:alpha-$ARCH $LABEL
|
||||
docker push $LABEL
|
||||
fi
|
||||
|
||||
# push to channel 'version' if master + beta
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "beta"]; then
|
||||
LABEL=jc5x/firefly-iii:version-$VERSION-$ARCH
|
||||
echo "GitHub branch is $TRAVIS_BRANCH and channel is $CHANNEL. Will also push beta as $LABEL"
|
||||
docker tag jc5x/firefly-iii:beta-$ARCH $LABEL
|
||||
docker push $LABEL
|
||||
fi
|
||||
|
||||
# push to channel 'version' if master + stable
|
||||
if [ $TRAVIS_BRANCH == "master" ] && [ $CHANNEL == "stable"]; then
|
||||
LABEL=jc5x/firefly-iii:version-$VERSION-$ARCH
|
||||
echo "GitHub branch is $TRAVIS_BRANCH and channel is $CHANNEL. Will also push beta as $LABEL"
|
||||
docker tag jc5x/firefly-iii:stable-$ARCH $LABEL
|
||||
docker push $LABEL
|
||||
fi
|
||||
|
||||
echo "Done!"
|
@@ -1,26 +0,0 @@
|
||||
server {
|
||||
listen 80 default_server;
|
||||
|
||||
server_name _ *.vm docker;
|
||||
|
||||
root "/app/public";
|
||||
index index.php;
|
||||
|
||||
include /opt/docker/etc/nginx/vhost.common.d/*.conf;
|
||||
}
|
||||
|
||||
##############
|
||||
# SSL
|
||||
##############
|
||||
|
||||
server {
|
||||
listen 443 default_server;
|
||||
|
||||
server_name _ *.vm docker;
|
||||
|
||||
root "/app/public";
|
||||
index index.php;
|
||||
|
||||
include /opt/docker/etc/nginx/vhost.common.d/*.conf;
|
||||
include /opt/docker/etc/nginx/vhost.ssl.conf;
|
||||
}
|
@@ -176,7 +176,6 @@ PUSHER_SECRET=
|
||||
PUSHER_ID=
|
||||
DEMO_USERNAME=
|
||||
DEMO_PASSWORD=
|
||||
IS_DOCKER=false
|
||||
IS_SANDSTORM=false
|
||||
IS_HEROKU=true
|
||||
BUNQ_USE_SANDBOX=false
|
||||
|
@@ -171,7 +171,6 @@ PUSHER_SECRET=
|
||||
PUSHER_ID=
|
||||
DEMO_USERNAME=
|
||||
DEMO_PASSWORD=
|
||||
IS_DOCKER=false
|
||||
IS_SANDSTORM=true
|
||||
IS_HEROKU=false
|
||||
BUNQ_USE_SANDBOX=false
|
||||
|
15
.env.example
15
.env.example
@@ -26,10 +26,13 @@ APP_URL=http://localhost
|
||||
TRUSTED_PROXIES=
|
||||
|
||||
# The log channel defines where your log entries go to.
|
||||
# 'daily' is the default logging mode giving you 5 daily rotated log files in /storage/logs/.
|
||||
# - Docker + versions <= 4.8.1.8 and before: use "stdout"
|
||||
# - Docker + versions > 4.8.1.8: use "docker_out"
|
||||
# - For everything else, use 'daily'
|
||||
|
||||
# Several other options exist. You can use 'single' for one big fat error log (not recommended).
|
||||
# Also available are 'syslog', 'errorlog' and 'stdout' which will log to the system itself.
|
||||
LOG_CHANNEL=daily
|
||||
LOG_CHANNEL=stdout
|
||||
|
||||
# Log level. You can set this from least severe to most severe:
|
||||
# debug, info, notice, warning, error, critical, alert, emergency
|
||||
@@ -38,7 +41,7 @@ LOG_CHANNEL=daily
|
||||
APP_LOG_LEVEL=notice
|
||||
|
||||
# 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
|
||||
# For other database types, please see the FAQ: https://docs.firefly-iii.org/support/faq
|
||||
DB_CONNECTION=pgsql
|
||||
DB_HOST=firefly_iii_db
|
||||
DB_PORT=5432
|
||||
@@ -76,7 +79,7 @@ COOKIE_DOMAIN=
|
||||
COOKIE_SECURE=false
|
||||
|
||||
# If you want Firefly III to mail you, update these settings
|
||||
# For instructions, see: https://firefly-iii.readthedocs.io/en/latest/installation/mail.html
|
||||
# For instructions, see: https://docs.firefly-iii.org/advanced-installation/email
|
||||
MAIL_DRIVER=log
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
@@ -121,7 +124,7 @@ ANALYTICS_ID=
|
||||
# Firefly III has two options for user authentication. "eloquent" is the default,
|
||||
# and "ldap" for LDAP servers.
|
||||
# For full instructions on these settings please visit:
|
||||
# https://firefly-iii.readthedocs.io/en/latest/installation/authentication.html
|
||||
# https://docs.firefly-iii.org/advanced-installation/authentication
|
||||
LOGIN_PROVIDER=eloquent
|
||||
|
||||
# LDAP connection configuration
|
||||
@@ -178,9 +181,9 @@ PUSHER_SECRET=
|
||||
PUSHER_ID=
|
||||
DEMO_USERNAME=
|
||||
DEMO_PASSWORD=
|
||||
IS_DOCKER=false
|
||||
USE_ENCRYPTION=false
|
||||
IS_SANDSTORM=false
|
||||
IS_DOCKER=false
|
||||
IS_HEROKU=false
|
||||
BUNQ_USE_SANDBOX=false
|
||||
FFIII_LAYOUT=v1
|
||||
|
2
.github/funding.yml
vendored
2
.github/funding.yml
vendored
@@ -1,5 +1,5 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
#github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
github: jc5
|
||||
patreon: JC5
|
||||
custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=44UKUT455HUFA
|
||||
|
2
.github/stale.yml
vendored
2
.github/stale.yml
vendored
@@ -13,8 +13,6 @@ exemptLabels:
|
||||
- enhancement
|
||||
- feature
|
||||
- bug
|
||||
- possible-bug
|
||||
- "possible bug"
|
||||
- announcement
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# 4.8.1.3
|
||||
# 4.8.1.4
|
||||
|
||||
- [Issue 2680](https://github.com/firefly-iii/firefly-iii/issues/2680) Upgrade routine would delete all transaction groups.
|
||||
|
||||
|
@@ -15,8 +15,8 @@ const pkgdef :Spk.PackageDefinition = (
|
||||
|
||||
manifest = (
|
||||
appTitle = (defaultText = "Firefly III"),
|
||||
appVersion = 38,
|
||||
appMarketingVersion = (defaultText = "4.8.1.2"),
|
||||
appVersion = 39,
|
||||
appMarketingVersion = (defaultText = "4.8.1.4"),
|
||||
|
||||
actions = [
|
||||
# Define your "new document" handlers here.
|
||||
|
39
.travis.yml
39
.travis.yml
@@ -1,9 +1,5 @@
|
||||
sudo: required
|
||||
language: bash
|
||||
env:
|
||||
- VERSION=4.8.1.3
|
||||
|
||||
dist: xenial
|
||||
|
||||
# safelist
|
||||
branches:
|
||||
@@ -14,16 +10,25 @@ branches:
|
||||
services:
|
||||
- docker
|
||||
|
||||
script:
|
||||
# enable experimental features.
|
||||
- echo '{"experimental":true}' | sudo tee /etc/docker/daemon.json
|
||||
- mkdir $HOME/.docker
|
||||
- touch $HOME/.docker/config.json
|
||||
- echo '{"experimental":"enabled"}' | sudo tee $HOME/.docker/config.json
|
||||
- sudo service docker restart
|
||||
- docker version -f '{{.Server.Experimental}}'
|
||||
- docker version
|
||||
# build everything
|
||||
- .deploy/docker/build-amd64.sh
|
||||
- .deploy/docker/build-arm.sh
|
||||
- .deploy/docker/manifest.sh
|
||||
jobs:
|
||||
include:
|
||||
- dist: xenial
|
||||
arch: amd64
|
||||
env: ARCH=amd64 CHANNEL=beta VERSION=4.8.2-beta.1
|
||||
stage: build
|
||||
script: ./.deploy/docker/travis.sh
|
||||
- dist: xenial
|
||||
arch: amd64
|
||||
env: ARCH=arm CHANNEL=beta VERSION=4.8.2-beta.1
|
||||
stage: build
|
||||
script: ./.deploy/docker/travis.sh
|
||||
- dist: xenial
|
||||
arch: arm64
|
||||
env: ARCH=arm64 CHANNEL=beta VERSION=4.8.2-beta.1
|
||||
stage: build
|
||||
script: ./.deploy/docker/travis.sh
|
||||
- dist: xenial
|
||||
arch: amd64
|
||||
env: CHANNEL=beta VERSION=4.8.2-beta.1
|
||||
stage: manifest
|
||||
script: ./.deploy/docker/manifest.sh
|
@@ -1,4 +1,7 @@
|
||||
FROM jc5x/firefly-iii-base-image:latest
|
||||
|
||||
# See also: https://github.com/JC5/firefly-iii-base-image
|
||||
|
||||
ENV FIREFLY_PATH=/var/www/firefly-iii COMPOSER_ALLOW_SUPERUSER=1
|
||||
LABEL version="1.5" maintainer="thegrumpydictator@gmail.com"
|
||||
|
||||
|
@@ -1,4 +1,7 @@
|
||||
FROM jc5x/firefly-iii-base-image:latest
|
||||
|
||||
# See also: https://github.com/JC5/firefly-iii-base-image
|
||||
|
||||
ENV FIREFLY_PATH=/var/www/firefly-iii COMPOSER_ALLOW_SUPERUSER=1
|
||||
LABEL version="1.5" maintainer="thegrumpydictator@gmail.com"
|
||||
|
||||
|
@@ -1,4 +1,7 @@
|
||||
FROM jc5x/firefly-iii-base-image:latest-arm
|
||||
|
||||
# See also: https://github.com/JC5/firefly-iii-base-image
|
||||
|
||||
ENV FIREFLY_PATH=/var/www/firefly-iii COMPOSER_ALLOW_SUPERUSER=1
|
||||
LABEL version="1.5" maintainer="thegrumpydictator@gmail.com"
|
||||
|
||||
|
@@ -1,25 +1,13 @@
|
||||
FROM arm32v7/php:7.2-apache-stretch
|
||||
ARG ARCH
|
||||
COPY tmp/qemu-arm-static /usr/bin/qemu-arm-static
|
||||
FROM jc5x/firefly-iii-base-image:latest-arm
|
||||
|
||||
# See also: https://github.com/JC5/firefly-iii-base-image
|
||||
|
||||
ENV FIREFLY_PATH=/var/www/firefly-iii COMPOSER_ALLOW_SUPERUSER=1
|
||||
LABEL version="1.5" maintainer="thegrumpydictator@gmail.com"
|
||||
|
||||
# Create volumes
|
||||
VOLUME $FIREFLY_PATH/storage/export $FIREFLY_PATH/storage/upload
|
||||
|
||||
# Install stuff Firefly III runs with & depends on: php extensions, locales, dev headers and composer
|
||||
RUN apt-get update && apt-get install -y locales unzip && apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ADD https://raw.githubusercontent.com/mlocati/docker-php-extension-installer/master/install-php-extensions /usr/local/bin/
|
||||
|
||||
RUN chmod uga+x /usr/local/bin/install-php-extensions && sync && \
|
||||
install-php-extensions --cleanup bcmath ldap gd pdo_pgsql pdo_sqlite pdo_mysql intl opcache memcached
|
||||
|
||||
RUN a2enmod rewrite && a2enmod ssl
|
||||
RUN echo "hu_HU.UTF-8 UTF-8\nro_RO.UTF-8 UTF-8\nnb_NO.UTF-8 UTF-8\nde_DE.UTF-8 UTF-8\ncs_CZ.UTF-8 UTF-8\nen_US.UTF-8 UTF-8\nes_ES.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8\nid_ID.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\nzh_TW.UTF-8 UTF-8\nzh_CN.UTF-8 UTF-8\n\n" > /etc/locale.gen
|
||||
RUN locale-gen
|
||||
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
||||
|
||||
# Copy in Firefly III source
|
||||
WORKDIR $FIREFLY_PATH
|
||||
ADD . $FIREFLY_PATH
|
||||
@@ -29,15 +17,6 @@ RUN chown -R www-data:www-data /var/www && \
|
||||
chmod -R 775 $FIREFLY_PATH/storage && \
|
||||
composer install --prefer-dist --no-dev --no-scripts --no-suggest
|
||||
|
||||
# copy ca certs to correct location
|
||||
COPY ./.deploy/docker/cacert.pem /usr/local/ssl/cert.pem
|
||||
|
||||
# copy Apache config to correct spot.
|
||||
COPY ./.deploy/docker/apache2.conf /etc/apache2/apache2.conf
|
||||
|
||||
# Enable default site (Firefly III)
|
||||
COPY ./.deploy/docker/apache-firefly.conf /etc/apache2/sites-available/000-default.conf
|
||||
|
||||
# Expose port 80
|
||||
EXPOSE 80
|
||||
|
||||
|
@@ -38,6 +38,7 @@ use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use League\Fractal\Resource\Collection as FractalCollection;
|
||||
use League\Fractal\Resource\Item;
|
||||
use Log;
|
||||
use function strlen;
|
||||
|
||||
/**
|
||||
@@ -97,10 +98,16 @@ class AttachmentController extends Controller
|
||||
public function download(Attachment $attachment): LaravelResponse
|
||||
{
|
||||
if (false === $attachment->uploaded) {
|
||||
throw new FireflyException('No file has been uploaded for this attachment (yet).');
|
||||
throw new FireflyException('200000: File has not been uploaded (yet).');
|
||||
}
|
||||
if (0 === $attachment->size) {
|
||||
throw new FireflyException('200000: File has not been uploaded (yet).');
|
||||
}
|
||||
if ($this->repository->exists($attachment)) {
|
||||
$content = $this->repository->getContent($attachment);
|
||||
if ('' === $content) {
|
||||
throw new FireflyException('200002: File is empty (zero bytes).');
|
||||
}
|
||||
$quoted = sprintf('"%s"', addcslashes(basename($attachment->filename), '"\\'));
|
||||
|
||||
/** @var LaravelResponse $response */
|
||||
@@ -118,7 +125,7 @@ class AttachmentController extends Controller
|
||||
|
||||
return $response;
|
||||
}
|
||||
throw new FireflyException('Could not find the indicated attachment. The file is no longer there.');
|
||||
throw new FireflyException('200003: File does not exist.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,6 +240,11 @@ class AttachmentController extends Controller
|
||||
/** @var AttachmentHelperInterface $helper */
|
||||
$helper = app(AttachmentHelperInterface::class);
|
||||
$body = $request->getContent();
|
||||
if ('' === $body) {
|
||||
Log::error('Body of attachment is empty.');
|
||||
|
||||
return response()->json([], 422);
|
||||
}
|
||||
$helper->saveAttachmentFromApi($attachment, $body);
|
||||
|
||||
return response()->json([], 204);
|
||||
|
@@ -211,20 +211,16 @@ class BillController extends Controller
|
||||
*/
|
||||
public function store(BillRequest $request): JsonResponse
|
||||
{
|
||||
$bill = $this->repository->store($request->getAll());
|
||||
if (null !== $bill) {
|
||||
$manager = $this->getManager();
|
||||
$bill = $this->repository->store($request->getAll());
|
||||
$manager = $this->getManager();
|
||||
|
||||
/** @var BillTransformer $transformer */
|
||||
$transformer = app(BillTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
/** @var BillTransformer $transformer */
|
||||
$transformer = app(BillTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($bill, $transformer, 'bills');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
throw new FireflyException('Could not store new bill.'); // @codeCoverageIgnore
|
||||
$resource = new Item($bill, $transformer, 'bills');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -187,19 +187,16 @@ class BudgetController extends Controller
|
||||
*/
|
||||
public function store(BudgetRequest $request): JsonResponse
|
||||
{
|
||||
$budget = $this->repository->store($request->getAll());
|
||||
if (null !== $budget) {
|
||||
$manager = $this->getManager();
|
||||
$budget = $this->repository->store($request->getAll());
|
||||
$manager = $this->getManager();
|
||||
|
||||
/** @var BudgetTransformer $transformer */
|
||||
$transformer = app(BudgetTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
/** @var BudgetTransformer $transformer */
|
||||
$transformer = app(BudgetTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($budget, $transformer, 'budgets');
|
||||
$resource = new Item($budget, $transformer, 'budgets');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
throw new FireflyException('Could not store new budget.'); // @codeCoverageIgnore
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -165,7 +165,7 @@ class BudgetLimitController extends Controller
|
||||
$data = $request->getAll();
|
||||
$budget = $this->repository->findNull($data['budget_id']);
|
||||
if (null === $budget) {
|
||||
throw new FireflyException('Unknown budget.');
|
||||
throw new FireflyException('200004: Budget does not exist.');
|
||||
}
|
||||
$data['budget'] = $budget;
|
||||
$budgetLimit = $this->blRepository->storeBudgetLimit($data);
|
||||
|
@@ -152,18 +152,15 @@ class CategoryController extends Controller
|
||||
public function store(CategoryRequest $request): JsonResponse
|
||||
{
|
||||
$category = $this->repository->store($request->getAll());
|
||||
if (null !== $category) {
|
||||
$manager = $this->getManager();
|
||||
$manager = $this->getManager();
|
||||
|
||||
/** @var CategoryTransformer $transformer */
|
||||
$transformer = app(CategoryTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
/** @var CategoryTransformer $transformer */
|
||||
$transformer = app(CategoryTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($category, $transformer, 'categories');
|
||||
$resource = new Item($category, $transformer, 'categories');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
throw new FireflyException('Could not store new category.'); // @codeCoverageIgnore
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -57,7 +57,7 @@ class ConfigurationController extends Controller
|
||||
$admin = auth()->user();
|
||||
|
||||
if (!$this->repository->hasRole($admin, 'owner')) {
|
||||
throw new FireflyException('No access to method.'); // @codeCoverageIgnore
|
||||
throw new FireflyException('200005: You need the "owner" role to do this.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
|
@@ -313,10 +313,10 @@ class CurrencyController extends Controller
|
||||
|
||||
if (!$this->userRepository->hasRole($admin, 'owner')) {
|
||||
// access denied:
|
||||
throw new FireflyException('No access to method, user is not owner.'); // @codeCoverageIgnore
|
||||
throw new FireflyException('200005: You need the "owner" role to do this.'); // @codeCoverageIgnore
|
||||
}
|
||||
if ($this->repository->currencyInUse($currency)) {
|
||||
throw new FireflyException('No access to method, currency is in use.'); // @codeCoverageIgnore
|
||||
throw new FireflyException('200006: Currency in use.'); // @codeCoverageIgnore
|
||||
}
|
||||
$this->repository->destroy($currency);
|
||||
|
||||
@@ -574,26 +574,21 @@ class CurrencyController extends Controller
|
||||
public function store(CurrencyRequest $request): JsonResponse
|
||||
{
|
||||
$currency = $this->repository->store($request->getAll());
|
||||
|
||||
if (null !== $currency) {
|
||||
if (true === $request->boolean('default')) {
|
||||
app('preferences')->set('currencyPreference', $currency->code);
|
||||
app('preferences')->mark();
|
||||
}
|
||||
$manager = $this->getManager();
|
||||
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
|
||||
$this->parameters->set('defaultCurrency', $defaultCurrency);
|
||||
|
||||
/** @var CurrencyTransformer $transformer */
|
||||
$transformer = app(CurrencyTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($currency, $transformer, 'currencies');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
if (true === $request->boolean('default')) {
|
||||
app('preferences')->set('currencyPreference', $currency->code);
|
||||
app('preferences')->mark();
|
||||
}
|
||||
throw new FireflyException('Could not store new currency.'); // @codeCoverageIgnore
|
||||
$manager = $this->getManager();
|
||||
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
|
||||
$this->parameters->set('defaultCurrency', $defaultCurrency);
|
||||
|
||||
/** @var CurrencyTransformer $transformer */
|
||||
$transformer = app(CurrencyTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($currency, $transformer, 'currencies');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -79,10 +79,10 @@ class CurrencyExchangeRateController extends Controller
|
||||
$toCurrency = $this->repository->findByCodeNull($request->get('to') ?? 'USD');
|
||||
|
||||
if (null === $fromCurrency) {
|
||||
throw new FireflyException('Unknown source currency.');
|
||||
throw new FireflyException('200007: Unknown source currency');
|
||||
}
|
||||
if (null === $toCurrency) {
|
||||
throw new FireflyException('Unknown destination currency.');
|
||||
throw new FireflyException('200007: Unknown destination currency');
|
||||
}
|
||||
|
||||
/** @var Carbon $dateObj */
|
||||
|
@@ -86,7 +86,7 @@ class LinkTypeController extends Controller
|
||||
public function delete(LinkType $linkType): JsonResponse
|
||||
{
|
||||
if (false === $linkType->editable) {
|
||||
throw new FireflyException(sprintf('You cannot delete this link type (#%d, "%s")', $linkType->id, $linkType->name));
|
||||
throw new FireflyException('200020: Link type cannot be changed.');
|
||||
}
|
||||
$this->repository->destroy($linkType);
|
||||
|
||||
@@ -160,7 +160,7 @@ class LinkTypeController extends Controller
|
||||
$admin = auth()->user();
|
||||
|
||||
if (!$this->userRepository->hasRole($admin, 'owner')) {
|
||||
throw new FireflyException('You need the "owner"-role to do this.');
|
||||
throw new FireflyException('200005: You need the "owner" role to do this.'); // @codeCoverageIgnore
|
||||
}
|
||||
$data = $request->getAll();
|
||||
// if currency ID is 0, find the currency by the code:
|
||||
@@ -247,14 +247,14 @@ class LinkTypeController extends Controller
|
||||
public function update(LinkTypeRequest $request, LinkType $linkType): JsonResponse
|
||||
{
|
||||
if (false === $linkType->editable) {
|
||||
throw new FireflyException(sprintf('You cannot edit this link type (#%d, "%s")', $linkType->id, $linkType->name));
|
||||
throw new FireflyException('200020: Link type cannot be changed.');
|
||||
}
|
||||
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
|
||||
if (!$this->userRepository->hasRole($admin, 'owner')) {
|
||||
throw new FireflyException('You need the "owner"-role to do this.');
|
||||
throw new FireflyException('200005: You need the "owner" role to do this.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$data = $request->getAll();
|
||||
|
@@ -181,19 +181,15 @@ class PiggyBankController extends Controller
|
||||
public function store(PiggyBankRequest $request): JsonResponse
|
||||
{
|
||||
$piggyBank = $this->repository->store($request->getAll());
|
||||
if (null !== $piggyBank) {
|
||||
$manager = $this->getManager();
|
||||
$manager = $this->getManager();
|
||||
|
||||
/** @var PiggyBankTransformer $transformer */
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
/** @var PiggyBankTransformer $transformer */
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($piggyBank, $transformer, 'piggy_banks');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
throw new FireflyException('Could not store new piggy bank.');
|
||||
$resource = new Item($piggyBank, $transformer, 'piggy_banks');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -236,7 +236,7 @@ class RecurrenceController extends Controller
|
||||
$result = $recurring->fire();
|
||||
} catch (FireflyException $e) {
|
||||
Log::error($e->getMessage());
|
||||
throw new FireflyException('Could not fire recurring cron job.');
|
||||
throw new FireflyException('200022: Error in cron job.');
|
||||
}
|
||||
if (false === $result) {
|
||||
return response()->json([], 204);
|
||||
|
@@ -257,7 +257,7 @@ class RuleGroupController extends Controller
|
||||
/** @var Collection $rules */
|
||||
$rules = $this->ruleGroupRepository->getActiveRules($group);
|
||||
if (0 === $rules->count()) {
|
||||
throw new FireflyException('No rules in this rule group.');
|
||||
throw new FireflyException('200023: No rules in this rule group.');
|
||||
}
|
||||
$parameters = $request->getTestParameters();
|
||||
$matchingTransactions = [];
|
||||
|
@@ -83,7 +83,8 @@ class AccountController extends Controller
|
||||
$transformer = app(AccountTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
$count = $accounts->count();
|
||||
$paginator = new LengthAwarePaginator($accounts, $count, $count, 1);
|
||||
$perPage = 0 === $count ? 1 : $count;
|
||||
$paginator = new LengthAwarePaginator($accounts, $count, $perPage, 1);
|
||||
|
||||
$resource = new FractalCollection($accounts, $transformer, 'accounts');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
116
app/Api/V1/Controllers/Search/TransferController.php
Normal file
116
app/Api/V1/Controllers/Search/TransferController.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
/**
|
||||
* TransferController.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers\Search;
|
||||
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Search\TransferRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Support\Search\TransferSearch;
|
||||
use FireflyIII\Transformers\TransactionGroupTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use League\Fractal\Resource\Collection as FractalCollection;
|
||||
|
||||
/**
|
||||
* Class TransferController
|
||||
*/
|
||||
class TransferController extends Controller
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return JsonResponse|Response
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function search(TransferRequest $request)
|
||||
{
|
||||
// configure transfer search to search for a > b
|
||||
$search = app(TransferSearch::class);
|
||||
$search->setSource($request->get('source'));
|
||||
$search->setDestination($request->get('destination'));
|
||||
$search->setAmount($request->get('amount'));
|
||||
$search->setDescription($request->get('description'));
|
||||
$search->setDate($request->get('date'));
|
||||
|
||||
$left = $search->search();
|
||||
|
||||
// configure transfer search to search for b > a
|
||||
$search->setSource($request->get('destination'));
|
||||
$search->setDestination($request->get('source'));
|
||||
$search->setAmount($request->get('amount'));
|
||||
$search->setDescription($request->get('description'));
|
||||
$search->setDate($request->get('date'));
|
||||
|
||||
$right = $search->search();
|
||||
|
||||
// add parameters to URL:
|
||||
$this->parameters->set('source', $request->get('source'));
|
||||
$this->parameters->set('destination', $request->get('destination'));
|
||||
$this->parameters->set('amount', $request->get('amount'));
|
||||
$this->parameters->set('description', $request->get('description'));
|
||||
$this->parameters->set('date', $request->get('date'));
|
||||
|
||||
// get all journal ID's.
|
||||
$total = $left->merge($right)->unique('id')->pluck('id')->toArray();
|
||||
if (0 === count($total)) {
|
||||
// forces search to be empty.
|
||||
$total = [-1];
|
||||
}
|
||||
|
||||
// collector to return results.
|
||||
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
|
||||
$manager = $this->getManager();
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
|
||||
// use new group collector:
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector
|
||||
->setUser($admin)
|
||||
// all info needed for the API:
|
||||
->withAPIInformation()
|
||||
// set page size:
|
||||
->setLimit($pageSize)
|
||||
// set page to retrieve
|
||||
->setPage(1)
|
||||
->setJournalIds($total);
|
||||
|
||||
$paginator = $collector->getPaginatedGroups();
|
||||
$paginator->setPath(route('api.v1.search.transfers') . $this->buildParams());
|
||||
$transactions = $paginator->getCollection();
|
||||
|
||||
/** @var TransactionGroupTransformer $transformer */
|
||||
$transformer = app(TransactionGroupTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new FractalCollection($transactions, $transformer, 'transactions');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
}
|
@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Requests\TransactionStoreRequest;
|
||||
use FireflyIII\Api\V1\Requests\TransactionUpdateRequest;
|
||||
use FireflyIII\Events\StoredTransactionGroup;
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
@@ -251,6 +252,19 @@ class TransactionController extends Controller
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a single transaction, by transaction journal.
|
||||
*
|
||||
* @param TransactionJournal $transactionJournal
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function showByJournal(TransactionJournal $transactionJournal): JsonResponse
|
||||
{
|
||||
return $this->show($transactionJournal->transactionGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new transaction.
|
||||
*
|
||||
@@ -266,7 +280,20 @@ class TransactionController extends Controller
|
||||
Log::channel('audit')
|
||||
->info('Store new transaction over API.', $data);
|
||||
|
||||
$transactionGroup = $this->groupRepository->store($data);
|
||||
try {
|
||||
$transactionGroup = $this->groupRepository->store($data);
|
||||
} catch (DuplicateTransactionException $e) {
|
||||
// return bad validation message.
|
||||
// TODO use Laravel's internal validation thing to do this.
|
||||
$response = [
|
||||
'message' => 'The given data was invalid.',
|
||||
'errors' => [
|
||||
'transactions.0.description' => [$e->getMessage()],
|
||||
],
|
||||
];
|
||||
|
||||
return response()->json($response, 422);
|
||||
}
|
||||
|
||||
event(new StoredTransactionGroup($transactionGroup));
|
||||
|
||||
|
@@ -165,7 +165,7 @@ class TransactionLinkController extends Controller
|
||||
$inward = $this->journalRepository->findNull($data['inward_id'] ?? 0);
|
||||
$outward = $this->journalRepository->findNull($data['outward_id'] ?? 0);
|
||||
if (null === $inward || null === $outward) {
|
||||
throw new FireflyException('Source or destination is NULL.');
|
||||
throw new FireflyException('200024: Source or destination does not exist.');
|
||||
}
|
||||
$data['direction'] = 'inward';
|
||||
|
||||
@@ -196,7 +196,7 @@ class TransactionLinkController extends Controller
|
||||
$data['inward'] = $this->journalRepository->findNull($data['inward_id'] ?? 0);
|
||||
$data['outward'] = $this->journalRepository->findNull($data['outward_id'] ?? 0);
|
||||
if (null === $data['inward'] || null === $data['outward']) {
|
||||
throw new FireflyException('Source or destination is NULL.');
|
||||
throw new FireflyException('200024: Source or destination does not exist.');
|
||||
}
|
||||
$data['direction'] = 'inward';
|
||||
$journalLink = $this->repository->updateLink($journalLink, $data);
|
||||
|
@@ -83,7 +83,7 @@ class UserController extends Controller
|
||||
|
||||
return response()->json([], 204);
|
||||
}
|
||||
throw new FireflyException('No access to method.'); // @codeCoverageIgnore
|
||||
throw new FireflyException('200025: No access to function.'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/**
|
||||
|
58
app/Api/V1/Requests/Search/TransferRequest.php
Normal file
58
app/Api/V1/Requests/Search/TransferRequest.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* TransferRequest.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests\Search;
|
||||
|
||||
|
||||
use FireflyIII\Api\V1\Requests\Request;
|
||||
use FireflyIII\Rules\IsTransferAccount;
|
||||
|
||||
/**
|
||||
* Class TransferRequest
|
||||
*/
|
||||
class TransferRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Authorize logged in users.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
// Only allow authenticated users
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'source' => ['required', new IsTransferAccount],
|
||||
'destination' => ['required', new IsTransferAccount],
|
||||
'amount' => 'required|numeric|more:0',
|
||||
'description' => 'required|min:1',
|
||||
'date' => 'required|date',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@@ -58,8 +58,9 @@ class TransactionStoreRequest extends Request
|
||||
public function getAll(): array
|
||||
{
|
||||
$data = [
|
||||
'group_title' => $this->string('group_title'),
|
||||
'transactions' => $this->getTransactionData(),
|
||||
'group_title' => $this->string('group_title'),
|
||||
'error_if_duplicate_hash' => $this->boolean('error_if_duplicate_hash'),
|
||||
'transactions' => $this->getTransactionData(),
|
||||
];
|
||||
|
||||
return $data;
|
||||
@@ -74,7 +75,8 @@ class TransactionStoreRequest extends Request
|
||||
{
|
||||
$rules = [
|
||||
// basic fields for group:
|
||||
'group_title' => 'between:1,1000',
|
||||
'group_title' => 'between:1,1000|nullable',
|
||||
'error_if_duplicate_hash' => [new IsBoolean],
|
||||
|
||||
// transaction rules (in array for splits):
|
||||
'transactions.*.type' => 'required|in:withdrawal,deposit,transfer,opening-balance,reconciliation',
|
||||
@@ -82,14 +84,14 @@ class TransactionStoreRequest extends Request
|
||||
'transactions.*.order' => 'numeric|min:0',
|
||||
|
||||
// currency info
|
||||
'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id',
|
||||
'transactions.*.currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
|
||||
'transactions.*.foreign_currency_id' => 'numeric|exists:transaction_currencies,id',
|
||||
'transactions.*.foreign_currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
|
||||
'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id|nullable',
|
||||
'transactions.*.currency_code' => 'min:3|max:3|exists:transaction_currencies,code|nullable',
|
||||
'transactions.*.foreign_currency_id' => 'numeric|exists:transaction_currencies,id|nullable',
|
||||
'transactions.*.foreign_currency_code' => 'min:3|max:3|exists:transaction_currencies,code|nullable',
|
||||
|
||||
// amount
|
||||
'transactions.*.amount' => 'required|numeric|more:0',
|
||||
'transactions.*.foreign_amount' => 'numeric|more:0',
|
||||
'transactions.*.foreign_amount' => 'numeric',
|
||||
|
||||
// description
|
||||
'transactions.*.description' => 'nullable|between:1,1000',
|
||||
@@ -97,10 +99,16 @@ class TransactionStoreRequest extends Request
|
||||
// source of transaction
|
||||
'transactions.*.source_id' => ['numeric', 'nullable', new BelongsUser],
|
||||
'transactions.*.source_name' => 'between:1,255|nullable',
|
||||
'transactions.*.source_iban' => 'between:1,255|nullable|iban',
|
||||
'transactions.*.source_number' => 'between:1,255|nullable',
|
||||
'transactions.*.source_bic' => 'between:1,255|nullable|bic',
|
||||
|
||||
// destination of transaction
|
||||
'transactions.*.destination_id' => ['numeric', 'nullable', new BelongsUser],
|
||||
'transactions.*.destination_name' => 'between:1,255|nullable',
|
||||
'transactions.*.destination_iban' => 'between:1,255|nullable|iban',
|
||||
'transactions.*.destination_number' => 'between:1,255|nullable',
|
||||
'transactions.*.destination_bic' => 'between:1,255|nullable|bic',
|
||||
|
||||
// budget, category, bill and piggy
|
||||
'transactions.*.budget_id' => ['mustExist:budgets,id', new BelongsUser],
|
||||
@@ -202,7 +210,7 @@ class TransactionStoreRequest extends Request
|
||||
'date' => $this->dateFromValue($object['date']),
|
||||
'order' => $this->integerFromValue((string)$object['order']),
|
||||
|
||||
'currency_id' => $this->integerFromValue($object['currency_id']),
|
||||
'currency_id' => $this->integerFromValue((string)$object['currency_id']),
|
||||
'currency_code' => $this->stringFromValue($object['currency_code']),
|
||||
|
||||
// foreign currency info:
|
||||
@@ -219,10 +227,16 @@ class TransactionStoreRequest extends Request
|
||||
// source of transaction. If everything is null, assume cash account.
|
||||
'source_id' => $this->integerFromValue((string)$object['source_id']),
|
||||
'source_name' => $this->stringFromValue($object['source_name']),
|
||||
'source_iban' => $this->stringFromValue($object['source_iban']),
|
||||
'source_number' => $this->stringFromValue($object['source_number']),
|
||||
'source_bic' => $this->stringFromValue($object['source_bic']),
|
||||
|
||||
// destination of transaction. If everything is null, assume cash account.
|
||||
'destination_id' => $this->integerFromValue((string)$object['destination_id']),
|
||||
'destination_name' => $this->stringFromValue($object['destination_name']),
|
||||
'destination_iban' => $this->stringFromValue($object['destination_iban']),
|
||||
'destination_number' => $this->stringFromValue($object['destination_number']),
|
||||
'destination_bic' => $this->stringFromValue($object['destination_bic']),
|
||||
|
||||
// budget info
|
||||
'budget_id' => $this->integerFromValue((string)$object['budget_id']),
|
||||
|
@@ -105,7 +105,13 @@ class TransactionUpdateRequest extends Request
|
||||
'foreign_amount',
|
||||
'description',
|
||||
'source_name',
|
||||
'source_iban',
|
||||
'source_number',
|
||||
'source_bic',
|
||||
'destination_name',
|
||||
'destination_iban',
|
||||
'destination_number',
|
||||
'destination_bic',
|
||||
'budget_name',
|
||||
'category_name',
|
||||
'bill_name',
|
||||
|
@@ -30,6 +30,7 @@ use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use Illuminate\Console\Command;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class FixAccountTypes
|
||||
@@ -66,6 +67,7 @@ class FixAccountTypes extends Command
|
||||
public function handle(): int
|
||||
{
|
||||
$this->stupidLaravel();
|
||||
Log::debug('Now in fix-account-types');
|
||||
$start = microtime(true);
|
||||
$this->factory = app(AccountFactory::class);
|
||||
// some combinations can be fixed by this script:
|
||||
@@ -88,13 +90,16 @@ class FixAccountTypes extends Command
|
||||
|
||||
$this->expected = config('firefly.source_dests');
|
||||
$journals = TransactionJournal::with(['TransactionType', 'transactions', 'transactions.account', 'transactions.account.accounttype'])->get();
|
||||
Log::debug(sprintf('Found %d journals to fix.', $journals->count()));
|
||||
foreach ($journals as $journal) {
|
||||
$this->inspectJournal($journal);
|
||||
}
|
||||
if (0 === $this->count) {
|
||||
Log::debug('No journals had to be fixed.');
|
||||
$this->info('All account types are OK!');
|
||||
}
|
||||
if (0 !== $this->count) {
|
||||
Log::debug(sprintf('%d journals had to be fixed.', $this->count));
|
||||
$this->info(sprintf('Acted on %d transaction(s)!', $this->count));
|
||||
}
|
||||
|
||||
@@ -223,21 +228,36 @@ class FixAccountTypes extends Command
|
||||
*/
|
||||
private function inspectJournal(TransactionJournal $journal): void
|
||||
{
|
||||
Log::debug(sprintf('Now trying to fix journal #%d', $journal->id));
|
||||
$count = $journal->transactions()->count();
|
||||
if (2 !== $count) {
|
||||
Log::debug(sprintf('Journal has %d transactions, so cant fix.', $count));
|
||||
$this->info(sprintf('Cannot inspect transaction journal #%d because it has %d transaction(s) instead of 2.', $journal->id, $count));
|
||||
|
||||
return;
|
||||
}
|
||||
$type = $journal->transactionType->type;
|
||||
$sourceTransaction = $this->getSourceTransaction($journal);
|
||||
$destTransaction = $this->getDestinationTransaction($journal);
|
||||
if (null === $sourceTransaction) {
|
||||
Log::error('Source transaction is unexpectedly NULL. Wont fix this journal.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (null === $destTransaction) {
|
||||
Log::error('Destination transaction is unexpectedly NULL. Wont fix this journal.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$sourceAccount = $sourceTransaction->account;
|
||||
$sourceAccountType = $sourceAccount->accountType->type;
|
||||
$destTransaction = $this->getDestinationTransaction($journal);
|
||||
$destAccount = $destTransaction->account;
|
||||
$destAccountType = $destAccount->accountType->type;
|
||||
|
||||
if (!isset($this->expected[$type])) {
|
||||
// @codeCoverageIgnoreStart
|
||||
Log::info(sprintf('No source/destination info for transaction type %s.', $type));
|
||||
$this->info(sprintf('No source/destination info for transaction type %s.', $type));
|
||||
|
||||
return;
|
||||
|
@@ -23,6 +23,7 @@ namespace FireflyIII\Console\Commands\Integrity;
|
||||
|
||||
use Artisan;
|
||||
use Crypt;
|
||||
use FireflyIII\Support\System\OAuthKeys;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
/**
|
||||
@@ -30,8 +31,6 @@ use Illuminate\Console\Command;
|
||||
*/
|
||||
class RestoreOAuthKeys extends Command
|
||||
{
|
||||
private const PRIVATE_KEY = 'oauth_private_key';
|
||||
private const PUBLIC_KEY = 'oauth_public_key';
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
@@ -62,7 +61,7 @@ class RestoreOAuthKeys extends Command
|
||||
*/
|
||||
private function generateKeys(): void
|
||||
{
|
||||
Artisan::call('passport:keys');
|
||||
OAuthKeys::generateKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,7 +69,7 @@ class RestoreOAuthKeys extends Command
|
||||
*/
|
||||
private function keysInDatabase(): bool
|
||||
{
|
||||
return app('fireflyconfig')->has(self::PRIVATE_KEY) && app('fireflyconfig')->has(self::PUBLIC_KEY);
|
||||
return OAuthKeys::keysInDatabase();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,10 +77,7 @@ class RestoreOAuthKeys extends Command
|
||||
*/
|
||||
private function keysOnDrive(): bool
|
||||
{
|
||||
$private = storage_path('oauth-private.key');
|
||||
$public = storage_path('oauth-public.key');
|
||||
|
||||
return file_exists($private) && file_exists($public);
|
||||
return OAuthKeys::hasKeyFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,12 +85,7 @@ class RestoreOAuthKeys extends Command
|
||||
*/
|
||||
private function restoreKeysFromDB(): void
|
||||
{
|
||||
$privateContent = Crypt::decrypt(app('fireflyconfig')->get(self::PRIVATE_KEY)->data);
|
||||
$publicContent = Crypt::decrypt(app('fireflyconfig')->get(self::PUBLIC_KEY)->data);
|
||||
$private = storage_path('oauth-private.key');
|
||||
$public = storage_path('oauth-public.key');
|
||||
file_put_contents($private, $privateContent);
|
||||
file_put_contents($public, $publicContent);
|
||||
OAuthKeys::restoreKeysFromDB();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,9 +120,6 @@ class RestoreOAuthKeys extends Command
|
||||
*/
|
||||
private function storeKeysInDB(): void
|
||||
{
|
||||
$private = storage_path('oauth-private.key');
|
||||
$public = storage_path('oauth-public.key');
|
||||
app('fireflyconfig')->set(self::PRIVATE_KEY, Crypt::encrypt(file_get_contents($private)));
|
||||
app('fireflyconfig')->set(self::PUBLIC_KEY, Crypt::encrypt(file_get_contents($public)));
|
||||
OAuthKeys::storeKeysInDB();
|
||||
}
|
||||
}
|
50
app/Console/Commands/SetLatestVersion.php
Normal file
50
app/Console/Commands/SetLatestVersion.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class SetLatestVersion extends Command
|
||||
{
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Command description';
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'firefly-iii:set-latest-version {--james-is-cool}';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if (!$this->option('james-is-cool')) {
|
||||
$this->error('Am too!');
|
||||
|
||||
return;
|
||||
}
|
||||
app('fireflyconfig')->set('db_version', config('firefly.db_version'));
|
||||
app('fireflyconfig')->set('ff3_version', config('firefly.version'));
|
||||
$this->line('Updated version.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
31
app/Exceptions/DuplicateTransactionException.php
Normal file
31
app/Exceptions/DuplicateTransactionException.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/**
|
||||
* DuplicateTransactionException.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Exceptions;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class DuplicateTransactionException
|
||||
*/
|
||||
class DuplicateTransactionException extends Exception
|
||||
{
|
||||
|
||||
}
|
@@ -101,6 +101,7 @@ class GracefulNotFoundHandler extends ExceptionHandler
|
||||
break;
|
||||
case 'tags.show.all':
|
||||
case 'tags.show':
|
||||
case 'tags.edit':
|
||||
$request->session()->reflash();
|
||||
|
||||
return redirect(route('tags.index'));
|
||||
|
@@ -68,7 +68,6 @@ class AccountMetaFactory
|
||||
{
|
||||
/** @var AccountMeta $entry */
|
||||
$entry = $account->accountMeta()->where('name', $field)->first();
|
||||
|
||||
// must not be an empty string:
|
||||
if ('' !== $value) {
|
||||
|
||||
|
@@ -24,10 +24,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Services\Internal\Support\BillServiceTrait;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
@@ -55,6 +57,7 @@ class BillFactory
|
||||
* @param array $data
|
||||
*
|
||||
* @return Bill|null
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function create(array $data): ?Bill
|
||||
{
|
||||
@@ -64,28 +67,31 @@ class BillFactory
|
||||
$currency = $factory->find((int)($data['currency_id'] ?? null), (string)($data['currency_code'] ?? null));
|
||||
|
||||
if (null === $currency) {
|
||||
// use default currency:
|
||||
$currency = app('amount')->getDefaultCurrencyByUser($this->user);
|
||||
}
|
||||
try {
|
||||
/** @var Bill $bill */
|
||||
$bill = Bill::create(
|
||||
[
|
||||
'name' => $data['name'],
|
||||
'match' => 'MIGRATED_TO_RULES',
|
||||
'amount_min' => $data['amount_min'],
|
||||
'user_id' => $this->user->id,
|
||||
'transaction_currency_id' => $currency->id,
|
||||
'amount_max' => $data['amount_max'],
|
||||
'date' => $data['date'],
|
||||
'repeat_freq' => $data['repeat_freq'],
|
||||
'skip' => $data['skip'],
|
||||
'automatch' => true,
|
||||
'active' => $data['active'] ?? true,
|
||||
]
|
||||
);
|
||||
} catch(QueryException $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
throw new FireflyException('400000: Could not store bill.');
|
||||
}
|
||||
|
||||
/** @var Bill $bill */
|
||||
$bill = Bill::create(
|
||||
[
|
||||
'name' => $data['name'],
|
||||
'match' => 'MIGRATED_TO_RULES',
|
||||
'amount_min' => $data['amount_min'],
|
||||
'user_id' => $this->user->id,
|
||||
'transaction_currency_id' => $currency->id,
|
||||
'amount_max' => $data['amount_max'],
|
||||
'date' => $data['date'],
|
||||
'repeat_freq' => $data['repeat_freq'],
|
||||
'skip' => $data['skip'],
|
||||
'automatch' => true,
|
||||
'active' => $data['active'] ?? true,
|
||||
]
|
||||
);
|
||||
|
||||
// update note:
|
||||
if (isset($data['notes'])) {
|
||||
$this->updateNote($bill, $data['notes']);
|
||||
}
|
||||
|
@@ -24,8 +24,10 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
@@ -62,7 +64,7 @@ class CategoryFactory
|
||||
* @param null|string $categoryName
|
||||
*
|
||||
* @return Category|null
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function findOrCreate(?int $categoryId, ?string $categoryName): ?Category
|
||||
{
|
||||
@@ -88,13 +90,17 @@ class CategoryFactory
|
||||
if (null !== $category) {
|
||||
return $category;
|
||||
}
|
||||
|
||||
return Category::create(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
'name' => $categoryName,
|
||||
]
|
||||
);
|
||||
try {
|
||||
return Category::create(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
'name' => $categoryName,
|
||||
]
|
||||
);
|
||||
} catch (QueryException $e) {
|
||||
Log::error($e->getMessage());
|
||||
throw new FireflyException('400003: Could not store new category.');
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@@ -27,6 +27,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Log;
|
||||
@@ -51,9 +52,10 @@ class TransactionCurrencyFactory
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionCurrency|null
|
||||
* @return TransactionCurrency
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function create(array $data): ?TransactionCurrency
|
||||
public function create(array $data): TransactionCurrency
|
||||
{
|
||||
try {
|
||||
/** @var TransactionCurrency $currency */
|
||||
@@ -69,6 +71,7 @@ class TransactionCurrencyFactory
|
||||
} catch (QueryException $e) {
|
||||
$result = null;
|
||||
Log::error(sprintf('Could not create new currency: %s', $e->getMessage()));
|
||||
throw new FireflyException('400004: Could not store new currency.');
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Factory;
|
||||
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\User;
|
||||
|
||||
@@ -52,10 +53,13 @@ class TransactionGroupFactory
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionGroup
|
||||
* @throws DuplicateTransactionException
|
||||
*/
|
||||
public function create(array $data): TransactionGroup
|
||||
{
|
||||
$this->journalFactory->setUser($this->user);
|
||||
$this->journalFactory->setErrorOnHash($data['error_if_duplicate_hash'] ?? false);
|
||||
|
||||
$collection = $this->journalFactory->create($data);
|
||||
$title = $data['group_title'] ?? null;
|
||||
$title = '' === $title ? null : $title;
|
||||
|
@@ -26,10 +26,12 @@ namespace FireflyIII\Factory;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionJournalMeta;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
@@ -72,6 +74,8 @@ class TransactionJournalFactory
|
||||
private $typeRepository;
|
||||
/** @var User The user */
|
||||
private $user;
|
||||
/** @var bool */
|
||||
private $errorOnHash;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -81,7 +85,8 @@ class TransactionJournalFactory
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->fields = [
|
||||
$this->errorOnHash = false;
|
||||
$this->fields = [
|
||||
// sepa
|
||||
'sepa_cc', 'sepa_ct_op', 'sepa_ct_id',
|
||||
'sepa_db', 'sepa_country', 'sepa_ep',
|
||||
@@ -119,6 +124,7 @@ class TransactionJournalFactory
|
||||
* @param array $data
|
||||
*
|
||||
* @return Collection
|
||||
* @throws DuplicateTransactionException
|
||||
*/
|
||||
public function create(array $data): Collection
|
||||
{
|
||||
@@ -193,11 +199,15 @@ class TransactionJournalFactory
|
||||
* @param NullArrayObject $row
|
||||
*
|
||||
* @return TransactionJournal|null
|
||||
* @throws Exception
|
||||
* @throws DuplicateTransactionException
|
||||
*/
|
||||
private function createJournal(NullArrayObject $row): ?TransactionJournal
|
||||
{
|
||||
$row['import_hash_v2'] = $this->hashArray($row);
|
||||
|
||||
$this->errorIfDuplicate($row['import_hash_v2']);
|
||||
|
||||
/** Some basic fields */
|
||||
$type = $this->typeRepository->findTransactionType(null, $row['type']);
|
||||
$carbon = $row['date'] ?? new Carbon;
|
||||
@@ -212,16 +222,33 @@ class TransactionJournalFactory
|
||||
$carbon->setTimezone(config('app.timezone'));
|
||||
|
||||
/** Get source + destination account */
|
||||
Log::debug(sprintf('Source info: ID #%d, name "%s"', $row['source_id'], $row['source_name']));
|
||||
Log::debug(sprintf('Destination info: ID #%d, name "%s"', $row['destination_id'], $row['destination_name']));
|
||||
|
||||
Log::debug(sprintf('Currency is #%d (%s)', $currency->id, $currency->code));
|
||||
|
||||
try {
|
||||
// validate source and destination using a new Validator.
|
||||
$this->validateAccounts($row);
|
||||
/** create or get source and destination accounts */
|
||||
$sourceAccount = $this->getAccount($type->type, 'source', (int)$row['source_id'], $row['source_name']);
|
||||
$destinationAccount = $this->getAccount($type->type, 'destination', (int)$row['destination_id'], $row['destination_name']);
|
||||
|
||||
$sourceInfo = [
|
||||
'id' => (int)$row['source_id'],
|
||||
'name' => $row['source_name'],
|
||||
'iban' => $row['source_iban'],
|
||||
'number' => $row['source_number'],
|
||||
'bic' => $row['source_bic'],
|
||||
];
|
||||
|
||||
$destInfo = [
|
||||
'id' => (int)$row['destination_id'],
|
||||
'name' => $row['destination_name'],
|
||||
'iban' => $row['destination_iban'],
|
||||
'number' => $row['destination_number'],
|
||||
'bic' => $row['destination_bic'],
|
||||
];
|
||||
Log::debug('Source info:', $sourceInfo);
|
||||
Log::debug('Destination info:', $destInfo);
|
||||
|
||||
$sourceAccount = $this->getAccount($type->type, 'source', $sourceInfo);
|
||||
$destinationAccount = $this->getAccount($type->type, 'destination', $destInfo);
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (FireflyException $e) {
|
||||
Log::error('Could not validate source or destination.');
|
||||
@@ -305,7 +332,7 @@ class TransactionJournalFactory
|
||||
$transactionFactory->setCurrency($sourceCurrency);
|
||||
$transactionFactory->setForeignCurrency($sourceForeignCurrency);
|
||||
$transactionFactory->setReconciled($row['reconciled'] ?? false);
|
||||
$transactionFactory->createNegative((string)$row['amount'], $row['foreign_amount']);
|
||||
$transactionFactory->createNegative((string)$row['amount'], (string)$row['foreign_amount']);
|
||||
|
||||
// and the destination one:
|
||||
/** @var TransactionFactory $transactionFactory */
|
||||
@@ -316,7 +343,7 @@ class TransactionJournalFactory
|
||||
$transactionFactory->setCurrency($destCurrency);
|
||||
$transactionFactory->setForeignCurrency($destForeignCurrency);
|
||||
$transactionFactory->setReconciled($row['reconciled'] ?? false);
|
||||
$transactionFactory->createPositive((string)$row['amount'], $row['foreign_amount']);
|
||||
$transactionFactory->createPositive((string)$row['amount'], (string)$row['foreign_amount']);
|
||||
|
||||
// verify that journal has two transactions. Otherwise, delete and cancel.
|
||||
// TODO this can't be faked so it can't be tested.
|
||||
@@ -359,6 +386,30 @@ class TransactionJournalFactory
|
||||
return $journal;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this transaction already exists, throw an error.
|
||||
*
|
||||
* @param string $hash
|
||||
*
|
||||
* @throws DuplicateTransactionException
|
||||
*/
|
||||
private function errorIfDuplicate(string $hash): void
|
||||
{
|
||||
if (false === $this->errorOnHash) {
|
||||
return;
|
||||
}
|
||||
$result = null;
|
||||
if ($this->errorOnHash) {
|
||||
/** @var TransactionJournalMeta $result */
|
||||
$result = TransactionJournalMeta::where('data', json_encode($hash, JSON_THROW_ON_ERROR))
|
||||
->with(['transactionJournal', 'transactionJournal.transactionGroup'])
|
||||
->first();
|
||||
}
|
||||
if (null !== $result) {
|
||||
throw new DuplicateTransactionException(sprintf('Duplicate of transaction #%d.', $result->transactionJournal->transaction_group_id));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency|null $currency
|
||||
* @param Account $account
|
||||
@@ -372,8 +423,10 @@ class TransactionJournalFactory
|
||||
// return user's default:
|
||||
return app('amount')->getDefaultCurrencyByUser($this->user);
|
||||
}
|
||||
$result = $preference ?? $currency;
|
||||
Log::debug(sprintf('Currency is now #%d (%s) because of account #%d (%s)', $result->id, $result->code, $account->id, $account->name));
|
||||
|
||||
return $preference ?? $currency;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -466,4 +519,14 @@ class TransactionJournalFactory
|
||||
throw new FireflyException(sprintf('Destination: %s', $this->accountValidator->destError)); // @codeCoverageIgnore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $errorOnHash
|
||||
*/
|
||||
public function setErrorOnHash(bool $errorOnHash): void
|
||||
{
|
||||
$this->errorOnHash = $errorOnHash;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Handlers\Events;
|
||||
|
||||
|
||||
use FireflyIII\Events\RequestedVersionCheckStatus;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Update\UpdateTrait;
|
||||
use FireflyIII\Models\Configuration;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
@@ -78,8 +79,15 @@ class VersionCheckEventHandler
|
||||
}
|
||||
// last check time was more than a week ago.
|
||||
Log::debug('Have not checked for a new version in a week!');
|
||||
try {
|
||||
$latestRelease = $this->getLatestRelease();
|
||||
} catch (FireflyException $e) {
|
||||
Log::error($e);
|
||||
session()->flash('error', (string)trans('firefly.update_check_error'));
|
||||
|
||||
$latestRelease = $this->getLatestRelease();
|
||||
// softfail.
|
||||
return;
|
||||
}
|
||||
$versionCheck = $this->versionCheck($latestRelease);
|
||||
$resultString = $this->parseResult($versionCheck, $latestRelease);
|
||||
if (0 !== $versionCheck && '' !== $resultString) {
|
||||
|
@@ -162,6 +162,13 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
return false;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
if ('' === $content) {
|
||||
Log::error('Cannot upload empty file.');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$path = stream_get_meta_data($resource)['uri'];
|
||||
fwrite($resource, $content);
|
||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||
@@ -199,6 +206,7 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
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.');
|
||||
@@ -362,6 +370,11 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
if (!$this->validMime($file)) {
|
||||
$result = false;
|
||||
}
|
||||
if (0 === $file->getSize()) {
|
||||
Log::error('Cannot upload empty file.');
|
||||
$result = false;
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
// can't seem to reach this point.
|
||||
if (true === $result && !$this->validSize($file)) {
|
||||
|
@@ -70,6 +70,8 @@ class GroupCollector implements GroupCollectorInterface
|
||||
private $total;
|
||||
/** @var User The user object. */
|
||||
private $user;
|
||||
/** @var array */
|
||||
private $integerFields;
|
||||
|
||||
/**
|
||||
* Group collector constructor.
|
||||
@@ -84,7 +86,23 @@ class GroupCollector implements GroupCollectorInterface
|
||||
$this->hasBudgetInformation = false;
|
||||
$this->hasBillInformation = false;
|
||||
$this->hasJoinedTagTables = false;
|
||||
|
||||
$this->integerFields = [
|
||||
'transaction_group_id',
|
||||
'user_id',
|
||||
'transaction_journal_id',
|
||||
'transaction_type_id',
|
||||
'order',
|
||||
'source_transaction_id',
|
||||
'source_account_id',
|
||||
'currency_id',
|
||||
'currency_decimal_places',
|
||||
'foreign_currency_id',
|
||||
'foreign_currency_decimal_places',
|
||||
'destination_transaction_id',
|
||||
'destination_account_id',
|
||||
'category_id',
|
||||
'budget_id'
|
||||
];
|
||||
$this->total = 0;
|
||||
$this->fields = [
|
||||
# group
|
||||
@@ -903,6 +921,22 @@ class GroupCollector implements GroupCollectorInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a selected set of fields to arrays.
|
||||
*
|
||||
* @param array $array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function convertToInteger(array $array): array
|
||||
{
|
||||
foreach ($this->integerFields as $field) {
|
||||
$array[$field] = isset($array[$field]) ? (int)$array[$field] : null;
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join table to get tag information.
|
||||
*/
|
||||
@@ -965,8 +999,8 @@ class GroupCollector implements GroupCollectorInterface
|
||||
// make new array
|
||||
$parsedGroup = $this->parseAugmentedGroup($augumentedJournal);
|
||||
$groupArray = [
|
||||
'id' => $augumentedJournal->transaction_group_id,
|
||||
'user_id' => $augumentedJournal->user_id,
|
||||
'id' => (int)$augumentedJournal->transaction_group_id,
|
||||
'user_id' => (int)$augumentedJournal->user_id,
|
||||
'title' => $augumentedJournal->transaction_group_title,
|
||||
'transaction_type' => $parsedGroup['transaction_type_type'],
|
||||
'count' => 1,
|
||||
@@ -1014,6 +1048,10 @@ class GroupCollector implements GroupCollectorInterface
|
||||
} catch (Exception $e) {
|
||||
Log::error($e->getMessage());
|
||||
}
|
||||
|
||||
// convert values to integers:
|
||||
$result = $this->convertToInteger($result);
|
||||
|
||||
$result['reconciled'] = 1 === (int)$result['reconciled'];
|
||||
if (isset($augumentedJournal['tag_id'])) { // assume the other fields are present as well.
|
||||
$tagId = (int)$augumentedJournal['tag_id'];
|
||||
|
@@ -25,8 +25,7 @@ namespace FireflyIII\Helpers\Update;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Services\Github\Object\Release;
|
||||
use FireflyIII\Services\Github\Request\UpdateRequest;
|
||||
use FireflyIII\Services\FireflyIIIOrg\Update\UpdateRequestInterface;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
@@ -38,75 +37,54 @@ trait UpdateTrait
|
||||
/**
|
||||
* Get object for the latest release from GitHub.
|
||||
*
|
||||
* @return Release|null
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function getLatestRelease(): ?Release
|
||||
public function getLatestRelease(): array
|
||||
{
|
||||
Log::debug('Now in getLatestRelease()');
|
||||
$return = null;
|
||||
/** @var UpdateRequest $request */
|
||||
$request = app(UpdateRequest::class);
|
||||
try {
|
||||
$request->call();
|
||||
} catch (FireflyException $e) {
|
||||
Log::error(sprintf('Could not check for updates: %s', $e->getMessage()));
|
||||
/** @var UpdateRequestInterface $checker */
|
||||
$checker = app(UpdateRequestInterface::class);
|
||||
$channel = app('fireflyconfig')->get('update_channel', 'stable')->data;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// get releases from array.
|
||||
$releases = $request->getReleases();
|
||||
|
||||
Log::debug(sprintf('Found %d releases', count($releases)));
|
||||
|
||||
if (count($releases) > 0) {
|
||||
// first entry should be the latest entry:
|
||||
/** @var Release $first */
|
||||
$first = reset($releases);
|
||||
$return = $first;
|
||||
Log::debug(sprintf('Number of releases found is larger than zero. Return %s ', $first->getTitle()));
|
||||
}
|
||||
|
||||
return $return;
|
||||
return $checker->getVersion($channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the version check result in a human readable sentence.
|
||||
*
|
||||
* @param int $versionCheck
|
||||
* @param Release|null $release
|
||||
* @param int $versionCheck
|
||||
* @param array $information
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function parseResult(int $versionCheck, Release $release = null): string
|
||||
public function parseResult(int $versionCheck, array $information): string
|
||||
{
|
||||
Log::debug(sprintf('Now in parseResult(%d)', $versionCheck));
|
||||
$current = (string)config('firefly.version');
|
||||
$return = '';
|
||||
$triggered = false;
|
||||
if ($versionCheck === -2) {
|
||||
Log::debug('-2, so give error.');
|
||||
$return = (string)trans('firefly.update_check_error');
|
||||
$triggered = true;
|
||||
}
|
||||
if ($versionCheck === -1 && null !== $release) {
|
||||
$triggered = true;
|
||||
Log::debug('New version!');
|
||||
// there is a new FF version!
|
||||
// has it been released for at least three days?
|
||||
$today = new Carbon;
|
||||
$releaseDate = $release->getUpdated();
|
||||
if ($today->diffInDays($releaseDate) > 3) {
|
||||
Log::debug('New version is older than 3 days!');
|
||||
$monthAndDayFormat = (string)trans('config.month_and_day');
|
||||
$return = (string)trans(
|
||||
'firefly.update_new_version_alert',
|
||||
[
|
||||
'your_version' => $current,
|
||||
'new_version' => $release->getTitle(),
|
||||
'date' => $release->getUpdated()->formatLocalized($monthAndDayFormat),
|
||||
]
|
||||
);
|
||||
if (-1 === $versionCheck) {
|
||||
$triggered = true;
|
||||
$monthAndDayFormat = (string)trans('config.month_and_day');
|
||||
$carbon = Carbon::createFromFormat('Y-m-d', $information['date']);
|
||||
$return = (string)trans(
|
||||
'firefly.update_new_version_alert',
|
||||
[
|
||||
'your_version' => $current,
|
||||
'new_version' => $information['version'],
|
||||
'date' => $carbon->formatLocalized($monthAndDayFormat),
|
||||
]
|
||||
);
|
||||
// append warning if beta or alpha.
|
||||
$isBeta = $information['is_beta'] ?? false;
|
||||
if (true === $isBeta) {
|
||||
$return = sprintf('%s %s', $return, trans('firefly.update_version_beta'));
|
||||
}
|
||||
|
||||
$isAlpha = $information['is_alpha'] ?? false;
|
||||
if (true === $isAlpha) {
|
||||
$return = sprintf('%s %s', $return, trans('firefly.update_version_alpha'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,19 +94,16 @@ trait UpdateTrait
|
||||
// you are running the current version!
|
||||
$return = (string)trans('firefly.update_current_version_alert', ['version' => $current]);
|
||||
}
|
||||
if (1 === $versionCheck && null !== $release) {
|
||||
if (1 === $versionCheck) {
|
||||
$triggered = true;
|
||||
Log::debug('User is running NEWER version.');
|
||||
// you are running a newer version!
|
||||
$return = (string)trans('firefly.update_newer_version_alert', ['your_version' => $current, 'new_version' => $release->getTitle()]);
|
||||
$return = (string)trans('firefly.update_newer_version_alert', ['your_version' => $current, 'new_version' => $information['version']]);
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
if (false === $triggered) {
|
||||
Log::debug('No option was triggered.');
|
||||
$return = (string)trans('firefly.update_check_error');
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return $return;
|
||||
}
|
||||
@@ -136,22 +111,16 @@ trait UpdateTrait
|
||||
/**
|
||||
* Compare version and store result.
|
||||
*
|
||||
* @param Release|null $release
|
||||
* @param array $information
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function versionCheck(Release $release = null): int
|
||||
public function versionCheck(array $information): int
|
||||
{
|
||||
Log::debug('Now in versionCheck()');
|
||||
if (null === $release) {
|
||||
Log::debug('Release is null, return -2.');
|
||||
|
||||
return -2;
|
||||
}
|
||||
$current = (string)config('firefly.version');
|
||||
$latest = $release->getTitle();
|
||||
$check = version_compare($current, $latest);
|
||||
Log::debug(sprintf('Comparing %s with %s, result is %s', $current, $latest, $check));
|
||||
$check = version_compare($current, $information['version']);
|
||||
Log::debug(sprintf('Comparing %s with %s, result is %s', $current, $information['version'], $check), $information);
|
||||
|
||||
return $check;
|
||||
}
|
||||
|
@@ -63,20 +63,19 @@ class IndexController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Show list of accounts.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $objectType
|
||||
* @param string $objectType
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request, string $objectType)
|
||||
public function inactive(Request $request, string $objectType)
|
||||
{
|
||||
$objectType = $objectType ?? 'asset';
|
||||
$subTitle = (string)trans(sprintf('firefly.%s_accounts', $objectType));
|
||||
$inactivePage = true;
|
||||
$subTitle = (string)trans(sprintf('firefly.%s_accounts_inactive', $objectType));
|
||||
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType));
|
||||
$types = config(sprintf('firefly.accountTypesByIdentifier.%s', $objectType));
|
||||
$collection = $this->repository->getAccountsByType($types);
|
||||
$collection = $this->repository->getInactiveAccountsByType($types);
|
||||
$total = $collection->count();
|
||||
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
@@ -105,11 +104,65 @@ class IndexController extends Controller
|
||||
}
|
||||
);
|
||||
|
||||
// make paginator:
|
||||
$accounts = new LengthAwarePaginator($accounts, $total, $pageSize, $page);
|
||||
$accounts->setPath(route('accounts.inactive.index', [$objectType]));
|
||||
|
||||
return view('accounts.index', compact('objectType','inactivePage', 'subTitleIcon', 'subTitle', 'page', 'accounts'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Show list of accounts.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $objectType
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function index(Request $request, string $objectType)
|
||||
{
|
||||
$objectType = $objectType ?? 'asset';
|
||||
$subTitle = (string)trans(sprintf('firefly.%s_accounts', $objectType));
|
||||
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType));
|
||||
$types = config(sprintf('firefly.accountTypesByIdentifier.%s', $objectType));
|
||||
$collection = $this->repository->getActiveAccountsByType($types);
|
||||
$total = $collection->count();
|
||||
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page');
|
||||
$pageSize = (int)app('preferences')->get('listPageSize', 50)->data;
|
||||
$accounts = $collection->slice(($page - 1) * $pageSize, $pageSize);
|
||||
$inactiveCount = $this->repository->getInactiveAccountsByType($types)->count();
|
||||
|
||||
|
||||
unset($collection);
|
||||
/** @var Carbon $start */
|
||||
$start = clone session('start', Carbon::now()->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
$end = clone session('end', Carbon::now()->endOfMonth());
|
||||
$start->subDay();
|
||||
|
||||
$ids = $accounts->pluck('id')->toArray();
|
||||
$startBalances = app('steam')->balancesByAccounts($accounts, $start);
|
||||
$endBalances = app('steam')->balancesByAccounts($accounts, $end);
|
||||
$activities = app('steam')->getLastActivities($ids);
|
||||
|
||||
$accounts->each(
|
||||
function (Account $account) use ($activities, $startBalances, $endBalances) {
|
||||
$account->lastActivityDate = $this->isInArray($activities, $account->id);
|
||||
$account->startBalance = $this->isInArray($startBalances, $account->id);
|
||||
$account->endBalance = $this->isInArray($endBalances, $account->id);
|
||||
$account->difference = bcsub($account->endBalance, $account->startBalance);
|
||||
$account->interest = round($this->repository->getMetaValue($account, 'interest'), 6);
|
||||
$account->interestPeriod = (string)trans(sprintf('firefly.interest_calc_%s', $this->repository->getMetaValue($account, 'interest_period')));
|
||||
$account->accountTypeString = (string)trans(sprintf('firefly.account_type_%s', $account->accountType->type));
|
||||
}
|
||||
);
|
||||
|
||||
// make paginator:
|
||||
$accounts = new LengthAwarePaginator($accounts, $total, $pageSize, $page);
|
||||
$accounts->setPath(route('accounts.index', [$objectType]));
|
||||
|
||||
return view('accounts.index', compact('objectType', 'subTitleIcon', 'subTitle', 'page', 'accounts'));
|
||||
return view('accounts.index', compact('objectType', 'inactiveCount', 'subTitleIcon', 'subTitle', 'page', 'accounts'));
|
||||
}
|
||||
|
||||
|
||||
|
@@ -23,10 +23,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Admin;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Update\UpdateTrait;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Middleware\IsDemoUser;
|
||||
use FireflyIII\Http\Middleware\IsSandStormUser;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Log;
|
||||
|
||||
@@ -44,7 +46,7 @@ class UpdateController extends Controller
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
static function ($request, $next) {
|
||||
app('view')->share('title', (string)trans('firefly.administration'));
|
||||
app('view')->share('mainTitleIcon', 'fa-hand-spock-o');
|
||||
|
||||
@@ -64,17 +66,25 @@ class UpdateController extends Controller
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$subTitle = (string)trans('firefly.update_check_title');
|
||||
$subTitleIcon = 'fa-star';
|
||||
$permission = app('fireflyconfig')->get('permission_update_check', -1);
|
||||
$selected = $permission->data;
|
||||
$options = [
|
||||
$subTitle = (string)trans('firefly.update_check_title');
|
||||
$subTitleIcon = 'fa-star';
|
||||
$permission = app('fireflyconfig')->get('permission_update_check', -1);
|
||||
$channel = app('fireflyconfig')->get('update_channel', 'stable');
|
||||
$selected = $permission->data;
|
||||
$channelSelected = $channel->data;
|
||||
$options = [
|
||||
-1 => (string)trans('firefly.updates_ask_me_later'),
|
||||
0 => (string)trans('firefly.updates_do_not_check'),
|
||||
1 => (string)trans('firefly.updates_enable_check'),
|
||||
];
|
||||
|
||||
return view('admin.update.index', compact('subTitle', 'subTitleIcon', 'selected', 'options'));
|
||||
$channelOptions = [
|
||||
'stable' => (string)trans('firefly.update_channel_stable'),
|
||||
'beta' => (string)trans('firefly.update_channel_beta'),
|
||||
'alpha' => (string)trans('firefly.update_channel_alpha'),
|
||||
];
|
||||
|
||||
return view('admin.update.index', compact('subTitle', 'subTitleIcon', 'selected', 'options', 'channelSelected', 'channelOptions'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,8 +97,11 @@ class UpdateController extends Controller
|
||||
public function post(Request $request)
|
||||
{
|
||||
$checkForUpdates = (int)$request->get('check_for_updates');
|
||||
$channel = $request->get('update_channel');
|
||||
$channel = in_array($channel, ['stable', 'beta', 'alpha'], true) ? $channel : 'stable';
|
||||
app('fireflyconfig')->set('permission_update_check', $checkForUpdates);
|
||||
app('fireflyconfig')->set('last_update_check', time());
|
||||
app('fireflyconfig')->set('update_channel', $channel);
|
||||
session()->flash('success', (string)trans('firefly.configuration_updated'));
|
||||
|
||||
return redirect(route('admin.update-check'));
|
||||
@@ -97,11 +110,33 @@ class UpdateController extends Controller
|
||||
/**
|
||||
* Does a manual update check.
|
||||
*/
|
||||
public function updateCheck()
|
||||
public function updateCheck(): JsonResponse
|
||||
{
|
||||
$latestRelease = $this->getLatestRelease();
|
||||
$versionCheck = $this->versionCheck($latestRelease);
|
||||
$resultString = $this->parseResult($versionCheck, $latestRelease);
|
||||
$success = true;
|
||||
$latestRelease = '1.0';
|
||||
$resultString = '';
|
||||
$versionCheck = -2;
|
||||
$channel = app('fireflyconfig')->get('update_channel', 'stable')->data;
|
||||
|
||||
try {
|
||||
$latestRelease = $this->getLatestRelease();
|
||||
} catch (FireflyException $e) {
|
||||
Log::error($e->getMessage());
|
||||
$success = false;
|
||||
}
|
||||
|
||||
// if error, tell the user.
|
||||
if (false === $success) {
|
||||
$resultString = (string)trans('firefly.update_check_error');
|
||||
session()->flash('error', $resultString);
|
||||
}
|
||||
|
||||
// if not, compare and tell the user.
|
||||
if (true === $success) {
|
||||
$versionCheck = $this->versionCheck($latestRelease);
|
||||
$resultString = $this->parseResult($versionCheck, $latestRelease);
|
||||
}
|
||||
|
||||
Log::debug(sprintf('Result string is: "%s"', $resultString));
|
||||
|
||||
if (0 !== $versionCheck && '' !== $resultString) {
|
||||
@@ -110,6 +145,11 @@ class UpdateController extends Controller
|
||||
}
|
||||
app('fireflyconfig')->set('last_update_check', time());
|
||||
|
||||
return response()->json(['result' => $resultString]);
|
||||
return response()->json(
|
||||
[
|
||||
'result' => $resultString,
|
||||
'channel' => $channel,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -222,11 +222,11 @@ class AttachmentController extends Controller
|
||||
"default-src 'none'",
|
||||
"object-src 'none'",
|
||||
"script-src 'none'",
|
||||
"style-src 'none'",
|
||||
"style-src 'self' 'unsafe-inline'",
|
||||
"base-uri 'none'",
|
||||
"font-src 'none'",
|
||||
"connect-src 'none'",
|
||||
"img-src 'none'",
|
||||
"img-src 'self'",
|
||||
"manifest-src 'none'",
|
||||
];
|
||||
|
||||
|
@@ -127,7 +127,7 @@ class IndexController extends Controller
|
||||
$array['spent'] = $spentArr[$entry->transaction_currency_id]['sum'] ?? '0';
|
||||
|
||||
// budgeted in period:
|
||||
$budgeted = $this->blRepository->budgeted($entry->start_date, $entry->end_date, $entry->transactionCurrency,);
|
||||
$budgeted = $this->blRepository->budgeted($entry->start_date, $entry->end_date, $entry->transactionCurrency, );
|
||||
$array['budgeted'] = $budgeted;
|
||||
$availableBudgets[] = $array;
|
||||
unset($spentArr);
|
||||
@@ -135,7 +135,7 @@ class IndexController extends Controller
|
||||
|
||||
if (0 === count($availableBudgets)) {
|
||||
// get budgeted for default currency:
|
||||
$budgeted = $this->blRepository->budgeted($start, $end, $defaultCurrency,);
|
||||
$budgeted = $this->blRepository->budgeted($start, $end, $defaultCurrency, );
|
||||
$spentArr = $this->opsRepository->sumExpenses($start, $end, null, null, $defaultCurrency);
|
||||
$spent = $spentArr[$defaultCurrency->id]['sum'] ?? '0';
|
||||
unset($spentArr);
|
||||
|
@@ -56,7 +56,6 @@ class BudgetController extends Controller
|
||||
protected $repository;
|
||||
/** @var BudgetLimitRepositoryInterface */
|
||||
private $blRepository;
|
||||
|
||||
/** @var NoBudgetRepositoryInterface */
|
||||
private $nbRepository;
|
||||
|
||||
@@ -379,7 +378,7 @@ class BudgetController extends Controller
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('chart.budget.frontpage');
|
||||
if ($cache->has()) {
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
//return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
$budgets = $this->repository->getActiveBudgets();
|
||||
$chartData = [
|
||||
@@ -390,23 +389,42 @@ class BudgetController extends Controller
|
||||
|
||||
/** @var Budget $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
// get relevant repetitions:
|
||||
$limits = $this->blRepository->getBudgetLimits($budget, $start, $end);
|
||||
$expenses = $this->getExpensesForBudget($limits, $budget, $start, $end);
|
||||
|
||||
foreach ($expenses as $name => $row) {
|
||||
$chartData[0]['entries'][$name] = $row['spent'];
|
||||
$chartData[1]['entries'][$name] = $row['left'];
|
||||
$chartData[2]['entries'][$name] = $row['overspent'];
|
||||
$limits = $this->blRepository->getBudgetLimits($budget, $start, $end);
|
||||
if (0 === $limits->count()) {
|
||||
$spent = $this->opsRepository->sumExpenses($start, $end, null, new Collection([$budget]), null);
|
||||
/** @var array $entry */
|
||||
foreach ($spent as $entry) {
|
||||
$title = sprintf('%s (%s)', $budget->name, $entry['currency_name']);
|
||||
$chartData[0]['entries'][$title] = bcmul($entry['sum'], '-1'); // spent
|
||||
$chartData[1]['entries'][$title] = 0; // left to spend
|
||||
$chartData[2]['entries'][$title] = 0; // overspent
|
||||
}
|
||||
}
|
||||
if (0 !== $limits->count()) {
|
||||
/** @var BudgetLimit $limit */
|
||||
foreach ($limits as $limit) {
|
||||
$spent = $this->opsRepository->sumExpenses(
|
||||
$limit->start_date, $limit->end_date, null, new Collection([$budget]), $limit->transactionCurrency
|
||||
);
|
||||
/** @var array $entry */
|
||||
foreach ($spent as $entry) {
|
||||
$title = sprintf('%s (%s)', $budget->name, $entry['currency_name']);
|
||||
if ($limit->start_date->startOfDay()->ne($start->startOfDay()) || $limit->end_date->startOfDay()->ne($end->startOfDay())) {
|
||||
$title = sprintf(
|
||||
'%s (%s) (%s - %s)', $budget->name, $entry['currency_name'],
|
||||
$limit->start_date->formatLocalized($this->monthAndDayFormat),
|
||||
$limit->end_date->formatLocalized($this->monthAndDayFormat)
|
||||
);
|
||||
}
|
||||
|
||||
$chartData[0]['entries'][$title] = bcmul($entry['sum'], '-1'); // spent
|
||||
$chartData[1]['entries'][$title] = 1 === bccomp($limit->amount, bcmul($entry['sum'], '-1')) ? bcadd($entry['sum'], $limit->amount)
|
||||
: '0';
|
||||
$chartData[2]['entries'][$title] = 1 === bccomp($limit->amount, bcmul($entry['sum'], '-1')) ?
|
||||
'0' : bcmul(bcadd($entry['sum'], $limit->amount), '-1');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// for no budget:
|
||||
$spent = $this->spentInPeriodWithout($start, $end);
|
||||
$name = (string)trans('firefly.no_budget');
|
||||
if (0 !== bccomp($spent, '0')) {
|
||||
$chartData[0]['entries'][$name] = bcmul($spent, '-1');
|
||||
$chartData[1]['entries'][$name] = '0';
|
||||
$chartData[2]['entries'][$name] = '0';
|
||||
}
|
||||
|
||||
$data = $this->generator->multiSet($chartData);
|
||||
|
@@ -174,9 +174,9 @@ class ReportController extends Controller
|
||||
$data[$currencyId] = $data[$currencyId] ?? [
|
||||
'currency_id' => $currencyId,
|
||||
'currency_symbol' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_code'],
|
||||
'currency_name' => $journal['currency_name'],
|
||||
'currency_decimal_places' => $journal['currency_decimal_places'],
|
||||
'currency_decimal_places' => (int)$journal['currency_decimal_places'],
|
||||
];
|
||||
$data[$currencyId][$period] = $data[$currencyId][$period] ?? [
|
||||
'period' => $period,
|
||||
@@ -218,7 +218,6 @@ class ReportController extends Controller
|
||||
// loop all possible periods between $start and $end
|
||||
$currentStart = clone $start;
|
||||
while ($currentStart <= $end) {
|
||||
$currentEnd = app('navigation')->endOfPeriod($currentStart, $preferredRange);
|
||||
$key = $currentStart->format($format);
|
||||
$title = $currentStart->formatLocalized($titleFormat);
|
||||
$income['entries'][$title] = round($currency[$key]['earned'] ?? '0', $currency['currency_decimal_places']);
|
||||
|
@@ -127,7 +127,6 @@ class DebugController extends Controller
|
||||
$currentDriver = DB::getDriverName();
|
||||
$userAgent = $request->header('user-agent');
|
||||
$isSandstorm = var_export(config('firefly.is_sandstorm'), true);
|
||||
$isDocker = var_export(config('firefly.is_docker'), true);
|
||||
$toSandbox = var_export(config('firefly.bunq_use_sandbox'), true);
|
||||
$trustedProxies = config('firefly.trusted_proxies');
|
||||
$displayErrors = ini_get('display_errors');
|
||||
@@ -178,7 +177,7 @@ class DebugController extends Controller
|
||||
'debug', compact(
|
||||
'phpVersion', 'extensions', 'localeAttempts', 'appEnv', 'appDebug', 'logChannel', 'appLogLevel', 'now', 'drivers',
|
||||
'currentDriver', 'loginProvider', 'storageDisks',
|
||||
'userAgent', 'displayErrors', 'errorReporting', 'phpOs', 'interface', 'logContent', 'cacheDriver', 'isDocker', 'isSandstorm',
|
||||
'userAgent', 'displayErrors', 'errorReporting', 'phpOs', 'interface', 'logContent', 'cacheDriver', 'isSandstorm',
|
||||
'trustedProxies',
|
||||
'toSandbox'
|
||||
)
|
||||
|
@@ -26,6 +26,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
@@ -282,6 +283,39 @@ class AutoCompleteController extends Controller
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An auto-complete specifically for asset accounts and liabilities, used when mass updating and for rules mostly.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function assetAccounts(Request $request): JsonResponse
|
||||
{
|
||||
$search = $request->get('search');
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
|
||||
// filter the account types:
|
||||
$allowedAccountTypes = [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE];
|
||||
Log::debug(sprintf('Now in expenseAccounts(%s). Filtering results.', $search), $allowedAccountTypes);
|
||||
|
||||
$return = [];
|
||||
$result = $repository->searchAccount((string)$search, $allowedAccountTypes);
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($result as $account) {
|
||||
$return[] = [
|
||||
'id' => $account->id,
|
||||
'name' => $account->name,
|
||||
'type' => $account->accountType->type,
|
||||
];
|
||||
}
|
||||
|
||||
return response()->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JsonResponse
|
||||
* @codeCoverageIgnore
|
||||
@@ -291,7 +325,26 @@ class AutoCompleteController extends Controller
|
||||
/** @var PiggyBankRepositoryInterface $repository */
|
||||
$repository = app(PiggyBankRepositoryInterface::class);
|
||||
|
||||
return response()->json($repository->getPiggyBanks()->toArray());
|
||||
/** @var AccountRepositoryInterface $accountRepos */
|
||||
$accountRepos = app(AccountRepositoryInterface::class);
|
||||
|
||||
$piggies = $repository->getPiggyBanks();
|
||||
$defaultCurrency = \Amount::getDefaultCurrency();
|
||||
$response = [];
|
||||
/** @var PiggyBank $piggy */
|
||||
foreach ($piggies as $piggy) {
|
||||
$currency = $accountRepos->getAccountCurrency($piggy->account) ?? $defaultCurrency;
|
||||
$currentAmount = $repository->getRepetition($piggy)->currentamount ?? '0';
|
||||
$piggy->name_with_amount = sprintf(
|
||||
'%s (%s / %s)',
|
||||
$piggy->name,
|
||||
app('amount')->formatAnything($currency, $currentAmount, false),
|
||||
app('amount')->formatAnything($currency, $piggy->targetamount, false),
|
||||
);
|
||||
$response[] = $piggy->toArray();
|
||||
}
|
||||
|
||||
return response()->json($response);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -113,6 +113,7 @@ class IntroController
|
||||
}
|
||||
Log::debug(sprintf('Going to mark the following route as NOT done: %s with special "%s" (%s)', $route, $specialPage, $key));
|
||||
app('preferences')->set($key, false);
|
||||
app('preferences')->mark();
|
||||
|
||||
return response()->json(['message' => (string)trans('firefly.intro_boxes_after_refresh')]);
|
||||
}
|
||||
|
@@ -289,8 +289,8 @@ class BudgetController extends Controller
|
||||
|
||||
// loop again to get percentages.
|
||||
foreach ($report as $budgetId => $data) {
|
||||
foreach ($data['currencies'] as $currencyId => $data) {
|
||||
$sum = $data['sum'] ?? '0';
|
||||
foreach ($data['currencies'] as $currencyId => $dataX) {
|
||||
$sum = $dataX['sum'] ?? '0';
|
||||
$total = $sums[$currencyId]['sum'] ?? '0';
|
||||
$pct = '0';
|
||||
if (0 !== bccomp($sum, '0') && 0 !== bccomp($total, '9')) {
|
||||
@@ -361,7 +361,8 @@ class BudgetController extends Controller
|
||||
];
|
||||
|
||||
// make sum information:
|
||||
$report['sums'][$currency->id] = $report['sums'][$currency->id] ?? [
|
||||
$report['sums'][$currency->id]
|
||||
= $report['sums'][$currency->id] ?? [
|
||||
'budgeted' => '0',
|
||||
'spent' => '0',
|
||||
'left' => '0',
|
||||
@@ -411,15 +412,13 @@ class BudgetController extends Controller
|
||||
// make percentages based on total amount.
|
||||
foreach ($report['budgets'] as $budgetId => $data) {
|
||||
foreach ($data['budget_limits'] as $limitId => $entry) {
|
||||
$currencyId = $entry['currency_id'];
|
||||
|
||||
$spent = $entry['spent'];
|
||||
$totalSpent = $report['sums'][$currencyId]['spent'] ?? '0';
|
||||
$spentPct = '0';
|
||||
|
||||
$currencyId = $entry['currency_id'];
|
||||
$spent = $entry['spent'];
|
||||
$totalSpent = $report['sums'][$currencyId]['spent'] ?? '0';
|
||||
$spentPct = '0';
|
||||
$budgeted = $entry['budgeted'];
|
||||
$totalBudgeted = $report['sums'][$currencyId]['budgeted'] ?? '0';;
|
||||
$budgetedPct = '0';
|
||||
$totalBudgeted = $report['sums'][$currencyId]['budgeted'] ?? '0';
|
||||
$budgetedPct = '0';
|
||||
|
||||
if (0 !== bccomp($spent, '0') && 0 !== bccomp($totalSpent, '0')) {
|
||||
$spentPct = round(bcmul(bcdiv($spent, $totalSpent), '100'));
|
||||
@@ -427,28 +426,13 @@ class BudgetController extends Controller
|
||||
if (0 !== bccomp($budgeted, '0') && 0 !== bccomp($totalBudgeted, '0')) {
|
||||
$budgetedPct = round(bcmul(bcdiv($budgeted, $totalBudgeted), '100'));
|
||||
}
|
||||
$report['sums'][$currencyId]['budgeted'] = $report['sums'][$currencyId]['budgeted'] ?? '0';
|
||||
$report['budgets'][$budgetId]['budget_limits'][$limitId]['spent_pct'] = $spentPct;
|
||||
$report['budgets'][$budgetId]['budget_limits'][$limitId]['budgeted_pct'] = $budgetedPct;
|
||||
}
|
||||
}
|
||||
|
||||
// var_dump($noBudget);
|
||||
//
|
||||
//
|
||||
// echo '<pre>';
|
||||
// print_r($report);
|
||||
// exit;
|
||||
// try {
|
||||
$result = view('reports.partials.budgets', compact('report'))->render();
|
||||
// @codeCoverageIgnoreStart
|
||||
// } catch (Throwable $e) {
|
||||
// Log::debug(sprintf('Could not render reports.partials.budgets: %s', $e->getMessage()));
|
||||
// $result = 'Could not render view.';
|
||||
// }
|
||||
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return $result;
|
||||
return view('reports.partials.budgets', compact('report'))->render();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -714,7 +714,6 @@ class CategoryController extends Controller
|
||||
/** @var NoCategoryRepositoryInterface $noCatRepository */
|
||||
$noCatRepository = app(NoCategoryRepositoryInterface::class);
|
||||
|
||||
$categories = $repository->getCategories();
|
||||
$earnedWith = $opsRepository->listIncome($start, $end, $accounts);
|
||||
$spentWith = $opsRepository->listExpenses($start, $end, $accounts);
|
||||
$earnedWithout = $noCatRepository->listIncome($start, $end, $accounts);
|
||||
@@ -745,7 +744,7 @@ class CategoryController extends Controller
|
||||
$key = sprintf('%s-%s', $currencyId, $categoryId);
|
||||
$report['categories'][$key] = $report['categories'][$key] ?? [
|
||||
'id' => $categoryId,
|
||||
'title' => sprintf('%s (%s)', $categoryRow['name'], $currencyRow['currency_name']),
|
||||
'title' => $categoryRow['name'],
|
||||
'currency_id' => $currencyRow['currency_id'],
|
||||
'currency_symbol' => $currencyRow['currency_symbol'],
|
||||
'currency_name' => $currencyRow['currency_name'],
|
||||
|
@@ -102,6 +102,9 @@ class InstallController extends Controller
|
||||
'firefly-iii:rename-meta-fields' => [],
|
||||
'firefly-iii:fix-ob-currencies' => [],
|
||||
'firefly-iii:fix-long-descriptions' => [],
|
||||
|
||||
// final command to set latest version in DB
|
||||
'firefly-iii:set-latest-version' => ['--james-is-cool' => true],
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -25,7 +25,6 @@ namespace FireflyIII\Http\Controllers\Transaction;
|
||||
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
|
||||
/**
|
||||
@@ -75,9 +74,12 @@ class CreateController extends Controller
|
||||
$subTitleIcon = 'fa-plus';
|
||||
$optionalFields = app('preferences')->get('transaction_journal_optional_fields', [])->data;
|
||||
$allowedOpposingTypes = config('firefly.allowed_opposing_types');
|
||||
$accountToTypes = config('firefly.account_to_transaction');
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$previousUri = $this->rememberPreviousUri('transactions.create.uri');
|
||||
$accountToTypes = config('firefly.account_to_transaction');
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$previousUri = $this->rememberPreviousUri('transactions.create.uri');
|
||||
$parts = parse_url($previousUri);
|
||||
$search = sprintf('?%s', $parts['query'] ?? '');
|
||||
$previousUri = str_replace($search, '', $previousUri);
|
||||
|
||||
session()->put('preFilled', $preFilled);
|
||||
|
||||
|
@@ -69,6 +69,8 @@ class EditController extends Controller
|
||||
*/
|
||||
public function edit(TransactionGroup $transactionGroup)
|
||||
{
|
||||
app('preferences')->mark();
|
||||
|
||||
if (!$this->isEditableGroup($transactionGroup)) {
|
||||
return $this->redirectGroupToAccount($transactionGroup); // @codeCoverageIgnore
|
||||
}
|
||||
@@ -80,6 +82,10 @@ class EditController extends Controller
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$cash = $repository->getCashAccount();
|
||||
$previousUri = $this->rememberPreviousUri('transactions.edit.uri');
|
||||
$parts = parse_url($previousUri);
|
||||
$search = sprintf('?%s', $parts['query'] ?? '');
|
||||
$previousUri = str_replace($search, '', $previousUri);
|
||||
|
||||
|
||||
return view('transactions.edit', compact('cash', 'transactionGroup', 'allowedOpposingTypes', 'accountToTypes', 'defaultCurrency', 'previousUri'));
|
||||
}
|
||||
|
@@ -182,7 +182,7 @@ class Kernel extends HttpKernel
|
||||
|
||||
'apiX' => [
|
||||
'auth:api',
|
||||
'throttle:60,1',
|
||||
//'throttle:60,1',
|
||||
'bindings',
|
||||
],
|
||||
];
|
||||
|
@@ -27,6 +27,7 @@ namespace FireflyIII\Http\Middleware;
|
||||
use Closure;
|
||||
use DB;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Support\System\OAuthKeys;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Log;
|
||||
|
||||
@@ -71,6 +72,7 @@ class Installer
|
||||
if ($this->hasNoTables() || $this->oldDBVersion() || $this->oldVersion()) {
|
||||
return response()->redirectTo(route('installer.index'));
|
||||
}
|
||||
OAuthKeys::verifyKeysRoutine();
|
||||
// update scheme version
|
||||
// update firefly version
|
||||
|
||||
@@ -182,4 +184,5 @@ class Installer
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -53,8 +53,6 @@ class Range
|
||||
// set more view variables:
|
||||
$this->configureList();
|
||||
|
||||
// flash a big fat warning when users use SQLite in Docker
|
||||
$this->loseItAll($request);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
@@ -104,22 +102,6 @@ class Range
|
||||
app('view')->share('defaultCurrency', $defaultCurrency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Error when sqlite in docker.
|
||||
*
|
||||
* @param Request $request
|
||||
*/
|
||||
private function loseItAll(Request $request): void
|
||||
{
|
||||
if ('sqlite' === config('database.default') && true === config('firefly.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
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the range for the current view.
|
||||
*/
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* FinTSConfigurationSteps.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
* Copyright (c) 2019 https://github.com/bnw
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* FinTSJobConfiguration.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
* Copyright (c) 2019 https://github.com/bnw
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* FinTSRoutine.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
* Copyright (c) 2019 https://github.com/bnw
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* AbnAmroDescription.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
* Copyright (c) 2019 Robert Horlings
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Belfius.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
* Copyright (c) 2019 Sander Kleykens <sander@kleykens.com>
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* IngBelgium.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
* Copyright (c) 2019 Sander Kleykens <sander@kleykens.com>
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* IngDescription.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
* Copyright (c) 2019 https://github.com/tomwerf
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* SnsDescription.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
* Copyright (c) 2019 hugovanduijn@gmail.com.
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
|
@@ -134,6 +134,10 @@ class CreateRecurringTransactions implements ShouldQueue
|
||||
$this->repository->setUser($recurrence->user);
|
||||
$this->journalRepository->setUser($recurrence->user);
|
||||
$this->groupRepository->setUser($recurrence->user);
|
||||
|
||||
// clear cache for user
|
||||
app('preferences')->setForUser($recurrence->user, 'lastActivity', microtime());
|
||||
|
||||
Log::debug(sprintf('Now at recurrence #%d', $recurrence->id));
|
||||
$created = $this->handleRepetitions($recurrence);
|
||||
Log::debug(sprintf('Done with recurrence #%d', $recurrence->id));
|
||||
@@ -238,8 +242,8 @@ class CreateRecurringTransactions implements ShouldQueue
|
||||
'recurrence_id' => (int)$recurrence->id,
|
||||
'order' => $index,
|
||||
'notes' => (string)trans('firefly.created_from_recurrence', ['id' => $recurrence->id, 'title' => $recurrence->title]),
|
||||
'tags' => $this->repository->getTags($recurrence),
|
||||
'piggy_bank_id' => null,
|
||||
'tags' => $this->repository->getTags($transaction),
|
||||
'piggy_bank_id' => $this->repository->getPiggyBank($transaction),
|
||||
'piggy_bank_name' => null,
|
||||
'bill_id' => null,
|
||||
'bill_name' => null,
|
||||
@@ -320,7 +324,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
||||
Log::info(sprintf('Created new transaction group #%d', $group->id));
|
||||
|
||||
// link to piggy:
|
||||
$this->linkGroupToPiggies($recurrence, $group);
|
||||
//$this->linkGroupToPiggies($recurrence, $group);
|
||||
|
||||
// trigger event:
|
||||
event(new StoredTransactionGroup($group, $recurrence->apply_rules));
|
||||
|
@@ -42,6 +42,8 @@ use FireflyIII\Repositories\TransactionType\TransactionTypeRepositoryInterface;
|
||||
use FireflyIII\Repositories\User\UserRepository;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\Services\Currency\ExchangeRateInterface;
|
||||
use FireflyIII\Services\FireflyIIIOrg\Update\UpdateRequest;
|
||||
use FireflyIII\Services\FireflyIIIOrg\Update\UpdateRequestInterface;
|
||||
use FireflyIII\Services\IP\IpifyOrg;
|
||||
use FireflyIII\Services\IP\IPRetrievalInterface;
|
||||
use FireflyIII\Services\Password\PwndVerifierV3;
|
||||
@@ -184,6 +186,8 @@ class FireflyServiceProvider extends ServiceProvider
|
||||
$this->app->bind(HelpInterface::class, Help::class);
|
||||
$this->app->bind(ReportHelperInterface::class, ReportHelper::class);
|
||||
$this->app->bind(FiscalHelperInterface::class, FiscalHelper::class);
|
||||
$this->app->bind(UpdateRequestInterface::class, UpdateRequest::class);
|
||||
|
||||
$class = (string)config(sprintf('firefly.cer_providers.%s', (string)config('firefly.cer_provider')));
|
||||
if ('' === $class) {
|
||||
throw new FireflyException('Invalid currency exchange rate provider. Cannot continue.');
|
||||
|
@@ -318,9 +318,8 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
$query->where('active', 1);
|
||||
$query->orderBy('accounts.account_type_id', 'ASC');
|
||||
$query->orderBy('accounts.name', 'ASC');
|
||||
$result = $query->get(['accounts.*']);
|
||||
|
||||
return $result;
|
||||
return $query->get(['accounts.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -555,10 +554,16 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
{
|
||||
$dbQuery = $this->user->accounts()
|
||||
->where('active', 1)
|
||||
->orderBy('accounts.name', 'ASC')
|
||||
->with(['accountType']);
|
||||
if ('' !== $query) {
|
||||
$search = sprintf('%%%s%%', $query);
|
||||
$dbQuery->where('name', 'LIKE', $search);
|
||||
// split query on spaces just in case:
|
||||
$parts = explode(' ', $query);
|
||||
foreach($parts as $part) {
|
||||
$search = sprintf('%%%s%%', $part);
|
||||
$dbQuery->where('name', 'LIKE', $search);
|
||||
}
|
||||
|
||||
}
|
||||
if (count($types) > 0) {
|
||||
$dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
|
||||
@@ -606,4 +611,27 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getInactiveAccountsByType(array $types): Collection
|
||||
{
|
||||
/** @var Collection $result */
|
||||
$query = $this->user->accounts()->with(
|
||||
['accountmeta' => function (HasMany $query) {
|
||||
$query->where('name', 'account_role');
|
||||
}]
|
||||
);
|
||||
if (count($types) > 0) {
|
||||
$query->accountTypeIn($types);
|
||||
}
|
||||
$query->where('active', 0);
|
||||
$query->orderBy('accounts.account_type_id', 'ASC');
|
||||
$query->orderBy('accounts.name', 'ASC');
|
||||
|
||||
return $query->get(['accounts.*']);
|
||||
}
|
||||
}
|
||||
|
@@ -142,6 +142,13 @@ interface AccountRepositoryInterface
|
||||
*/
|
||||
public function getActiveAccountsByType(array $types): Collection;
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getInactiveAccountsByType(array $types): Collection;
|
||||
|
||||
/**
|
||||
* @return Account
|
||||
*/
|
||||
|
@@ -24,6 +24,7 @@ namespace FireflyIII\Repositories\Bill;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\BillFactory;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Note;
|
||||
@@ -662,9 +663,10 @@ class BillRepository implements BillRepositoryInterface
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Bill|null
|
||||
* @return Bill
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): ?Bill
|
||||
public function store(array $data): Bill
|
||||
{
|
||||
/** @var BillFactory $factory */
|
||||
$factory = app(BillFactory::class);
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\Bill;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
@@ -266,9 +267,10 @@ interface BillRepositoryInterface
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return Bill|null
|
||||
* @return Bill
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): ?Bill;
|
||||
public function store(array $data): Bill;
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
|
@@ -73,6 +73,7 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface
|
||||
->where('budget_limits.start_date', $start->format('Y-m-d 00:00:00'))
|
||||
->where('budget_limits.end_date', $end->format('Y-m-d 00:00:00'))
|
||||
->where('budget_limits.transaction_currency_id', $currency->id)
|
||||
->whereNull('budgets.deleted_at')
|
||||
->where('budgets.user_id', $this->user->id);
|
||||
if (null !== $budgets && $budgets->count() > 0) {
|
||||
$query->whereIn('budget_limits.budget_id', $budgets->pluck('id')->toArray());
|
||||
|
@@ -25,6 +25,7 @@ namespace FireflyIII\Repositories\Budget;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\RecurrenceTransactionMeta;
|
||||
@@ -32,6 +33,7 @@ use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\RuleTrigger;
|
||||
use FireflyIII\Services\Internal\Destroy\BudgetDestroyService;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
@@ -269,16 +271,20 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
* @param array $data
|
||||
*
|
||||
* @return Budget
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): Budget
|
||||
{
|
||||
$newBudget = new Budget(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
'name' => $data['name'],
|
||||
]
|
||||
);
|
||||
$newBudget->save();
|
||||
try {
|
||||
$newBudget = Budget::create(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
'name' => $data['name'],
|
||||
]
|
||||
);
|
||||
} catch(QueryException $e) {
|
||||
throw new FireflyException('400002: Could not store budget.');
|
||||
}
|
||||
|
||||
return $newBudget;
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\Budget;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -132,6 +133,7 @@ interface BudgetRepositoryInterface
|
||||
* @param array $data
|
||||
*
|
||||
* @return Budget
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): Budget;
|
||||
|
||||
|
@@ -24,6 +24,7 @@ namespace FireflyIII\Repositories\Category;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\CategoryFactory;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\RecurrenceTransactionMeta;
|
||||
@@ -239,6 +240,7 @@ class CategoryRepository implements CategoryRepositoryInterface
|
||||
* @param array $data
|
||||
*
|
||||
* @return Category
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): Category
|
||||
{
|
||||
@@ -246,7 +248,13 @@ class CategoryRepository implements CategoryRepositoryInterface
|
||||
$factory = app(CategoryFactory::class);
|
||||
$factory->setUser($this->user);
|
||||
|
||||
return $factory->findOrCreate(null, $data['name']);
|
||||
$category = $factory->findOrCreate(null, $data['name']);
|
||||
|
||||
if (null === $category) {
|
||||
throw new FireflyException(sprintf('400003: Could not store new category with name "%s"', $data['name']));
|
||||
}
|
||||
return $category;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\Category;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -117,7 +118,7 @@ interface CategoryRepositoryInterface
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @return Category
|
||||
*/
|
||||
public function store(array $data): Category;
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\Currency;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\TransactionCurrencyFactory;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Models\AvailableBudget;
|
||||
@@ -489,14 +490,20 @@ class CurrencyRepository implements CurrencyRepositoryInterface
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionCurrency|null
|
||||
* @return TransactionCurrency
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): ?TransactionCurrency
|
||||
public function store(array $data): TransactionCurrency
|
||||
{
|
||||
/** @var TransactionCurrencyFactory $factory */
|
||||
$factory = app(TransactionCurrencyFactory::class);
|
||||
$result = $factory->create($data);
|
||||
|
||||
return $factory->create($data);
|
||||
if (null === $result) {
|
||||
throw new FireflyException('400004: Could not store new currency.');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -234,9 +234,9 @@ interface CurrencyRepositoryInterface
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionCurrency|null
|
||||
* @return TransactionCurrency
|
||||
*/
|
||||
public function store(array $data): ?TransactionCurrency;
|
||||
public function store(array $data): TransactionCurrency;
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency $currency
|
||||
|
@@ -24,6 +24,7 @@ namespace FireflyIII\Repositories\PiggyBank;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
@@ -33,6 +34,7 @@ use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
@@ -416,9 +418,11 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
*/
|
||||
public function getPiggyBanks(): Collection
|
||||
{
|
||||
return $this->user->piggyBanks()->orderBy('order', 'ASC')->get();
|
||||
return $this->user->piggyBanks()->with(['account'])->orderBy('order', 'ASC')->get();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Also add amount in name.
|
||||
*
|
||||
@@ -556,13 +560,19 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return PiggyBank|null
|
||||
* @return PiggyBank
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): ?PiggyBank
|
||||
public function store(array $data): PiggyBank
|
||||
{
|
||||
$data['order'] = $this->getMaxOrder() + 1;
|
||||
try {
|
||||
/** @var PiggyBank $piggyBank */
|
||||
$piggyBank = PiggyBank::create($data);
|
||||
} catch(QueryException $e) {
|
||||
Log::error(sprintf('Could not store piggy bank: %s',$e->getMessage()));
|
||||
throw new FireflyException('400005: Could not store new piggy bank.');
|
||||
}
|
||||
|
||||
$this->updateNote($piggyBank, $data['notes']);
|
||||
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Repositories\PiggyBank;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\PiggyBankEvent;
|
||||
use FireflyIII\Models\PiggyBankRepetition;
|
||||
@@ -245,9 +246,10 @@ interface PiggyBankRepositoryInterface
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return PiggyBank|null
|
||||
* @return PiggyBank
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(array $data): ?PiggyBank;
|
||||
public function store(array $data): PiggyBank;
|
||||
|
||||
/**
|
||||
* Update existing piggy bank.
|
||||
|
@@ -28,7 +28,6 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\RecurrenceFactory;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Models\RecurrenceMeta;
|
||||
@@ -253,19 +252,17 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Recurrence $recurrence
|
||||
* @param RecurrenceTransaction $transaction
|
||||
*
|
||||
* @return PiggyBank|null
|
||||
* @return int|null
|
||||
*/
|
||||
public function getPiggyBank(Recurrence $recurrence): ?PiggyBank
|
||||
public function getPiggyBank(RecurrenceTransaction $transaction): ?int
|
||||
{
|
||||
$meta = $recurrence->recurrenceMeta;
|
||||
/** @var RecurrenceMeta $metaEntry */
|
||||
$meta = $transaction->recurrenceTransactionMeta;
|
||||
/** @var RecurrenceTransactionMeta $metaEntry */
|
||||
foreach ($meta as $metaEntry) {
|
||||
if ('piggy_bank_id' === $metaEntry->name) {
|
||||
$piggyId = (int)$metaEntry->value;
|
||||
|
||||
return $this->user->piggyBanks()->where('piggy_banks.id', $piggyId)->first(['piggy_banks.*']);
|
||||
return (int)$metaEntry->value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,17 +272,18 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
/**
|
||||
* Get the tags from the recurring transaction.
|
||||
*
|
||||
* @param Recurrence $recurrence
|
||||
* @param RecurrenceTransaction $transaction
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTags(Recurrence $recurrence): array
|
||||
public function getTags(RecurrenceTransaction $transaction): array
|
||||
{
|
||||
$tags = [];
|
||||
/** @var RecurrenceMeta $meta */
|
||||
foreach ($recurrence->recurrenceMeta as $meta) {
|
||||
foreach ($transaction->recurrenceTransactionMeta as $meta) {
|
||||
if ('tags' === $meta->name && '' !== $meta->value) {
|
||||
$tags = explode(',', $meta->value);
|
||||
//$tags = explode(',', $meta->value);
|
||||
$tags = json_decode($meta->value, true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,6 +402,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
*/
|
||||
public function repetitionDescription(RecurrenceRepetition $repetition): string
|
||||
{
|
||||
Log::debug('Now in repetitionDescription()');
|
||||
/** @var Preference $pref */
|
||||
$pref = app('preferences')->getForUser($this->user, 'language', config('firefly.default_language', 'en_US'));
|
||||
$language = $pref->data;
|
||||
@@ -514,6 +513,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
*/
|
||||
public function getXOccurrencesSince(RecurrenceRepetition $repetition, Carbon $date, Carbon $afterDate, int $count): array
|
||||
{
|
||||
Log::debug('Now in getXOccurrencesSince()');
|
||||
$skipMod = $repetition->repetition_skip + 1;
|
||||
$occurrences = [];
|
||||
if ('daily' === $repetition->repetition_type) {
|
||||
|
@@ -120,19 +120,19 @@ interface RecurringRepositoryInterface
|
||||
public function getOccurrencesInRange(RecurrenceRepetition $repetition, Carbon $start, Carbon $end): array;
|
||||
|
||||
/**
|
||||
* @param Recurrence $recurrence
|
||||
* @return PiggyBank|null
|
||||
* @param RecurrenceTransaction $transaction
|
||||
* @return int|null
|
||||
*/
|
||||
public function getPiggyBank(Recurrence $recurrence): ?PiggyBank;
|
||||
public function getPiggyBank(RecurrenceTransaction $transaction): ?int;
|
||||
|
||||
/**
|
||||
* Get the tags from the recurring transaction.
|
||||
*
|
||||
* @param Recurrence $recurrence
|
||||
* @param RecurrenceTransaction $transaction
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTags(Recurrence $recurrence): array;
|
||||
public function getTags(RecurrenceTransaction $transaction): array;
|
||||
|
||||
/**
|
||||
* @param Recurrence $recurrence
|
||||
|
@@ -27,6 +27,7 @@ namespace FireflyIII\Repositories\TransactionGroup;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\TransactionGroupFactory;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
@@ -97,6 +98,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
||||
$journals = $group->transactionJournals->pluck('id')->toArray();
|
||||
$set = Attachment::whereIn('attachable_id', $journals)
|
||||
->where('attachable_type', TransactionJournal::class)
|
||||
->where('uploaded', 1)
|
||||
->whereNull('deleted_at')->get();
|
||||
|
||||
$result = [];
|
||||
@@ -313,6 +315,7 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionGroup
|
||||
* @throws DuplicateTransactionException
|
||||
*/
|
||||
public function store(array $data): TransactionGroup
|
||||
{
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Repositories\TransactionGroup;
|
||||
|
||||
use FireflyIII\Exceptions\DuplicateTransactionException;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Support\NullArrayObject;
|
||||
use FireflyIII\User;
|
||||
@@ -125,6 +126,7 @@ interface TransactionGroupRepositoryInterface
|
||||
* @param array $data
|
||||
*
|
||||
* @return TransactionGroup
|
||||
* @throws DuplicateTransactionException
|
||||
*/
|
||||
public function store(array $data): TransactionGroup;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user