commit
5ea4290571
294 changed files with 69757 additions and 0 deletions
-
15.editorconfig
-
169.env.example
-
5.gitattributes
-
46.github/code_of_conduct.md
-
3.github/contributing.md
-
18.github/dependabot.yml
-
4.github/funding.yml
-
7.github/issue_template/Custom.md
-
9.github/pull_request_template.md
-
5.github/security.md
-
16.github/support.md
-
12.gitignore
-
58.scrutinizer.yml
-
13.styleci.yml
-
661COPYING
-
661LICENSE
-
1README.md
-
218app/Console/AutoImports.php
-
93app/Console/Commands/AutoImport.php
-
139app/Console/Commands/Import.php
-
58app/Console/Commands/ShowVersion.php
-
64app/Console/HaveAccess.php
-
66app/Console/Kernel.php
-
41app/Console/ManageMessages.php
-
79app/Console/StartImport.php
-
57app/Console/VerifyJSON.php
-
36app/Exceptions/ApiException.php
-
36app/Exceptions/ApiHttpException.php
-
53app/Exceptions/Handler.php
-
35app/Exceptions/ImportException.php
-
36app/Exceptions/ImporterErrorException.php
-
36app/Exceptions/ImporterHttpException.php
-
38app/Exceptions/SpectreErrorException.php
-
37app/Exceptions/SpectreHttpException.php
-
90app/Http/Controllers/AutoImportController.php
-
78app/Http/Controllers/AutoUploadController.php
-
110app/Http/Controllers/Controller.php
-
39app/Http/Controllers/Import/AuthenticateController.php
-
169app/Http/Controllers/Import/ConfigurationController.php
-
72app/Http/Controllers/Import/DownloadController.php
-
228app/Http/Controllers/Import/MapController.php
-
175app/Http/Controllers/Import/RoleController.php
-
194app/Http/Controllers/Import/RunController.php
-
73app/Http/Controllers/Import/StartController.php
-
193app/Http/Controllers/Import/UploadController.php
-
141app/Http/Controllers/IndexController.php
-
73app/Http/Controllers/NavController.php
-
46app/Http/Controllers/ServiceController.php
-
309app/Http/Controllers/TokenController.php
-
116app/Http/Kernel.php
-
49app/Http/Middleware/Authenticate.php
-
43app/Http/Middleware/CheckForMaintenanceMode.php
-
52app/Http/Middleware/ConfigComplete.php
-
43app/Http/Middleware/EncryptCookies.php
-
52app/Http/Middleware/MappingComplete.php
-
53app/Http/Middleware/ReadyForImport.php
-
54app/Http/Middleware/RedirectIfAuthenticated.php
-
52app/Http/Middleware/RolesComplete.php
-
44app/Http/Middleware/TrimStrings.php
-
65app/Http/Middleware/TrustProxies.php
-
53app/Http/Middleware/UploadedFiles.php
-
43app/Http/Middleware/VerifyCsrfToken.php
-
31app/Http/Request/AutoUploadRequest.php
-
149app/Http/Request/ConfigurationPostRequest.php
-
190app/Http/Request/Request.php
-
111app/Http/Request/RolesPostRequest.php
-
49app/Mail/ImportFinished.php
-
60app/Providers/AppServiceProvider.php
-
56app/Providers/AuthServiceProvider.php
-
47app/Providers/BroadcastServiceProvider.php
-
48app/Providers/EventServiceProvider.php
-
93app/Providers/RouteServiceProvider.php
-
66app/Services/CSV/Configuration/ConfigFileProcessor.php
-
545app/Services/CSV/Configuration/Configuration.php
-
272app/Services/CSV/Converter/Amount.php
-
59app/Services/CSV/Converter/AmountCredit.php
-
60app/Services/CSV/Converter/AmountDebit.php
-
55app/Services/CSV/Converter/AmountNegated.php
-
72app/Services/CSV/Converter/BankDebitCredit.php
-
59app/Services/CSV/Converter/CleanId.php
-
55app/Services/CSV/Converter/CleanInteger.php
-
54app/Services/CSV/Converter/CleanNlString.php
-
57app/Services/CSV/Converter/CleanString.php
-
46app/Services/CSV/Converter/ConverterInterface.php
-
81app/Services/CSV/Converter/ConverterService.php
-
113app/Services/CSV/Converter/Date.php
-
54app/Services/CSV/Converter/Description.php
-
95app/Services/CSV/Converter/Iban.php
-
56app/Services/CSV/Converter/TagsComma.php
-
56app/Services/CSV/Converter/TagsSpace.php
-
61app/Services/CSV/File/FileReader.php
-
45app/Services/CSV/Mapper/AssetAccountIbans.php
-
45app/Services/CSV/Mapper/AssetAccounts.php
-
68app/Services/CSV/Mapper/Bills.php
-
72app/Services/CSV/Mapper/Budgets.php
-
70app/Services/CSV/Mapper/Categories.php
-
230app/Services/CSV/Mapper/GetAccounts.php
-
38app/Services/CSV/Mapper/MapperInterface.php
-
122app/Services/CSV/Mapper/MapperService.php
-
45app/Services/CSV/Mapper/OpposingAccountIbans.php
@ -0,0 +1,15 @@ |
|||
root = true |
|||
|
|||
[*] |
|||
charset = utf-8 |
|||
end_of_line = lf |
|||
insert_final_newline = true |
|||
indent_style = space |
|||
indent_size = 4 |
|||
trim_trailing_whitespace = true |
|||
|
|||
[*.md] |
|||
trim_trailing_whitespace = false |
|||
|
|||
[*.yml] |
|||
indent_size = 2 |
@ -0,0 +1,169 @@ |
|||
# |
|||
# Where is Firefly III? |
|||
# |
|||
# 1) Make sure you ADD http:// or https:// |
|||
# 2) Make sure you REMOVE any trailing slash from the end of the URL. |
|||
# 3) In case of Docker, refer to the internal IP of your Firefly III installation. |
|||
# |
|||
# This value is not mandatory. But it is very useful. |
|||
# |
|||
FIREFLY_III_URL= |
|||
|
|||
# |
|||
# Imagine Firefly III can be reached at "http://172.16.0.2:8082" (internal Docker network or something). |
|||
# But you have a fancy URL: "https://personal-finances.bill.microsoft.com/" |
|||
# |
|||
# In those cases, you can overrule the URL so when the CSV importer links back to Firefly III, it uses the correct URL. |
|||
# |
|||
# 1) Make sure you ADD http:// or https:// |
|||
# 2) Make sure you REMOVE any trailing slash from the end of the URL. |
|||
# |
|||
VANITY_URL= |
|||
|
|||
# |
|||
# Set your Firefly III Personal Access Token |
|||
# You can find create a Personal Access Token on the /profile page (at the bottom) |
|||
# |
|||
# - Do not use the "command line token". That's the WRONG one. |
|||
# - Do not use "APP_KEY". That's the WRONG one. |
|||
# |
|||
# This value is not mandatory to set. Instructions will follow if you omit this field. |
|||
# |
|||
FIREFLY_III_ACCESS_TOKEN= |
|||
|
|||
# |
|||
# You can also use a public client ID. This is available in Firefly III 5.4.0-alpha.3 and higher. |
|||
# This is a number (1, 2, 3). If you use the client ID, you can leave the access token empty and vice versa. |
|||
# |
|||
# This value is not mandatory to set. Instructions will follow if you omit this field. |
|||
# |
|||
FIREFLY_III_CLIENT_ID= |
|||
|
|||
# |
|||
# Nordigen |
|||
# |
|||
NORDIGEN_ID= |
|||
NORDIGEN_KEY= |
|||
|
|||
# |
|||
# Spectre |
|||
# |
|||
SPECTRE_APP_ID= |
|||
SPECTRE_SECRET= |
|||
|
|||
# |
|||
# When you're running Firefly III under a (self-signed) certificate, |
|||
# the CSV importer may have trouble verifying the TLS connection. |
|||
# |
|||
# You have a few options to make sure the CSV importer can connect |
|||
# to Firefly III: |
|||
# - 'true': will verify all certificates. The most secure option and the default. |
|||
# - 'file.pem': refer to a file (you must provide it) to your custom root or intermediate certificates. |
|||
# - 'false': will verify NO certificates. Not very secure. |
|||
VERIFY_TLS_SECURITY=true |
|||
|
|||
# |
|||
# If you want, you can set a directory here where the CSV importer will look for import configurations. |
|||
# This is a separate setting from the /import directory that the auto-import uses. |
|||
# Setting this variable isn't necessary. The default value is "storage/configurations". |
|||
# |
|||
JSON_CONFIGURATION_DIR= |
|||
|
|||
# |
|||
# Time out when connecting with Firefly III. |
|||
# π*10 seconds is usually fine. |
|||
# |
|||
CONNECTION_TIMEOUT=31.41 |
|||
|
|||
# The following variables can be useful when debugging the application |
|||
APP_ENV=local |
|||
APP_DEBUG=false |
|||
LOG_CHANNEL=stack |
|||
|
|||
# Log level. You can set this from least severe to most severe: |
|||
# debug, info, notice, warning, error, critical, alert, emergency |
|||
# If you set it to debug your logs will grow large, and fast. If you set it to emergency probably |
|||
# nothing will get logged, ever. |
|||
LOG_LEVEL=debug |
|||
|
|||
# TRUSTED_PROXIES is a useful variable when using Docker and/or a reverse proxy. |
|||
# Set it to ** and reverse proxies work just fine. |
|||
TRUSTED_PROXIES= |
|||
|
|||
# |
|||
# Time zone |
|||
# |
|||
TZ=Europe/Amsterdam |
|||
|
|||
# |
|||
# Use ASSET_URL when you're running the CSV importer in a sub-directory. |
|||
# |
|||
ASSET_URL= |
|||
|
|||
# |
|||
# Email settings. |
|||
# The CSV importer can send you a message with all errors, warnings and messages |
|||
# after a successful import. This is disabled by default |
|||
# |
|||
ENABLE_MAIL_REPORT=false |
|||
|
|||
# If enabled, define which mailer you want to use. |
|||
# Options include: smtp, mailgun, postmark, sendmail, log, array |
|||
# Amazon SES is not supported. |
|||
# log = drop mails in the logs instead of sending them |
|||
# array = debug mailer that does nothing. |
|||
MAIL_DESTINATION=YOUR_OWN_EMAIL@example.com |
|||
|
|||
# |
|||
# Force Firefly III URL to be secure? |
|||
# |
|||
# |
|||
EXPECT_SECURE_URL=false |
|||
|
|||
MAIL_MAILER=smtp |
|||
MAIL_HOST=example.com |
|||
MAIL_PORT=25 |
|||
MAIL_ENCRYPTION=tls |
|||
MAIL_USERNAME=username |
|||
MAIL_PASSWORD=secret |
|||
MAIL_FROM_ADDRESS=noreply@example.com |
|||
|
|||
# Extra settings depending on your mail configuration above. |
|||
MAILGUN_DOMAIN= |
|||
MAILGUN_SECRET= |
|||
MAILGUN_ENDPOINT= |
|||
POSTMARK_TOKEN= |
|||
|
|||
# |
|||
# You probably won't need to change these settings. |
|||
# |
|||
BROADCAST_DRIVER=log |
|||
CACHE_DRIVER=file |
|||
QUEUE_CONNECTION=sync |
|||
SESSION_DRIVER=file |
|||
SESSION_LIFETIME=120 |
|||
IS_EXTERNAL=false |
|||
|
|||
REDIS_HOST=127.0.0.1 |
|||
REDIS_PASSWORD=null |
|||
REDIS_PORT=6379 |
|||
|
|||
# always use quotes |
|||
REDIS_DB="0" |
|||
REDIS_CACHE_DB="1" |
|||
|
|||
# The only tracker supported is Matomo. |
|||
# This is used on the public instance. |
|||
TRACKER_SITE_ID= |
|||
TRACKER_URL= |
|||
|
|||
|
|||
APP_NAME=CSVImporter |
|||
|
|||
# |
|||
# The APP_URL environment variable is NOT used anywhere. |
|||
# Don't bother setting it to fix your reverse proxy problems. It won't help. |
|||
# Don't open issues telling me it doesn't help because it's not supposed to. |
|||
# Laravel uses this to generate links on the command line, which is a feature the CVS importer does not use. |
|||
# |
|||
APP_URL=http://localhost |
@ -0,0 +1,5 @@ |
|||
* text=auto |
|||
*.css linguist-vendored |
|||
*.scss linguist-vendored |
|||
*.js linguist-vendored |
|||
CHANGELOG.md export-ignore |
@ -0,0 +1,46 @@ |
|||
# Contributor Covenant Code of Conduct |
|||
|
|||
## Our Pledge |
|||
|
|||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. |
|||
|
|||
## Our Standards |
|||
|
|||
Examples of behavior that contributes to creating a positive environment include: |
|||
|
|||
* Using welcoming and inclusive language |
|||
* Being respectful of differing viewpoints and experiences |
|||
* Gracefully accepting constructive criticism |
|||
* Focusing on what is best for the community |
|||
* Showing empathy towards other community members |
|||
|
|||
Examples of unacceptable behavior by participants include: |
|||
|
|||
* The use of sexualized language or imagery and unwelcome sexual attention or advances |
|||
* Trolling, insulting/derogatory comments, and personal or political attacks |
|||
* Public or private harassment |
|||
* Publishing others' private information, such as a physical or electronic address, without explicit permission |
|||
* Other conduct which could reasonably be considered inappropriate in a professional setting |
|||
|
|||
## Our Responsibilities |
|||
|
|||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. |
|||
|
|||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. |
|||
|
|||
## Scope |
|||
|
|||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. |
|||
|
|||
## Enforcement |
|||
|
|||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at james@firefly-iii.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. |
|||
|
|||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. |
|||
|
|||
## Attribution |
|||
|
|||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] |
|||
|
|||
[homepage]: http://contributor-covenant.org |
|||
[version]: http://contributor-covenant.org/version/1/4/ |
@ -0,0 +1,3 @@ |
|||
# [Contributing guidelines](https://docs.firefly-iii.org/other-pages/contributing) |
|||
|
|||
[Contributing guidelines](https://docs.firefly-iii.org/other-pages/contributing) |
@ -0,0 +1,18 @@ |
|||
version: 2 |
|||
updates: |
|||
|
|||
# composer updates |
|||
- package-ecosystem: "composer" |
|||
directory: "/" |
|||
target-branch: develop |
|||
labels: ["bug"] |
|||
schedule: |
|||
interval: "weekly" |
|||
|
|||
# yarn / JS updates |
|||
- package-ecosystem: "npm" |
|||
directory: "/" |
|||
target-branch: develop |
|||
labels: ["bug"] |
|||
schedule: |
|||
interval: "weekly" |
@ -0,0 +1,4 @@ |
|||
# These are supported funding model platforms |
|||
|
|||
github: jc5 |
|||
patreon: JC5 |
@ -0,0 +1,7 @@ |
|||
--- |
|||
name: I have a question or a problem |
|||
about: Ask away! |
|||
|
|||
--- |
|||
|
|||
(empty template) |
@ -0,0 +1,9 @@ |
|||
Fixes issue # (if relevant) |
|||
|
|||
Changes in this pull request: |
|||
|
|||
- |
|||
- |
|||
- |
|||
|
|||
@JC5 |
@ -0,0 +1,5 @@ |
|||
# Security Policy |
|||
|
|||
The Security Policy for the software and/or documentation in this repository is equal to the [Security Policy](https://github.com/firefly-iii/firefly-iii/security/policy) of [Firefly III](https://github.com/firefly-iii/firefly-iii) itself. |
|||
|
|||
* https://github.com/firefly-iii/firefly-iii/security/policy |
@ -0,0 +1,16 @@ |
|||
|
|||
# Welcome to the Firefly III CSV importer on Github! |
|||
|
|||
:+1::tada: Thank you for taking the time to contribute something to the Firefly III CSV importer! |
|||
|
|||
## Bugs |
|||
|
|||
First of all: thank you for reporting a bug instead of ditching the tool altogether. If you find a bug, include as many log files and details as you think |
|||
are necessary. Bugs have a lot of priority! |
|||
|
|||
## Installation problems |
|||
|
|||
Please take the time to read the [documentation of Firefly III](https://docs.firefly-iii.org/) or the |
|||
[documentation of the CSV importer](https://docs.firefly-iii.org/csv) and make sure you search through closed issues for the problems |
|||
other people have had. Your problem may be among them! If not, open an issue and I will help where I can. |
|||
|
@ -0,0 +1,12 @@ |
|||
/node_modules |
|||
/public/hot |
|||
/public/storage |
|||
/storage/*.key |
|||
/vendor |
|||
.env |
|||
.env.backup |
|||
.phpunit.result.cache |
|||
Homestead.json |
|||
Homestead.yaml |
|||
npm-debug.log |
|||
yarn-error.log |
@ -0,0 +1,58 @@ |
|||
--- |
|||
build: |
|||
nodes: |
|||
analysis: |
|||
project_setup: |
|||
override: true |
|||
tests: |
|||
override: |
|||
- php-scrutinizer-run |
|||
checks: |
|||
javascript: true |
|||
php: |
|||
align_assignments: true |
|||
avoid_fixme_comments: true |
|||
avoid_multiple_statements_on_same_line: true |
|||
avoid_perl_style_comments: true |
|||
avoid_todo_comments: true |
|||
duplication: false |
|||
encourage_single_quotes: true |
|||
newline_at_end_of_file: true |
|||
no_goto: true |
|||
no_long_variable_names: |
|||
maximum: "20" |
|||
no_short_method_names: |
|||
minimum: "3" |
|||
no_short_variable_names: |
|||
minimum: "3" |
|||
optional_parameters_at_the_end: true |
|||
parameter_doc_comments: true |
|||
remove_extra_empty_lines: true |
|||
return_doc_comment_if_not_inferrable: true |
|||
return_doc_comments: true |
|||
uppercase_constants: true |
|||
use_self_instead_of_fqcn: true |
|||
coding_style: |
|||
php: |
|||
spaces: |
|||
around_operators: |
|||
concatenation: true |
|||
other: |
|||
after_type_cast: false |
|||
filter: |
|||
excluded_paths: |
|||
- database/migrations/* |
|||
- bootstrap/* |
|||
- config/* |
|||
- docker/* |
|||
- public/js/lib/* |
|||
- public/lib/adminlte/js/* |
|||
- public/lib/bootstrap/js/* |
|||
- resources/* |
|||
- routes/* |
|||
- storage/* |
|||
paths: |
|||
- app/* |
|||
- public/js/ff/* |
|||
tools: |
|||
external_code_coverage: false |
@ -0,0 +1,13 @@ |
|||
php: |
|||
preset: laravel |
|||
disabled: |
|||
- unused_use |
|||
finder: |
|||
not-name: |
|||
- index.php |
|||
- server.php |
|||
js: |
|||
finder: |
|||
not-name: |
|||
- webpack.mix.js |
|||
css: true |
@ -0,0 +1,661 @@ |
|||
GNU AFFERO GENERAL PUBLIC LICENSE |
|||
Version 3, 19 November 2007 |
|||
|
|||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> |
|||
Everyone is permitted to copy and distribute verbatim copies |
|||
of this license document, but changing it is not allowed. |
|||
|
|||
Preamble |
|||
|
|||
The GNU Affero General Public License is a free, copyleft license for |
|||
software and other kinds of works, specifically designed to ensure |
|||
cooperation with the community in the case of network server software. |
|||
|
|||
The licenses for most software and other practical works are designed |
|||
to take away your freedom to share and change the works. By contrast, |
|||
our General Public Licenses are intended to guarantee your freedom to |
|||
share and change all versions of a program--to make sure it remains free |
|||
software for all its users. |
|||
|
|||
When we speak of free software, we are referring to freedom, not |
|||
price. Our General Public Licenses are designed to make sure that you |
|||
have the freedom to distribute copies of free software (and charge for |
|||
them if you wish), that you receive source code or can get it if you |
|||
want it, that you can change the software or use pieces of it in new |
|||
free programs, and that you know you can do these things. |
|||
|
|||
Developers that use our General Public Licenses protect your rights |
|||
with two steps: (1) assert copyright on the software, and (2) offer |
|||
you this License which gives you legal permission to copy, distribute |
|||
and/or modify the software. |
|||
|
|||
A secondary benefit of defending all users' freedom is that |
|||
improvements made in alternate versions of the program, if they |
|||
receive widespread use, become available for other developers to |
|||
incorporate. Many developers of free software are heartened and |
|||
encouraged by the resulting cooperation. However, in the case of |
|||
software used on network servers, this result may fail to come about. |
|||
The GNU General Public License permits making a modified version and |
|||
letting the public access it on a server without ever releasing its |
|||
source code to the public. |
|||
|
|||
The GNU Affero General Public License is designed specifically to |
|||
ensure that, in such cases, the modified source code becomes available |
|||
to the community. It requires the operator of a network server to |
|||
provide the source code of the modified version running there to the |
|||
users of that server. Therefore, public use of a modified version, on |
|||
a publicly accessible server, gives the public access to the source |
|||
code of the modified version. |
|||
|
|||
An older license, called the Affero General Public License and |
|||
published by Affero, was designed to accomplish similar goals. This is |
|||
a different license, not a version of the Affero GPL, but Affero has |
|||
released a new version of the Affero GPL which permits relicensing under |
|||
this license. |
|||
|
|||
The precise terms and conditions for copying, distribution and |
|||
modification follow. |
|||
|
|||
TERMS AND CONDITIONS |
|||
|
|||
0. Definitions. |
|||
|
|||
"This License" refers to version 3 of the GNU Affero General Public License. |
|||
|
|||
"Copyright" also means copyright-like laws that apply to other kinds of |
|||
works, such as semiconductor masks. |
|||
|
|||
"The Program" refers to any copyrightable work licensed under this |
|||
License. Each licensee is addressed as "you". "Licensees" and |
|||
"recipients" may be individuals or organizations. |
|||
|
|||
To "modify" a work means to copy from or adapt all or part of the work |
|||
in a fashion requiring copyright permission, other than the making of an |
|||
exact copy. The resulting work is called a "modified version" of the |
|||
earlier work or a work "based on" the earlier work. |
|||
|
|||
A "covered work" means either the unmodified Program or a work based |
|||
on the Program. |
|||
|
|||
To "propagate" a work means to do anything with it that, without |
|||
permission, would make you directly or secondarily liable for |
|||
infringement under applicable copyright law, except executing it on a |
|||
computer or modifying a private copy. Propagation includes copying, |
|||
distribution (with or without modification), making available to the |
|||
public, and in some countries other activities as well. |
|||
|
|||
To "convey" a work means any kind of propagation that enables other |
|||
parties to make or receive copies. Mere interaction with a user through |
|||
a computer network, with no transfer of a copy, is not conveying. |
|||
|
|||
An interactive user interface displays "Appropriate Legal Notices" |
|||
to the extent that it includes a convenient and prominently visible |
|||
feature that (1) displays an appropriate copyright notice, and (2) |
|||
tells the user that there is no warranty for the work (except to the |
|||
extent that warranties are provided), that licensees may convey the |
|||
work under this License, and how to view a copy of this License. If |
|||
the interface presents a list of user commands or options, such as a |
|||
menu, a prominent item in the list meets this criterion. |
|||
|
|||
1. Source Code. |
|||
|
|||
The "source code" for a work means the preferred form of the work |
|||
for making modifications to it. "Object code" means any non-source |
|||
form of a work. |
|||
|
|||
A "Standard Interface" means an interface that either is an official |
|||
standard defined by a recognized standards body, or, in the case of |
|||
interfaces specified for a particular programming language, one that |
|||
is widely used among developers working in that language. |
|||
|
|||
The "System Libraries" of an executable work include anything, other |
|||
than the work as a whole, that (a) is included in the normal form of |
|||
packaging a Major Component, but which is not part of that Major |
|||
Component, and (b) serves only to enable use of the work with that |
|||
Major Component, or to implement a Standard Interface for which an |
|||
implementation is available to the public in source code form. A |
|||
"Major Component", in this context, means a major essential component |
|||
(kernel, window system, and so on) of the specific operating system |
|||
(if any) on which the executable work runs, or a compiler used to |
|||
produce the work, or an object code interpreter used to run it. |
|||
|
|||
The "Corresponding Source" for a work in object code form means all |
|||
the source code needed to generate, install, and (for an executable |
|||
work) run the object code and to modify the work, including scripts to |
|||
control those activities. However, it does not include the work's |
|||
System Libraries, or general-purpose tools or generally available free |
|||
programs which are used unmodified in performing those activities but |
|||
which are not part of the work. For example, Corresponding Source |
|||
includes interface definition files associated with source files for |
|||
the work, and the source code for shared libraries and dynamically |
|||
linked subprograms that the work is specifically designed to require, |
|||
such as by intimate data communication or control flow between those |
|||
subprograms and other parts of the work. |
|||
|
|||
The Corresponding Source need not include anything that users |
|||
can regenerate automatically from other parts of the Corresponding |
|||
Source. |
|||
|
|||
The Corresponding Source for a work in source code form is that |
|||
same work. |
|||
|
|||
2. Basic Permissions. |
|||
|
|||
All rights granted under this License are granted for the term of |
|||
copyright on the Program, and are irrevocable provided the stated |
|||
conditions are met. This License explicitly affirms your unlimited |
|||
permission to run the unmodified Program. The output from running a |
|||
covered work is covered by this License only if the output, given its |
|||
content, constitutes a covered work. This License acknowledges your |
|||
rights of fair use or other equivalent, as provided by copyright law. |
|||
|
|||
You may make, run and propagate covered works that you do not |
|||
convey, without conditions so long as your license otherwise remains |
|||
in force. You may convey covered works to others for the sole purpose |
|||
of having them make modifications exclusively for you, or provide you |
|||
with facilities for running those works, provided that you comply with |
|||
the terms of this License in conveying all material for which you do |
|||
not control copyright. Those thus making or running the covered works |
|||
for you must do so exclusively on your behalf, under your direction |
|||
and control, on terms that prohibit them from making any copies of |
|||
your copyrighted material outside their relationship with you. |
|||
|
|||
Conveying under any other circumstances is permitted solely under |
|||
the conditions stated below. Sublicensing is not allowed; section 10 |
|||
makes it unnecessary. |
|||
|
|||
3. Protecting Users' Legal Rights From Anti-Circumvention Law. |
|||
|
|||
No covered work shall be deemed part of an effective technological |
|||
measure under any applicable law fulfilling obligations under article |
|||
11 of the WIPO copyright treaty adopted on 20 December 1996, or |
|||
similar laws prohibiting or restricting circumvention of such |
|||
measures. |
|||
|
|||
When you convey a covered work, you waive any legal power to forbid |
|||
circumvention of technological measures to the extent such circumvention |
|||
is effected by exercising rights under this License with respect to |
|||
the covered work, and you disclaim any intention to limit operation or |
|||
modification of the work as a means of enforcing, against the work's |
|||
users, your or third parties' legal rights to forbid circumvention of |
|||
technological measures. |
|||
|
|||
4. Conveying Verbatim Copies. |
|||
|
|||
You may convey verbatim copies of the Program's source code as you |
|||
receive it, in any medium, provided that you conspicuously and |
|||
appropriately publish on each copy an appropriate copyright notice; |
|||
keep intact all notices stating that this License and any |
|||
non-permissive terms added in accord with section 7 apply to the code; |
|||
keep intact all notices of the absence of any warranty; and give all |
|||
recipients a copy of this License along with the Program. |
|||
|
|||
You may charge any price or no price for each copy that you convey, |
|||
and you may offer support or warranty protection for a fee. |
|||
|
|||
5. Conveying Modified Source Versions. |
|||
|
|||
You may convey a work based on the Program, or the modifications to |
|||
produce it from the Program, in the form of source code under the |
|||
terms of section 4, provided that you also meet all of these conditions: |
|||
|
|||
a) The work must carry prominent notices stating that you modified |
|||
it, and giving a relevant date. |
|||
|
|||
b) The work must carry prominent notices stating that it is |
|||
released under this License and any conditions added under section |
|||
7. This requirement modifies the requirement in section 4 to |
|||
"keep intact all notices". |
|||
|
|||
c) You must license the entire work, as a whole, under this |
|||
License to anyone who comes into possession of a copy. This |
|||
License will therefore apply, along with any applicable section 7 |
|||
additional terms, to the whole of the work, and all its parts, |
|||
regardless of how they are packaged. This License gives no |
|||
permission to license the work in any other way, but it does not |
|||
invalidate such permission if you have separately received it. |
|||
|
|||
d) If the work has interactive user interfaces, each must display |
|||
Appropriate Legal Notices; however, if the Program has interactive |
|||
interfaces that do not display Appropriate Legal Notices, your |
|||
work need not make them do so. |
|||
|
|||
A compilation of a covered work with other separate and independent |
|||
works, which are not by their nature extensions of the covered work, |
|||
and which are not combined with it such as to form a larger program, |
|||
in or on a volume of a storage or distribution medium, is called an |
|||
"aggregate" if the compilation and its resulting copyright are not |
|||
used to limit the access or legal rights of the compilation's users |
|||
beyond what the individual works permit. Inclusion of a covered work |
|||
in an aggregate does not cause this License to apply to the other |
|||
parts of the aggregate. |
|||
|
|||
6. Conveying Non-Source Forms. |
|||
|
|||
You may convey a covered work in object code form under the terms |
|||
of sections 4 and 5, provided that you also convey the |
|||
machine-readable Corresponding Source under the terms of this License, |
|||
in one of these ways: |
|||
|
|||
a) Convey the object code in, or embodied in, a physical product |
|||
(including a physical distribution medium), accompanied by the |
|||
Corresponding Source fixed on a durable physical medium |
|||
customarily used for software interchange. |
|||
|
|||
b) Convey the object code in, or embodied in, a physical product |
|||
(including a physical distribution medium), accompanied by a |
|||
written offer, valid for at least three years and valid for as |
|||
long as you offer spare parts or customer support for that product |
|||
model, to give anyone who possesses the object code either (1) a |
|||
copy of the Corresponding Source for all the software in the |
|||
product that is covered by this License, on a durable physical |
|||
medium customarily used for software interchange, for a price no |
|||
more than your reasonable cost of physically performing this |
|||
conveying of source, or (2) access to copy the |
|||
Corresponding Source from a network server at no charge. |
|||
|
|||
c) Convey individual copies of the object code with a copy of the |
|||
written offer to provide the Corresponding Source. This |
|||
alternative is allowed only occasionally and noncommercially, and |
|||
only if you received the object code with such an offer, in accord |
|||
with subsection 6b. |
|||
|
|||
d) Convey the object code by offering access from a designated |
|||
place (gratis or for a charge), and offer equivalent access to the |
|||
Corresponding Source in the same way through the same place at no |
|||
further charge. You need not require recipients to copy the |
|||
Corresponding Source along with the object code. If the place to |
|||
copy the object code is a network server, the Corresponding Source |
|||
may be on a different server (operated by you or a third party) |
|||
that supports equivalent copying facilities, provided you maintain |
|||
clear directions next to the object code saying where to find the |
|||
Corresponding Source. Regardless of what server hosts the |
|||
Corresponding Source, you remain obligated to ensure that it is |
|||
available for as long as needed to satisfy these requirements. |
|||
|
|||
e) Convey the object code using peer-to-peer transmission, provided |
|||
you inform other peers where the object code and Corresponding |
|||
Source of the work are being offered to the general public at no |
|||
charge under subsection 6d. |
|||
|
|||
A separable portion of the object code, whose source code is excluded |
|||
from the Corresponding Source as a System Library, need not be |
|||
included in conveying the object code work. |
|||
|
|||
A "User Product" is either (1) a "consumer product", which means any |
|||
tangible personal property which is normally used for personal, family, |
|||
or household purposes, or (2) anything designed or sold for incorporation |
|||
into a dwelling. In determining whether a product is a consumer product, |
|||
doubtful cases shall be resolved in favor of coverage. For a particular |
|||
product received by a particular user, "normally used" refers to a |
|||
typical or common use of that class of product, regardless of the status |
|||
of the particular user or of the way in which the particular user |
|||
actually uses, or expects or is expected to use, the product. A product |
|||
is a consumer product regardless of whether the product has substantial |
|||
commercial, industrial or non-consumer uses, unless such uses represent |
|||
the only significant mode of use of the product. |
|||
|
|||
"Installation Information" for a User Product means any methods, |
|||
procedures, authorization keys, or other information required to install |
|||
and execute modified versions of a covered work in that User Product from |
|||
a modified version of its Corresponding Source. The information must |
|||
suffice to ensure that the continued functioning of the modified object |
|||
code is in no case prevented or interfered with solely because |
|||
modification has been made. |
|||
|
|||
If you convey an object code work under this section in, or with, or |
|||
specifically for use in, a User Product, and the conveying occurs as |
|||
part of a transaction in which the right of possession and use of the |
|||
User Product is transferred to the recipient in perpetuity or for a |
|||
fixed term (regardless of how the transaction is characterized), the |
|||
Corresponding Source conveyed under this section must be accompanied |
|||
by the Installation Information. But this requirement does not apply |
|||
if neither you nor any third party retains the ability to install |
|||
modified object code on the User Product (for example, the work has |
|||
been installed in ROM). |
|||
|
|||
The requirement to provide Installation Information does not include a |
|||
requirement to continue to provide support service, warranty, or updates |
|||
for a work that has been modified or installed by the recipient, or for |
|||
the User Product in which it has been modified or installed. Access to a |
|||
network may be denied when the modification itself materially and |
|||
adversely affects the operation of the network or violates the rules and |
|||
protocols for communication across the network. |
|||
|
|||
Corresponding Source conveyed, and Installation Information provided, |
|||
in accord with this section must be in a format that is publicly |
|||
documented (and with an implementation available to the public in |
|||
source code form), and must require no special password or key for |
|||
unpacking, reading or copying. |
|||
|
|||
7. Additional Terms. |
|||
|
|||
"Additional permissions" are terms that supplement the terms of this |
|||
License by making exceptions from one or more of its conditions. |
|||
Additional permissions that are applicable to the entire Program shall |
|||
be treated as though they were included in this License, to the extent |
|||
that they are valid under applicable law. If additional permissions |
|||
apply only to part of the Program, that part may be used separately |
|||
under those permissions, but the entire Program remains governed by |
|||
this License without regard to the additional permissions. |
|||
|
|||
When you convey a copy of a covered work, you may at your option |
|||
remove any additional permissions from that copy, or from any part of |
|||
it. (Additional permissions may be written to require their own |
|||
removal in certain cases when you modify the work.) You may place |
|||
additional permissions on material, added by you to a covered work, |
|||
for which you have or can give appropriate copyright permission. |
|||
|
|||
Notwithstanding any other provision of this License, for material you |
|||
add to a covered work, you may (if authorized by the copyright holders of |
|||
that material) supplement the terms of this License with terms: |
|||
|
|||
a) Disclaiming warranty or limiting liability differently from the |
|||
terms of sections 15 and 16 of this License; or |
|||
|
|||
b) Requiring preservation of specified reasonable legal notices or |
|||
author attributions in that material or in the Appropriate Legal |
|||
Notices displayed by works containing it; or |
|||
|
|||
c) Prohibiting misrepresentation of the origin of that material, or |
|||
requiring that modified versions of such material be marked in |
|||
reasonable ways as different from the original version; or |
|||
|
|||
d) Limiting the use for publicity purposes of names of licensors or |
|||
authors of the material; or |
|||
|
|||
e) Declining to grant rights under trademark law for use of some |
|||
trade names, trademarks, or service marks; or |
|||
|
|||
f) Requiring indemnification of licensors and authors of that |
|||
material by anyone who conveys the material (or modified versions of |
|||
it) with contractual assumptions of liability to the recipient, for |
|||
any liability that these contractual assumptions directly impose on |
|||
those licensors and authors. |
|||
|
|||
All other non-permissive additional terms are considered "further |
|||
restrictions" within the meaning of section 10. If the Program as you |
|||
received it, or any part of it, contains a notice stating that it is |
|||
governed by this License along with a term that is a further |
|||
restriction, you may remove that term. If a license document contains |
|||
a further restriction but permits relicensing or conveying under this |
|||
License, you may add to a covered work material governed by the terms |
|||
of that license document, provided that the further restriction does |
|||
not survive such relicensing or conveying. |
|||
|
|||
If you add terms to a covered work in accord with this section, you |
|||
must place, in the relevant source files, a statement of the |
|||
additional terms that apply to those files, or a notice indicating |
|||
where to find the applicable terms. |
|||
|
|||
Additional terms, permissive or non-permissive, may be stated in the |
|||
form of a separately written license, or stated as exceptions; |
|||
the above requirements apply either way. |
|||
|
|||
8. Termination. |
|||
|
|||
You may not propagate or modify a covered work except as expressly |
|||
provided under this License. Any attempt otherwise to propagate or |
|||
modify it is void, and will automatically terminate your rights under |
|||
this License (including any patent licenses granted under the third |
|||
paragraph of section 11). |
|||
|
|||
However, if you cease all violation of this License, then your |
|||
license from a particular copyright holder is reinstated (a) |
|||
provisionally, unless and until the copyright holder explicitly and |
|||
finally terminates your license, and (b) permanently, if the copyright |
|||
holder fails to notify you of the violation by some reasonable means |
|||
prior to 60 days after the cessation. |
|||
|
|||
Moreover, your license from a particular copyright holder is |
|||
reinstated permanently if the copyright holder notifies you of the |
|||
violation by some reasonable means, this is the first time you have |
|||
received notice of violation of this License (for any work) from that |
|||
copyright holder, and you cure the violation prior to 30 days after |
|||
your receipt of the notice. |
|||
|
|||
Termination of your rights under this section does not terminate the |
|||
licenses of parties who have received copies or rights from you under |
|||
this License. If your rights have been terminated and not permanently |
|||
reinstated, you do not qualify to receive new licenses for the same |
|||
material under section 10. |
|||
|
|||
9. Acceptance Not Required for Having Copies. |
|||
|
|||
You are not required to accept this License in order to receive or |
|||
run a copy of the Program. Ancillary propagation of a covered work |
|||
occurring solely as a consequence of using peer-to-peer transmission |
|||
to receive a copy likewise does not require acceptance. However, |
|||
nothing other than this License grants you permission to propagate or |
|||
modify any covered work. These actions infringe copyright if you do |
|||
not accept this License. Therefore, by modifying or propagating a |
|||
covered work, you indicate your acceptance of this License to do so. |
|||
|
|||
10. Automatic Licensing of Downstream Recipients. |
|||
|
|||
Each time you convey a covered work, the recipient automatically |
|||
receives a license from the original licensors, to run, modify and |
|||
propagate that work, subject to this License. You are not responsible |
|||
for enforcing compliance by third parties with this License. |
|||
|
|||
An "entity transaction" is a transaction transferring control of an |
|||
organization, or substantially all assets of one, or subdividing an |
|||
organization, or merging organizations. If propagation of a covered |
|||
work results from an entity transaction, each party to that |
|||
transaction who receives a copy of the work also receives whatever |
|||
licenses to the work the party's predecessor in interest had or could |
|||
give under the previous paragraph, plus a right to possession of the |
|||
Corresponding Source of the work from the predecessor in interest, if |
|||
the predecessor has it or can get it with reasonable efforts. |
|||
|
|||
You may not impose any further restrictions on the exercise of the |
|||
rights granted or affirmed under this License. For example, you may |
|||
not impose a license fee, royalty, or other charge for exercise of |
|||
rights granted under this License, and you may not initiate litigation |
|||
(including a cross-claim or counterclaim in a lawsuit) alleging that |
|||
any patent claim is infringed by making, using, selling, offering for |
|||
sale, or importing the Program or any portion of it. |
|||
|
|||
11. Patents. |
|||
|
|||
A "contributor" is a copyright holder who authorizes use under this |
|||
License of the Program or a work on which the Program is based. The |
|||
work thus licensed is called the contributor's "contributor version". |
|||
|
|||
A contributor's "essential patent claims" are all patent claims |
|||
owned or controlled by the contributor, whether already acquired or |
|||
hereafter acquired, that would be infringed by some manner, permitted |
|||
by this License, of making, using, or selling its contributor version, |
|||
but do not include claims that would be infringed only as a |
|||
consequence of further modification of the contributor version. For |
|||
purposes of this definition, "control" includes the right to grant |
|||
patent sublicenses in a manner consistent with the requirements of |
|||
this License. |
|||
|
|||
Each contributor grants you a non-exclusive, worldwide, royalty-free |
|||
patent license under the contributor's essential patent claims, to |
|||
make, use, sell, offer for sale, import and otherwise run, modify and |
|||
propagate the contents of its contributor version. |
|||
|
|||
In the following three paragraphs, a "patent license" is any express |
|||
agreement or commitment, however denominated, not to enforce a patent |
|||
(such as an express permission to practice a patent or covenant not to |
|||
sue for patent infringement). To "grant" such a patent license to a |
|||
party means to make such an agreement or commitment not to enforce a |
|||
patent against the party. |
|||
|
|||
If you convey a covered work, knowingly relying on a patent license, |
|||
and the Corresponding Source of the work is not available for anyone |
|||
to copy, free of charge and under the terms of this License, through a |
|||
publicly available network server or other readily accessible means, |
|||
then you must either (1) cause the Corresponding Source to be so |
|||
available, or (2) arrange to deprive yourself of the benefit of the |
|||
patent license for this particular work, or (3) arrange, in a manner |
|||
consistent with the requirements of this License, to extend the patent |
|||
license to downstream recipients. "Knowingly relying" means you have |
|||
actual knowledge that, but for the patent license, your conveying the |
|||
covered work in a country, or your recipient's use of the covered work |
|||
in a country, would infringe one or more identifiable patents in that |
|||
country that you have reason to believe are valid. |
|||
|
|||
If, pursuant to or in connection with a single transaction or |
|||
arrangement, you convey, or propagate by procuring conveyance of, a |
|||
covered work, and grant a patent license to some of the parties |
|||
receiving the covered work authorizing them to use, propagate, modify |
|||
or convey a specific copy of the covered work, then the patent license |
|||
you grant is automatically extended to all recipients of the covered |
|||
work and works based on it. |
|||
|
|||
A patent license is "discriminatory" if it does not include within |
|||
the scope of its coverage, prohibits the exercise of, or is |
|||
conditioned on the non-exercise of one or more of the rights that are |
|||
specifically granted under this License. You may not convey a covered |
|||
work if you are a party to an arrangement with a third party that is |
|||
in the business of distributing software, under which you make payment |
|||
to the third party based on the extent of your activity of conveying |
|||
the work, and under which the third party grants, to any of the |
|||
parties who would receive the covered work from you, a discriminatory |
|||
patent license (a) in connection with copies of the covered work |
|||
conveyed by you (or copies made from those copies), or (b) primarily |
|||
for and in connection with specific products or compilations that |
|||
contain the covered work, unless you entered into that arrangement, |
|||
or that patent license was granted, prior to 28 March 2007. |
|||
|
|||
Nothing in this License shall be construed as excluding or limiting |
|||
any implied license or other defenses to infringement that may |
|||
otherwise be available to you under applicable patent law. |
|||
|
|||
12. No Surrender of Others' Freedom. |
|||
|
|||
If conditions are imposed on you (whether by court order, agreement or |
|||
otherwise) that contradict the conditions of this License, they do not |
|||
excuse you from the conditions of this License. If you cannot convey a |
|||
covered work so as to satisfy simultaneously your obligations under this |
|||
License and any other pertinent obligations, then as a consequence you may |
|||
not convey it at all. For example, if you agree to terms that obligate you |
|||
to collect a royalty for further conveying from those to whom you convey |
|||
the Program, the only way you could satisfy both those terms and this |
|||
License would be to refrain entirely from conveying the Program. |
|||
|
|||
13. Remote Network Interaction; Use with the GNU General Public License. |
|||
|
|||
Notwithstanding any other provision of this License, if you modify the |
|||
Program, your modified version must prominently offer all users |
|||
interacting with it remotely through a computer network (if your version |
|||
supports such interaction) an opportunity to receive the Corresponding |
|||
Source of your version by providing access to the Corresponding Source |
|||
from a network server at no charge, through some standard or customary |
|||
means of facilitating copying of software. This Corresponding Source |
|||
shall include the Corresponding Source for any work covered by version 3 |
|||
of the GNU General Public License that is incorporated pursuant to the |
|||
following paragraph. |
|||
|
|||
Notwithstanding any other provision of this License, you have |
|||
permission to link or combine any covered work with a work licensed |
|||
under version 3 of the GNU General Public License into a single |
|||
combined work, and to convey the resulting work. The terms of this |
|||
License will continue to apply to the part which is the covered work, |
|||
but the work with which it is combined will remain governed by version |
|||
3 of the GNU General Public License. |
|||
|
|||
14. Revised Versions of this License. |
|||
|
|||
The Free Software Foundation may publish revised and/or new versions of |
|||
the GNU Affero General Public License from time to time. Such new versions |
|||
will be similar in spirit to the present version, but may differ in detail to |
|||
address new problems or concerns. |
|||
|
|||
Each version is given a distinguishing version number. If the |
|||
Program specifies that a certain numbered version of the GNU Affero General |
|||
Public License "or any later version" applies to it, you have the |
|||
option of following the terms and conditions either of that numbered |
|||
version or of any later version published by the Free Software |
|||
Foundation. If the Program does not specify a version number of the |
|||
GNU Affero General Public License, you may choose any version ever published |
|||
by the Free Software Foundation. |
|||
|
|||
If the Program specifies that a proxy can decide which future |
|||
versions of the GNU Affero General Public License can be used, that proxy's |
|||
public statement of acceptance of a version permanently authorizes you |
|||
to choose that version for the Program. |
|||
|
|||
Later license versions may give you additional or different |
|||
permissions. However, no additional obligations are imposed on any |
|||
author or copyright holder as a result of your choosing to follow a |
|||
later version. |
|||
|
|||
15. Disclaimer of Warranty. |
|||
|
|||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY |
|||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT |
|||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY |
|||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, |
|||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM |
|||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF |
|||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
|||
|
|||
16. Limitation of Liability. |
|||
|
|||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
|||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS |
|||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY |
|||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE |
|||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF |
|||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD |
|||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), |
|||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF |
|||
SUCH DAMAGES. |
|||
|
|||
17. Interpretation of Sections 15 and 16. |
|||
|
|||
If the disclaimer of warranty and limitation of liability provided |
|||
above cannot be given local legal effect according to their terms, |
|||
reviewing courts shall apply local law that most closely approximates |
|||
an absolute waiver of all civil liability in connection with the |
|||
Program, unless a warranty or assumption of liability accompanies a |
|||
copy of the Program in return for a fee. |
|||
|
|||
END OF TERMS AND CONDITIONS |
|||
|
|||
How to Apply These Terms to Your New Programs |
|||
|
|||
If you develop a new program, and you want it to be of the greatest |
|||
possible use to the public, the best way to achieve this is to make it |
|||
free software which everyone can redistribute and change under these terms. |
|||
|
|||
To do so, attach the following notices to the program. It is safest |
|||
to attach them to the start of each source file to most effectively |
|||
state the exclusion of warranty; and each file should have at least |
|||
the "copyright" line and a pointer to where the full notice is found. |
|||
|
|||
<one line to give the program's name and a brief idea of what it does.> |
|||
Copyright (C) <year> <name of author> |
|||
|
|||
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/>. |
|||
|
|||
Also add information on how to contact you by electronic and paper mail. |
|||
|
|||
If your software can interact with users remotely through a computer |
|||
network, you should also make sure that it provides a way for users to |
|||
get its source. For example, if your program is a web application, its |
|||
interface could display a "Source" link that leads users to an archive |
|||
of the code. There are many ways you could offer source, and different |
|||
solutions will be better for different programs; see section 13 for the |
|||
specific requirements. |
|||
|
|||
You should also get your employer (if you work as a programmer) or school, |
|||
if any, to sign a "copyright disclaimer" for the program, if necessary. |
|||
For more information on this, and how to apply and follow the GNU AGPL, see |
|||
<https://www.gnu.org/licenses/>. |
@ -0,0 +1,661 @@ |
|||
GNU AFFERO GENERAL PUBLIC LICENSE |
|||
Version 3, 19 November 2007 |
|||
|
|||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> |
|||
Everyone is permitted to copy and distribute verbatim copies |
|||
of this license document, but changing it is not allowed. |
|||
|
|||
Preamble |
|||
|
|||
The GNU Affero General Public License is a free, copyleft license for |
|||
software and other kinds of works, specifically designed to ensure |
|||
cooperation with the community in the case of network server software. |
|||
|
|||
The licenses for most software and other practical works are designed |
|||
to take away your freedom to share and change the works. By contrast, |
|||
our General Public Licenses are intended to guarantee your freedom to |
|||
share and change all versions of a program--to make sure it remains free |
|||
software for all its users. |
|||
|
|||
When we speak of free software, we are referring to freedom, not |
|||
price. Our General Public Licenses are designed to make sure that you |
|||
have the freedom to distribute copies of free software (and charge for |
|||
them if you wish), that you receive source code or can get it if you |
|||
want it, that you can change the software or use pieces of it in new |
|||
free programs, and that you know you can do these things. |
|||
|
|||
Developers that use our General Public Licenses protect your rights |
|||
with two steps: (1) assert copyright on the software, and (2) offer |
|||
you this License which gives you legal permission to copy, distribute |
|||
and/or modify the software. |
|||
|
|||
A secondary benefit of defending all users' freedom is that |
|||
improvements made in alternate versions of the program, if they |
|||
receive widespread use, become available for other developers to |
|||
incorporate. Many developers of free software are heartened and |
|||
encouraged by the resulting cooperation. However, in the case of |
|||
software used on network servers, this result may fail to come about. |
|||
The GNU General Public License permits making a modified version and |
|||
letting the public access it on a server without ever releasing its |
|||
source code to the public. |
|||
|
|||
The GNU Affero General Public License is designed specifically to |
|||
ensure that, in such cases, the modified source code becomes available |
|||
to the community. It requires the operator of a network server to |
|||
provide the source code of the modified version running there to the |
|||
users of that server. Therefore, public use of a modified version, on |
|||
a publicly accessible server, gives the public access to the source |
|||
code of the modified version. |
|||
|
|||
An older license, called the Affero General Public License and |
|||
published by Affero, was designed to accomplish similar goals. This is |
|||
a different license, not a version of the Affero GPL, but Affero has |
|||
released a new version of the Affero GPL which permits relicensing under |
|||
this license. |
|||
|
|||
The precise terms and conditions for copying, distribution and |
|||
modification follow. |
|||
|
|||
TERMS AND CONDITIONS |
|||
|
|||
0. Definitions. |
|||
|
|||
"This License" refers to version 3 of the GNU Affero General Public License. |
|||
|
|||
"Copyright" also means copyright-like laws that apply to other kinds of |
|||
works, such as semiconductor masks. |
|||
|
|||
"The Program" refers to any copyrightable work licensed under this |
|||
License. Each licensee is addressed as "you". "Licensees" and |
|||
"recipients" may be individuals or organizations. |
|||
|
|||
To "modify" a work means to copy from or adapt all or part of the work |
|||
in a fashion requiring copyright permission, other than the making of an |
|||
exact copy. The resulting work is called a "modified version" of the |
|||
earlier work or a work "based on" the earlier work. |
|||
|
|||
A "covered work" means either the unmodified Program or a work based |
|||
on the Program. |
|||
|
|||
To "propagate" a work means to do anything with it that, without |
|||
permission, would make you directly or secondarily liable for |
|||
infringement under applicable copyright law, except executing it on a |
|||
computer or modifying a private copy. Propagation includes copying, |
|||
distribution (with or without modification), making available to the |
|||
public, and in some countries other activities as well. |
|||
|
|||
To "convey" a work means any kind of propagation that enables other |
|||
parties to make or receive copies. Mere interaction with a user through |
|||
a computer network, with no transfer of a copy, is not conveying. |
|||
|
|||
An interactive user interface displays "Appropriate Legal Notices" |
|||
to the extent that it includes a convenient and prominently visible |
|||
feature that (1) displays an appropriate copyright notice, and (2) |
|||
tells the user that there is no warranty for the work (except to the |
|||
extent that warranties are provided), that licensees may convey the |
|||
work under this License, and how to view a copy of this License. If |
|||
the interface presents a list of user commands or options, such as a |
|||
menu, a prominent item in the list meets this criterion. |
|||
|
|||
1. Source Code. |
|||
|
|||
The "source code" for a work means the preferred form of the work |
|||
for making modifications to it. "Object code" means any non-source |
|||
form of a work. |
|||
|
|||
A "Standard Interface" means an interface that either is an official |
|||
standard defined by a recognized standards body, or, in the case of |
|||
interfaces specified for a particular programming language, one that |
|||
is widely used among developers working in that language. |
|||
|
|||
The "System Libraries" of an executable work include anything, other |
|||
than the work as a whole, that (a) is included in the normal form of |
|||
packaging a Major Component, but which is not part of that Major |
|||
Component, and (b) serves only to enable use of the work with that |
|||
Major Component, or to implement a Standard Interface for which an |
|||
implementation is available to the public in source code form. A |
|||
"Major Component", in this context, means a major essential component |
|||
(kernel, window system, and so on) of the specific operating system |
|||
(if any) on which the executable work runs, or a compiler used to |
|||
produce the work, or an object code interpreter used to run it. |
|||
|
|||
The "Corresponding Source" for a work in object code form means all |
|||
the source code needed to generate, install, and (for an executable |
|||
work) run the object code and to modify the work, including scripts to |
|||
control those activities. However, it does not include the work's |
|||
System Libraries, or general-purpose tools or generally available free |
|||
programs which are used unmodified in performing those activities but |
|||
which are not part of the work. For example, Corresponding Source |
|||
includes interface definition files associated with source files for |
|||
the work, and the source code for shared libraries and dynamically |
|||
linked subprograms that the work is specifically designed to require, |
|||
such as by intimate data communication or control flow between those |
|||
subprograms and other parts of the work. |
|||
|
|||
The Corresponding Source need not include anything that users |
|||
can regenerate automatically from other parts of the Corresponding |
|||
Source. |
|||
|
|||
The Corresponding Source for a work in source code form is that |
|||
same work. |
|||
|
|||
2. Basic Permissions. |
|||
|
|||
All rights granted under this License are granted for the term of |
|||
copyright on the Program, and are irrevocable provided the stated |
|||
conditions are met. This License explicitly affirms your unlimited |
|||
permission to run the unmodified Program. The output from running a |
|||
covered work is covered by this License only if the output, given its |
|||
content, constitutes a covered work. This License acknowledges your |
|||
rights of fair use or other equivalent, as provided by copyright law. |
|||
|
|||
You may make, run and propagate covered works that you do not |
|||
convey, without conditions so long as your license otherwise remains |
|||
in force. You may convey covered works to others for the sole purpose |
|||
of having them make modifications exclusively for you, or provide you |
|||
with facilities for running those works, provided that you comply with |
|||
the terms of this License in conveying all material for which you do |
|||
not control copyright. Those thus making or running the covered works |
|||
for you must do so exclusively on your behalf, under your direction |
|||
and control, on terms that prohibit them from making any copies of |
|||
your copyrighted material outside their relationship with you. |
|||
|
|||
Conveying under any other circumstances is permitted solely under |
|||
the conditions stated below. Sublicensing is not allowed; section 10 |
|||
makes it unnecessary. |
|||
|
|||
3. Protecting Users' Legal Rights From Anti-Circumvention Law. |
|||
|
|||
No covered work shall be deemed part of an effective technological |
|||
measure under any applicable law fulfilling obligations under article |
|||
11 of the WIPO copyright treaty adopted on 20 December 1996, or |
|||
similar laws prohibiting or restricting circumvention of such |
|||
measures. |
|||
|
|||
When you convey a covered work, you waive any legal power to forbid |
|||
circumvention of technological measures to the extent such circumvention |
|||
is effected by exercising rights under this License with respect to |
|||
the covered work, and you disclaim any intention to limit operation or |
|||
modification of the work as a means of enforcing, against the work's |
|||
users, your or third parties' legal rights to forbid circumvention of |
|||
technological measures. |
|||
|
|||
4. Conveying Verbatim Copies. |
|||
|
|||
You may convey verbatim copies of the Program's source code as you |
|||
receive it, in any medium, provided that you conspicuously and |
|||
appropriately publish on each copy an appropriate copyright notice; |
|||
keep intact all notices stating that this License and any |
|||
non-permissive terms added in accord with section 7 apply to the code; |
|||
keep intact all notices of the absence of any warranty; and give all |
|||
recipients a copy of this License along with the Program. |
|||
|
|||
You may charge any price or no price for each copy that you convey, |
|||
and you may offer support or warranty protection for a fee. |
|||
|
|||
5. Conveying Modified Source Versions. |
|||
|
|||
You may convey a work based on the Program, or the modifications to |
|||
produce it from the Program, in the form of source code under the |
|||
terms of section 4, provided that you also meet all of these conditions: |
|||
|
|||
a) The work must carry prominent notices stating that you modified |
|||
it, and giving a relevant date. |
|||
|
|||
b) The work must carry prominent notices stating that it is |
|||
released under this License and any conditions added under section |
|||
7. This requirement modifies the requirement in section 4 to |
|||
"keep intact all notices". |
|||
|
|||
c) You must license the entire work, as a whole, under this |
|||
License to anyone who comes into possession of a copy. This |
|||
License will therefore apply, along with any applicable section 7 |
|||
additional terms, to the whole of the work, and all its parts, |
|||
regardless of how they are packaged. This License gives no |
|||
permission to license the work in any other way, but it does not |
|||
invalidate such permission if you have separately received it. |
|||
|
|||
d) If the work has interactive user interfaces, each must display |
|||
Appropriate Legal Notices; however, if the Program has interactive |
|||
interfaces that do not display Appropriate Legal Notices, your |
|||
work need not make them do so. |
|||
|
|||
A compilation of a covered work with other separate and independent |
|||
works, which are not by their nature extensions of the covered work, |
|||
and which are not combined with it such as to form a larger program, |
|||
in or on a volume of a storage or distribution medium, is called an |
|||
"aggregate" if the compilation and its resulting copyright are not |
|||
used to limit the access or legal rights of the compilation's users |
|||
beyond what the individual works permit. Inclusion of a covered work |
|||
in an aggregate does not cause this License to apply to the other |
|||
parts of the aggregate. |
|||
|
|||
6. Conveying Non-Source Forms. |
|||
|
|||
You may convey a covered work in object code form under the terms |
|||
of sections 4 and 5, provided that you also convey the |
|||
machine-readable Corresponding Source under the terms of this License, |
|||
in one of these ways: |
|||
|
|||
a) Convey the object code in, or embodied in, a physical product |
|||
(including a physical distribution medium), accompanied by the |
|||
Corresponding Source fixed on a durable physical medium |
|||
customarily used for software interchange. |
|||
|
|||
b) Convey the object code in, or embodied in, a physical product |
|||
(including a physical distribution medium), accompanied by a |
|||
written offer, valid for at least three years and valid for as |
|||
long as you offer spare parts or customer support for that product |
|||
model, to give anyone who possesses the object code either (1) a |
|||
copy of the Corresponding Source for all the software in the |
|||
product that is covered by this License, on a durable physical |
|||
medium customarily used for software interchange, for a price no |
|||
more than your reasonable cost of physically performing this |
|||
conveying of source, or (2) access to copy the |
|||
Corresponding Source from a network server at no charge. |
|||
|
|||
c) Convey individual copies of the object code with a copy of the |
|||
written offer to provide the Corresponding Source. This |
|||
alternative is allowed only occasionally and noncommercially, and |
|||
only if you received the object code with such an offer, in accord |
|||
with subsection 6b. |
|||
|
|||
d) Convey the object code by offering access from a designated |
|||
place (gratis or for a charge), and offer equivalent access to the |
|||
Corresponding Source in the same way through the same place at no |
|||
further charge. You need not require recipients to copy the |
|||
Corresponding Source along with the object code. If the place to |
|||
copy the object code is a network server, the Corresponding Source |
|||
may be on a different server (operated by you or a third party) |
|||
that supports equivalent copying facilities, provided you maintain |
|||
clear directions next to the object code saying where to find the |
|||
Corresponding Source. Regardless of what server hosts the |
|||
Corresponding Source, you remain obligated to ensure that it is |
|||
available for as long as needed to satisfy these requirements. |
|||
|
|||
e) Convey the object code using peer-to-peer transmission, provided |
|||
you inform other peers where the object code and Corresponding |
|||
Source of the work are being offered to the general public at no |
|||
charge under subsection 6d. |
|||
|
|||
A separable portion of the object code, whose source code is excluded |
|||
from the Corresponding Source as a System Library, need not be |
|||
included in conveying the object code work. |
|||
|
|||
A "User Product" is either (1) a "consumer product", which means any |
|||
tangible personal property which is normally used for personal, family, |
|||
or household purposes, or (2) anything designed or sold for incorporation |
|||
into a dwelling. In determining whether a product is a consumer product, |
|||
doubtful cases shall be resolved in favor of coverage. For a particular |
|||
product received by a particular user, "normally used" refers to a |
|||
typical or common use of that class of product, regardless of the status |
|||
of the particular user or of the way in which the particular user |
|||
actually uses, or expects or is expected to use, the product. A product |
|||
is a consumer product regardless of whether the product has substantial |
|||
commercial, industrial or non-consumer uses, unless such uses represent |
|||
the only significant mode of use of the product. |
|||
|
|||
"Installation Information" for a User Product means any methods, |
|||
procedures, authorization keys, or other information required to install |
|||
and execute modified versions of a covered work in that User Product from |
|||
a modified version of its Corresponding Source. The information must |
|||
suffice to ensure that the continued functioning of the modified object |
|||
code is in no case prevented or interfered with solely because |
|||
modification has been made. |
|||
|
|||
If you convey an object code work under this section in, or with, or |
|||
specifically for use in, a User Product, and the conveying occurs as |
|||
part of a transaction in which the right of possession and use of the |
|||
User Product is transferred to the recipient in perpetuity or for a |
|||
fixed term (regardless of how the transaction is characterized), the |
|||
Corresponding Source conveyed under this section must be accompanied |
|||
by the Installation Information. But this requirement does not apply |
|||
if neither you nor any third party retains the ability to install |
|||
modified object code on the User Product (for example, the work has |
|||
been installed in ROM). |
|||
|
|||
The requirement to provide Installation Information does not include a |
|||
requirement to continue to provide support service, warranty, or updates |
|||
for a work that has been modified or installed by the recipient, or for |
|||
the User Product in which it has been modified or installed. Access to a |
|||
network may be denied when the modification itself materially and |
|||
adversely affects the operation of the network or violates the rules and |
|||
protocols for communication across the network. |
|||
|
|||
Corresponding Source conveyed, and Installation Information provided, |
|||
in accord with this section must be in a format that is publicly |
|||
documented (and with an implementation available to the public in |
|||
source code form), and must require no special password or key for |
|||
unpacking, reading or copying. |
|||
|
|||
7. Additional Terms. |
|||
|
|||
"Additional permissions" are terms that supplement the terms of this |
|||
License by making exceptions from one or more of its conditions. |
|||
Additional permissions that are applicable to the entire Program shall |
|||
be treated as though they were included in this License, to the extent |
|||
that they are valid under applicable law. If additional permissions |
|||
apply only to part of the Program, that part may be used separately |
|||
under those permissions, but the entire Program remains governed by |
|||
this License without regard to the additional permissions. |
|||
|
|||
When you convey a copy of a covered work, you may at your option |
|||
remove any additional permissions from that copy, or from any part of |
|||
it. (Additional permissions may be written to require their own |
|||
removal in certain cases when you modify the work.) You may place |
|||
additional permissions on material, added by you to a covered work, |
|||
for which you have or can give appropriate copyright permission. |
|||
|
|||
Notwithstanding any other provision of this License, for material you |
|||
add to a covered work, you may (if authorized by the copyright holders of |
|||
that material) supplement the terms of this License with terms: |
|||
|
|||
a) Disclaiming warranty or limiting liability differently from the |
|||
terms of sections 15 and 16 of this License; or |
|||
|
|||
b) Requiring preservation of specified reasonable legal notices or |
|||
author attributions in that material or in the Appropriate Legal |
|||
Notices displayed by works containing it; or |
|||
|
|||
c) Prohibiting misrepresentation of the origin of that material, or |
|||
requiring that modified versions of such material be marked in |
|||
reasonable ways as different from the original version; or |
|||
|
|||
d) Limiting the use for publicity purposes of names of licensors or |
|||
authors of the material; or |
|||
|
|||
e) Declining to grant rights under trademark law for use of some |
|||
trade names, trademarks, or service marks; or |
|||
|
|||
f) Requiring indemnification of licensors and authors of that |
|||
material by anyone who conveys the material (or modified versions of |
|||
it) with contractual assumptions of liability to the recipient, for |
|||
any liability that these contractual assumptions directly impose on |
|||
those licensors and authors. |
|||
|
|||
All other non-permissive additional terms are considered "further |
|||
restrictions" within the meaning of section 10. If the Program as you |
|||
received it, or any part of it, contains a notice stating that it is |
|||
governed by this License along with a term that is a further |
|||
restriction, you may remove that term. If a license document contains |
|||
a further restriction but permits relicensing or conveying under this |
|||
License, you may add to a covered work material governed by the terms |
|||
of that license document, provided that the further restriction does |
|||
not survive such relicensing or conveying. |
|||
|
|||
If you add terms to a covered work in accord with this section, you |
|||
must place, in the relevant source files, a statement of the |
|||
additional terms that apply to those files, or a notice indicating |
|||
where to find the applicable terms. |
|||
|
|||
Additional terms, permissive or non-permissive, may be stated in the |
|||
form of a separately written license, or stated as exceptions; |
|||
the above requirements apply either way. |
|||
|
|||
8. Termination. |
|||
|
|||
You may not propagate or modify a covered work except as expressly |
|||
provided under this License. Any attempt otherwise to propagate or |
|||
modify it is void, and will automatically terminate your rights under |
|||
this License (including any patent licenses granted under the third |
|||
paragraph of section 11). |
|||
|
|||
However, if you cease all violation of this License, then your |
|||
license from a particular copyright holder is reinstated (a) |
|||
provisionally, unless and until the copyright holder explicitly and |
|||
finally terminates your license, and (b) permanently, if the copyright |
|||
holder fails to notify you of the violation by some reasonable means |
|||
prior to 60 days after the cessation. |
|||
|
|||
Moreover, your license from a particular copyright holder is |
|||
reinstated permanently if the copyright holder notifies you of the |
|||
violation by some reasonable means, this is the first time you have |
|||
received notice of violation of this License (for any work) from that |
|||
copyright holder, and you cure the violation prior to 30 days after |
|||
your receipt of the notice. |
|||
|
|||
Termination of your rights under this section does not terminate the |
|||
licenses of parties who have received copies or rights from you under |
|||
this License. If your rights have been terminated and not permanently |
|||
reinstated, you do not qualify to receive new licenses for the same |
|||
material under section 10. |
|||
|
|||
9. Acceptance Not Required for Having Copies. |
|||
|
|||
You are not required to accept this License in order to receive or |
|||
run a copy of the Program. Ancillary propagation of a covered work |
|||
occurring solely as a consequence of using peer-to-peer transmission |
|||
to receive a copy likewise does not require acceptance. However, |
|||
nothing other than this License grants you permission to propagate or |
|||
modify any covered work. These actions infringe copyright if you do |
|||
not accept this License. Therefore, by modifying or propagating a |
|||
covered work, you indicate your acceptance of this License to do so. |
|||
|
|||
10. Automatic Licensing of Downstream Recipients. |
|||
|
|||
Each time you convey a covered work, the recipient automatically |
|||
receives a license from the original licensors, to run, modify and |
|||
propagate that work, subject to this License. You are not responsible |
|||
for enforcing compliance by third parties with this License. |
|||
|
|||
An "entity transaction" is a transaction transferring control of an |
|||
organization, or substantially all assets of one, or subdividing an |
|||
organization, or merging organizations. If propagation of a covered |
|||
work results from an entity transaction, each party to that |
|||
transaction who receives a copy of the work also receives whatever |
|||
licenses to the work the party's predecessor in interest had or could |
|||
give under the previous paragraph, plus a right to possession of the |
|||
Corresponding Source of the work from the predecessor in interest, if |
|||
the predecessor has it or can get it with reasonable efforts. |
|||
|
|||
You may not impose any further restrictions on the exercise of the |
|||
rights granted or affirmed under this License. For example, you may |
|||
not impose a license fee, royalty, or other charge for exercise of |
|||
rights granted under this License, and you may not initiate litigation |
|||
(including a cross-claim or counterclaim in a lawsuit) alleging that |
|||
any patent claim is infringed by making, using, selling, offering for |
|||
sale, or importing the Program or any portion of it. |
|||
|
|||
11. Patents. |
|||
|
|||
A "contributor" is a copyright holder who authorizes use under this |
|||
License of the Program or a work on which the Program is based. The |
|||
work thus licensed is called the contributor's "contributor version". |
|||
|
|||
A contributor's "essential patent claims" are all patent claims |
|||
owned or controlled by the contributor, whether already acquired or |
|||
hereafter acquired, that would be infringed by some manner, permitted |
|||
by this License, of making, using, or selling its contributor version, |
|||
but do not include claims that would be infringed only as a |
|||
consequence of further modification of the contributor version. For |
|||
purposes of this definition, "control" includes the right to grant |
|||
patent sublicenses in a manner consistent with the requirements of |
|||
this License. |
|||
|
|||
Each contributor grants you a non-exclusive, worldwide, royalty-free |
|||
patent license under the contributor's essential patent claims, to |
|||
make, use, sell, offer for sale, import and otherwise run, modify and |
|||
propagate the contents of its contributor version. |
|||
|
|||
In the following three paragraphs, a "patent license" is any express |
|||
agreement or commitment, however denominated, not to enforce a patent |
|||
(such as an express permission to practice a patent or covenant not to |
|||
sue for patent infringement). To "grant" such a patent license to a |
|||
party means to make such an agreement or commitment not to enforce a |
|||
patent against the party. |
|||
|
|||
If you convey a covered work, knowingly relying on a patent license, |
|||
and the Corresponding Source of the work is not available for anyone |
|||
to copy, free of charge and under the terms of this License, through a |
|||
publicly available network server or other readily accessible means, |
|||
then you must either (1) cause the Corresponding Source to be so |
|||
available, or (2) arrange to deprive yourself of the benefit of the |
|||
patent license for this particular work, or (3) arrange, in a manner |
|||
consistent with the requirements of this License, to extend the patent |
|||
license to downstream recipients. "Knowingly relying" means you have |
|||
actual knowledge that, but for the patent license, your conveying the |
|||
covered work in a country, or your recipient's use of the covered work |
|||
in a country, would infringe one or more identifiable patents in that |
|||
country that you have reason to believe are valid. |
|||
|
|||
If, pursuant to or in connection with a single transaction or |
|||
arrangement, you convey, or propagate by procuring conveyance of, a |
|||
covered work, and grant a patent license to some of the parties |
|||
receiving the covered work authorizing them to use, propagate, modify |
|||
or convey a specific copy of the covered work, then the patent license |
|||
you grant is automatically extended to all recipients of the covered |
|||
work and works based on it. |
|||
|
|||
A patent license is "discriminatory" if it does not include within |
|||
the scope of its coverage, prohibits the exercise of, or is |
|||
conditioned on the non-exercise of one or more of the rights that are |
|||
specifically granted under this License. You may not convey a covered |
|||
work if you are a party to an arrangement with a third party that is |
|||
in the business of distributing software, under which you make payment |
|||
to the third party based on the extent of your activity of conveying |
|||
the work, and under which the third party grants, to any of the |
|||
parties who would receive the covered work from you, a discriminatory |
|||
patent license (a) in connection with copies of the covered work |
|||
conveyed by you (or copies made from those copies), or (b) primarily |
|||
for and in connection with specific products or compilations that |
|||
contain the covered work, unless you entered into that arrangement, |
|||
or that patent license was granted, prior to 28 March 2007. |
|||
|
|||
Nothing in this License shall be construed as excluding or limiting |
|||
any implied license or other defenses to infringement that may |
|||
otherwise be available to you under applicable patent law. |
|||
|
|||
12. No Surrender of Others' Freedom. |
|||
|
|||
If conditions are imposed on you (whether by court order, agreement or |
|||
otherwise) that contradict the conditions of this License, they do not |
|||
excuse you from the conditions of this License. If you cannot convey a |
|||
covered work so as to satisfy simultaneously your obligations under this |
|||
License and any other pertinent obligations, then as a consequence you may |
|||
not convey it at all. For example, if you agree to terms that obligate you |
|||
to collect a royalty for further conveying from those to whom you convey |
|||
the Program, the only way you could satisfy both those terms and this |
|||
License would be to refrain entirely from conveying the Program. |
|||
|
|||
13. Remote Network Interaction; Use with the GNU General Public License. |
|||
|
|||
Notwithstanding any other provision of this License, if you modify the |
|||
Program, your modified version must prominently offer all users |
|||
interacting with it remotely through a computer network (if your version |
|||
supports such interaction) an opportunity to receive the Corresponding |
|||
Source of your version by providing access to the Corresponding Source |
|||
from a network server at no charge, through some standard or customary |
|||
means of facilitating copying of software. This Corresponding Source |
|||
shall include the Corresponding Source for any work covered by version 3 |
|||
of the GNU General Public License that is incorporated pursuant to the |
|||
following paragraph. |
|||
|
|||
Notwithstanding any other provision of this License, you have |
|||
permission to link or combine any covered work with a work licensed |
|||
under version 3 of the GNU General Public License into a single |
|||
combined work, and to convey the resulting work. The terms of this |
|||
License will continue to apply to the part which is the covered work, |
|||
but the work with which it is combined will remain governed by version |
|||
3 of the GNU General Public License. |
|||
|
|||
14. Revised Versions of this License. |
|||
|
|||
The Free Software Foundation may publish revised and/or new versions of |
|||
the GNU Affero General Public License from time to time. Such new versions |
|||
will be similar in spirit to the present version, but may differ in detail to |
|||
address new problems or concerns. |
|||
|
|||
Each version is given a distinguishing version number. If the |
|||
Program specifies that a certain numbered version of the GNU Affero General |
|||
Public License "or any later version" applies to it, you have the |
|||
option of following the terms and conditions either of that numbered |
|||
version or of any later version published by the Free Software |
|||
Foundation. If the Program does not specify a version number of the |
|||
GNU Affero General Public License, you may choose any version ever published |
|||
by the Free Software Foundation. |
|||
|
|||
If the Program specifies that a proxy can decide which future |
|||
versions of the GNU Affero General Public License can be used, that proxy's |
|||
public statement of acceptance of a version permanently authorizes you |
|||
to choose that version for the Program. |
|||
|
|||
Later license versions may give you additional or different |
|||
permissions. However, no additional obligations are imposed on any |
|||
author or copyright holder as a result of your choosing to follow a |
|||
later version. |
|||
|
|||
15. Disclaimer of Warranty. |
|||
|
|||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY |
|||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT |
|||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY |
|||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, |
|||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM |
|||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF |
|||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
|||
|
|||
16. Limitation of Liability. |
|||
|
|||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
|||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS |
|||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY |
|||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE |
|||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF |
|||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD |
|||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), |
|||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF |
|||
SUCH DAMAGES. |
|||
|
|||
17. Interpretation of Sections 15 and 16. |
|||
|
|||
If the disclaimer of warranty and limitation of liability provided |
|||
above cannot be given local legal effect according to their terms, |
|||
reviewing courts shall apply local law that most closely approximates |
|||
an absolute waiver of all civil liability in connection with the |
|||
Program, unless a warranty or assumption of liability accompanies a |
|||
copy of the Program in return for a fee. |
|||
|
|||
END OF TERMS AND CONDITIONS |
|||
|
|||
How to Apply These Terms to Your New Programs |
|||
|
|||
If you develop a new program, and you want it to be of the greatest |
|||
possible use to the public, the best way to achieve this is to make it |
|||
free software which everyone can redistribute and change under these terms. |
|||
|
|||
To do so, attach the following notices to the program. It is safest |
|||
to attach them to the start of each source file to most effectively |
|||
state the exclusion of warranty; and each file should have at least |
|||
the "copyright" line and a pointer to where the full notice is found. |
|||
|
|||
<one line to give the program's name and a brief idea of what it does.> |
|||
Copyright (C) <year> <name of author> |
|||
|
|||
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/>. |
|||
|
|||
Also add information on how to contact you by electronic and paper mail. |
|||
|
|||
If your software can interact with users remotely through a computer |
|||
network, you should also make sure that it provides a way for users to |
|||
get its source. For example, if your program is a web application, its |
|||
interface could display a "Source" link that leads users to an archive |
|||
of the code. There are many ways you could offer source, and different |
|||
solutions will be better for different programs; see section 13 for the |
|||
specific requirements. |
|||
|
|||
You should also get your employer (if you work as a programmer) or school, |
|||
if any, to sign a "copyright disclaimer" for the program, if necessary. |
|||
For more information on this, and how to apply and follow the GNU AGPL, see |
|||
<https://www.gnu.org/licenses/>. |
@ -0,0 +1 @@ |
|||
# Universal importer |
@ -0,0 +1,218 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/* |
|||
* AutoImports.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Console; |
|||
|
|||
use App\Exceptions\ImportException; |
|||
use App\Mail\ImportFinished; |
|||
use Illuminate\Support\Facades\Mail; |
|||
use JsonException; |
|||
use Log; |
|||
|
|||
/** |
|||
* Trait AutoImports |
|||
*/ |
|||
trait AutoImports |
|||
{ |
|||
/** |
|||
* @return array |
|||
*/ |
|||
protected function getFiles(): array |
|||
{ |
|||
$ignore = ['.', '..']; |
|||
|
|||
if (null === $this->directory || '' === $this->directory) { |
|||
$this->error(sprintf('Directory "%s" is empty or invalid.', $this->directory)); |
|||
|
|||
return []; |
|||
} |
|||
$array = scandir($this->directory); |
|||
if (!is_array($array)) { |
|||
$this->error(sprintf('Directory "%s" is empty or invalid.', $this->directory)); |
|||
|
|||
return []; |
|||
} |
|||
$files = array_diff($array, $ignore); |
|||
$return = []; |
|||
foreach ($files as $file) { |
|||
if ('csv' === $this->getExtension($file) && $this->hasJsonConfiguration($file)) { |
|||
$return[] = $file; |
|||
} |
|||
} |
|||
|
|||
return $return; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* @param string $file |
|||
* |
|||
* @return string |
|||
*/ |
|||
private function getExtension(string $file): string |
|||
{ |
|||
$parts = explode('.', $file); |
|||
if (1 === count($parts)) { |
|||
return ''; |
|||
} |
|||
|
|||
return strtolower($parts[count($parts) - 1]); |
|||
} |
|||
|
|||
/** |
|||
* @param string $file |
|||
* |
|||
* @return bool |
|||
*/ |
|||
private function hasJsonConfiguration(string $file): bool |
|||
{ |
|||
$short = substr($file, 0, -4); |
|||
$jsonFile = sprintf('%s.json', $short); |
|||
$fullJson = sprintf('%s/%s', $this->directory, $jsonFile); |
|||
if (!file_exists($fullJson)) { |
|||
$this->warn(sprintf('Can\'t find JSON file "%s" expected to go with CSV file "%s". CSV file will be ignored.', $fullJson, $file)); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* @param array $files |
|||
* |
|||
* @throws ImportException |
|||
*/ |
|||
protected function importFiles(array $files): void |
|||
{ |
|||
/** @var string $file */ |
|||
foreach ($files as $file) { |
|||
$this->importFile($file); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @param string $file |
|||
* |
|||
* @throws ImportException |
|||
*/ |
|||
private function importFile(string $file): void |
|||
{ |
|||
$csvFile = sprintf('%s/%s', $this->directory, $file); |
|||
$jsonFile = sprintf('%s/%s.json', $this->directory, substr($file, 0, -4)); |
|||
|
|||
// do JSON check
|
|||
$jsonResult = $this->verifyJSON($jsonFile); |
|||
if (false === $jsonResult) { |
|||
$message = sprintf('The importer can\'t import %s: could not decode the JSON in config file %s.', $csvFile, $jsonFile); |
|||
$this->error($message); |
|||
|
|||
return; |
|||
} |
|||
try { |
|||
$configuration = json_decode(file_get_contents($jsonFile), true, 512, JSON_THROW_ON_ERROR); |
|||
} catch (JsonException $e) { |
|||
Log::error($e->getMessage()); |
|||
throw new ImportException(sprintf('Bad JSON in configuration file: %s', $e->getMessage())); |
|||
} |
|||
$this->line(sprintf('Going to import from file %s using configuration %s.', $csvFile, $jsonFile)); |
|||
// create importer
|
|||
$csv = file_get_contents($csvFile); |
|||
$result = $this->startImport($csv, $configuration); |
|||
|
|||
if (0 === $result) { |
|||
$this->line('Import complete.'); |
|||
} |
|||
if (0 !== $result) { |
|||
$this->warn('The import finished with errors.'); |
|||
} |
|||
|
|||
$this->line(sprintf('Done importing from file %s using configuration %s.', $csvFile, $jsonFile)); |
|||
|
|||
// send mail:
|
|||
$log |
|||
= [ |
|||
'messages' => $this->messages, |
|||
'warnings' => $this->warnings, |
|||
'errors' => $this->errors, |
|||
]; |
|||
|
|||
$send = config('mail.enable_mail_report'); |
|||
Log::debug('Log log', $log); |
|||
if (true === $send) { |
|||
Log::debug('SEND MAIL'); |
|||
Mail::to(config('mail.destination'))->send(new ImportFinished($log)); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @param string $file |
|||
* |
|||
* @throws ImportException |
|||
*/ |
|||
private function importUpload(string $csvFile, string $jsonFile): void |
|||
{ |
|||
// do JSON check
|
|||
$jsonResult = $this->verifyJSON($jsonFile); |
|||
if (false === $jsonResult) { |
|||
$message = sprintf('The importer can\'t import %s: could not decode the JSON in config file %s.', $csvFile, $jsonFile); |
|||
$this->error($message); |
|||
|
|||
return; |
|||
} |
|||
try { |
|||
$configuration = json_decode(file_get_contents($jsonFile), true, 512, JSON_THROW_ON_ERROR); |
|||
} catch (JsonException $e) { |
|||
Log::error($e->getMessage()); |
|||
throw new ImportException(sprintf('Bad JSON in configuration file: %s', $e->getMessage())); |
|||
} |
|||
$this->line(sprintf('Going to import from file %s using configuration %s.', $csvFile, $jsonFile)); |
|||
// create importer
|
|||
$csv = file_get_contents($csvFile); |
|||
$result = $this->startImport($csv, $configuration); |
|||
|
|||
if (0 === $result) { |
|||
$this->line('Import complete.'); |
|||
} |
|||
if (0 !== $result) { |
|||
$this->warn('The import finished with errors.'); |
|||
} |
|||
|
|||
$this->line(sprintf('Done importing from file %s using configuration %s.', $csvFile, $jsonFile)); |
|||
|
|||
// send mail:
|
|||
$log |
|||
= [ |
|||
'messages' => $this->messages, |
|||
'warnings' => $this->warnings, |
|||
'errors' => $this->errors, |
|||
]; |
|||
|
|||
$send = config('mail.enable_mail_report'); |
|||
Log::debug('Log log', $log); |
|||
if (true === $send) { |
|||
Log::debug('SEND MAIL'); |
|||
Mail::to(config('mail.destination'))->send(new ImportFinished($log)); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,93 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* AutoImport.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Console\Commands; |
|||
|
|||
use App\Console\AutoImports; |
|||
use App\Console\HaveAccess; |
|||
use App\Console\StartImport; |
|||
use App\Console\VerifyJSON; |
|||
use App\Exceptions\ImportException; |
|||
use Illuminate\Console\Command; |
|||
use Log; |
|||
|
|||
/** |
|||
* Class AutoImport |
|||
*/ |
|||
class AutoImport extends Command |
|||
{ |
|||
use HaveAccess, VerifyJSON, StartImport, AutoImports; |
|||
|
|||
/** |
|||
* The console command description. |
|||
* |
|||
* @var string |
|||
*/ |
|||
protected $description = 'Will automatically import from the given directory and use the JSON and CSV files found.'; |
|||
/** |
|||
* The name and signature of the console command. |
|||
* |
|||
* @var string |
|||
*/ |
|||
protected $signature = 'importer:auto-import {directory : The directory from which to import automatically.}'; |
|||
/** @var string */ |
|||
private $directory = './'; |
|||
|
|||
/** |
|||
* Execute the console command. |
|||
* |
|||
* @return int |
|||
*/ |
|||
public function handle(): int |
|||
{ |
|||
$access = $this->haveAccess(); |
|||
if (false === $access) { |
|||
$this->error('Could not connect to your local Firefly III instance.'); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
$argument = (string) ($this->argument('directory') ?? './'); |
|||
$this->directory = realpath($argument); |
|||
$this->line(sprintf('Going to automatically import everything found in %s (%s)', $this->directory, $argument)); |
|||
|
|||
$files = $this->getFiles(); |
|||
if (0 === count($files)) { |
|||
$this->info(sprintf('There are no files in directory %s', $this->directory)); |
|||
$this->info('To learn more about this process, read the docs:'); |
|||
$this->info('https://docs.firefly-iii.org/csv/install/docker/'); |
|||
|
|||
return 1; |
|||
} |
|||
$this->line(sprintf('Found %d CSV + JSON file sets in %s', count($files), $this->directory)); |
|||
try { |
|||
$this->importFiles($files); |
|||
} catch (ImportException $e) { |
|||
Log::error($e->getMessage()); |
|||
$this->error(sprintf('Import exception (see the logs): %s', $e->getMessage())); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,139 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* Import.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Console\Commands; |
|||
|
|||
use App\Console\HaveAccess; |
|||
use App\Console\StartImport; |
|||
use App\Console\VerifyJSON; |
|||
use App\Mail\ImportFinished; |
|||
use Illuminate\Console\Command; |
|||
use Illuminate\Support\Facades\Mail; |
|||
use JsonException; |
|||
use Log; |
|||
|
|||
/** |
|||
* Class Import |
|||
*/ |
|||
class Import extends Command |
|||
{ |
|||
use HaveAccess, VerifyJSON, StartImport; |
|||
|
|||
/** |
|||
* The console command description. |
|||
* |
|||
* @var string |
|||
*/ |
|||
protected $description = 'Import a CSV file. Requires the CSV file and the associated configuration file.'; |
|||
/** |
|||
* The name and signature of the console command. |
|||
* |
|||
* @var string |
|||
*/ |
|||
protected $signature = 'importer:import |
|||
{file : The CSV file you want to import} |
|||
{config : The associated configuration file}'; |
|||
|
|||
/** |
|||
* Execute the console command. |
|||
* |
|||
* @return int |
|||
*/ |
|||
public function handle(): int |
|||
{ |
|||
|
|||
$access = $this->haveAccess(); |
|||
if (false === $access) { |
|||
$this->error('Could not connect to your local Firefly III instance.'); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
$this->info(sprintf('Welcome to the Firefly III data importer, v%s', config('importer.version'))); |
|||
Log::debug(sprintf('Now in %s', __METHOD__)); |
|||
$file = (string) $this->argument('file'); |
|||
$config = (string) $this->argument('config'); |
|||
if (!file_exists($file) || (file_exists($file) && !is_file($file))) { |
|||
$message = sprintf('The importer can\'t import: CSV file "%s" does not exist or could not be read.', $file); |
|||
$this->error($message); |
|||
Log::error($message); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
if (!file_exists($config) || (file_exists($config) && !is_file($config))) { |
|||
$message = sprintf('The importer can\'t import: configuration file "%s" does not exist or could not be read.', $config); |
|||
$this->error($message); |
|||
Log::error($message); |
|||
|
|||
return 1; |
|||
} |
|||
$jsonResult = $this->verifyJSON($config); |
|||
if (false === $jsonResult) { |
|||
$message = 'The importer can\'t import: could not decode the JSON in the config file.'; |
|||
$this->error($message); |
|||
|
|||
return 1; |
|||
} |
|||
try { |
|||
$configuration = json_decode(file_get_contents($config), true, 512, JSON_THROW_ON_ERROR); |
|||
} catch (JsonException $e) { |
|||
Log::error($e->getMessage()); |
|||
$this->error(sprintf('Invalid JSON in configuration file: %s', $e->getMessage())); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
$this->line('The import routine is about to start.'); |
|||
$this->line('This is invisible and may take quite some time.'); |
|||
$this->line('Once finished, you will see a list of errors, warnings and messages (if applicable).'); |
|||
$this->line('--------'); |
|||
$this->line('Running...'); |
|||
$csv = file_get_contents($file); |
|||
$result = $this->startImport($csv, $configuration); |
|||
if (0 === $result) { |
|||
$this->line('Import complete.'); |
|||
} |
|||
if (0 !== $result) { |
|||
$this->warn('The import finished with errors.'); |
|||
} |
|||
|
|||
// send mail:
|
|||
$log |
|||
= [ |
|||
'messages' => $this->messages, |
|||
'warnings' => $this->warnings, |
|||
'errors' => $this->errors, |
|||
]; |
|||
|
|||
$send = config('mail.enable_mail_report'); |
|||
Log::debug('Log log', $log); |
|||
if (true === $send) { |
|||
Log::debug('SEND MAIL'); |
|||
Mail::to(config('mail.destination'))->send(new ImportFinished($log)); |
|||
} |
|||
|
|||
|
|||
return $result; |
|||
} |
|||
} |
@ -0,0 +1,58 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* ShowVersion.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Console\Commands; |
|||
|
|||
use Illuminate\Console\Command; |
|||
|
|||
/** |
|||
* Class ShowVersion |
|||
*/ |
|||
class ShowVersion extends Command |
|||
{ |
|||
/** |
|||
* The console command description. |
|||
* |
|||
* @var string |
|||
*/ |
|||
protected $description = 'Echoes the current version and some debug info.'; |
|||
/** |
|||
* The name and signature of the console command. |
|||
* |
|||
* @var string |
|||
*/ |
|||
protected $signature = 'importer:version'; |
|||
|
|||
/** |
|||
* Execute the console command. |
|||
* |
|||
* @return int |
|||
*/ |
|||
public function handle(): int |
|||
{ |
|||
$this->line(sprintf('Firefly III data importer v%s', config('importer.version'))); |
|||
$this->line(sprintf('PHP: %s %s %s', PHP_SAPI, PHP_VERSION, PHP_OS)); |
|||
|
|||
return 0; |
|||
} |
|||
} |
@ -0,0 +1,64 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* HaveAccess.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Console; |
|||
|
|||
use GrumpyDictator\FFIIIApiSupport\Exceptions\ApiHttpException; |
|||
use GrumpyDictator\FFIIIApiSupport\Request\SystemInformationRequest; |
|||
|
|||
/** |
|||
* Trait HaveAccess |
|||
*/ |
|||
trait HaveAccess |
|||
{ |
|||
/** |
|||
* @return bool |
|||
*/ |
|||
private function haveAccess(): bool |
|||
{ |
|||
$url = (string) config('importer.url'); |
|||
$token = (string) config('importer.access_token'); |
|||
$request = new SystemInformationRequest($url, $token); |
|||
|
|||
$request->setVerify(config('importer.connection.verify')); |
|||
$request->setTimeOut(config('importer.connection.timeout')); |
|||
|
|||
try { |
|||
$request->get(); |
|||
} catch (ApiHttpException $e) { |
|||
$this->error(sprintf('Could not connect to Firefly III: %s', $e->getMessage())); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* @param $string |
|||
* @param null $verbosity |
|||
* |
|||
* @return void |
|||
*/ |
|||
abstract public function error($string, $verbosity = null); |
|||
} |
@ -0,0 +1,66 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* Kernel.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Console; |
|||
|
|||
use Illuminate\Console\Scheduling\Schedule; |
|||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel; |
|||
|
|||
/** |
|||
* Class Kernel |
|||
*/ |
|||
class Kernel extends ConsoleKernel |
|||
{ |
|||
/** |
|||
* The Artisan commands provided by your application. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $commands = [ |
|||
//
|
|||
]; |
|||
|
|||
/** |
|||
* Define the application's command schedule. |
|||
* |
|||
* @param Schedule $schedule |
|||
* @return void |
|||
*/ |
|||
protected function schedule(Schedule $schedule): void |
|||
{ |
|||
} |
|||
|
|||
/** |
|||
* Register the commands for the application. |
|||
* |
|||
* @return void |
|||
*/ |
|||
protected function commands(): void |
|||
{ |
|||
$this->load(__DIR__ . '/Commands'); |
|||
|
|||
require base_path('routes/console.php'); |
|||
} |
|||
} |
@ -0,0 +1,41 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
namespace App\Console; |
|||
|
|||
/** |
|||
* Trait ManageMessages |
|||
*/ |
|||
trait ManageMessages |
|||
{ |
|||
|
|||
/** |
|||
* @param string $key |
|||
* @param array $messages |
|||
*/ |
|||
protected function listMessages(string $key, array $messages): void |
|||
{ |
|||
$functions = [ |
|||
'ERROR' => 'error', |
|||
'Warning' => 'warn', |
|||
'Message' => 'info', |
|||
]; |
|||
|
|||
$func = $functions[$key] ?? 'line'; |
|||
|
|||
if (!empty($messages)) { |
|||
/** |
|||
* @var int $index |
|||
* @var array $error |
|||
*/ |
|||
foreach ($messages as $index => $list) { |
|||
/** @var string $line */ |
|||
foreach ($list as $line) { |
|||
|
|||
$this->$func(sprintf('%s in line #%d: %s', $key, $index + 1, $line)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,79 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* StartImport.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Console; |
|||
|
|||
use App\Exceptions\ImportException; |
|||
use App\Services\CSV\Configuration\Configuration; |
|||
use App\Services\CSV\File\FileReader; |
|||
use App\Services\Import\ImportRoutineManager; |
|||
use Log; |
|||
|
|||
/** |
|||
* Trait StartImport |
|||
*/ |
|||
trait StartImport |
|||
{ |
|||
use ManageMessages; |
|||
|
|||
protected array $messages; |
|||
protected array $warnings; |
|||
protected array $errors; |
|||
|
|||
/** |
|||
* @param string $csv |
|||
* @param array $configuration |
|||
* |
|||
* @return int |
|||
*/ |
|||
private function startImport(string $csv, array $configuration): int |
|||
{ |
|||
$this->messages = []; |
|||
$this->warnings = []; |
|||
$this->errors = []; |
|||
|
|||
Log::debug(sprintf('Now in %s', __METHOD__)); |
|||
$configObject = Configuration::fromFile($configuration); |
|||
$manager = new ImportRoutineManager; |
|||
|
|||
try { |
|||
$manager->setConfiguration($configObject); |
|||
} catch (ImportException $e) { |
|||
$this->error($e->getMessage()); |
|||
|
|||
return 1; |
|||
} |
|||
$manager->setReader(FileReader::getReaderFromContent($csv)); |
|||
$manager->start(); |
|||
|
|||
$this->messages = $manager->getAllMessages(); |
|||
$this->warnings = $manager->getAllWarnings(); |
|||
$this->errors = $manager->getAllErrors(); |
|||
|
|||
$this->listMessages('ERROR', $this->errors); |
|||
$this->listMessages('Warning', $this->warnings); |
|||
$this->listMessages('Message', $this->messages); |
|||
|
|||
return 0; |
|||
} |
|||
} |
@ -0,0 +1,57 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* VerifyJSON.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Console; |
|||
|
|||
use Exception; |
|||
use JsonException; |
|||
use Log; |
|||
|
|||
/** |
|||
* Trait VerifyJSON |
|||
*/ |
|||
trait VerifyJSON |
|||
{ |
|||
/** |
|||
* @param string $file |
|||
* |
|||
* @return bool |
|||
*/ |
|||
private function verifyJSON(string $file): bool |
|||
{ |
|||
// basic check on the JSON.
|
|||
$json = file_get_contents($file); |
|||
try { |
|||
json_decode($json, true, 512, JSON_THROW_ON_ERROR); |
|||
} catch (Exception | JsonException $e) { |
|||
$message = sprintf('The importer can\'t import: could not decode the JSON in the config file: %s', $e->getMessage()); |
|||
Log::error($message); |
|||
|
|||
return false; |
|||
|
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,36 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* ApiException.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Exceptions; |
|||
|
|||
|
|||
use Exception; |
|||
|
|||
/** |
|||
* Class ApiException |
|||
* @deprecated |
|||
*/ |
|||
class ApiException extends Exception |
|||
{ |
|||
|
|||
} |
@ -0,0 +1,36 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* ApiHttpException.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Exceptions; |
|||
|
|||
use Exception; |
|||
|
|||
|
|||
/** |
|||
* Class ApiHttpException |
|||
* @deprecated |
|||
*/ |
|||
class ApiHttpException extends Exception |
|||
{ |
|||
|
|||
} |
@ -0,0 +1,53 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* Handler.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Exceptions; |
|||
|
|||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; |
|||
|
|||
/** |
|||
* Class Handler |
|||
*/ |
|||
class Handler extends ExceptionHandler |
|||
{ |
|||
/** |
|||
* A list of the exception types that are not reported. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $dontReport = [ |
|||
//
|
|||
]; |
|||
|
|||
/** |
|||
* A list of the inputs that are never flashed for validation exceptions. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $dontFlash = [ |
|||
'password', |
|||
'password_confirmation', |
|||
]; |
|||
} |
@ -0,0 +1,35 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* ImportException.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Exceptions; |
|||
|
|||
use Exception; |
|||
|
|||
/** |
|||
* Class ImportException |
|||
* @deprecated |
|||
*/ |
|||
class ImportException extends Exception |
|||
{ |
|||
|
|||
} |
@ -0,0 +1,36 @@ |
|||
<?php |
|||
/* |
|||
* ImporterErrorException.php |
|||
* Copyright (c) 2021 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III Nordigen importer |
|||
* (https://github.com/firefly-iii/nordigen-importer). |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
*/ |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
|
|||
namespace App\Exceptions; |
|||
|
|||
use Exception; |
|||
|
|||
/** |
|||
* Class ImporterErrorException |
|||
*/ |
|||
class ImporterErrorException extends Exception |
|||
{ |
|||
public array $json; |
|||
} |
@ -0,0 +1,36 @@ |
|||
<?php |
|||
/* |
|||
* ImporterHttpException.php |
|||
* Copyright (c) 2021 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III Nordigen importer |
|||
* (https://github.com/firefly-iii/nordigen-importer). |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
*/ |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
|
|||
namespace App\Exceptions; |
|||
|
|||
use Exception; |
|||
|
|||
/** |
|||
* Class ImporterHttpException |
|||
*/ |
|||
class ImporterHttpException extends Exception |
|||
{ |
|||
|
|||
} |
@ -0,0 +1,38 @@ |
|||
<?php |
|||
/** |
|||
* SpectreErrorException.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III Spectre importer |
|||
* (https://github.com/firefly-iii/spectre-importer). |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
*/ |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
|
|||
namespace App\Exceptions; |
|||
|
|||
use Exception; |
|||
|
|||
/** |
|||
* Class SpectreErrorException |
|||
* @deprecated |
|||
*/ |
|||
class SpectreErrorException extends Exception |
|||
{ |
|||
/** @var array */ |
|||
public $json; |
|||
} |
@ -0,0 +1,37 @@ |
|||
<?php |
|||
/** |
|||
* SpectreHttpException.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III Spectre importer |
|||
* (https://github.com/firefly-iii/spectre-importer). |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
*/ |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
|
|||
namespace App\Exceptions; |
|||
|
|||
use Exception; |
|||
|
|||
/** |
|||
* Class SpectreHttpException |
|||
* @deprecated |
|||
*/ |
|||
class SpectreHttpException extends Exception |
|||
{ |
|||
|
|||
} |
@ -0,0 +1,90 @@ |
|||
<?php |
|||
|
|||
|
|||
namespace App\Http\Controllers; |
|||
|
|||
|
|||
use App\Console\AutoImports; |
|||
use App\Console\HaveAccess; |
|||
use App\Console\StartImport; |
|||
use App\Console\VerifyJSON; |
|||
use App\Exceptions\ImportException; |
|||
use Illuminate\Http\Request; |
|||
use Log; |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
class AutoImportController extends Controller |
|||
{ |
|||
use HaveAccess, AutoImports, VerifyJSON, StartImport; |
|||
|
|||
private string $directory; |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function index(Request $request) |
|||
{ |
|||
$access = $this->haveAccess(); |
|||
if (false === $access) { |
|||
throw new ImportException('Could not connect to your local Firefly III instance.'); |
|||
} |
|||
|
|||
$argument = (string) ($request->get('directory') ?? './'); |
|||
$this->directory = realpath($argument); |
|||
$this->line(sprintf('Going to automatically import everything found in %s (%s)', $this->directory, $argument)); |
|||
|
|||
$files = $this->getFiles(); |
|||
if (0 === count($files)) { |
|||
$this->line(sprintf('There are no files in directory %s', $this->directory)); |
|||
$this->line('To learn more about this process, read the docs:'); |
|||
$this->line('https://docs.firefly-iii.org/csv/install/docker/'); |
|||
|
|||
return ' '; |
|||
} |
|||
$this->line(sprintf('Found %d CSV + JSON file sets in %s', count($files), $this->directory)); |
|||
try { |
|||
$this->importFiles($files); |
|||
} catch (ImportException $e) { |
|||
Log::error($e->getMessage()); |
|||
$this->line(sprintf('Import exception (see the logs): %s', $e->getMessage())); |
|||
} |
|||
|
|||
return ' '; |
|||
} |
|||
|
|||
/** |
|||
* @inheritDoc |
|||
*/ |
|||
public function line(string $string) |
|||
{ |
|||
echo sprintf("%s: %s\n", date('Y-m-d H:i:s'), $string); |
|||
} |
|||
|
|||
/** |
|||
* @inheritDoc |
|||
*/ |
|||
public function error($string, $verbosity = null) |
|||
{ |
|||
$this->line($string); |
|||
} |
|||
|
|||
/** |
|||
* @param $string |
|||
* @param null $verbosity |
|||
*/ |
|||
public function warn($string, $verbosity = null) |
|||
{ |
|||
$this->line($string); |
|||
} |
|||
|
|||
/** |
|||
* @param $string |
|||
* @param null $verbosity |
|||
*/ |
|||
public function info($string, $verbosity = null) |
|||
{ |
|||
$this->line($string); |
|||
} |
|||
} |
@ -0,0 +1,78 @@ |
|||
<?php |
|||
|
|||
|
|||
namespace App\Http\Controllers; |
|||
|
|||
|
|||
use App\Console\AutoImports; |
|||
use App\Console\HaveAccess; |
|||
use App\Console\StartImport; |
|||
use App\Console\VerifyJSON; |
|||
use App\Exceptions\ImportException; |
|||
use App\Http\Request\AutoUploadRequest; |
|||
use Log; |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
class AutoUploadController extends Controller |
|||
{ |
|||
use HaveAccess, AutoImports, VerifyJSON, StartImport; |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function index(AutoUploadRequest $request) |
|||
{ |
|||
$access = $this->haveAccess(); |
|||
if (false === $access) { |
|||
throw new ImportException('Could not connect to your local Firefly III instance.'); |
|||
} |
|||
|
|||
$json = $request->file('json'); |
|||
$csv = $request->file('csv'); |
|||
|
|||
try { |
|||
$this->importUpload($csv->getPathname(), $json->getPathname()); |
|||
} catch (ImportException $e) { |
|||
Log::error($e->getMessage()); |
|||
$this->line(sprintf('Import exception (see the logs): %s', $e->getMessage())); |
|||
} |
|||
|
|||
return ' '; |
|||
} |
|||
|
|||
/** |
|||
* @inheritDoc |
|||
*/ |
|||
public function line(string $string) |
|||
{ |
|||
echo sprintf("%s: %s\n", date('Y-m-d H:i:s'), $string); |
|||
} |
|||
|
|||
/** |
|||
* @inheritDoc |
|||
*/ |
|||
public function error($string, $verbosity = null) |
|||
{ |
|||
$this->line($string); |
|||
} |
|||
|
|||
/** |
|||
* @param $string |
|||
* @param null $verbosity |
|||
*/ |
|||
public function warn($string, $verbosity = null) |
|||
{ |
|||
$this->line($string); |
|||
} |
|||
|
|||
/** |
|||
* @param $string |
|||
* @param null $verbosity |
|||
*/ |
|||
public function info($string, $verbosity = null) |
|||
{ |
|||
$this->line($string); |
|||
} |
|||
} |
@ -0,0 +1,110 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* Controller.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Controllers; |
|||
|
|||
use App\Exceptions\ImporterHttpException; |
|||
use App\Services\Nordigen\TokenManager; |
|||
use App\Services\Spectre\Request\ListCustomersRequest; |
|||
use App\Services\Spectre\Response\ErrorResponse; |
|||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests; |
|||
use Illuminate\Foundation\Bus\DispatchesJobs; |
|||
use Illuminate\Foundation\Validation\ValidatesRequests; |
|||
use Illuminate\Routing\Controller as BaseController; |
|||
use Log; |
|||
|
|||
/** |
|||
* Class Controller |
|||
*/ |
|||
class Controller extends BaseController |
|||
{ |
|||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests; |
|||
|
|||
/** |
|||
* Controller constructor. |
|||
*/ |
|||
public function __construct() |
|||
{ |
|||
$path = config('importer.upload_path'); |
|||
$writable = is_dir($path) && is_writable($path); |
|||
if (false === $writable) { |
|||
echo sprintf('Make sure that directory "%s" exists and is writeable.', $path); |
|||
exit; |
|||
} |
|||
|
|||
app('view')->share('version', config('importer.version')); |
|||
} |
|||
|
|||
/** |
|||
* @return string|null |
|||
*/ |
|||
protected function verifyNordigen(): ?string |
|||
{ |
|||
Log::debug(sprintf('Now at %s', __METHOD__)); |
|||
|
|||
// is there a valid access and refresh token?
|
|||
if (TokenManager::hasValidRefreshToken() && TokenManager::hasValidAccessToken()) { |
|||
return null; |
|||
} |
|||
|
|||
if (TokenManager::hasExpiredRefreshToken()) { |
|||
// refresh!
|
|||
TokenManager::getFreshAccessToken(); |
|||
} |
|||
|
|||
// get complete set!
|
|||
try { |
|||
TokenManager::getNewTokenSet(); |
|||
} catch (ImporterHttpException $e) { |
|||
return $e->getMessage(); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* @return string|null |
|||
*/ |
|||
protected function verifySpectre(): ?string |
|||
{ |
|||
$url = config('spectre.url'); |
|||
$appId = config('spectre.app_id'); |
|||
$secret = config('spectre.secret'); |
|||
$request = new ListCustomersRequest($url, $appId, $secret); |
|||
|
|||
$request->setTimeOut(config('importer.connection.timeout')); |
|||
|
|||
try { |
|||
$response = $request->get(); |
|||
} catch (ImporterHttpException $e) { |
|||
return $e->getMessage(); |
|||
} |
|||
if ($response instanceof ErrorResponse) { |
|||
return sprintf('%s: %s', $response->class, $response->message); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,39 @@ |
|||
<?php |
|||
|
|||
namespace App\Http\Controllers\Import; |
|||
|
|||
use App\Http\Controllers\Controller; |
|||
use App\Services\Session\Constants; |
|||
use Illuminate\Http\Request; |
|||
|
|||
/** |
|||
* Class AuthenticateController |
|||
*/ |
|||
class AuthenticateController extends Controller |
|||
{ |
|||
/** |
|||
* @param Request $request |
|||
*/ |
|||
public function index(Request $request) |
|||
{ |
|||
$flow = $request->cookie(Constants::FLOW_COOKIE); |
|||
if ('csv' === $flow) { |
|||
// redirect straight to upload
|
|||
return redirect(route('003-upload.index')); |
|||
} |
|||
|
|||
exit; // here we are deze functies moeten iets anders teruggeven.
|
|||
// dus niet true/false of null/string maar evt een error ofzo?
|
|||
// plus wat als de values leeg zijn geeft-ie dan false terug of wat anders?
|
|||
$verifySpectre = $this->verifySpectre(); |
|||
if ('spectre' === $flow && null === $verifySpectre) { |
|||
return redirect(route('003-upload.index')); |
|||
} |
|||
|
|||
$verifyNordigen = $this->verifyNordigen(); |
|||
if ('spectre' === $flow && null === $verifySpectre) { |
|||
return redirect(route('003-upload.index')); |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,169 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* ConfigurationController.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Controllers\Import; |
|||
|
|||
|
|||
use App\Http\Controllers\Controller; |
|||
use App\Http\Middleware\ConfigComplete; |
|||
use App\Http\Request\ConfigurationPostRequest; |
|||
use App\Services\CSV\Configuration\Configuration; |
|||
use App\Services\CSV\Converter\Date; |
|||
use App\Services\CSV\Specifics\SpecificService; |
|||
use App\Services\Session\Constants; |
|||
use App\Services\Storage\StorageService; |
|||
use App\Support\Token; |
|||
use Carbon\Carbon; |
|||
use GrumpyDictator\FFIIIApiSupport\Model\Account; |
|||
use GrumpyDictator\FFIIIApiSupport\Request\GetAccountsRequest; |
|||
use Illuminate\Contracts\View\Factory; |
|||
use Illuminate\Http\JsonResponse; |
|||
use Illuminate\Http\RedirectResponse; |
|||
use Illuminate\Http\Request; |
|||
use Illuminate\View\View; |
|||
use JsonException; |
|||
use Log; |
|||
|
|||
/** |
|||
* Class ConfigurationController |
|||
*/ |
|||
class ConfigurationController extends Controller |
|||
{ |
|||
/** |
|||
* StartController constructor. |
|||
*/ |
|||
public function __construct() |
|||
{ |
|||
parent::__construct(); |
|||
app('view')->share('pageTitle', 'Import configuration'); |
|||
$this->middleware(ConfigComplete::class); |
|||
} |
|||
|
|||
/** |
|||
* @return Factory|RedirectResponse|View |
|||
*/ |
|||
public function index(Request $request) |
|||
{ |
|||
Log::debug(sprintf('Now at %s', __METHOD__)); |
|||
$mainTitle = 'Import routine'; |
|||
$subTitle = 'Configure your CSV file import'; |
|||
$accounts = []; |
|||
|
|||
$configuration = null; |
|||
if (session()->has(Constants::CONFIGURATION)) { |
|||
$configuration = Configuration::fromArray(session()->get(Constants::CONFIGURATION)); |
|||
} |
|||
// if config says to skip it, skip it:
|
|||
$overruleSkip = 'true' === $request->get('overruleskip'); |
|||
if (null !== $configuration && true === $configuration->isSkipForm() && false === $overruleSkip) { |
|||
// skipForm
|
|||
return redirect()->route('import.roles.index'); |
|||
} |
|||
|
|||
// get list of asset accounts:
|
|||
$url = Token::getURL(); |
|||
$token = Token::getAccessToken(); |
|||
$request = new GetAccountsRequest($url, $token); |
|||
$request->setType(GetAccountsRequest::ASSET); |
|||
$request->setVerify(config('csv_importer.connection.verify')); |
|||
$request->setTimeOut(config('csv_importer.connection.timeout')); |
|||
$response = $request->get(); |
|||
|
|||
// get list of specifics:
|
|||
$specifics = SpecificService::getSpecifics(); |
|||
|
|||
/** @var Account $account */ |
|||
foreach ($response as $account) { |
|||
$accounts['Asset accounts'][$account->id] = $account; |
|||
} |
|||
|
|||
// also get liabilities
|
|||
$url = Token::getURL(); |
|||
$token = Token::getAccessToken(); |
|||
$request = new GetAccountsRequest($url, $token); |
|||
$request->setVerify(config('csv_importer.connection.verify')); |
|||
$request->setTimeOut(config('csv_importer.connection.timeout')); |
|||
$request->setType(GetAccountsRequest::LIABILITIES); |
|||
$response = $request->get(); |
|||
/** @var Account $account */ |
|||
foreach ($response as $account) { |
|||
$accounts['Liabilities'][$account->id] = $account; |
|||
} |
|||
|
|||
// created default configuration object for sensible defaults:
|
|||
if (null === $configuration) { |
|||
$configuration = Configuration::make(); |
|||
} |
|||
|
|||
return view( |
|||
'import.configuration.index', |
|||
compact('mainTitle', 'subTitle', 'accounts', 'specifics', 'configuration') |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* @param Request $request |
|||
* |
|||
* @return JsonResponse |
|||
*/ |
|||
public function phpDate(Request $request): JsonResponse |
|||
{ |
|||
Log::debug(sprintf('Method %s', __METHOD__)); |
|||
|
|||
$dateObj = new Date; |
|||
[$locale, $format] = $dateObj->splitLocaleFormat($request->get('format')); |
|||
$date = Carbon::make('1984-09-17')->locale($locale); |
|||
|
|||
return response()->json(['result' => $date->translatedFormat($format)]); |
|||
} |
|||
|
|||
/** |
|||
* @param ConfigurationPostRequest $request |
|||
* |
|||
* @return RedirectResponse |
|||
*/ |
|||
public function postIndex(ConfigurationPostRequest $request): RedirectResponse |
|||
{ |
|||
Log::debug(sprintf('Now running %s', __METHOD__)); |
|||
// store config on drive.
|
|||
$fromRequest = $request->getAll(); |
|||
$configuration = Configuration::fromRequest($fromRequest); |
|||
|
|||
$json = '[]'; |
|||
try { |
|||
$json = json_encode($configuration, JSON_THROW_ON_ERROR, 512); |
|||
} catch (JsonException $e) { |
|||
Log::error($e->getMessage()); |
|||
} |
|||
StorageService::storeContent($json); |
|||
|
|||
session()->put(Constants::CONFIGURATION, $configuration->toSessionArray()); |
|||
|
|||
// set config as complete.
|
|||
session()->put(Constants::CONFIG_COMPLETE_INDICATOR, true); |
|||
|
|||
// redirect to import things?
|
|||
return redirect()->route('import.roles.index'); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,72 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* DownloadController.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Controllers\Import; |
|||
|
|||
|
|||
use App\Http\Controllers\Controller; |
|||
use App\Services\CSV\Configuration\Configuration; |
|||
use App\Services\Session\Constants; |
|||
use App\Services\Storage\StorageService; |
|||
use Illuminate\Contracts\Routing\ResponseFactory; |
|||
use Illuminate\Http\Response; |
|||
|
|||
/** |
|||
* Class DownloadController |
|||
*/ |
|||
class DownloadController extends Controller |
|||
{ |
|||
/** |
|||
* @return ResponseFactory|Response |
|||
*/ |
|||
public function download() |
|||
{ |
|||
// do something
|
|||
$configuration = Configuration::fromArray(session()->get(Constants::CONFIGURATION)); |
|||
|
|||
// append the config file with values from the disk:
|
|||
$diskArray = json_decode(StorageService::getContent(session()->get(Constants::UPLOAD_CONFIG_FILE)), true, JSON_THROW_ON_ERROR); |
|||
$diskConfig = Configuration::fromArray($diskArray); |
|||
|
|||
$configuration->setRoles($diskConfig->getRoles()); |
|||
$configuration->setMapping($diskConfig->getMapping()); |
|||
$configuration->setDoMapping($diskConfig->getDoMapping()); |
|||
$array = $configuration->toArray(); |
|||
|
|||
$result = json_encode($array, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT, 512); |
|||
|
|||
$response = response($result); |
|||
$name = sprintf('import_config_%s.json', date('Y-m-d')); |
|||
$response->header('Content-disposition', 'attachment; filename=' . $name) |
|||
->header('Content-Type', 'application/json') |
|||
->header('Content-Description', 'File Transfer') |
|||
->header('Connection', 'Keep-Alive') |
|||
->header('Expires', '0') |
|||
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0') |
|||
->header('Pragma', 'public') |
|||
->header('Content-Length', strlen($result)); |
|||
|
|||
return $response; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,228 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* MapController.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Controllers\Import; |
|||
|
|||
|
|||
use App\Http\Controllers\Controller; |
|||
use App\Http\Middleware\MappingComplete; |
|||
use App\Services\CSV\Configuration\Configuration; |
|||
use App\Services\CSV\Mapper\MapperInterface; |
|||
use App\Services\CSV\Mapper\MapperService; |
|||
use App\Services\Session\Constants; |
|||
use App\Services\Storage\StorageService; |
|||
use Illuminate\Contracts\Filesystem\FileNotFoundException; |
|||
use Illuminate\Contracts\View\Factory; |
|||
use Illuminate\Http\RedirectResponse; |
|||
use Illuminate\Http\Request; |
|||
use Illuminate\View\View; |
|||
use InvalidArgumentException; |
|||
use League\Csv\Exception; |
|||
use Log; |
|||
|
|||
/** |
|||
* Class MapController |
|||
*/ |
|||
class MapController extends Controller |
|||
{ |
|||
|
|||
/** |
|||
* RoleController constructor. |
|||
*/ |
|||
public function __construct() |
|||
{ |
|||
parent::__construct(); |
|||
app('view')->share('pageTitle', 'Map data'); |
|||
$this->middleware(MappingComplete::class); |
|||
} |
|||
|
|||
/** |
|||
* @return Factory|View |
|||
* @throws Exception |
|||
* @throws FileNotFoundException |
|||
*/ |
|||
public function index() |
|||
{ |
|||
$mainTitle = 'Map data'; |
|||
$subTitle = 'Map values in CSV file to actual data in Firefly III'; |
|||
Log::debug('Now in mapController index'); |
|||
|
|||
// get configuration object.
|
|||
$configuration = Configuration::fromArray(session()->get(Constants::CONFIGURATION)); |
|||
|
|||
// the config in the session will miss important values, we must get those from disk:
|
|||
// 'mapping', 'do_mapping', 'roles' are missing.
|
|||
$diskArray = json_decode(StorageService::getContent(session()->get(Constants::UPLOAD_CONFIG_FILE)), true, JSON_THROW_ON_ERROR); |
|||
$diskConfig = Configuration::fromArray($diskArray); |
|||
|
|||
$configuration->setMapping($diskConfig->getMapping()); |
|||
$configuration->setDoMapping($diskConfig->getDoMapping()); |
|||
$configuration->setRoles($diskConfig->getRoles()); |
|||
|
|||
// then we can use them:
|
|||
$roles = $configuration->getRoles(); |
|||
$existingMapping = $configuration->getMapping(); |
|||
$doMapping = $configuration->getDoMapping(); |
|||
$data = []; |
|||
|
|||
foreach ($roles as $index => $role) { |
|||
$info = config('csv_importer.import_roles')[$role] ?? null; |
|||
$mappable = $info['mappable'] ?? false; |
|||
if (null === $info) { |
|||
continue; |
|||
} |
|||
if (false === $mappable) { |
|||
continue; |
|||
} |
|||
$mapColumn = $doMapping[$index] ?? false; |
|||
if (false === $mapColumn) { |
|||
continue; |
|||
} |
|||
Log::debug(sprintf('Mappable role is "%s"', $role)); |
|||
|
|||
$info['role'] = $role; |
|||
$info['values'] = []; |
|||
|
|||
|
|||
// create the "mapper" class which will get data from Firefly III.
|
|||
$class = sprintf('App\\Services\\CSV\\Mapper\\%s', $info['mapper']); |
|||
if (!class_exists($class)) { |
|||
throw new InvalidArgumentException(sprintf('Class %s does not exist.', $class)); |
|||
} |
|||
Log::debug(sprintf('Associated class is %s', $class)); |
|||
|
|||
|
|||
/** @var MapperInterface $object */ |
|||
$object = app($class); |
|||
$info['mapping_data'] = $object->getMap(); |
|||
$info['mapped'] = $existingMapping[$index] ?? []; |
|||
|
|||
Log::debug(sprintf('Mapping data length is %d', count($info['mapping_data']))); |
|||
|
|||
$data[$index] = $info; |
|||
} |
|||
|
|||
// get columns from file
|
|||
$content = StorageService::getContent(session()->get(Constants::UPLOAD_CSV_FILE)); |
|||
$delimiter = (string) config(sprintf('csv_importer.delimiters.%s', $configuration->getDelimiter())); |
|||
$data = MapperService::getMapData($content, $delimiter, $configuration->isHeaders(), $configuration->getSpecifics(), $data); |
|||
|
|||
return view('import.map.index', compact('mainTitle', 'subTitle', 'roles', 'data')); |
|||
} |
|||
|
|||
/** |
|||
* @param Request $request |
|||
* |
|||
* @return RedirectResponse |
|||
*/ |
|||
public function postIndex(Request $request): RedirectResponse |
|||
{ |
|||
$values = $request->get('values') ?? []; |
|||
$mapping = $request->get('mapping') ?? []; |
|||
$values = !is_array($values) ? [] : $values; |
|||
$mapping = !is_array($mapping) ? [] : $mapping; |
|||
$data = []; |
|||
|
|||
$configuration = Configuration::fromArray(session()->get(Constants::CONFIGURATION)); |
|||
|
|||
/** |
|||
* Loop array with available columns. |
|||
* |
|||
* @var int $index |
|||
* @var array $row |
|||
*/ |
|||
foreach ($values as $columnIndex => $column) { |
|||
/** |
|||
* Loop all values for this column |
|||
* |
|||
* @var int $valueIndex |
|||
* @var string $value |
|||
*/ |
|||
foreach ($column as $valueIndex => $value) { |
|||
$mappedValue = $mapping[$columnIndex][$valueIndex] ?? null; |
|||
if (null !== $mappedValue && 0 !== $mappedValue && '0' !== $mappedValue) { |
|||
$data[$columnIndex][$value] = (int) $mappedValue; |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
// at this point the $data array must be merged with the mapping as it is on the disk,
|
|||
// and then saved to disk once again in a new config file.
|
|||
$diskArray = json_decode(StorageService::getContent(session()->get(Constants::UPLOAD_CONFIG_FILE)), true, JSON_THROW_ON_ERROR); |
|||
$diskConfig = Configuration::fromArray($diskArray); |
|||
$originalMapping = $diskConfig->getMapping(); |
|||
|
|||
// loop $data and save values:
|
|||
$mergedMapping = $this->mergeMapping($originalMapping, $data); |
|||
|
|||
$configuration->setMapping($mergedMapping); |
|||
|
|||
// store mapping in config object ( + session)
|
|||
session()->put(Constants::CONFIGURATION, $configuration->toSessionArray()); |
|||
|
|||
// since the configuration saved in the session will omit 'mapping', 'do_mapping' and 'roles'
|
|||
// these must be set to the configuration file
|
|||
// no need to do this sooner because toSessionArray would have dropped them anyway.
|
|||
$configuration->setRoles($diskConfig->getRoles()); |
|||
$configuration->setDoMapping($diskConfig->getDoMapping()); |
|||
|
|||
// then save entire thing to a new disk file:
|
|||
$configFileName = StorageService::storeArray($configuration->toArray()); |
|||
Log::debug(sprintf('Old configuration was stored under key "%s".', session()->get(Constants::UPLOAD_CONFIG_FILE))); |
|||
|
|||
session()->put(Constants::UPLOAD_CONFIG_FILE, $configFileName); |
|||
|
|||
Log::debug(sprintf('New configuration is stored under key "%s".', session()->get(Constants::UPLOAD_CONFIG_FILE))); |
|||
|
|||
// set map config as complete.
|
|||
session()->put(Constants::MAPPING_COMPLETE_INDICATOR, true); |
|||
|
|||
return redirect()->route('import.run.index'); |
|||
} |
|||
|
|||
/** |
|||
* @param array $original |
|||
* @param array $new |
|||
* @return array |
|||
*/ |
|||
private function mergeMapping(array $original, array $new): array |
|||
{ |
|||
Log::debug('Now merging disk mapping with new mapping'); |
|||
foreach ($new as $column => $mappedValues) { |
|||
Log::debug(sprintf('Now working on column "%s"', $column)); |
|||
if (array_key_exists($column, $original)) { |
|||
foreach ($mappedValues as $name => $value) { |
|||
Log::debug(sprintf('Updated mapping of "%s" to ID "%s"', $name, $value)); |
|||
$original[$column][$name] = $value; |
|||
} |
|||
} |
|||
if (!array_key_exists($column, $original)) { |
|||
Log::debug('The original mapping has no map data for this column. We will set it now.'); |
|||
$original[$column] = $mappedValues; |
|||
} |
|||
} |
|||
// original has been updated:
|
|||
return $original; |
|||
} |
|||
} |
@ -0,0 +1,175 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* RoleController.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Controllers\Import; |
|||
|
|||
|
|||
use App\Http\Controllers\Controller; |
|||
use App\Http\Middleware\RolesComplete; |
|||
use App\Http\Request\RolesPostRequest; |
|||
use App\Services\CSV\Configuration\ConfigFileProcessor; |
|||
use App\Services\CSV\Configuration\Configuration; |
|||
use App\Services\CSV\Roles\RoleService; |
|||
use App\Services\Session\Constants; |
|||
use App\Services\Storage\StorageService; |
|||
use Illuminate\Contracts\Filesystem\FileNotFoundException; |
|||
use Illuminate\Contracts\View\Factory; |
|||
use Illuminate\Http\RedirectResponse; |
|||
use Illuminate\View\View; |
|||
use League\Csv\Exception; |
|||
use Log; |
|||
|
|||
/** |
|||
* Class RoleController |
|||
*/ |
|||
class RoleController extends Controller |
|||
{ |
|||
/** |
|||
* RoleController constructor. |
|||
*/ |
|||
public function __construct() |
|||
{ |
|||
parent::__construct(); |
|||
app('view')->share('pageTitle', 'Define roles'); |
|||
$this->middleware(RolesComplete::class); |
|||
} |
|||
|
|||
/** |
|||
* @return Factory|View |
|||
* @throws FileNotFoundException |
|||
* @throws Exception |
|||
*/ |
|||
public function index() |
|||
{ |
|||
Log::debug('Now in role controller'); |
|||
$mainTitle = 'Define roles'; |
|||
$subTitle = 'Configure the role of each column in your file'; |
|||
|
|||
// get configuration object.
|
|||
// Read configuration from session, will miss some important keys:
|
|||
$configuration = Configuration::fromArray(session()->get(Constants::CONFIGURATION)); |
|||
|
|||
// append configuration from original file
|
|||
// because the session omits 3 arrays: mapping, do_mapping and roles
|
|||
$configFileName = session()->get(Constants::UPLOAD_CONFIG_FILE); |
|||
$fileConfiguration = ConfigFileProcessor::convertConfigFile($configFileName); |
|||
$configuration->setDoMapping($fileConfiguration->getDoMapping()); |
|||
$configuration->setMapping($fileConfiguration->getMapping()); |
|||
$configuration->setRoles($fileConfiguration->getRoles()); |
|||
|
|||
// get columns from file
|
|||
$content = StorageService::getContent(session()->get(Constants::UPLOAD_CSV_FILE)); |
|||
$columns = RoleService::getColumns($content, $configuration); |
|||
$examples = RoleService::getExampleData($content, $configuration); |
|||
|
|||
// submit mapping from config.
|
|||
$mapping = base64_encode(json_encode($configuration->getMapping(), JSON_THROW_ON_ERROR, 512)); |
|||
|
|||
// roles
|
|||
$roles = config('csv_importer.import_roles'); |
|||
ksort($roles); |
|||
|
|||
// configuration (if it is set)
|
|||
$configuredRoles = $configuration->getRoles(); |
|||
$configuredDoMapping = $configuration->getDoMapping(); |
|||
|
|||
return view( |
|||
'import.roles.index', |
|||
compact('mainTitle', 'configuration', 'subTitle', 'columns', 'examples', 'roles', 'configuredRoles', 'configuredDoMapping', 'mapping') |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* @param RolesPostRequest $request |
|||
* |
|||
* @return RedirectResponse |
|||
*/ |
|||
public function postIndex(RolesPostRequest $request): RedirectResponse |
|||
{ |
|||
$data = $request->getAll(); |
|||
|
|||
// get configuration object.
|
|||
// Read configuration from session, may miss some important keys:
|
|||
$configuration = Configuration::fromArray(session()->get(Constants::CONFIGURATION)); |
|||
|
|||
$needsMapping = $this->needMapping($data['do_mapping']); |
|||
$configuration->setRoles($data['roles']); |
|||
$configuration->setDoMapping($data['do_mapping']); |
|||
|
|||
session()->put(Constants::CONFIGURATION, $configuration->toSessionArray()); |
|||
|
|||
// the new configuration array 'roles' and 'do_mapping' will not be saved to the session
|
|||
// and would otherwise be lost. Those must be saved to the file on disk instead.
|
|||
|
|||
// the 'mapping' array is missing because it was saved to disk and not used otherwise
|
|||
// it must be restored, and THEN saved:
|
|||
$diskArray = json_decode(StorageService::getContent(session()->get(Constants::UPLOAD_CONFIG_FILE)), true, JSON_THROW_ON_ERROR); |
|||
$diskConfig = Configuration::fromArray($diskArray); |
|||
// save the mapping from the diskConfig to our updated config:
|
|||
$configuration->setMapping($diskConfig->getMapping()); |
|||
|
|||
// then this is the new, full array:
|
|||
$fullArray = $configuration->toArray(); |
|||
|
|||
// and it can be saved on disk:
|
|||
$configFileName = StorageService::storeArray($fullArray); |
|||
Log::debug(sprintf('Old configuration was stored under key "%s".', session()->get(Constants::UPLOAD_CONFIG_FILE))); |
|||
|
|||
// this is a new config file name.
|
|||
session()->put(Constants::UPLOAD_CONFIG_FILE, $configFileName); |
|||
|
|||
Log::debug(sprintf('New configuration is stored under key "%s".', session()->get(Constants::UPLOAD_CONFIG_FILE))); |
|||
|
|||
// set role config as complete.
|
|||
session()->put(Constants::ROLES_COMPLETE_INDICATOR, true); |
|||
|
|||
// redirect to mapping thing.
|
|||
if (true === $needsMapping) { |
|||
return redirect()->route('import.mapping.index'); |
|||
} |
|||
// otherwise, store empty mapping, and continue:
|
|||
// set map config as complete.
|
|||
session()->put(Constants::MAPPING_COMPLETE_INDICATOR, true); |
|||
|
|||
return redirect()->route('import.run.index'); |
|||
} |
|||
|
|||
/** |
|||
* Will tell you if any role needs mapping. |
|||
* |
|||
* @param array $array |
|||
* |
|||
* @return bool |
|||
*/ |
|||
private function needMapping(array $array): bool |
|||
{ |
|||
$need = false; |
|||
foreach ($array as $value) { |
|||
if (true === $value) { |
|||
$need = true; |
|||
} |
|||
} |
|||
|
|||
return $need; |
|||
} |
|||
} |
@ -0,0 +1,194 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* RunController.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Controllers\Import; |
|||
|
|||
|
|||
use App\Exceptions\ImportException; |
|||
use App\Http\Controllers\Controller; |
|||
use App\Http\Middleware\ReadyForImport; |
|||
use App\Mail\ImportFinished; |
|||
use App\Services\CSV\Configuration\Configuration; |
|||
use App\Services\CSV\File\FileReader; |
|||
use App\Services\Import\ImportJobStatus\ImportJobStatus; |
|||
use App\Services\Import\ImportJobStatus\ImportJobStatusManager; |
|||
use App\Services\Import\ImportRoutineManager; |
|||
use App\Services\Session\Constants; |
|||
use App\Services\Storage\StorageService; |
|||
use ErrorException; |
|||
use Illuminate\Http\JsonResponse; |
|||
use Illuminate\Http\Request; |
|||
use JsonException; |
|||
use Log; |
|||
use Mail; |
|||
use TypeError; |
|||
|
|||
|
|||
/** |
|||
* Class RunController |
|||
*/ |
|||
class RunController extends Controller |
|||
{ |
|||
|
|||
/** |
|||
* StartController constructor. |
|||
*/ |
|||
public function __construct() |
|||
{ |
|||
parent::__construct(); |
|||
app('view')->share('pageTitle', 'Importing data...'); |
|||
$this->middleware(ReadyForImport::class); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
*/ |
|||
public function index() |
|||
{ |
|||
Log::debug(sprintf('Now in %s', __METHOD__)); |
|||
$mainTitle = 'Import the data'; |
|||
$subTitle = 'Connect to Firefly III and store your data'; |
|||
|
|||
// get configuration object.
|
|||
$configuration = Configuration::fromArray(session()->get(Constants::CONFIGURATION)); |
|||
|
|||
// append info from the file on disk:
|
|||
$diskArray = json_decode(StorageService::getContent(session()->get(Constants::UPLOAD_CONFIG_FILE)), true, JSON_THROW_ON_ERROR); |
|||
$diskConfig = Configuration::fromArray($diskArray); |
|||
|
|||
$configuration->setDoMapping($diskConfig->getDoMapping()); |
|||
$configuration->setMapping($diskConfig->getMapping()); |
|||
|
|||
|
|||
Log::debug('Will now verify configuration content.'); |
|||
if ([] === $configuration->getDoMapping()) { |
|||
// no mapping, back to roles
|
|||
Log::debug('NO role info in config, will send you back to roles..'); |
|||
$jobBackUrl = route('back.roles'); |
|||
} |
|||
if ([] !== $configuration->getMapping()) { |
|||
// back to mapping
|
|||
Log::debug('NO mapping in file, will send you back to mapping..'); |
|||
$jobBackUrl = route('back.mapping'); |
|||
} |
|||
|
|||
// job ID may be in session:
|
|||
$identifier = session()->get(Constants::JOB_IDENTIFIER); |
|||
$routine = new ImportRoutineManager($identifier); |
|||
$identifier = $routine->getIdentifier(); |
|||
|
|||
Log::debug(sprintf('Import routine manager identifier is "%s"', $identifier)); |
|||
|
|||
// store identifier in session so the status can get it.
|
|||
session()->put(Constants::JOB_IDENTIFIER, $identifier); |
|||
Log::debug(sprintf('Stored "%s" under "%s"', $identifier, Constants::JOB_IDENTIFIER)); |
|||
|
|||
return view('import.run.index', compact('mainTitle', 'subTitle', 'identifier', 'jobBackUrl')); |
|||
} |
|||
|
|||
/** |
|||
* @param Request $request |
|||
* |
|||
* @return JsonResponse |
|||
* @throws JsonException |
|||
* @throws JsonException |
|||
*/ |
|||
public function start(Request $request): JsonResponse |
|||
{ |
|||
Log::debug(sprintf('Now at %s', __METHOD__)); |
|||
$identifier = $request->get('identifier'); |
|||
$routine = new ImportRoutineManager($identifier); |
|||
|
|||
$importJobStatus = ImportJobStatusManager::startOrFindJob($identifier); |
|||
ImportJobStatusManager::setJobStatus(ImportJobStatus::JOB_RUNNING); |
|||
|
|||
try { |
|||
// read configuration from session
|
|||
$configuration = Configuration::fromArray(session()->get(Constants::CONFIGURATION)); |
|||
|
|||
// read configuration from disk (to append data)
|
|||
$diskArray = json_decode(StorageService::getContent(session()->get(Constants::UPLOAD_CONFIG_FILE)), true, JSON_THROW_ON_ERROR); |
|||
$diskConfig = Configuration::fromArray($diskArray); |
|||
$configuration->setMapping($diskConfig->getMapping()); |
|||
$configuration->setDoMapping($diskConfig->getDoMapping()); |
|||
$configuration->setRoles($diskConfig->getRoles()); |
|||
|
|||
$routine->setConfiguration($configuration); |
|||
$routine->setReader(FileReader::getReaderFromSession()); |
|||
$routine->start(); |
|||
} /** @noinspection PhpRedundantCatchClauseInspection */ catch (ImportException | ErrorException | TypeError $e) { |
|||
// update job to error state.
|
|||
ImportJobStatusManager::setJobStatus(ImportJobStatus::JOB_ERRORED); |
|||
$error = sprintf('Internal error: %s in file %s:%d', $e->getMessage(), $e->getFile(), $e->getLine()); |
|||
Log::error($e->getMessage()); |
|||
Log::error($e->getTraceAsString()); |
|||
ImportJobStatusManager::addError($identifier, 0, $error); |
|||
|
|||
return response()->json($importJobStatus->toArray()); |
|||
} |
|||
|
|||
// set done:
|
|||
ImportJobStatusManager::setJobStatus(ImportJobStatus::JOB_DONE); |
|||
|
|||
// if configured, send report!
|
|||
$log |
|||
= [ |
|||
'messages' => $routine->getAllMessages(), |
|||
'warnings' => $routine->getAllWarnings(), |
|||
'errors' => $routine->getAllErrors(), |
|||
]; |
|||
|
|||
$send = config('mail.enable_mail_report'); |
|||
Log::debug('Log log', $log); |
|||
if (true === $send) { |
|||
Log::debug('SEND MAIL'); |
|||
Mail::to(config('mail.destination'))->send(new ImportFinished($log)); |
|||
} |
|||
|
|||
return response()->json($importJobStatus->toArray()); |
|||
} |
|||
|
|||
/** |
|||
* @param Request $request |
|||
* |
|||
* @return JsonResponse |
|||
* @throws JsonException |
|||
*/ |
|||
public function status(Request $request): JsonResponse |
|||
{ |
|||
|
|||
$identifier = $request->get('identifier'); |
|||
Log::debug(sprintf('Now at %s(%s)', __METHOD__, $identifier)); |
|||
if (null === $identifier) { |
|||
Log::warning('Identifier is NULL.'); |
|||
// no status is known yet because no identifier is in the session.
|
|||
// As a fallback, return empty status
|
|||
$fakeStatus = new ImportJobStatus; |
|||
|
|||
return response()->json($fakeStatus->toArray()); |
|||
} |
|||
$importJobStatus = ImportJobStatusManager::startOrFindJob($identifier); |
|||
|
|||
return response()->json($importJobStatus->toArray()); |
|||
} |
|||
} |
@ -0,0 +1,73 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* StartController.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Controllers\Import; |
|||
|
|||
|
|||
use App\Http\Controllers\Controller; |
|||
use App\Http\Middleware\UploadedFiles; |
|||
use Illuminate\Contracts\View\Factory; |
|||
use Illuminate\View\View; |
|||
use Log; |
|||
use Storage; |
|||
|
|||
/** |
|||
* Class StartController |
|||
*/ |
|||
class StartController extends Controller |
|||
{ |
|||
/** |
|||
* StartController constructor. |
|||
*/ |
|||
public function __construct() |
|||
{ |
|||
parent::__construct(); |
|||
app('view')->share('pageTitle', 'Import'); |
|||
$this->middleware(UploadedFiles::class); |
|||
} |
|||
|
|||
/** |
|||
* @return Factory|View |
|||
*/ |
|||
public function index() |
|||
{ |
|||
Log::debug(sprintf('Now at %s', __METHOD__)); |
|||
$mainTitle = 'Import routine'; |
|||
$subTitle = 'Start page and instructions'; |
|||
|
|||
// get existing configs.
|
|||
$disk = Storage::disk('configurations'); |
|||
Log::debug( |
|||
sprintf( |
|||
'Going to check directory for config files: %s', |
|||
config('filesystems.disks.configurations.root'), |
|||
) |
|||
); |
|||
$list = $disk->files(); |
|||
|
|||
Log::debug('List of files:', $list); |
|||
|
|||
return view('import.index', compact('mainTitle', 'subTitle', 'list')); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,193 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* UploadController.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Controllers\Import; |
|||
|
|||
|
|||
use App\Exceptions\ImportException; |
|||
use App\Http\Controllers\Controller; |
|||
use App\Http\Middleware\UploadedFiles; |
|||
use App\Services\CSV\Configuration\ConfigFileProcessor; |
|||
use App\Services\Session\Constants; |
|||
use App\Services\Storage\StorageService; |
|||
use Illuminate\Http\RedirectResponse; |
|||
use Illuminate\Http\Request; |
|||
use Illuminate\Routing\Redirector; |
|||
use Illuminate\Support\MessageBag; |
|||
use Log; |
|||
use Storage; |
|||
|
|||
/** |
|||
* Class UploadController |
|||
*/ |
|||
class UploadController extends Controller |
|||
{ |
|||
/** |
|||
* UploadController constructor. |
|||
*/ |
|||
public function __construct() |
|||
{ |
|||
parent::__construct(); |
|||
$this->middleware(UploadedFiles::class); |
|||
} |
|||
|
|||
/** |
|||
* @param Request $request |
|||
* |
|||
* @return RedirectResponse|Redirector |
|||
*/ |
|||
public function upload(Request $request) |
|||
{ |
|||
Log::debug(sprintf('Now at %s', __METHOD__)); |
|||
$csvFile = $request->file('csv_file'); |
|||
$configFile = $request->file('config_file'); |
|||
$errors = new MessageBag; |
|||
|
|||
if (null === $csvFile) { |
|||
$errors->add('csv_file', 'No file was uploaded.'); |
|||
|
|||
return redirect(route('import.start'))->withErrors($errors); |
|||
} |
|||
$errorNumber = $csvFile->getError(); |
|||
if (0 !== $errorNumber) { |
|||
$errors->add('csv_file', $this->getError($errorNumber)); |
|||
} |
|||
|
|||
// upload the file to a temp directory and use it from there.
|
|||
if (0 === $errorNumber) { |
|||
$content = file_get_contents($csvFile->getPathname()); |
|||
|
|||
// https://stackoverflow.com/questions/11066857/detect-eol-type-using-php
|
|||
// because apparantly there are banks that use "\r" as newline. Looking at the morons of KBC Bank, Belgium.
|
|||
// This one is for you: 🤦♀️
|
|||
$eol = $this->detectEOL($content); |
|||
if ("\r" === $eol) { |
|||
Log::error('You bank is dumb. Tell them to fix their CSV files.'); |
|||
$content = str_replace("\r", "\n", $content); |
|||
} |
|||
|
|||
$csvFileName = StorageService::storeContent($content); |
|||
session()->put(Constants::UPLOAD_CSV_FILE, $csvFileName); |
|||
session()->put(Constants::HAS_UPLOAD, 'true'); |
|||
} |
|||
|
|||
// if present, and no errors, upload the config file and store it in the session.
|
|||
if (null !== $configFile) { |
|||
Log::debug('Config file is present.'); |
|||
$errorNumber = $configFile->getError(); |
|||
if (0 !== $errorNumber) { |
|||
$errors->add('config_file', $errorNumber); |
|||
} |
|||
// upload the file to a temp directory and use it from there.
|
|||
if (0 === $errorNumber) { |
|||
Log::debug('Config file uploaded.'); |
|||
$configFileName = StorageService::storeContent(file_get_contents($configFile->getPathname())); |
|||
|
|||
session()->put(Constants::UPLOAD_CONFIG_FILE, $configFileName); |
|||
|
|||
// process the config file
|
|||
try { |
|||
$configuration = ConfigFileProcessor::convertConfigFile($configFileName); |
|||
session()->put(Constants::CONFIGURATION, $configuration->toSessionArray()); |
|||
} catch (ImportException $e) { |
|||
$errors->add('config_file', $e->getMessage()); |
|||
} |
|||
} |
|||
} |
|||
// if no uploaded config file, read and use the submitted existing file, if any.
|
|||
$existingFile = (string) $request->get('existing_config'); |
|||
|
|||
if (null === $configFile && '' !== $existingFile) { |
|||
Log::debug('User selected a config file from the store.'); |
|||
$disk = Storage::disk('configurations'); |
|||
$configFileName = StorageService::storeContent($disk->get($existingFile)); |
|||
|
|||
session()->put(Constants::UPLOAD_CONFIG_FILE, $configFileName); |
|||
|
|||
// process the config file
|
|||
try { |
|||
$configuration = ConfigFileProcessor::convertConfigFile($configFileName); |
|||
session()->put(Constants::CONFIGURATION, $configuration->toSessionArray()); |
|||
} catch (ImportException $e) { |
|||
$errors->add('config_file', $e->getMessage()); |
|||
} |
|||
} |
|||
|
|||
if ($errors->count() > 0) { |
|||
return redirect(route('import.start'))->withErrors($errors); |
|||
} |
|||
|
|||
return redirect(route('import.configure.index')); |
|||
} |
|||
|
|||
/** |
|||
* @param int $error |
|||
* |
|||
* @return string |
|||
*/ |
|||
private function getError(int $error): string |
|||
{ |
|||
app('log')->debug(sprintf('Now at %s', __METHOD__)); |
|||
$errors = [ |
|||
UPLOAD_ERR_OK => 'There is no error, the file uploaded with success.', |
|||
UPLOAD_ERR_INI_SIZE => 'The uploaded file exceeds the upload_max_filesize directive in php.ini.', |
|||
UPLOAD_ERR_FORM_SIZE => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.', |
|||
UPLOAD_ERR_PARTIAL => 'The uploaded file was only partially uploaded.', |
|||
UPLOAD_ERR_NO_FILE => 'No file was uploaded.', |
|||
UPLOAD_ERR_NO_TMP_DIR => 'Missing a temporary folder.', |
|||
UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk. Introduced in PHP 5.1.0.', |
|||
UPLOAD_ERR_EXTENSION => 'A PHP extension stopped the file upload.', |
|||
]; |
|||
|
|||
return $errors[$error] ?? 'Unknown error'; |
|||
} |
|||
|
|||
/** |
|||
* @param string $string |
|||
* |
|||
* @return string |
|||
*/ |
|||
private function detectEOL(string $string): string |
|||
{ |
|||
$eols = [ |
|||
'\n\r' => "\n\r", // 0x0A - 0x0D - acorn BBC
|
|||
'\r\n' => "\r\n", // 0x0D - 0x0A - Windows, DOS OS/2
|
|||
'\n' => "\n", // 0x0A - - Unix, OSX
|
|||
'\r' => "\r", // 0x0D - - Apple ][, TRS80
|
|||
]; |
|||
$curCount = 0; |
|||
$curEol = ''; |
|||
foreach ($eols as $eolKey => $eol) { |
|||
$count = substr_count($string, $eol); |
|||
Log::debug(sprintf('Counted %dx "%s" EOL in upload.', $count, $eolKey)); |
|||
if ($count > $curCount) { |
|||
$curCount = $count; |
|||
$curEol = $eol; |
|||
Log::debug(sprintf('Conclusion: "%s" is the EOL in this file.', $eolKey)); |
|||
} |
|||
} |
|||
|
|||
return $curEol; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,141 @@ |
|||
<?php |
|||
/** |
|||
* IndexController.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
*/ |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Http\Controllers; |
|||
|
|||
use App\Services\Session\Constants; |
|||
use Artisan; |
|||
use Illuminate\Http\Request; |
|||
use Log; |
|||
|
|||
/** |
|||
* |
|||
* Class IndexController |
|||
*/ |
|||
class IndexController extends Controller |
|||
{ |
|||
/** |
|||
* IndexController constructor. |
|||
*/ |
|||
public function __construct() |
|||
{ |
|||
parent::__construct(); |
|||
app('view')->share('pageTitle', 'Index'); |
|||
} |
|||
|
|||
/** |
|||
* @param Request $request |
|||
*/ |
|||
public function postIndex(Request $request) |
|||
{ |
|||
// set cookie with flow:
|
|||
$flow = $request->get('flow'); |
|||
if (in_array($flow, config('importer.flows'), true)) { |
|||
$cookies = [ |
|||
cookie(Constants::FLOW_COOKIE, $flow), |
|||
]; |
|||
return redirect(route('002-authenticate.index'))->withCookies($cookies); |
|||
} |
|||
return redirect(route('index')); |
|||
} |
|||
|
|||
/** |
|||
* @param Request $request |
|||
* @return mixed |
|||
*/ |
|||
public function index(Request $request): mixed |
|||
{ |
|||
Log::debug(sprintf('Now at %s', __METHOD__)); |
|||
// check for access token cookie. if not, redirect to flow to get it.
|
|||
$accessToken = (string) $request->cookie('access_token'); |
|||
$refreshToken = (string) $request->cookie('refresh_token'); |
|||
$baseURL = (string) $request->cookie('base_url'); |
|||
$vanityURL = (string) $request->cookie('vanity_url'); |
|||
|
|||
Log::debug(sprintf('Base URL : "%s"', $baseURL)); |
|||
Log::debug(sprintf('Vanity URL : "%s"', $vanityURL)); |
|||
|
|||
if ('' === $accessToken && '' === $refreshToken && '' === $baseURL) { |
|||
Log::debug('No access token cookie, redirect to token.index'); |
|||
return redirect(route('token.index')); |
|||
} |
|||
Log::debug('Has access token cookie.'); |
|||
|
|||
// display to user the method of authentication
|
|||
$pat = false; |
|||
if ('' !== (string) env('FIREFLY_III_ACCESS_TOKEN')) { |
|||
$pat = true; |
|||
} |
|||
$clientIdWithURL = false; |
|||
if ('' !== (string) env('FIREFLY_III_URL') && '' !== (string) env('FIREFLY_III_CLIENT_ID')) { |
|||
$clientIdWithURL = true; |
|||
} |
|||
$URLonly = false; |
|||
if ('' !== (string) env('FIREFLY_III_URL') && '' === (string) env('FIREFLY_III_CLIENT_ID') && '' === (string) env('FIREFLY_III_ACCESS_TOKEN') |
|||
) { |
|||
$URLonly = true; |
|||
} |
|||
$flexible = false; |
|||
if ('' === (string) env('FIREFLY_III_URL') && '' === (string) env('FIREFLY_III_CLIENT_ID')) { |
|||
$flexible = true; |
|||
} |
|||
|
|||
|
|||
return view('index', compact('pat', 'clientIdWithURL', 'URLonly', 'flexible')); |
|||
} |
|||
|
|||
/** |
|||
* @return mixed |
|||
*/ |
|||
public function reset(): mixed |
|||
{ |
|||
Log::debug(sprintf('Now at %s', __METHOD__)); |
|||
session()->forget(['csv_file_path', 'config_file_path', 'import_job_id']); |
|||
session()->flush(); |
|||
Artisan::call('cache:clear'); |
|||
|
|||
$cookies = [ |
|||
cookie('access_token', ''), |
|||
cookie('base_url', ''), |
|||
cookie('refresh_token', ''), |
|||
]; |
|||
|
|||
return redirect(route('index'))->withCookies($cookies); |
|||
} |
|||
|
|||
/** |
|||
* @return mixed |
|||
*/ |
|||
public function flush(): mixed |
|||
{ |
|||
Log::debug(sprintf('Now at %s', __METHOD__)); |
|||
session()->forget(['csv_file_path', 'config_file_path', 'import_job_id']); |
|||
session()->flush(); |
|||
Artisan::call('cache:clear'); |
|||
Artisan::call('config:clear'); |
|||
|
|||
return redirect(route('index')); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,73 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* NavController.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Controllers; |
|||
|
|||
use App\Services\Session\Constants; |
|||
use Illuminate\Contracts\Foundation\Application; |
|||
use Illuminate\Http\RedirectResponse; |
|||
use Illuminate\Routing\Redirector; |
|||
|
|||
/** |
|||
* Class NavController |
|||
*/ |
|||
class NavController extends Controller |
|||
{ |
|||
/** |
|||
* Return back to config |
|||
*/ |
|||
public function toConfig() |
|||
{ |
|||
session()->forget(Constants::CONFIG_COMPLETE_INDICATOR); |
|||
|
|||
return redirect(route('import.configure.index') . '?overruleskip=true'); |
|||
} |
|||
|
|||
/** |
|||
* @return Application|RedirectResponse|Redirector |
|||
*/ |
|||
public function toRoles() |
|||
{ |
|||
session()->forget(Constants::ROLES_COMPLETE_INDICATOR); |
|||
return redirect(route('import.roles.index')); |
|||
} |
|||
|
|||
/** |
|||
* Return back to index. Needs no session updates. |
|||
*/ |
|||
public function toStart() |
|||
{ |
|||
return redirect(route('index')); |
|||
} |
|||
|
|||
/** |
|||
* Return back to upload. |
|||
*/ |
|||
public function toUpload() |
|||
{ |
|||
session()->forget(Constants::HAS_UPLOAD); |
|||
|
|||
return redirect(route('import.start')); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,46 @@ |
|||
<?php |
|||
|
|||
namespace App\Http\Controllers; |
|||
|
|||
use App\Exceptions\ImporterHttpException; |
|||
use App\Services\Nordigen\TokenManager; |
|||
use App\Services\Spectre\Request\ListCustomersRequest; |
|||
use App\Services\Spectre\Response\ErrorResponse; |
|||
use Illuminate\Http\JsonResponse; |
|||
use Illuminate\Http\Request; |
|||
use Log; |
|||
|
|||
/** |
|||
* Class ServiceController |
|||
*/ |
|||
class ServiceController extends Controller |
|||
{ |
|||
/** |
|||
* @param Request $request |
|||
* @return JsonResponse |
|||
*/ |
|||
public function validateSpectre(Request $request): JsonResponse |
|||
{ |
|||
$error = $this->verifySpectre(); |
|||
|
|||
if (null !== $error) { |
|||
// send user error:
|
|||
return response()->json(['result' => 'NOK', 'message' => $error]); |
|||
} |
|||
|
|||
return response()->json(['result' => 'OK']); |
|||
} |
|||
|
|||
/** |
|||
* @return JsonResponse |
|||
*/ |
|||
public function validateNordigen(): JsonResponse |
|||
{ |
|||
$error = $this->verifyNordigen(); |
|||
if (null !== $error) { |
|||
// send user error:
|
|||
return response()->json(['result' => 'NOK', 'message' => $error]); |
|||
} |
|||
return response()->json(['result' => 'OK']); |
|||
} |
|||
} |
@ -0,0 +1,309 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* TokenController.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Controllers; |
|||
|
|||
use App\Exceptions\ApiException; |
|||
use GrumpyDictator\FFIIIApiSupport\Exceptions\ApiHttpException; |
|||
use GrumpyDictator\FFIIIApiSupport\Request\SystemInformationRequest; |
|||
use GuzzleHttp\Client; |
|||
use GuzzleHttp\Exception\ClientException; |
|||
use Illuminate\Contracts\Foundation\Application; |
|||
use Illuminate\Contracts\View\Factory; |
|||
use Illuminate\Http\JsonResponse; |
|||
use Illuminate\Http\RedirectResponse; |
|||
use Illuminate\Http\Request; |
|||
use Illuminate\Routing\Redirector; |
|||
use Illuminate\View\View; |
|||
use InvalidArgumentException; |
|||
use JsonException; |
|||
use Log; |
|||
use Str; |
|||
|
|||
/** |
|||
* Class TokenController |
|||
*/ |
|||
class TokenController extends Controller |
|||
{ |
|||
/** |
|||
* Start page where the user will always end up on. Will do either of 3 things: |
|||
* |
|||
* 1. All info is present. Set some cookies and continue. |
|||
* 2. Has client ID + URL. Will send user to Firefly III for permission. |
|||
* 3. Has either 1 of those. Will show user some input form. |
|||
* @param Request $request |
|||
* |
|||
* @return Application|Factory|RedirectResponse|Redirector|View |
|||
*/ |
|||
public function index(Request $request) |
|||
{ |
|||
$pageTitle = 'CSV importer'; |
|||
Log::debug(sprintf('Now at %s', __METHOD__)); |
|||
$configToken = (string) config('importer.access_token'); |
|||
$clientId = (int) config('importer.client_id'); |
|||
$baseURL = (string) config('importer.url'); |
|||
$vanityURL = $baseURL; |
|||
if ('' !== (string) config('importer.vanity_url')) { |
|||
$vanityURL = config('importer.vanity_url'); |
|||
} |
|||
|
|||
Log::info('The following configuration information was found:'); |
|||
Log::info(sprintf('Personal Access Token: "%s" (limited to 25 chars if present)', substr($configToken, 0, 25))); |
|||
Log::info(sprintf('Client ID : "%s"', $clientId)); |
|||
Log::info(sprintf('Base URL : "%s"', $baseURL)); |
|||
Log::info(sprintf('Vanity URL : "%s"', $vanityURL)); |
|||
|
|||
// Option 1: access token and url are present:
|
|||
if ('' !== $configToken && '' !== $baseURL) { |
|||
Log::debug(sprintf('Found personal access token + URL "%s" in config, set cookie and return to index.', $baseURL)); |
|||
|
|||
// set cookies.
|
|||
$cookies = [ |
|||
cookie('access_token', $configToken), |
|||
cookie('base_url', $baseURL), |
|||
cookie('vanity_url', $vanityURL), |
|||
cookie('refresh_token', ''), |
|||
]; |
|||
|
|||
return redirect(route('index'))->withCookies($cookies); |
|||
} |
|||
|
|||
// Option 2: client ID + base URL.
|
|||
if (0 !== $clientId && '' !== $baseURL) { |
|||
Log::debug(sprintf('Found client ID "%d" + URL "%s" in config, redirect to Firefly III for permission.', $clientId, $baseURL)); |
|||
return $this->redirectForPermission($request, $baseURL, $vanityURL, $clientId); |
|||
} |
|||
|
|||
// Option 3: either is empty, ask for client ID and/or base URL:
|
|||
$clientId = 0 === $clientId ? '' : $clientId; |
|||
|
|||
return view('token.client_id', compact('baseURL', 'clientId', 'pageTitle')); |
|||
} |
|||
|
|||
/** |
|||
* This method forwards the user to Firefly III. Some parameters are stored in the user's session. |
|||
* |
|||
* @param Request $request |
|||
* @param string $baseURL |
|||
* @param string $vanityURL |
|||
* @param int $clientId |
|||
* |
|||
* @return RedirectResponse |
|||
*/ |
|||
private function redirectForPermission(Request $request, string $baseURL, string $vanityURL, int $clientId): RedirectResponse |
|||
{ |
|||
$baseURL = rtrim($baseURL, '/'); |
|||
$vanityURL = rtrim($vanityURL, '/'); |
|||
|
|||
|
|||
Log::debug(sprintf('Now in %s(request, "%s", "%s", %d)', __METHOD__, $baseURL, $vanityURL, $clientId)); |
|||
$state = Str::random(40); |
|||
$codeVerifier = Str::random(128); |
|||
$request->session()->put('state', $state); |
|||
$request->session()->put('code_verifier', $codeVerifier); |
|||
$request->session()->put('form_client_id', $clientId); |
|||
$request->session()->put('form_base_url', $baseURL); |
|||
$request->session()->put('form_vanity_url', $vanityURL); |
|||
|
|||
$codeChallenge = strtr(rtrim(base64_encode(hash('sha256', $codeVerifier, true)), '='), '+/', '-_'); |
|||
$params = [ |
|||
'client_id' => $clientId, |
|||
'redirect_uri' => route('token.callback'), |
|||
'response_type' => 'code', |
|||
'scope' => '', |
|||
'state' => $state, |
|||
'code_challenge' => $codeChallenge, |
|||
'code_challenge_method' => 'S256', |
|||
]; |
|||
$query = http_build_query($params); |
|||
// we redirect the user to the vanity URL, which is the same as the base_url, unless the user actually set a vanity URL.
|
|||
$finalURL = sprintf('%s/oauth/authorize?', $vanityURL); |
|||
Log::debug('Query parameters are', $params); |
|||
Log::debug(sprintf('Now redirecting to "%s" (params omitted)', $finalURL)); |
|||
|
|||
return redirect($finalURL . $query); |
|||
} |
|||
|
|||
/** |
|||
* User submits the client ID + optionally the base URL. |
|||
* Whatever happens, we redirect the user to Firefly III and beg for permission. |
|||
* |
|||
* @param Request $request |
|||
* @return Application|RedirectResponse|Redirector |
|||
*/ |
|||
public function submitClientId(Request $request) |
|||
{ |
|||
Log::debug(sprintf('Now at %s', __METHOD__)); |
|||
$data = $request->validate( |
|||
[ |
|||
'client_id' => 'required|numeric|min:1|max:65536', |
|||
'base_url' => 'url', |
|||
] |
|||
); |
|||
Log::debug('Submitted data: ', $data); |
|||
|
|||
if (true === config('importer.expect_secure_url') && array_key_exists('base_url', $data) && !str_starts_with($data['base_url'], 'https://')) { |
|||
$request->session()->flash('secure_url', 'URL must start with https://'); |
|||
|
|||
return redirect(route('token.index')); |
|||
} |
|||
|
|||
$data['client_id'] = (int) $data['client_id']; |
|||
|
|||
// grab base URL from config first, otherwise from submitted data:
|
|||
$baseURL = config('importer.url'); |
|||
Log::debug(sprintf('Base URL is "%s"', $baseURL)); |
|||
$vanityURL = $baseURL; |
|||
|
|||
Log::debug(sprintf('Vanity URL is now "%s"', $vanityURL)); |
|||
|
|||
// if the config has a vanity URL it will always overrule.
|
|||
if ('' !== (string) config('importer.vanity_url')) { |
|||
$vanityURL = config('importer.vanity_url'); |
|||
Log::debug(sprintf('Vanity URL is now "%s"', $vanityURL)); |
|||
} |
|||
|
|||
// otherwise take base URL from the submitted data:
|
|||
if (array_key_exists('base_url', $data) && '' !== $data['base_url']) { |
|||
$baseURL = $data['base_url']; |
|||
Log::debug(sprintf('Base URL is now "%s"', $baseURL)); |
|||
} |
|||
if ('' === (string) $vanityURL) { |
|||
$vanityURL = $baseURL; |
|||
Log::debug(sprintf('Vanity URL is now "%s"', $vanityURL)); |
|||
} |
|||
|
|||
// return request for permission:
|
|||
return $this->redirectForPermission($request, $baseURL, $vanityURL, $data['client_id']); |
|||
} |
|||
|
|||
/** |
|||
* This method will check if Firefly III accepts the access_token from the cookie |
|||
* and the base URL (also from the cookie). The base_url is NEVER the vanity URL.§ |
|||
* |
|||
* @param Request $request |
|||
* @return JsonResponse |
|||
*/ |
|||
public function doValidate(Request $request): JsonResponse |
|||
{ |
|||
Log::debug(sprintf('Now at %s', __METHOD__)); |
|||
$response = ['result' => 'OK', 'message' => null]; |
|||
$url = (string) $request->cookie('base_url'); |
|||
$token = (string) $request->cookie('access_token'); |
|||
$request = new SystemInformationRequest($url, $token); |
|||
|
|||
$request->setVerify(config('importer.connection.verify')); |
|||
$request->setTimeOut(config('importer.connection.timeout')); |
|||
|
|||
try { |
|||
$result = $request->get(); |
|||
} catch (ApiHttpException $e) { |
|||
return response()->json(['result' => 'NOK', 'message' => $e->getMessage()]); |
|||
} |
|||
// -1 = OK (minimum is smaller)
|
|||
// 0 = OK (same version)
|
|||
// 1 = NOK (too low a version)
|
|||
|
|||
$minimum = (string) config('importer.minimum_version'); |
|||
$compare = version_compare($minimum, $result->version); |
|||
if (1 === $compare) { |
|||
$errorMessage = sprintf( |
|||
'Your Firefly III version %s is below the minimum required version %s', |
|||
$result->version, $minimum |
|||
); |
|||
$response = ['result' => 'NOK', 'message' => $errorMessage]; |
|||
} |
|||
|
|||
return response()->json($response); |
|||
} |
|||
|
|||
/** |
|||
* The user ends up here when they come back from Firefly III. |
|||
* |
|||
* @param Request $request |
|||
*/ |
|||
public function callback(Request $request) |
|||
{ |
|||
Log::debug(sprintf('Now at %s', __METHOD__)); |
|||
$state = (string) $request->session()->pull('state'); |
|||
$codeVerifier = (string) $request->session()->pull('code_verifier'); |
|||
$clientId = (int) $request->session()->pull('form_client_id'); |
|||
$baseURL = (string) $request->session()->pull('form_base_url'); |
|||
$vanityURL = (string) $request->session()->pull('form_vanity_url'); |
|||
$code = $request->get('code'); |
|||
|
|||
throw_unless( |
|||
strlen($state) > 0 && $state === $request->state, |
|||
InvalidArgumentException::class |
|||
); |
|||
// always POST to the base URL, never the vanity URL.
|
|||
$finalURL = sprintf('%s/oauth/token', $baseURL); |
|||
$params = [ |
|||
'form_params' => [ |
|||
'grant_type' => 'authorization_code', |
|||
'client_id' => $clientId, |
|||
'redirect_uri' => route('token.callback'), |
|||
'code_verifier' => $codeVerifier, |
|||
'code' => $code, |
|||
], |
|||
]; |
|||
Log::debug('State is valid!'); |
|||
Log::debug('Params for access token', $params); |
|||
Log::debug(sprintf('Will contact "%s" for a token.', $finalURL)); |
|||
|
|||
$opts = [ |
|||
'verify' => config('importer.connection.verify'), |
|||
'connect_timeout' => config('importer.connection.timeout'), |
|||
]; |
|||
try { |
|||
$response = (new Client($opts))->post($finalURL, $params); |
|||
} catch (ClientException $e) { |
|||
$body = (string) $e->getResponse()->getBody(); |
|||
Log::error(sprintf('Client exception when decoding response: %s', $e->getMessage())); |
|||
Log::error(sprintf('Response from server: "%s"', $body)); |
|||
Log::error($e->getTraceAsString()); |
|||
return view('error')->with('message', $e->getMessage())->with('body', $body); |
|||
} |
|||
|
|||
try { |
|||
$data = json_decode((string) $response->getBody(), true, 512, JSON_THROW_ON_ERROR); |
|||
} catch (JsonException $e) { |
|||
Log::error(sprintf('JSON exception when decoding response: %s', $e->getMessage())); |
|||
Log::error(sprintf('Response from server: "%s"', (string) $response->getBody())); |
|||
Log::error($e->getTraceAsString()); |
|||
throw new ApiException(sprintf('JSON exception when decoding response: %s', $e->getMessage())); |
|||
} |
|||
Log::debug('Response', $data); |
|||
|
|||
// set cookies.
|
|||
$cookies = [ |
|||
cookie('access_token', (string) $data['access_token']), |
|||
cookie('base_url', $baseURL), |
|||
cookie('vanity_url', $vanityURL), |
|||
cookie('refresh_token', (string) $data['refresh_token']), |
|||
]; |
|||
Log::debug(sprintf('Return redirect with cookies to "%s"', route('index'))); |
|||
|
|||
return redirect(route('index'))->withCookies($cookies); |
|||
} |
|||
} |
@ -0,0 +1,116 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* Kernel.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http; |
|||
|
|||
use App\Http\Middleware\Authenticate; |
|||
use App\Http\Middleware\CheckForMaintenanceMode; |
|||
use App\Http\Middleware\EncryptCookies; |
|||
use App\Http\Middleware\RedirectIfAuthenticated; |
|||
use App\Http\Middleware\TrimStrings; |
|||
use App\Http\Middleware\TrustProxies; |
|||
use App\Http\Middleware\VerifyCsrfToken; |
|||
use Fruitcake\Cors\HandleCors; |
|||
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth; |
|||
use Illuminate\Auth\Middleware\Authorize; |
|||
use Illuminate\Auth\Middleware\EnsureEmailIsVerified; |
|||
use Illuminate\Auth\Middleware\RequirePassword; |
|||
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; |
|||
use Illuminate\Foundation\Http\Kernel as HttpKernel; |
|||
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull; |
|||
use Illuminate\Foundation\Http\Middleware\ValidatePostSize; |
|||
use Illuminate\Http\Middleware\SetCacheHeaders; |
|||
use Illuminate\Routing\Middleware\SubstituteBindings; |
|||
use Illuminate\Routing\Middleware\ThrottleRequests; |
|||
use Illuminate\Routing\Middleware\ValidateSignature; |
|||
use Illuminate\Session\Middleware\StartSession; |
|||
use Illuminate\View\Middleware\ShareErrorsFromSession; |
|||
|
|||
/** |
|||
* Class Kernel |
|||
*/ |
|||
class Kernel extends HttpKernel |
|||
{ |
|||
/** |
|||
* The application's global HTTP middleware stack. |
|||
* |
|||
* These middleware are run during every request to your application. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $middleware |
|||
= [ |
|||
TrustProxies::class, |
|||
HandleCors::class, |
|||
CheckForMaintenanceMode::class, |
|||
ValidatePostSize::class, |
|||
TrimStrings::class, |
|||
ConvertEmptyStringsToNull::class, |
|||
]; |
|||
|
|||
/** |
|||
* The application's route middleware groups. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $middlewareGroups |
|||
= [ |
|||
'web' => [ |
|||
EncryptCookies::class, |
|||
AddQueuedCookiesToResponse::class, |
|||
StartSession::class, |
|||
// \Illuminate\Session\Middleware\AuthenticateSession::class,
|
|||
ShareErrorsFromSession::class, |
|||
VerifyCsrfToken::class, |
|||
SubstituteBindings::class, |
|||
], |
|||
|
|||
'api' => [ |
|||
'throttle:60,1', |
|||
SubstituteBindings::class, |
|||
], |
|||
]; |
|||
|
|||
/** |
|||
* The application's route middleware. |
|||
* |
|||
* These middleware may be assigned to groups or used individually. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $routeMiddleware |
|||
= [ |
|||
'auth' => Authenticate::class, |
|||
'auth.basic' => AuthenticateWithBasicAuth::class, |
|||
'bindings' => SubstituteBindings::class, |
|||
'cache.headers' => SetCacheHeaders::class, |
|||
'can' => Authorize::class, |
|||
'guest' => RedirectIfAuthenticated::class, |
|||
'password.confirm' => RequirePassword::class, |
|||
'signed' => ValidateSignature::class, |
|||
'throttle' => ThrottleRequests::class, |
|||
'verified' => EnsureEmailIsVerified::class, |
|||
]; |
|||
} |
@ -0,0 +1,49 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* Authenticate.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Middleware; |
|||
|
|||
use Illuminate\Auth\Middleware\Authenticate as Middleware; |
|||
use Illuminate\Http\Request; |
|||
|
|||
/** |
|||
* Class Authenticate |
|||
*/ |
|||
class Authenticate extends Middleware |
|||
{ |
|||
/** |
|||
* Get the path the user should be redirected to when they are not authenticated. |
|||
* |
|||
* @param Request $request |
|||
* @return string|null |
|||
*/ |
|||
protected function redirectTo($request) |
|||
{ |
|||
if (!$request->expectsJson()) { |
|||
return route('login'); |
|||
} |
|||
return null; |
|||
} |
|||
} |
@ -0,0 +1,43 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* CheckForMaintenanceMode.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Middleware; |
|||
|
|||
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware; |
|||
|
|||
/** |
|||
* Class CheckForMaintenanceMode |
|||
*/ |
|||
class CheckForMaintenanceMode extends Middleware |
|||
{ |
|||
/** |
|||
* The URIs that should be reachable while maintenance mode is enabled. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $except = [ |
|||
//
|
|||
]; |
|||
} |
@ -0,0 +1,52 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* ConfigComplete.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Middleware; |
|||
|
|||
use App\Services\Session\Constants; |
|||
use Closure; |
|||
use Illuminate\Http\Request; |
|||
|
|||
/** |
|||
* Class ConfigComplete |
|||
*/ |
|||
class ConfigComplete |
|||
{ |
|||
/** |
|||
* Check if the user has already uploaded files in this session. If so, continue to configuration. |
|||
* |
|||
* @param Request $request |
|||
* @param Closure $next |
|||
* |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function handle(Request $request, Closure $next) |
|||
{ |
|||
if (session()->has(Constants::CONFIG_COMPLETE_INDICATOR) && true === session()->get(Constants::CONFIG_COMPLETE_INDICATOR)) { |
|||
return redirect()->route('import.roles.index'); |
|||
} |
|||
|
|||
return $next($request); |
|||
} |
|||
} |
@ -0,0 +1,43 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* EncryptCookies.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Middleware; |
|||
|
|||
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware; |
|||
|
|||
/** |
|||
* Class EncryptCookies |
|||
*/ |
|||
class EncryptCookies extends Middleware |
|||
{ |
|||
/** |
|||
* The names of the cookies that should not be encrypted. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $except = [ |
|||
//
|
|||
]; |
|||
} |
@ -0,0 +1,52 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* MappingComplete.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Middleware; |
|||
|
|||
use App\Services\Session\Constants; |
|||
use Closure; |
|||
use Illuminate\Http\Request; |
|||
|
|||
/** |
|||
* Class MappingComplete |
|||
*/ |
|||
class MappingComplete |
|||
{ |
|||
/** |
|||
* Check if the user has already set the mapping in this session. If so, continue to configuration. |
|||
* |
|||
* @param Request $request |
|||
* @param Closure $next |
|||
* |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function handle(Request $request, Closure $next) |
|||
{ |
|||
if (session()->has(Constants::MAPPING_COMPLETE_INDICATOR) && true === session()->get(Constants::MAPPING_COMPLETE_INDICATOR)) { |
|||
return redirect()->route('import.run.index'); |
|||
} |
|||
|
|||
return $next($request); |
|||
} |
|||
} |
@ -0,0 +1,53 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* ReadyForImport.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Middleware; |
|||
|
|||
use App\Services\Session\Constants; |
|||
use Closure; |
|||
use Illuminate\Http\Request; |
|||
|
|||
/** |
|||
* Class ReadyForImport |
|||
*/ |
|||
class ReadyForImport |
|||
{ |
|||
/** |
|||
* Check if the user has already set the mapping in this session. If so, continue to configuration. |
|||
* |
|||
* @param Request $request |
|||
* @param Closure $next |
|||
* |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function handle(Request $request, Closure $next) |
|||
{ |
|||
if (session()->has(Constants::MAPPING_COMPLETE_INDICATOR) && true === session()->get(Constants::MAPPING_COMPLETE_INDICATOR)) { |
|||
return $next($request); |
|||
} |
|||
|
|||
echo 'Import is not yet ready.'; |
|||
exit; |
|||
} |
|||
} |
@ -0,0 +1,54 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* RedirectIfAuthenticated.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Middleware; |
|||
|
|||
use App\Providers\RouteServiceProvider; |
|||
use Closure; |
|||
use Illuminate\Http\Request; |
|||
use Illuminate\Support\Facades\Auth; |
|||
|
|||
/** |
|||
* Class RedirectIfAuthenticated |
|||
*/ |
|||
class RedirectIfAuthenticated |
|||
{ |
|||
/** |
|||
* Handle an incoming request. |
|||
* |
|||
* @param Request $request |
|||
* @param Closure $next |
|||
* @param string|null $guard |
|||
* @return mixed |
|||
*/ |
|||
public function handle($request, Closure $next, $guard = null) |
|||
{ |
|||
if (Auth::guard($guard)->check()) { |
|||
return redirect(RouteServiceProvider::HOME); |
|||
} |
|||
|
|||
return $next($request); |
|||
} |
|||
} |
@ -0,0 +1,52 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* RolesComplete.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Middleware; |
|||
|
|||
use App\Services\Session\Constants; |
|||
use Closure; |
|||
use Illuminate\Http\Request; |
|||
|
|||
/** |
|||
* Class RolesComplete |
|||
*/ |
|||
class RolesComplete |
|||
{ |
|||
/** |
|||
* Check if the user has already uploaded files in this session. If so, continue to configuration. |
|||
* |
|||
* @param Request $request |
|||
* @param Closure $next |
|||
* |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function handle(Request $request, Closure $next) |
|||
{ |
|||
if (session()->has(Constants::ROLES_COMPLETE_INDICATOR) && true === session()->get(Constants::ROLES_COMPLETE_INDICATOR)) { |
|||
return redirect()->route('import.mapping.index'); |
|||
} |
|||
|
|||
return $next($request); |
|||
} |
|||
} |
@ -0,0 +1,44 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* TrimStrings.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Middleware; |
|||
|
|||
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware; |
|||
|
|||
/** |
|||
* Class TrimStrings |
|||
*/ |
|||
class TrimStrings extends Middleware |
|||
{ |
|||
/** |
|||
* The names of the attributes that should not be trimmed. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $except = [ |
|||
'password', |
|||
'password_confirmation', |
|||
]; |
|||
} |
@ -0,0 +1,65 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* TrustProxies.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Middleware; |
|||
|
|||
use Fideloper\Proxy\TrustProxies as Middleware; |
|||
use Illuminate\Contracts\Config\Repository; |
|||
use Illuminate\Http\Request; |
|||
|
|||
/** |
|||
* Class TrustProxies |
|||
*/ |
|||
class TrustProxies extends Middleware |
|||
{ |
|||
/** |
|||
* The trusted proxies for this application. |
|||
* |
|||
* @var array|string |
|||
*/ |
|||
protected $proxies; |
|||
|
|||
/** |
|||
* The headers that should be used to detect proxies. |
|||
* |
|||
* @var int |
|||
*/ |
|||
protected $headers = Request::HEADER_X_FORWARDED_ALL; |
|||
|
|||
/** |
|||
* TrustProxies constructor. |
|||
* |
|||
* @param Repository $config |
|||
*/ |
|||
public function __construct(Repository $config) |
|||
{ |
|||
$trustedProxies = (string) config('csv_importer.trusted_proxies'); |
|||
$this->proxies = explode(',', $trustedProxies); |
|||
if ('**' === $trustedProxies) { |
|||
$this->proxies = '**'; |
|||
} |
|||
parent::__construct($config); |
|||
} |
|||
} |
@ -0,0 +1,53 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* UploadedFiles.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Middleware; |
|||
|
|||
use App\Services\Session\Constants; |
|||
use Closure; |
|||
use Illuminate\Http\Request; |
|||
|
|||
/** |
|||
* Class UploadedFiles |
|||
*/ |
|||
class UploadedFiles |
|||
{ |
|||
/** |
|||
* Check if the user has already uploaded files in this session. If so, continue to configuration. |
|||
* |
|||
* @param Request $request |
|||
* @param Closure $next |
|||
* |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function handle(Request $request, Closure $next) |
|||
{ |
|||
|
|||
if (session()->has(Constants::HAS_UPLOAD)) { |
|||
return redirect()->route('import.configure.index'); |
|||
} |
|||
|
|||
return $next($request); |
|||
} |
|||
} |
@ -0,0 +1,43 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* VerifyCsrfToken.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Middleware; |
|||
|
|||
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware; |
|||
|
|||
/** |
|||
* Class VerifyCsrfToken |
|||
*/ |
|||
class VerifyCsrfToken extends Middleware |
|||
{ |
|||
/** |
|||
* The URIs that should be excluded from CSRF verification. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $except = [ |
|||
'autoimport', 'autoupload', |
|||
]; |
|||
} |
@ -0,0 +1,31 @@ |
|||
<?php |
|||
|
|||
|
|||
namespace App\Http\Request; |
|||
|
|||
|
|||
class AutoUploadRequest extends Request |
|||
{ |
|||
/** |
|||
* Verify the request. |
|||
* |
|||
* @return bool |
|||
*/ |
|||
public function authorize(): bool |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* @return array |
|||
*/ |
|||
public function rules(): array |
|||
{ |
|||
return [ |
|||
'csv' => 'required|file', |
|||
'json' => 'required|file', |
|||
]; |
|||
|
|||
} |
|||
} |
@ -0,0 +1,149 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* ConfigurationPostRequest.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Request; |
|||
|
|||
|
|||
use App\Services\CSV\Specifics\SpecificService; |
|||
use JsonException; |
|||
use Log; |
|||
|
|||
/** |
|||
* Class ConfigurationPostRequest |
|||
*/ |
|||
class ConfigurationPostRequest extends Request |
|||
{ |
|||
/** |
|||
* Verify the request. |
|||
* |
|||
* @return bool |
|||
*/ |
|||
public function authorize(): bool |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* @return array |
|||
*/ |
|||
public function getAll(): array |
|||
{ |
|||
try { |
|||
$roles = $this->get('roles') ? |
|||
json_decode(base64_decode($this->get('roles')), true, 512, JSON_THROW_ON_ERROR) : null; |
|||
} catch (JsonException $e) { |
|||
Log::warning( |
|||
sprintf( |
|||
'Could not decode roles JSON "%s" ("%s") but this is not a problem.', |
|||
$this->get('roles'), |
|||
$e->getMessage() |
|||
) |
|||
); |
|||
$roles = []; |
|||
} |
|||
try { |
|||
$mapping = $this->get('mapping') ? |
|||
json_decode(base64_decode($this->get('mapping')), true, 512, JSON_THROW_ON_ERROR) : null; |
|||
} catch (JsonException $e) { |
|||
Log::warning( |
|||
sprintf( |
|||
'Could not decode mapping JSON "%s" ("%s") but this is not a problem.', |
|||
$this->get('mapping'), |
|||
$e->getMessage() |
|||
) |
|||
); |
|||
$mapping = []; |
|||
} |
|||
try { |
|||
$doMapping = $this->get('do_mapping') ? |
|||
json_decode(base64_decode($this->get('do_mapping')), true, 512, JSON_THROW_ON_ERROR) : null; |
|||
} catch (JsonException $e) { |
|||
Log::warning( |
|||
sprintf( |
|||
'Could not decode doMapping JSON "%s" ("%s") but this is not a problem.', |
|||
$this->get('do_mapping'), |
|||
$e->getMessage() |
|||
) |
|||
); |
|||
$doMapping = []; |
|||
} |
|||
|
|||
$result = [ |
|||
'headers' => $this->convertBoolean($this->get('headers')), |
|||
'delimiter' => $this->string('delimiter'), |
|||
'date' => $this->string('date'), |
|||
'default_account' => $this->integer('default_account'), |
|||
'rules' => $this->convertBoolean($this->get('rules')), |
|||
'ignore_duplicate_lines' => $this->convertBoolean($this->get('ignore_duplicate_lines')), |
|||
'ignore_duplicate_transactions' => $this->convertBoolean($this->get('ignore_duplicate_transactions')), |
|||
'skip_form' => $this->convertBoolean($this->get('skip_form')), |
|||
'add_import_tag' => $this->convertBoolean($this->get('add_import_tag')), |
|||
'specifics' => [], |
|||
'roles' => $roles, |
|||
'mapping' => $mapping, |
|||
'do_mapping' => $doMapping, |
|||
// duplicate detection:
|
|||
'duplicate_detection_method' => $this->string('duplicate_detection_method'), |
|||
'unique_column_index' => $this->integer('unique_column_index'), |
|||
'unique_column_type' => $this->string('unique_column_type'), |
|||
]; |
|||
// rules for specifics:
|
|||
$specifics = SpecificService::getSpecifics(); |
|||
foreach (array_keys($specifics) as $specific) { |
|||
$result['specifics'][$specific] = $this->convertBoolean($this->get(sprintf('specific_%s', $specific))); |
|||
} |
|||
|
|||
return $result; |
|||
} |
|||
|
|||
/** |
|||
* @return array |
|||
*/ |
|||
public function rules(): array |
|||
{ |
|||
$rules = [ |
|||
//'some_weird_field' => 'required',
|
|||
'headers' => 'numeric|between:0,1', |
|||
'delimiter' => 'required|in:comma,semicolon,tab', |
|||
'date' => 'required|between:1,15', |
|||
'default_account' => 'required|numeric|min:1|max:100000', |
|||
'rules' => 'numeric|between:0,1', |
|||
'ignore_duplicate_lines' => 'numeric|between:0,1', |
|||
'ignore_duplicate_transactions' => 'numeric|between:0,1', |
|||
'skip_form' => 'numeric|between:0,1', |
|||
'add_import_tag' => 'numeric|between:0,1', |
|||
|
|||
// duplicate detection:
|
|||
'duplicate_detection_method' => 'required|in:cell,none,classic', |
|||
'unique_column_index' => 'numeric', |
|||
'unique_column_type' => sprintf('required|in:%s', join(',', array_keys(config('csv_importer.unique_column_options')))), |
|||
]; |
|||
// rules for specifics:
|
|||
$specifics = SpecificService::getSpecifics(); |
|||
foreach (array_keys($specifics) as $specific) { |
|||
$rules[sprintf('specific_%s', $specific)] = 'numeric|between:0,1'; |
|||
} |
|||
|
|||
return $rules; |
|||
} |
|||
} |
@ -0,0 +1,190 @@ |
|||
<?php |
|||
/** |
|||
* Request.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
*/ |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Http\Request; |
|||
|
|||
use Carbon\Carbon; |
|||
use Exception; |
|||
use Illuminate\Foundation\Http\FormRequest; |
|||
use Log; |
|||
|
|||
/** |
|||
* Class Request. |
|||
* |
|||
* @codeCoverageIgnore |
|||
* |
|||
*/ |
|||
class Request extends FormRequest |
|||
{ |
|||
/** |
|||
* @param string $value |
|||
* |
|||
* @return bool |
|||
*/ |
|||
public function convertBoolean(?string $value): bool |
|||
{ |
|||
if (null === $value) { |
|||
return false; |
|||
} |
|||
if (in_array(trim($value), ['true', 'yes', '1'], true)) { |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* Return floating value. |
|||
* |
|||
* @param string $field |
|||
* |
|||
* @return float|null |
|||
*/ |
|||
public function float(string $field): ?float |
|||
{ |
|||
$res = $this->get($field); |
|||
if (null === $res) { |
|||
return null; |
|||
} |
|||
|
|||
return (float) $res; |
|||
} |
|||
|
|||
/** |
|||
* Return integer value. |
|||
* |
|||
* @param string $field |
|||
* |
|||
* @return int |
|||
*/ |
|||
public function integer(string $field): int |
|||
{ |
|||
return (int) $this->get($field); |
|||
} |
|||
|
|||
/** |
|||
* Parse to integer |
|||
* |
|||
* @param string|null $string |
|||
* |
|||
* @return int|null |
|||
*/ |
|||
public function integerFromValue(?string $string): ?int |
|||
{ |
|||
if (null === $string) { |
|||
return null; |
|||
} |
|||
if ('' === $string) { |
|||
return null; |
|||
} |
|||
|
|||
return (int) $string; |
|||
} |
|||
|
|||
/** |
|||
* Return integer value, or NULL when it's not set. |
|||
* |
|||
* @param string $field |
|||
* |
|||
* @return int|null |
|||
*/ |
|||
public function nullableInteger(string $field): ?int |
|||
{ |
|||
if (!$this->has($field)) { |
|||
return null; |
|||
} |
|||
|
|||
$value = (string) $this->get($field); |
|||
if ('' === $value) { |
|||
return null; |
|||
} |
|||
|
|||
return (int) $value; |
|||
} |
|||
|
|||
/** |
|||
* Return string value, or NULL if empty. |
|||
* |
|||
* @param string $field |
|||
* |
|||
* @return string|null |
|||
*/ |
|||
public function nullableString(string $field): ?string |
|||
{ |
|||
if (!$this->has($field)) { |
|||
return null; |
|||
} |
|||
|
|||
return app('steam')->cleanStringAndNewlines((string) ($this->get($field) ?? '')); |
|||
} |
|||
|
|||
/** |
|||
* Return string value. |
|||
* |
|||
* @param string $field |
|||
* |
|||
* @return string |
|||
*/ |
|||
public function string(string $field): string |
|||
{ |
|||
return app('steam')->cleanStringAndNewlines((string) ($this->get($field) ?? '')); |
|||
} |
|||
|
|||
/** |
|||
* Parse and clean a string. |
|||
* |
|||
* @param string|null $string |
|||
* |
|||
* @return string|null |
|||
*/ |
|||
public function stringFromValue(?string $string): ?string |
|||
{ |
|||
if (null === $string) { |
|||
return null; |
|||
} |
|||
$result = app('steam')->cleanStringAndNewlines($string); |
|||
|
|||
return '' === $result ? null : $result; |
|||
|
|||
} |
|||
|
|||
/** |
|||
* Return date or NULL. |
|||
* |
|||
* @param string $field |
|||
* |
|||
* @return Carbon|null |
|||
*/ |
|||
protected function date(string $field): ?Carbon |
|||
{ |
|||
$result = null; |
|||
try { |
|||
$result = $this->get($field) ? new Carbon($this->get($field)) : null; |
|||
} catch (Exception $e) { |
|||
Log::debug(sprintf('Exception when parsing date. Not interesting: %s', $e->getMessage())); |
|||
} |
|||
|
|||
return $result; |
|||
} |
|||
} |
@ -0,0 +1,111 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* RolesPostRequest.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Http\Request; |
|||
|
|||
|
|||
use Illuminate\Validation\Validator; |
|||
|
|||
/** |
|||
* Class RolesPostRequest |
|||
*/ |
|||
class RolesPostRequest extends Request |
|||
{ |
|||
|
|||
/** |
|||
* Verify the request. |
|||
* |
|||
* @return bool |
|||
*/ |
|||
public function authorize(): bool |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* @return array |
|||
*/ |
|||
public function getAll(): array |
|||
{ |
|||
$data = [ |
|||
'roles' => $this->get('roles') ?? [], |
|||
'do_mapping' => $this->get('do_mapping') ?? [], |
|||
]; |
|||
foreach (array_keys($data['roles']) as $index) { |
|||
|
|||
$data['do_mapping'][$index] = $this->convertBoolean($data['do_mapping'][$index] ?? 'false'); |
|||
} |
|||
|
|||
return $data; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* @return array |
|||
*/ |
|||
public function rules(): array |
|||
{ |
|||
$keys = implode(',', array_keys(config('csv_importer.import_roles'))); |
|||
|
|||
return [ |
|||
'roles.*' => sprintf('required|in:%s', $keys), |
|||
'do_mapping.*' => 'numeric|between:0,1', |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* Configure the validator instance with special rules for after the basic validation rules. |
|||
* |
|||
* @param Validator $validator |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function withValidator(Validator $validator): void |
|||
{ |
|||
$validator->after( |
|||
function (Validator $validator) { |
|||
// validate all account info
|
|||
$this->validateAmountRole($validator); |
|||
} |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* @param Validator $validator |
|||
*/ |
|||
protected function validateAmountRole(Validator $validator): void |
|||
{ |
|||
$data = $validator->getData(); |
|||
$roles = $data['roles'] ?? []; |
|||
$count = 0; |
|||
foreach ($roles as $role) { |
|||
if (in_array($role, ['amount', 'amount_negated', 'amount_debit', 'amount_credit'], true)) { |
|||
$count++; |
|||
} |
|||
} |
|||
if (0 === $count) { |
|||
$validator->errors()->add('roles.0', 'The import will fail if no column is assigned an "Amount"-role.'); |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,49 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Mail; |
|||
|
|||
use Illuminate\Bus\Queueable; |
|||
use Illuminate\Mail\Mailable; |
|||
use Illuminate\Queue\SerializesModels; |
|||
|
|||
/** |
|||
* Class ImportFinished |
|||
*/ |
|||
class ImportFinished extends Mailable |
|||
{ |
|||
use Queueable, SerializesModels; |
|||
|
|||
public $time; |
|||
public $errors; |
|||
public $warnings; |
|||
public $messages; |
|||
public $url; |
|||
|
|||
/** |
|||
* Create a new message instance. |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function __construct(array $log) |
|||
{ |
|||
$this->time = date('Y-m-d \@ H:i:s'); |
|||
$this->url = config('csv_importer.url'); |
|||
$this->errors = $log['errors'] ?? []; |
|||
$this->warnings = $log['warnings'] ?? []; |
|||
$this->messages = $log['messages'] ?? []; |
|||
} |
|||
|
|||
/** |
|||
* Build the message. |
|||
* |
|||
* @return $this |
|||
*/ |
|||
public function build() |
|||
{ |
|||
$address = (string) config('mail.from.address'); |
|||
$name = (string) config('mail.from.name'); |
|||
|
|||
return $this->from($address, $name)->markdown('emails.import.finished'); |
|||
} |
|||
} |
@ -0,0 +1,60 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* AppServiceProvider.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Providers; |
|||
|
|||
use App\Support\Steam; |
|||
use Illuminate\Support\ServiceProvider; |
|||
|
|||
/** |
|||
* Class AppServiceProvider |
|||
*/ |
|||
class AppServiceProvider extends ServiceProvider |
|||
{ |
|||
/** |
|||
* Register any application services. |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function register(): void |
|||
{ |
|||
$this->app->bind( |
|||
'steam', |
|||
static function () { |
|||
return new Steam; |
|||
} |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* Bootstrap any application services. |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function boot(): void |
|||
{ |
|||
//
|
|||
} |
|||
} |
@ -0,0 +1,56 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* AuthServiceProvider.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Providers; |
|||
|
|||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; |
|||
|
|||
|
|||
/** |
|||
* Class AuthServiceProvider |
|||
*/ |
|||
class AuthServiceProvider extends ServiceProvider |
|||
{ |
|||
/** |
|||
* The policy mappings for the application. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $policies = [ |
|||
// 'App\Model' => 'App\Policies\ModelPolicy',
|
|||
]; |
|||
|
|||
/** |
|||
* Register any authentication / authorization services. |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function boot(): void |
|||
{ |
|||
$this->registerPolicies(); |
|||
|
|||
//
|
|||
} |
|||
} |
@ -0,0 +1,47 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* BroadcastServiceProvider.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Providers; |
|||
|
|||
use Illuminate\Support\Facades\Broadcast; |
|||
use Illuminate\Support\ServiceProvider; |
|||
|
|||
/** |
|||
* Class BroadcastServiceProvider |
|||
*/ |
|||
class BroadcastServiceProvider extends ServiceProvider |
|||
{ |
|||
/** |
|||
* Bootstrap any application services. |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function boot(): void |
|||
{ |
|||
Broadcast::routes(); |
|||
|
|||
require base_path('routes/channels.php'); |
|||
} |
|||
} |
@ -0,0 +1,48 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* EventServiceProvider.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Providers; |
|||
|
|||
use Illuminate\Auth\Events\Registered; |
|||
use Illuminate\Auth\Listeners\SendEmailVerificationNotification; |
|||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; |
|||
|
|||
/** |
|||
* Class EventServiceProvider |
|||
*/ |
|||
class EventServiceProvider extends ServiceProvider |
|||
{ |
|||
/** |
|||
* The event listener mappings for the application. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $listen = [ |
|||
Registered::class => [ |
|||
SendEmailVerificationNotification::class, |
|||
], |
|||
]; |
|||
|
|||
} |
@ -0,0 +1,93 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
|
|||
|
|||
/** |
|||
* RouteServiceProvider.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Providers; |
|||
|
|||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; |
|||
use Illuminate\Support\Facades\Route; |
|||
|
|||
/** |
|||
* Class RouteServiceProvider |
|||
*/ |
|||
class RouteServiceProvider extends ServiceProvider |
|||
{ |
|||
/** |
|||
* The path to the "home" route for your application. |
|||
* |
|||
* @var string |
|||
*/ |
|||
public const HOME = '/home'; |
|||
/** |
|||
* This namespace is applied to your controller routes. |
|||
* |
|||
* In addition, it is set as the URL generator's root namespace. |
|||
* |
|||
* @var string |
|||
*/ |
|||
protected $namespace = 'App\Http\Controllers'; |
|||
|
|||
/** |
|||
* Define the routes for the application. |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function map(): void |
|||
{ |
|||
$this->mapApiRoutes(); |
|||
|
|||
$this->mapWebRoutes(); |
|||
|
|||
//
|
|||
} |
|||
|
|||
/** |
|||
* Define the "api" routes for the application. |
|||
* |
|||
* These routes are typically stateless. |
|||
* |
|||
* @return void |
|||
*/ |
|||
protected function mapApiRoutes(): void |
|||
{ |
|||
Route::prefix('api') |
|||
->middleware('api') |
|||
->namespace($this->namespace) |
|||
->group(base_path('routes/api.php')); |
|||
} |
|||
|
|||
/** |
|||
* Define the "web" routes for the application. |
|||
* |
|||
* These routes all receive session state, CSRF protection, etc. |
|||
* |
|||
* @return void |
|||
*/ |
|||
protected function mapWebRoutes(): void |
|||
{ |
|||
Route::middleware('web') |
|||
->namespace($this->namespace) |
|||
->group(base_path('routes/web.php')); |
|||
} |
|||
} |
@ -0,0 +1,66 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* ConfigFileProcessor.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Configuration; |
|||
|
|||
|
|||
use App\Exceptions\ImportException; |
|||
use App\Services\Storage\StorageService; |
|||
use Illuminate\Contracts\Filesystem\FileNotFoundException; |
|||
use JsonException; |
|||
use Log; |
|||
|
|||
/** |
|||
* Class ConfigFileProcessor |
|||
*/ |
|||
class ConfigFileProcessor |
|||
{ |
|||
/** |
|||
* Input (the content of) a configuration file and this little script will convert it to a compatible array. |
|||
* |
|||
* @param string $fileName |
|||
* |
|||
* @return Configuration |
|||
* @throws ImportException |
|||
*/ |
|||
public static function convertConfigFile(string $fileName): Configuration |
|||
{ |
|||
Log::debug('Now in ConfigFileProcessor::convertConfigFile'); |
|||
try { |
|||
$content = StorageService::getContent($fileName); |
|||
} catch (FileNotFoundException $e) { |
|||
Log::error($e->getMessage()); |
|||
throw new ImportException(sprintf('Cpuld not find config file: %s', $e->getMessage())); |
|||
} |
|||
try { |
|||
$json = json_decode($content, true, 512, JSON_THROW_ON_ERROR); |
|||
} catch (JsonException $e) { |
|||
Log::error($e->getMessage()); |
|||
throw new ImportException(sprintf('Invalid JSON configuration file: %s', $e->getMessage())); |
|||
} |
|||
|
|||
return Configuration::fromFile($json); |
|||
|
|||
} |
|||
|
|||
} |
@ -0,0 +1,545 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* Configuration.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Configuration; |
|||
|
|||
use App\Services\CSV\Specifics\SpecificService; |
|||
use Log; |
|||
use UnexpectedValueException; |
|||
|
|||
/** |
|||
* Class Configuration |
|||
*/ |
|||
class Configuration |
|||
{ |
|||
/** @var int */ |
|||
public const VERSION = 2; |
|||
private string $date; |
|||
private int $defaultAccount; |
|||
private string $delimiter; |
|||
private bool $headers; |
|||
private bool $rules; |
|||
private bool $skipForm; |
|||
private array $specifics; |
|||
private array $roles; |
|||
private int $version; |
|||
private array $doMapping; |
|||
private bool $addImportTag; |
|||
|
|||
// how to do double transaction detection?
|
|||
private array $mapping; // 'classic' or 'cell'
|
|||
|
|||
// configuration for "classic" method:
|
|||
private string $duplicateDetectionMethod; |
|||
private bool $ignoreDuplicateTransactions; |
|||
|
|||
// configuration for "cell" method:
|
|||
private bool $ignoreDuplicateLines; |
|||
private int $uniqueColumnIndex; |
|||
private string $uniqueColumnType; |
|||
|
|||
/** |
|||
* Configuration constructor. |
|||
*/ |
|||
private function __construct() |
|||
{ |
|||
$this->date = 'Y-m-d'; |
|||
$this->defaultAccount = 1; |
|||
$this->delimiter = 'comma'; |
|||
$this->headers = false; |
|||
$this->rules = true; |
|||
$this->skipForm = false; |
|||
$this->addImportTag = true; |
|||
$this->specifics = []; |
|||
$this->roles = []; |
|||
$this->mapping = []; |
|||
$this->doMapping = []; |
|||
|
|||
// double transaction detection:
|
|||
$this->duplicateDetectionMethod = 'classic'; |
|||
|
|||
// config for "classic":
|
|||
$this->ignoreDuplicateTransactions = true; |
|||
$this->ignoreDuplicateLines = true; |
|||
|
|||
// config for "cell":
|
|||
$this->uniqueColumnIndex = 0; |
|||
$this->uniqueColumnType = 'internal_reference'; |
|||
|
|||
$this->version = self::VERSION; |
|||
} |
|||
|
|||
/** |
|||
* Create a standard empty configuration. |
|||
* |
|||
* @return static |
|||
*/ |
|||
public static function make(): self |
|||
{ |
|||
return new self; |
|||
} |
|||
|
|||
/** |
|||
* @param array $array |
|||
* |
|||
* @return $this |
|||
*/ |
|||
public static function fromRequest(array $array): self |
|||
{ |
|||
$delimiters = config('csv_importer.delimiters_reversed'); |
|||
$object = new self; |
|||
$object->version = self::VERSION; |
|||
$object->headers = $array['headers']; |
|||
$object->date = $array['date']; |
|||
$object->defaultAccount = $array['default_account']; |
|||
$object->delimiter = $delimiters[$array['delimiter']] ?? 'comma'; |
|||
$object->rules = $array['rules']; |
|||
$object->skipForm = $array['skip_form']; |
|||
$object->addImportTag = $array['add_import_tag'] ?? true; |
|||
$object->roles = $array['roles'] ?? []; |
|||
$object->mapping = $array['mapping'] ?? []; |
|||
$object->doMapping = $array['do_mapping'] ?? []; |
|||
|
|||
// duplicate transaction detection
|
|||
$object->duplicateDetectionMethod = $array['duplicate_detection_method'] ?? 'classic'; |
|||
|
|||
// config for "classic":
|
|||
$object->ignoreDuplicateLines = $array['ignore_duplicate_lines']; |
|||
$object->ignoreDuplicateTransactions = true; |
|||
|
|||
// config for "cell":
|
|||
$object->uniqueColumnIndex = $array['unique_column_index'] ?? 0; |
|||
$object->uniqueColumnType = $array['unique_column_type'] ?? ''; |
|||
|
|||
// overrule a setting:
|
|||
if ('none' === $object->duplicateDetectionMethod) { |
|||
$object->ignoreDuplicateTransactions = false; |
|||
} |
|||
|
|||
$object->specifics = []; |
|||
foreach ($array['specifics'] as $key => $enabled) { |
|||
if (true === $enabled) { |
|||
$object->specifics[] = $key; |
|||
} |
|||
} |
|||
|
|||
return $object; |
|||
} |
|||
|
|||
/** |
|||
* @param array $data |
|||
* |
|||
* @return $this |
|||
*/ |
|||
public static function fromFile(array $data): self |
|||
{ |
|||
Log::debug('Now in Configuration::fromFile. Data is omitted and will not be printed.'); |
|||
$version = $data['version'] ?? 1; |
|||
if (1 === $version) { |
|||
Log::debug('v1, going for classic.'); |
|||
|
|||
return self::fromClassicFile($data); |
|||
} |
|||
if (2 === $version) { |
|||
Log::debug('v2 config file!'); |
|||
|
|||
return self::fromVersionTwo($data); |
|||
} |
|||
throw new UnexpectedValueException(sprintf('Configuration file version "%s" cannot be parsed.', $version)); |
|||
} |
|||
|
|||
/** |
|||
* @param array $data |
|||
* |
|||
* @return static |
|||
*/ |
|||
private static function fromClassicFile(array $data): self |
|||
{ |
|||
$delimiters = config('csv_importer.delimiters_reversed'); |
|||
$classicRoleNames = config('csv_importer.classic_roles'); |
|||
$object = new self; |
|||
$object->headers = $data['has-headers'] ?? false; |
|||
$object->date = $data['date-format'] ?? $object->date; |
|||
$object->delimiter = $delimiters[$data['delimiter']] ?? 'comma'; |
|||
$object->defaultAccount = $data['import-account'] ?? $object->defaultAccount; |
|||
$object->rules = $data['apply-rules'] ?? true; |
|||
|
|||
$object->ignoreDuplicateTransactions = $data['ignore_duplicate_transactions'] ?? true; |
|||
|
|||
if (isset($data['ignore_duplicates']) && true === $data['ignore_duplicates']) { |
|||
Log::debug('Will ignore duplicates.'); |
|||
$object->ignoreDuplicateTransactions = true; |
|||
$object->duplicateDetectionMethod = 'classic'; |
|||
} |
|||
|
|||
if (isset($data['ignore_duplicates']) && false === $data['ignore_duplicates']) { |
|||
Log::debug('Will NOT ignore duplicates.'); |
|||
$object->ignoreDuplicateTransactions = false; |
|||
$object->duplicateDetectionMethod = 'none'; |
|||
} |
|||
|
|||
if (isset($data['ignore_lines']) && true === $data['ignore_lines']) { |
|||
Log::debug('Will ignore duplicate lines.'); |
|||
$object->ignoreDuplicateLines = true; |
|||
} |
|||
|
|||
// array values
|
|||
$object->specifics = []; |
|||
$object->roles = []; |
|||
$object->doMapping = []; |
|||
$object->mapping = []; |
|||
|
|||
// loop specifics from classic file:
|
|||
// Fix as suggested by @FelikZ in https://github.com/firefly-iii/csv-importer/pull/4
|
|||
$specifics = array_keys($data['specifics'] ?? []); |
|||
|
|||
foreach ($specifics as $name) { |
|||
$class = SpecificService::fullClass($name); |
|||
if (class_exists($class)) { |
|||
$object->specifics[] = $name; |
|||
} |
|||
} |
|||
|
|||
// loop roles from classic file:
|
|||
$roles = $data['column-roles'] ?? []; |
|||
foreach ($roles as $role) { |
|||
// some roles have been given a new name some time in the past.
|
|||
$role = $classicRoleNames[$role] ?? $role; |
|||
|
|||
$config = config(sprintf('csv_importer.import_roles.%s', $role)); |
|||
if (null !== $config) { |
|||
$object->roles[] = $role; |
|||
} |
|||
} |
|||
|
|||
// loop do mapping from classic file.
|
|||
$doMapping = $data['column-do-mapping'] ?? []; |
|||
foreach ($doMapping as $index => $map) { |
|||
$index = (int) $index; |
|||
$object->doMapping[$index] = $map; |
|||
} |
|||
|
|||
// loop mapping from classic file.
|
|||
$mapping = $data['column-mapping-config'] ?? []; |
|||
foreach ($mapping as $index => $map) { |
|||
$index = (int) $index; |
|||
$object->mapping[$index] = $map; |
|||
} |
|||
// set version to "2" and return.
|
|||
$object->version = 2; |
|||
|
|||
return $object; |
|||
} |
|||
|
|||
/** |
|||
* @param array $data |
|||
* |
|||
* @return static |
|||
*/ |
|||
private static function fromVersionTwo(array $data): self |
|||
{ |
|||
return self::fromArray($data); |
|||
} |
|||
|
|||
/** |
|||
* @param array $array |
|||
* |
|||
* @return static |
|||
*/ |
|||
public static function fromArray(array $array): self |
|||
{ |
|||
$version = $array['version'] ?? 1; |
|||
$delimiters = config('csv_importer.delimiters_reversed'); |
|||
$object = new self; |
|||
$object->headers = $array['headers']; |
|||
$object->date = $array['date']; |
|||
$object->defaultAccount = $array['default_account']; |
|||
$object->delimiter = $delimiters[$array['delimiter']] ?? 'comma'; |
|||
$object->rules = $array['rules']; |
|||
$object->skipForm = $array['skip_form']; |
|||
$object->addImportTag = $array['add_import_tag'] ?? true; |
|||
$object->specifics = $array['specifics']; |
|||
$object->roles = $array['roles'] ?? []; |
|||
$object->mapping = $array['mapping'] ?? []; |
|||
$object->doMapping = $array['do_mapping'] ?? []; |
|||
$object->version = $version; |
|||
|
|||
// duplicate transaction detection
|
|||
$object->duplicateDetectionMethod = $array['duplicate_detection_method'] ?? 'classic'; |
|||
|
|||
// config for "classic":
|
|||
$object->ignoreDuplicateLines = $array['ignore_duplicate_lines']; |
|||
$object->ignoreDuplicateTransactions = $array['ignore_duplicate_transactions']; |
|||
|
|||
if (!array_key_exists('duplicate_detection_method', $array)) { |
|||
if (false === $object->ignoreDuplicateTransactions) { |
|||
Log::debug('Set the duplicate method to "none".'); |
|||
$object->duplicateDetectionMethod = 'none'; |
|||
} |
|||
} |
|||
|
|||
// overrule a setting:
|
|||
if ('none' === $object->duplicateDetectionMethod) { |
|||
$object->ignoreDuplicateTransactions = false; |
|||
} |
|||
|
|||
// config for "cell":
|
|||
$object->uniqueColumnIndex = $array['unique_column_index'] ?? 0; |
|||
$object->uniqueColumnType = $array['unique_column_type'] ?? ''; |
|||
|
|||
$firstValue = count(array_values($array['specifics'])) > 0 ? array_values($array['specifics'])[0] : null; |
|||
$firstKey = count(array_values($array['specifics'])) > 0 ? array_keys($array['specifics'])[0] : null; |
|||
|
|||
// due to a bug, the "specifics" array could still be broken at this point.
|
|||
// do a quick check and verification.
|
|||
if (is_bool($firstValue) && is_string($firstKey)) { |
|||
$actualSpecifics = []; |
|||
foreach ($array['specifics'] as $key => $value) { |
|||
if (true === $value) { |
|||
$actualSpecifics[] = $key; |
|||
} |
|||
} |
|||
$object->specifics = $actualSpecifics; |
|||
} |
|||
|
|||
//Log::debug(var_export($object->ignoreDuplicateLines, true));
|
|||
//Log::debug(var_export($object->ignoreDuplicateTransactions, true));
|
|||
|
|||
return $object; |
|||
} |
|||
|
|||
/** |
|||
* @return bool |
|||
*/ |
|||
public function isSkipForm(): bool |
|||
{ |
|||
return $this->skipForm; |
|||
} |
|||
|
|||
/** |
|||
* @param string $name |
|||
* |
|||
* @return bool |
|||
*/ |
|||
public function hasSpecific(string $name): bool |
|||
{ |
|||
return in_array($name, $this->specifics, true); |
|||
} |
|||
|
|||
/** |
|||
* @return bool |
|||
*/ |
|||
public function isAddImportTag(): bool |
|||
{ |
|||
return $this->addImportTag; |
|||
} |
|||
|
|||
/** |
|||
* @return array |
|||
*/ |
|||
public function getRoles(): array |
|||
{ |
|||
return $this->roles ?? []; |
|||
} |
|||
|
|||
/** |
|||
* @param array $roles |
|||
*/ |
|||
public function setRoles(array $roles): void |
|||
{ |
|||
$this->roles = $roles; |
|||
} |
|||
|
|||
/** |
|||
* @return bool |
|||
*/ |
|||
public function isIgnoreDuplicateLines(): bool |
|||
{ |
|||
return $this->ignoreDuplicateLines; |
|||
} |
|||
|
|||
/** |
|||
* @return bool |
|||
*/ |
|||
public function isIgnoreDuplicateTransactions(): bool |
|||
{ |
|||
return $this->ignoreDuplicateTransactions; |
|||
} |
|||
|
|||
/** |
|||
* Return the array but drop some potentially massive arrays. |
|||
* @return array |
|||
*/ |
|||
public function toSessionArray(): array |
|||
{ |
|||
$array = $this->toArray(); |
|||
unset($array['mapping'], $array['do_mapping'], $array['roles']); |
|||
return $array; |
|||
} |
|||
|
|||
/** |
|||
* @return array |
|||
*/ |
|||
public function toArray(): array |
|||
{ |
|||
$array = [ |
|||
'date' => $this->date, |
|||
'default_account' => $this->defaultAccount, |
|||
'delimiter' => $this->delimiter, |
|||
'headers' => $this->headers, |
|||
'rules' => $this->rules, |
|||
'skip_form' => $this->skipForm, |
|||
'add_import_tag' => $this->addImportTag, |
|||
'specifics' => $this->specifics, |
|||
'roles' => $this->roles, |
|||
'do_mapping' => $this->doMapping, |
|||
'mapping' => $this->mapping, |
|||
'duplicate_detection_method' => $this->duplicateDetectionMethod, |
|||
'ignore_duplicate_lines' => $this->ignoreDuplicateLines, |
|||
'ignore_duplicate_transactions' => $this->ignoreDuplicateTransactions, |
|||
'unique_column_index' => $this->uniqueColumnIndex, |
|||
'unique_column_type' => $this->uniqueColumnType, |
|||
'version' => $this->version, |
|||
]; |
|||
|
|||
// make sure that "ignore duplicate transactions" is turned off
|
|||
// to deliver a consistent file.
|
|||
$array['ignore_duplicate_transactions'] = false; |
|||
if ('classic' === $this->duplicateDetectionMethod) { |
|||
$array['ignore_duplicate_transactions'] = true; |
|||
} |
|||
|
|||
return $array; |
|||
} |
|||
|
|||
/** |
|||
* @return string |
|||
*/ |
|||
public function getDate(): string |
|||
{ |
|||
return $this->date; |
|||
} |
|||
|
|||
/** |
|||
* @return int |
|||
*/ |
|||
public function getDefaultAccount(): ?int |
|||
{ |
|||
return $this->defaultAccount; |
|||
} |
|||
|
|||
/** |
|||
* @return string |
|||
*/ |
|||
public function getDelimiter(): string |
|||
{ |
|||
return $this->delimiter; |
|||
} |
|||
|
|||
/** |
|||
* @return bool |
|||
*/ |
|||
public function isHeaders(): bool |
|||
{ |
|||
return $this->headers; |
|||
} |
|||
|
|||
/** |
|||
* @return bool |
|||
*/ |
|||
public function isRules(): bool |
|||
{ |
|||
return $this->rules; |
|||
} |
|||
|
|||
/** |
|||
* @return array |
|||
*/ |
|||
public function getDoMapping(): array |
|||
{ |
|||
return $this->doMapping ?? []; |
|||
} |
|||
|
|||
/** |
|||
* @param array $doMapping |
|||
*/ |
|||
public function setDoMapping(array $doMapping): void |
|||
{ |
|||
$this->doMapping = $doMapping; |
|||
} |
|||
|
|||
/** |
|||
* @return array |
|||
*/ |
|||
public function getMapping(): array |
|||
{ |
|||
return $this->mapping ?? []; |
|||
} |
|||
|
|||
/** |
|||
* @param array $mapping |
|||
*/ |
|||
public function setMapping(array $mapping): void |
|||
{ |
|||
$newMap = []; |
|||
foreach($mapping as $column => $map) { |
|||
ksort($map); |
|||
$newMap[$column] = $map; |
|||
} |
|||
$this->mapping = $newMap; |
|||
} |
|||
|
|||
/** |
|||
* @return array |
|||
*/ |
|||
public function getSpecifics(): array |
|||
{ |
|||
return $this->specifics; |
|||
} |
|||
|
|||
/** |
|||
* @return string |
|||
*/ |
|||
public function getDuplicateDetectionMethod(): string |
|||
{ |
|||
return $this->duplicateDetectionMethod; |
|||
} |
|||
|
|||
/** |
|||
* @return int |
|||
*/ |
|||
public function getUniqueColumnIndex(): int |
|||
{ |
|||
return $this->uniqueColumnIndex; |
|||
} |
|||
|
|||
/** |
|||
* @return string |
|||
*/ |
|||
public function getUniqueColumnType(): string |
|||
{ |
|||
return $this->uniqueColumnType; |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,272 @@ |
|||
<?php |
|||
/** |
|||
* Amount.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
*/ |
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Services\CSV\Converter; |
|||
|
|||
use Log; |
|||
|
|||
/** |
|||
* Class Amount. |
|||
*/ |
|||
class Amount implements ConverterInterface |
|||
{ |
|||
/** |
|||
* @param string $amount |
|||
* |
|||
* @return string |
|||
*/ |
|||
public static function positive(string $amount): string |
|||
{ |
|||
if (-1 === bccomp($amount, '0')) { |
|||
$amount = bcmul($amount, '-1'); |
|||
} |
|||
|
|||
return $amount; |
|||
} |
|||
|
|||
/** |
|||
* @param string $amount |
|||
* |
|||
* @return string |
|||
*/ |
|||
public static function negative(string $amount): string |
|||
{ |
|||
if (1 === bccomp($amount, '0')) { |
|||
$amount = bcmul($amount, '-1'); |
|||
} |
|||
|
|||
return $amount; |
|||
} |
|||
|
|||
/** |
|||
* Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems. |
|||
* - Jamie Zawinski. |
|||
* |
|||
* @param $value |
|||
* |
|||
* @return string |
|||
*/ |
|||
public function convert($value): string |
|||
{ |
|||
if (null === $value || '' === $value) { |
|||
return '0'; |
|||
} |
|||
|
|||
Log::debug(sprintf('Start with amount "%s"', $value)); |
|||
$original = $value; |
|||
$value = $this->stripAmount((string) $value); |
|||
$decimal = null; |
|||
|
|||
if ($this->decimalIsDot($value)) { |
|||
$decimal = '.'; |
|||
Log::debug(sprintf('Decimal character in "%s" seems to be a dot.', $value)); |
|||
} |
|||
|
|||
if ($this->decimalIsComma($value)) { |
|||
$decimal = ','; |
|||
Log::debug(sprintf('Decimal character in "%s" seems to be a comma.', $value)); |
|||
} |
|||
|
|||
// decimal character is null? find out if "0.1" or ".1" or "0,1" or ",1"
|
|||
if ($this->alternativeDecimalSign($value)) { |
|||
$decimal = $this->getAlternativeDecimalSign($value); |
|||
} |
|||
|
|||
// decimal character still null? Search from the left for '.',',' or ' '.
|
|||
if (null === $decimal) { |
|||
$decimal = $this->findFromLeft($value); |
|||
} |
|||
|
|||
// if decimal is dot, replace all comma's and spaces with nothing
|
|||
if (null !== $decimal) { |
|||
$value = $this->replaceDecimal($decimal, $value); |
|||
Log::debug(sprintf('Converted amount from "%s" to "%s".', $original, $value)); |
|||
} |
|||
|
|||
if (null === $decimal) { |
|||
// replace all:
|
|||
$search = ['.', ' ', ',']; |
|||
$value = str_replace($search, '', $value); |
|||
Log::debug(sprintf('No decimal character found. Converted amount from "%s" to "%s".', $original, $value)); |
|||
} |
|||
if (0 === strpos($value, '.')) { |
|||
$value = '0' . $value; |
|||
} |
|||
|
|||
if (is_numeric($value)) { |
|||
Log::debug(sprintf('Final NUMERIC value is: "%s"', $value)); |
|||
|
|||
return $value; |
|||
} |
|||
// @codeCoverageIgnoreStart
|
|||
Log::debug(sprintf('Final value is: "%s"', $value)); |
|||
$formatted = sprintf('%01.12f', $value); |
|||
Log::debug(sprintf('Is formatted to : "%s"', $formatted)); |
|||
|
|||
return $formatted; |
|||
// @codeCoverageIgnoreEnd
|
|||
} |
|||
|
|||
/** |
|||
* Strip amount from weird characters. |
|||
* |
|||
* @param string $value |
|||
* |
|||
* @return string |
|||
*/ |
|||
private function stripAmount(string $value): string |
|||
{ |
|||
if (0 === strpos($value, '--')) { |
|||
$value = substr($value, 2); |
|||
} |
|||
// have to strip the € because apparantly the Postbank (DE) thinks "1.000,00 €" is a normal way to format a number.
|
|||
// 2020-12-01 added "EUR" because another German bank doesn't know what a data format is.
|
|||
// This way of stripping exceptions is unsustainable.
|
|||
$value = trim((string) str_replace(['€', 'EUR'], '', $value)); |
|||
$str = preg_replace('/[^\-().,0-9 ]/', '', $value); |
|||
$len = strlen($str); |
|||
if (0 === strpos($str, '(') && ')' === $str[$len - 1]) { |
|||
$str = '-' . substr($str, 1, $len - 2); |
|||
} |
|||
$str = trim($str); |
|||
|
|||
Log::debug(sprintf('Stripped "%s" away to "%s"', $value, $str)); |
|||
|
|||
return $str; |
|||
} |
|||
|
|||
/** |
|||
* Helper function to see if the decimal separator is a dot. |
|||
* |
|||
* @param string $value |
|||
* |
|||
* @return bool |
|||
*/ |
|||
private function decimalIsDot(string $value): bool |
|||
{ |
|||
$length = strlen($value); |
|||
$decimalPosition = $length - 3; |
|||
|
|||
return ($length > 2 && '.' === $value[$decimalPosition]) || ($length > 2 && strpos($value, '.') > $decimalPosition); |
|||
} |
|||
|
|||
/** |
|||
* Helper function to see if the decimal separator is a comma. |
|||
* |
|||
* @param string $value |
|||
* |
|||
* @return bool |
|||
*/ |
|||
private function decimalIsComma(string $value): bool |
|||
{ |
|||
$length = strlen($value); |
|||
$decimalPosition = $length - 3; |
|||
|
|||
return $length > 2 && ',' === $value[$decimalPosition]; |
|||
} |
|||
|
|||
/** |
|||
* Check if the value has a dot or comma on an alternative place, |
|||
* catching strings like ",1" or ".5". |
|||
* |
|||
* @param string $value |
|||
* |
|||
* @return bool |
|||
*/ |
|||
private function alternativeDecimalSign(string $value): bool |
|||
{ |
|||
$length = strlen($value); |
|||
$altPosition = $length - 2; |
|||
|
|||
return $length > 1 && ('.' === $value[$altPosition] || ',' === $value[$altPosition]); |
|||
} |
|||
|
|||
/** |
|||
* Returns the alternative decimal point used, such as a dot or a comma, |
|||
* from strings like ",1" or "0.5". |
|||
* |
|||
* @param string $value |
|||
* |
|||
* @return string |
|||
*/ |
|||
private function getAlternativeDecimalSign(string $value): string |
|||
{ |
|||
$length = strlen($value); |
|||
$altPosition = $length - 2; |
|||
|
|||
return $value[$altPosition]; |
|||
|
|||
} |
|||
|
|||
/** |
|||
* Search from the left for decimal sign. |
|||
* |
|||
* @param string $value |
|||
* |
|||
* @return string |
|||
*/ |
|||
private function findFromLeft(string $value): ?string |
|||
{ |
|||
$decimal = null; |
|||
Log::debug('Decimal is still NULL, probably number with >2 decimals. Search for a dot.'); |
|||
$res = strrpos($value, '.'); |
|||
if (false !== $res) { |
|||
// blandly assume this is the one.
|
|||
Log::debug(sprintf('Searched from the left for "." in amount "%s", assume this is the decimal sign.', $value)); |
|||
$decimal = '.'; |
|||
} |
|||
|
|||
return $decimal; |
|||
} |
|||
|
|||
/** |
|||
* Replaces other characters like thousand separators with nothing to make the decimal separator the only special |
|||
* character in the string. |
|||
* |
|||
* @param string $decimal |
|||
* @param string $value |
|||
* |
|||
* @return string |
|||
*/ |
|||
private function replaceDecimal(string $decimal, string $value): string |
|||
{ |
|||
$search = [',', ' ']; // default when decimal sign is a dot.
|
|||
if (',' === $decimal) { |
|||
$search = ['.', ' ']; |
|||
} |
|||
$value = str_replace($search, '', $value); |
|||
|
|||
/** @noinspection CascadeStringReplacementInspection */ |
|||
return str_replace(',', '.', $value); |
|||
} |
|||
|
|||
/** |
|||
* Add extra configuration parameters. |
|||
* |
|||
* @param string $configuration |
|||
*/ |
|||
public function setConfiguration(string $configuration): void |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,59 @@ |
|||
<?php |
|||
/** |
|||
* AmountCredit.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
*/ |
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Services\CSV\Converter; |
|||
|
|||
/** |
|||
* Class AmountCredit |
|||
*/ |
|||
class AmountCredit implements ConverterInterface |
|||
{ |
|||
/** |
|||
* Convert an amount, always return positive. |
|||
* |
|||
* @param $value |
|||
* |
|||
* @return string |
|||
*/ |
|||
public function convert($value): string |
|||
{ |
|||
if (null === $value || '' === $value) { |
|||
return ''; |
|||
} |
|||
/** @var ConverterInterface $converter */ |
|||
$converter = app(Amount::class); |
|||
$result = $converter->convert($value); |
|||
|
|||
return Amount::positive($result); |
|||
} |
|||
|
|||
/** |
|||
* Add extra configuration parameters. |
|||
* |
|||
* @param string $configuration |
|||
*/ |
|||
public function setConfiguration(string $configuration): void |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,60 @@ |
|||
<?php |
|||
/** |
|||
* AmountDebit.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
*/ |
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Services\CSV\Converter; |
|||
|
|||
/** |
|||
* Class AmountDebit |
|||
*/ |
|||
class AmountDebit implements ConverterInterface |
|||
{ |
|||
/** |
|||
* Convert amount, always return positive. |
|||
* |
|||
* @param $value |
|||
* |
|||
* @return string |
|||
*/ |
|||
public function convert($value): string |
|||
{ |
|||
if (null === $value || '' === $value) { |
|||
return ''; |
|||
} |
|||
|
|||
/** @var ConverterInterface $converter */ |
|||
$converter = app(Amount::class); |
|||
$result = $converter->convert($value); |
|||
$result = Amount::positive($result); |
|||
return bcmul($result, '-1'); |
|||
} |
|||
|
|||
/** |
|||
* Add extra configuration parameters. |
|||
* |
|||
* @param string $configuration |
|||
*/ |
|||
public function setConfiguration(string $configuration): void |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,55 @@ |
|||
<?php |
|||
/** |
|||
* AmountNegated.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
*/ |
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Services\CSV\Converter; |
|||
|
|||
/** |
|||
* Class AmountNegated |
|||
*/ |
|||
class AmountNegated implements ConverterInterface |
|||
{ |
|||
/** |
|||
* Negate amount. |
|||
* |
|||
* @param $value |
|||
* |
|||
* @return string |
|||
*/ |
|||
public function convert($value): string |
|||
{ |
|||
/** @var ConverterInterface $converter */ |
|||
$converter = app(Amount::class); |
|||
$result = $converter->convert($value); |
|||
return bcmul($result, '-1'); |
|||
} |
|||
|
|||
/** |
|||
* Add extra configuration parameters. |
|||
* |
|||
* @param string $configuration |
|||
*/ |
|||
public function setConfiguration(string $configuration): void |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,72 @@ |
|||
<?php |
|||
/** |
|||
* BankDebitCredit.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
*/ |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Services\CSV\Converter; |
|||
|
|||
|
|||
use Log; |
|||
|
|||
/** |
|||
* |
|||
* Class BankDebitCredit |
|||
*/ |
|||
class BankDebitCredit implements ConverterInterface |
|||
{ |
|||
|
|||
/** |
|||
* Convert a value. |
|||
* |
|||
* @param $value |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function convert($value): int |
|||
{ |
|||
Log::debug('Going to convert ', ['value' => $value]); |
|||
$negative = [ |
|||
'D', // Old style Rabobank (NL). Short for "Debit"
|
|||
'A', // New style Rabobank (NL). Short for "Af"
|
|||
'DR', // https://old.reddit.com/r/FireflyIII/comments/bn2edf/generic_debitcredit_indicator/
|
|||
'Af', // ING (NL).
|
|||
'Debet', // Triodos (NL)
|
|||
'Debit', // ING (EN), thx Quibus!
|
|||
'S', // Volksbank (DE), Short for "Soll"
|
|||
]; |
|||
if (in_array(trim($value), $negative, true)) { |
|||
return -1; |
|||
} |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
/** |
|||
* Add extra configuration parameters. |
|||
* |
|||
* @param string $configuration |
|||
*/ |
|||
public function setConfiguration(string $configuration): void |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,59 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* CleanId.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Converter; |
|||
|
|||
use Log; |
|||
|
|||
/** |
|||
* Class CleanId |
|||
*/ |
|||
class CleanId implements ConverterInterface |
|||
{ |
|||
|
|||
/** |
|||
* Convert a value. |
|||
* |
|||
* @param $value |
|||
* |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function convert($value) |
|||
{ |
|||
Log::debug(sprintf('Now applying CleanId converter on "%s"', $value)); |
|||
$value = (int) $value; |
|||
|
|||
return 0 === $value ? null : $value; |
|||
} |
|||
|
|||
/** |
|||
* Add extra configuration parameters. |
|||
* |
|||
* @param string $configuration |
|||
*/ |
|||
public function setConfiguration(string $configuration): void |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,55 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* CleanInteger.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Converter; |
|||
|
|||
|
|||
/** |
|||
* Class CleanInteger |
|||
*/ |
|||
class CleanInteger implements ConverterInterface |
|||
{ |
|||
|
|||
/** |
|||
* Convert a value. |
|||
* |
|||
* @param $value |
|||
* |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function convert($value) |
|||
{ |
|||
return (int) $value; |
|||
} |
|||
|
|||
/** |
|||
* Add extra configuration parameters. |
|||
* |
|||
* @param string $configuration |
|||
*/ |
|||
public function setConfiguration(string $configuration): void |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,54 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* CleanNlString.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Converter; |
|||
|
|||
/** |
|||
* Class CleanNlString |
|||
*/ |
|||
class CleanNlString implements ConverterInterface |
|||
{ |
|||
|
|||
/** |
|||
* Convert a value. |
|||
* |
|||
* @param $value |
|||
* |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function convert($value) |
|||
{ |
|||
return app('steam')->cleanString($value); |
|||
} |
|||
|
|||
/** |
|||
* Add extra configuration parameters. |
|||
* |
|||
* @param string $configuration |
|||
*/ |
|||
public function setConfiguration(string $configuration): void |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,57 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* CleanString.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Converter; |
|||
|
|||
/** |
|||
* Class CleanString |
|||
*/ |
|||
class CleanString implements ConverterInterface |
|||
{ |
|||
|
|||
/** |
|||
* Convert a value. |
|||
* |
|||
* @param $value |
|||
* |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function convert($value) |
|||
{ |
|||
$value = app('steam')->cleanStringAndNewlines($value); |
|||
|
|||
// also remove newlines:
|
|||
return trim(str_replace("\n", '', $value)); |
|||
} |
|||
|
|||
/** |
|||
* Add extra configuration parameters. |
|||
* |
|||
* @param string $configuration |
|||
*/ |
|||
public function setConfiguration(string $configuration): void |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,46 @@ |
|||
<?php |
|||
/** |
|||
* ConverterInterface.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
*/ |
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Services\CSV\Converter; |
|||
|
|||
/** |
|||
* Interface ConverterInterface. |
|||
*/ |
|||
interface ConverterInterface |
|||
{ |
|||
/** |
|||
* Convert a value. |
|||
* |
|||
* @param $value |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function convert($value); |
|||
|
|||
/** |
|||
* Add extra configuration parameters. |
|||
* |
|||
* @param string $configuration |
|||
*/ |
|||
public function setConfiguration(string $configuration): void; |
|||
} |
@ -0,0 +1,81 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* ConverterService.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Converter; |
|||
|
|||
use Log; |
|||
use UnexpectedValueException; |
|||
|
|||
/** |
|||
* Class ConverterService |
|||
*/ |
|||
class ConverterService |
|||
{ |
|||
/** |
|||
* @param string $class |
|||
* @param mixed $value |
|||
* @param string|null $configuration |
|||
* |
|||
* @return mixed |
|||
*/ |
|||
public static function convert(string $class, $value, ?string $configuration) |
|||
{ |
|||
if ('' === $class) { |
|||
return $value; |
|||
} |
|||
if (self::exists($class)) { |
|||
/** @var ConverterInterface $object */ |
|||
$object = app(self::fullName($class)); |
|||
Log::debug(sprintf('Created converter class %s', $class)); |
|||
if (null !== $configuration) { |
|||
$object->setConfiguration($configuration); |
|||
} |
|||
|
|||
return $object->convert($value); |
|||
} |
|||
throw new UnexpectedValueException(sprintf('No such converter: "%s"', $class)); |
|||
} |
|||
|
|||
/** |
|||
* @param string $class |
|||
* |
|||
* @return bool |
|||
*/ |
|||
public static function exists(string $class): bool |
|||
{ |
|||
$name = self::fullName($class); |
|||
|
|||
return class_exists($name); |
|||
} |
|||
|
|||
/** |
|||
* @param string $class |
|||
* |
|||
* @return string |
|||
*/ |
|||
public static function fullName(string $class): string |
|||
{ |
|||
return sprintf('App\\Services\\CSV\\Converter\\%s', $class); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,113 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* Date.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Converter; |
|||
|
|||
use Carbon\Carbon; |
|||
use Carbon\Language; |
|||
use Exception; |
|||
use InvalidArgumentException; |
|||
use Log; |
|||
|
|||
/** |
|||
* Class Date |
|||
*/ |
|||
class Date implements ConverterInterface |
|||
{ |
|||
private string $dateFormat; |
|||
private string $dateLocale; |
|||
private string $dateFormatPattern; |
|||
|
|||
/** |
|||
* Date constructor. |
|||
*/ |
|||
public function __construct() |
|||
{ |
|||
$this->dateFormat = 'Y-m-d'; |
|||
$this->dateLocale = 'en'; |
|||
$this->dateFormatPattern = '/(?:(' . join("|", array_keys(Language::all())) . ')\:)?(.+)/'; |
|||
} |
|||
|
|||
/** |
|||
* Convert a value. |
|||
* |
|||
* @param $value |
|||
* |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function convert($value) |
|||
{ |
|||
$string = app('steam')->cleanStringAndNewlines($value); |
|||
$carbon = null; |
|||
|
|||
if ('!' !== $this->dateFormat[0]) { |
|||
$this->dateFormat = sprintf('!%s', $this->dateFormat); |
|||
} |
|||
|
|||
if ('' === $string) { |
|||
Log::warning('Empty date string, so date is set to today.'); |
|||
$carbon = today(); |
|||
$carbon->startOfDay(); |
|||
} |
|||
if ('' !== $string) { |
|||
Log::debug(sprintf('Date converter is going to work on "%s" using format "%s"', $string, $this->dateFormat)); |
|||
try { |
|||
$carbon = Carbon::createFromLocaleFormat($this->dateFormat, $this->dateLocale, $string); |
|||
} catch (InvalidArgumentException | Exception $e) { |
|||
Log::error(sprintf('%s converting the date: %s', get_class($e), $e->getMessage())); |
|||
|
|||
return Carbon::today()->startOfDay()->format('Y-m-d H:i:s'); |
|||
} |
|||
} |
|||
|
|||
return $carbon->format('Y-m-d H:i:s'); |
|||
} |
|||
|
|||
/** |
|||
* Add extra configuration parameters. |
|||
* |
|||
* @param string $configuration |
|||
*/ |
|||
public function setConfiguration(string $configuration): void |
|||
{ |
|||
[$this->dateLocale, $this->dateFormat] = $this->splitLocaleFormat($configuration); |
|||
} |
|||
|
|||
/** |
|||
* @param string $format |
|||
* @return array|string[] |
|||
*/ |
|||
public function splitLocaleFormat(string $format): array |
|||
{ |
|||
$currentDateLocale = 'en'; |
|||
$currentDateFormat = 'Y-m-d'; |
|||
$dateFormatConfiguration = []; |
|||
preg_match($this->dateFormatPattern, $format, $dateFormatConfiguration); |
|||
if (3 === count($dateFormatConfiguration)) { |
|||
$currentDateLocale = $dateFormatConfiguration[1] ?: $currentDateLocale; |
|||
$currentDateFormat = $dateFormatConfiguration[2]; |
|||
} |
|||
return [$currentDateLocale, $currentDateFormat]; |
|||
} |
|||
} |
@ -0,0 +1,54 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* Description.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Converter; |
|||
|
|||
/** |
|||
* Class Description |
|||
*/ |
|||
class Description implements ConverterInterface |
|||
{ |
|||
|
|||
/** |
|||
* Convert a value. |
|||
* |
|||
* @param $value |
|||
* |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function convert($value) |
|||
{ |
|||
return $value; |
|||
} |
|||
|
|||
/** |
|||
* Add extra configuration parameters. |
|||
* |
|||
* @param string $configuration |
|||
*/ |
|||
public function setConfiguration(string $configuration): void |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,95 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* Iban.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Converter; |
|||
|
|||
use Log; |
|||
use ValueError; |
|||
|
|||
/** |
|||
* Class Iban |
|||
*/ |
|||
class Iban implements ConverterInterface |
|||
{ |
|||
|
|||
/** |
|||
* Convert a value. |
|||
* |
|||
* @param $value |
|||
* |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function convert($value) |
|||
{ |
|||
if ($this->isValidIban($value)) { |
|||
// strip spaces from IBAN and make upper case.
|
|||
$result = str_replace("\x20", '', strtoupper(app('steam')->cleanStringAndNewlines($value))); |
|||
Log::debug(sprintf('Converted "%s" to "%s"', $value, $result)); |
|||
|
|||
return $result; |
|||
} |
|||
Log::info(sprintf('"%s" is not a valid IBAN.', $value)); |
|||
|
|||
return ''; |
|||
} |
|||
|
|||
/** |
|||
* @param string $value |
|||
* |
|||
* @return bool |
|||
*/ |
|||
private function isValidIban(string $value): bool |
|||
{ |
|||
Log::debug(sprintf('isValidIBAN("%s")', $value)); |
|||
$value = strtoupper(trim(app('steam')->cleanStringAndNewlines($value))); |
|||
$value = str_replace("\x20", '', $value); |
|||
Log::debug(sprintf('Trim: isValidIBAN("%s")', $value)); |
|||
$search = [' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; |
|||
$replace = ['', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', |
|||
'32', '33', '34', '35',]; |
|||
// take
|
|||
$first = substr($value, 0, 4); |
|||
$last = substr($value, 4); |
|||
$iban = $last . $first; |
|||
$iban = str_replace($search, $replace, $iban); |
|||
try { |
|||
$checksum = bcmod($iban, '97'); |
|||
} catch (ValueError $e) { |
|||
Log::error(sprintf('Bad IBAN: %s', $e->getMessage())); |
|||
$checksum = 2; |
|||
} |
|||
|
|||
return 1 === (int) $checksum; |
|||
} |
|||
|
|||
/** |
|||
* Add extra configuration parameters. |
|||
* |
|||
* @param string $configuration |
|||
*/ |
|||
public function setConfiguration(string $configuration): void |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,56 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* TagsComma.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Converter; |
|||
|
|||
/** |
|||
* Class TagsComma |
|||
*/ |
|||
class TagsComma implements ConverterInterface |
|||
{ |
|||
|
|||
/** |
|||
* Convert a value. |
|||
* |
|||
* @param $value |
|||
* |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function convert($value) |
|||
{ |
|||
$string = app('steam')->cleanStringAndNewlines($value); |
|||
|
|||
return explode(',', $string); |
|||
} |
|||
|
|||
/** |
|||
* Add extra configuration parameters. |
|||
* |
|||
* @param string $configuration |
|||
*/ |
|||
public function setConfiguration(string $configuration): void |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,56 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* TagsSpace.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Converter; |
|||
|
|||
/** |
|||
* Class TagsSpace |
|||
*/ |
|||
class TagsSpace implements ConverterInterface |
|||
{ |
|||
|
|||
/** |
|||
* Convert a value. |
|||
* |
|||
* @param $value |
|||
* |
|||
* @return mixed |
|||
* |
|||
*/ |
|||
public function convert($value) |
|||
{ |
|||
$string = app('steam')->cleanStringAndNewlines($value); |
|||
|
|||
return explode(' ', $string); |
|||
} |
|||
|
|||
/** |
|||
* Add extra configuration parameters. |
|||
* |
|||
* @param string $configuration |
|||
*/ |
|||
public function setConfiguration(string $configuration): void |
|||
{ |
|||
|
|||
} |
|||
} |
@ -0,0 +1,61 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* FileReader.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\File; |
|||
|
|||
|
|||
use App\Services\Session\Constants; |
|||
use App\Services\Storage\StorageService; |
|||
use Illuminate\Contracts\Filesystem\FileNotFoundException; |
|||
use League\Csv\Reader; |
|||
|
|||
/** |
|||
* Class FileReader |
|||
*/ |
|||
class FileReader |
|||
{ |
|||
/** |
|||
* Get a CSV file reader and fill it with data from CSV file. |
|||
* |
|||
* @return Reader |
|||
* @throws FileNotFoundException |
|||
*/ |
|||
public static function getReaderFromSession(): Reader |
|||
{ |
|||
$content = StorageService::getContent(session()->get(Constants::UPLOAD_CSV_FILE)); |
|||
|
|||
// room for config
|
|||
return Reader::createFromString($content); |
|||
} |
|||
|
|||
/** |
|||
* @param string $content |
|||
* |
|||
* @return Reader |
|||
*/ |
|||
public static function getReaderFromContent(string $content): Reader |
|||
{ |
|||
return Reader::createFromString($content); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,45 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* AssetAccountIbans.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Mapper; |
|||
|
|||
use App\Exceptions\ImportException; |
|||
|
|||
/** |
|||
* Class AssetAccountIbans |
|||
*/ |
|||
class AssetAccountIbans implements MapperInterface |
|||
{ |
|||
use GetAccounts; |
|||
|
|||
/** |
|||
* Get map of objects. |
|||
* |
|||
* @return array |
|||
* @throws ImportException |
|||
*/ |
|||
public function getMap(): array |
|||
{ |
|||
return $this->mergeWithIBAN($this->getAssetAccounts()); |
|||
} |
|||
} |
@ -0,0 +1,45 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* AssetAccounts.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Mapper; |
|||
|
|||
use App\Exceptions\ImportException; |
|||
|
|||
/** |
|||
* Class AssetAccounts |
|||
*/ |
|||
class AssetAccounts implements MapperInterface |
|||
{ |
|||
use GetAccounts; |
|||
|
|||
/** |
|||
* Get map of objects. |
|||
* |
|||
* @return array |
|||
* @throws ImportException |
|||
*/ |
|||
public function getMap(): array |
|||
{ |
|||
return $this->mergeAll($this->getAssetAccounts()); |
|||
} |
|||
} |
@ -0,0 +1,68 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* Bills.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Mapper; |
|||
|
|||
use App\Exceptions\ImportException; |
|||
use App\Support\Token; |
|||
use GrumpyDictator\FFIIIApiSupport\Exceptions\ApiHttpException; |
|||
use GrumpyDictator\FFIIIApiSupport\Model\Bill; |
|||
use GrumpyDictator\FFIIIApiSupport\Request\GetBillsRequest; |
|||
|
|||
/** |
|||
* Class Bills |
|||
*/ |
|||
class Bills implements MapperInterface |
|||
{ |
|||
/** |
|||
* Get map of objects. |
|||
* |
|||
* @return array |
|||
* @throws ImportException |
|||
*/ |
|||
public function getMap(): array |
|||
{ |
|||
$result = []; |
|||
$url = Token::getURL(); |
|||
$token = Token::getAccessToken(); |
|||
$request = new GetBillsRequest($url, $token); |
|||
|
|||
$request->setVerify(config('csv_importer.connection.verify')); |
|||
$request->setTimeOut(config('csv_importer.connection.timeout')); |
|||
|
|||
try { |
|||
$response = $request->get(); |
|||
} catch (ApiHttpException $e) { |
|||
Log::error($e->getMessage()); |
|||
Log::error($e->getTraceAsString()); |
|||
throw new ImportException(sprintf('Could not download bills: %s', $e->getMessage())); |
|||
} |
|||
/** @var Bill $bill */ |
|||
foreach ($response as $bill) { |
|||
$result[$bill->id] = sprintf('%s (%s)', $bill->name, $bill->repeat_freq); |
|||
} |
|||
asort($result, SORT_STRING); |
|||
|
|||
return $result; |
|||
} |
|||
} |
@ -0,0 +1,72 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* Budgets.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Mapper; |
|||
|
|||
use App\Exceptions\ImportException; |
|||
use App\Support\Token; |
|||
use GrumpyDictator\FFIIIApiSupport\Exceptions\ApiHttpException; |
|||
use GrumpyDictator\FFIIIApiSupport\Model\Budget; |
|||
use GrumpyDictator\FFIIIApiSupport\Request\GetBudgetsRequest; |
|||
use Log; |
|||
|
|||
/** |
|||
* Class Budgets |
|||
*/ |
|||
class Budgets implements MapperInterface |
|||
{ |
|||
|
|||
/** |
|||
* Get map of objects. |
|||
* |
|||
* @return array |
|||
* @throws ImportException |
|||
*/ |
|||
public function getMap(): array |
|||
{ |
|||
$result = []; |
|||
$url = Token::getURL(); |
|||
$token = Token::getAccessToken(); |
|||
$request = new GetBudgetsRequest($url, $token); |
|||
|
|||
$request->setVerify(config('csv_importer.connection.verify')); |
|||
$request->setTimeOut(config('csv_importer.connection.timeout')); |
|||
|
|||
try { |
|||
$response = $request->get(); |
|||
} catch (ApiHttpException $e) { |
|||
Log::error($e->getMessage()); |
|||
Log::error($e->getTraceAsString()); |
|||
throw new ImportException(sprintf('Could not download budgets: %s', $e->getMessage())); |
|||
} |
|||
|
|||
|
|||
/** @var Budget $budget */ |
|||
foreach ($response as $budget) { |
|||
$result[$budget->id] = sprintf('%s', $budget->name); |
|||
} |
|||
asort($result, SORT_STRING); |
|||
|
|||
return $result; |
|||
} |
|||
} |
@ -0,0 +1,70 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* Categories.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Mapper; |
|||
|
|||
use App\Exceptions\ImportException; |
|||
use App\Support\Token; |
|||
use GrumpyDictator\FFIIIApiSupport\Exceptions\ApiHttpException; |
|||
use GrumpyDictator\FFIIIApiSupport\Model\Category; |
|||
use GrumpyDictator\FFIIIApiSupport\Request\GetCategoriesRequest; |
|||
use Log; |
|||
|
|||
/** |
|||
* Class Categories |
|||
*/ |
|||
class Categories implements MapperInterface |
|||
{ |
|||
|
|||
/** |
|||
* Get map of objects. |
|||
* |
|||
* @return array |
|||
* @throws ImportException |
|||
*/ |
|||
public function getMap(): array |
|||
{ |
|||
$result = []; |
|||
$url = Token::getURL(); |
|||
$token = Token::getAccessToken(); |
|||
$request = new GetCategoriesRequest($url, $token); |
|||
|
|||
$request->setVerify(config('csv_importer.connection.verify')); |
|||
$request->setTimeOut(config('csv_importer.connection.timeout')); |
|||
|
|||
try { |
|||
$response = $request->get(); |
|||
} catch (ApiHttpException $e) { |
|||
Log::error($e->getMessage()); |
|||
Log::error($e->getTraceAsString()); |
|||
throw new ImportException(sprintf('Could not download categories: %s', $e->getMessage())); |
|||
} |
|||
/** @var Category $category */ |
|||
foreach ($response as $category) { |
|||
$result[$category->id] = sprintf('%s', $category->name); |
|||
} |
|||
asort($result, SORT_STRING); |
|||
|
|||
return $result; |
|||
} |
|||
} |
@ -0,0 +1,230 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* GetAccounts.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Mapper; |
|||
|
|||
use App\Exceptions\ImportException; |
|||
use App\Support\Token; |
|||
use GrumpyDictator\FFIIIApiSupport\Exceptions\ApiHttpException; |
|||
use GrumpyDictator\FFIIIApiSupport\Model\Account; |
|||
use GrumpyDictator\FFIIIApiSupport\Request\GetAccountsRequest; |
|||
use GrumpyDictator\FFIIIApiSupport\Response\GetAccountsResponse; |
|||
use Log; |
|||
|
|||
/** |
|||
* Trait GetAccounts |
|||
*/ |
|||
trait GetAccounts |
|||
{ |
|||
|
|||
/** |
|||
* Returns a combined list of asset accounts and all liability accounts. |
|||
* |
|||
* @return array |
|||
* @throws ImportException |
|||
*/ |
|||
protected function getAllAccounts(): array |
|||
{ |
|||
// get list of asset accounts:
|
|||
$accounts = []; |
|||
$url = Token::getURL(); |
|||
$token = Token::getAccessToken(); |
|||
$request = new GetAccountsRequest($url, $token); |
|||
|
|||
$request->setVerify(config('csv_importer.connection.verify')); |
|||
$request->setTimeOut(config('csv_importer.connection.timeout')); |
|||
$request->setType(GetAccountsRequest::ALL); |
|||
|
|||
/** @var GetAccountsResponse $response */ |
|||
try { |
|||
$response = $request->get(); |
|||
} catch (ApiHttpException $e) { |
|||
Log::error($e->getMessage()); |
|||
Log::error($e->getTraceAsString()); |
|||
throw new ImportException(sprintf('Could not download accounts: %s', $e->getMessage())); |
|||
} |
|||
|
|||
if ($response instanceof GetAccountsResponse) { |
|||
$accounts = $this->toArray($response); |
|||
} |
|||
|
|||
if (!$response instanceof GetAccountsResponse) { |
|||
throw new ImportException('Could not get list of ALL accounts.'); |
|||
} |
|||
|
|||
return array_merge($accounts); |
|||
} |
|||
|
|||
/** |
|||
* @param GetAccountsResponse $list |
|||
* |
|||
* @return array |
|||
*/ |
|||
private function toArray(GetAccountsResponse $list): array |
|||
{ |
|||
$return = []; |
|||
foreach ($list as $account) { |
|||
$return[] = $account; |
|||
} |
|||
|
|||
return $return; |
|||
} |
|||
|
|||
/** |
|||
* Returns a combined list of asset accounts and all liability accounts. |
|||
* |
|||
* @return array |
|||
* @throws ImportException |
|||
*/ |
|||
protected function getAssetAccounts(): array |
|||
{ |
|||
// get list of asset accounts:
|
|||
$accounts = []; |
|||
$liabilities = []; |
|||
$url = Token::getURL(); |
|||
$token = Token::getAccessToken(); |
|||
$request = new GetAccountsRequest($url, $token); |
|||
|
|||
$request->setType(GetAccountsRequest::ASSET); |
|||
$request->setVerify(config('csv_importer.connection.verify')); |
|||
$request->setTimeOut(config('csv_importer.connection.timeout')); |
|||
|
|||
/** @var GetAccountsResponse $response */ |
|||
try { |
|||
$response = $request->get(); |
|||
} catch (ApiHttpException $e) { |
|||
Log::error($e->getMessage()); |
|||
Log::error($e->getTraceAsString()); |
|||
throw new ImportException(sprintf('Could not download asset accounts: %s', $e->getMessage())); |
|||
} |
|||
|
|||
if ($response instanceof GetAccountsResponse) { |
|||
$accounts = $this->toArray($response); |
|||
} |
|||
|
|||
if (!$response instanceof GetAccountsResponse) { |
|||
throw new ImportException('Could not get list of asset accounts.'); |
|||
} |
|||
|
|||
$request = new GetAccountsRequest($url, $token); |
|||
|
|||
$request->setType(GetAccountsRequest::LIABILITIES); |
|||
$request->setVerify(config('csv_importer.connection.verify')); |
|||
$request->setTimeOut(config('csv_importer.connection.timeout')); |
|||
|
|||
/** @var GetAccountsResponse $response */ |
|||
try { |
|||
$response = $request->get(); |
|||
} catch (ApiHttpException $e) { |
|||
Log::error($e->getMessage()); |
|||
Log::error($e->getTraceAsString()); |
|||
throw new ImportException(sprintf('Could not download liability accounts: %s', $e->getMessage())); |
|||
} |
|||
|
|||
if ($response instanceof GetAccountsResponse) { |
|||
$liabilities = $this->toArray($response); |
|||
} |
|||
|
|||
if (!$response instanceof GetAccountsResponse) { |
|||
throw new ImportException('Could not get list of asset accounts.'); |
|||
} |
|||
|
|||
return array_merge($accounts, $liabilities); |
|||
} |
|||
|
|||
/** |
|||
* Merge all arrays into <select> ready list. |
|||
* |
|||
* @param array $accounts |
|||
* |
|||
* @return array |
|||
*/ |
|||
protected function mergeAll(array $accounts): array |
|||
{ |
|||
$invalidTypes = ['initial-balance', 'reconciliation']; |
|||
$result = []; |
|||
/** @var Account $account */ |
|||
foreach ($accounts as $account) { |
|||
$name = $account->name; |
|||
|
|||
// remove some types:
|
|||
if (in_array($account->type, $invalidTypes, true)) { |
|||
continue; |
|||
} |
|||
|
|||
if (null !== $account->iban) { |
|||
$name = sprintf('%s (%s)', $account->name, $account->iban); |
|||
} |
|||
|
|||
// add optgroup to result:
|
|||
$group = trans(sprintf('import.account_types_%s', $account->type)); |
|||
$result[$group] = $result[$group] ?? []; |
|||
$result[$group][$account->id] = $name; |
|||
} |
|||
foreach ($result as $group => $accounts) { |
|||
asort($accounts, SORT_STRING); |
|||
$result[$group] = $accounts; |
|||
} |
|||
|
|||
return $result; |
|||
} |
|||
|
|||
/** |
|||
* Merge all arrays into <select> ready list. |
|||
* |
|||
* @param array $accounts |
|||
* |
|||
* @return array |
|||
*/ |
|||
protected function mergeWithIBAN(array $accounts): array |
|||
{ |
|||
$result = []; |
|||
$invalidTypes = ['initial-balance', 'reconciliation']; |
|||
/** @var Account $account */ |
|||
foreach ($accounts as $account) { |
|||
|
|||
// remove some types:
|
|||
if (in_array($account->type, $invalidTypes, true)) { |
|||
continue; |
|||
} |
|||
|
|||
// only merge if IBAN is not null.
|
|||
if (null !== $account->iban) { |
|||
|
|||
|
|||
$name = sprintf('%s (%s)', $account->name, $account->iban); |
|||
// add optgroup to result:
|
|||
$group = trans(sprintf('import.account_types_%s', $account->type)); |
|||
$result[$group] = $result[$group] ?? []; |
|||
$result[$group][$account->id] = $name; |
|||
} |
|||
} |
|||
|
|||
foreach ($result as $group => $accounts) { |
|||
asort($accounts, SORT_STRING); |
|||
$result[$group] = $accounts; |
|||
} |
|||
|
|||
return $result; |
|||
} |
|||
} |
@ -0,0 +1,38 @@ |
|||
<?php |
|||
/** |
|||
* MapperInterface.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
|||
*/ |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace App\Services\CSV\Mapper; |
|||
|
|||
/** |
|||
* Interface MapperInterface. |
|||
*/ |
|||
interface MapperInterface |
|||
{ |
|||
/** |
|||
* Get map of objects. |
|||
* |
|||
* @return array |
|||
*/ |
|||
public function getMap(): array; |
|||
} |
@ -0,0 +1,122 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* MapperService.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Mapper; |
|||
|
|||
|
|||
use App\Exceptions\ImportException; |
|||
use App\Services\CSV\Specifics\SpecificService; |
|||
use League\Csv\Exception; |
|||
use League\Csv\Reader; |
|||
use League\Csv\Statement; |
|||
use Log; |
|||
|
|||
/** |
|||
* Class MapperService |
|||
*/ |
|||
class MapperService |
|||
{ |
|||
|
|||
/** |
|||
* Appends the given array with data from the CSV file in the config. |
|||
* |
|||
* @param string $content |
|||
* @param string $delimiter |
|||
* @param bool $hasHeaders |
|||
* @param array $specifics |
|||
* @param array $data |
|||
* |
|||
* @return array |
|||
* @throws ImportException |
|||
*/ |
|||
public static function getMapData(string $content, string $delimiter, bool $hasHeaders, array $specifics, array $data): array |
|||
{ |
|||
Log::debug('Now in getMapData'); |
|||
// make file reader first.
|
|||
$reader = Reader::createFromString($content); |
|||
|
|||
// reader not configured to use correct delimiter.
|
|||
try { |
|||
$reader->setDelimiter($delimiter); |
|||
} catch (Exception $e) { |
|||
Log::error($e->getMessage()); |
|||
Log::error($e->getTraceAsString()); |
|||
throw new ImportException(sprintf('Could not set delimiter: %s', $e->getMessage())); |
|||
} |
|||
|
|||
$offset = 0; |
|||
if (true === $hasHeaders) { |
|||
$offset = 1; |
|||
} |
|||
try { |
|||
$stmt = (new Statement)->offset($offset); |
|||
$records = $stmt->process($reader); |
|||
} catch (Exception $e) { |
|||
Log::error($e->getMessage()); |
|||
throw new ImportException($e->getMessage()); |
|||
} |
|||
// loop each row, apply specific:
|
|||
Log::debug('Going to loop all records to collect information'); |
|||
foreach ($records as $row) { |
|||
$row = SpecificService::runSpecifics($row, $specifics); |
|||
// loop each column, put in $data
|
|||
foreach ($row as $columnIndex => $column) { |
|||
if (!isset($data[$columnIndex])) { |
|||
// don't need to handle this. Continue.
|
|||
continue; |
|||
} |
|||
if ('' !== $column) { |
|||
$data[$columnIndex]['values'][] = trim($column); |
|||
} |
|||
} |
|||
} |
|||
// loop data, clean up data:
|
|||
foreach ($data as $index => $columnInfo) { |
|||
$data[$index]['values'] = array_unique($columnInfo['values']); |
|||
sort($data[$index]['values']); |
|||
|
|||
/* |
|||
* The config may contain mapped values that aren't in this CSV file. They're saved as |
|||
* hidden values (under unused_maps). |
|||
* |
|||
* Change on 2021-10-10: These unused_maps are no longer saved or use. |
|||
* The original mapping (saved on disk) will be merged with the new mapping (submitted by the user) |
|||
*/ |
|||
|
|||
// $mappedValues = array_keys($columnInfo['mapped'] ?? []);
|
|||
// $foundValues = $columnInfo['values'] ?? [];
|
|||
// $missingValues = array_diff($mappedValues, $foundValues);
|
|||
// // get them from mapped.
|
|||
// $missingMap = [];
|
|||
// foreach ($missingValues as $missingValue) {
|
|||
// if (array_key_exists($missingValue, $columnInfo['mapped'])) {
|
|||
// $missingMap[$missingValue] = $columnInfo['mapped'][$missingValue];
|
|||
// }
|
|||
// }
|
|||
// $data[$index]['missing_map'] = $missingMap;
|
|||
} |
|||
|
|||
return $data; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,45 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
/** |
|||
* OpposingAccountIbans.php |
|||
* Copyright (c) 2020 james@firefly-iii.org |
|||
* |
|||
* This file is part of the Firefly III CSV importer |
|||
* (https://github.com/firefly-iii/csv-importer). |
|||
* |
|||
* 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 App\Services\CSV\Mapper; |
|||
|
|||
use App\Exceptions\ImportException; |
|||
|
|||
/** |
|||
* Class OpposingAccountIbans |
|||
*/ |
|||
class OpposingAccountIbans implements MapperInterface |
|||
{ |
|||
use GetAccounts; |
|||
|
|||
/** |
|||
* Get map of objects. |
|||
* |
|||
* @return array |
|||
* @throws ImportException |
|||
*/ |
|||
public function getMap(): array |
|||
{ |
|||
return $this->mergeWithIBAN($this->getAllAccounts()); |
|||
} |
|||
} |
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue