130 changes: 95 additions & 35 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,82 @@ on:
- developer

jobs:
tests73:
tests74:
runs-on: ubuntu-latest
name: PHP 7.3 - MariaDB 10
name: PHP 7.4 - MariaDB 10.5
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Tests
uses: YetiForceCompany/YetiForceCRM-Tests/7.3@main
uses: YetiForceCompany/YetiForceCRM-Tests/7.4@main
env:
YETI_TEST_MODULE_KEY: ${{ secrets.YETI_TEST_MODULE_KEY }}
YETI_MAIL_PASS: ${{ secrets.YETI_MAIL_PASS }}

tests74:
tests80:
runs-on: ubuntu-latest
name: PHP 7.4 - MariaDB 10
name: PHP 8.0 - MariaDB 10.5
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 0
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis

- name: Tests
uses: YetiForceCompany/YetiForceCRM-Tests/7.4@main
uses: YetiForceCompany/YetiForceCRM-Tests/8.0@main
env:
YETI_TEST_MODULE_KEY: ${{ secrets.YETI_TEST_MODULE_KEY }}
YETI_MAIL_PASS: ${{ secrets.YETI_MAIL_PASS }}

tests80:
tests81:
runs-on: ubuntu-latest
name: PHP 8.0 - MariaDB 10
name: PHP 8.1 - MariaDB 10.5
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis

- name: Tests
uses: YetiForceCompany/YetiForceCRM-Tests/8.0@main
uses: YetiForceCompany/YetiForceCRM-Tests/8.1@main
env:
YETI_TEST_MODULE_KEY: ${{ secrets.YETI_TEST_MODULE_KEY }}
YETI_MAIL_PASS: ${{ secrets.YETI_MAIL_PASS }}

tests80jit:
runs-on: ubuntu-latest
name: PHP 8.0 JIT - MariaDB 10.5
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis

- name: Tests
uses: YetiForceCompany/YetiForceCRM-Tests/8.0-JIT@main
env:
YETI_TEST_MODULE_KEY: ${{ secrets.YETI_TEST_MODULE_KEY }}
YETI_MAIL_PASS: ${{ secrets.YETI_MAIL_PASS }}

tests81jit:
runs-on: ubuntu-latest
name: PHP 8.1 JIT - MariaDB 10.5
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis

- name: Tests
uses: YetiForceCompany/YetiForceCRM-Tests/8.1-JIT@main
env:
YETI_TEST_MODULE_KEY: ${{ secrets.YETI_TEST_MODULE_KEY }}
YETI_MAIL_PASS: ${{ secrets.YETI_MAIL_PASS }}

tests74MariaDB106:
needs: tests80
runs-on: ubuntu-latest
name: PHP 7.4 - MariaDB 10.6
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis

Expand All @@ -62,11 +91,57 @@ jobs:
YETI_TEST_MODULE_KEY: ${{ secrets.YETI_TEST_MODULE_KEY }}
YETI_MAIL_PASS: ${{ secrets.YETI_MAIL_PASS }}

tests74MariaDB107:
needs: tests80
runs-on: ubuntu-latest
name: PHP 7.4 - MariaDB 10.7
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis

- name: Tests
uses: YetiForceCompany/YetiForceCRM-Tests/mariadb-10.7@main
env:
YETI_TEST_MODULE_KEY: ${{ secrets.YETI_TEST_MODULE_KEY }}
YETI_MAIL_PASS: ${{ secrets.YETI_MAIL_PASS }}

tests74MariaDB108:
needs: tests80
runs-on: ubuntu-latest
name: PHP 7.4 - MariaDB 10.8
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis

- name: Tests
uses: YetiForceCompany/YetiForceCRM-Tests/mariadb-10.8@main
env:
YETI_TEST_MODULE_KEY: ${{ secrets.YETI_TEST_MODULE_KEY }}
YETI_MAIL_PASS: ${{ secrets.YETI_MAIL_PASS }}

tests74MariaDB109:
needs: tests80
runs-on: ubuntu-latest
name: PHP 7.4 - MariaDB 10.9
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis

- name: Tests
uses: YetiForceCompany/YetiForceCRM-Tests/mariadb-10.9@main
env:
YETI_TEST_MODULE_KEY: ${{ secrets.YETI_TEST_MODULE_KEY }}
YETI_MAIL_PASS: ${{ secrets.YETI_MAIL_PASS }}

tests74MySQL57:
needs: tests80
runs-on: ubuntu-latest
name: PHP 7.4 - Percona MySQL 5.7
name: PHP 7.4 - MySQL 5.7 Percona
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis

Expand All @@ -77,10 +152,11 @@ jobs:
YETI_MAIL_PASS: ${{ secrets.YETI_MAIL_PASS }}

coverage:
needs: tests80
runs-on: ubuntu-latest
name: Code Coverage
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis

Expand Down Expand Up @@ -111,30 +187,14 @@ jobs:
coverageLocations: ${{github.workspace}}/tests/coverages/coverage3.xml:clover

- name: Upload artifact Coverages
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: Coverages
path: ${{github.workspace}}/tests/coverages

- name: Upload artifact Logs
if: ${{ always() }}
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: Logs
path: ${{github.workspace}}/cache/logs/

coverage8:
runs-on: ubuntu-latest
name: Code Coverage PHP8
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis

