diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..f4cab784eb --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +.git +/vendor +/docs \ No newline at end of file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..6d70ac906d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +# This file is for unifying the coding style for different editors and IDEs. +# More information at http://EditorConfig.org + +# Set this file as the root +root = true + +# Global settings for all files +[*] +indent_style = space +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +# PHP files +[*.php] +indent_size = 4 + +# Frontend files +[*.{css,html,js,less,sass,scss}] +indent_size = 2 diff --git a/.github/workflows/composer-validate.yml b/.github/workflows/composer-validate.yml index 869b13d00d..07bd51ee4e 100644 --- a/.github/workflows/composer-validate.yml +++ b/.github/workflows/composer-validate.yml @@ -6,8 +6,8 @@ name: Validate Composer dependencies on: pull_request: branches: - - alpha - + - 'develop' + jobs: build-test: runs-on: ubuntu-latest diff --git a/.github/workflows/docker-test.yml b/.github/workflows/docker-test.yml index ac272915bc..62b2613362 100644 --- a/.github/workflows/docker-test.yml +++ b/.github/workflows/docker-test.yml @@ -7,19 +7,18 @@ on: # only trigger CI when pull request on following branches pull_request: branches: - - 'alpha' + - 'develop' # this is to manually trigger the worklow workflow_dispatch: inputs: logLevel: - description: 'Reason' + description: 'Reason' default: 'Manual launch' jobs: buildAndTestDockerImg: runs-on: ubuntu-latest steps: - - name: Check Out Repo # Check out the repo, using current branch # https://github.com/marketplace/actions/checkout @@ -35,6 +34,7 @@ jobs: docker run -p 80:80 -d --rm --name jeedom_bullseye jeedom:bullseye sleep 45 docker exec jeedom_bullseye php sick.php + - name: Build jeedom:bookworm # build current image for bookworm run: | @@ -45,7 +45,7 @@ jobs: docker run -p 81:80 -d --rm --name jeedom_bookworm jeedom:bookworm sleep 45 docker exec jeedom_bookworm php sick.php - + - name: Clean docker image continue-on-error: true run: | diff --git a/.github/workflows/phpstan.yaml b/.github/workflows/phpstan.yaml index 8d90800544..be829bf51c 100644 --- a/.github/workflows/phpstan.yaml +++ b/.github/workflows/phpstan.yaml @@ -2,29 +2,31 @@ name: PHPStan on: push: - branches: [ alpha ] + branches: [ develop ] pull_request: - branches: [ alpha ] + branches: [ develop ] jobs: phpstan: runs-on: ubuntu-latest + # define every php version to test + strategy: + # do not stop at first fail + fail-fast: false + matrix: + php: [7.4, 8.2] + steps: - uses: actions/checkout@v4 - - name: Setup PHP 7.4 for dependencies + - name: Setup PHP ${{ matrix.php }} for dependencies uses: shivammathur/setup-php@v2 with: - php-version: 7.4 + php-version: ${{ matrix.php }} - name: Install Dependencies run: composer update --ignore-platform-reqs - - name: Setup PHP 8.2 for PHPStan - uses: shivammathur/setup-php@v2 - with: - php-version: 8.2 - - name: Restore PHPStan cache id: cache-phpstan uses: actions/cache/restore@v3 @@ -32,16 +34,12 @@ jobs: path: phpstan.phar key: phpstan-1 - - name: Download PHPStan - if: steps.cache-phpstan.outputs.cache-hit != 'true' - run: wget https://github.com/phpstan/phpstan/releases/latest/download/phpstan.phar - - name: Run PHPStan - run: php phpstan.phar analyse --configuration phpstan.neon + run: vendor/bin/phpstan analyse --configuration phpstan.neon update-baseline: needs: phpstan - if: github.event_name == 'push' && github.ref == 'refs/heads/alpha' + if: github.event_name == 'push' && github.ref == 'refs/heads/develop' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -50,7 +48,7 @@ jobs: - name: Delete existing branch if exists run: | - if git ls-remote --heads origin update-phpstan-baseline | grep update-phpstan-baseline; then + if git ls-remote --heads origin update-phpstan-baseline | grep -q update-phpstan-baseline; then git push origin --delete update-phpstan-baseline fi @@ -62,19 +60,11 @@ jobs: - name: Install Dependencies run: composer update --ignore-platform-reqs - - name: Setup PHP 8.2 for PHPStan - uses: shivammathur/setup-php@v2 - with: - php-version: 8.2 - - - name: Download PHPStan - run: wget https://github.com/phpstan/phpstan/releases/latest/download/phpstan.phar - - name: Generate new baseline id: generate-baseline run: | cp phpstan-baseline.neon phpstan-baseline.neon.old - php phpstan.phar analyse --configuration phpstan.neon --generate-baseline + vendor/bin/phpstan analyse --configuration phpstan.neon --generate-baseline if ! diff -q phpstan-baseline.neon phpstan-baseline.neon.old > /dev/null; then echo "baseline_changed=true" >> $GITHUB_OUTPUT fi @@ -87,10 +77,10 @@ jobs: title: '[CI] Update PHPStan baseline' body: | Mise à jour automatique du baseline PHPStan suite à la correction d'erreurs. - + Cette PR a été générée automatiquement par le workflow CI/CD. branch: update-phpstan-baseline - base: alpha + base: develop delete-branch: true add-paths: | phpstan-baseline.neon diff --git a/.github/workflows/translations.yml b/.github/workflows/translations.yml new file mode 100644 index 0000000000..e27b7cd9dd --- /dev/null +++ b/.github/workflows/translations.yml @@ -0,0 +1,18 @@ +name: translate + +on: + workflow_dispatch: + push: + branches: + - develop + +jobs: + auto-translate: + runs-on: ubuntu-latest + steps: + - uses: jeedom/jeetranslate@main + with: + deepl_api_key: ${{ secrets.DEEPL_API_KEY }} + include_empty_translation: false + target_languages: "en_US,es_ES,de_DE,it_IT,pt_PT" + use_core_translations: true \ No newline at end of file diff --git a/.github/workflows/work.yml b/.github/workflows/work.yml index 9db6932f30..960eb4e76c 100644 --- a/.github/workflows/work.yml +++ b/.github/workflows/work.yml @@ -2,12 +2,10 @@ on: # Workflows check plugin Jeedom push: branches: - - alpha - - beta + - develop pull_request: branches: - - alpha - - beta + - develop - master name : 'Test Core Jeedom' diff --git a/Dockerfile b/Dockerfile index 37a75bffed..4628ef8761 100644 --- a/Dockerfile +++ b/Dockerfile @@ -44,18 +44,18 @@ RUN apt -o Dpkg::Options::="--force-confdef" -y install software-properties-comm php libapache2-mod-php php-json php-mysql php-curl php-gd php-imap php-xml php-opcache php-soap php-xmlrpc \ php-common php-dev php-zip php-ssh2 php-mbstring php-ldap php-yaml php-snmp && apt -y remove brltty -COPY install/install.sh /tmp/ -RUN sh /tmp/install.sh -s 1 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker -RUN sh /tmp/install.sh -s 2 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker -RUN sh /tmp/install.sh -s 3 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker -RUN sh /tmp/install.sh -s 4 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker -RUN sh /tmp/install.sh -s 5 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker +COPY --chown=root:root --chmod=550 install/install.sh /root/ +RUN sh /root/install.sh -s 1 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker +RUN sh /root/install.sh -s 2 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker +RUN sh /root/install.sh -s 3 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker +RUN sh /root/install.sh -s 4 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker +RUN sh /root/install.sh -s 5 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker COPY . ${WEBSERVER_HOME} -RUN sh /tmp/install.sh -s 7 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker -RUN sh /tmp/install.sh -s 8 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker -RUN sh /tmp/install.sh -s 9 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker -RUN sh /tmp/install.sh -s 10 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker -RUN sh /tmp/install.sh -s 11 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker +RUN sh /root/install.sh -s 7 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker +RUN sh /root/install.sh -s 8 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker +RUN sh /root/install.sh -s 9 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker +RUN sh /root/install.sh -s 10 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker +RUN sh /root/install.sh -s 11 -v ${VERSION} -w ${WEBSERVER_HOME} -d ${DATABASE} -i docker RUN apt-get clean && rm -rf /var/lib/apt/lists/* RUN echo >${WEBSERVER_HOME}/initialisation diff --git a/composer.json b/composer.json index 25d7fc3830..8bd5350b62 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,6 @@ { "require": { + "abbadon1334/sun-position-spa-php" : "^2", "dragonmantank/cron-expression": "^3", "symfony/expression-language": "5 - 7", "pragmarx/google2fa-qrcode": "^3", @@ -15,5 +16,8 @@ "platform": { "php": "7.4" } + }, + "require-dev": { + "phpstan/phpstan": "^2.1" } } diff --git a/composer.lock b/composer.lock index b78c8572c4..96e13482b3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,59 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6d3817ee337cc5ed162b1e9463030e8a", + "content-hash": "6f406f5b318ce2f2efbbed9597706668", "packages": [ + { + "name": "abbadon1334/sun-position-spa-php", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/abbadon1334/sun-position-spa-php.git", + "reference": "26244d51284ae80061dc21f26d4b1c31672354bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/abbadon1334/sun-position-spa-php/zipball/26244d51284ae80061dc21f26d4b1c31672354bf", + "reference": "26244d51284ae80061dc21f26d4b1c31672354bf", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "require-dev": { + "codacy/coverage": "dev-master", + "friendsofphp/php-cs-fixer": "dev-master@dev", + "phpmd/phpmd": "2.6.0", + "phpmetrics/phpmetrics": "dev-master@dev", + "phpstan/phpstan": "0.11.5", + "phpunit/phpunit": "*", + "squizlabs/php_codesniffer": "3.4.2", + "symfony/yaml": "~2.1|~3.0|~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "SolarData\\": "src/", + "SolarData\\Tests\\": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Francesco Danti", + "email": "fdanti@gmail.com" + } + ], + "description": "solar data calculation and sun position", + "support": { + "issues": "https://github.com/abbadon1334/sun-position-spa-php/issues", + "source": "https://github.com/abbadon1334/sun-position-spa-php/tree/master" + }, + "time": "2019-07-08T09:51:15+00:00" + }, { "name": "bacon/bacon-qr-code", "version": "2.0.8", @@ -128,16 +179,16 @@ }, { "name": "dasprid/enum", - "version": "1.0.6", + "version": "1.0.7", "source": { "type": "git", "url": "https://github.com/DASPRiD/Enum.git", - "reference": "8dfd07c6d2cf31c8da90c53b83c026c7696dda90" + "reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/8dfd07c6d2cf31c8da90c53b83c026c7696dda90", - "reference": "8dfd07c6d2cf31c8da90c53b83c026c7696dda90", + "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/b5874fa9ed0043116c72162ec7f4fb50e02e7cce", + "reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce", "shasum": "" }, "require": { @@ -172,35 +223,34 @@ ], "support": { "issues": "https://github.com/DASPRiD/Enum/issues", - "source": "https://github.com/DASPRiD/Enum/tree/1.0.6" + "source": "https://github.com/DASPRiD/Enum/tree/1.0.7" }, - "time": "2024-08-09T14:30:48+00:00" + "time": "2025-09-16T12:23:56+00:00" }, { "name": "dragonmantank/cron-expression", - "version": "v3.4.0", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/dragonmantank/cron-expression.git", - "reference": "8c784d071debd117328803d86b2097615b457500" + "reference": "1b2de7f4a468165dca07b142240733a1973e766d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/8c784d071debd117328803d86b2097615b457500", - "reference": "8c784d071debd117328803d86b2097615b457500", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/1b2de7f4a468165dca07b142240733a1973e766d", + "reference": "1b2de7f4a468165dca07b142240733a1973e766d", "shasum": "" }, "require": { - "php": "^7.2|^8.0", - "webmozart/assert": "^1.0" + "php": "^7.2|^8.0" }, "replace": { "mtdowling/cron-expression": "^1.0" }, "require-dev": { - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.0", - "phpunit/phpunit": "^7.0|^8.0|^9.0" + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.32|^2.1.31", + "phpunit/phpunit": "^8.5.48|^9.0" }, "type": "library", "extra": { @@ -231,7 +281,7 @@ ], "support": { "issues": "https://github.com/dragonmantank/cron-expression/issues", - "source": "https://github.com/dragonmantank/cron-expression/tree/v3.4.0" + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.5.0" }, "funding": [ { @@ -239,20 +289,20 @@ "type": "github" } ], - "time": "2024-10-09T13:47:03+00:00" + "time": "2025-10-31T18:36:32+00:00" }, { "name": "influxdata/influxdb-client-php", - "version": "3.6.0", + "version": "3.8.0", "source": { "type": "git", "url": "https://github.com/influxdata/influxdb-client-php.git", - "reference": "3606b12214508f22126b7ed0565d53380674312a" + "reference": "59ac11d63ce030973c79d5b05797813761a0d58e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/influxdata/influxdb-client-php/zipball/3606b12214508f22126b7ed0565d53380674312a", - "reference": "3606b12214508f22126b7ed0565d53380674312a", + "url": "https://api.github.com/repos/influxdata/influxdb-client-php/zipball/59ac11d63ce030973c79d5b05797813761a0d58e", + "reference": "59ac11d63ce030973c79d5b05797813761a0d58e", "shasum": "" }, "require": { @@ -287,22 +337,22 @@ ], "support": { "issues": "https://github.com/influxdata/influxdb-client-php/issues", - "source": "https://github.com/influxdata/influxdb-client-php/tree/3.6.0" + "source": "https://github.com/influxdata/influxdb-client-php/tree/3.8.0" }, - "time": "2024-06-24T10:01:53+00:00" + "time": "2025-06-26T05:12:59+00:00" }, { "name": "paragonie/constant_time_encoding", - "version": "v2.7.0", + "version": "v2.8.2", "source": { "type": "git", "url": "https://github.com/paragonie/constant_time_encoding.git", - "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105" + "reference": "e30811f7bc69e4b5b6d5783e712c06c8eabf0226" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/52a0d99e69f56b9ec27ace92ba56897fe6993105", - "reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/e30811f7bc69e4b5b6d5783e712c06c8eabf0226", + "reference": "e30811f7bc69e4b5b6d5783e712c06c8eabf0226", "shasum": "" }, "require": { @@ -356,7 +406,7 @@ "issues": "https://github.com/paragonie/constant_time_encoding/issues", "source": "https://github.com/paragonie/constant_time_encoding" }, - "time": "2024-05-08T12:18:48+00:00" + "time": "2025-09-24T15:12:37+00:00" }, { "name": "php-http/client-common", @@ -738,21 +788,21 @@ }, { "name": "pragmarx/google2fa-qrcode", - "version": "v3.0.0", + "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/antonioribeiro/google2fa-qrcode.git", - "reference": "ce4d8a729b6c93741c607cfb2217acfffb5bf76b" + "reference": "c23ebcc3a50de0d1566016a6dd1486e183bb78e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/antonioribeiro/google2fa-qrcode/zipball/ce4d8a729b6c93741c607cfb2217acfffb5bf76b", - "reference": "ce4d8a729b6c93741c607cfb2217acfffb5bf76b", + "url": "https://api.github.com/repos/antonioribeiro/google2fa-qrcode/zipball/c23ebcc3a50de0d1566016a6dd1486e183bb78e1", + "reference": "c23ebcc3a50de0d1566016a6dd1486e183bb78e1", "shasum": "" }, "require": { "php": ">=7.1", - "pragmarx/google2fa": ">=4.0" + "pragmarx/google2fa": "^4.0|^5.0|^6.0|^7.0|^8.0" }, "require-dev": { "bacon/bacon-qr-code": "^2.0", @@ -799,9 +849,9 @@ ], "support": { "issues": "https://github.com/antonioribeiro/google2fa-qrcode/issues", - "source": "https://github.com/antonioribeiro/google2fa-qrcode/tree/v3.0.0" + "source": "https://github.com/antonioribeiro/google2fa-qrcode/tree/v3.0.1" }, - "time": "2021-08-15T12:53:48+00:00" + "time": "2025-09-19T23:02:26+00:00" }, { "name": "psr/cache", @@ -1487,7 +1537,7 @@ }, { "name": "symfony/polyfill-php73", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", @@ -1543,7 +1593,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.33.0" }, "funding": [ { @@ -1554,6 +1604,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -1563,16 +1617,16 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.31.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", - "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", "shasum": "" }, "require": { @@ -1623,7 +1677,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" }, "funding": [ { @@ -1634,12 +1688,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-01-02T08:10:11+00:00" }, { "name": "symfony/service-contracts", @@ -1796,76 +1854,72 @@ } ], "time": "2024-09-25T14:11:13+00:00" - }, + } + ], + "packages-dev": [ { - "name": "webmozart/assert", - "version": "1.11.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" - }, + "name": "phpstan/phpstan", + "version": "2.1.48", "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/231397213efb7c0a066ee024b5c3c87f2d3adfa0", + "reference": "231397213efb7c0a066ee024b5c3c87f2d3adfa0", "shasum": "" }, "require": { - "ext-ctype": "*", - "php": "^7.2 || ^8.0" + "php": "^7.4|^8.0" }, "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" + "phpstan/phpstan-shim": "*" }, + "bin": [ + "phpstan", + "phpstan.phar" + ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } + "files": [ + "bootstrap.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", + "description": "PHPStan - PHP Static Analysis Tool", "keywords": [ - "assert", - "check", - "validate" + "dev", + "static analysis" ], "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.11.0" + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" }, - "time": "2022-06-03T18:03:27+00:00" + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2026-04-15T20:24:19+00:00" } ], - "packages-dev": [], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { "php": ">=7.4" }, - "platform-dev": {}, + "platform-dev": [], "platform-overrides": { "php": "7.4" }, diff --git a/core/ajax/cache.ajax.php b/core/ajax/cache.ajax.php index ee5b5baef7..bb7a56e802 100644 --- a/core/ajax/cache.ajax.php +++ b/core/ajax/cache.ajax.php @@ -28,7 +28,7 @@ if (init('action') == 'set') { unautorizedInDemo(); - cache::set(init('key'), init('value'), init('lifetime', 0), init('options', null)); + cache::set(init('key'), init('value'), init('lifetime', 0)); ajax::success(); } diff --git a/core/ajax/cmd.ajax.php b/core/ajax/cmd.ajax.php index 9b858a2dbc..6e1f905431 100644 --- a/core/ajax/cmd.ajax.php +++ b/core/ajax/cmd.ajax.php @@ -246,12 +246,12 @@ } if (init('action') == 'byEqLogic') { - if (init('typeCmd')) { - ajax::success(utils::o2a(cmd::byEqLogicId(init('eqLogic_id'), init('typeCmd')))); - } else { - ajax::success(utils::o2a(cmd::byEqLogicId(init('eqLogic_id')))); - } - } + if (init('typeCmd')) { + ajax::success(utils::o2a(cmd::byEqLogicId(init('eqLogic_id'), init('typeCmd')))); + } else { + ajax::success(utils::o2a(cmd::byEqLogicId(init('eqLogic_id')))); + } + } if (init('action') == 'getCmd') { $cmd = cmd::byId(init('id')); @@ -422,6 +422,13 @@ } $return['derive'] = $derive; $groupingType = init('groupingType'); + if (is_array($groupingType)) { + if (isset($groupingType['function']) && isset($groupingType['time'])) { + $groupingType = $groupingType['function'] . '::' . $groupingType['time']; + } else { + $groupingType = implode('::', array_values($groupingType)); + } + } if ($groupingType == '') { $groupingType = $cmd->getDisplay('groupingType'); } @@ -465,7 +472,7 @@ $data[] = $info_history; } } else { - $histories = history::getHistoryFromCalcul(jeedom::fromHumanReadable(init('id')), $dateStart, $dateEnd, init('allowZero', false), init('groupingType'), init('addFirstPreviousValue', false)); + $histories = history::getHistoryFromCalcul(jeedom::fromHumanReadable(init('id')), $dateStart, $dateEnd, init('allowZero', false), init('groupingType')); if (is_array($histories)) { foreach ($histories as $datetime => $value) { $info_history = array(); @@ -497,7 +504,7 @@ if (init('action') == 'getLastHistory') { $cmd = cmd::byId(init('id')); $_time = date('Y-m-d H:i:s', strtotime(init('time'))); - if(is_object($cmd)){ + if (is_object($cmd)) { ajax::success($cmd->getLastHistory($_time)); } else { throw new Exception(__('Nombre maximum de niveaux d’éléments affichés dans les graphiques de liens', __FILE__) . ' ' . init('id')); diff --git a/core/ajax/eqLogic.ajax.php b/core/ajax/eqLogic.ajax.php index 99f30677e3..b9479ebc2e 100644 --- a/core/ajax/eqLogic.ajax.php +++ b/core/ajax/eqLogic.ajax.php @@ -425,7 +425,7 @@ } if (count($cmdData['node']) > 0) { foreach ($cmdData['node'] as $name => $data) { - if (cmd::byId(str_replace('cmd', '', $data['id']))->getEqLogic_id() == $eqLogic->getId()) { + if (is_object(cmd::byId(str_replace('cmd', '', $data['id']))) && cmd::byId(str_replace('cmd', '', $data['id']))->getEqLogic_id() == $eqLogic->getId()) { continue; } diff --git a/core/ajax/interact.ajax.php b/core/ajax/interact.ajax.php index 31ad3f4008..cf022a81bf 100644 --- a/core/ajax/interact.ajax.php +++ b/core/ajax/interact.ajax.php @@ -30,7 +30,7 @@ $results = utils::o2a(interactDef::all()); foreach ($results as &$result) { $result['nbInteractQuery'] = count(interactQuery::byInteractDefId($result['id'])); - $result['nbEnableInteractQuery'] = count(interactQuery::byInteractDefId($result['id'], true)); + $result['nbEnableInteractQuery'] = count(interactQuery::byInteractDefId($result['id'])); if (isset($result['link_type']) && $result['link_type'] == 'cmd' && $result['link_id'] != '') { $link_id = ''; foreach (explode('&&', $result['link_id']) as $cmd_id) { @@ -49,7 +49,7 @@ if (init('action') == 'byId') { $result = utils::o2a(interactDef::byId(init('id'))); $result['nbInteractQuery'] = count(interactQuery::byInteractDefId($result['id'])); - $result['nbEnableInteractQuery'] = count(interactQuery::byInteractDefId($result['id'], true)); + $result['nbEnableInteractQuery'] = count(interactQuery::byInteractDefId($result['id'])); ajax::success(jeedom::toHumanReadable($result)); } diff --git a/core/ajax/listener.ajax.php b/core/ajax/listener.ajax.php index e0abe1d9d1..59144059eb 100644 --- a/core/ajax/listener.ajax.php +++ b/core/ajax/listener.ajax.php @@ -43,7 +43,7 @@ } if (init('action') == 'all') { - $listeners = utils::o2a(listener::all(true)); + $listeners = utils::o2a(listener::all()); foreach ($listeners as &$listener) { $listener['event_str'] = ''; foreach ($listener['event'] as $event) { diff --git a/core/ajax/object.ajax.php b/core/ajax/object.ajax.php index 43eac0e1f9..da8ec2bed6 100644 --- a/core/ajax/object.ajax.php +++ b/core/ajax/object.ajax.php @@ -231,7 +231,7 @@ function jeeAjax_objectToHtml($_id = -1, $_version = 'dashboard', $_category = ' if (!isConnect('admin')) { throw new Exception(__('401 - Accès non autorisé', __FILE__)); } - ajax::success(jeeObject::getUISelectList(init('none'), true)); + ajax::success(jeeObject::getUISelectList(init('none'))); } if (init('action') == 'getSummaryHtml') { diff --git a/core/ajax/plugin.ajax.php b/core/ajax/plugin.ajax.php index a6face2566..c5b95894d5 100644 --- a/core/ajax/plugin.ajax.php +++ b/core/ajax/plugin.ajax.php @@ -180,6 +180,21 @@ $infoPost .= ' - (' . ($daemon_info['last_launch'] ?? __('Inconnue', __FILE__)) . ')'; } + $healt = '[details="' . __('Santé', __FILE__) . '"]'; + $healt .= '
```
'; + foreach ((jeedom::health()) as $datas) { + if ($datas['state'] === 2) { + $healt .= "🟠 "; + } else if ($datas['state']) { + $healt .= "🟢 "; + } else { + $healt .= "🔴 "; + } + $healt .= $datas['name'] . ' : ' . str_replace(["\r","\n"], " ", $datas['result']) . '
'; + } + $healt .= '
```
'; + $healt .= '[/details]
'; + $infoPlugin = ''; if (method_exists($plugin_id, 'getConfigForCommunity')) { $infoPlugin .= '**' . __('Informations complémentaires', __FILE__) . '**
'; @@ -190,7 +205,7 @@ $communitUrl = 'https://community.jeedom.com'; $ressource = '/new-topic?'; - $finalBody = br2nl($header . $infoPost . $footer . $infoPlugin); + $finalBody = br2nl($header . $infoPost . $footer . $healt . $infoPlugin); $data = array( 'category' => 'plugins/' . $plugin->getCategory(), diff --git a/core/ajax/queue.ajax.php b/core/ajax/queue.ajax.php index 3e094df417..e5957904d6 100644 --- a/core/ajax/queue.ajax.php +++ b/core/ajax/queue.ajax.php @@ -43,7 +43,7 @@ } if (init('action') == 'all') { - $queues = queue::all(true); + $queues = queue::all(); foreach ($queues as $queue) { $queue->refresh(); } diff --git a/core/ajax/report.ajax.php b/core/ajax/report.ajax.php index 178b0dc16d..9d3c7b0cd7 100644 --- a/core/ajax/report.ajax.php +++ b/core/ajax/report.ajax.php @@ -61,7 +61,7 @@ foreach (ls($path, '*') as $value) { unlink($path . $value); } - ajax::success($return); + ajax::success(); } throw new Exception(__('Aucune méthode correspondante à :', __FILE__) . ' ' . init('action')); diff --git a/core/ajax/user.ajax.php b/core/ajax/user.ajax.php index 8cb6103efb..d4ebf911a0 100644 --- a/core/ajax/user.ajax.php +++ b/core/ajax/user.ajax.php @@ -52,6 +52,7 @@ throw new Exception(__('Double authentification requise', __FILE__), -32012); } if (!login(init('username'), init('password'), init('twoFactorCode'))) { + log::add('connection', 'info',network::getClientIp().' - '. __('Mot de passe ou nom d\'utilisateur incorrect', __FILE__)); throw new Exception(__('Mot de passe ou nom d\'utilisateur incorrect', __FILE__)); } } @@ -78,6 +79,7 @@ $_SESSION['user']->save(); @session_write_close(); } + log::add('connection', 'info',network::getClientIp().' - '. __('Connexion réussie pour : ', __FILE__).$_SESSION['user']->getLogin()); ajax::success(); } @@ -343,7 +345,8 @@ if (init('action') == 'removeBanIp') { unautorizedInDemo(); - ajax::success(user::removeBanIp()); + user::removeBanIp(); + ajax::success(); } if (init('action') == 'supportAccess') { diff --git a/core/ajax/view.ajax.php b/core/ajax/view.ajax.php index 033976e1de..23eff4530d 100644 --- a/core/ajax/view.ajax.php +++ b/core/ajax/view.ajax.php @@ -164,12 +164,20 @@ } unautorizedInDemo(); $components = json_decode(init('components'), true); - $sql = ''; + $allowedTypes = array('cmd', 'eqLogic', 'scenario'); foreach ($components as $component) { if (!isset($component['viewZone_id']) || !is_numeric($component['viewZone_id']) || !is_numeric($component['id']) || !is_numeric($component['viewOrder']) || (isset($component['object_id']) && !is_numeric($component['object_id']))) { continue; } - $sql .= 'UPDATE viewData SET `order`= ' . $component['viewOrder'] . ' WHERE link_id=' . $component['id'] . ' AND type="' . $component['type'] . '" AND viewZone_id=' . $component['viewZone_id'] . ';'; + if (!isset($component['type']) || !in_array($component['type'], $allowedTypes)) { + continue; + } + DB::Prepare('UPDATE viewData SET `order`= :viewOrder WHERE link_id= :id AND type= :type AND viewZone_id= :viewZone_id', array( + 'viewOrder' => $component['viewOrder'], + 'id' => $component['id'], + 'type' => $component['type'], + 'viewZone_id' => $component['viewZone_id'], + ), DB::FETCH_TYPE_ROW); if ($component['type'] == 'eqLogic') { unset($component['type']); $eqLogic = eqLogic::byId($component['id']); @@ -188,9 +196,6 @@ $scenario->save(true); } } - if ($sql != '') { - DB::Prepare($sql, array(), DB::FETCH_TYPE_ROW); - } ajax::success(); } diff --git a/core/api/jeeApi.php b/core/api/jeeApi.php index 87c2a76b37..5bb0adeec1 100644 --- a/core/api/jeeApi.php +++ b/core/api/jeeApi.php @@ -416,7 +416,7 @@ if (is_object($_USER_GLOBAL) && $_USER_GLOBAL->getProfils() != 'admin') { throw new Exception(__('Vous n\'êtes pas autorisé à effectuer cette action', __FILE__) . ' ' . $jsonrpc->getMethod(), -32001); } - jeedom::update($params['options'], 0); + jeedom::update($params['options']); $jsonrpc->makeSuccess('ok'); } @@ -1276,7 +1276,7 @@ throw new Exception(__('Vous n\'avez pas les droits de faire cette action', __FILE__), -32701); } unautorizedInDemo(); - jeedom::update('', 0); + jeedom::update(''); $jsonrpc->makeSuccess('ok'); } diff --git a/core/api/proApi.php b/core/api/proApi.php index cdf7f18ac9..1e9b781402 100644 --- a/core/api/proApi.php +++ b/core/api/proApi.php @@ -147,7 +147,7 @@ $result = jeedom::version(); $advice = ''; $productName = config::byKey('product_name'); - $health[] = array('plugin' => 'core', 'type' => 'Version '. $productName , 'defaut' => $defaut, 'result' => $result, 'advice' => $advice); + $health[] = array('plugin' => 'core', 'type' => 'Version ' . $productName, 'defaut' => $defaut, 'result' => $result, 'advice' => $advice); $defaut = 0; $result = phpversion(); @@ -199,7 +199,7 @@ $result = 'OK'; } else { $filename = __DIR__ . '/../../cache.tar.gz'; - $result = 'OK (' . date('Y-m-d H:i:s',(int) filemtime($filename)) . ')'; + $result = 'OK (' . date('Y-m-d H:i:s', (int) filemtime($filename)) . ')'; } } else { $result = 'NOK'; @@ -569,8 +569,8 @@ $jsonrpc->makeSuccess($scenario->stop()); } if ($params['state'] == 'run') { - $scenario->addTag('trigger','api'); - $scenario->addTag('trigger_message',__('Scénario exécuté sur appel API', __FILE__)); + $scenario->addTag('trigger', 'api'); + $scenario->addTag('trigger_message', __('Scénario exécuté sur appel API', __FILE__)); $jsonrpc->makeSuccess($scenario->launch()); } if ($params['state'] == 'enable') { @@ -584,147 +584,18 @@ throw new Exception(__('Le paramètre "state" ne peut être vide et doit avoir pour valeur [run,stop,enable,disable]', __FILE__)); } - /* * ************************JeeNetwork*************************** */ - if ($jsonrpc->getMethod() == 'jeeNetwork::handshake') { - if (config::byKey('jeeNetwork::mode') != 'slave') { - throw new Exception(__('Impossible d\'ajouter une box Jeedom non esclave à un réseau Jeedom', __FILE__)); - } - $auiKey = config::byKey('auiKey'); - if ($auiKey == '') { - $auiKey = config::genKey(255); - config::save('auiKey', $auiKey); - } - $return = array( - 'mode' => config::byKey('jeeNetwork::mode'), - 'nbUpdate' => update::nbNeedUpdate(), - 'version' => jeedom::version(), - 'nbMessage' => message::nbMessage(), - 'auiKey' => $auiKey, - 'jeedom::url' => config::byKey('jeedom::url'), - 'ngrok::port' => config::byKey('ngrok::port'), - ); - if (!filter_var(network::getNetworkAccess('external', 'ip'), FILTER_VALIDATE_IP) && network::getNetworkAccess('external', 'ip') != '') { - $return['jeedom::url'] = network::getNetworkAccess('internal'); - } - foreach (plugin::listPlugin(true) as $plugin) { - if ($plugin->getAllowRemote() == 1) { - $return['plugin'][] = $plugin->getId(); - } - } - $address = (isset($params['address']) && $params['address'] != '') ? $params['address'] : getClientIp(); - config::save('jeeNetwork::master::ip', $address); - config::save('jeeNetwork::master::apikey', $params['apikey_master']); - config::save('jeeNetwork::slave::id', $params['slave_id']); - if (config::byKey('internalAddr') == '') { - config::save('internalAddr', $params['slave_ip']); - } - jeeNetwork::testMaster(); - $jsonrpc->makeSuccess($return); - } + /* * ************************System*************************** */ - if ($jsonrpc->getMethod() == 'jeeNetwork::reload') { - foreach (plugin::listPlugin(true) as $plugin) { - try { - $plugin->launch('slaveReload'); - } catch (Exception $ex) { - } - } - $jsonrpc->makeSuccess('ok'); - } - - if ($jsonrpc->getMethod() == 'jeeNetwork::halt') { + if ($jsonrpc->getMethod() == 'jeedom::halt') { jeedom::haltSystem(); $jsonrpc->makeSuccess('ok'); } - if ($jsonrpc->getMethod() == 'jeeNetwork::reboot') { + if ($jsonrpc->getMethod() == 'jeedom::reboot') { jeedom::rebootSystem(); $jsonrpc->makeSuccess('ok'); } - if ($jsonrpc->getMethod() == 'jeeNetwork::update') { - jeedom::update('', 0); - $jsonrpc->makeSuccess('ok'); - } - - if ($jsonrpc->getMethod() == 'jeeNetwork::checkUpdate') { - update::checkAllUpdate(); - $jsonrpc->makeSuccess('ok'); - } - - if ($jsonrpc->getMethod() == 'jeeNetwork::receivedBackup') { - if (config::byKey('jeeNetwork::mode') == 'slave') { - throw new Exception(__('Seul un maître peut recevoir une sauvegarde', __FILE__)); - } - $jeeNetwork = jeeNetwork::byId($params['slave_id']); - if (!is_object($jeeNetwork)) { - throw new Exception(__('Aucun esclave correspondant à l\'ID :', __FILE__) . ' ' . secureXSS($params['slave_id'])); - } - if (substr(config::byKey('backup::path'), 0, 1) != '/') { - $backup_dir = __DIR__ . '/../../' . config::byKey('backup::path'); - } else { - $backup_dir = config::byKey('backup::path'); - } - $uploaddir = $backup_dir . '/slave/'; - if (!file_exists($uploaddir)) { - mkdir($uploaddir); - } - if (!file_exists($uploaddir)) { - throw new Exception(__('Répertoire de téléversement non trouvé :', __FILE__) . ' ' . secureXSS($uploaddir)); - } - $_file = $_FILES['file']; - $extension = strtolower(strrchr($_file['name'], '.')); - if (!in_array($extension, array('.tar.gz', '.gz', '.tar'))) { - throw new Exception(__('Extension du fichier non valide (autorisé .tar.gz, .tar et .gz) :', __FILE__) . ' ' . secureXSS($extension)); - } - if (filesize($_file['tmp_name']) > 50000000) { - throw new Exception(__('La taille du fichier est trop importante (maximum 50Mo)', __FILE__)); - } - $uploadfile = $uploaddir . $jeeNetwork->getId() . '-' . $jeeNetwork->getName() . '-' . $jeeNetwork->getConfiguration('version') . '-' . date('Y-m-d_H\hi') . '.tar' . $extension; - if (!move_uploaded_file($_file['tmp_name'], $uploadfile)) { - throw new Exception(__('Impossible de téléverser le fichier', __FILE__)); - } - system('find ' . $uploaddir . $jeeNetwork->getId() . '*' . ' -mtime +' . config::byKey('backup::keepDays') . ' -print | xargs -r rm'); - $jsonrpc->makeSuccess('ok'); - } - - if ($jsonrpc->getMethod() == 'jeeNetwork::restoreBackup') { - if (config::byKey('jeeNetwork::mode') != 'slave') { - throw new Exception(__('Seul un esclave peut restaurer une sauvegarde', __FILE__)); - } - if (substr(config::byKey('backup::path'), 0, 1) != '/') { - $uploaddir = __DIR__ . '/../../' . config::byKey('backup::path'); - } else { - $uploaddir = config::byKey('backup::path'); - } - if (!file_exists($uploaddir)) { - mkdir($uploaddir); - } - if (!file_exists($uploaddir)) { - throw new Exception(__('Répertoire de téléversement non trouvé :', __FILE__) . ' ' . secureXSS($uploaddir)); - } - $_file = $_FILES['file']; - $extension = strtolower(strrchr($_file['name'], '.')); - if (!in_array($extension, array('.tar.gz', '.gz', '.tar'))) { - throw new Exception(__('Extension du fichier non valide (autorisé .tar.gz, .tar et .gz) :', __FILE__) . ' ' . secureXSS($extension)); - } - if (filesize($_file['tmp_name']) > 50000000) { - throw new Exception(__('La taille du fichier est trop importante (maximum 50Mo)', __FILE__)); - } - $backup_name = 'backup-' . jeedom::version() . '-' . date("d-m-Y-H\hi") . '.tar.gz'; - $uploadfile = $uploaddir . '/' . $backup_name; - if (!move_uploaded_file($_file['tmp_name'], $uploadfile)) { - throw new Exception(__('Impossible de téléverser le fichier', __FILE__)); - } - jeedom::restore($uploadfile, true); - $jsonrpc->makeSuccess('ok'); - } - - if ($jsonrpc->getMethod() == 'jeeNetwork::backup') { - jeedom::backup(true); - $jsonrpc->makeSuccess('ok'); - } - /* * ************************Backup*************************** */ if ($jsonrpc->getMethod() == 'backup::list') { @@ -751,7 +622,7 @@ } if ($jsonrpc->getMethod() == 'backup::restoreMarket') { - repo_market::backup_restore($params['backup'], true); + repo_market::backup_restore($params['backup']); $jsonrpc->makeSuccess(); } @@ -814,9 +685,9 @@ /* * ************************Plugin*************************** */ if ($jsonrpc->getMethod() == 'plugin::install') { try { - $market = market::byId($params['plugin_id']); + $market = repo_market::byId($params['plugin_id']); } catch (Exception $e) { - $market = market::byLogicalId($params['plugin_id']); + $market = repo_market::byLogicalId($params['plugin_id']); } if (!is_object($market)) { throw new Exception(__('Impossible de trouver l\'objet associé :', __FILE__) . ' ' . secureXSS($params['plugin_id'])); @@ -829,7 +700,7 @@ } if ($jsonrpc->getMethod() == 'plugin::remove') { - $market = market::byId($params['plugin_id']); + $market = repo_market::byId($params['plugin_id']); if (!is_object($market)) { throw new Exception(__('Impossible de trouver l\'objet associé :', __FILE__) . ' ' . secureXSS($params['plugin_id'])); } @@ -857,7 +728,7 @@ } if ($jsonrpc->getMethod() == 'update::update') { - jeedom::update('', 0); + jeedom::update(''); $jsonrpc->makeSuccess('ok'); } diff --git a/core/class/cache.class.php b/core/class/cache.class.php index 277a5293a4..88ca33f7be 100644 --- a/core/class/cache.class.php +++ b/core/class/cache.class.php @@ -30,17 +30,17 @@ class cache { /* * ***********************Methode static*************************** */ - public static function getEngine(){ - if(self::$_engine != null){ + public static function getEngine() { + if (self::$_engine != null) { return self::$_engine; } self::$_engine = config::byKey('cache::engine'); - if(!class_exists(self::$_engine)){ - config::save('cache::engine','FileCache'); + if (!class_exists(self::$_engine)) { + config::save('cache::engine', 'FileCache'); self::$_engine = 'FileCache'; } - if(method_exists(self::$_engine,'isOk') && !self::$_engine::isOk()){ - config::save('cache::engine','FileCache'); + if (method_exists(self::$_engine, 'isOk') && !self::$_engine::isOk()) { + config::save('cache::engine', 'FileCache'); self::$_engine = 'FileCache'; } return self::$_engine; @@ -51,7 +51,7 @@ public static function set($_key, $_value, $_lifetime = 0) { ->setKey($_key) ->setValue($_value) ->setLifetime($_lifetime) - ->save(); + ->save(); } public static function delete($_key) { @@ -76,7 +76,7 @@ public static function byKey($_key) { return $cache; } - public static function exist($_key){ + public static function exist($_key) { return (self::byKey($_key)->getValue(null) !== null); } @@ -85,31 +85,31 @@ public static function flush() { } public static function persist() { - if(method_exists(self::getEngine(),'persist')){ + if (method_exists(self::getEngine(), 'persist')) { self::getEngine()::persist(); } } public static function isPersistOk(): bool { - if(method_exists(self::getEngine(),'isPersistOk')){ + if (method_exists(self::getEngine(), 'isPersistOk')) { return self::getEngine()::isPersistOk(); } return true; } public static function restore() { - if(method_exists(self::getEngine(),'restore')){ + if (method_exists(self::getEngine(), 'restore')) { self::getEngine()::restore(); } } public static function clean() { - if(method_exists(self::getEngine(),'clean')){ + if (method_exists(self::getEngine(), 'clean')) { self::getEngine()::clean(); } $caches = self::getEngine()::all(); foreach ($caches as $cache) { - if(!is_object($cache)){ + if (!is_object($cache)) { continue; } $matches = null; @@ -188,7 +188,7 @@ public function setLifetime($_lifetime): self { } public function getDatetime() { - return date('Y-m-d H:i:s',(int) $this->timestamp); + return date('Y-m-d H:i:s', (int) $this->timestamp); } public function setDatetime($_datetime): self { @@ -196,11 +196,11 @@ public function setDatetime($_datetime): self { return $this; } - public function getTimestamp(){ + public function getTimestamp() { return $this->timestamp; } - public function setTimestamp($_timestamp){ + public function setTimestamp($_timestamp) { $this->timestamp = $_timestamp; return $this; } @@ -209,73 +209,72 @@ public function setTimestamp($_timestamp){ class MariadbCache { - public static function all(){ + public static function all() { $sql = 'SELECT `key`,`timestamp`,`value`,`lifetime` FROM cache'; - $results = DB::Prepare($sql,array(), DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS,'cache'); + $results = DB::Prepare($sql, array(), DB::FETCH_TYPE_ALL, PDO::FETCH_CLASS, 'cache'); foreach ($results as $cache) { $cache->setValue(unserialize($cache->getValue())); } return $results; } - public static function clean(){ - $sql = 'DELETE + public static function clean() { + $sql = 'DELETE FROM cache WHERE `lifetime` > 0 AND (`timestamp`+`lifetime`) < UNIX_TIMESTAMP()'; - return DB::Prepare($sql,array(), DB::FETCH_TYPE_ROW, PDO::FETCH_CLASS); + return DB::Prepare($sql, array(), DB::FETCH_TYPE_ROW, PDO::FETCH_CLASS); } - public static function fetch($_key){ + public static function fetch($_key) { $sql = 'SELECT `key`,`timestamp`,`value`,`lifetime` FROM cache WHERE `key`=:key'; - $cache = DB::Prepare($sql,array('key' => $_key), DB::FETCH_TYPE_ROW, PDO::FETCH_CLASS,'cache'); - if($cache === false || !is_object($cache)){ + $cache = DB::Prepare($sql, array('key' => $_key), DB::FETCH_TYPE_ROW, PDO::FETCH_CLASS, 'cache'); + if ($cache === false || !is_object($cache)) { return null; } - if($cache->getLifetime() > 0 && ($cache->getTimestamp() + $cache->getLifetime()) < strtotime('now')){ + if ($cache->getLifetime() > 0 && ($cache->getTimestamp() + $cache->getLifetime()) < strtotime('now')) { return null; } $cache->setValue(unserialize($cache->getValue())); return $cache; } - public static function delete($_key){ - $sql = 'DELETE + public static function delete($_key) { + $sql = 'DELETE FROM cache WHERE `key`=:key'; - return DB::Prepare($sql,array('key' => $_key), DB::FETCH_TYPE_ROW); + return DB::Prepare($sql, array('key' => $_key), DB::FETCH_TYPE_ROW); } - public static function deleteAll(){ - return DB::Prepare('TRUNCATE cache',array(), DB::FETCH_TYPE_ROW); + public static function deleteAll() { + return DB::Prepare('TRUNCATE cache', array(), DB::FETCH_TYPE_ROW); } - public static function save($_cache){ + public static function save($_cache) { $value = array( 'key' => $_cache->getKey(), 'value' => serialize($_cache->getValue()), - 'lifetime' =>$_cache->getLifetime(), + 'lifetime' => $_cache->getLifetime(), 'timestamp' => $_cache->getTimestamp() ); $sql = 'REPLACE INTO cache SET `key`=:key, `value`=:value,`timestamp`=:timestamp,`lifetime`=:lifetime'; - return DB::Prepare($sql,$value, DB::FETCH_TYPE_ROW); + return DB::Prepare($sql, $value, DB::FETCH_TYPE_ROW); } - } class RedisCache { private static $connection = null; - public static function isOk(){ + public static function isOk() { return class_exists('redis'); } - public static function getConnection(){ - if(static::$connection !== null){ + public static function getConnection() { + if (static::$connection !== null) { return static::$connection; } $redis = new Redis(); @@ -284,7 +283,7 @@ public static function getConnection(){ return static::$connection; } - public static function all(){ + public static function all() { $return = array(); $keys = self::getConnection()->keys('*'); foreach ($keys as $key) { @@ -293,88 +292,87 @@ public static function all(){ return $return; } - public static function fetch($_key){ + public static function fetch($_key) { $data = self::getConnection()->get($_key); - if($data === false){ + if ($data === false) { return null; } return @unserialize($data); } - public static function delete($_key){ + public static function delete($_key) { self::getConnection()->del($_key); } - public static function deleteAll(){ + public static function deleteAll() { return self::getConnection()->flushDb(); } - public static function save($_cache){ - if($_cache->getLifetime() > 0){ - self::getConnection()->set($_cache->getKey(),serialize($_cache), $_cache->getLifetime()); - }else{ - self::getConnection()->set($_cache->getKey(),serialize($_cache)); + public static function save($_cache) { + if ($_cache->getLifetime() > 0) { + self::getConnection()->set($_cache->getKey(), serialize($_cache), $_cache->getLifetime()); + } else { + self::getConnection()->set($_cache->getKey(), serialize($_cache)); } } - } class FileCache { - public static function all(){ + public static function all() { $return = array(); - foreach (ls(jeedom::getTmpFolder('cache'), '*',false,array('files')) as $file) { + foreach (ls(jeedom::getTmpFolder('cache'), '*', false, array('files')) as $file) { $return[] = self::fetch(base64_decode($file)); } return $return; } - public static function clean(){ - foreach (ls(jeedom::getTmpFolder('cache'), '*',false,array('files')) as $file) { - $cache = unserialize(file_get_contents(jeedom::getTmpFolder('cache').'/'.$file)); - if(!is_object($cache)){ - unlink(jeedom::getTmpFolder('cache').'/'.$file); + public static function clean() { + foreach (ls(jeedom::getTmpFolder('cache'), '*', false, array('files')) as $file) { + $cache = unserialize(file_get_contents(jeedom::getTmpFolder('cache') . '/' . $file)); + if (!is_object($cache)) { + unlink(jeedom::getTmpFolder('cache') . '/' . $file); continue; } - if($cache->getLifetime() > 0 && ($cache->getTimestamp() + $cache->getLifetime()) < strtotime('now')){ - unlink(jeedom::getTmpFolder('cache').'/'.$file); + if ($cache->getLifetime() > 0 && ($cache->getTimestamp() + $cache->getLifetime()) < strtotime('now')) { + unlink(jeedom::getTmpFolder('cache') . '/' . $file); } } } - public static function fetch($_key){ - $data = @file_get_contents(jeedom::getTmpFolder('cache').'/'.base64_encode($_key)); - if($data === false){ - return null; - } - $cache = unserialize($data); - if(!is_object($cache)){ + public static function fetch($_key) { + $data = @file_get_contents(jeedom::getTmpFolder('cache') . '/' . base64_encode($_key)); + if ($data === false) { return null; } - if($cache->getLifetime() > 0 && ($cache->getTimestamp() + $cache->getLifetime()) < strtotime('now')){ + $cache = unserialize($data); + if (!is_object($cache)) { + return null; + } + if ($cache->getLifetime() > 0 && ($cache->getTimestamp() + $cache->getLifetime()) < strtotime('now')) { self::delete($_key); return null; } return $cache; } - public static function delete($_key){ - @unlink(jeedom::getTmpFolder('cache').'/'.base64_encode($_key)); + public static function delete($_key) { + @unlink(jeedom::getTmpFolder('cache') . '/' . base64_encode($_key)); } - public static function deleteAll(){ - return shell_exec(system::getCmdSudo().' rm -rf '.jeedom::getTmpFolder('cache')); + public static function deleteAll() { + return shell_exec(system::getCmdSudo() . ' rm -rf ' . jeedom::getTmpFolder('cache')); } - public static function save($_cache){ - file_put_contents(jeedom::getTmpFolder('cache').'/'.base64_encode($_cache->getKey()),serialize($_cache)); + public static function save($_cache) { + file_put_contents(jeedom::getTmpFolder('cache') . '/' . base64_encode($_cache->getKey()), serialize($_cache)); } public static function persist() { $cache_dir = jeedom::getTmpFolder('cache'); try { $cmd = system::getCmdSudo() . 'rm -rf ' . __DIR__ . '/../../cache.tar.gz;cd ' . $cache_dir . ';'; - $cmd .= system::getCmdSudo() . 'tar cfz ' . __DIR__ . '/../../cache.tar.gz * 2>&1 > /dev/null;'; + $cmd .= system::getCmdSudo() . 'tar cfz ' . __DIR__ . '/../../cache.tar.gz . 2>&1 > /dev/null;'; $cmd .= system::getCmdSudo() . 'chmod 774 ' . __DIR__ . '/../../cache.tar.gz;'; $cmd .= system::getCmdSudo() . 'chown ' . system::get('www-uid') . ':' . system::get('www-gid') . ' ' . __DIR__ . '/../../cache.tar.gz;'; $cmd .= system::getCmdSudo() . 'chown -R ' . system::get('www-uid') . ':' . system::get('www-gid') . ' ' . $cache_dir . ';'; @@ -410,5 +408,4 @@ public static function restore() { $cmd .= 'chmod -R 777 ' . $cache_dir . ' 2>&1 > /dev/null;'; com_shell::execute($cmd); } - } diff --git a/core/class/cmd.class.php b/core/class/cmd.class.php index 7c0ffb79b5..f785ef0c8b 100644 --- a/core/class/cmd.class.php +++ b/core/class/cmd.class.php @@ -1042,10 +1042,10 @@ public function formatValue($_value, $_quote = false) { return intval($binary xor boolval($this->getConfiguration('invertBinary', false))); case 'numeric': if ($this->getConfiguration('historizeRound') !== '' && is_numeric($this->getConfiguration('historizeRound')) && $this->getConfiguration('historizeRound') >= 0) { - if (!is_numeric($_value)) { - log::add('cmd', 'error', __('La formule de calcul doit retourner une valeur numérique uniquement : ', __FILE__) . $this->getHumanName() . ' => ' . $_value); - $_value = (float) (str_replace(',', '.', $_value)); - } + if (!is_numeric($_value)) { + log::add('cmd', 'error', __('La formule de calcul doit retourner une valeur numérique uniquement : ', __FILE__) . $this->getHumanName() . ' => ' . $_value); + $_value = (float) (str_replace(',', '.', $_value)); + } $_value = round($_value, $this->getConfiguration('historizeRound')); } if ($_value > $this->getConfiguration('maxValue', $_value)) { @@ -1757,13 +1757,13 @@ public function toHtml($_version = 'dashboard', $_options = '') { $replace['#hide_history#'] = ''; $historyStatistique = $this->getStatistique($startHist, date('Y-m-d H:i:s')); if ($historyStatistique['avg'] == 0 && $historyStatistique['min'] == 0 && $historyStatistique['max'] == 0) { - $replace['#averageHistoryValue#'] = round(intval($replace['#state#']), 1); - $replace['#minHistoryValue#'] = round(intval($replace['#state#']), 1); - $replace['#maxHistoryValue#'] = round(intval($replace['#state#']), 1); + $replace['#averageHistoryValue#'] = round(floatval($replace['#state#']), 1); + $replace['#minHistoryValue#'] = round(floatval($replace['#state#']), 1); + $replace['#maxHistoryValue#'] = round(floatval($replace['#state#']), 1); } else { - $replace['#averageHistoryValue#'] = round(intval($historyStatistique['avg']), 1); - $replace['#minHistoryValue#'] = round(intval($historyStatistique['min']), 1); - $replace['#maxHistoryValue#'] = round(intval($historyStatistique['max']), 1); + $replace['#averageHistoryValue#'] = round(floatval($historyStatistique['avg']), 1); + $replace['#minHistoryValue#'] = round(floatval($historyStatistique['min']), 1); + $replace['#maxHistoryValue#'] = round(floatval($historyStatistique['max']), 1); } $startHist = date('Y-m-d H:i:s', strtotime(date('Y-m-d H:i:s') . ' -' . config::byKey('historyCalculTendance') . ' hour')); $tendance = $this->getTendance($startHist, date('Y-m-d H:i:s')); @@ -2330,7 +2330,7 @@ public function pushInflux($_value = null) { return; } - public function dropInfluxDatabase() { + public static function dropInfluxDatabase() { try { $database = cmd::getInflux(); if ($database == '') { @@ -3071,7 +3071,7 @@ public function getDisplay($_key = '', $_default = '') { } public function setDisplay($_key, $_value) { - if ($this->getDisplay($_key) !== $_value) { + if ($this->getDisplay($_key, null) !== $_value) { $this->_needRefreshWidget = true; $this->_changed = true; } diff --git a/core/class/config.class.php b/core/class/config.class.php index a33f7d2832..8f46a09f84 100644 --- a/core/class/config.class.php +++ b/core/class/config.class.php @@ -29,26 +29,44 @@ class config { /* * ***********************Methode static*************************** */ - public static function getDefaultConfiguration(string $_plugin = 'core') { - if (!isset(self::$defaultConfiguration[$_plugin])) { - if ($_plugin == 'core') { - self::$defaultConfiguration[$_plugin] = parse_ini_file(__DIR__ . '/../../core/config/default.config.ini', true); - if (file_exists(__DIR__ . '/../../data/custom/custom.config.ini')) { - $custom = parse_ini_file(__DIR__ . '/../../data/custom/custom.config.ini', true); - self::$defaultConfiguration[$_plugin]['core'] = array_merge(self::$defaultConfiguration[$_plugin]['core'], $custom['core']); - } - } else { - $filename = __DIR__ . '/../../plugins/' . $_plugin . '/core/config/' . $_plugin . '.config.ini'; - if (file_exists($filename)) { - self::$defaultConfiguration[$_plugin] = parse_ini_file($filename, true); - } - } + /** + * Get default configuration for core or plugin + * @param string $_plugin + * @return array + */ + public static function getDefaultConfiguration(string $_plugin = 'core'): array { + if (isset(self::$defaultConfiguration[$_plugin])) { + return self::$defaultConfiguration[$_plugin]; } - if (!isset(self::$defaultConfiguration[$_plugin])) { + + if ($_plugin == 'core') { + self::$defaultConfiguration[$_plugin] = parse_ini_file(__DIR__ . '/../../core/config/default.config.ini', true); + + if (file_exists(__DIR__ . '/../../data/custom/custom.config.ini')) { + $custom = parse_ini_file(__DIR__ . '/../../data/custom/custom.config.ini', true); + self::$defaultConfiguration[$_plugin]['core'] = array_merge(self::$defaultConfiguration[$_plugin]['core'], $custom['core']); + } + } else { self::$defaultConfiguration[$_plugin] = array(); + + $filename = __DIR__ . '/../../plugins/' . $_plugin . '/core/config/' . $_plugin . '.config.ini'; + if (file_exists($filename)) { + self::$defaultConfiguration[$_plugin] = parse_ini_file($filename, true); + } + + $specificConf = __DIR__ . '/../../plugins/' . $_plugin . '/core/config/specific.config.ini'; + if (file_exists($specificConf)) { + $specific = parse_ini_file($specificConf, true); + $hardware = strtolower(jeedom::getHardwareName()); + if (isset($specific[$hardware])) { + self::$defaultConfiguration[$_plugin] = array_replace_recursive(self::$defaultConfiguration[$_plugin], $specific[$hardware]); + } + } } + return self::$defaultConfiguration[$_plugin]; } + /** * Save key to config * @param string $_key @@ -111,8 +129,8 @@ public static function save($_key, $_value, $_plugin = 'core') { /** * Delete key from config - * @param string $_key nom de la clef à supprimer - * @return boolean vrai si ok faux sinon + * @param string $_key + * @return boolean */ public static function remove(string $_key, string $_plugin = 'core') { if ($_key == "*" && $_plugin != 'core') { @@ -122,11 +140,11 @@ public static function remove(string $_key, string $_plugin = 'core') { $sql = 'DELETE FROM config WHERE plugin=:plugin'; DB::Prepare($sql, $values, DB::FETCH_TYPE_ROW); - foreach (self::$cache as $cacheKey => $value) { - if (strpos($cacheKey, $_plugin . '::') === 0) { - unset(self::$cache[$cacheKey]); - } - } + foreach (self::$cache as $cacheKey => $value) { + if (strpos($cacheKey, $_plugin . '::') === 0) { + unset(self::$cache[$cacheKey]); + } + } } else { $values = array( 'plugin' => $_plugin, @@ -136,15 +154,15 @@ public static function remove(string $_key, string $_plugin = 'core') { WHERE `key`=:key AND plugin=:plugin'; DB::Prepare($sql, $values, DB::FETCH_TYPE_ROW); - unset(self::$cache[$_plugin . '::' . $_key]); + unset(self::$cache[$_plugin . '::' . $_key]); } return true; } /** * Get config by key - * @param string $_key nom de la clef dont on veut la valeur - * @return string valeur de la clef + * @param string $_key + * @return string */ public static function byKey($_key, $_plugin = 'core', $_default = '', $_forceFresh = false) { if (!$_forceFresh && isset(self::$cache[$_plugin . '::' . $_key]) && !in_array($_key, self::$nocache)) { @@ -227,6 +245,26 @@ public static function byKeys($_keys, $_plugin = 'core', $_default = '') { return $return; } + /** + * Get list of plugins|keys from unencrypted value + * @param mixed $_value + * @param string $_key (optional) + * @return array + */ + public static function byValue($_value, string $_key = null): array { + $values = array( + 'value' => $_value + ); + + if ($_key) { + $values['key'] = $_key; + $sql = 'SELECT `plugin` FROM config WHERE `value`=:value AND `key`=:key'; + } else { + $sql = 'SELECT `plugin`,`key` FROM config WHERE `value`=:value'; + } + return DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL); + } + public static function searchKey($_key, $_plugin = 'core') { $values = array( 'plugin' => $_plugin, @@ -251,9 +289,9 @@ public static function searchKey($_key, $_plugin = 'core') { } public static function genKey($_car = 64) { - if ($_car > 256) { - throw new \Exception('Key length too long'); - } + if ($_car > 256) { + throw new \Exception('Key length too long'); + } $key = ''; $chaine = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"; for ($i = 0; $i < $_car; $i++) { @@ -325,7 +363,11 @@ public static function getGenericTypes($_coreOnly = false) { } } } - asort($types['byFamily'], SORT_STRING | SORT_FLAG_CASE); + + if (is_array($types['byFamily'])) { + asort($types['byFamily'], SORT_STRING | SORT_FLAG_CASE); + } + return $types; } diff --git a/core/class/history.class.php b/core/class/history.class.php index 9c9e4dcd6b..3b4c0d4203 100644 --- a/core/class/history.class.php +++ b/core/class/history.class.php @@ -226,10 +226,6 @@ public static function archive() { DB::Prepare($sql, array()); $sql = 'DELETE FROM historyArch WHERE `value` IS NULL'; DB::Prepare($sql, array()); - $sql = 'DELETE FROM history WHERE `value` IS NULL'; - DB::Prepare($sql, array()); - $sql = 'DELETE FROM historyArch WHERE `value` IS NULL'; - DB::Prepare($sql, array()); if (config::byKey('historyArchivePackage') < 1) { config::save('historyArchivePackage', 1); } diff --git a/core/class/interactQuery.class.php b/core/class/interactQuery.class.php index be5117a895..341120a283 100644 --- a/core/class/interactQuery.class.php +++ b/core/class/interactQuery.class.php @@ -667,7 +667,7 @@ public static function contextualReply($_query, $_parameters = array(), $_lastCm return $return; } - public function replaceForContextual($_replace, $_by, $_in) { + public static function replaceForContextual($_replace, $_by, $_in) { return str_replace(strtolower(sanitizeAccent($_replace)), strtolower(sanitizeAccent($_by)), str_replace($_replace, $_by, $_in)); } diff --git a/core/class/jeedom.class.php b/core/class/jeedom.class.php index d090860d81..92a47f48ec 100644 --- a/core/class/jeedom.class.php +++ b/core/class/jeedom.class.php @@ -222,7 +222,7 @@ public static function health() { $state = self::isDateOk(); $cache = cache::byKey('hour'); $lastKnowDate = $cache->getValue(); - if($lastKnowDate === ""){ + if ($lastKnowDate === "") { $lastKnowDate = 0; } $return[] = array( @@ -294,17 +294,20 @@ public static function health() { $state = false; } else { $version = trim(strtolower(file_get_contents('/etc/debian_version'))); - if (version_compare($version, '8', '<')) { - if (strpos($version, 'jessie') === false && strpos($version, 'stretch') === false) { + $majorVersion = intval($version); + if ($majorVersion > 0) { + if ($majorVersion < 11 || $majorVersion > 12) { $state = false; } + } else if (strpos($version, 'bullseye') === false && strpos($version, 'bookworm') === false) { + $state = false; } } $return[] = array( 'name' => __('Version OS', __FILE__), 'state' => $state, 'result' => ($state) ? $uname . ' [' . $version . ']' : $uname, - 'comment' => ($state) ? '' : __('Vous n\'êtes pas sur un OS officiellement supporté par l\'équipe Jeedom (toute demande de support pourra donc être refusée). Les OS officiellement supportés sont Debian Strech et Debian Buster', __FILE__), + 'comment' => ($state) ? '' : __("Cet OS n'est pas pris en charge, toute demande de support pourra donc être refusée (voir la documentation sur la compatibilité logicielle).", __FILE__) ); $version = DB::Prepare('select version()', array(), DB::FETCH_TYPE_ROW); @@ -427,7 +430,7 @@ public static function health() { $return[] = array( 'name' => __('Charge', __FILE__), 'state' => ($values[2] < 20), - 'result' => round($values[0],2) . ' - ' . round($values[1],2) . ' - ' . round($values[2],2), + 'result' => round($values[0], 2) . ' - ' . round($values[1], 2) . ' - ' . round($values[2], 2), 'comment' => '', 'key' => 'load' ); @@ -731,36 +734,42 @@ public static function getUsbMapping($_name = '', $_getGPIO = false) { } $usbMapping = self::getUsbLegacy($usbMapping); if ($_getGPIO) { + if (file_exists('/dev/ttyLuna-Zigbee')) { + $usbMapping['Jeedom Luna Zigbee'] = '/dev/ttyLuna-Zigbee'; + } if (file_exists('/dev/ttyS0')) { $usbMapping['Cubiboard'] = '/dev/ttyS0'; } if (file_exists('/dev/ttyS1')) { $usbMapping['Jeedom Luna Zwave'] = '/dev/ttyS1'; - } - if (file_exists('/dev/ttyS1')) { - $usbMapping['Odroid C2'] = '/dev/ttyS1'; + $usbMapping['Odroid (old)'] = '/dev/ttyS1'; } if (file_exists('/dev/ttyS2')) { $usbMapping['Jeedom Atlas'] = '/dev/ttyS2'; + $usbMapping['Rock Pi'] = '/dev/ttyS2'; } if (file_exists('/dev/ttyS3')) { - $usbMapping['Orange PI'] = '/dev/ttyS3'; + $usbMapping['Orange Pi'] = '/dev/ttyS3'; } if (file_exists('/dev/ttymxc0')) { $usbMapping['Jeedom board'] = '/dev/ttymxc0'; } - if (file_exists('/dev/ttyAML1')) { - $usbMapping['Odroid ARMBIAN (Buster)'] = '/dev/ttyAML1'; - } if (file_exists('/dev/ttyAMA0')) { - $usbMapping['Raspberry pi'] = '/dev/ttyAMA0'; + $usbMapping['Raspberry Pi'] = '/dev/ttyAMA0'; + } + if (file_exists('/dev/ttyAML1')) { + $usbMapping['Jeedom Smart'] = '/dev/ttyAML1'; + $usbMapping['Odroid'] = '/dev/ttyAML1'; } if (file_exists('/dev/S2')) { - $usbMapping['Banana PI'] = '/dev/S2'; + $usbMapping['Banana Pi'] = '/dev/S2'; } foreach (ls('/dev/', 'ttyAMA*') as $value) { $usbMapping['/dev/' . $value] = '/dev/' . $value; } + foreach (ls('/dev/', 'ttyAML*') as $value) { + $usbMapping['/dev/' . $value] = '/dev/' . $value; + } } cache::set('jeedom::usbMapping', json_encode($usbMapping)); } else { @@ -1036,18 +1045,6 @@ public static function isDateOk() { return false; } } - $minDateValue = new \DateTime('2020-01-01'); - $mindate = strtotime($minDateValue->format('Y-m-d 00:00:00')); - $maxDateValue = $minDateValue->modify('+6 year')->format('Y-m-d 00:00:00'); - $maxdate = strtotime($maxDateValue); - if (strtotime('now') < $mindate || strtotime('now') > $maxdate) { - self::forceSyncHour(); - sleep(3); - if (strtotime('now') < $mindate || strtotime('now') > $maxdate) { - log::add('core', 'error', __('La date du système est incorrecte (avant ' . $minDateValue . ' ou après ' . $maxDateValue . ') :', __FILE__) . ' ' . (new \DateTime())->format('Y-m-d H:i:s'), 'dateCheckFailed'); - return false; - } - } return true; } @@ -1252,8 +1249,8 @@ public static function cronDaily() { log::add('jeedom', 'error', log::exception($e)); } $disk_space = self::checkSpaceLeft(); - if($disk_space < 10){ - log::add('jeedom', 'error',__('Espace disque disponible faible : ',__FILE__).$disk_space.'%.'.__('Veuillez faire de la place (suppression de backup, de video/capture du plugin camera, d\'historique...)',__FILE__)); + if ($disk_space < 10) { + log::add('jeedom', 'error', __('Espace disque disponible faible : ', __FILE__) . $disk_space . '%.' . __('Veuillez faire de la place (suppression de backup, de video/capture du plugin camera, d\'historique...)', __FILE__)); } } @@ -1309,6 +1306,13 @@ public static function cronHourly() { } catch (Error $e) { log::add('jeedom', 'error', log::exception($e)); } + try { + log::chunk('', True); + } catch (Throwable $e) { + log::add('jeedom', 'error', $e->getMessage()); + } catch (Error $e) { + log::add('jeedom', 'error', $e->getMessage()); + } } /*************************************************************************************/ @@ -1549,7 +1553,7 @@ public static function massReplace($_options = array(), $_eqlogics = array(), $_ if (count($_eqlogics) == 0 && count($_cmds) == 0) { throw new Exception('{{Aucun équipement ou commande à remplacer ou copier}}'); } - foreach (['copyEqProperties', 'hideEqs', 'copyCmdProperties', 'removeCmdHistory', 'copyCmdHistory','disableEqs'] as $key) { + foreach (['copyEqProperties', 'hideEqs', 'copyCmdProperties', 'removeCmdHistory', 'copyCmdHistory', 'disableEqs'] as $key) { if (!isset($_options[$key])) { $_options[$key] = false; } @@ -1636,7 +1640,7 @@ public static function massReplace($_options = array(), $_eqlogics = array(), $_ $targetEq->save(); $return['eqlogics'] += 1; } - } + } if ($_options['hideEqs'] == "true") { foreach ($_eqlogics as $_sourceId => $_targetId) { $sourceEq = eqLogic::byId($_sourceId); @@ -1747,7 +1751,7 @@ public static function checkSpaceLeft($_dir = null) { } public static function getTmpFolder($_plugin = '') { - if(isset(self::$cache['getTmpFolder::' . $_plugin])){ + if (isset(self::$cache['getTmpFolder::' . $_plugin])) { return self::$cache['getTmpFolder::' . $_plugin]; } $return = '/' . trim(config::byKey('folder::tmp'), '/'); @@ -1804,7 +1808,7 @@ public static function getHardwareName() { $result = 'Atlas'; } else if (strpos($hostname, 'Luna') !== false) { $result = 'Luna'; - } else if (file_exists('/proc/1/sched') && strpos(shell_exec('cat /proc/1/sched | head -n 1'),'systemd') === false){ + } else if (file_exists('/proc/1/sched') && strpos(shell_exec('cat /proc/1/sched | head -n 1'), 'systemd') === false) { $result = 'docker'; } config::save('hardware_name', $result); diff --git a/core/class/jsonrpcClient.class.php b/core/class/jsonrpcClient.class.php index 5a00138230..c1df3395a5 100644 --- a/core/class/jsonrpcClient.class.php +++ b/core/class/jsonrpcClient.class.php @@ -138,21 +138,22 @@ private function send($_request, $_timeout = 15, $_file = null, $_maxRetry = 2) curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); } - if(config::byKey('proxyEnabled')) { - if(config::byKey('proxyAddress') == ''){ - // throw new Exception(__('renseigne l\'adresse', __FILE__)); - $this->error = 'Erreur address '; - } else if (config::byKey('proxyPort') == ''){ - // throw new Exception(__('renseigne le port', __FILE__)); - } else { - curl_setopt($ch, CURLOPT_PROXY, config::byKey('proxyAddress')); - curl_setopt($ch, CURLOPT_PROXYPORT, config::byKey('proxyPort')); - if(!empty(config::byKey('proxyLogin') || config::byKey('proxyPassword'))){ - curl_setopt($ch, CURLOPT_PROXYUSERPWD, 'proxyLogin:proxyPassword'); + if (config::byKey('proxyEnabled') == 1) { + $proxyAddress = config::byKey('proxyAddress'); + $proxyPort = config::byKey('proxyPort'); + if ($proxyAddress != '' && $proxyPort != '') { + curl_setopt($ch, CURLOPT_PROXY, $proxyAddress); + curl_setopt($ch, CURLOPT_PROXYPORT, $proxyPort); + $proxyLogin = config::byKey('proxyLogin'); + $proxyPassword = config::byKey('proxyPassword'); + if (!empty($proxyLogin) || !empty($proxyPassword)) { + curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxyLogin . ':' . $proxyPassword); + } + } else { + $this->error = 'Proxy enabled but address or port is missing'; + log::add('connection', 'error', $this->error); } - log::add('Connection', 'debug', $ch); - } - } + } $response = curl_exec($ch); $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE); $nbRetry++; diff --git a/core/class/log.class.php b/core/class/log.class.php index 4660c278ff..c279114e79 100644 --- a/core/class/log.class.php +++ b/core/class/log.class.php @@ -59,7 +59,7 @@ public function log($level, $message, array $context = array()) { public static function getConfig($_key, $_default = '') { if (self::$config === null) { - self::$config = array_merge(config::getLogLevelPlugin(), config::byKeys(array('log::engine', 'log::formatter', 'log::level', 'addMessageForErrorLog', 'maxLineLog'))); + self::$config = array_merge(config::getLogLevelPlugin(), config::byKeys(array('log::engine', 'log::formatter', 'log::level', 'addMessageForErrorLog', 'maxLineLog', 'maxSizeLog'))); } if (isset(self::$config[$_key])) { return self::$config[$_key]; @@ -69,9 +69,9 @@ public static function getConfig($_key, $_default = '') { public static function getLogLevel($_log) { $specific_level = self::getConfig('log::level::' . $_log); - if (!is_array($specific_level) && strpos($_log,'_') !== false) { + if (!is_array($specific_level) && strpos($_log, '_') !== false) { preg_match('/(.*?)\_[a-zA-Z]*?$/m', $_log, $matches); - if(isset($matches[1])){ + if (isset($matches[1])) { $specific_level = self::getConfig('log::level::' . $matches[1]); } } @@ -96,7 +96,7 @@ public static function convertLogLevel($_level = 100) { return 'none'; } foreach (self::$level as $key => $value) { - if($value == $_level){ + if ($value == $_level) { return $key; } } @@ -108,36 +108,36 @@ public static function convertLogLevel($_level = 100) { * @param string $_type message type (info, debug, warning, danger) * @param string $_message message added into log */ - public static function add($_log, $_type, $_message, $_logicalId = '') { + public static function add(string $_log, string $_type, string $_message, string $_logicalId = '') { if (trim($_message) == '') { return; } $level = (isset(self::$level[strtolower($_type)])) ? self::$level[strtolower($_type)] : 100; - if($level < self::getLogLevel($_log)){ + if ($level < self::getLogLevel($_log)) { return; } $fp = fopen(self::getPathToLog($_log), 'a'); - fwrite($fp,'['.date('Y-m-d H:i:s').']['.strtoupper($_type).'] '.$_message."\n"); + fwrite($fp, '[' . date('Y-m-d H:i:s') . '][' . strtoupper($_type) . '] ' . $_message . "\n"); fclose($fp); try { - $action = '' . __('Log', __FILE__) . ' ' . $_log . ''; + $action = '' . __('Log', __FILE__) . ' ' . $_log . ''; if ($level == 400 && self::getConfig('addMessageForErrorLog') == 1) { @message::add($_log, $_message, $action, $_logicalId); } elseif ($level >= 500 && $_log != 'update') { @message::add($_log, $_message, $action, $_logicalId); } } catch (Exception $e) { - } } - public static function chunk($_log = '') { + public static function chunk($_log = '', $_onlyIfSizeExceeded = False) { $paths = array(); if ($_log != '') { $paths = array(self::getPathToLog($_log)); } else { $relativeLogPaths = array('', 'scenarioLog/'); foreach ($relativeLogPaths as $relativeLogPath) { + $logPath = self::getPathToLog($relativeLogPath); $logs = ls($logPath, '*'); foreach ($logs as $log) { @@ -147,6 +147,9 @@ public static function chunk($_log = '') { } foreach ($paths as $path) { if (is_file($path)) { + if ($_onlyIfSizeExceeded && filesize($path) < (self::getConfig('maxSizeLog') * 1024 * 1024)) { + continue; + } self::chunkLog($path); } } @@ -161,7 +164,7 @@ public static function chunkLog($_path) { $maxLineLog = self::DEFAULT_MAX_LINE; } try { - com_shell::execute(system::getCmdSudo() . 'chmod 664 ' . $_path . ' > /dev/null 2>&1;'. system::getCmdSudo() . 'chown -R ' . system::get('www-uid') . ':' . system::get('www-gid') . ' ' . $_path.' > /dev/null 2>&1;'.system::getCmdSudo() . ' echo "$(tail -n ' . $maxLineLog . ' ' . $_path . ')" > ' . $_path); + com_shell::execute(system::getCmdSudo() . 'chmod 664 ' . $_path . ' > /dev/null 2>&1;' . system::getCmdSudo() . 'chown -R ' . system::get('www-uid') . ':' . system::get('www-gid') . ' ' . $_path . ' > /dev/null 2>&1;' . system::getCmdSudo() . ' echo "$(tail -n ' . $maxLineLog . ' ' . $_path . ')" > ' . $_path); } catch (\Exception $e) { } @chown($_path, system::get('www-uid')); @@ -184,77 +187,144 @@ public static function getPathToLog($_log = 'core') { /** * Check authorisation to emptying log file */ - public static function authorizeClearLog($_log, $_subPath = '') { + public static function authorizeClearLog(string $_log, string $_subPath = ''): bool { $path = self::getPathToLog($_subPath . $_log); - return !((strpos($_log, '.htaccess') !== false) - || (!file_exists($path) || !is_file($path))); + return !((strpos($_log, '.htaccess') !== false) || (!file_exists($path) || !is_file($path))); } /** * Empty log file */ - public static function clear($_log) { + public static function clear(string $_log) { if (self::authorizeClearLog($_log)) { $path = self::getPathToLog($_log); - com_shell::execute(system::getCmdSudo() . 'chmod 664 ' . $path . '> /dev/null 2>&1;'. system::getCmdSudo() . 'chown -R ' . system::get('www-uid') . ':' . system::get('www-gid') . ' ' . $path.' > /dev/null 2>&1;'.system::getCmdSudo() . ' cat /dev/null > ' . $path); + com_shell::execute(system::getCmdSudo() . 'chmod 664 ' . $path . '> /dev/null 2>&1;' . system::getCmdSudo() . 'chown -R ' . system::get('www-uid') . ':' . system::get('www-gid') . ' ' . $path . ' > /dev/null 2>&1;' . system::getCmdSudo() . ' cat /dev/null > ' . $path); return true; } return; } - public static function clearAll() { + public static function clearAll(): void { foreach (ls(self::getPathToLog(''), '*', false, array('files')) as $log) self::clear($log); + return; + } + + private static function getActiveDaemonPluginIdsSortedByLength(): array { + static $activePluginsWithDaemon = null; + if ($activePluginsWithDaemon === null) { + $activePluginsWithDaemon = []; + foreach (plugin::listPlugin(true) as $plugin) { + if ($plugin->getHasOwnDeamon() == 0) continue; + $activePluginsWithDaemon[] = $plugin->getId(); + } + usort($activePluginsWithDaemon, function ($a, $b) { + return strlen($b) - strlen($a); + }); + } + + return $activePluginsWithDaemon; + } + + private static function canRemoveLog(string $_log): bool { + if (strpos($_log, 'nginx.error') !== false || strpos($_log, 'http.error') !== false) { + return false; + } + + if (substr($_log, -9) === '_packages' || substr($_log, -7) === '_update') { + return true; + } + + // if a new core log is added to the codebase, add it here to prevent a plugin with the same name from protecting it by mistake. + static $coreLogNames = [ + 'api', + 'apipro', + 'backup', + 'cmd', + 'connection', + 'cron', + 'cron_execution', + 'debug_translate', + 'design', + 'event', + 'expression', + 'history', + 'http.com', + 'interact', + 'jeedom', + 'jeedomAlert', + 'jeeEvent', + 'listener', + 'listener_execution', + 'market', + 'monitoring_cloud', + 'network', + 'plugin', + 'queue', + 'report', + 'scenario', + 'starting', + 'tts', + 'update', + ]; + if (in_array($_log, $coreLogNames)) { + return true; + } + + $plugins = self::getActiveDaemonPluginIdsSortedByLength(); + foreach ($plugins as $plugin) { + if (strpos($_log, $plugin) === 0) { + if ($_log !== $plugin) { + return false; + } + return true; + } + } + return true; } /** * Delete log file */ - public static function remove($_log) { - if (strpos($_log, 'nginx.error') !== false || strpos($_log, 'http.error') !== false) { - self::clear($_log); - return; - } - if (endsWith($_log, 'd') || endsWith($_log, 'd_1') || endsWith($_log, 'd_2') || endsWith($_log, 'd_3')) { + public static function remove(string $_log) { + if (!self::canRemoveLog($_log)) { self::clear($_log); return; } + if (self::authorizeClearLog($_log)) { $path = self::getPathToLog($_log); - com_shell::execute(system::getCmdSudo() . 'chmod 664 ' . $path . ' > /dev/null 2>&1;'. system::getCmdSudo() . 'chown -R ' . system::get('www-uid') . ':' . system::get('www-gid') . ' ' . $path.' > /dev/null 2>&1;'.system::getCmdSudo() . ' cat /dev/null > ' . $path.';rm ' . $path . ' 2>&1 > /dev/null'); - - - + com_shell::execute(system::getCmdSudo() . 'chmod 664 ' . $path . ' > /dev/null 2>&1;' . system::getCmdSudo() . 'chown -R ' . system::get('www-uid') . ':' . system::get('www-gid') . ' ' . $path . ' > /dev/null 2>&1;' . system::getCmdSudo() . ' cat /dev/null > ' . $path . ';rm ' . $path . ' 2>&1 > /dev/null'); return true; } } - public static function removeAll() { + public static function removeAll(): void { foreach (ls(self::getPathToLog(''), '*', false, array('files')) as $log) self::remove($log); - return true; + return; } /** - * Get $_nbLines from a $_log from $_begin position - * @param string $_log - * @param int $_begin - * @param int $_nbLines - * @return boolean|array - * @deprecated v4.4 - * => removed in v4.6 (use log::getDelta() instead) - * - * Note that log::get($_log, $_begin, $_nbLines) is equivalent to: - * $path = (!file_exists($_log) || !is_file($_log)) ? self::getPathToLog($_log) : $_log; - * if (!file_exists($path)) { - * return false; - * } - * $delta = self::getDelta($_log, $_begin, '', false, false, 0, $_nbLines); - * $arr = explode("\n", $delta['logText']); - * unset($arr[count($arr) - 1]); - * $res = array_reverse($arr); - */ + * Get $_nbLines from a $_log from $_begin position + * @param string $_log + * @param int $_begin + * @param int $_nbLines + * @return boolean|array + * @deprecated v4.4 + * => removed in v4.6 (use log::getDelta() instead) + * + * Note that log::get($_log, $_begin, $_nbLines) is equivalent to: + * $path = (!file_exists($_log) || !is_file($_log)) ? self::getPathToLog($_log) : $_log; + * if (!file_exists($path)) { + * return false; + * } + * $delta = self::getDelta($_log, $_begin, '', false, false, 0, $_nbLines); + * $arr = explode("\n", $delta['logText']); + * unset($arr[count($arr) - 1]); + * $res = array_reverse($arr); + */ public static function get($_log, $_begin, $_nbLines) { $path = (!file_exists($_log) || !is_file($_log)) ? self::getPathToLog($_log) : $_log; if (!file_exists($path)) { @@ -270,7 +340,6 @@ public static function get($_log, $_begin, $_nbLines) { $line = trim($log->current()); //get current line if ($line != '') { array_unshift($page, mb_convert_encoding($line, 'UTF-8')); - } $log->next(); $linesRead++; @@ -280,18 +349,18 @@ public static function get($_log, $_begin, $_nbLines) { } /** - * Get the log delta from $_position to the end of the file - * New position is stored in $_position when eof is reached - * - * @param string $_log Log filename (default 'core') - * @param int $_position Bytes representing position from the begining of the file (default 0) - * @param string $_search Text to find in log file (default '') - * @param bool $_colored Should lines be colored (default false) - * @param bool $_numbered Should lines be numbered (default true) - * @param int $_numStart At what number should lines number start (default 0) - * @param int $_max Max number of returned lines (default is config value "maxLineLog") - * @return array Array containing log to append to buffer and new position for next call - */ + * Get the log delta from $_position to the end of the file + * New position is stored in $_position when eof is reached + * + * @param string $_log Log filename (default 'core') + * @param int $_position Bytes representing position from the begining of the file (default 0) + * @param string $_search Text to find in log file (default '') + * @param bool $_colored Should lines be colored (default false) + * @param bool $_numbered Should lines be numbered (default true) + * @param int $_numStart At what number should lines number start (default 0) + * @param int $_max Max number of returned lines (default is config value "maxLineLog") + * @return array Array containing log to append to buffer and new position for next call + */ public static function getDelta($_log = 'core', $_position = 0, $_search = '', $_colored = false, $_numbered = true, $_numStart = 0, $_max = -1) { // Add path to file if needed $filename = (file_exists($_log) && is_file($_log)) ? $_log : self::getPathToLog($_log); @@ -359,46 +428,82 @@ public static function getDelta($_log = 'core', $_position = 0, $_search = '', $ $logText = preg_replace('/(' . $srch . ')/i', '$1', $logText); } - $search = array(); $replace = array(); - $search[] = '[DEBUG]'; $replace[] = ' D<&>EBUG '; - $search[] = '[INFO]'; $replace[] = ' I<&>NFO '; - $search[] = '[NOTICE]'; $replace[] = 'N<&>OTICE '; - $search[] = '[WARNING]'; $replace[] = 'W<&>ARNING'; - $search[] = '[ERROR]'; $replace[] = ' E<&>RROR '; - $search[] = '[CRITICAL]'; $replace[] = ' C<&>RITI '; - $search[] = '[ALERT]'; $replace[] = ' A<&>LERT '; - $search[] = '[EMERGENCY]'; $replace[] = ' E<&>MERG '; - - $search[] = '[ OK ]'; $replace[] = '[  O<&>K  ]'; - $search[] = '[ KO ]'; $replace[] = '[  K<&>O  ]'; - $search[] = ' OK '; $replace[] = ' O<&>K '; - $search[] = ' KO '; $replace[] = ' K<&>O '; - $search[] = 'ERROR'; $replace[] = 'E<&>RROR'; - $search[] = 'PHP Notice:'; $replace[] = 'PHP N<&>otice:'; - $search[] = 'PHP Warning:'; $replace[] = 'PHP War<&>ning:'; - $search[] = 'PHP Stack trace:'; $replace[] = 'PHP S<&>tack trace:'; - - $search[] = ':br:'; $replace[] = '
'; - $search[] = ':bg-success:'; $replace[] = ''; - $search[] = ':bg-info:'; $replace[] = ''; - $search[] = ':bg-warning:'; $replace[] = ''; - $search[] = ':bg-danger:'; $replace[] = ''; - $search[] = ':/bg:'; $replace[] = ''; - $search[] = ':fg-success:'; $replace[] = ''; - $search[] = ':fg-info:'; $replace[] = ''; - $search[] = ':fg-warning:'; $replace[] = ''; - $search[] = ':fg-danger:'; $replace[] = ''; - $search[] = ':/fg:'; $replace[] = ''; - $search[] = ':b:'; $replace[] = ''; - $search[] = ':/b:'; $replace[] = ''; - $search[] = ':s:'; $replace[] = ''; - $search[] = ':/s:'; $replace[] = ''; - $search[] = ':i:'; $replace[] = ''; - $search[] = ':/i:'; $replace[] = ''; - $search[] = ':hide:'; $replace[] = ''; - - foreach($GLOBALS['JEEDOM_SCLOG_TEXT'] as $item) { + $search = array(); + $replace = array(); + $search[] = '[DEBUG]'; + $replace[] = ' D<&>EBUG '; + $search[] = '[INFO]'; + $replace[] = ' I<&>NFO '; + $search[] = '[NOTICE]'; + $replace[] = 'N<&>OTICE '; + $search[] = '[WARNING]'; + $replace[] = 'W<&>ARNING'; + $search[] = '[ERROR]'; + $replace[] = ' E<&>RROR '; + $search[] = '[CRITICAL]'; + $replace[] = ' C<&>RITI '; + $search[] = '[ALERT]'; + $replace[] = ' A<&>LERT '; + $search[] = '[EMERGENCY]'; + $replace[] = ' E<&>MERG '; + + $search[] = '[ OK ]'; + $replace[] = '[  O<&>K  ]'; + $search[] = '[ KO ]'; + $replace[] = '[  K<&>O  ]'; + $search[] = ' OK '; + $replace[] = ' O<&>K '; + $search[] = ' KO '; + $replace[] = ' K<&>O '; + $search[] = 'ERROR'; + $replace[] = 'E<&>RROR'; + $search[] = 'PHP Notice:'; + $replace[] = 'PHP N<&>otice:'; + $search[] = 'PHP Warning:'; + $replace[] = 'PHP War<&>ning:'; + $search[] = 'PHP Stack trace:'; + $replace[] = 'PHP S<&>tack trace:'; + + $search[] = ':br:'; + $replace[] = '
'; + $search[] = ':bg-success:'; + $replace[] = ''; + $search[] = ':bg-info:'; + $replace[] = ''; + $search[] = ':bg-warning:'; + $replace[] = ''; + $search[] = ':bg-danger:'; + $replace[] = ''; + $search[] = ':/bg:'; + $replace[] = ''; + $search[] = ':fg-success:'; + $replace[] = ''; + $search[] = ':fg-info:'; + $replace[] = ''; + $search[] = ':fg-warning:'; + $replace[] = ''; + $search[] = ':fg-danger:'; + $replace[] = ''; + $search[] = ':/fg:'; + $replace[] = ''; + $search[] = ':b:'; + $replace[] = ''; + $search[] = ':/b:'; + $replace[] = ''; + $search[] = ':s:'; + $replace[] = ''; + $search[] = ':/s:'; + $replace[] = ''; + $search[] = ':i:'; + $replace[] = ''; + $search[] = ':/i:'; + $replace[] = ''; + $search[] = ':hide:'; + $replace[] = ''; + + foreach ($GLOBALS['JEEDOM_SCLOG_TEXT'] as $item) { $search[] = $item['txt']; // Insert a marker into subject string to avoid replacing it multiple times $subject = $item['txt'][0] . '<&>' . substr($item['txt'], 1); @@ -413,7 +518,7 @@ public static function getDelta($_log = 'core', $_position = 0, $_search = '', $ array('txt' => '-------------------- TRUNCATED LOG --------------------', 'replace' => '::') ); - foreach($replacables as $item) { + foreach ($replacables as $item) { if (strlen($item['txt']) >= 2) { $search[] = $item['txt']; // Insert a marker into subject string to avoid replacing it multiple times @@ -432,10 +537,10 @@ public static function getDelta($_log = 'core', $_position = 0, $_search = '', $ } /** - * Efficiently get the last line of a file - * @param string $_log Log filename - * @return string The last non-empty line of the file (or '') - */ + * Efficiently get the last line of a file + * @param string $_log Log filename + * @return string The last non-empty line of the file (or '') + */ public static function getLastLine($_log) { // Add path to file if needed $filename = (file_exists($_log) && is_file($_log)) ? $_log : self::getPathToLog($_log); @@ -512,7 +617,7 @@ public static function exception($e) { if (self::getConfig('log::level') > 100) { return $e->getMessage(); } else { - return $e->getMessage()."\n".$e->getTraceAsString(); + return $e->getMessage() . "\n" . $e->getTraceAsString(); } } diff --git a/core/class/plugin.class.php b/core/class/plugin.class.php index 8f43d1e354..a31c88fd3a 100644 --- a/core/class/plugin.class.php +++ b/core/class/plugin.class.php @@ -57,10 +57,10 @@ class plugin { /* * ***********************Méthodes statiques*************************** */ - public static function byId($_id,$_full = false) { + public static function byId($_id, $_full = false) { global $JEEDOM_INTERNAL_CONFIG; - if (is_string($_id) && isset(self::$_cache[$_id.'::'.$_full])) { - return self::$_cache[$_id.'::'.$_full]; + if (is_string($_id) && isset(self::$_cache[$_id . '::' . $_full])) { + return self::$_cache[$_id . '::' . $_full]; } if (!file_exists($_id) || strpos($_id, '/') === false) { $path = self::getPathById($_id); @@ -134,19 +134,19 @@ public static function byId($_id,$_full = false) { 'type' => 'class', ); } - - - $plugin->functionality['interact'] = array('exists' => method_exists($plugin->getId(), 'interact'), 'controlable' => 1); - $plugin->functionality['cron'] = array('exists' => method_exists($plugin->getId(), 'cron'), 'controlable' => 1); - $plugin->functionality['cron5'] = array('exists' => method_exists($plugin->getId(), 'cron5'), 'controlable' => 1); - $plugin->functionality['cron10'] = array('exists' => method_exists($plugin->getId(), 'cron10'), 'controlable' => 1); - $plugin->functionality['cron15'] = array('exists' => method_exists($plugin->getId(), 'cron15'), 'controlable' => 1); - $plugin->functionality['cron30'] = array('exists' => method_exists($plugin->getId(), 'cron30'), 'controlable' => 1); - $plugin->functionality['cronHourly'] = array('exists' => method_exists($plugin->getId(), 'cronHourly'), 'controlable' => 1); - $plugin->functionality['cronDaily'] = array('exists' => method_exists($plugin->getId(), 'cronDaily'), 'controlable' => 1); - $plugin->functionality['deadcmd'] = array('exists' => method_exists($plugin->getId(), 'deadCmd'), 'controlable' => 0); - $plugin->functionality['health'] = array('exists' => method_exists($plugin->getId(), 'health'), 'controlable' => 0); - + + + $plugin->functionality['interact'] = array('exists' => method_exists($plugin->getId(), 'interact'), 'controlable' => 1); + $plugin->functionality['cron'] = array('exists' => method_exists($plugin->getId(), 'cron'), 'controlable' => 1); + $plugin->functionality['cron5'] = array('exists' => method_exists($plugin->getId(), 'cron5'), 'controlable' => 1); + $plugin->functionality['cron10'] = array('exists' => method_exists($plugin->getId(), 'cron10'), 'controlable' => 1); + $plugin->functionality['cron15'] = array('exists' => method_exists($plugin->getId(), 'cron15'), 'controlable' => 1); + $plugin->functionality['cron30'] = array('exists' => method_exists($plugin->getId(), 'cron30'), 'controlable' => 1); + $plugin->functionality['cronHourly'] = array('exists' => method_exists($plugin->getId(), 'cronHourly'), 'controlable' => 1); + $plugin->functionality['cronDaily'] = array('exists' => method_exists($plugin->getId(), 'cronDaily'), 'controlable' => 1); + $plugin->functionality['deadcmd'] = array('exists' => method_exists($plugin->getId(), 'deadCmd'), 'controlable' => 0); + $plugin->functionality['health'] = array('exists' => method_exists($plugin->getId(), 'health'), 'controlable' => 0); + $plugin->functionality['interact'] = array('exists' => method_exists($plugin->getId(), 'interact'), 'controlable' => 1); $plugin->functionality['cron'] = array('exists' => method_exists($plugin->getId(), 'cron'), 'controlable' => 1); $plugin->functionality['cron5'] = array('exists' => method_exists($plugin->getId(), 'cron5'), 'controlable' => 1); @@ -157,11 +157,11 @@ public static function byId($_id,$_full = false) { $plugin->functionality['cronDaily'] = array('exists' => method_exists($plugin->getId(), 'cronDaily'), 'controlable' => 1); $plugin->functionality['deadcmd'] = array('exists' => method_exists($plugin->getId(), 'deadCmd'), 'controlable' => 0); $plugin->functionality['health'] = array('exists' => method_exists($plugin->getId(), 'health'), 'controlable' => 0); - if($_full){ - if($plugin->getCache('usedSpace',-1) == -1){ - $plugin->setCache('usedSpace',getDirectorySize(__DIR__ . '/../../plugins/' . $data['id']),86400); + if ($_full) { + if ($plugin->getCache('usedSpace', -1) == -1) { + $plugin->setCache('usedSpace', getDirectorySize(__DIR__ . '/../../plugins/' . $data['id']), 86400); } - $plugin->usedSpace = $plugin->getCache('usedSpace',-1); + $plugin->usedSpace = $plugin->getCache('usedSpace', -1); } if (!isset($JEEDOM_INTERNAL_CONFIG['plugin']['category'][$plugin->category])) { foreach ($JEEDOM_INTERNAL_CONFIG['plugin']['category'] as $key => $value) { @@ -174,7 +174,7 @@ public static function byId($_id,$_full = false) { } } } - self::$_cache[$plugin->id.'::'.$_full] = $plugin; + self::$_cache[$plugin->id . '::' . $_full] = $plugin; return $plugin; } @@ -619,14 +619,14 @@ public static function checkDeamon() { } } - public static function isInstalled($_pluginId): bool { - try { - plugin::byId($_pluginId); - return true; - } catch (Exception $e) { - return false; - } - } + public static function isInstalled($_pluginId): bool { + try { + plugin::byId($_pluginId); + return true; + } catch (Exception $e) { + return false; + } + } /* * *********************Méthodes d'instance************************* */ @@ -689,7 +689,7 @@ public function callInstallFunction($_function, $_direct = false) { public function dependancy_info($_refresh = false) { $plugin_id = $this->getId(); - $cache = cache::byKey('dependancy' . $this->getID()); + $cache = cache::byKey('dependancy' . $this->getId()); if ($_refresh) { $cache->remove(); } else { @@ -725,14 +725,16 @@ public function dependancy_info($_refresh = false) { } $return['last_launch'] = config::byKey('lastDependancyInstallTime', $this->getId(), __('Inconnue', __FILE__)); $return['auto'] = config::byKey('dependancyAutoMode', $this->getId(), 1); - if ($return['state'] != 'in_progress' && method_exists($plugin_id, 'additionnalDependancyCheck')) { + + if ($return['state'] === 'ok' && method_exists($plugin_id, 'additionnalDependancyCheck')) { $additionnal = $plugin_id::additionnalDependancyCheck(); if (isset($additionnal['state'])) { $return['state'] = $additionnal['state']; } } - if ($return['state'] == 'ok') { - cache::set('dependancy' . $this->getID(), $return); + + if ($return['state'] === 'ok') { + cache::set('dependancy' . $this->getId(), $return); } return $return; } @@ -764,7 +766,7 @@ public function dependancy_info($_refresh = false) { $return['last_launch'] = config::byKey('lastDependancyInstallTime', $this->getId(), __('Inconnue', __FILE__)); $return['auto'] = config::byKey('dependancyAutoMode', $this->getId(), 1); if ($return['state'] == 'ok') { - cache::set('dependancy' . $this->getID(), $return); + cache::set('dependancy' . $this->getId(), $return); } return $return; } @@ -776,7 +778,7 @@ public function dependancy_info($_refresh = false) { public function dependancy_install($_force = false, $_foreground = false) { $plugin_id = $this->getId(); if (!$_force && config::byKey('dontProtectTooFastLaunchDependancy') == 0 && abs(strtotime('now') - strtotime(config::byKey('lastDependancyInstallTime', $plugin_id))) <= 60) { - $cache = cache::byKey('dependancy' . $this->getID()); + $cache = cache::byKey('dependancy' . $this->getId()); $cache->remove(); throw new Exception(__('Vous devez attendre au moins 60 secondes entre deux lancements d\'installation de dépendances', __FILE__)); } @@ -788,7 +790,7 @@ public function dependancy_install($_force = false, $_foreground = false) { $this->deamon_stop(); config::save('lastDependancyInstallTime', date('Y-m-d H:i:s'), $plugin_id); system::checkAndInstall(json_decode(file_get_contents(__DIR__ . '/../../plugins/' . $plugin_id . '/plugin_info/packages.json'), true), true, $_foreground, $plugin_id, $_force); - $cache = cache::byKey('dependancy' . $this->getID()); + $cache = cache::byKey('dependancy' . $this->getId()); $cache->remove(); return; } @@ -831,7 +833,7 @@ public function dependancy_install($_force = false, $_foreground = false) { log::add($plugin_id, 'error', __('Aucun script ne correspond à votre type de Linux :', __FILE__) . ' ' . $cmd['script'] . ' ' . __('avec #stype# :', __FILE__) . ' ' . system::get('type')); } } - $cache = cache::byKey('dependancy' . $this->getID()); + $cache = cache::byKey('dependancy' . $this->getId()); $cache->remove(); return; } @@ -966,9 +968,9 @@ public function setIsEnable($_state, $_force = false, $_foreground = false) { } $osVersion = $this->getRequireOsVersion(); $distrib = system::getDistrib(); - if(isset($osVersion)){ + if (isset($osVersion)) { if ($distrib == 'debian' && version_compare(system::getOsVersion(), $osVersion) == -1 && $_state == 1) { - throw new Exception(__('Votre version Debian n\'est pas assez récente pour activer cette version du plugin, '.$osVersion.' minimum demandé', __FILE__)); + throw new Exception(__('Votre version Debian n\'est pas assez récente pour activer cette version du plugin, ' . $osVersion . ' minimum demandé', __FILE__)); } } $alreadyActive = config::byKey('active', $this->getId(), 0); diff --git a/core/class/scenario.class.php b/core/class/scenario.class.php index 2b96c67bec..c8385ed3a4 100644 --- a/core/class/scenario.class.php +++ b/core/class/scenario.class.php @@ -912,16 +912,20 @@ public function execute($instance_id = '') { return; } } - $cmd = cmd::byId(str_replace('#', '', $this->getTag('trigger_id'))); - if (is_object($cmd)) { - log::add('event', 'info', __('Exécution du scénario', __FILE__) . ' ' . $this->getHumanName() . ' ' . __('déclenché par :', __FILE__) . ' ' . $cmd->getHumanName()); + if($this->getTag('trigger') == 'scenario'){ + $obj_trigger = scenario::byId(str_replace('#', '', $this->getTag('trigger_id'))); + }else{ + $obj_trigger = cmd::byId(str_replace('#', '', $this->getTag('trigger_id'))); + } + if (is_object($obj_trigger)) { + log::add('event', 'info', __('Exécution du scénario', __FILE__) . ' ' . $this->getHumanName() . ' ' . __('déclenché par :', __FILE__) . ' ' . $obj_trigger->getHumanName()); if ($this->getConfiguration('timeline::enable')) { $timeline = new timeline(); $timeline->setType('scenario'); $timeline->setFolder($this->getConfiguration('timeline::folder')); $timeline->setLink_id($this->getId()); $timeline->setName($this->getHumanName(true, true, true, true)); - $timeline->setOptions(array('trigger' => $cmd->getHumanName(true))); + $timeline->setOptions(array('trigger' => $obj_trigger->getHumanName(true))); $timeline->save(); } } else { @@ -2024,7 +2028,7 @@ public function getTags() { * @return $this */ public function setTags($_tags) { - $this->_tags = $_tags; + $this->_tags = array_merge($this->_tags, $_tags); return $this; } diff --git a/core/class/scenarioExpression.class.php b/core/class/scenarioExpression.class.php index 952352df20..122c407b8e 100644 --- a/core/class/scenarioExpression.class.php +++ b/core/class/scenarioExpression.class.php @@ -194,17 +194,17 @@ public static function getDatesFromPeriod($_period = '1 hour') { if ($_period == 'day') $_period = '1 day'; if (ctype_digit($_period[0]) && !stristr($_period, "ago")) { - $_startTime = date('Y-m-d H:i:s',(int) strtotime('-' . $_period)); + $_startTime = date('Y-m-d H:i:s', (int) strtotime('-' . $_period)); } else { - $_startTime = date('Y-m-d H:i:s',(int) strtotime($_period)); + $_startTime = date('Y-m-d H:i:s', (int) strtotime($_period)); } $_endTime = date('Y-m-d H:i:s'); if ($_period == 'today') { $_startTime = date('Y-m-d') . ' 00:00:00'; } elseif ($_period == 'yesterday') { - $_startTime = date('Y-m-d',(int) strtotime('-1 day')) . ' 00:00:00'; - $_endTime = date('Y-m-d',(int) strtotime('-1 day')) . ' 23:59:59'; + $_startTime = date('Y-m-d', (int) strtotime('-1 day')) . ' 00:00:00'; + $_endTime = date('Y-m-d', (int) strtotime('-1 day')) . ' 23:59:59'; } return array($_startTime, $_endTime); } @@ -213,19 +213,20 @@ public static function randText($_sValue) { $_sValue = self::setTags($_sValue); $_aValue = explode(";", $_sValue); try { - $result = evaluate($_aValue); + $result = evaluate($_sValue); if (is_string($result)) { $result = $_aValue; } } catch (Exception $e) { $result = $_aValue; } - if (is_array($_aValue)) { - $nbr = mt_rand(0, count($_aValue) - 1); - return $_aValue[$nbr]; - } else { - return $_aValue; + if (is_array($result)) { + if (count($result) === 0) { + return ''; + } + return $result[array_rand($result)]; } + return $result; } public static function scenario($_scenario) { @@ -303,8 +304,8 @@ public static function averageBetween($_cmd_id, $_startDate, $_endDate, $_round if (!is_object($cmd) || $cmd->getIsHistorized() == 0) { return ''; } - $_startTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_startDate))); - $_endTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_endDate))); + $_startTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_startDate))); + $_endTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_endDate))); $historyStatistique = $cmd->getStatistique($_startTime, $_endTime); if (!isset($historyStatistique['avg'])) { return ''; @@ -328,8 +329,8 @@ public static function averageTemporalBetween($_cmd_id, $_startDate, $_endDate, if (!is_object($cmd) || $cmd->getIsHistorized() == 0) { return ''; } - $_startTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_startDate))); - $_endTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_endDate))); + $_startTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_startDate))); + $_endTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_endDate))); return round($cmd->getTemporalAvg($_startTime, $_endTime), $_round); } @@ -458,8 +459,8 @@ public static function maxBetween($_cmd_id, $_startDate, $_endDate, $_round = 1) if (!is_object($cmd) || $cmd->getIsHistorized() == 0) { return ''; } - $_startTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_startDate))); - $_endTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_endDate))); + $_startTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_startDate))); + $_endTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_endDate))); $historyStatistique = $cmd->getStatistique($_startTime, $_endTime); if (!isset($historyStatistique['max'])) { return ''; @@ -489,8 +490,8 @@ public static function minBetween($_cmd_id, $_startDate, $_endDate, $_round = 1) if (!is_object($cmd) || $cmd->getIsHistorized() == 0) { return ''; } - $_startTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_startDate))); - $_endTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_endDate))); + $_startTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_startDate))); + $_endTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_endDate))); $historyStatistique = $cmd->getStatistique($_startTime, $_endTime); if (!isset($historyStatistique['min'])) { return ''; @@ -642,8 +643,8 @@ public static function stateChangesBetween($_cmd_id, $_value, $_startDate, $_end $_endDate = func_get_arg(2); $_value = null; } - $_startTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_startDate))); - $_endTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_endDate))); + $_startTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_startDate))); + $_endTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_endDate))); return history::stateChanges($cmd_id, $_value, $_startTime, $_endTime); } @@ -724,8 +725,8 @@ public static function durationBetween($_cmd_id, $_value, $_startDate, $_endDate $_endDate = date('Y-m-d H:i:s'); } - $_startTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_startDate))); - $_endTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_endDate))); + $_startTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_startDate))); + $_endTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_endDate))); $_value = str_replace(',', '.', $_value); $_decimal = strlen(substr(strrchr($_value, "."), 1)); @@ -769,8 +770,8 @@ public static function lastBetween($_cmd_id, $_startDate, $_endDate) { if (!is_object($cmd) || $cmd->getIsHistorized() == 0) { return ''; } - $_startTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_startDate))); - $_endTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_endDate))); + $_startTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_startDate))); + $_endTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_endDate))); $historyStatistique = $cmd->getStatistique($_startTime, $_endTime); if (!isset($historyStatistique['last']) || $historyStatistique['last'] === '') { return ''; @@ -802,8 +803,8 @@ public static function statisticsBetween($_cmd_id, $_calc, $_startDate, $_endDat return ''; } $_calc = str_replace(' ', '', $_calc); - $_startTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_startDate))); - $_endTime = date('Y-m-d H:i:s',(int) strtotime(self::setTags($_endDate))); + $_startTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_startDate))); + $_endTime = date('Y-m-d H:i:s', (int) strtotime(self::setTags($_endDate))); $historyStatistique = $cmd->getStatistique(self::setTags($_startTime), self::setTags($_endTime)); return $historyStatistique[$_calc]; } @@ -960,7 +961,7 @@ public static function trigger($_name = '', &$_scenario = null) { if (trim($_name) == '') { return $_scenario->getTag('trigger_name'); } - if (trim(jeedom::toHumanReadable($_name),'#') == $_scenario->getTag('trigger_name')) { + if (trim(jeedom::toHumanReadable($_name), '#') == $_scenario->getTag('trigger_name')) { return 1; } return 0; @@ -1038,8 +1039,8 @@ public static function time_diff($_date1, $_date2, $_format = 'd', $_rnd = 2) { if ($_date2 < 100) $_date2 = '00' . $_date2; if ($_date2 < 1000) $_date2 = '0' . $_date2; } - $d1 = str_replace(array('"','\'',"'"), '', self::setTags($_date1)); - $d2 = str_replace(array('"','\'',"'"), '', self::setTags($_date2)); + $d1 = str_replace(array('"', '\'', "'"), '', self::setTags($_date1)); + $d2 = str_replace(array('"', '\'', "'"), '', self::setTags($_date2)); $date1 = new DateTime($d1); $date2 = new DateTime($d2); $duree = $date2->getTimestamp() - $date1->getTimestamp(); @@ -1275,6 +1276,9 @@ public static function setTags(&$_expression, &$_scenario = null, $_quote = fals } if ($_quote) { foreach ($replace1 as &$value) { + if ($value === null) { + continue; + } if (strpos($value, ' ') !== false || preg_match("/[a-zA-Z]/", $value) || $value === '') { $value = '"' . trim($value, '"') . '"'; } @@ -1386,7 +1390,7 @@ public function execute(&$scenario = null) { } $this->checkBackground(); if ($this->getOptions('background', 0) == 1) { - $key = 'scenarioElement'.$this->getId().'::' . config::genKey(16).'::'.strtotime('now'); + $key = 'scenarioElement' . $this->getId() . '::' . config::genKey(16) . '::' . strtotime('now'); cache::set($key, array('scenarioExpression' => $this, 'scenario' => $scenario), 60); $cmd = __DIR__ . '/../php/jeeScenarioExpression.php'; $cmd .= ' key=' . $key; @@ -1547,16 +1551,13 @@ public function execute(&$scenario = null) { event::add('changeTheme', $options['theme']); return; } elseif ($this->getExpression() == 'scenario') { - if ($scenario !== null && $this->getOptions('scenario_id') == $scenario->getId()) { - $actionScenario = &$scenario; - } else { - $actionScenario = scenario::byId($this->getOptions('scenario_id')); - } + $actionScenario = scenario::byId($this->getOptions('scenario_id')); if (!is_object($actionScenario)) { throw new Exception($GLOBALS['JEEDOM_SCLOG_TEXT']['unfoundScenario']['txt'] . $this->getOptions('scenario_id')); } switch ($this->getOptions('action')) { case 'start': + case 'startsync': if ($this->getOptions('tags') != '' && !is_array($this->getOptions('tags'))) { $tags = array(); $args = arg2array($this->getOptions('tags')); @@ -1569,45 +1570,19 @@ public function execute(&$scenario = null) { if (is_array($this->getOptions('tags'))) { $actionScenario->setTags($this->getOptions('tags')); } - $this->setLog($scenario, $GLOBALS['JEEDOM_SCLOG_TEXT']['launchScenario']['txt'] . $actionScenario->getName() . ' ' . __('options :', __FILE__) . ' ' . json_encode($actionScenario->getTags())); - if ($scenario !== null) { - $actionScenario->addTag('trigger','scenario'); - $actionScenario->addTag('trigger_message',$GLOBALS['JEEDOM_SCLOG_TEXT']['startByScenario']['txt'] . $scenario->getHumanName()); - $actionScenario->addTag('trigger_name',trim($scenario->getHumanName(),'#')); - $actionScenario->addTag('trigger_id',$scenario->getId()); - return $actionScenario->launch(); - } else { - $actionScenario->addTag('trigger','other'); - $actionScenario->addTag('trigger_message',$GLOBALS['JEEDOM_SCLOG_TEXT']['startCausedBy']['txt']); - return $actionScenario->launch(); - } - break; - case 'startsync': - if ($this->getOptions('tags') != '' && !is_array($this->getOptions('tags'))) { - $tags = array(); - $args = arg2array($this->getOptions('tags')); - foreach ($args as $key => $value) { - $value = trim($value); - $tags['#' . trim(trim($key), '#') . '#'] = trim(self::setTags($value, $scenario), '"'); - } - $actionScenario->setTags($tags); - } - if (is_array($this->getOptions('tags'))) { - $actionScenario->setTags($this->getOptions('tags')); - } - $this->setLog($scenario, $GLOBALS['JEEDOM_SCLOG_TEXT']['launchScenario']['txt'] . $actionScenario->getName() . ' ' . __('options :', __FILE__) . ' ' . json_encode($actionScenario->getTags())); if ($scenario !== null) { - $actionScenario->addTag('trigger','scenario'); - $actionScenario->addTag('trigger_message',$GLOBALS['JEEDOM_SCLOG_TEXT']['startByScenario']['txt'] . $scenario->getHumanName()); - $actionScenario->addTag('trigger_name',trim($scenario->getHumanName(),'#')); - $actionScenario->addTag('trigger_id',$scenario->getId()); - return $actionScenario->launch(true); + $actionScenario->addTag('trigger', 'scenario'); + $actionScenario->addTag('trigger_message', $GLOBALS['JEEDOM_SCLOG_TEXT']['startByScenario']['txt'] . $scenario->getHumanName()); + $actionScenario->addTag('trigger_name', trim($scenario->getHumanName(), '#')); + $actionScenario->addTag('trigger_id', $scenario->getId()); } else { - $actionScenario->addTag('trigger','other'); - $actionScenario->addTag('trigger_message',$GLOBALS['JEEDOM_SCLOG_TEXT']['startCausedBy']['txt']); - return $actionScenario->launch(true); + $actionScenario->addTag('trigger', 'other'); + $actionScenario->addTag('trigger_message', $GLOBALS['JEEDOM_SCLOG_TEXT']['startCausedBy']['txt']); } - break; + $forceSync = ($this->getOptions('action') == 'startsync'); + $launchScenarioLogKey = ($forceSync) ? 'launchScenarioSync' : 'launchScenario'; + $this->setLog($scenario, $GLOBALS['JEEDOM_SCLOG_TEXT'][$launchScenarioLogKey]['txt'] . $actionScenario->getName() . ' ' . __('options :', __FILE__) . ' ' . json_encode($actionScenario->getTags())); + return $actionScenario->launch($forceSync); case 'stop': $this->setLog($scenario, __('Arrêt forcé du scénario :', __FILE__) . ' ' . $actionScenario->getName()); $actionScenario->stop(); @@ -1791,8 +1766,8 @@ public function execute(&$scenario = null) { $tmp_file = jeedom::getTmpFolder('history_export') . '/' . $options['name'] . '.csv'; $cmd_parameters = array('files' => [$tmp_file], 'title' => $options['name'], 'message' => $options['name']); - $start = date('Y-m-d H:i:s',(int) strtotime($options['start'])); - $end = date('Y-m-d H:i:s',(int) strtotime($options['end'])); + $start = date('Y-m-d H:i:s', (int) strtotime($options['start'])); + $end = date('Y-m-d H:i:s', (int) strtotime($options['end'])); $this->setLog($scenario, __('Export de l\'historique du', __FILE__) . ' ' . $start . ' ' . __('au', __FILE__) . ' ' . $end); $histories = array(); diff --git a/core/class/system.class.php b/core/class/system.class.php index af5962d3d7..347876791f 100644 --- a/core/class/system.class.php +++ b/core/class/system.class.php @@ -793,7 +793,7 @@ public static function installPackageInProgress($_plugin = ''): bool { } return true; } - if (shell_exec('ls /tmp/jeedom_install_in_progress* | wc -l') > 0) { + if (shell_exec('ls /tmp/jeedom_install_in_progress* | wc -l 2> /dev/null') > 0) { return true; } return false; @@ -918,4 +918,4 @@ public static function checkInstallationLog($_plugin = ''): string { } return ''; } -} \ No newline at end of file +} diff --git a/core/class/update.class.php b/core/class/update.class.php index c2b5062355..4fa62240b0 100644 --- a/core/class/update.class.php +++ b/core/class/update.class.php @@ -515,7 +515,7 @@ public function checkUpdate() { return; } if (config::byKey('core::repo::provider') == 'default') { - $this->setRemoteVersion(self::getLastAvailableVersion(true)); + $this->setRemoteVersion(self::getLastAvailableVersion()); } else { $class = 'repo_' . config::byKey('core::repo::provider'); if (!method_exists($class, 'versionCore') || config::byKey(config::byKey('core::repo::provider') . '::enable') != 1) { diff --git a/core/class/user.class.php b/core/class/user.class.php index 8f834215c1..95567f5302 100644 --- a/core/class/user.class.php +++ b/core/class/user.class.php @@ -122,7 +122,7 @@ public static function connect(string $_login, string $_mdp) { ->setProfils($profile); $user->save(); log::add("connection", "info", __('User created from the LDAP :', __FILE__) . ' ' . $_login); - jeedom::event('user_connect'); + jeedom::event('user_connect', false, array('trigger_value' => $_login)); // TODO : if username == password => change ldap password log::add('event', 'info', __('User connection accepted', __FILE__) . ' ' . $_login); return $user; @@ -145,7 +145,7 @@ public static function connect(string $_login, string $_mdp) { if (is_object($user)) { $user->setOptions('lastConnection', date('Y-m-d H:i:s')); $user->save(); - jeedom::event('user_connect'); + jeedom::event('user_connect', false, array('trigger_value' => $_login)); log::add('event', 'info', __('Local account found for', __FILE__) . ' ' . $_login); log::add('event', 'info', __('User connection accepted', __FILE__) . ' ' . $_login); } diff --git a/core/config/default.config.ini b/core/config/default.config.ini index 1d54bc82d2..8ad321a6c1 100644 --- a/core/config/default.config.ini +++ b/core/config/default.config.ini @@ -80,6 +80,7 @@ security::whiteips = "127.0.0.1;192.168.*.*;10.*.*.*;172.*.*.*" ;Log maxLineLog = 500 +maxSizeLog = 5 log::level = 400 log::syslogudpport = 514 log::syslogudpfacility = user diff --git a/core/config/version b/core/config/version index 958d30d86d..4e298cc965 100644 --- a/core/config/version +++ b/core/config/version @@ -1 +1 @@ -4.5 \ No newline at end of file +4.5.3 diff --git a/core/js/history.class.js b/core/js/history.class.js index 9af112f932..0d1d80f807 100644 --- a/core/js/history.class.js +++ b/core/js/history.class.js @@ -160,7 +160,7 @@ jeedom.history.graphUpdate = function(_params) { continue; } for(var chart in jeedom.history.chart){ - for(var serie in jeedom.history.chart[chart]){ + for(var serie in jeedom.history.chart[chart].chart.series){ if(jeedom.history.chart[chart].chart.series[serie] && jeedom.history.chart[chart].chart.series[serie].options.id == _params[i].cmd_id){ jeedom.history.chart[chart].chart.series[serie].addPoint([Date.now()+(-1*(new Date()).getTimezoneOffset()*60*1000),_params[i].value]) } diff --git a/core/repo/github.repo.php b/core/repo/github.repo.php index 136428ed4b..f76cf5e179 100644 --- a/core/repo/github.repo.php +++ b/core/repo/github.repo.php @@ -22,19 +22,19 @@ class repo_github { /* * *************************Attributs****************************** */ - + public static $_name = 'Github'; - + public static $_scope = array( 'plugin' => true, 'backup' => false, 'hasConfiguration' => true, 'core' => true, ); - - + + /* * ***********************Méthodes statiques*************************** */ - + public static function getConfigurationOption(){ return array( 'parameters_for_add' => array( @@ -79,7 +79,7 @@ public static function getConfigurationOption(){ ), ); } - + public static function checkUpdate(&$_update) { if (is_array($_update)) { if (count($_update) < 1) { @@ -123,7 +123,7 @@ public static function getBranchInfo($_update){ $request_http->setHeader($headers); return json_decode($request_http->exec(10, 1), true); } - + public static function downloadObject($_update) { $token = $_update->getConfiguration('token',config::byKey('github::token','core','')); $branch = self::getBranchInfo($_update); @@ -141,29 +141,41 @@ public static function downloadObject($_update) { $url = 'https://api.github.com/repos/' . $_update->getConfiguration('user') . '/' . $_update->getConfiguration('repository') . '/zipball/' . $_update->getConfiguration('version', 'master'); log::add('update', 'alert', __('Téléchargement de', __FILE__) . ' ' . $_update->getLogicalId() . '...'); if ($token == '') { - $result = shell_exec('curl -s -L ' . $url . ' > ' . $tmp); + exec('curl -s -f -L -o ' . escapeshellarg($tmp) . ' ' . escapeshellarg($url) . ' 2>&1', $output, $return_code); } else { - $result = shell_exec('curl -s -H "Authorization: token ' . $token . '" -L ' . $url . ' > ' . $tmp); + exec('curl -s -f -L -H ' . escapeshellarg('Authorization: token ' . $token) . ' -o ' . escapeshellarg($tmp) . ' ' . escapeshellarg($url) . ' 2>&1', $output, $return_code); } - log::add('update', 'alert', $result); - + if ($return_code !== 0 || !file_exists($tmp) || filesize($tmp) == 0) { + $error_msg = __('Erreur lors du téléchargement', __FILE__); + if (!empty($output)) { + $error_msg .= ': ' . implode("\n", $output); + } + if (!file_exists($tmp)) { + $error_msg .= ' - ' . __('Fichier non créé', __FILE__); + } elseif (filesize($tmp) == 0) { + $error_msg .= ' - ' . __('Fichier vide', __FILE__); + } + log::add('update', 'error', $error_msg); + throw new Exception($error_msg); + } + log::add('update', 'info', __('Téléchargement réussi', __FILE__) . ' (' . round(filesize($tmp) / 1024 / 1024, 2) . ' MB)'); + if (!isset($branch['commit']) || !isset($branch['commit']['sha'])) { return array('path' => $tmp); } return array('localVersion' => $branch['commit']['sha'], 'path' => $tmp); } - + public static function deleteObjet($_update) { - } - + public static function objectInfo($_update) { return array( 'doc' => 'https://github.com/' . $_update->getConfiguration('user') . '/' . $_update->getConfiguration('repository') . '/blob/' . $_update->getConfiguration('version', 'master') . '/doc/' . config::byKey('language', 'core', 'fr_FR') . '/index.asciidoc', 'changelog' => 'https://github.com/' . $_update->getConfiguration('user') . '/' . $_update->getConfiguration('repository') . '/commits/' . $_update->getConfiguration('version', 'master'), ); } - + public static function downloadCore($_path) { $url = 'https://api.github.com/repos/' . config::byKey('github::core::user', 'core', 'jeedom') . '/' . config::byKey('github::core::repository', 'core', 'core') . '/zipball/' . config::byKey('github::core::branch', 'core', 'stable'); echo __('Téléchargement de', __FILE__) . ' ' . $url . '...'; @@ -174,15 +186,14 @@ public static function downloadCore($_path) { } return; } - + public static function versionCore() { $url = 'https://raw.githubusercontent.com/'.config::byKey('github::core::user', 'core', 'jeedom').'/'.config::byKey('github::core::repository', 'core', 'core').'/' . config::byKey('github::core::branch', 'core', 'stable') . '/core/config/version'; $request_http = new com_http($url); return trim($request_http->exec(30)); } - + /* * *********************Methode d'instance************************* */ - + /* * **********************Getteur Setteur*************************** */ - } diff --git a/core/repo/market.display.repo.php b/core/repo/market.display.repo.php index cb0aa4a257..551e03f3e6 100644 --- a/core/repo/market.display.repo.php +++ b/core/repo/market.display.repo.php @@ -114,21 +114,25 @@ ?>

getCertification() == 'Premium') { - echo '{{Nous Contacter}}'; + echo '{{Nous Contacter}}'; } else { - if ($market->getCost() > 0) { - if ($market->getPurchase() == 1 && isset($purchase_info['user_id']) && is_numeric($purchase_info['user_id'])) { - echo '{{Plugin deja acheté et/ou inclus dans votre service Pack}}'; - }else{ - if ($market->getCost() != $market->getRealCost()) { + if (isset($purchase_info['user_id']) && is_numeric($purchase_info['user_id']) && $market->getPurchase() == 1) { + echo '{{Plugin deja acheté et/ou inclus dans votre service Pack}}'; + } else { + if ($market->getCost() > 0) { + if ($market->getCost() != $market->getRealCost()) { echo '' . number_format($market->getRealCost(), 2) . ' € '; - } - echo '' . number_format($market->getCost(), 2) . ' € TTC'; - } - } else { - echo '{{Gratuit}}'; - } + } + echo '' . number_format($market->getCost(), 2) . ' € TTC'; + } else { + echo '{{Gratuit}}'; + } + } } ?> diff --git a/core/repo/market.repo.php b/core/repo/market.repo.php index 97b7c08c33..d4a5de72bb 100644 --- a/core/repo/market.repo.php +++ b/core/repo/market.repo.php @@ -144,7 +144,7 @@ public static function pullInstall() { $update->setType($repo->getType()); $update->setLocalVersion($repo->getDatetime($plugin['version'])); $update->setConfiguration('version', $plugin['version']); - $update->setConfiguration('user',null); + $update->setConfiguration('user', null); $update->save(); $update->doUpdate(); $nbInstall++; @@ -231,31 +231,32 @@ public static function objectInfo($_update) { /* * ***********************BACKUP*************************** */ public static function backup_createFolderIsNotExist() { - $request_http = new com_http(config::byKey('service::backup::url').'/webdav/'.config::byKey('market::username'),config::byKey('market::username'),config::byKey('market::password')); + $request_http = new com_http(config::byKey('service::backup::url') . '/webdav/' . urlencode(config::byKey('market::username')), config::byKey('market::username'), config::byKey('market::password')); $request_http->setCURLOPT(array( - CURLOPT_CUSTOMREQUEST => "PROPFIND" + CURLOPT_CUSTOMREQUEST => "PROPFIND" )); $xml = simplexml_load_string($request_http->exec()); $ns = $xml->getNamespaces(true); $child = $xml->children($ns['D']); - $found = false; + $found = false; foreach ($child->response as $file) { - if($file->propstat->prop->getcontenttype){ + if ($file->propstat->prop->getcontenttype) { continue; } - $folder = trim(trim(str_replace('http://backup.jeedom.com/webdav/'.config::byKey('market::username'),'',$file->href),'/')); - if($folder == ''){ + $folder = trim(trim(str_replace('http://backup.jeedom.com/webdav/' . urlencode(config::byKey('market::username')), '', $file->href), '/')); + $folder = trim(trim(str_replace('http://backup.jeedom.com/webdav/' . config::byKey('market::username'), '', $folder), '/')); + if ($folder == '') { continue; } - if($folder == config::byKey('market::cloud::backup::name')){ + if ($folder == config::byKey('market::cloud::backup::name')) { $found = true; break; } } if (!$found) { - $request_http = new com_http(config::byKey('service::backup::url').'/webdav/'.config::byKey('market::username').'/'.rawurldecode(config::byKey('market::cloud::backup::name')),config::byKey('market::username'),config::byKey('market::password')); + $request_http = new com_http(config::byKey('service::backup::url') . '/webdav/' . urlencode(config::byKey('market::username')) . '/' . rawurldecode(config::byKey('market::cloud::backup::name')), config::byKey('market::username'), config::byKey('market::password')); $request_http->setCURLOPT(array( - CURLOPT_CUSTOMREQUEST => "MKCOL" + CURLOPT_CUSTOMREQUEST => "MKCOL" )); $request_http->exec(); } @@ -271,7 +272,7 @@ public static function backup_send($_path) { if (config::byKey('market::cloud::backup::password') != config::byKey('market::cloud::backup::password_confirmation')) { throw new Exception(__('Le mot de passe du backup cloud n\'est pas identique à la confirmation', __FILE__)); } - self::backup_clean($_path); + //self::backup_clean($_path); self::backup_createFolderIsNotExist(); try { if (!file_exists('/tmp/jeedom_gnupg')) { @@ -280,8 +281,13 @@ public static function backup_send($_path) { com_shell::execute('sudo chmod 777 -R /tmp/jeedom_gnupg'); $cmd = 'echo "' . config::byKey('market::cloud::backup::password') . '" | gpg --homedir /tmp/jeedom_gnupg --batch --yes --passphrase-fd 0 -c ' . $_path; com_shell::execute($cmd); - $cmd = "curl --user '".config::byKey('market::username').":".config::byKey('market::password')."' -T '".$_path . '.gpg'."' '".config::byKey('service::backup::url').'/webdav/'.config::byKey('market::username'). '/' . rawurldecode(config::byKey('market::cloud::backup::name'))."/'"; - com_shell::execute($cmd); + $cmd = "curl --retry 5 --retry-delay 3 --retry-max-time 60 --retry-connrefused --keepalive-time 30 --user '" . config::byKey('market::username') . ":" . config::byKey('market::password') . "' -T '" . $_path . '.gpg' . "' '" . config::byKey('service::backup::url') . '/webdav/' . urlencode(config::byKey('market::username')) . '/' . rawurldecode(config::byKey('market::cloud::backup::name')) . "/'"; + try { + com_shell::execute($cmd); + } catch (\Exception $e) { + $cmd = "curl --http1.1 --retry 5 --retry-delay 3 --retry-max-time 60 --retry-connrefused --keepalive-time 30 --user '" . config::byKey('market::username') . ":" . config::byKey('market::password') . "' -T '" . $_path . '.gpg' . "' '" . config::byKey('service::backup::url') . '/webdav/' . urlencode(config::byKey('market::username')) . '/' . rawurldecode(config::byKey('market::cloud::backup::name')) . "/'"; + com_shell::execute($cmd); + } unlink($_path . '.gpg'); rrmdir('/tmp/jeedom_gnupg'); } catch (\Exception $e) { @@ -298,17 +304,17 @@ public static function backup_clean($_path) { $limit = 3700; self::backup_createFolderIsNotExist(); - $request_http = new com_http(config::byKey('service::backup::url').'/webdav/'.config::byKey('market::username'),config::byKey('market::username'),config::byKey('market::password')); + $request_http = new com_http(config::byKey('service::backup::url') . '/webdav/' . urlencode(config::byKey('market::username')), config::byKey('market::username'), config::byKey('market::password')); $request_http->setCURLOPT(array( - CURLOPT_CUSTOMREQUEST => "PROPFIND" + CURLOPT_CUSTOMREQUEST => "PROPFIND" )); $xml = simplexml_load_string($request_http->exec()); $ns = $xml->getNamespaces(true); $child = $xml->children($ns['D']); $total_size = 0; - $files = []; + $files = []; foreach ($child->response as $file) { - if(!$file->propstat->prop->getcontenttype){ + if (!$file->propstat->prop->getcontenttype) { continue; } $files[] = array( @@ -335,9 +341,9 @@ public static function backup_clean($_path) { } $file = array_shift($files); echo __('Supression du backup cloud :', __FILE__) . ' ' . $file['name'] . "\n"; - $request_http = new com_http($file['href'],config::byKey('market::username'),config::byKey('market::password')); + $request_http = new com_http($file['href'], config::byKey('market::username'), config::byKey('market::password')); $request_http->setCURLOPT(array( - CURLOPT_CUSTOMREQUEST => "DELETE" + CURLOPT_CUSTOMREQUEST => "DELETE" )); $request_http->exec(); $total_size -= $file['size']; @@ -353,24 +359,24 @@ public static function backup_list() { return array(); } self::backup_createFolderIsNotExist(); - $request_http = new com_http(config::byKey('service::backup::url').'/webdav/'.config::byKey('market::username'). '/' . rawurldecode(config::byKey('market::cloud::backup::name')),config::byKey('market::username'),config::byKey('market::password')); + $request_http = new com_http(config::byKey('service::backup::url') . '/webdav/' . urlencode(config::byKey('market::username')) . '/' . rawurldecode(config::byKey('market::cloud::backup::name')), config::byKey('market::username'), config::byKey('market::password')); $request_http->setCURLOPT(array( - CURLOPT_CUSTOMREQUEST => "PROPFIND" + CURLOPT_CUSTOMREQUEST => "PROPFIND" )); $xml = simplexml_load_string($request_http->exec()); $ns = $xml->getNamespaces(true); $child = $xml->children($ns['D']); $files = array(); foreach ($child->response as $file) { - if(!$file->propstat->prop->getcontenttype){ + if (!$file->propstat->prop->getcontenttype) { continue; } $files[] = array( - 'name' => (string) $file->propstat->prop->displayname, - 'timestamp' => strtotime($file->propstat->prop->getlastmodified) - ); + 'name' => (string) $file->propstat->prop->displayname, + 'timestamp' => strtotime($file->propstat->prop->getlastmodified) + ); } - function cmp($a,$b){ // $a,$b are reference to first index of array + function cmp($a, $b) { // $a,$b are reference to first index of array return strcmp($a["timestamp"], $b["timestamp"]); } usort($files, "cmp"); @@ -411,6 +417,9 @@ public static function backup_restore($_backup) { /* * ***********************CRON*************************** */ public static function cronHourly() { + if (empty(config::byKey('market::username')) || empty(config::byKey('market::password'))) { + return; + } if (strtotime(config::byKey('market::lastCommunication', 'core', 0)) > (strtotime('now') - (24 * 3600))) { return; } @@ -441,7 +450,7 @@ public static function cron5() { try { $result = json_decode($request_http->exec(60, 1), true); if ($result == null || $result['state'] != 'ok') { - sleep(rand(5,45)); + sleep(rand(5, 45)); $result = json_decode($request_http->exec(60, 1), true); } if ($result == null || $result['state'] != 'ok') { @@ -957,13 +966,13 @@ public function install($_version = 'stable') { } $url = config::byKey('market::address') . "/core/php/downloadFile.php?id=" . $this->getId(); - $url .='&version=' . $_version ; - $url .='&jeedomversion=' . jeedom::version(); - $url .='&osversion=' . system::getOsVersion(); - $url .='&hwkey=' . jeedom::getHardwareKey(); - $url .='&username=' . urlencode(config::byKey('market::username')); - $url .='&password=' . self::getPassword(); - $url .='&password_type=sha1'; + $url .= '&version=' . $_version; + $url .= '&jeedomversion=' . jeedom::version(); + $url .= '&osversion=' . system::getOsVersion(); + $url .= '&hwkey=' . jeedom::getHardwareKey(); + $url .= '&username=' . urlencode(config::byKey('market::username')); + $url .= '&password=' . self::getPassword(); + $url .= '&password_type=sha1'; log::add('update', 'alert', __('Téléchargement de', __FILE__) . ' ' . $this->getLogicalId() . '...'); log::add('update', 'alert', __('URL', __FILE__) . ' ' . $url); exec('wget "' . $url . '" -O ' . $tmp . ' >> ' . log::getPathToLog('update') . ' 2>&1'); @@ -1065,7 +1074,7 @@ public function save() { } if ($update->getSource() == 'market') { $update->setConfiguration('version', 'beta'); - $update->setLocalVersion(date('Y-m-d H:i:s',(int) strtotime('+10 minute' . date('Y-m-d H:i:s')))); + $update->setLocalVersion(date('Y-m-d H:i:s', (int) strtotime('+10 minute' . date('Y-m-d H:i:s')))); $update->save(); } $update->checkUpdate(); diff --git a/core/template/dashboard/cmd.action.color.picker.html b/core/template/dashboard/cmd.action.color.picker.html index 3c4bf73cca..62d1f17f5a 100644 --- a/core/template/dashboard/cmd.action.color.picker.html +++ b/core/template/dashboard/cmd.action.color.picker.html @@ -19,7 +19,13 @@ if ('#time#' == 'duration' || '#time#' == 'date') { jeedom.cmd.displayDuration(_options.valueDate, cmd.querySelector('.timeCmd'), '#time#') } - cmd.querySelector('.action_colorpicker_change').value = (_options.display_value != '') ? _options.display_value.substr(0, 7) : '#000000' + if (_options.display_value.length == 0) { + cmd.querySelector('.action_colorpicker_change').value = '#000000' + } else if (_options.display_value.startsWith('#')) { + cmd.querySelector('.action_colorpicker_change').value = _options.display_value.substr(0, 7) + } else { + cmd.querySelector('.action_colorpicker_change').value = '#' + _options.display_value.substr(0, 6) + } } }) diff --git a/desktop/js/scenario.js b/desktop/js/scenario.js index 531d350dcb..ab6f03f5b5 100644 --- a/desktop/js/scenario.js +++ b/desktop/js/scenario.js @@ -1999,8 +1999,11 @@ document.getElementById('div_editScenario').querySelector('div.floatingbar').add _target.setAttribute('data-state', '1') //open code blocks for later search: document.querySelectorAll('#div_scenarioElement div.elementCODE.elementCollapse').forEach(_code => { - _code.removeClass('elementCollapse') - _code.querySelector('textarea[data-l1key="expression"]').show() + _code.classList.remove('elementCollapse'); + const textarea = _code.querySelector('textarea[data-l1key="expression"]'); + if (textarea) { + textarea.style.display = 'block'; + } }) jeeP.setEditors() document.querySelectorAll('textarea[data-l1key="expression"]').unseen() diff --git a/desktop/modal/search.php b/desktop/modal/search.php index 051940aa03..62b4635a10 100644 --- a/desktop/modal/search.php +++ b/desktop/modal/search.php @@ -75,7 +75,7 @@
- + @@ -652,6 +652,23 @@ jeeM.init() + function updateEquipmentInputDisabled() { + var inputIds = [ + 'in_searchFor_equipment', + 'in_searchFor_command', + ]; + inputIds.forEach(function(id) { + var input = document.getElementById(id); + if (input) { + input.disabled = true; + } + }); + } + + updateEquipmentInputDisabled(); + + + //Manage events outside parents delegations: document.querySelector('#md_search #in_searchFor_string')?.addEventListener('keypress', function(event) { if (event.which === 13) { @@ -785,6 +802,8 @@ if (dataFilter[i] == 1) table.parentNode.seen() else table.parentNode.unseen() } + + updateEquipmentInputDisabled(); return } diff --git a/desktop/php/administration.php b/desktop/php/administration.php index e89a5e1f0d..f226834255 100644 --- a/desktop/php/administration.php +++ b/desktop/php/administration.php @@ -41,7 +41,7 @@
  • {{Rapports}}
  • {{Liens}}
  • {{Interactions}}
  • -
  • {{Securité}}
  • +
  • {{Sécurité}}
  • {{Mises à jour/Market}}
  • {{Cache}}
  • {{API}}
  • @@ -950,6 +950,12 @@
    +
    + +
    + +
    +
    @@ -1128,15 +1134,15 @@
    - +
    @@ -1761,11 +1767,11 @@ foreach ($ban_ips as $ip => $datetime) { $div .= ''; $div .= '' . $ip . ''; - $div .= '' . date('Y-m-d H:i:s',(int) $datetime) . ''; + $div .= '' . date('Y-m-d H:i:s', (int) $datetime) . ''; if (config::byKey('security::bantime') == -1) { $div .= '{{Jamais}}'; } else { - $div .= '' . date('Y-m-d H:i:s',(int) ($datetime + config::byKey('security::bantime'))) . ''; + $div .= '' . date('Y-m-d H:i:s', (int) ($datetime + config::byKey('security::bantime'))) . ''; } $div .= ''; } @@ -1814,52 +1820,52 @@ - getValue(array()); - if(!isset($lists['branchs']) || !is_array($lists['branchs'])){ + if (!isset($lists['branchs']) || !is_array($lists['branchs'])) { $request_http = new com_http('https://api.github.com/repos/jeedom/core/branches'); $request_http->setHeader(array('User-agent: jeedom')); try { $lists['branchs'] = json_decode($request_http->exec(10, 1), true); } catch (\Exception $e) { } - cache::set('core::branch::default::list',$lists,86400); + cache::set('core::branch::default::list', $lists, 86400); } - if(!isset($lists['tags']) || !is_array($lists['tags'])){ + if (!isset($lists['tags']) || !is_array($lists['tags'])) { $request_http = new com_http('https://api.github.com/repos/jeedom/core/tags'); $request_http->setHeader(array('User-agent: jeedom')); try { $lists['tags'] = json_decode($request_http->exec(10, 1), true); } catch (\Exception $e) { } - cache::set('core::branch::default::list',$lists,86400); - } - if(isset($lists['branchs']) && is_array($lists['branchs'])){ - echo ''; - foreach ($lists['branchs'] as $branch) { - if(!is_array($branch) || !isset($branch['name'])){ - continue; - } - if(in_array($branch['name'],array('V4-stable','master'))){ - continue; + cache::set('core::branch::default::list', $lists, 86400); + } + if (isset($lists['branchs']) && is_array($lists['branchs'])) { + echo ''; + foreach ($lists['branchs'] as $branch) { + if (!is_array($branch) || !isset($branch['name'])) { + continue; + } + if (in_array($branch['name'], array('V4-stable', 'master'))) { + continue; + } + echo ''; } - echo ''; + echo ''; } - echo ''; - } - if(isset($lists['tags']) && is_array($lists['tags'])){ - echo ''; - foreach ($lists['tags'] as $tag) { - if(!is_array($tag) || !isset($tag['name'])){ - continue; + if (isset($lists['tags']) && is_array($lists['tags'])) { + echo ''; + foreach ($lists['tags'] as $tag) { + if (!is_array($tag) || !isset($tag['name'])) { + continue; + } + echo ''; } - echo ''; + echo ''; } - echo ''; } - } - ?> + ?> @@ -2331,4 +2337,4 @@
    - + \ No newline at end of file diff --git a/desktop/php/object.php b/desktop/php/object.php index 0db55bcc10..87ce627fbf 100644 --- a/desktop/php/object.php +++ b/desktop/php/object.php @@ -3,7 +3,7 @@ throw new Exception('{{401 - Accès non autorisé}}'); } $allObject = jeeObject::buildTree(null, false); -$config_objSummary = config::byKey('object:summary'); +$config_objSummary = (array) config::byKey('object:summary'); sendVarToJS([ 'jeephp2js.selectId' => init('id', '-1'), @@ -102,7 +102,9 @@
    - +
    diff --git a/desktop/php/update.php b/desktop/php/update.php index 5d7295083a..ea18cb41bd 100644 --- a/desktop/php/update.php +++ b/desktop/php/update.php @@ -185,7 +185,7 @@