- name: Tests
uses: YetiForceCompany/YetiForceCRM-Tests/coverage@main
env:
YETI_TEST_MODULE_KEY: ${{ secrets.YETI_TEST_MODULE_KEY }}
YETI_MAIL_PASS: ${{ secrets.YETI_MAIL_PASS }}
CODACY_PROJECT_TOKEN: ${{ secrets.YETI_CODACY_PROJECT_TOKEN }}
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
2 changes: 1 addition & 1 deletion .htaccess
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ RedirectMatch 403 (?i).*\.log$
<IfModule mod_php5.c>
php_flag output_buffering On
php_flag always_populate_raw_post_data Off
php_flag mbstring.func_overload Off
php_flag mbstring.func_overload 0
</IfModule>
</Files>
########################
Expand Down
14 changes: 9 additions & 5 deletions .php_cs.dist
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
$config = \PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setIndent("\t")
->setUsingCache(false)
->setCacheFile(__DIR__ . '/.php-cs-fixer.cache')
->setRules([
'@PHP56Migration' => true,
'@PHPUnit60Migration:risky' => true,
'@PHP74Migration' => true,
'@PHP74Migration:risky' => true,
'@PHP80Migration' => true,
'@PHP80Migration:risky' => true,
'@PhpCsFixer' => true,
'@PhpCsFixer:risky' => true,
'list_syntax' => ['syntax' => 'short'],
'@PSR2' => true,
'list_syntax' => ['syntax' => 'short'],
'align_multiline_comment' => true,
'array_syntax' => ['syntax' => 'short'],
'blank_line_after_namespace' => true,
Expand All @@ -27,6 +29,7 @@ $config = \PhpCsFixer\Config::create()
],
'explicit_string_variable' => false,
'declare_equal_normalize' => true,
'declare_strict_types' => false,
'dir_constant' => false,
'doctrine_annotation_braces' => true,
'doctrine_annotation_indentation' => true,
Expand Down Expand Up @@ -145,13 +148,14 @@ $config = \PhpCsFixer\Config::create()
'switch_case_space' => true,
'ternary_operator_spaces' => true,
'ternary_to_null_coalescing' => true,
'trailing_comma_in_multiline_array' => false,
'trailing_comma_in_multiline' => ['after_heredoc' => false, 'elements' => []],
'trim_array_spaces' => true,
'unary_operator_spaces' => true,
'visibility_required' => [
'property',
'method',
],
'void_return' => false,
'whitespace_after_comma_in_array' => true,
])
->setFinder(PhpCsFixer\Finder::create()
Expand Down
2 changes: 1 addition & 1 deletion .symfony.insight.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
php_version: 7.3
php_version: 7.4

php_ini: |
extension=imap.so
Expand Down
285 changes: 152 additions & 133 deletions .yarnclean
Original file line number Diff line number Diff line change
Expand Up @@ -14,122 +14,9 @@ test.js
CODE_OF_CONDUCT.md
node_modules


# asset directories
docs
doc
chart.js/node_modules
chart.js/samples
chart.js/dist/Chart.bundle.js
chart.js/dist/Chart.bundle.min.js
chart.js/scripts
chart.js/src
chart.js/.htmllintrc

#package
split.js/logo.svg
gantt-elastic/src
gantt-elastic/*.jpg
gantt-elastic/*.gif
updated-jqplot/optionsTutorial.txt
updated-jqplot/usage.txt
updated-jqplot/jqPlotCssStyling.txt
updated-jqplot/jqPlotOptions.txt
leaflet.markercluster/ISSUE_TEMPLATE.md
jQuery-Validation-Engine/releases.html
jQuery-Validation-Engine/runDemo.bat
jQuery-Validation-Engine/runDemo.sh
jQuery-Validation-Engine/js/jquery-1.8.2.min.js
jQuery-Validation-Engine/js/libs
jquery-gantt-editor/gantt.html
footable/icomoon
footable/js
footable/less
floatthead/src
blueimp-file-upload/node_modules
bootstrap-chosen/dist
bootstrap-datepicker/js
bootstrap-datepicker/less
bootstrap-daterangepicker/website
bootstrap-daterangepicker/drp.png
chartjs-plugin-funnel/spec
chartjs-plugin-funnel/config.jshintrc
clockpicker/assets
clockpicker/src
clockpicker/jquery.html
delegate/dist
@fortawesome/fontawesome-free/less
@fortawesome/fontawesome-free/scss
@fortawesome/fontawesome-free/sprites
@fortawesome/fontawesome-free/svgs
@fortawesome/fontawesome-free/js
@fortawesome/fontawesome-free/css/brands.css
@fortawesome/fontawesome-free/css/brands.min.css
@fortawesome/fontawesome-free/css/fontawesome.css
@fortawesome/fontawesome-free/css/fontawesome.min.css
@fortawesome/fontawesome-free/css/regular.css
@fortawesome/fontawesome-free/css/regular.min.css
@fortawesome/fontawesome-free/css/solid.css
@fortawesome/fontawesome-free/css/solid.min.css
@fortawesome/fontawesome-free/css/svg-with-js.css
@fortawesome/fontawesome-free/css/svg-with-js.min.css
@fortawesome/fontawesome-free/css/v4-shims.css
@fortawesome/fontawesome-free/css/v4-shims.min.css
good-listener/dist
html2canvas/flow-typed
jquery/external
jquery-lazy/plugins
jquery-outside-events/unit
jquery-outside-events/shared
jQuery-Validation-Engine/less
jstorage/debian
jstree-bootstrap-theme/dist/libs/
jstree-bootstrap-theme/dist/.esformatter
jstree-bootstrap-theme/dist/jstree.js
jstree-bootstrap-theme/dist/jstree.min.js
jstree-bootstrap-theme/libs/bootstrap/js/bootstrap.js
jstree-bootstrap-theme/libs/jquery.js
jstree-bootstrap-theme/libs/bootstrap/js/bootstrap.min.js
leaflet.awesome-markers/screenshots
leaflet.markercluster/spec
mousetrap/plugins
perfect-scrollbar/types
popper.js/index.d.ts
popper.js/dist/esm
respond.js/src
respond.js/cross-domain
select2-theme-bootstrap4/dist
svg/svgBasic.html
svg/lion.svg

hammerjs/.bowerrc
hammerjs/.jscsrc
html2canvas/dist/npm

# removing unnecessary packages
updated-jqplot
css-line-break
delegate
good-listener
tiny-emitter
jquery-ui
jquery-ui-dist/external
asap
core-js
encoding
fbemitter
fbjs
iconv-lite
is-stream
isomorphic-fetch
js-tokens
loose-envify
node-fetch
object-assign
promise
safer-buffer
setimmediate
ua-parser-js

# examples
example
Expand Down Expand Up @@ -203,74 +90,206 @@ MAINTAINING.md
source
build

#source - automatically generated
#removing unnecessary files in packages
@fortawesome/fontawesome-free/css/brands.css
@fortawesome/fontawesome-free/css/brands.min.css
@fortawesome/fontawesome-free/css/fontawesome.css
@fortawesome/fontawesome-free/css/fontawesome.min.css
@fortawesome/fontawesome-free/css/regular.css
@fortawesome/fontawesome-free/css/regular.min.css
@fortawesome/fontawesome-free/css/solid.css
@fortawesome/fontawesome-free/css/solid.min.css
@fortawesome/fontawesome-free/css/svg-with-js.css
@fortawesome/fontawesome-free/css/svg-with-js.min.css
@fortawesome/fontawesome-free/css/v4-font-face.css
@fortawesome/fontawesome-free/css/v4-font-face.min.css
@fortawesome/fontawesome-free/css/v4-shims.css
@fortawesome/fontawesome-free/css/v4-shims.min.css
@fortawesome/fontawesome-free/css/v5-font-face.css
@fortawesome/fontawesome-free/css/v5-font-face.min.css
@fortawesome/fontawesome-free/js
@fortawesome/fontawesome-free/less
@fortawesome/fontawesome-free/scss
@fortawesome/fontawesome-free/sprites
@fortawesome/fontawesome-free/svgs
@fortawesome/fontawesome-free/webfonts/fa-v4compatibility.ttf
@fortawesome/fontawesome-free/webfonts/fa-v4compatibility.woff2
add/src
almond/src
animate.css/src
base64-arraybuffer/src
block-ui/src
blueimp-canvas-to-blob/src
blueimp-file-upload/node_modules
blueimp-file-upload/src
blueimp-load-image/src
blueimp-tmpl/src
bootbox/src
bootstrap/src
bootstrap/js
bootstrap/dist/css
bootstrap-chosen/dist
bootstrap-colorpicker/src
bootstrap-datepicker/js
bootstrap-datepicker/less
bootstrap-datepicker/src
bootstrap-daterangepicker/drp.png
bootstrap-daterangepicker/moment.min.js
bootstrap-daterangepicker/src
bootstrap-daterangepicker/website
bootstrap/dist/css
bootstrap/js
bootstrap/src
chart.js/.htmllintrc
chart.js/auto/
chart.js/chunks/
chart.js/dist/Chart.bundle.js
chart.js/dist/Chart.bundle.min.js
chart.js/helpers/
chart.js/node_modules
chart.js/samples
chart.js/scripts/
chart.js/src/
chart.js/types/
chartjs-color-string/src
chartjs-plugin-datalabels/src
chartjs-plugin-funnel/config.jshintrc
chartjs-plugin-funnel/spec
chartjs-plugin-funnel/src
chosen-js/src
clipboard/src
clockpicker/assets
clockpicker/jquery.html
clockpicker/src
color-name/src
css-line-break/src
datatables.net/src
datatables.net-bs4/src
datatables.net-responsive/src
datatables.net-responsive-bs4/src
datatables.net-responsive/src
datatables.net/src
delegate/dist
device-uuid/src
dompurify/src
floatthead/src
footable/icomoon
footable/js
footable/less
footable/src
fullcalendar/locales-all.js
fullcalendar/locales-all.min.js
fullcalendar/src
fullcalendar/locales
gantt-elastic/*.gif
gantt-elastic/*.jpg
gantt-elastic/src
good-listener/dist
gridstack/dist/es5/
gridstack/dist/gridstack-dd*
gridstack/dist/gridstack-engine*
gridstack/dist/gridstack-extra*
gridstack/dist/gridstack-jq*
gridstack/dist/gridstack-static*
gridstack/dist/gridstack.js
gridstack/dist/gridstack.js.map
gridstack/dist/h5/
gridstack/dist/jq/
gridstack/dist/src/
gridstack/src
hammerjs/src
html2canvas/dist/npm
html2canvas/flow-typed
html2canvas/src
html5shiv/src
inputmask/src
inputmask/dist/min
inputmask/dist/inputmask
jquery/src
inputmask/dist/min
inputmask/src
jquery-gantt-editor/gantt.html
jquery-hoverintent/src
jquery-lazy/plugins
jquery-lazy/src
jquery-mousewheel/src
jquery-outside-events/shared
jquery-outside-events/src
jquery-outside-events/unit
jquery-slimscroll/src
jquery-ui-dist/src
jquery-ui-touch-punch/src
jQuery-Validation-Engine/js/jquery-1.8.2.min.js
jQuery-Validation-Engine/js/libs
jQuery-Validation-Engine/less
jQuery-Validation-Engine/releases.html
jQuery-Validation-Engine/runDemo.bat
jQuery-Validation-Engine/runDemo.sh
jquery/external
jquery/src
jstorage/debian
jstorage/src
jstree/src
jstree-bootstrap-theme/dist/.esformatter
jstree-bootstrap-theme/dist/jstree.js
jstree-bootstrap-theme/dist/jstree.min.js
jstree-bootstrap-theme/dist/libs/
jstree-bootstrap-theme/libs/bootstrap/js/bootstrap.js
jstree-bootstrap-theme/libs/bootstrap/js/bootstrap.min.js
jstree-bootstrap-theme/libs/jquery.js
jstree-bootstrap-theme/src
leaflet/src
leaflet/dist/leaflet-src.js.map
leaflet/dist/leaflet-src.esm.js.map
leaflet/dist/leaflet-src.js
leaflet/dist/leaflet-src.esm.js
jstree/src
leaflet.awesome-markers/screenshots
leaflet.awesome-markers/src
leaflet.markercluster/ISSUE_TEMPLATE.md
leaflet.markercluster/spec
leaflet.markercluster/src
moment/src
moment/moment.js
leaflet/dist/leaflet-src.esm.js
leaflet/dist/leaflet-src.esm.js.map
leaflet/dist/leaflet-src.js
leaflet/dist/leaflet-src.js.map
leaflet/src
moment/dist
moment/locale
moment/ts3.1-typings
moment/min/locales.js
moment/min/moment-with-locales.js
moment/min/moment-with-locales.min.js
moment/min/moment-with-locales.min.js.map
moment/moment.js
moment/src
mousetrap/plugins
mousetrap/src
perfect-scrollbar/src
perfect-scrollbar/types
popper.js/dist/esm
popper.js/index.d.ts
popper.js/src
respond.js/cross-domain
respond.js/src
sass-material-colors/src
select2-theme-bootstrap4/dist
select2/src
split.js/logo.svg
split.js/src
svg/lion.svg
svg/svgBasic.html
tiny-emitter/src
updated-jqplot/jqPlotCssStyling.txt
updated-jqplot/jqPlotOptions.txt
updated-jqplot/optionsTutorial.txt
updated-jqplot/src
updated-jqplot/usage.txt

# removing unnecessary packages
updated-jqplot
css-line-break
delegate
good-listener
tiny-emitter
jquery-ui
jquery-ui-dist/external
asap
core-js
encoding
fbemitter
fbjs
iconv-lite
is-stream
isomorphic-fetch
js-tokens
loose-envify
node-fetch
object-assign
promise
safer-buffer
setimmediate
ua-parser-js
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM debian:buster
FROM debian:bullseye

MAINTAINER m.krzaczkowski@yetiforce.com

Expand Down
8 changes: 4 additions & 4 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
YetiForce Public License 4.0
Producer: YetiForce Sp. z o.o., PL1180002425
YetiForce Public License 5.0
Producer: YetiForce S.A., PL1180002425
Email: registration@yetiforce.com (registration of the Software)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

a) Any file under this license must contain the content of the license or a link to the content of the license;
b) The Software must, if technically possible, be registered with the Software Manufacturer using the built-in form or via e-mail as described on the Producer’s website. Each Entity that uses, configures or modifies the Software is subject to registration, regardless of whether it registers the Software for itself or on behalf of other entities. In the case of groups of people, i.e. an organization, company, family or any group of people, it is enough to register only a group of people by providing the data of the organization / company or data of one person from the family / group. If, despite many correct attempts to register the Software, there is no reply from the Producer, the Entity may generate the registration keys on its own;
c) Data used for registration must be true. All provided registration information, including the company’s name, can be used by YetiForce Sp. z o.o. (Ltd.) for marketing purposes (i.e. preparation of statistics, publication on the website).
YetiForce Sp. z o.o. (Ltd.) does not sell or transfer that data to other entities and guarantees confidentiality of personal data.
c) Data used for registration must be true. All provided registration information, including the company’s name, can be used by YetiForce S.A. (Ltd.) for marketing purposes (i.e. preparation of statistics, publication on the website).
YetiForce S.A. (Ltd.) does not sell or transfer that data to other entities and guarantees confidentiality of personal data.
d) The content of the system footer, printouts and emails (including links and mechanisms controlling product registration and purchase of paid products) cannot be changed in the system, unless a written consent from the Producer is obtained or an official addon sold by the Producer is purchased, which allows the purchaser to modify the footer. The color of the footer can be changed as long as the footer content remains legible.
e) In the case of products marked as paid, an appropriate license / subscription must be purchased from the Producer or an official Producer Partner;
f) The entity using the Software is obligated to keep a history of changes introduced into the Software and, at the request of the Producer, enable an inspection to verify that the Entity complies with the terms of this license. The inspection may not take place more often than once every 3 years;
Expand Down
31 changes: 18 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![Latest Stable Version](https://poser.pugx.org/yetiforce/yetiforce-crm/v/stable)](https://packagist.org/packages/yetiforce/yetiforce-crm)
![release date](https://img.shields.io/github/release-date/YetiForceCompany/YetiForceCRM)
![PHP Version](https://img.shields.io/packagist/php-v/yetiforce/yetiforce-crm)
[![Tested on PHP 7.3 to nightly](https://img.shields.io/badge/tested%20on-PHP%207.3%20|%207.4%20|%208.0%20-brightgreen.svg?maxAge=2419200)](https://github.com/YetiForceCompany/YetiForceCRM/actions?query=workflow%3Atests)
[![Tested on PHP 7.4 to nightly](https://img.shields.io/badge/tested%20on-PHP%207.4%20%7C%208.0%20%7C%208.1%20-brightgreen.svg?maxAge=2419200)](https://github.com/YetiForceCompany/YetiForceCRM/actions?query=workflow%3Atests)
[![Download YetiForce CRM](https://img.shields.io/sourceforge/dt/yetiforce.svg)](https://sourceforge.net/projects/yetiforce/files/latest/download)
[![GitHub contributors](https://img.shields.io/github/contributors/YetiForceCompany/YetiForceCRM.svg)](https://GitHub.com/YetiForceCompany/YetiForceCRM/graphs/contributors/)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/yetiforcecrm/localized.svg)](https://crowdin.com/project/yetiforcecrm)
Expand All @@ -22,6 +22,8 @@
[![mozilla-observatory](https://img.shields.io/mozilla-observatory/grade/gitdeveloper.yetiforce.com?publish)](https://observatory.mozilla.org/analyze/gitdeveloper.yetiforce.com)
[![Docker Hub](https://img.shields.io/badge/docker-ready-blue.svg)](https://registry.hub.docker.com/r/yetiforce/yetiforcecrm/)

<img src="https://stats.yetiforce.com/matomo.php?idsite=4&amp;rec=1" style="border:0" alt="" />

<p align="center">
<a href='http://www.capterra.com/customer-relationship-management-software/reviews/159123/Yetiforce%20/YetiForce?utm_source=vendor&utm_medium=badge&utm_campaign=capterra_reviews_badge'> <img border='0' src='https://assets.capterra.com/badge/470cd214b89233aa4e89972fa49c3253.png?v=2111411&p=159123' /></a>
<a href='https://www.capterra.com/customer-relationship-management-software/#affordable' width="50"><img border='0' src='https://public.yetiforce.com/img/CRM-AF-2017.png' width="150" /></a>
Expand All @@ -48,7 +50,7 @@
</a>
</p>

We design an innovative CRM system that is dedicated for large and medium sized companies. We dedicate it to everyone who values open source software, security and innovation. YetiForce was built on a rock-solid Vtiger foundation, but has hundreds of changes that help to accomplish even the most challenging tasks in the simplest way. Every function within the system was thought through and automated to ensure that all of them work together seamlessly and form a coherent integrity. We looked at the entire sales process and consequently refined the system, module by module. We have years of experience creating tailor made CRM software for a variety of different companies. Download it and have a first-hand experience.
We design an innovative CRM system that is dedicated to large and medium-sized companies. We dedicate it to everyone who values open source software, security, and innovation. YetiForce was built on a rock-solid Vtiger foundation but has hundreds of changes that help to accomplish even the most challenging tasks in the simplest way. Every function within the system was thought through and automated to ensure that all of them work together seamlessly and form coherent integrity. We looked at the entire sales process and consequently refined the system, module by module. We have years of experience creating tailor-made CRM software for a variety of different companies. Download it and have a first-hand experience.

## 😎 Demos

Expand Down Expand Up @@ -149,14 +151,17 @@ Support this project by becoming a sponsor. Your logo will show up here with a l

### Gallery: https://public.yetiforce.com/gallery

![](https://public.yetiforce.com/img/main/1_Home_page.png)

![](https://public.yetiforce.com/gallery/uploads/big/7679123c2d73f4065c9abc532d1bde77.png)

![](https://public.yetiforce.com/img/main/3_Home_page.png)

![](https://public.yetiforce.com/img/main/4_Calendar.png)

![](https://public.yetiforce.com/img/main/8_List_Accounts.png)

![](https://public.yetiforce.com/img/main/24_Detail_Projects_Gantt_Months.png)
![](https://yetiforce.com/images/v6/1_home.png)
![](https://yetiforce.com/images/v6/1_home2.png)
![](https://yetiforce.com/images/v6/1_home3.png)
![](https://yetiforce.com/images/v6/2_kanban1.png)
![](https://yetiforce.com/images/v6/2_kanban2.png)
![](https://yetiforce.com/images/v6/3_detail.png)
![](https://yetiforce.com/images/v6/3_edit.png)
![](https://yetiforce.com/images/v6/3_list.png)
![](https://yetiforce.com/images/v6/4_detail.png)
![](https://yetiforce.com/images/v6/5_perms.png)
![](https://yetiforce.com/images/v6/5_progreswizard.png)
![](https://yetiforce.com/images/v6/6_calendar.png)
![](https://yetiforce.com/images/v6/7_map.png)
![](https://yetiforce.com/images/v6/8_admin.png)
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"ApprovalsRegister"
],
"summary": "Adds an consent entry",
"description": "Add record.",
"operationId": "425399d47c958ba5c538827d258fde0a",
"requestBody": {
"description": "Required data for communication",
Expand Down Expand Up @@ -95,6 +96,7 @@
"Approvals"
],
"summary": "Gets the list of consents",
"description": "Gets consents.",
"operationId": "04e7ebb08f943d466f20bb0e98311271",
"parameters": [
{
Expand Down Expand Up @@ -222,6 +224,7 @@
"BaseModule"
],
"summary": "Gets the list of consents for specific entry",
"description": "Gets consents.",
"operationId": "9fd993e544cb6935282883e505b8d1d6",
"parameters": [
{
Expand Down Expand Up @@ -295,6 +298,7 @@
"BaseModule"
],
"summary": "Send e-mail",
"description": "Send e-mail.",
"operationId": "86c8610aedbae9a8690ab71a3ae22134",
"parameters": [
{
Expand Down Expand Up @@ -563,7 +567,6 @@
},
"Exception": {
"title": "General - Error exception",
"description": "Gets consents.",
"properties": {
"status": {
"description": "0 - error",
Expand Down Expand Up @@ -618,7 +621,6 @@
},
"BaseModule_Post_GetConsentsForEntry_Response": {
"title": "Response body for GetConsentsForEntry",
"description": "Gets consents.",
"properties": {
"status": {
"description": "A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error",
Expand Down Expand Up @@ -667,7 +669,6 @@
},
"BaseModule_Post_SendEmail_Response": {
"title": "Response body for SendEmail",
"description": "Send e-mail.",
"properties": {
"status": {
"description": "A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ paths:
tags:
- ApprovalsRegister
summary: 'Adds an consent entry'
description: 'Add record.'
operationId: 425399d47c958ba5c538827d258fde0a
requestBody:
description: 'Required data for communication'
Expand Down Expand Up @@ -64,6 +65,7 @@ paths:
tags:
- Approvals
summary: 'Gets the list of consents'
description: 'Gets consents.'
operationId: 04e7ebb08f943d466f20bb0e98311271
parameters:
-
Expand Down Expand Up @@ -149,6 +151,7 @@ paths:
tags:
- BaseModule
summary: 'Gets the list of consents for specific entry'
description: 'Gets consents.'
operationId: 9fd993e544cb6935282883e505b8d1d6
parameters:
-
Expand Down Expand Up @@ -197,6 +200,7 @@ paths:
tags:
- BaseModule
summary: 'Send e-mail'
description: 'Send e-mail.'
operationId: 86c8610aedbae9a8690ab71a3ae22134
parameters:
-
Expand Down Expand Up @@ -317,7 +321,6 @@ components:
type: object
Exception:
title: 'General - Error exception'
description: 'Gets consents.'
properties:
status:
description: '0 - error'
Expand Down Expand Up @@ -358,7 +361,6 @@ components:
type: object
BaseModule_Post_GetConsentsForEntry_Response:
title: 'Response body for GetConsentsForEntry'
description: 'Gets consents.'
properties:
status:
description: 'A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error'
Expand Down Expand Up @@ -394,7 +396,6 @@ components:
type: object
BaseModule_Post_SendEmail_Response:
title: 'Response body for SendEmail'
description: 'Send e-mail.'
properties:
status:
description: 'A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error'
Expand Down
173 changes: 173 additions & 0 deletions api/doc/SMS.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
{
"openapi": "3.0.0",
"info": {
"title": "YetiForce API for SMS. Type: SMS",
"description": "",
"termsOfService": "https://yetiforce.com/",
"contact": {
"name": "Devs API Team",
"url": "https://yetiforce.com/",
"email": "devs@yetiforce.com"
},
"license": {
"name": "YetiForce Public License",
"url": "https://yetiforce.com/en/yetiforce/license"
},
"version": "0.1"
},
"servers": [
{
"url": "https://gitdeveloper.yetiforce.com",
"description": "Demo server of the development version"
},
{
"url": "https://gitstable.yetiforce.com",
"description": "Demo server of the latest stable version"
}
],
"paths": {
"/webservice/SMS/SMSAPI/Reception": {
"get": {
"tags": [
"SMSAPI"
],
"summary": "Receipt of SMS",
"description": "Add record.",
"externalDocs": {
"description": "SMSApi Documentation",
"url": "https://www.smsapi.pl/docs"
},
"operationId": "1d5b693764111be12b9441546ea6e2cb",
"responses": {
"200": {
"description": "Result",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SMS_SMSAPI_Post_Reception"
}
}
}
},
"401": {
"description": "`No sent token` OR `Invalid token` OR `wrong data provided in the request`"
},
"403": {
"description": "No permissions for module"
},
"405": {
"description": "Method Not Allowed"
}
},
"security": [
{
"ApiKeyAuth": [],
"token": []
}
]
}
},
"/webservice/SMS/SMSAPI/Report": {
"get": {
"tags": [
"SMSAPI"
],
"summary": "Report for sms",
"description": "Update record status.",
"externalDocs": {
"description": "SMSApi Documentation",
"url": "https://www.smsapi.pl/docs"
},
"operationId": "82162b057882b4798a1d4844f9e0161f",
"responses": {
"200": {
"description": "Result",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SMS_SMSAPI_Get_Report"
}
}
}
},
"401": {
"description": "`No sent token` OR `Invalid token` OR `wrong data provided in the request`"
},
"403": {
"description": "No permissions for module"
},
"405": {
"description": "Method Not Allowed"
}
},
"security": [
{
"ApiKeyAuth": [],
"token": []
}
]
},
"post": {
"tags": [
"SMSAPI"
],
"summary": "Report for sms",
"description": "Update record status.",
"externalDocs": {
"description": "SMSApi Documentation",
"url": "https://www.smsapi.pl/docs"
},
"operationId": "2d104552585271b46f199a9df6b49930",
"responses": {
"200": {
"description": "Result",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SMS_SMSAPI_Post_Report"
}
}
}
},
"401": {
"description": "`No sent token` OR `Invalid token` OR `wrong data provided in the request`"
},
"403": {
"description": "No permissions for module"
},
"405": {
"description": "Method Not Allowed"
}
},
"security": [
{
"ApiKeyAuth": [],
"token": []
}
]
}
}
},
"components": {
"schemas": {
"SMS_SMSAPI_Post_Reception": {
"title": "Response",
"description": "Response",
"type": "string",
"example": "OK"
},
"SMS_SMSAPI_Get_Report": {
"title": "Response",
"description": "Response",
"type": "string",
"example": "OK"
},
"SMS_SMSAPI_Post_Report": {
"title": "Response",
"description": "Response",
"type": "string",
"example": "OK"
}
}
}
}
118 changes: 118 additions & 0 deletions api/doc/SMS.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
openapi: 3.0.0
info:
title: 'YetiForce API for SMS. Type: SMS'
description: ''
termsOfService: 'https://yetiforce.com/'
contact:
name: 'Devs API Team'
url: 'https://yetiforce.com/'
email: devs@yetiforce.com
license:
name: 'YetiForce Public License'
url: 'https://yetiforce.com/en/yetiforce/license'
version: '0.1'
servers:
-
url: 'https://gitdeveloper.yetiforce.com'
description: 'Demo server of the development version'
-
url: 'https://gitstable.yetiforce.com'
description: 'Demo server of the latest stable version'
paths:
/webservice/SMS/SMSAPI/Reception:
get:
tags:
- SMSAPI
summary: 'Receipt of SMS'
description: 'Add record.'
externalDocs:
description: 'SMSApi Documentation'
url: 'https://www.smsapi.pl/docs'
operationId: 1d5b693764111be12b9441546ea6e2cb
responses:
'200':
description: Result
content:
application/json:
schema:
$ref: '#/components/schemas/SMS_SMSAPI_Post_Reception'
'401':
description: '`No sent token` OR `Invalid token` OR `wrong data provided in the request`'
'403':
description: 'No permissions for module'
'405':
description: 'Method Not Allowed'
security:
-
ApiKeyAuth: []
token: []
/webservice/SMS/SMSAPI/Report:
get:
tags:
- SMSAPI
summary: 'Report for sms'
description: 'Update record status.'
externalDocs:
description: 'SMSApi Documentation'
url: 'https://www.smsapi.pl/docs'
operationId: 82162b057882b4798a1d4844f9e0161f
responses:
'200':
description: Result
content:
application/json:
schema:
$ref: '#/components/schemas/SMS_SMSAPI_Get_Report'
'401':
description: '`No sent token` OR `Invalid token` OR `wrong data provided in the request`'
'403':
description: 'No permissions for module'
'405':
description: 'Method Not Allowed'
security:
-
ApiKeyAuth: []
token: []
post:
tags:
- SMSAPI
summary: 'Report for sms'
description: 'Update record status.'
externalDocs:
description: 'SMSApi Documentation'
url: 'https://www.smsapi.pl/docs'
operationId: 2d104552585271b46f199a9df6b49930
responses:
'200':
description: Result
content:
application/json:
schema:
$ref: '#/components/schemas/SMS_SMSAPI_Post_Report'
'401':
description: '`No sent token` OR `Invalid token` OR `wrong data provided in the request`'
'403':
description: 'No permissions for module'
'405':
description: 'Method Not Allowed'
security:
-
ApiKeyAuth: []
token: []
components:
schemas:
SMS_SMSAPI_Post_Reception:
title: Response
description: Response
type: string
example: OK
SMS_SMSAPI_Get_Report:
title: Response
description: Response
type: string
example: OK
SMS_SMSAPI_Post_Report:
title: Response
description: Response
type: string
example: OK
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,19 @@
},
"example": 5
},
{
"name": "x-fields-params",
"in": "header",
"description": "JSON array - list of fields to be returned in the specified way",
"required": false,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Fields-Settings"
}
}
}
},
{
"name": "x-header-fields",
"in": "header",
Expand Down Expand Up @@ -1201,6 +1214,21 @@
"$ref": "#/components/links/GetRecordById"
}
}
},
"406": {
"description": "No input data",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Exception"
}
},
"application/xml": {
"schema": {
"$ref": "#/components/schemas/Exception"
}
}
}
}
},
"security": [
Expand Down Expand Up @@ -1280,7 +1308,7 @@
"BaseModule"
],
"summary": "Create record",
"description": "Gets data to save record",
"description": "Create new record",
"operationId": "10503c8d531e680a764151718cb0ca34",
"parameters": [
{
Expand Down Expand Up @@ -1338,6 +1366,21 @@
"$ref": "#/components/links/GetRecordById"
}
}
},
"406": {
"description": "No input data",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Exception"
}
},
"application/xml": {
"schema": {
"$ref": "#/components/schemas/Exception"
}
}
}
}
},
"security": [
Expand Down Expand Up @@ -3979,7 +4022,6 @@
},
"BaseModule_Get_Dashboard_Response": {
"title": "Base module - Dashboard response schema",
"description": "Get method - Gets widgets' data from the dashboard.",
"properties": {
"status": {
"description": "A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error",
Expand Down Expand Up @@ -4566,7 +4608,6 @@
},
"BaseModule_Get_Hierarchy_Response": {
"title": "Base module - Hierarchy response schema",
"description": "Get method - Gets records hierarchy.",
"properties": {
"status": {
"description": "A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error",
Expand All @@ -4592,7 +4633,7 @@
},
"name": {
"type": "string",
"example": "YetiForce Sp. z o.o."
"example": "YetiForce S.A."
}
},
"type": "object"
Expand All @@ -4603,7 +4644,6 @@
},
"BaseModule_Get_Pdf_Response": {
"title": "Base module - Generate PDF response schema",
"description": "Get method - Generates and downloads a PDF file from a template.",
"properties": {
"status": {
"description": "A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error",
Expand Down Expand Up @@ -4636,7 +4676,6 @@
},
"BaseModule_Get_PdfTemplates_Response": {
"title": "Base module - Get PDF templates list response schema",
"description": "Get method - Gets a list of PDF templates.",
"properties": {
"status": {
"description": "A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error",
Expand Down Expand Up @@ -4678,7 +4717,6 @@
},
"BaseModule_Get_Privileges_Response": {
"title": "Base module - Privileges response schema",
"description": "Get privileges for module.",
"properties": {
"status": {
"description": "A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error",
Expand All @@ -4703,9 +4741,18 @@
},
"type": "object"
},
"Fields-Settings": {
"title": "Custom field settings",
"description": "A list of custom parameters that can affect the return value of a given field.",
"type": "object",
"example": {
"password": {
"showHiddenData": true
}
}
},
"BaseModule_Get_Record_Response": {
"title": "Base module - Response body for Record",
"description": "Get record detail.",
"required": [
"status",
"result"
Expand Down Expand Up @@ -5666,7 +5713,6 @@
},
"BaseAction_SaveInventory_ResponseBodyError": {
"title": "Base module - Create inventory record response error schema",
"description": "Put method - A store functionality - creates a record in an advanced module (orders).",
"properties": {
"errors": {
"description": "Error details",
Expand Down Expand Up @@ -5852,7 +5898,10 @@
},
"Products_Get_Record_Response": {
"title": "Base module - Response body for Record",
"description": "{@inheritdoc}",
"required": [
"status",
"result"
],
"properties": {
"status": {
"description": "A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error",
Expand All @@ -5863,7 +5912,13 @@
]
},
"result": {
"description": "Record data",
"title": "Record data",
"required": [
"name",
"id",
"fields",
"data"
],
"properties": {
"name": {
"description": "Record name",
Expand Down Expand Up @@ -5893,7 +5948,11 @@
"$ref": "#/components/schemas/Record_Display_Details"
},
"privileges": {
"description": "Parameters determining checking of editing rights and moving to the trash",
"title": "Parameters determining checking of editing rights and moving to the trash",
"required": [
"isEditable",
"moveToTrash"
],
"properties": {
"isEditable": {
"description": "Check if record is editable",
Expand Down Expand Up @@ -6004,7 +6063,6 @@
},
"Users_Get_AccessActivityHistory_Response": {
"title": "Users module - History of access activity data",
"description": "Get user history of access activity.",
"required": [
"status",
"result"
Expand Down Expand Up @@ -6071,7 +6129,6 @@
},
"Users_Put_ChangePassword_Response": {
"title": "Users module - Users password change response body",
"description": "Put method.",
"required": [
"status",
"result"
Expand Down Expand Up @@ -6447,7 +6504,6 @@
},
"Exception": {
"title": "General - Error exception",
"description": "Post method.",
"required": [
"status",
"error"
Expand Down Expand Up @@ -6534,7 +6590,6 @@
},
"Users_Put_Preferences_Response": {
"title": "Users module - Response content of changing user settings",
"description": "Put method - Changes user’s preferences.",
"required": [
"status",
"result"
Expand All @@ -6558,7 +6613,6 @@
},
"Users_Get_Record_Response": {
"title": "Users module - Response body for user",
"description": "Get user detail.",
"properties": {
"status": {
"description": "A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error",
Expand Down Expand Up @@ -6692,7 +6746,6 @@
},
"Users_Post_ResetPassword_Response": {
"title": "Users module - Users password reset response body",
"description": "Post method.",
"required": [
"status",
"result"
Expand Down Expand Up @@ -6749,7 +6802,6 @@
},
"Users_Put_ResetPassword_Response": {
"title": "Users module - Users password reset response body",
"description": "Put method.",
"required": [
"status",
"result"
Expand All @@ -6773,7 +6825,6 @@
},
"Users_Get_TwoFactorAuth_Response": {
"title": "Users module - Authentication secret details",
"description": "Get two factor authentication details.",
"required": [
"status",
"result"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,15 @@ paths:
schema:
type: integer
example: 5
-
name: x-fields-params
in: header
description: 'JSON array - list of fields to be returned in the specified way'
required: false
content:
application/json:
schema:
$ref: '#/components/schemas/Fields-Settings'
-
name: x-header-fields
in: header
Expand Down Expand Up @@ -797,6 +806,15 @@ paths:
links:
GetRecordById:
$ref: '#/components/links/GetRecordById'
'406':
description: 'No input data'
content:
application/json:
schema:
$ref: '#/components/schemas/Exception'
application/xml:
schema:
$ref: '#/components/schemas/Exception'
security:
-
basicAuth: []
Expand Down Expand Up @@ -851,7 +869,7 @@ paths:
tags:
- BaseModule
summary: 'Create record'
description: 'Gets data to save record'
description: 'Create new record'
operationId: 10503c8d531e680a764151718cb0ca34
parameters:
-
Expand Down Expand Up @@ -891,6 +909,15 @@ paths:
links:
GetRecordById:
$ref: '#/components/links/GetRecordById'
'406':
description: 'No input data'
content:
application/json:
schema:
$ref: '#/components/schemas/Exception'
application/xml:
schema:
$ref: '#/components/schemas/Exception'
security:
-
basicAuth: []
Expand Down Expand Up @@ -2657,7 +2684,6 @@ components:
type: object
BaseModule_Get_Dashboard_Response:
title: 'Base module - Dashboard response schema'
description: 'Get method - Gets widgets'' data from the dashboard.'
properties:
status:
description: 'A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error'
Expand Down Expand Up @@ -2822,7 +2848,6 @@ components:
type: object
BaseModule_Get_Hierarchy_Response:
title: 'Base module - Hierarchy response schema'
description: 'Get method - Gets records hierarchy.'
properties:
status:
description: 'A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error'
Expand All @@ -2844,12 +2869,11 @@ components:
example: 0
name:
type: string
example: 'YetiForce Sp. z o.o.'
example: 'YetiForce S.A.'
type: object
type: object
BaseModule_Get_Pdf_Response:
title: 'Base module - Generate PDF response schema'
description: 'Get method - Generates and downloads a PDF file from a template.'
properties:
status:
description: 'A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error'
Expand All @@ -2873,7 +2897,6 @@ components:
type: object
BaseModule_Get_PdfTemplates_Response:
title: 'Base module - Get PDF templates list response schema'
description: 'Get method - Gets a list of PDF templates.'
properties:
status:
description: 'A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error'
Expand Down Expand Up @@ -2904,7 +2927,6 @@ components:
type: object
BaseModule_Get_Privileges_Response:
title: 'Base module - Privileges response schema'
description: 'Get privileges for module.'
properties:
status:
description: 'A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error'
Expand All @@ -2922,9 +2944,15 @@ components:
title: Action
type: boolean
type: object
Fields-Settings:
title: 'Custom field settings'
description: 'A list of custom parameters that can affect the return value of a given field.'
type: object
example:
password:
showHiddenData: true
BaseModule_Get_Record_Response:
title: 'Base module - Response body for Record'
description: 'Get record detail.'
required:
- status
- result
Expand Down Expand Up @@ -3383,7 +3411,6 @@ components:
type: object
BaseAction_SaveInventory_ResponseBodyError:
title: 'Base module - Create inventory record response error schema'
description: 'Put method - A store functionality - creates a record in an advanced module (orders).'
properties:
errors:
description: 'Error details'
Expand Down Expand Up @@ -3525,7 +3552,9 @@ components:
type: object
Products_Get_Record_Response:
title: 'Base module - Response body for Record'
description: '{@inheritdoc}'
required:
- status
- result
properties:
status:
description: 'A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error'
Expand All @@ -3534,7 +3563,12 @@ components:
- 0
- 1
result:
description: 'Record data'
title: 'Record data'
required:
- name
- id
- fields
- data
properties:
name:
description: 'Record name'
Expand All @@ -3558,7 +3592,10 @@ components:
data:
$ref: '#/components/schemas/Record_Display_Details'
privileges:
description: 'Parameters determining checking of editing rights and moving to the trash'
title: 'Parameters determining checking of editing rights and moving to the trash'
required:
- isEditable
- moveToTrash
properties:
isEditable:
description: 'Check if record is editable'
Expand Down Expand Up @@ -3635,7 +3672,6 @@ components:
type: object
Users_Get_AccessActivityHistory_Response:
title: 'Users module - History of access activity data'
description: 'Get user history of access activity.'
required:
- status
- result
Expand Down Expand Up @@ -3685,7 +3721,6 @@ components:
type: object
Users_Put_ChangePassword_Response:
title: 'Users module - Users password change response body'
description: 'Put method.'
required:
- status
- result
Expand Down Expand Up @@ -3971,7 +4006,6 @@ components:
type: object
Exception:
title: 'General - Error exception'
description: 'Post method.'
required:
- status
- error
Expand Down Expand Up @@ -4036,7 +4070,6 @@ components:
menuPin: 1
Users_Put_Preferences_Response:
title: 'Users module - Response content of changing user settings'
description: 'Put method - Changes user’s preferences.'
required:
- status
- result
Expand All @@ -4054,7 +4087,6 @@ components:
type: object
Users_Get_Record_Response:
title: 'Users module - Response body for user'
description: 'Get user detail.'
properties:
status:
description: 'A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error'
Expand Down Expand Up @@ -4153,7 +4185,6 @@ components:
type: object
Users_Post_ResetPassword_Response:
title: 'Users module - Users password reset response body'
description: 'Post method.'
required:
- status
- result
Expand Down Expand Up @@ -4195,7 +4226,6 @@ components:
type: object
Users_Put_ResetPassword_Response:
title: 'Users module - Users password reset response body'
description: 'Put method.'
required:
- status
- result
Expand All @@ -4213,7 +4243,6 @@ components:
type: object
Users_Get_TwoFactorAuth_Response:
title: 'Users module - Authentication secret details'
description: 'Get two factor authentication details.'
required:
- status
- result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,19 @@
"type": "integer"
},
"example": 5
},
{
"name": "x-fields-params",
"in": "header",
"description": "JSON array - list of fields to be returned in the specified way",
"required": false,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Fields-Settings"
}
}
}
}
],
"responses": {
Expand Down Expand Up @@ -734,6 +747,21 @@
"$ref": "#/components/links/GetRecordById"
}
}
},
"406": {
"description": "No input data",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Exception"
}
},
"application/xml": {
"schema": {
"$ref": "#/components/schemas/Exception"
}
}
}
}
},
"security": [
Expand Down Expand Up @@ -813,7 +841,7 @@
"BaseModule"
],
"summary": "Create record",
"description": "Gets data to save record",
"description": "Create new record",
"operationId": "ea3b9bea091cbde741323b5393901825",
"parameters": [
{
Expand Down Expand Up @@ -871,6 +899,21 @@
"$ref": "#/components/links/GetRecordById"
}
}
},
"406": {
"description": "No input data",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Exception"
}
},
"application/xml": {
"schema": {
"$ref": "#/components/schemas/Exception"
}
}
}
}
},
"security": [
Expand Down Expand Up @@ -1901,7 +1944,7 @@
],
"summary": "Data for the user",
"description": "Gets details about the user",
"operationId": "5de1069868c749968f98e50485b6f084",
"operationId": "getUser",
"parameters": [
{
"name": "userId",
Expand Down Expand Up @@ -1992,6 +2035,86 @@
]
}
},
"/webservice/WebserviceStandard/Users/Record": {
"post": {
"tags": [
"Users"
],
"summary": "Create user",
"description": "Create new user",
"operationId": "b2550c068a0148252c584ed08f9d7fae",
"parameters": [
{
"name": "X-ENCRYPTED",
"in": "header",
"required": true,
"schema": {
"$ref": "#/components/schemas/Header-Encrypted"
}
}
],
"requestBody": {
"description": "Contents of the request contains an associative array with the user data.",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User_Create_Details"
}
},
"application/xml": {
"schema": {
"$ref": "#/components/schemas/User_Create_Details"
}
}
}
},
"responses": {
"200": {
"description": "Contents of the response contains only id",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User_Post_Record_Response"
}
},
"application/xml": {
"schema": {
"$ref": "#/components/schemas/User_Post_Record_Response"
}
}
},
"links": {
"GetUserById": {
"$ref": "#/components/links/GetUserById"
}
}
},
"406": {
"description": "No input data",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Exception"
}
},
"application/xml": {
"schema": {
"$ref": "#/components/schemas/Exception"
}
}
}
}
},
"security": [
{
"basicAuth": [],
"ApiKeyAuth": [],
"token": []
}
]
}
},
"/webservice/WebserviceStandard/Users/RecordsList": {
"get": {
"tags": [
Expand Down Expand Up @@ -3282,7 +3405,6 @@
},
"BaseModule_Privileges_ResponseBody": {
"title": "Base module - Privileges response schema",
"description": "Get privileges for module.",
"properties": {
"status": {
"description": "A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error",
Expand All @@ -3309,9 +3431,18 @@
},
"type": "object"
},
"Fields-Settings": {
"title": "Custom field settings",
"description": "A list of custom parameters that can affect the return value of a given field.",
"type": "object",
"example": {
"password": {
"showHiddenData": true
}
}
},
"BaseModule_Get_Record_Response": {
"title": "Base module - Response body for Record",
"description": "Get record detail.",
"required": [
"status",
"result"
Expand Down Expand Up @@ -4055,7 +4186,6 @@
},
"Users_Get_AccessActivityHistory_Response": {
"title": "Users module - History of access activity data",
"description": "Get user history of access activity.",
"required": [
"status",
"result"
Expand Down Expand Up @@ -4122,7 +4252,6 @@
},
"Users_Put_ChangePassword_Response": {
"title": "Users module - Users password change response body",
"description": "Put method.",
"required": [
"status",
"result"
Expand Down Expand Up @@ -4428,7 +4557,6 @@
},
"Exception": {
"title": "General - Error exception",
"description": "Post method.",
"required": [
"status",
"error"
Expand Down Expand Up @@ -4508,7 +4636,6 @@
},
"Users_Get_Record_Response": {
"title": "Users module - Response body for user",
"description": "Get user detail.",
"properties": {
"status": {
"description": "A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error",
Expand Down Expand Up @@ -4573,6 +4700,65 @@
},
"type": "object"
},
"User_Post_Record_Response": {
"title": "User - Created user",
"description": "Contents of the response contains only id and name",
"required": [
"status",
"result"
],
"properties": {
"status": {
"description": "A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error",
"type": "integer",
"enum": [
0,
1
]
},
"result": {
"title": "User data",
"description": "Created user id and name.",
"required": [
"id",
"name"
],
"properties": {
"id": {
"description": "Id of the newly created user",
"type": "integer",
"example": 22
},
"name": {
"description": "Id of the newly created user",
"type": "string",
"example": "YetiForce Name"
},
"skippedData": {
"description": "List of parameters passed in the request that were skipped in the write process",
"type": "object"
}
},
"type": "object"
}
},
"type": "object"
},
"User_Create_Details": {
"title": "General - User create details",
"description": "User data in user format for create view",
"type": "object",
"example": {
"user_name": "tom",
"first_name": "Tom",
"last_name": "Kowalski",
"roleid": "H38",
"password": "MyFunP@ssword",
"confirm_password": "MyFunP@ssword",
"email1": "my@email.com",
"language": "en-US"
}
},
"Users_RecordsList_ResponseBody": {
"title": "Users module - Response action users list",
"description": "Module action record list response body",
Expand Down Expand Up @@ -4636,7 +4822,6 @@
},
"Users_Post_ResetPassword_Response": {
"title": "Users module - Users password reset response body",
"description": "Post method.",
"required": [
"status",
"result"
Expand Down Expand Up @@ -4687,7 +4872,6 @@
},
"Users_Put_ResetPassword_Response": {
"title": "Users module - Users password reset response body",
"description": "Put method.",
"required": [
"status",
"result"
Expand All @@ -4711,7 +4895,6 @@
},
"Users_Get_TwoFactorAuth_Response": {
"title": "Users module - Authentication secret details",
"description": "Get two factor authentication details.",
"required": [
"status",
"result"
Expand Down Expand Up @@ -4811,6 +4994,13 @@
"recordId": "$response.body#/result/id"
},
"description": "The `id` value returned in the response can be used as the `recordId` parameter in `GET /webservice/{moduleName}/Record/{recordId}`."
},
"GetUserById": {
"operationId": "getUser",
"parameters": {
"recordId": "$response.body#/result/id"
},
"description": "The `id` value returned in the response can be used as the `userId` parameter in `GET /webservice/Users/Record/{userId}`."
}
}
},
Expand All @@ -4823,10 +5013,6 @@
"name": "BaseAction",
"description": "Access to user methods"
},
{
"name": "Products",
"description": "Products methods"
},
{
"name": "Users",
"description": "Access to user methods"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,15 @@ paths:
schema:
type: integer
example: 5
-
name: x-fields-params
in: header
description: 'JSON array - list of fields to be returned in the specified way'
required: false
content:
application/json:
schema:
$ref: '#/components/schemas/Fields-Settings'
responses:
'200':
description: 'Gets data for the record'
Expand Down Expand Up @@ -486,6 +495,15 @@ paths:
links:
GetRecordById:
$ref: '#/components/links/GetRecordById'
'406':
description: 'No input data'
content:
application/json:
schema:
$ref: '#/components/schemas/Exception'
application/xml:
schema:
$ref: '#/components/schemas/Exception'
security:
-
basicAuth: []
Expand Down Expand Up @@ -540,7 +558,7 @@ paths:
tags:
- BaseModule
summary: 'Create record'
description: 'Gets data to save record'
description: 'Create new record'
operationId: ea3b9bea091cbde741323b5393901825
parameters:
-
Expand Down Expand Up @@ -580,6 +598,15 @@ paths:
links:
GetRecordById:
$ref: '#/components/links/GetRecordById'
'406':
description: 'No input data'
content:
application/json:
schema:
$ref: '#/components/schemas/Exception'
application/xml:
schema:
$ref: '#/components/schemas/Exception'
security:
-
basicAuth: []
Expand Down Expand Up @@ -1280,7 +1307,7 @@ paths:
- Users
summary: 'Data for the user'
description: 'Gets details about the user'
operationId: 5de1069868c749968f98e50485b6f084
operationId: getUser
parameters:
-
name: userId
Expand Down Expand Up @@ -1340,6 +1367,57 @@ paths:
basicAuth: []
ApiKeyAuth: []
token: []
/webservice/WebserviceStandard/Users/Record:
post:
tags:
- Users
summary: 'Create user'
description: 'Create new user'
operationId: b2550c068a0148252c584ed08f9d7fae
parameters:
-
name: X-ENCRYPTED
in: header
required: true
schema:
$ref: '#/components/schemas/Header-Encrypted'
requestBody:
description: 'Contents of the request contains an associative array with the user data.'
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/User_Create_Details'
application/xml:
schema:
$ref: '#/components/schemas/User_Create_Details'
responses:
'200':
description: 'Contents of the response contains only id'
content:
application/json:
schema:
$ref: '#/components/schemas/User_Post_Record_Response'
application/xml:
schema:
$ref: '#/components/schemas/User_Post_Record_Response'
links:
GetUserById:
$ref: '#/components/links/GetUserById'
'406':
description: 'No input data'
content:
application/json:
schema:
$ref: '#/components/schemas/Exception'
application/xml:
schema:
$ref: '#/components/schemas/Exception'
security:
-
basicAuth: []
ApiKeyAuth: []
token: []
/webservice/WebserviceStandard/Users/RecordsList:
get:
tags:
Expand Down Expand Up @@ -1988,7 +2066,6 @@ components:
type: object
BaseModule_Privileges_ResponseBody:
title: 'Base module - Privileges response schema'
description: 'Get privileges for module.'
properties:
status:
description: 'A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error'
Expand All @@ -2008,9 +2085,15 @@ components:
description: Action
type: boolean
type: object
Fields-Settings:
title: 'Custom field settings'
description: 'A list of custom parameters that can affect the return value of a given field.'
type: object
example:
password:
showHiddenData: true
BaseModule_Get_Record_Response:
title: 'Base module - Response body for Record'
description: 'Get record detail.'
required:
- status
- result
Expand Down Expand Up @@ -2424,7 +2507,6 @@ components:
type: object
Users_Get_AccessActivityHistory_Response:
title: 'Users module - History of access activity data'
description: 'Get user history of access activity.'
required:
- status
- result
Expand Down Expand Up @@ -2474,7 +2556,6 @@ components:
type: object
Users_Put_ChangePassword_Response:
title: 'Users module - Users password change response body'
description: 'Put method.'
required:
- status
- result
Expand Down Expand Up @@ -2708,7 +2789,6 @@ components:
type: object
Exception:
title: 'General - Error exception'
description: 'Post method.'
required:
- status
- error
Expand Down Expand Up @@ -2768,7 +2848,6 @@ components:
type: object
Users_Get_Record_Response:
title: 'Users module - Response body for user'
description: 'Get user detail.'
properties:
status:
description: 'A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error'
Expand Down Expand Up @@ -2816,6 +2895,52 @@ components:
type: object
type: object
type: object
User_Post_Record_Response:
title: 'User - Created user'
description: 'Contents of the response contains only id and name'
required:
- status
- result
properties:
status:
description: 'A numeric value of 0 or 1 that indicates whether the communication is valid. 1 - success , 0 - error'
type: integer
enum:
- 0
- 1
result:
title: 'User data'
description: 'Created user id and name.'
required:
- id
- name
properties:
id:
description: 'Id of the newly created user'
type: integer
example: 22
name:
description: 'Id of the newly created user'
type: string
example: 'YetiForce Name'
skippedData:
description: 'List of parameters passed in the request that were skipped in the write process'
type: object
type: object
type: object
User_Create_Details:
title: 'General - User create details'
description: 'User data in user format for create view'
type: object
example:
user_name: tom
first_name: Tom
last_name: Kowalski
roleid: H38
password: MyFunP@ssword
confirm_password: MyFunP@ssword
email1: my@email.com
language: en-US
Users_RecordsList_ResponseBody:
title: 'Users module - Response action users list'
description: 'Module action record list response body'
Expand Down Expand Up @@ -2862,7 +2987,6 @@ components:
type: object
Users_Post_ResetPassword_Response:
title: 'Users module - Users password reset response body'
description: 'Post method.'
required:
- status
- result
Expand Down Expand Up @@ -2899,7 +3023,6 @@ components:
type: object
Users_Put_ResetPassword_Response:
title: 'Users module - Users password reset response body'
description: 'Put method.'
required:
- status
- result
Expand All @@ -2917,7 +3040,6 @@ components:
type: object
Users_Get_TwoFactorAuth_Response:
title: 'Users module - Authentication secret details'
description: 'Get two factor authentication details.'
required:
- status
- result
Expand Down Expand Up @@ -2991,16 +3113,18 @@ components:
parameters:
recordId: '$response.body#/result/id'
description: 'The `id` value returned in the response can be used as the `recordId` parameter in `GET /webservice/{moduleName}/Record/{recordId}`.'
GetUserById:
operationId: getUser
parameters:
recordId: '$response.body#/result/id'
description: 'The `id` value returned in the response can be used as the `userId` parameter in `GET /webservice/Users/Record/{userId}`.'
tags:
-
name: BaseModule
description: 'Access to record methods'
-
name: BaseAction
description: 'Access to user methods'
-
name: Products
description: 'Products methods'
-
name: Users
description: 'Access to user methods'
22 changes: 10 additions & 12 deletions api/webservice/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
*
* @package API
*
* @copyright YetiForce Sp. z o.o
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
* @author Radosław Skrzypczak <r.skrzypczak@yetiforce.com>
*/
Expand Down Expand Up @@ -84,22 +84,20 @@ public function preProcess(): bool
$this->response->setAcceptableMethods($handler->allowedMethod);
return false;
}
$this->app = Core\Auth::init($this);
$this->app['tables'] = Core\Containers::$listTables[$this->app['type']] ?? [];
if ($this->app['type'] !== $this->request->getByType('_container', 'Alnum')) {
throw new Core\Exception('Invalid api type', 404);
}

$this->headers = $this->request->getHeaders();
Core\Auth::init($this);
if (empty($this->app)) {
throw new Core\Exception('Web service - Applications: Unauthorized', 401);
}
$this->app['tables'] = Core\Containers::$listTables[$this->app['type']] ?? [];
if (!empty($this->app['ips']) && !\in_array(\App\RequestUtil::getRemoteIP(true), array_map('trim', explode(',', $this->app['ips'])))) {
throw new Core\Exception('Illegal IP address', 401);
}
if ($this->headers['x-api-key'] !== \App\Encryption::getInstance()->decrypt($this->app['api_key'])) {
throw new Core\Exception('Invalid api key', 401);
}
if (empty($this->request->getByType('action', 'Alnum'))) {
if ($this->request->isEmpty('action', true)) {
throw new Core\Exception('No action', 404);
}
\App\Process::$processName = $this->request->getByType('action', 'Alnum');
\App\Process::$processName = $this->request->getByType('action', \App\Purifier::ALNUM);
\App\Process::$processType = $this->app['type'];
return true;
}
Expand Down
18 changes: 12 additions & 6 deletions api/webservice/Core/Auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
*
* @package API
*
* @copyright YetiForce Sp. z o.o
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
* @author Radosław Skrzypczak <r.skrzypczak@yetiforce.com>
*/

namespace Api\Core;
Expand All @@ -28,15 +29,20 @@ class Auth
*
* @param \Api\Controller $controller
*
* @return array
* @return Auth\AbstractAuth
*/
public static function init(\Api\Controller $controller): array
public static function init(\Api\Controller $controller): Auth\AbstractAuth
{
$method = \App\Config::api('AUTH_METHOD');
$class = "Api\\Core\\Auth\\$method";
$container = $controller->request->getByType('_container', \App\Purifier::STANDARD);
$class = "Api\\{$container}\\Auth\\{$method}";
if (!class_exists($class)) {
$class = "Api\\Core\\Auth\\{$method}";
}
$self = new $class();
$self->setApi($controller);
$self->setServer();
$self->authenticate(static::$realm);
return $self->getCurrentServer();
return $self;
}
}
17 changes: 6 additions & 11 deletions api/webservice/Core/Auth/AbstractAuth.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
*
* @package API
*
* @copyright YetiForce Sp. z o.o
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
* @author Radosław Skrzypczak <r.skrzypczak@yetiforce.com>
*/

namespace Api\Core\Auth;
Expand All @@ -16,9 +17,6 @@
*/
abstract class AbstractAuth
{
/** @var array Current server details (w_#__servers) */
protected $currentServer;

/** @var \Api\Controller Controller instance */
protected $api;

Expand Down Expand Up @@ -46,12 +44,9 @@ public function setApi(\Api\Controller $api): void
abstract protected function authenticate(string $realm): bool;

/**
* Get current server details.
* Set server data.
*
* @return array
* @return self
*/
public function getCurrentServer(): array
{
return $this->currentServer;
}
abstract protected function setServer(): self;
}
43 changes: 27 additions & 16 deletions api/webservice/Core/Auth/Basic.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
*
* @package API
*
* @copyright YetiForce Sp. z o.o
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
* @author Radosław Skrzypczak <r.skrzypczak@yetiforce.com>
*/

namespace Api\Core\Auth;
Expand All @@ -23,32 +24,42 @@ public function authenticate(string $realm): bool
$this->api->response->addHeader('WWW-Authenticate', 'Basic realm="' . $realm . '"');
throw new \Api\Core\Exception('Web service - Applications: Unauthorized', 401);
}
if (!$this->validatePass($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) {
if (!$this->api->app || !$this->validatePwd($_SERVER['PHP_AUTH_PW'])) {
$this->api->response->addHeader('WWW-Authenticate', 'Basic realm="' . $realm . '"');
throw new \Api\Core\Exception('Web service - Applications: Wrong Credentials', 401);
}
$apiKey = $this->api->request->getHeaders()['x-api-key'] ?? null;
if (!$apiKey || $apiKey !== \App\Encryption::getInstance()->decrypt($this->api->app['api_key'])) {
throw new \Api\Core\Exception('Invalid api key', 401);
}

return true;
}

/** {@inheritdoc} */
public function setServer(): self
{
$this->api->app = [];
$userName = $_SERVER['PHP_AUTH_USER'] ?? '';
$type = $this->api->request->getByType('_container', \App\Purifier::STANDARD);
$query = (new \App\Db\Query())->from('w_#__servers')->where(['type' => $type, 'name' => $userName, 'status' => 1]);
if ($userName && $row = $query->one()) {
$row['id'] = (int) $row['id'];
$this->api->app = $row;
}

return $this;
}

/**
* Validate pass.
* Validate pwd.
*
* @param string $userName
* @param string $password
*
* @return bool
*/
public function validatePass(string $userName, string $password): bool
public function validatePwd(string $password): bool
{
$row = (new \App\Db\Query())->from('w_#__servers')->where(['name' => $userName, 'status' => 1])->one();
if ($row) {
$status = $password === \App\Encryption::getInstance()->decrypt($row['pass']);
if ($status) {
$row['id'] = (int) $row['id'];
$this->currentServer = $row;
}
return $status;
}
return false;
return $this->api->app && $password === \App\Encryption::getInstance()->decrypt($this->api->app['pass']);
}
}
55 changes: 0 additions & 55 deletions api/webservice/Core/Auth/Digest.php

This file was deleted.

26 changes: 8 additions & 18 deletions api/webservice/Core/BaseAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
*
* @package API
*
* @copyright YetiForce Sp. z o.o
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
*/

Expand Down Expand Up @@ -189,31 +189,21 @@ public function getUserStorageId(): ?int
return $this->userData['istorage'] ?? null;
}

/**
* Get information, whether to check inventory levels.
*
* @return bool
*/
public function getCheckStockLevels(): bool
{
$parentId = \Api\WebservicePremium\Privilege::USER_PERMISSIONS !== $this->getPermissionType() ? $this->getParentCrmId() : 0;
return empty($parentId) || (bool) \Vtiger_Record_Model::getInstanceById($parentId)->get('check_stock_levels');
}

/**
* Get parent record.
*
* @throws \Api\Core\Exception
*
* @return int
* @return int|null
*/
public function getParentCrmId(): int
public function getParentCrmId(): ?int
{
if ($this->controller && ($parentId = $this->controller->request->getHeader('x-parent-id'))) {
$hierarchy = new \Api\WebservicePremium\BaseModule\Hierarchy();
$hierarchy->setAllUserData($this->userData);
$hierarchy->findId = $parentId;
$hierarchy->moduleName = \App\Record::getType(\App\Record::getParentRecord($this->getUserCrmId()));
$parentRecord = \App\Record::getParentRecord($this->getUserCrmId());
$hierarchy->moduleName = $parentRecord ? '' : \App\Record::getType($parentRecord);
$records = $hierarchy->get();
if (isset($records[$parentId])) {
return $parentId;
Expand Down Expand Up @@ -299,7 +289,7 @@ public function updateSession(array $data = []): void
$data['ip'] = $this->controller->request->getServer('REMOTE_ADDR');
$data['parent_id'] = $this->controller->request->getHeader('x-parent-id') ?: 0;
$data['last_method'] = $this->controller->request->getServer('REQUEST_URI');
$data['agent'] = \App\TextParser::textTruncate($this->controller->request->getServer('HTTP_USER_AGENT', '-'), 100, false);
$data['agent'] = \App\TextUtils::textTruncate($this->controller->request->getServer('HTTP_USER_AGENT', '-'), 100, false);
\App\Db::getInstance('webservice')->createCommand()
->update($this->controller->app['tables']['session'], $data, ['id' => $this->userData['sid']])
->execute();
Expand All @@ -317,7 +307,7 @@ public function updateUser(array $data = []): void
if (!\is_array($this->userData['custom_params'])) {
$this->userData['custom_params'] = \App\Json::isEmpty($this->userData['custom_params']) ? [] : \App\Json::decode($this->userData['custom_params']);
}
$this->userData['custom_params']['agent'] = \App\TextParser::textTruncate($this->controller->request->getServer('HTTP_USER_AGENT', '-'), 100, false);
$this->userData['custom_params']['agent'] = \App\TextUtils::textTruncate($this->controller->request->getServer('HTTP_USER_AGENT', '-'), 100, false);
if (isset($data['custom_params'])) {
$data['custom_params'] = \App\Json::encode(\App\Utils::merge($this->userData['custom_params'], $data['custom_params']));
}
Expand Down
11 changes: 7 additions & 4 deletions api/webservice/Core/Containers.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
*
* @package API
*
* @copyright YetiForce Sp. z o.o
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
* @author Radosław Skrzypczak <r.skrzypczak@yetiforce.com>
*/
Expand All @@ -19,12 +19,12 @@ class Containers
{
/** @var string[] List of available API containers */
public static $list = [
'WebserviceStandard', 'WebservicePremium', 'ManageConsents',
'WebserviceStandard', 'WebservicePremium', 'ManageConsents', 'SMS',
];

/** @var string[] List of GUI tabs */
public static $listTab = [
'WebserviceStandard', 'WebservicePremium', 'ManageConsents',
'WebserviceStandard', 'WebservicePremium', 'ManageConsents', 'SMS',
];

/** @var array List of db tables */
Expand All @@ -42,5 +42,8 @@ class Containers
'ManageConsents' => [
'user' => 'w_#__manage_consents_user',
],
'SMS' => [
'user' => 'w_#__sms_user',
],
];
}
4 changes: 2 additions & 2 deletions api/webservice/Core/Exception.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
*
* @package API
*
* @copyright YetiForce Sp. z o.o
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
*/

Expand Down
4 changes: 2 additions & 2 deletions api/webservice/Core/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
*
* @package API
*
* @copyright YetiForce Sp. z o.o
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
*/

Expand Down
9 changes: 4 additions & 5 deletions api/webservice/Core/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
*
* @package API
*
* @copyright YetiForce Sp. z o.o
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
* @author Radosław Skrzypczak <r.skrzypczak@yetiforce.com>
*/
Expand Down Expand Up @@ -95,7 +95,7 @@ private function contentParse(string $content): array
{
$type = $this->contentType;
if (!empty($type)) {
$type = explode('/', $type);
$type = explode('/', (explode(';', $type)[0]));
$type = array_pop($type);
}
$return = [];
Expand All @@ -105,8 +105,7 @@ private function contentParse(string $content): array
break;
case 'form-data':
case 'x-www-form-urlencoded':
mb_parse_str($content, $data);
$return = $data;
$return = \Notihnio\MultipartFormDataParser\MultipartFormDataParser::parse()->params;
break;
}
return $this->content = $return;
Expand Down
6 changes: 3 additions & 3 deletions api/webservice/Core/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
*
* @package API
*
* @copyright YetiForce Sp. z o.o
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
*/

Expand Down Expand Up @@ -114,7 +114,7 @@ public function setReasonPhrase(string $reasonPhrase): void
/**
* Set body data.
*
* @param array|\App\Fields\File $body
* @param array $body
*
* @return void
*/
Expand Down
6 changes: 3 additions & 3 deletions api/webservice/Core/Traits/LoginHistory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
*
* @package API
*
* @copyright YetiForce Sp. z o.o
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
*/

Expand All @@ -30,7 +30,7 @@ protected function saveLoginHistory(array $data): void
->insert($this->controller->app['tables']['loginHistory'], array_merge([
'time' => date('Y-m-d H:i:s'),
'ip' => $this->controller->request->getServer('REMOTE_ADDR'),
'agent' => \App\TextParser::textTruncate($this->controller->request->getServer('HTTP_USER_AGENT', '-'), 100, false),
'agent' => \App\TextUtils::textTruncate($this->controller->request->getServer('HTTP_USER_AGENT', '-'), 100, false),
'user_name' => $this->controller->request->has('userName') ? $this->controller->request->get('userName') : $this->getUserData('user_name'),
'user_id' => $this->getUserData('id'),
],
Expand Down
14 changes: 7 additions & 7 deletions api/webservice/Core/TwoFactorAuth.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
*
* @package API
*
* @copyright YetiForce Sp. z o.o
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
*/

namespace Api\Core;

use Sonata\GoogleAuthenticator\GoogleAuthenticator;
use PragmaRX\Google2FA\Google2FA;

/**
* Two Factor Authorization class.
Expand Down Expand Up @@ -68,14 +68,14 @@ public function generate(): array
{
return [
'authMethods' => 'TOTP',
'secretKey' => (new GoogleAuthenticator())->generateSecret(),
'secretKey' => (new Google2FA())->generateSecretKey(),
];
}

/**
* Get details.
*
* @return string
* @return array
*/
public function details(): array
{
Expand Down Expand Up @@ -109,7 +109,7 @@ public function activate(): string
{
$code = $this->action->controller->request->getByType('code', \App\Purifier::ALNUM);
$secret = $this->action->controller->request->getByType('secret', \App\Purifier::ALNUM);
if (!(new GoogleAuthenticator())->checkCode($secret, (string) $code)) {
if (!(new Google2FA())->verifyKey($secret, (string) $code)) {
return \App\Language::translate('ERR_INCORRECT_2FA_TOTP_CODE', 'Other.Exceptions');
}
$this->action->updateUser([
Expand All @@ -130,7 +130,7 @@ public function activate(): string
public function verify(): void
{
$auth = $this->action->getUserData('auth');
if (!(new GoogleAuthenticator())->checkCode($auth['authy_secret_key'], (string) $this->action->controller->request->get('code'))) {
if (!(new Google2FA())->verifyKey($auth['authy_secret_key'], (string) $this->action->controller->request->get('code'))) {
throw new \Exception('Incorrect 2FA TOTP code');
}
}
Expand Down
14 changes: 8 additions & 6 deletions api/webservice/ManageConsents/Approvals/RecordsList.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
/**
* Gets list of records.
*
* @package Api
* @package API
*
* @copyright YetiForce Sp. z o.o
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Radosław Skrzypczak <r.skrzypczak@yetiforce.com>
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
*/
Expand Down Expand Up @@ -160,6 +160,7 @@ class RecordsList extends \Api\ManageConsents\BaseAction
public function get()
{
$rawData = $records = [];
$showRaw = $this->isRawData();
$queryGenerator = $this->getQuery();

$limit = $queryGenerator->getLimit() - 1;
Expand All @@ -178,10 +179,11 @@ public function get()
$records[$recordModel->getId()]['id'] = $recordModel->getId();
foreach ($fields as $fieldName => $fieldModel) {
$records[$recordModel->getId()][$fieldName] = $fieldModel->getUITypeModel()->getApiDisplayValue($row[$fieldName], $recordModel);
if ($showRaw) {
$rawData[$recordModel->getId()] = $recordModel->getRawValue($fieldName);
}
}
if ($this->isRawData()) {
$rawData[$recordModel->getId()] = $row;
}

if ($limit === $count) {
break;
}
Expand Down
6 changes: 3 additions & 3 deletions api/webservice/ManageConsents/ApprovalsRegister/Record.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
/**
* The file contains: Record operations.
*
* @package Api
* @package API
*
* @copyright YetiForce Sp. z o.o
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Radosław Skrzypczak <r.skrzypczak@yetiforce.com>
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
*/
Expand Down
6 changes: 3 additions & 3 deletions api/webservice/ManageConsents/BaseAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
/**
* Api actions.
*
* @package Api
* @package API
*
* @copyright YetiForce Sp. z o.o.
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Radosław Skrzypczak <r.skrzypczak@yetiforce.com>
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
/**
* Gets list of records.
*
* @package Api
* @package API
*
* @copyright YetiForce Sp. z o.o
* @license YetiForce Public License 4.0 (licenses/LicenseEN.txt or yetiforce.com)
* @copyright YetiForce S.A.
* @license YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
* @author Radosław Skrzypczak <r.skrzypczak@yetiforce.com>
* @author Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
*/
Expand Down
Loading