673 ha cambiato i file con 126346 aggiunte e 1 eliminazioni
@ -0,0 +1,12 @@
|
||||
# Uncomment the following to prevent the httpoxy vulnerability |
||||
# See: https://httpoxy.org/ |
||||
#<IfModule mod_headers.c> |
||||
# RequestHeader unset Proxy |
||||
#</IfModule> |
||||
|
||||
<IfModule mod_rewrite.c> |
||||
RewriteEngine on |
||||
RewriteRule ^(\.well-known/.*)$ $1 [L] |
||||
RewriteRule ^$ webroot/ [L] |
||||
RewriteRule (.*) webroot/$1 [L] |
||||
</IfModule> |
||||
@ -0,0 +1,20 @@
|
||||
FROM registrywgs.webgenesis.it/webgenesys/jixel/jixel-dockers/almalinux9.5-php8.4.4:latest-master |
||||
RUN dnf -y install npm |
||||
RUN npm install -g bower |
||||
RUN dnf -y install git |
||||
RUN mkdir /var/www/jixel |
||||
COPY . /var/www/jixel |
||||
WORKDIR /var/www/jixel |
||||
RUN composer install --no-interaction |
||||
WORKDIR /var/www/jixel/webroot |
||||
RUN npm install |
||||
RUN bower install |
||||
EXPOSE 443 |
||||
EXPOSE 80 |
||||
WORKDIR /var/www/jixel |
||||
RUN mkdir /run/php-fpm |
||||
COPY ./dockerfiles/run /usr/local/bin/run |
||||
RUN chmod 500 /usr/local/bin/run |
||||
COPY ./dockerfiles/cake /var/www/jixel/bin/cake |
||||
RUN chmod 500 /var/www/jixel/bin/cake |
||||
CMD ["run"] |
||||
@ -0,0 +1,61 @@
|
||||
# IDROCAP Jixel repository |
||||
|
||||
Jixel core for IDROCAP developing. Based on [CakePHP](https://cakephp.org) 5.x. |
||||
|
||||
The framework source code can be found here: [cakephp/cakephp](https://github.com/cakephp/cakephp). |
||||
|
||||
Before you run the docker stack: |
||||
make sure you have a few configs keys under in `config/app_local.php`: |
||||
|
||||
```php |
||||
'Custom' => [ |
||||
'background_tasks' => [ |
||||
'notifications' => [ |
||||
'channel' => 'newjixel_background_tasks', |
||||
] |
||||
], |
||||
], |
||||
``` |
||||
and: |
||||
|
||||
```php |
||||
'Datasources' => [ |
||||
'default' => [ |
||||
'host' => 'mysql8', |
||||
'username' => 'jixel', |
||||
'password' => 'jixel2023', |
||||
'database' => 'jixel', |
||||
'url' => env('DATABASE_URL', null), |
||||
], |
||||
'geo' => [ |
||||
'host' => 'mysql-geo', |
||||
'port' => '3307', |
||||
'username' => 'gecos', |
||||
'password' => 'gecos2015', |
||||
'database' => 'geo', |
||||
], |
||||
'test' => [ |
||||
'host' => 'localhost', |
||||
'username' => 'my_app', |
||||
'password' => 'secret', |
||||
'database' => 'test_myapp', |
||||
'url' => env('DATABASE_TEST_URL', 'sqlite://127.0.0.1/tests.sqlite'), |
||||
], |
||||
], |
||||
```` |
||||
|
||||
First bootstrap only (and only if you are mapping in your host machine, idrocapjixel repository): |
||||
|
||||
enter the container: |
||||
`docker exec -it -u <USERNAME> jixel` |
||||
|
||||
install vendor packages: |
||||
`composer install -n` |
||||
|
||||
install vendor front end packages: |
||||
`cd webroot` |
||||
`npm install -y` |
||||
`bower install -y` |
||||
|
||||
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
# |
||||
# Bash completion file for CakePHP console. |
||||
# Copy this file to a file named `cake` under `/etc/bash_completion.d/`. |
||||
# For more info check https://book.cakephp.org/4/en/console-commands/completion.html#how-to-enable-bash-autocompletion-for-the-cakephp-console |
||||
# |
||||
|
||||
_cake() |
||||
{ |
||||
local cur prev opts cake |
||||
COMPREPLY=() |
||||
cake="${COMP_WORDS[0]}" |
||||
cur="${COMP_WORDS[COMP_CWORD]}" |
||||
prev="${COMP_WORDS[COMP_CWORD-1]}" |
||||
|
||||
if [[ "$cur" == -* ]] ; then |
||||
if [[ ${COMP_CWORD} = 1 ]] ; then |
||||
opts=$(${cake} completion options) |
||||
elif [[ ${COMP_CWORD} = 2 ]] ; then |
||||
opts=$(${cake} completion options "${COMP_WORDS[1]}") |
||||
else |
||||
opts=$(${cake} completion options "${COMP_WORDS[1]}" "${COMP_WORDS[2]}") |
||||
fi |
||||
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) |
||||
return 0 |
||||
fi |
||||
|
||||
if [[ ${COMP_CWORD} = 1 ]] ; then |
||||
opts=$(${cake} completion commands) |
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) |
||||
return 0 |
||||
fi |
||||
|
||||
if [[ ${COMP_CWORD} = 2 ]] ; then |
||||
opts=$(${cake} completion subcommands $prev) |
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) |
||||
if [[ $COMPREPLY = "" ]] ; then |
||||
_filedir |
||||
return 0 |
||||
fi |
||||
return 0 |
||||
fi |
||||
|
||||
return 0 |
||||
} |
||||
|
||||
complete -F _cake cake bin/cake |
||||
@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env sh |
||||
################################################################################ |
||||
# |
||||
# Cake is a shell script for invoking CakePHP shell commands |
||||
# |
||||
# CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
||||
# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
# |
||||
# Licensed under The MIT License |
||||
# For full copyright and license information, please see the LICENSE.txt |
||||
# Redistributions of files must retain the above copyright notice. |
||||
# |
||||
# @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
# @link https://cakephp.org CakePHP(tm) Project |
||||
# @since 1.2.0 |
||||
# @license https://opensource.org/licenses/mit-license.php MIT License |
||||
# |
||||
################################################################################ |
||||
|
||||
# Canonicalize by following every symlink of the given name recursively |
||||
canonicalize() { |
||||
NAME="$1" |
||||
if [ -f "$NAME" ] |
||||
then |
||||
DIR=$(dirname -- "$NAME") |
||||
NAME=$(cd -P "$DIR" > /dev/null && pwd -P)/$(basename -- "$NAME") |
||||
fi |
||||
while [ -h "$NAME" ]; do |
||||
DIR=$(dirname -- "$NAME") |
||||
SYM=$(readlink "$NAME") |
||||
NAME=$(cd "$DIR" > /dev/null && cd "$(dirname -- "$SYM")" > /dev/null && pwd)/$(basename -- "$SYM") |
||||
done |
||||
echo "$NAME" |
||||
} |
||||
|
||||
# Find a CLI version of PHP |
||||
findCliPhp() { |
||||
for TESTEXEC in php php-cli /usr/local/bin/php |
||||
do |
||||
SAPI=$(echo "<?= PHP_SAPI ?>" | $TESTEXEC 2>/dev/null) |
||||
if [ "$SAPI" = "cli" ] |
||||
then |
||||
echo $TESTEXEC |
||||
return |
||||
fi |
||||
done |
||||
echo "Failed to find a CLI version of PHP; falling back to system standard php executable" >&2 |
||||
echo "php"; |
||||
} |
||||
|
||||
# If current path is a symlink, resolve to real path |
||||
realname="$0" |
||||
if [ -L "$realname" ] |
||||
then |
||||
realname=$(readlink -f "$0") |
||||
fi |
||||
|
||||
CONSOLE=$(dirname -- "$(canonicalize "$realname")") |
||||
APP=$(dirname "$CONSOLE") |
||||
|
||||
# If your CLI PHP is somewhere that this doesn't find, you can define a PHP environment |
||||
# variable with the correct path in it. |
||||
if [ -z "$PHP" ] |
||||
then |
||||
PHP=$(findCliPhp) |
||||
fi |
||||
|
||||
if [ "$(basename "$realname")" != 'cake' ] |
||||
then |
||||
exec "$PHP" "$CONSOLE"/cake.php "$(basename "$realname")" "$@" |
||||
else |
||||
exec "$PHP" "$CONSOLE"/cake.php "$@" |
||||
fi |
||||
|
||||
exit |
||||
@ -0,0 +1,27 @@
|
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
||||
:: |
||||
:: Cake is a Windows batch script for invoking CakePHP shell commands |
||||
:: |
||||
:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
||||
:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
:: |
||||
:: Licensed under The MIT License |
||||
:: Redistributions of files must retain the above copyright notice. |
||||
:: |
||||
:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
:: @link https://cakephp.org CakePHP(tm) Project |
||||
:: @since 2.0.0 |
||||
:: @license https://opensource.org/licenses/mit-license.php MIT License |
||||
:: |
||||
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: |
||||
|
||||
@echo off |
||||
|
||||
SET app=%0 |
||||
SET lib=%~dp0 |
||||
|
||||
php "%lib%cake.php" %* |
||||
|
||||
echo. |
||||
|
||||
exit /B %ERRORLEVEL% |
||||
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/php -q |
||||
<?php |
||||
require dirname(__DIR__) . '/vendor/autoload.php'; |
||||
|
||||
use App\Application; |
||||
use Cake\Console\CommandRunner; |
||||
|
||||
// Build the runner with an application and root executable name. |
||||
$runner = new CommandRunner(new Application(dirname(__DIR__) . '/config'), 'cake'); |
||||
exit($runner->run($argv)); |
||||
@ -0,0 +1,67 @@
|
||||
{ |
||||
"name": "cakephp/app", |
||||
"description": "CakePHP skeleton app", |
||||
"homepage": "https://cakephp.org", |
||||
"type": "project", |
||||
"license": "MIT", |
||||
"require": { |
||||
"php": ">=8.1", |
||||
"arodu/cakelte": "^2.0", |
||||
"aws/aws-sdk-php": "^3.301", |
||||
"cakephp/authentication": "^3.0", |
||||
"cakephp/cakephp": "^5.0.1", |
||||
"cakephp/migrations": "^4.0.0", |
||||
"cakephp/plugin-installer": "^2.0", |
||||
"firebase/php-jwt": "^6.10", |
||||
"friendsofcake/cakephp-csvview": "^5.0", |
||||
"lordsimal/cakephp-sentry": "^3.0", |
||||
"mobiledetect/mobiledetectlib": "^3.74", |
||||
"muffin/trash": "^4.0", |
||||
"php-amqplib/php-amqplib": "^3.6", |
||||
"simpleenergy/php-webhdfs": "^1.0" |
||||
}, |
||||
"require-dev": { |
||||
"cakephp/bake": "^3.0.0", |
||||
"cakephp/cakephp-codesniffer": "^5.0", |
||||
"cakephp/debug_kit": "^5.0.0", |
||||
"josegonzalez/dotenv": "^4.0", |
||||
"phpunit/phpunit": "^10.1.0" |
||||
}, |
||||
"suggest": { |
||||
"markstory/asset_compress": "An asset compression plugin which provides file concatenation and a flexible filter system for preprocessing and minification.", |
||||
"dereuromark/cakephp-ide-helper": "After baking your code, this keeps your annotations in sync with the code evolving from there on for maximum IDE and PHPStan/Psalm compatibility.", |
||||
"phpstan/phpstan": "PHPStan focuses on finding errors in your code without actually running it. It catches whole classes of bugs even before you write tests for the code.", |
||||
"cakephp/repl": "Console tools for a REPL interface for CakePHP applications." |
||||
}, |
||||
"autoload": { |
||||
"psr-4": { |
||||
"App\\": "src/" |
||||
} |
||||
}, |
||||
"autoload-dev": { |
||||
"psr-4": { |
||||
"App\\Test\\": "tests/", |
||||
"Cake\\Test\\": "vendor/cakephp/cakephp/tests/" |
||||
} |
||||
}, |
||||
"scripts": { |
||||
"post-install-cmd": "App\\Console\\Installer::postInstall", |
||||
"post-create-project-cmd": "App\\Console\\Installer::postInstall", |
||||
"check": [ |
||||
"@test", |
||||
"@cs-check" |
||||
], |
||||
"cs-check": "phpcs --colors -p", |
||||
"cs-fix": "phpcbf --colors -p", |
||||
"stan": "phpstan analyse", |
||||
"test": "phpunit --colors=always" |
||||
}, |
||||
"config": { |
||||
"platform-check": true, |
||||
"sort-packages": true, |
||||
"allow-plugins": { |
||||
"cakephp/plugin-installer": true, |
||||
"dealerdirect/phpcodesniffer-composer-installer": true |
||||
} |
||||
} |
||||
} |
||||
File diff soppresso perché troppo grande
Load Diff
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash |
||||
# Used as a default to seed config/.env which |
||||
# enables you to use environment variables to configure |
||||
# the aspects of your application that vary by |
||||
# environment. |
||||
# |
||||
# Having this file in production is considered a **SECURITY RISK** and also decreases |
||||
# the bootstrap performance of your application. |
||||
# |
||||
# To use this file, first copy it into `config/.env`. Also ensure the related |
||||
# code block for loading this file is uncommented in `config/bootstrap.php` |
||||
# |
||||
# In development .env files are parsed by PHP |
||||
# and set into the environment. This provides a simpler |
||||
# development workflow over standard environment variables. |
||||
export APP_NAME="__APP_NAME__" |
||||
export DEBUG="true" |
||||
export APP_ENCODING="UTF-8" |
||||
export APP_DEFAULT_LOCALE="en_US" |
||||
export APP_DEFAULT_TIMEZONE="UTC" |
||||
export SECURITY_SALT="__SALT__" |
||||
|
||||
# Uncomment these to define cache configuration via environment variables. |
||||
#export CACHE_DURATION="+2 minutes" |
||||
#export CACHE_DEFAULT_URL="file:///path/to/tmp/cache/?prefix=${APP_NAME}_default_&duration=${CACHE_DURATION}" |
||||
#export CACHE_CAKECORE_URL="file:///path/to/tmp/cache/persistent?prefix=${APP_NAME}_cake_core_&serialize=true&duration=${CACHE_DURATION}" |
||||
#export CACHE_CAKEMODEL_URL="file:///path/to/tmp/cache/models?prefix=${APP_NAME}_cake_model_&serialize=true&duration=${CACHE_DURATION}" |
||||
|
||||
# Uncomment these to define email transport configuration via environment variables. |
||||
#export EMAIL_TRANSPORT_DEFAULT_URL="" |
||||
|
||||
# Uncomment these to define database configuration via environment variables. |
||||
#export DATABASE_URL="mysql://my_app:secret@localhost/${APP_NAME}?encoding=utf8&timezone=UTC&cacheMetadata=true"eIdentifiers=false&persistent=false" |
||||
#export DATABASE_TEST_URL="mysql://my_app:secret@localhost/test_${APP_NAME}?encoding=utf8&timezone=UTC&cacheMetadata=true"eIdentifiers=false&persistent=false" |
||||
|
||||
# Uncomment these to define logging configuration via environment variables. |
||||
#export LOG_DEBUG_URL="file:///path/to/logs/?levels[]=notice&levels[]=info&levels[]=debug&file=debug" |
||||
#export LOG_ERROR_URL="file:///path/to/logs/?levels[]=warning&levels[]=error&levels[]=critical&levels[]=alert&levels[]=emergency&file=error" |
||||
@ -0,0 +1,436 @@
|
||||
<?php |
||||
|
||||
use Cake\Cache\Engine\FileEngine; |
||||
use Cake\Database\Connection; |
||||
use Cake\Database\Driver\Mysql; |
||||
use Cake\Log\Engine\FileLog; |
||||
use Cake\Mailer\Transport\MailTransport; |
||||
use Cake\Cache\Engine\RedisEngine; |
||||
|
||||
return [ |
||||
/* |
||||
* Debug Level: |
||||
* |
||||
* Production Mode: |
||||
* false: No error messages, errors, or warnings shown. |
||||
* |
||||
* Development Mode: |
||||
* true: Errors and warnings shown. |
||||
*/ |
||||
'debug' => filter_var(env('DEBUG', false), FILTER_VALIDATE_BOOLEAN), |
||||
|
||||
/* |
||||
* Configure basic information about the application. |
||||
* |
||||
* - namespace - The namespace to find app classes under. |
||||
* - defaultLocale - The default locale for translation, formatting currencies and numbers, date and time. |
||||
* - encoding - The encoding used for HTML + database connections. |
||||
* - base - The base directory the app resides in. If false this |
||||
* will be auto detected. |
||||
* - dir - Name of app directory. |
||||
* - webroot - The webroot directory. |
||||
* - wwwRoot - The file path to webroot. |
||||
* - baseUrl - To configure CakePHP to *not* use mod_rewrite and to |
||||
* use CakePHP pretty URLs, remove these .htaccess |
||||
* files: |
||||
* /.htaccess |
||||
* /webroot/.htaccess |
||||
* And uncomment the baseUrl key below. |
||||
* - fullBaseUrl - A base URL to use for absolute links. When set to false (default) |
||||
* CakePHP generates required value based on `HTTP_HOST` environment variable. |
||||
* However, you can define it manually to optimize performance or if you |
||||
* are concerned about people manipulating the `Host` header. |
||||
* - imageBaseUrl - Web path to the public images directory under webroot. |
||||
* - cssBaseUrl - Web path to the public css directory under webroot. |
||||
* - jsBaseUrl - Web path to the public js directory under webroot. |
||||
* - paths - Configure paths for non class based resources. Supports the |
||||
* `plugins`, `templates`, `locales` subkeys, which allow the definition of |
||||
* paths for plugins, view templates and locale files respectively. |
||||
*/ |
||||
'App' => [ |
||||
'namespace' => 'App', |
||||
'encoding' => env('APP_ENCODING', 'UTF-8'), |
||||
'defaultLocale' => env('APP_DEFAULT_LOCALE', 'it'), |
||||
'defaultTimezone' => env('APP_DEFAULT_TIMEZONE', 'UTC'), |
||||
'defaultUserTimezone' => 'Europe/Rome', |
||||
'base' => false, |
||||
'dir' => 'src', |
||||
'webroot' => 'webroot', |
||||
'wwwRoot' => WWW_ROOT, |
||||
//'baseUrl' => env('SCRIPT_NAME'), |
||||
'fullBaseUrl' => false, |
||||
'imageBaseUrl' => 'img/', |
||||
'cssBaseUrl' => 'css/', |
||||
'jsBaseUrl' => 'js/', |
||||
'paths' => [ |
||||
'plugins' => [ROOT . DS . 'plugins' . DS], |
||||
'templates' => [ROOT . DS . 'templates' . DS], |
||||
'locales' => [RESOURCES . 'locales' . DS], |
||||
], |
||||
], |
||||
|
||||
/* |
||||
* Security and encryption configuration |
||||
* |
||||
* - salt - A random string used in security hashing methods. |
||||
* The salt value is also used as the encryption key. |
||||
* You should treat it as extremely sensitive data. |
||||
*/ |
||||
'Security' => [ |
||||
'salt' => env('SECURITY_SALT'), |
||||
], |
||||
|
||||
/* |
||||
* Apply timestamps with the last modified time to static assets (js, css, images). |
||||
* Will append a querystring parameter containing the time the file was modified. |
||||
* This is useful for busting browser caches. |
||||
* |
||||
* Set to true to apply timestamps when debug is true. Set to 'force' to always |
||||
* enable timestamping regardless of debug value. |
||||
*/ |
||||
'Asset' => [ |
||||
//'timestamp' => true, |
||||
// 'cacheTime' => '+1 year' |
||||
], |
||||
|
||||
/* |
||||
* Configure the cache adapters. |
||||
*/ |
||||
'Cache' => [ |
||||
'default' => [ |
||||
'className' => RedisEngine::class, |
||||
'database' => 1, |
||||
'duration' => 3600, |
||||
'groups' => [], |
||||
'password' => false, |
||||
'persistent' => true, |
||||
'port' => 6379, |
||||
'prefix' => '', |
||||
'probability' => 100, |
||||
'host' => null, |
||||
'server' => 'redis', |
||||
'timeout' => 0, |
||||
'unix_socket' => false, |
||||
], |
||||
|
||||
/* |
||||
* Configure the cache used for general framework caching. |
||||
* Translation cache files are stored with this configuration. |
||||
* Duration will be set to '+2 minutes' in bootstrap.php when debug = true |
||||
* If you set 'className' => 'Null' core cache will be disabled. |
||||
*/ |
||||
'_cake_translations_' => [ |
||||
'className' => FileEngine::class, |
||||
'prefix' => 'myapp_cake_core_', |
||||
'path' => CACHE . 'persistent' . DS, |
||||
'serialize' => true, |
||||
'duration' => '+1 years', |
||||
'url' => env('CACHE_CAKECORE_URL', null), |
||||
], |
||||
|
||||
/* |
||||
* Configure the cache for model and datasource caches. This cache |
||||
* configuration is used to store schema descriptions, and table listings |
||||
* in connections. |
||||
* Duration will be set to '+2 minutes' in bootstrap.php when debug = true |
||||
*/ |
||||
'_cake_model_' => [ |
||||
'className' => FileEngine::class, |
||||
'prefix' => 'myapp_cake_model_', |
||||
'path' => CACHE . 'models' . DS, |
||||
'serialize' => true, |
||||
'duration' => '+1 years', |
||||
'url' => env('CACHE_CAKEMODEL_URL', null), |
||||
], |
||||
], |
||||
|
||||
/* |
||||
* Configure the Error and Exception handlers used by your application. |
||||
* |
||||
* By default errors are displayed using Debugger, when debug is true and logged |
||||
* by Cake\Log\Log when debug is false. |
||||
* |
||||
* In CLI environments exceptions will be printed to stderr with a backtrace. |
||||
* In web environments an HTML page will be displayed for the exception. |
||||
* With debug true, framework errors like Missing Controller will be displayed. |
||||
* When debug is false, framework errors will be coerced into generic HTTP errors. |
||||
* |
||||
* Options: |
||||
* |
||||
* - `errorLevel` - int - The level of errors you are interested in capturing. |
||||
* - `trace` - boolean - Whether backtraces should be included in |
||||
* logged errors/exceptions. |
||||
* - `log` - boolean - Whether you want exceptions logged. |
||||
* - `exceptionRenderer` - string - The class responsible for rendering uncaught exceptions. |
||||
* The chosen class will be used for both CLI and web environments. If you want different |
||||
* classes used in CLI and web environments you'll need to write that conditional logic as well. |
||||
* The conventional location for custom renderers is in `src/Error`. Your exception renderer needs to |
||||
* implement the `render()` method and return either a string or Http\Response. |
||||
* `errorRenderer` - string - The class responsible for rendering PHP errors. The selected |
||||
* class will be used for both web and CLI contexts. If you want different classes for each environment |
||||
* you'll need to write that conditional logic as well. Error renderers need to |
||||
* to implement the `Cake\Error\ErrorRendererInterface`. |
||||
* - `skipLog` - array - List of exceptions to skip for logging. Exceptions that |
||||
* extend one of the listed exceptions will also be skipped for logging. |
||||
* E.g.: |
||||
* `'skipLog' => ['Cake\Http\Exception\NotFoundException', 'Cake\Http\Exception\UnauthorizedException']` |
||||
* - `extraFatalErrorMemory` - int - The number of megabytes to increase the memory limit by |
||||
* when a fatal error is encountered. This allows |
||||
* breathing room to complete logging or error handling. |
||||
* - `ignoredDeprecationPaths` - array - A list of glob compatible file paths that deprecations |
||||
* should be ignored in. Use this to ignore deprecations for plugins or parts of |
||||
* your application that still emit deprecations. |
||||
*/ |
||||
'Error' => [ |
||||
'errorLevel' => E_ALL, |
||||
'skipLog' => [], |
||||
'log' => true, |
||||
'trace' => true, |
||||
'ignoredDeprecationPaths' => [], |
||||
'exceptionRenderer' => 'App\Error\AppExceptionRenderer', |
||||
], |
||||
|
||||
/* |
||||
* Debugger configuration |
||||
* |
||||
* Define development error values for Cake\Error\Debugger |
||||
* |
||||
* - `editor` Set the editor URL format you want to use. |
||||
* By default atom, emacs, macvim, phpstorm, sublime, textmate, and vscode are |
||||
* available. You can add additional editor link formats using |
||||
* `Debugger::addEditor()` during your application bootstrap. |
||||
* - `outputMask` A mapping of `key` to `replacement` values that |
||||
* `Debugger` should replace in dumped data and logs generated by `Debugger`. |
||||
*/ |
||||
'Debugger' => [ |
||||
'editor' => 'phpstorm', |
||||
], |
||||
|
||||
/* |
||||
* Email configuration. |
||||
* |
||||
* By defining transports separately from delivery profiles you can easily |
||||
* re-use transport configuration across multiple profiles. |
||||
* |
||||
* You can specify multiple configurations for production, development and |
||||
* testing. |
||||
* |
||||
* Each transport needs a `className`. Valid options are as follows: |
||||
* |
||||
* Mail - Send using PHP mail function |
||||
* Smtp - Send using SMTP |
||||
* Debug - Do not send the email, just return the result |
||||
* |
||||
* You can add custom transports (or override existing transports) by adding the |
||||
* appropriate file to src/Mailer/Transport. Transports should be named |
||||
* 'YourTransport.php', where 'Your' is the name of the transport. |
||||
*/ |
||||
'EmailTransport' => [ |
||||
'default' => [ |
||||
'className' => MailTransport::class, |
||||
/* |
||||
* The keys host, port, timeout, username, password, client and tls |
||||
* are used in SMTP transports |
||||
*/ |
||||
'host' => 'localhost', |
||||
'port' => 25, |
||||
'timeout' => 30, |
||||
/* |
||||
* It is recommended to set these options through your environment or app_local.php |
||||
*/ |
||||
//'username' => null, |
||||
//'password' => null, |
||||
'client' => null, |
||||
'tls' => false, |
||||
'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null), |
||||
], |
||||
], |
||||
|
||||
/* |
||||
* Email delivery profiles |
||||
* |
||||
* Delivery profiles allow you to predefine various properties about email |
||||
* messages from your application and give the settings a name. This saves |
||||
* duplication across your application and makes maintenance and development |
||||
* easier. Each profile accepts a number of keys. See `Cake\Mailer\Email` |
||||
* for more information. |
||||
*/ |
||||
'Email' => [ |
||||
'default' => [ |
||||
'transport' => 'default', |
||||
'from' => 'you@localhost', |
||||
/* |
||||
* Will by default be set to config value of App.encoding, if that exists otherwise to UTF-8. |
||||
*/ |
||||
//'charset' => 'utf-8', |
||||
//'headerCharset' => 'utf-8', |
||||
], |
||||
], |
||||
|
||||
/* |
||||
* Connection information used by the ORM to connect |
||||
* to your application's datastores. |
||||
* |
||||
* ### Notes |
||||
* - Drivers include Mysql Postgres Sqlite Sqlserver |
||||
* See vendor\cakephp\cakephp\src\Database\Driver for complete list |
||||
* - Do not use periods in database name - it may lead to error. |
||||
* See https://github.com/cakephp/cakephp/issues/6471 for details. |
||||
* - 'encoding' is recommended to be set to full UTF-8 4-Byte support. |
||||
* E.g set it to 'utf8mb4' in MariaDB and MySQL and 'utf8' for any |
||||
* other RDBMS. |
||||
*/ |
||||
'Datasources' => [ |
||||
/* |
||||
* These configurations should contain permanent settings used |
||||
* by all environments. |
||||
* |
||||
* The values in app_local.php will override any values set here |
||||
* and should be used for local and per-environment configurations. |
||||
* |
||||
* Environment variable based configurations can be loaded here or |
||||
* in app_local.php depending on the applications needs. |
||||
*/ |
||||
'default' => [ |
||||
'className' => Connection::class, |
||||
'driver' => Mysql::class, |
||||
'persistent' => false, |
||||
'timezone' => 'UTC', |
||||
|
||||
/* |
||||
* For MariaDB/MySQL the internal default changed from utf8 to utf8mb4, aka full utf-8 support, in CakePHP 3.6 |
||||
*/ |
||||
//'encoding' => 'utf8mb4', |
||||
|
||||
/* |
||||
* If your MySQL server is configured with `skip-character-set-client-handshake` |
||||
* then you MUST use the `flags` config to set your charset encoding. |
||||
* For e.g. `'flags' => [\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4']` |
||||
*/ |
||||
'flags' => [], |
||||
'cacheMetadata' => true, |
||||
'log' => false, |
||||
|
||||
/* |
||||
* Set identifier quoting to true if you are using reserved words or |
||||
* special characters in your table or column names. Enabling this |
||||
* setting will result in queries built using the Query Builder having |
||||
* identifiers quoted when creating SQL. It should be noted that this |
||||
* decreases performance because each query needs to be traversed and |
||||
* manipulated before being executed. |
||||
*/ |
||||
'quoteIdentifiers' => true, |
||||
|
||||
/* |
||||
* During development, if using MySQL < 5.6, uncommenting the |
||||
* following line could boost the speed at which schema metadata is |
||||
* fetched from the database. It can also be set directly with the |
||||
* mysql configuration directive 'innodb_stats_on_metadata = 0' |
||||
* which is the recommended value in production environments |
||||
*/ |
||||
//'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'], |
||||
], |
||||
|
||||
'geo' => [ |
||||
'className' => Connection::class, |
||||
'driver' => Mysql::class, |
||||
'persistent' => false, |
||||
'timezone' => 'UTC', |
||||
'encoding' => 'utf8', |
||||
'flags' => [], |
||||
'cacheMetadata' => true, |
||||
'log' => false, |
||||
'quoteIdentifiers' => false, |
||||
], |
||||
|
||||
/* |
||||
* The test connection is used during the test suite. |
||||
*/ |
||||
'test' => [ |
||||
'className' => Connection::class, |
||||
'driver' => Mysql::class, |
||||
'persistent' => false, |
||||
'timezone' => 'UTC', |
||||
//'encoding' => 'utf8mb4', |
||||
'flags' => [], |
||||
'cacheMetadata' => true, |
||||
'quoteIdentifiers' => false, |
||||
'log' => false, |
||||
//'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'], |
||||
], |
||||
], |
||||
|
||||
/* |
||||
* Configures logging options |
||||
*/ |
||||
'Log' => [ |
||||
'debug' => [ |
||||
'className' => FileLog::class, |
||||
'path' => LOGS, |
||||
'file' => 'debug', |
||||
'url' => env('LOG_DEBUG_URL', null), |
||||
'scopes' => null, |
||||
'levels' => ['notice', 'info', 'debug'], |
||||
], |
||||
'error' => [ |
||||
'className' => FileLog::class, |
||||
'path' => LOGS, |
||||
'file' => 'error', |
||||
'url' => env('LOG_ERROR_URL', null), |
||||
'scopes' => null, |
||||
'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'], |
||||
], |
||||
// To enable this dedicated query log, you need set your datasource's log flag to true |
||||
'queries' => [ |
||||
'className' => FileLog::class, |
||||
'path' => LOGS, |
||||
'file' => 'queries', |
||||
'url' => env('LOG_QUERIES_URL', null), |
||||
'scopes' => ['cake.database.queries'], |
||||
], |
||||
], |
||||
|
||||
/* |
||||
* Session configuration. |
||||
* |
||||
* Contains an array of settings to use for session configuration. The |
||||
* `defaults` key is used to define a default preset to use for sessions, any |
||||
* settings declared here will override the settings of the default config. |
||||
* |
||||
* ## Options |
||||
* |
||||
* - `cookie` - The name of the cookie to use. Defaults to value set for `session.name` php.ini config. |
||||
* Avoid using `.` in cookie names, as PHP will drop sessions from cookies with `.` in the name. |
||||
* - `cookiePath` - The url path for which session cookie is set. Maps to the |
||||
* `session.cookie_path` php.ini config. Defaults to base path of app. |
||||
* - `timeout` - The time in minutes the session should be valid for. |
||||
* Pass 0 to disable checking timeout. |
||||
* Please note that php.ini's session.gc_maxlifetime must be equal to or greater |
||||
* than the largest Session['timeout'] in all served websites for it to have the |
||||
* desired effect. |
||||
* - `defaults` - The default configuration set to use as a basis for your session. |
||||
* There are four built-in options: php, cake, cache, database. |
||||
* - `handler` - Can be used to enable a custom session handler. Expects an |
||||
* array with at least the `engine` key, being the name of the Session engine |
||||
* class to use for managing the session. CakePHP bundles the `CacheSession` |
||||
* and `DatabaseSession` engines. |
||||
* - `ini` - An associative array of additional 'session.*` ini values to set. |
||||
* |
||||
* The built-in `defaults` options are: |
||||
* |
||||
* - 'php' - Uses settings defined in your php.ini. |
||||
* - 'cake' - Saves session files in CakePHP's /tmp directory. |
||||
* - 'database' - Uses CakePHP's database sessions. |
||||
* - 'cache' - Use the Cache class to save sessions. |
||||
* |
||||
* To define a custom session handler, save it at src/Http/Session/<name>.php. |
||||
* Make sure the class implements PHP's `SessionHandlerInterface` and set |
||||
* Session.handler to <name> |
||||
* |
||||
* To use database sessions, load the SQL file located at config/schema/sessions.sql |
||||
*/ |
||||
'Session' => [ |
||||
'cookie' => 'JIXEL', |
||||
'defaults' => 'cache', |
||||
], |
||||
]; |
||||
@ -0,0 +1,94 @@
|
||||
<?php |
||||
/* |
||||
* Local configuration file to provide any overrides to your app.php configuration. |
||||
* Copy and save this file as app_local.php and make changes as required. |
||||
* Note: It is not recommended to commit files with credentials such as app_local.php |
||||
* into source code version control. |
||||
*/ |
||||
return [ |
||||
/* |
||||
* Debug Level: |
||||
* |
||||
* Production Mode: |
||||
* false: No error messages, errors, or warnings shown. |
||||
* |
||||
* Development Mode: |
||||
* true: Errors and warnings shown. |
||||
*/ |
||||
'debug' => filter_var(env('DEBUG', true), FILTER_VALIDATE_BOOLEAN), |
||||
|
||||
/* |
||||
* Security and encryption configuration |
||||
* |
||||
* - salt - A random string used in security hashing methods. |
||||
* The salt value is also used as the encryption key. |
||||
* You should treat it as extremely sensitive data. |
||||
*/ |
||||
'Security' => [ |
||||
'salt' => env('SECURITY_SALT', '__SALT__'), |
||||
], |
||||
|
||||
/* |
||||
* Connection information used by the ORM to connect |
||||
* to your application's datastores. |
||||
* |
||||
* See app.php for more configuration options. |
||||
*/ |
||||
'Datasources' => [ |
||||
'default' => [ |
||||
'host' => 'localhost', |
||||
/* |
||||
* CakePHP will use the default DB port based on the driver selected |
||||
* MySQL on MAMP uses port 8889, MAMP users will want to uncomment |
||||
* the following line and set the port accordingly |
||||
*/ |
||||
//'port' => 'non_standard_port_number', |
||||
|
||||
'username' => 'my_app', |
||||
'password' => 'secret', |
||||
|
||||
'database' => 'my_app', |
||||
/* |
||||
* If not using the default 'public' schema with the PostgreSQL driver |
||||
* set it here. |
||||
*/ |
||||
//'schema' => 'myapp', |
||||
|
||||
/* |
||||
* You can use a DSN string to set the entire configuration |
||||
*/ |
||||
'url' => env('DATABASE_URL', null), |
||||
], |
||||
|
||||
/* |
||||
* The test connection is used during the test suite. |
||||
*/ |
||||
'test' => [ |
||||
'host' => 'localhost', |
||||
//'port' => 'non_standard_port_number', |
||||
'username' => 'my_app', |
||||
'password' => 'secret', |
||||
'database' => 'test_myapp', |
||||
//'schema' => 'myapp', |
||||
'url' => env('DATABASE_TEST_URL', 'sqlite://127.0.0.1/tmp/tests.sqlite'), |
||||
], |
||||
], |
||||
|
||||
/* |
||||
* Email configuration. |
||||
* |
||||
* Host and credential configuration in case you are using SmtpTransport |
||||
* |
||||
* See app.php for more configuration options. |
||||
*/ |
||||
'EmailTransport' => [ |
||||
'default' => [ |
||||
'host' => 'localhost', |
||||
'port' => 25, |
||||
'username' => null, |
||||
'password' => null, |
||||
'client' => null, |
||||
'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null), |
||||
], |
||||
], |
||||
]; |
||||
@ -0,0 +1,94 @@
|
||||
<?php |
||||
/* |
||||
* Local configuration file to provide any overrides to your app.php configuration. |
||||
* Copy and save this file as app_local.php and make changes as required. |
||||
* Note: It is not recommended to commit files with credentials such as app_local.php |
||||
* into source code version control. |
||||
*/ |
||||
return [ |
||||
/* |
||||
* Debug Level: |
||||
* |
||||
* Production Mode: |
||||
* false: No error messages, errors, or warnings shown. |
||||
* |
||||
* Development Mode: |
||||
* true: Errors and warnings shown. |
||||
*/ |
||||
'debug' => filter_var(env('DEBUG', true), FILTER_VALIDATE_BOOLEAN), |
||||
|
||||
/* |
||||
* Security and encryption configuration |
||||
* |
||||
* - salt - A random string used in security hashing methods. |
||||
* The salt value is also used as the encryption key. |
||||
* You should treat it as extremely sensitive data. |
||||
*/ |
||||
'Security' => [ |
||||
'salt' => env('SECURITY_SALT', '1d8f10d21d25f4efea479140b503d0c32a7aac909d93d0a48bb9e153d49a0449'), |
||||
], |
||||
|
||||
/* |
||||
* Connection information used by the ORM to connect |
||||
* to your application's datastores. |
||||
* |
||||
* See app.php for more configuration options. |
||||
*/ |
||||
'Datasources' => [ |
||||
'default' => [ |
||||
'host' => 'localhost', |
||||
/* |
||||
* CakePHP will use the default DB port based on the driver selected |
||||
* MySQL on MAMP uses port 8889, MAMP users will want to uncomment |
||||
* the following line and set the port accordingly |
||||
*/ |
||||
//'port' => 'non_standard_port_number', |
||||
|
||||
'username' => 'my_app', |
||||
'password' => 'secret', |
||||
|
||||
'database' => 'my_app', |
||||
/* |
||||
* If not using the default 'public' schema with the PostgreSQL driver |
||||
* set it here. |
||||
*/ |
||||
//'schema' => 'myapp', |
||||
|
||||
/* |
||||
* You can use a DSN string to set the entire configuration |
||||
*/ |
||||
'url' => env('DATABASE_URL', null), |
||||
], |
||||
|
||||
/* |
||||
* The test connection is used during the test suite. |
||||
*/ |
||||
'test' => [ |
||||
'host' => 'localhost', |
||||
//'port' => 'non_standard_port_number', |
||||
'username' => 'my_app', |
||||
'password' => 'secret', |
||||
'database' => 'test_myapp', |
||||
//'schema' => 'myapp', |
||||
'url' => env('DATABASE_TEST_URL', 'sqlite://127.0.0.1/tmp/tests.sqlite'), |
||||
], |
||||
], |
||||
|
||||
/* |
||||
* Email configuration. |
||||
* |
||||
* Host and credential configuration in case you are using SmtpTransport |
||||
* |
||||
* See app.php for more configuration options. |
||||
*/ |
||||
'EmailTransport' => [ |
||||
'default' => [ |
||||
'host' => 'localhost', |
||||
'port' => 25, |
||||
'username' => null, |
||||
'password' => null, |
||||
'client' => null, |
||||
'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null), |
||||
], |
||||
], |
||||
]; |
||||
@ -0,0 +1,231 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* |
||||
* Licensed under The MIT License |
||||
* For full copyright and license information, please see the LICENSE.txt |
||||
* Redistributions of files must retain the above copyright notice. |
||||
* |
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* @link https://cakephp.org CakePHP(tm) Project |
||||
* @since 0.10.8 |
||||
* @license https://opensource.org/licenses/mit-license.php MIT License |
||||
*/ |
||||
|
||||
/* |
||||
* Configure paths required to find CakePHP + general filepath constants |
||||
*/ |
||||
require __DIR__ . DIRECTORY_SEPARATOR . 'paths.php'; |
||||
|
||||
/* |
||||
* Bootstrap CakePHP. |
||||
* |
||||
* Does the various bits of setup that CakePHP needs to do. |
||||
* This includes: |
||||
* |
||||
* - Registering the CakePHP autoloader. |
||||
* - Setting the default application paths. |
||||
*/ |
||||
require CORE_PATH . 'config' . DS . 'bootstrap.php'; |
||||
|
||||
use Cake\Cache\Cache; |
||||
use Cake\Core\Configure; |
||||
use Cake\Core\Configure\Engine\PhpConfig; |
||||
use Cake\Database\Type\StringType; |
||||
use Cake\Database\TypeFactory; |
||||
use Cake\Datasource\ConnectionManager; |
||||
use Cake\Error\ErrorTrap; |
||||
use Cake\Error\ExceptionTrap; |
||||
use Cake\Http\ServerRequest; |
||||
use Cake\Log\Log; |
||||
use Cake\Mailer\Mailer; |
||||
use Cake\Mailer\TransportFactory; |
||||
use Cake\Routing\Router; |
||||
use Cake\Utility\Security; |
||||
|
||||
/** |
||||
* Load global functions. |
||||
*/ |
||||
require CAKE . 'functions.php'; |
||||
|
||||
/* |
||||
* See https://github.com/josegonzalez/php-dotenv for API details. |
||||
* |
||||
* Uncomment block of code below if you want to use `.env` file during development. |
||||
* You should copy `config/.env.example` to `config/.env` and set/modify the |
||||
* variables as required. |
||||
* |
||||
* The purpose of the .env file is to emulate the presence of the environment |
||||
* variables like they would be present in production. |
||||
* |
||||
* If you use .env files, be careful to not commit them to source control to avoid |
||||
* security risks. See https://github.com/josegonzalez/php-dotenv#general-security-information |
||||
* for more information for recommended practices. |
||||
*/ |
||||
// if (!env('APP_NAME') && file_exists(CONFIG . '.env')) { |
||||
// $dotenv = new \josegonzalez\Dotenv\Loader([CONFIG . '.env']); |
||||
// $dotenv->parse() |
||||
// ->putenv() |
||||
// ->toEnv() |
||||
// ->toServer(); |
||||
// } |
||||
|
||||
/* |
||||
* Read configuration file and inject configuration into various |
||||
* CakePHP classes. |
||||
* |
||||
* By default there is only one configuration file. It is often a good |
||||
* idea to create multiple configuration files, and separate the configuration |
||||
* that changes from configuration that does not. This makes deployment simpler. |
||||
*/ |
||||
try { |
||||
Configure::config('default', new PhpConfig()); |
||||
Configure::load('app', 'default', false); |
||||
} catch (\Exception $e) { |
||||
exit($e->getMessage() . "\n"); |
||||
} |
||||
|
||||
/* |
||||
* Load an environment local configuration file to provide overrides to your configuration. |
||||
* Notice: For security reasons app_local.php **should not** be included in your git repo. |
||||
*/ |
||||
if (file_exists(CONFIG . 'app_local.php')) { |
||||
Configure::load('app_local', 'default'); |
||||
} |
||||
|
||||
/* |
||||
* When debug = true the metadata cache should only last |
||||
* for a short time. |
||||
*/ |
||||
if (Configure::read('debug')) { |
||||
Configure::write('Cache._cake_model_.duration', '+2 minutes'); |
||||
Configure::write('Cache._cake_core_.duration', '+2 minutes'); |
||||
// disable router cache during development |
||||
Configure::write('Cache._cake_routes_.duration', '+2 seconds'); |
||||
} |
||||
|
||||
/* |
||||
* Set the default server timezone. Using UTC makes time calculations / conversions easier. |
||||
* Check https://php.net/manual/en/timezones.php for list of valid timezone strings. |
||||
*/ |
||||
date_default_timezone_set(Configure::read('App.defaultTimezone')); |
||||
|
||||
/* |
||||
* Configure the mbstring extension to use the correct encoding. |
||||
*/ |
||||
mb_internal_encoding(Configure::read('App.encoding')); |
||||
|
||||
/* |
||||
* Set the default locale. This controls how dates, number and currency is |
||||
* formatted and sets the default language to use for translations. |
||||
*/ |
||||
ini_set('intl.default_locale', Configure::read('App.defaultLocale')); |
||||
|
||||
/* |
||||
* Register application error and exception handlers. |
||||
*/ |
||||
(new ErrorTrap(Configure::read('Error')))->register(); |
||||
(new ExceptionTrap(Configure::read('Error')))->register(); |
||||
|
||||
/* |
||||
* Include the CLI bootstrap overrides. |
||||
*/ |
||||
if (PHP_SAPI === 'cli') { |
||||
require CONFIG . 'bootstrap_cli.php'; |
||||
} |
||||
|
||||
/* |
||||
* Set the full base URL. |
||||
* This URL is used as the base of all absolute links. |
||||
*/ |
||||
$fullBaseUrl = Configure::read('App.fullBaseUrl'); |
||||
if (!$fullBaseUrl) { |
||||
/* |
||||
* When using proxies or load balancers, SSL/TLS connections might |
||||
* get terminated before reaching the server. If you trust the proxy, |
||||
* you can enable `$trustProxy` to rely on the `X-Forwarded-Proto` |
||||
* header to determine whether to generate URLs using `https`. |
||||
* |
||||
* See also https://book.cakephp.org/4/en/controllers/request-response.html#trusting-proxy-headers |
||||
*/ |
||||
$trustProxy = false; |
||||
|
||||
$s = null; |
||||
if (env('HTTPS') || ($trustProxy && env('HTTP_X_FORWARDED_PROTO') === 'https')) { |
||||
$s = 's'; |
||||
} |
||||
|
||||
$httpHost = env('HTTP_HOST'); |
||||
if (isset($httpHost)) { |
||||
$fullBaseUrl = 'http' . $s . '://' . $httpHost; |
||||
} |
||||
unset($httpHost, $s); |
||||
} |
||||
if ($fullBaseUrl) { |
||||
Router::fullBaseUrl($fullBaseUrl); |
||||
} |
||||
unset($fullBaseUrl); |
||||
|
||||
Cache::setConfig(Configure::consume('Cache')); |
||||
ConnectionManager::setConfig(Configure::consume('Datasources')); |
||||
TransportFactory::setConfig(Configure::consume('EmailTransport')); |
||||
Mailer::setConfig(Configure::consume('Email')); |
||||
Log::setConfig(Configure::consume('Log')); |
||||
Security::setSalt(Configure::consume('Security.salt')); |
||||
|
||||
/* |
||||
* Setup detectors for mobile and tablet. |
||||
* If you don't use these checks you can safely remove this code |
||||
* and the mobiledetect package from composer.json. |
||||
*/ |
||||
ServerRequest::addDetector('mobile', function ($request) { |
||||
$detector = new \Detection\MobileDetect(); |
||||
|
||||
return $detector->isMobile(); |
||||
}); |
||||
ServerRequest::addDetector('tablet', function ($request) { |
||||
$detector = new \Detection\MobileDetect(); |
||||
|
||||
return $detector->isTablet(); |
||||
}); |
||||
|
||||
/* |
||||
* You can enable default locale format parsing by adding calls |
||||
* to `useLocaleParser()`. This enables the automatic conversion of |
||||
* locale specific date formats. For details see |
||||
* @link https://book.cakephp.org/4/en/core-libraries/internationalization-and-localization.html#parsing-localized-datetime-data |
||||
*/ |
||||
// \Cake\Database\TypeFactory::build('time') |
||||
// ->useLocaleParser(); |
||||
// \Cake\Database\TypeFactory::build('date') |
||||
// ->useLocaleParser(); |
||||
// \Cake\Database\TypeFactory::build('datetime') |
||||
// ->useLocaleParser(); |
||||
// \Cake\Database\TypeFactory::build('timestamp') |
||||
// ->useLocaleParser(); |
||||
// \Cake\Database\TypeFactory::build('datetimefractional') |
||||
// ->useLocaleParser(); |
||||
// \Cake\Database\TypeFactory::build('timestampfractional') |
||||
// ->useLocaleParser(); |
||||
// \Cake\Database\TypeFactory::build('datetimetimezone') |
||||
// ->useLocaleParser(); |
||||
// \Cake\Database\TypeFactory::build('timestamptimezone') |
||||
// ->useLocaleParser(); |
||||
|
||||
/* |
||||
* Custom Inflector rules, can be set to correctly pluralize or singularize |
||||
* table, model, controller names or whatever other string is passed to the |
||||
* inflection functions. |
||||
*/ |
||||
//Inflector::rules('plural', ['/^(inflect)or$/i' => '\1ables']); |
||||
//Inflector::rules('irregular', ['red' => 'redlings']); |
||||
//Inflector::rules('uninflected', ['dontinflectme']); |
||||
|
||||
// set a custom date and time format |
||||
// see https://book.cakephp.org/4/en/core-libraries/time.html#setting-the-default-locale-and-format-string |
||||
// and https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax |
||||
//\Cake\I18n\FrozenDate::setToStringFormat('dd.MM.yyyy'); |
||||
//\Cake\I18n\FrozenTime::setToStringFormat('dd.MM.yyyy HH:mm'); |
||||
@ -0,0 +1,35 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* |
||||
* Licensed under The MIT License |
||||
* For full copyright and license information, please see the LICENSE.txt |
||||
* Redistributions of files must retain the above copyright notice. |
||||
* |
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* @link https://cakephp.org CakePHP(tm) Project |
||||
* @since 3.0.0 |
||||
* @license https://opensource.org/licenses/mit-license.php MIT License |
||||
*/ |
||||
|
||||
use Cake\Core\Configure; |
||||
|
||||
/* |
||||
* Additional bootstrapping and configuration for CLI environments should |
||||
* be put here. |
||||
*/ |
||||
|
||||
// Set the fullBaseUrl to allow URLs to be generated in shell tasks. |
||||
// This is useful when sending email from shells. |
||||
//Configure::write('App.fullBaseUrl', php_uname('n')); |
||||
|
||||
// Set logs to different files so they don't have permission conflicts. |
||||
if (Configure::check('Log.debug')) { |
||||
Configure::write('Log.debug.file', 'cli-debug'); |
||||
} |
||||
if (Configure::check('Log.error')) { |
||||
Configure::write('Log.error.file', 'cli-error'); |
||||
} |
||||
@ -0,0 +1,43 @@
|
||||
<?php |
||||
|
||||
use CakeLte\Style\Header; |
||||
use CakeLte\Style\Sidebar; |
||||
use Cake\Core\Configure; |
||||
|
||||
return [ |
||||
'CakeLte' => [ |
||||
'app-name' => '<b>' . Configure::read('Theme.title') . '</b>', |
||||
'app-logo' => Configure::read('Theme.logo'), |
||||
|
||||
'small-text' => false, |
||||
'dark-mode' => false, |
||||
'layout-boxed' => false, |
||||
|
||||
'header' => [ |
||||
'fixed' => false, |
||||
'border' => true, |
||||
'style' => Header::STYLE_DARK, |
||||
'dropdown-legacy' => false, |
||||
], |
||||
|
||||
'sidebar' => [ |
||||
'fixed' => true, |
||||
'collapsed' => false, |
||||
'mini' => true, |
||||
'mini-md' => false, |
||||
'mini-xs' => false, |
||||
'style' => Sidebar::STYLE_DARK_PRIMARY, |
||||
|
||||
'flat-style' => false, |
||||
'legacy-style' => false, |
||||
'compact' => false, |
||||
'child-indent' => true, |
||||
'child-hide-collapse' => false, |
||||
'disabled-auto-expand' => false, |
||||
], |
||||
|
||||
'footer' => [ |
||||
'fixed' => false, |
||||
], |
||||
], |
||||
]; |
||||
@ -0,0 +1,52 @@
|
||||
-----BEGIN RSA PRIVATE KEY----- |
||||
MIIJKQIBAAKCAgEA0YVnol1T7RaJIiMDiivC1bgDyqn2b31j+t8NQXcLm7dOq8az |
||||
Wgsn3ySGj1Was/Mlye5uCegnj9LPOvK6b6wG4NcNKEouAdjwoZ8PFsTZU2q/lGzr |
||||
Ze4Kc/E19oVgdKRhTgDuCKq7sShC7Un+2lY0CCt2GSA133Mqoztih5Y+zvlqyKaM |
||||
xF6eNy62L1IqNUWEMFIgkVq4Jy2XMii7qrYdE9cJbleZ1MDlTO7a0v3bhLxdC5D6 |
||||
2HPcalV3qYKiCWX/EhCz4b8JWfoW8tfV8GoEX+6JV+AohOXC9wdopCV89SJu1x+S |
||||
p4yWkBtm1nSMifaPfXqyz9tiGFL8ziJpEW59lTgbd1KZMCcoGIHR8gq7PowDVkAQ |
||||
IdU628DS3FPgBgPRV7r9oPuytjPzojmuu64aClgWylE6WDn2daBHUHtlY0NLA7VN |
||||
jIMMnvnlM0OBGGN4god4LVzFZkgso36i6RJghYUiKaz7DOQEMEGx6bWQlHxnLR0/ |
||||
khv/1ERpKNWq/q0vXeoNA7L1jZ64k3U/MyWmaJPdjcoPFGYI2Vwlz//M1TZmyoV7 |
||||
YC01YJcsTbA5+ocukOZDlvsEWZKWJoi/I5vYcQfBZGrAY8pl7LFCVlnpUR+UHB3a |
||||
Fp0+Q4OK0OhQuOmbMqz2J/t2MbWXwBsnQkP3XNnoA1t4fbraPeex25NTZVMCAwEA |
||||
AQKCAgEAjnRkzQkleeq7nIEv8+7jDsqJkW7UBmO76aNkcOFO/DW7AKId6ZfyKQ69 |
||||
ipEKmVU1mUFKgePdmjUb/xlv12OgXZj58i3VcB4fJdRuvu1iUgwfa/xOZMRfSQt0 |
||||
xENVHJlzK0UIks36xW35azrHU44O3IsoRdcXqfC0yb0jtcpatADzMK/Ev/MRIbXZ |
||||
2vzDg+rbALumNw32bXTa+xik2GHwDUBEwkg/aF8qyI8SKyi861fi721IkIjeEVJB |
||||
BPiz0S4PKio/E7r+0bVvivdjF44NoWge66eWBR3u3GSmKgzvFACwWgW2gcLdz+dB |
||||
mYgu0dLZJtiY4ShpXt510nWk+Fwmd2YHSt0U/rnoiOSEXRqh2UPZL9zgK0F81E8v |
||||
Ay1Yij59P0tkjIz3VtYluMGV6nXoQunJyIFsUN3r3h2p6ZxeitN+CEmUN/zOvmrN |
||||
Ziqy4Hnta03eC3ZZ3i3NIHuth63hVrh5qFEKT5Ggqvw6Swfzg1mL9biZ+4A1xICP |
||||
8850+yBaX6n3BgRwLmFd9xjtA7GNJ1vrcOn6+uw7OOaUl+WUlnX8uqDCPE/mhMd4 |
||||
SM/O4kL/G4BFb45q4LeYkiuFk5UHatWdcOlttQkvrgSCH4PpfJDiilKn/tVU34HY |
||||
OM7/N+j9wMpZj7dqPMra+WbzKA4I0d+rnKZsUVHbCAZZzEf0w/kCggEBAPRQKV8W |
||||
w1Z+JlZeRtoxSSCSEgHDpun13ZiXBi17ErYhN5LTCMJ8XUmeeexVCcRMOqjvClgz |
||||
2hrHaC66nW2pfBu2euVHqecD0likKEINsucbTa2PNZeP0sV8px1k5NASRlNilqGy |
||||
vrWT425E7yrss2RBOcE6ro6M9QYZSLZjiYNqzk6w4j6McyFertq7/Yz9JCaAq72e |
||||
ptCrvzoAtCFra3nwTgxlu1QVB8I/Kjg94lpTLQcS7mehDep+qYSlnFzJ5CnGF7t4 |
||||
K5WZ4VEo1u4dpbewTVDfc3W+ODTQgmYByU6mUwl4Kf4V6ovKJ9say1z0ZdbXcHRJ |
||||
ZG8+Hdld47TwHe8CggEBANuLLtsoCvUyLs9X6+6kToSTN3FVRnkfoJLbXe9+smw/ |
||||
5QAvvh2lwlwc6xXajEEsNK8z9mVRSCrXoiqRTjTo2ioe0oxx9Gnou+/d2MB9WJm3 |
||||
hQAwMGjwifg6AD9bZre+NiEl92WmlJs3fm4zFrEMpCBCOJ7JIe7GxsdKwR/guvQt |
||||
9k/NCQj2fOnCzCoFYtebPPDXukcn2Ad2XOkvLWzLmG4HRGuLPeqgjvxppBdtU3Xm |
||||
NJklIndw1g+xcY8/7bbNyo8Nd/PV/ymv/sflrQyXjVs4mwwAgY9usFntO+qT4nEd |
||||
wfPgedDlpsNDprSdjDo5xNA79yaVFUuzJCIDFXO9Ut0CggEAaA5QYKCoWAlouLZ0 |
||||
xO/i7o1oP/od+F3woNIKHorhwFLLgayCeZtQfE+ULFVX0JSLE3KkXEbRaUBvHh/7 |
||||
dz6NjpwdIdRxB+S3zWs1flSpUwdtATQSplfqdJSP9NQJJJnz/AXslDg2Q84WOtv/ |
||||
Za/lBBlHyQX+XNaqcYuJTa19X0y5TAjIg818J8VVAfK5njgfEosRGrUc5ZmQ29p6 |
||||
3hULdKcmBt+5dqlyYYhXqhapdsEgV3f3tImDDNIfz1BeFaMjm6s0ZnNbVN9yeQfE |
||||
6ywTbfYYKA7T9V0sQUphj6LJI8dxbIISmJarDBjw+sAhx5iMW4Hs8opjzYGOYws7 |
||||
NdBjXwKCAQBc0Bh8+g633gFAEtFhUAEJtxsHRJ/IcQB3VVn+97cCYHi1fXmIGx1x |
||||
x5/y2zPUEZYsQ3F1H8m8ovChwlAnuhERIXqteTd01rktDMKnjdY5FgaaL8UneBk7 |
||||
4XldT4y7PSSxGtXeGXBVtj4y5FJBgzCXmqdJKYq44TwD4KyIh39B33R0BCA/s8TX |
||||
Jk0drq08rRo0T18m2cdQUE+zHQi9J81HJrdcJ7+DQ2FvgFGovcU84Jd37uUFTaSR |
||||
ediiUMp0L8fkdjMx2FRJEWhKpeRkoGVYHTQe/M/JDWhsfAiKgP6IB6aJLWsSTyQT |
||||
BLSjQr+XlfiId/FiVEBugktSPa+CAJXZAoIBAQDj32TA+MI5gWtWlP4u9KsyrDGD |
||||
NJyutrAGziQSibgj5CW++fVm6TcXZ3rezxFZ/QDr8MlEJhpGoi3Ca+U0JyIcrn3z |
||||
fgwKGJd7kVFD8jhqm85j8rMk9sqEgg88cE6yt4tC+LAwLLeyhVqea5q5vF5dV9gN |
||||
1LtP6E30MQxWRBWhcp7FyZEzS6eYIjQwVCaVD2tDXg3hQQ/gxyPantsEdgoqCfgu |
||||
MjBJiaw5fO+qBROzema0LDXs7m5HAZRur22c9a45d0+SmCAmudsxoKrnV6w7gdd+ |
||||
1Jp1KFef7gx9iSBm3E3rcCBBOfPfRKbvBD5bhNXxT/a/iK8wPQY4uKiwgKt+ |
||||
-----END RSA PRIVATE KEY----- |
||||
|
||||
@ -0,0 +1,15 @@
|
||||
-----BEGIN PUBLIC KEY----- |
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0YVnol1T7RaJIiMDiivC |
||||
1bgDyqn2b31j+t8NQXcLm7dOq8azWgsn3ySGj1Was/Mlye5uCegnj9LPOvK6b6wG |
||||
4NcNKEouAdjwoZ8PFsTZU2q/lGzrZe4Kc/E19oVgdKRhTgDuCKq7sShC7Un+2lY0 |
||||
CCt2GSA133Mqoztih5Y+zvlqyKaMxF6eNy62L1IqNUWEMFIgkVq4Jy2XMii7qrYd |
||||
E9cJbleZ1MDlTO7a0v3bhLxdC5D62HPcalV3qYKiCWX/EhCz4b8JWfoW8tfV8GoE |
||||
X+6JV+AohOXC9wdopCV89SJu1x+Sp4yWkBtm1nSMifaPfXqyz9tiGFL8ziJpEW59 |
||||
lTgbd1KZMCcoGIHR8gq7PowDVkAQIdU628DS3FPgBgPRV7r9oPuytjPzojmuu64a |
||||
ClgWylE6WDn2daBHUHtlY0NLA7VNjIMMnvnlM0OBGGN4god4LVzFZkgso36i6RJg |
||||
hYUiKaz7DOQEMEGx6bWQlHxnLR0/khv/1ERpKNWq/q0vXeoNA7L1jZ64k3U/MyWm |
||||
aJPdjcoPFGYI2Vwlz//M1TZmyoV7YC01YJcsTbA5+ocukOZDlvsEWZKWJoi/I5vY |
||||
cQfBZGrAY8pl7LFCVlnpUR+UHB3aFp0+Q4OK0OhQuOmbMqz2J/t2MbWXwBsnQkP3 |
||||
XNnoA1t4fbraPeex25NTZVMCAwEAAQ== |
||||
-----END PUBLIC KEY----- |
||||
|
||||
@ -0,0 +1,94 @@
|
||||
<?php |
||||
/** |
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* |
||||
* Licensed under The MIT License |
||||
* Redistributions of files must retain the above copyright notice. |
||||
* |
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* @link https://cakephp.org CakePHP(tm) Project |
||||
* @since 3.0.0 |
||||
* @license MIT License (https://opensource.org/licenses/mit-license.php) |
||||
*/ |
||||
|
||||
/* |
||||
* Use the DS to separate the directories in other defines |
||||
*/ |
||||
if (!defined('DS')) { |
||||
define('DS', DIRECTORY_SEPARATOR); |
||||
} |
||||
|
||||
/* |
||||
* These defines should only be edited if you have cake installed in |
||||
* a directory layout other than the way it is distributed. |
||||
* When using custom settings be sure to use the DS and do not add a trailing DS. |
||||
*/ |
||||
|
||||
/* |
||||
* The full path to the directory which holds "src", WITHOUT a trailing DS. |
||||
*/ |
||||
define('ROOT', dirname(__DIR__)); |
||||
|
||||
/* |
||||
* The actual directory name for the application directory. Normally |
||||
* named 'src'. |
||||
*/ |
||||
define('APP_DIR', 'src'); |
||||
|
||||
/* |
||||
* Path to the application's directory. |
||||
*/ |
||||
define('APP', ROOT . DS . APP_DIR . DS); |
||||
|
||||
/* |
||||
* Path to the config directory. |
||||
*/ |
||||
define('CONFIG', ROOT . DS . 'config' . DS); |
||||
|
||||
/* |
||||
* File path to the webroot directory. |
||||
* |
||||
* To derive your webroot from your webserver change this to: |
||||
* |
||||
* `define('WWW_ROOT', rtrim($_SERVER['DOCUMENT_ROOT'], DS) . DS);` |
||||
*/ |
||||
define('WWW_ROOT', ROOT . DS . 'webroot' . DS); |
||||
|
||||
/* |
||||
* Path to the tests directory. |
||||
*/ |
||||
define('TESTS', ROOT . DS . 'tests' . DS); |
||||
|
||||
/* |
||||
* Path to the temporary files directory. |
||||
*/ |
||||
define('TMP', ROOT . DS . 'tmp' . DS); |
||||
|
||||
/* |
||||
* Path to the logs directory. |
||||
*/ |
||||
define('LOGS', ROOT . DS . 'logs' . DS); |
||||
|
||||
/* |
||||
* Path to the cache files directory. It can be shared between hosts in a multi-server setup. |
||||
*/ |
||||
define('CACHE', TMP . 'cache' . DS); |
||||
|
||||
/* |
||||
* Path to the resources directory. |
||||
*/ |
||||
define('RESOURCES', ROOT . DS . 'resources' . DS); |
||||
|
||||
/* |
||||
* The absolute path to the "cake" directory, WITHOUT a trailing DS. |
||||
* |
||||
* CakePHP should always be installed with composer, so look there. |
||||
*/ |
||||
define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'vendor' . DS . 'cakephp' . DS . 'cakephp'); |
||||
|
||||
/* |
||||
* Path to the cake directory. |
||||
*/ |
||||
define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); |
||||
define('CAKE', CORE_PATH . 'src' . DS); |
||||
@ -0,0 +1,15 @@
|
||||
<?php |
||||
|
||||
return [ |
||||
'DebugKit' => [ |
||||
'onlyDebug' => true, |
||||
], |
||||
'Bake' => [ |
||||
'onlyCli' => true, |
||||
'optional' => true, |
||||
], |
||||
'Migrations' => [ |
||||
'onlyCli' => true, |
||||
], |
||||
'CakeLte' => [], |
||||
]; |
||||
@ -0,0 +1,357 @@
|
||||
<?php |
||||
/** |
||||
* Routes configuration. |
||||
* |
||||
* In this file, you set up routes to your controllers and their actions. |
||||
* Routes are very important mechanism that allows you to freely connect |
||||
* different URLs to chosen controllers and their actions (functions). |
||||
* |
||||
* It's loaded within the context of `Application::routes()` method which |
||||
* receives a `RouteBuilder` instance `$routes` as method argument. |
||||
* |
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* |
||||
* Licensed under The MIT License |
||||
* For full copyright and license information, please see the LICENSE.txt |
||||
* Redistributions of files must retain the above copyright notice. |
||||
* |
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* @link https://cakephp.org CakePHP(tm) Project |
||||
* @license https://opensource.org/licenses/mit-license.php MIT License |
||||
*/ |
||||
|
||||
use Cake\Routing\RouteBuilder; |
||||
use Cake\Routing\Route\InflectedRoute; |
||||
|
||||
return static function (RouteBuilder $routes) { |
||||
$routes->setRouteClass(InflectedRoute::class); |
||||
|
||||
$routes->prefix('Api', function (RouteBuilder $routes) { |
||||
$routes->setExtensions(['json', 'csv']); |
||||
|
||||
$routes->resources('Attachments', [ |
||||
'id' => '.*', |
||||
]); |
||||
|
||||
$routes->resources('Notifications', [ |
||||
'map' => [ |
||||
'' => [ |
||||
'action' => 'index', |
||||
'method' => ['GET'], |
||||
], |
||||
'index' => [ |
||||
'action' => 'index', |
||||
'method' => ['GET'], |
||||
], |
||||
'count' => [ |
||||
'action' => 'count', |
||||
'method' => ['GET'], |
||||
], |
||||
'edit/{id}' => [ |
||||
'action' => 'edit', |
||||
'method' => ['POST'], |
||||
], |
||||
'check' => [ |
||||
'action' => 'check', |
||||
'method' => ['GET'], |
||||
], |
||||
], |
||||
]); |
||||
|
||||
$routes->resources('Organisations', [ |
||||
'connectOptions' => [ |
||||
'photo' => '.*', |
||||
'pass' => ['id', 'photo'], |
||||
], |
||||
'map' => [ |
||||
'get_photo/{photo}' => [ |
||||
'action' => 'getPhoto', |
||||
'method' => ['GET'], |
||||
], |
||||
], |
||||
]); |
||||
|
||||
$routes->resources('OrganisationTypes', ['inflect' => 'underscore']); |
||||
|
||||
$routes->resources('Users', [ |
||||
'connectOptions' => [ |
||||
'photo' => '.*', |
||||
'pass' => ['id', 'photo'], |
||||
], |
||||
'map' => [ |
||||
'login' => [ |
||||
'action' => 'login', |
||||
'method' => ['POST', 'GET'], |
||||
], |
||||
'get_photo/{photo}' => [ |
||||
'action' => 'getPhoto', |
||||
'method' => ['GET'], |
||||
], |
||||
], |
||||
]); |
||||
|
||||
$routes->resources('Subscriptions', [ |
||||
'map' => [ |
||||
'subscribe' => [ |
||||
'action' => 'subscribe', |
||||
'method' => ['POST'], |
||||
], |
||||
'unsubscribe' => [ |
||||
'action' => 'unsubscribe', |
||||
'method' => ['DELETE'], |
||||
], |
||||
], |
||||
]); |
||||
|
||||
$routes->resources('WaterDrawingPaperworks', [ |
||||
'inflect' => 'underscore', |
||||
'map' => [ |
||||
'' => [ |
||||
'action' => 'index', |
||||
'method' => ['GET'], |
||||
], |
||||
'index' => [ |
||||
'action' => 'index', |
||||
'method' => ['GET'], |
||||
], |
||||
'view/{id}' => [ |
||||
'action' => 'view', |
||||
'method' => ['GET'], |
||||
], |
||||
], |
||||
]); |
||||
|
||||
$routes->resources('WaterDrawingDerivations', [ |
||||
'inflect' => 'underscore', |
||||
'map' => [ |
||||
'update_data' => [ |
||||
'action' => 'update_data', |
||||
'method' => ['POST'], |
||||
], |
||||
'update_location' => [ |
||||
'action' => 'update_location', |
||||
'method' => ['POST'], |
||||
], |
||||
'view/{id}' => [ |
||||
'action' => 'view', |
||||
'method' => ['GET'], |
||||
], |
||||
], |
||||
]); |
||||
|
||||
$routes->resources('WaterDrawingMeasurements', [ |
||||
'inflect' => 'underscore', |
||||
'map' => [ |
||||
'add' => [ |
||||
'action' => 'add', |
||||
'method' => ['POST'], |
||||
], |
||||
'last_index/{id}' => [ |
||||
'action' => 'last_index', |
||||
'method' => ['GET'], |
||||
], |
||||
], |
||||
]); |
||||
}); |
||||
|
||||
$routes->scope('/', function (RouteBuilder $builder) { |
||||
$builder->setExtensions(['json', 'csv']); |
||||
|
||||
$builder->connect('/', ['controller' => 'Dashboard', 'action' => 'index']); |
||||
|
||||
$builder->connect('/attachments/view/{id}', ['controller' => 'Attachments', 'action' => 'view'])->setPass(['id']); |
||||
$builder->connect('/attachments/markAsRelevant/{id}', ['controller' => 'Attachments', 'action' => 'markAsRelevant'])->setPass(['id']); |
||||
$builder->connect('/attachments/markAsDeleted/{id}', ['controller' => 'Attachments', 'action' => 'markAsDeleted'])->setPass(['id']); |
||||
|
||||
$builder->connect('/capabilities', ['controller' => 'Capabilities', 'action' => 'index']); |
||||
$builder->connect('/capabilities/index', ['controller' => 'Capabilities', 'action' => 'index']); |
||||
$builder->connect('/capabilities/hide/{id}', ['controller' => 'Capabilities', 'action' => 'hide'])->setPass(['id']); |
||||
$builder->connect('/capabilities/show/{id}', ['controller' => 'Capabilities', 'action' => 'show'])->setPass(['id']); |
||||
$builder->connect('/capabilities/delete/{id}', ['controller' => 'Capabilities', 'action' => 'delete'])->setPass(['id']); |
||||
$builder->connect('/capabilities/restore/{id}', ['controller' => 'Capabilities', 'action' => 'restore'])->setPass(['id']); |
||||
|
||||
$builder->connect('/controllable_objects/getAttachments/{id}', ['controller' => 'ControllableObjects', 'action' => 'getAttachments'])->setPass(['id']); |
||||
|
||||
$builder->connect('/deliveries/{id}', ['controller' => 'Deliveries', 'action' => 'index'])->setPass(['id']); |
||||
$builder->connect('/deliveries/index/{id}', ['controller' => 'Deliveries', 'action' => 'index'])->setPass(['id']); |
||||
$builder->connect('/deliveries/delete/{id}', ['controller' => 'Deliveries', 'action' => 'delete'])->setPass(['id']); |
||||
|
||||
$builder->connect('/emails/add/{id}', ['controller' => 'Emails', 'action' => 'add'])->setPass(['id']); |
||||
$builder->connect('/emails/edit/{id}', ['controller' => 'Emails', 'action' => 'edit'])->setPass(['id']); |
||||
|
||||
$builder->connect('/faxes/add/{id}', ['controller' => 'Faxes', 'action' => 'add'])->setPass(['id']); |
||||
$builder->connect('/faxes/edit/{id}', ['controller' => 'Faxes', 'action' => 'edit'])->setPass(['id']); |
||||
|
||||
$builder->connect('/filters/getFilterInput/{id}', ['controller' => 'Filters', 'action' => 'getFilterInput'])->setPass(['id']); |
||||
|
||||
$builder->connect('/groups', ['controller' => 'Groups', 'action' => 'index']); |
||||
$builder->connect('/groups/index', ['controller' => 'Groups', 'action' => 'index']); |
||||
$builder->connect('/groups/add', ['controller' => 'Groups', 'action' => 'add']); |
||||
$builder->connect('/groups/view/{id}', ['controller' => 'Groups', 'action' => 'view'])->setPass(['id']); |
||||
$builder->connect('/groups/edit/{id}', ['controller' => 'Groups', 'action' => 'edit'])->setPass(['id']); |
||||
$builder->connect('/groups/delete/{id}', ['controller' => 'Groups', 'action' => 'delete'])->setPass(['id']); |
||||
$builder->connect('/groups/handleCapabilities/{id}', ['controller' => 'Groups', 'action' => 'handleCapabilities'])->setPass(['id']); |
||||
|
||||
$builder->connect('/maps', ['controller' => 'Maps', 'action' => 'index']); |
||||
$builder->connect('/maps/index', ['controller' => 'Maps', 'action' => 'index']); |
||||
$builder->connect('/maps/getWfs', ['controller' => 'Maps', 'action' => 'getWfs']); |
||||
$builder->connect('/maps/geocode', ['controller' => 'Maps', 'action' => 'geocode']); |
||||
|
||||
$builder->connect('/mobile_phones/add/{id}', ['controller' => 'MobilePhones', 'action' => 'add'])->setPass(['id']); |
||||
$builder->connect('/mobile_phones/edit/{id}', ['controller' => 'MobilePhones', 'action' => 'edit'])->setPass(['id']); |
||||
|
||||
$builder->connect('/notifications', ['controller' => 'Notifications', 'action' => 'index']); |
||||
$builder->connect('/notifications/index', ['controller' => 'Notifications', 'action' => 'index']); |
||||
$builder->connect('/notifications/readAll', ['controller' => 'Notifications', 'action' => 'readAll']); |
||||
$builder->connect('/notifications/testAll', ['controller' => 'Notifications', 'action' => 'testAll']); |
||||
$builder->connect('/notifications/view/{id}', ['controller' => 'Notifications', 'action' => 'view'])->setPass(['id']); |
||||
|
||||
$builder->connect('/organisations', ['controller' => 'Organisations', 'action' => 'index']); |
||||
$builder->connect('/organisations/index', ['controller' => 'Organisations', 'action' => 'index']); |
||||
$builder->connect('/organisations/add', ['controller' => 'Organisations', 'action' => 'add']); |
||||
$builder->connect('/organisations/view/{id}', ['controller' => 'Organisations', 'action' => 'view'])->setPass(['id']); |
||||
$builder->connect('/organisations/edit/{id}', ['controller' => 'Organisations', 'action' => 'edit'])->setPass(['id']); |
||||
$builder->connect('/organisations/delete/{id}', ['controller' => 'Organisations', 'action' => 'delete'])->setPass(['id']); |
||||
|
||||
$builder->connect('/phones/add/{id}', ['controller' => 'Phones', 'action' => 'add'])->setPass(['id']); |
||||
$builder->connect('/phones/edit/{id}', ['controller' => 'Phones', 'action' => 'edit'])->setPass(['id']); |
||||
|
||||
$builder->connect('/telegram_chats/add/{id}', ['controller' => 'TelegramChats', 'action' => 'add'])->setPass(['id']); |
||||
$builder->connect('/telegram_chats/edit/{id}', ['controller' => 'TelegramChats', 'action' => 'edit'])->setPass(['id']); |
||||
|
||||
$builder->connect('/users', ['controller' => 'Users', 'action' => 'index']); |
||||
$builder->connect('/users/login_oidc', ['controller' => 'Users', 'action' => 'login_oidc']); |
||||
$builder->connect('/users/login_oidc_authenticated', ['controller' => 'Users', 'action' => 'login_oidc_authenticated']); |
||||
$builder->connect('/users/index', ['controller' => 'Users', 'action' => 'index']); |
||||
$builder->connect('/users/add', ['controller' => 'Users', 'action' => 'add']); |
||||
$builder->connect('/users/view/{id}', ['controller' => 'Users', 'action' => 'view'])->setPass(['id']); |
||||
$builder->connect('/users/edit/{id}', ['controller' => 'Users', 'action' => 'edit'])->setPass(['id']); |
||||
$builder->connect('/users/delete/{id}', ['controller' => 'Users', 'action' => 'delete'])->setPass(['id']); |
||||
$builder->connect('/users/login', ['controller' => 'Users', 'action' => 'login']); |
||||
$builder->connect('/users/logout', ['controller' => 'Users', 'action' => 'logout']); |
||||
$builder->connect('/users/passwordRecovery', ['controller' => 'Users', 'action' => 'passwordRecovery']); |
||||
$builder->connect('/users/chooseNewPassword/{id}', ['controller' => 'Users', 'action' => 'chooseNewPassword'])->setPass(['id']); |
||||
$builder->connect('/users/oneTimePassword/{otp}', ['controller' => 'Users', 'action' => 'oneTimePassword'])->setPass(['otp']); |
||||
$builder->connect('/users/getPhoto/{id}', ['controller' => 'Users', 'action' => 'getPhoto'])->setPass(['id']); |
||||
$builder->connect('/users/deleteUserPhoto/{id}', ['controller' => 'Users', 'action' => 'deleteUserPhoto'])->setPass(['id']); |
||||
$builder->connect('/users/add-citizen', ['controller' => 'Users', 'action' => 'add_citizen']); |
||||
$builder->connect('/users/verify-citizen/{token}', ['controller' => 'Users', 'action' => 'verify_citizen'])->setPass(['token']); |
||||
|
||||
$builder->connect('/water_drawing_paperworks', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index']); |
||||
$builder->connect('/water_drawing_paperworks/index', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index']); |
||||
$builder->connect('/water_drawing_paperworks/index_snapshots/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots'])->setPass(['water_drawing_paperwork_id']); |
||||
$builder->connect('/water_drawing_paperworks/index_snapshots_all', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_all']); |
||||
$builder->connect('/water_drawing_paperworks/validate_index', ['controller' => 'WaterDrawingPaperworks', 'action' => 'validate_index']); |
||||
$builder->connect('/water_drawing_paperworks/add_scan', ['controller' => 'WaterDrawingPaperworks', 'action' => 'add_scan']); |
||||
$builder->connect('/water_drawing_paperworks/add', ['controller' => 'WaterDrawingPaperworks', 'action' => 'add']); |
||||
$builder->connect('/water_drawing_paperworks/view_scan/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'view_scan'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/view/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'view'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/view_scan_snapshot/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'view_scan_snapshot'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/view_snapshot/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'view_snapshot'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/edit_scan/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'edit_scan'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/edit/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'edit'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/delete/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'delete'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/validate_scan/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'validate_scan'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/validate/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'validate'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/send_to_drar/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'send_to_drar'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/send_to_gc/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'send_to_gc'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/submit_antimafia_request/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'submit_antimafia_request'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/antimafia_request_to_anac/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'antimafia_request_to_anac'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/request_self_certification/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'request_self_certification'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/applicants_water_drawing_paperworks_item_block/{id}/{status_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'applicants_water_drawing_paperworks_item_block'])->setPass(['id', 'status_id']); |
||||
$builder->connect('/water_drawing_paperworks/applicants_water_drawing_paperworks_item_block/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'applicants_water_drawing_paperworks_item_block'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/intended_uses_water_drawing_paperworks_item_block/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'intended_uses_water_drawing_paperworks_item_block'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/upload_attachment/{id}/{tag_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'upload_attachment'])->setPass(['id', 'tag_id']); |
||||
$builder->connect('/water_drawing_paperworks/upload_attachment_scan/{id}/{tag_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'upload_attachment_scan'])->setPass(['id', 'tag_id']); |
||||
$builder->connect('/water_drawing_paperworks/upload_antimafia_attachment/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'upload_antimafia_attachment'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/assign/{id}/{organisation_type_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'assign'])->setPass(['id', 'organisation_type_id']); |
||||
$builder->connect('/water_drawing_paperworks/citizen_submission_index', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index']); |
||||
$builder->connect('/water_drawing_paperworks/citizen_documentation_index/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_documentation_index'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/citizen_documentation_requested/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_documentation_requested'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/citizen_upload_attachment/{id}/{tag_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_upload_attachment'])->setPass(['id', 'tag_id']); |
||||
$builder->connect('/water_drawing_paperworks/citizen_submit_paperwork/{applicant_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submit_paperwork'])->setPass(['applicant_id']); |
||||
$builder->connect('/water_drawing_paperworks/citizen_request_paperwork', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_request_paperwork']); |
||||
$builder->connect('/water_drawing_paperworks/citizen_send_to_validation/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_send_to_validation'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperworks/delete_attachment/{id}/{attachment_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'delete_attachment'])->setPass(['id', 'attachment_id']); |
||||
$builder->connect('/water_drawing_paperworks/send_to_validation/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'send_to_validation'])->setPass(['id']); |
||||
|
||||
$builder->connect('/applicants/search_applicants', ['controller' => 'Applicants', 'action' => 'search_applicants']); |
||||
$builder->connect('/applicants/get_applicant/{id}', ['controller' => 'Applicants', 'action' => 'get_applicant'])->setPass(['id']); |
||||
$builder->connect('/applicants/edit/{id}', ['controller' => 'Applicants', 'action' => 'edit'])->setPass(['id']); |
||||
$builder->connect('/applicants/edit/{id}/{water_id}', ['controller' => 'Applicants', 'action' => 'edit'])->setPass(['id','water_id']); |
||||
$builder->connect('/applicants/view/{id}/', ['controller' => 'Applicants', 'action' => 'view'])->setPass(['id']); |
||||
$builder->connect('/applicants/citizen_add/', ['controller' => 'Applicants', 'action' => 'citizen_add']); |
||||
$builder->connect('/applicants/citizen_edit/{id}', ['controller' => 'Applicants', 'action' => 'citizen_edit'])->setPass(['id']); |
||||
$builder->connect('/applicants/citizen_view', ['controller' => 'Applicants', 'action' => 'citizen_view']); |
||||
|
||||
$builder->connect('/water_drawing_measurements/add/{water_drawing_meter_id}', ['controller' => 'WaterDrawingMeasurements', 'action' => 'add'])->setPass(['water_drawing_meter_id']); |
||||
$builder->connect('/water_drawing_measurements/index/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingMeasurements', 'action' => 'index'])->setPass(['water_drawing_paperwork_id']); |
||||
|
||||
$builder->connect('/water_drawing_meters/add/{water_drawing_derivation_id}', ['controller' => 'WaterDrawingMeters', 'action' => 'add'])->setPass(['water_drawing_derivation_id']); |
||||
$builder->connect('/water_drawing_meters/edit/{water_drawing_meter_id}', ['controller' => 'WaterDrawingMeters', 'action' => 'edit'])->setPass(['water_drawing_meter_id']); |
||||
$builder->connect('/water_drawing_meters/view/{water_drawing_meter_id}', ['controller' => 'WaterDrawingMeters', 'action' => 'view'])->setPass(['water_drawing_meter_id']); |
||||
$builder->connect('/water_drawing_meters/dismiss/{water_drawing_meter_id}', ['controller' => 'WaterDrawingMeters', 'action' => 'dismiss'])->setPass(['water_drawing_meter_id']); |
||||
|
||||
$builder->connect('/water_drawing_payments/index_all', ['controller' => 'WaterDrawingPayments', 'action' => 'index_all']); |
||||
$builder->connect('/water_drawing_payments/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPayments', 'action' => 'index'])->setPass(['water_drawing_paperwork_id']); |
||||
$builder->connect('/water_drawing_payments/index/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPayments', 'action' => 'index'])->setPass(['water_drawing_paperwork_id']); |
||||
$builder->connect('/water_drawing_payments/add/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPayments', 'action' => 'add'])->setPass(['water_drawing_paperwork_id']); |
||||
$builder->connect('/water_drawing_payments/edit/{id}', ['controller' => 'WaterDrawingPayments', 'action' => 'edit'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_payments/view/{id}', ['controller' => 'WaterDrawingPayments', 'action' => 'view'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_payments/delete/{id}', ['controller' => 'WaterDrawingPayments', 'action' => 'delete'])->setPass(['id']); |
||||
|
||||
$builder->connect('/water_drawing_derivations/add/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingDerivations', 'action' => 'add'])->setPass(['water_drawing_paperwork_id']); |
||||
$builder->connect('/water_drawing_derivations/view/{water_drawing_derivation_id}', ['controller' => 'WaterDrawingDerivations', 'action' => 'view'])->setPass(['water_drawing_derivation_id']); |
||||
$builder->connect('/water_drawing_derivations/edit/{water_drawing_derivation_id}', ['controller' => 'WaterDrawingDerivations', 'action' => 'edit'])->setPass(['water_drawing_derivation_id']); |
||||
$builder->connect('/water_drawing_derivations/delete/{water_drawing_derivation_id}', ['controller' => 'WaterDrawingDerivations', 'action' => 'delete'])->setPass(['water_drawing_derivation_id']); |
||||
|
||||
$builder->connect('/water_drawing_return_points/add/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingReturnPoints', 'action' => 'add'])->setPass(['water_drawing_paperwork_id']); |
||||
$builder->connect('/water_drawing_return_points/view/{id}', ['controller' => 'WaterDrawingReturnPoints', 'action' => 'view'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_return_points/edit/{id}', ['controller' => 'WaterDrawingReturnPoints', 'action' => 'edit'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_return_points/delete/{id}', ['controller' => 'WaterDrawingReturnPoints', 'action' => 'delete'])->setPass(['id']); |
||||
|
||||
$builder->connect('/water_drawing_articles/', ['controller' => 'WaterDrawingArticles', 'action' => 'index']); |
||||
$builder->connect('/water_drawing_articles/add', ['controller' => 'WaterDrawingArticles', 'action' => 'add']); |
||||
$builder->connect('/water_drawing_articles/edit/{id}', ['controller' => 'WaterDrawingArticles', 'action' => 'edit'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_articles/view/{id}', ['controller' => 'WaterDrawingArticles', 'action' => 'view'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_articles/delete/{id}', ['controller' => 'WaterDrawingArticles', 'action' => 'delete'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_articles/change_status/{id}', ['controller' => 'WaterDrawingArticles', 'action' => 'change_status'])->setPass(['id']); |
||||
|
||||
$builder->connect('/water_drawing_fees/index/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingFees', 'action' => 'index'])->setPass(['water_drawing_paperwork_id']); |
||||
$builder->connect('/water_drawing_fees/add/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingFees', 'action' => 'add'])->setPass(['water_drawing_paperwork_id']); |
||||
$builder->connect('/water_drawing_fees/view/{id}', ['controller' => 'WaterDrawingFees', 'action' => 'view'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_fees/edit/{id}', ['controller' => 'WaterDrawingFees', 'action' => 'edit'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_fees/delete/{id}', ['controller' => 'WaterDrawingFees', 'action' => 'delete'])->setPass(['id']); |
||||
|
||||
$builder->connect('/water_drawing_paperwork_pecs/index/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'index'])->setPass(['water_drawing_paperwork_id']); |
||||
$builder->connect('/water_drawing_paperwork_pecs/add/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'add'])->setPass(['water_drawing_paperwork_id']); |
||||
$builder->connect('/water_drawing_paperwork_pecs/edit/{id}', ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'edit'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperwork_pecs/view/{id}', ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'view'])->setPass(['id']); |
||||
$builder->connect('/water_drawing_paperwork_pecs/delete/{id}', ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'delete'])->setPass(['id']); |
||||
|
||||
$builder->connect('/ai_services/autocomplete', ['controller' => 'AiServices', 'action' => 'autocomplete']); |
||||
$builder->connect('/pecs/add/{id}', ['controller' => 'Pecs', 'action' => 'add'])->setPass(['id']); |
||||
$builder->connect('/pecs/edit/{id}', ['controller' => 'Pecs', 'action' => 'edit'])->setPass(['id']); |
||||
|
||||
$builder->connect('/privacy/edit/', ['controller' => 'Privacy', 'action' => 'edit']); |
||||
$builder->connect('/privacy/view', ['controller' => 'Privacy', 'action' => 'view']); |
||||
$builder->connect('/privacy/view_public', ['controller' => 'Privacy', 'action' => 'view_public']); |
||||
$builder->connect('/privacy/accept_privacy', ['controller' => 'Privacy', 'action' => 'accept_privacy']); |
||||
|
||||
$builder->connect('/districts/search_districts', ['controller' => 'Districts', 'action' => 'search_districts']); |
||||
$builder->connect('/water_drawing_paperworks/citizen_upload_payment_receipt/{id}/{tag_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_upload_payment_receipt'])->setPass(['id', 'tag_id']); |
||||
$builder->connect('/water_drawing_paperworks/index_csv', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_csv']); |
||||
$builder->connect('/water_drawing_paperworks/index_snapshots_all_csv', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_all_csv']); |
||||
$builder->connect('/water_drawing_paperworks/index_snapshots_csv/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_csv'])->setPass(['id']); |
||||
|
||||
$builder->connect('/tags', ['controller' => 'Tags', 'action' => 'index']); |
||||
$builder->connect('/tags/index', ['controller' => 'Tags', 'action' => 'index']); |
||||
$builder->connect('/tags/add', ['controller' => 'Tags', 'action' => 'add']); |
||||
$builder->connect('/tags/view', ['controller' => 'Tags', 'action' => 'view']); |
||||
$builder->connect('/tags/view/{id}', ['controller' => 'Tags', 'action' => 'view'])->setPass(['id']); |
||||
$builder->connect('/tags/edit', ['controller' => 'Tags', 'action' => 'edit']); |
||||
$builder->connect('/tags/edit/{id}', ['controller' => 'Tags', 'action' => 'edit'])->setPass(['id']); |
||||
|
||||
}); |
||||
}; |
||||
@ -0,0 +1,18 @@
|
||||
# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
# |
||||
# Licensed under The MIT License |
||||
# For full copyright and license information, please see the LICENSE.txt |
||||
# Redistributions of files must retain the above copyright notice. |
||||
# MIT License (https://opensource.org/licenses/mit-license.php) |
||||
|
||||
CREATE TABLE i18n ( |
||||
id int NOT NULL auto_increment, |
||||
locale varchar(6) NOT NULL, |
||||
model varchar(255) NOT NULL, |
||||
foreign_key int(10) NOT NULL, |
||||
field varchar(255) NOT NULL, |
||||
content text, |
||||
PRIMARY KEY (id), |
||||
UNIQUE INDEX I18N_LOCALE_FIELD(locale, model, foreign_key, field), |
||||
INDEX I18N_FIELD(model, foreign_key, field) |
||||
); |
||||
@ -0,0 +1,15 @@
|
||||
# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
# |
||||
# Licensed under The MIT License |
||||
# For full copyright and license information, please see the LICENSE.txt |
||||
# Redistributions of files must retain the above copyright notice. |
||||
# MIT License (https://opensource.org/licenses/mit-license.php) |
||||
|
||||
CREATE TABLE `sessions` ( |
||||
`id` char(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, |
||||
`created` datetime DEFAULT CURRENT_TIMESTAMP, -- optional, requires MySQL 5.6.5+ |
||||
`modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- optional, requires MySQL 5.6.5+ |
||||
`data` blob DEFAULT NULL, -- for PostgreSQL use bytea instead of blob |
||||
`expires` int(10) unsigned DEFAULT NULL, |
||||
PRIMARY KEY (`id`) |
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
||||
@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env sh |
||||
|
||||
if [ -f /run/secrets/sentry_dsn ]; then |
||||
export SENTRY_DSN=$(cat /run/secrets/sentry_dsn) |
||||
else |
||||
echo "Secret file 'sentry_dsn' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/oidc_client_id ]; then |
||||
export OIDC_CLIENT_ID=$(cat /run/secrets/oidc_client_id) |
||||
else |
||||
echo "Secret file 'oidc_client_id' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/rabbitmq_username ]; then |
||||
export RABBITMQ_USERNAME=$(cat /run/secrets/rabbitmq_username) |
||||
else |
||||
echo "Secret file 'rabbitmq_username' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/rabbitmq_password ]; then |
||||
export RABBITMQ_PASSWORD=$(cat /run/secrets/rabbitmq_password) |
||||
else |
||||
echo "Secret file 'rabbitmq_password' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/geoserver_username ]; then |
||||
export GEOSERVER_USERNAME=$(cat /run/secrets/geoserver_username) |
||||
else |
||||
echo "Secret file 'geoserver_username' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/geoserver_password ]; then |
||||
export GEOSERVER_PASSWORD=$(cat /run/secrets/geoserver_password) |
||||
else |
||||
echo "Secret file 'geoserver_password' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/minio_access_key ]; then |
||||
export MINIO_ACCESS_KEY=$(cat /run/secrets/minio_access_key) |
||||
else |
||||
echo "Secret file 'minio_access_key' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/minio_secret_key ]; then |
||||
export MINIO_SECRET_KEY=$(cat /run/secrets/minio_secret_key) |
||||
else |
||||
echo "Secret file 'minio_secret_key' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/telegram_bot_token ]; then |
||||
export TELEGRAM_BOT_TOKEN=$(cat /run/secrets/telegram_bot_token) |
||||
else |
||||
echo "Secret file 'telegram_bot_token' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/security_jwuc ]; then |
||||
export SECURITY_JWUC=$(cat /run/secrets/security_jwuc) |
||||
else |
||||
echo "Secret file 'security_jwuc' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/security_jwac ]; then |
||||
export SECURITY_JWAC=$(cat /run/secrets/security_jwac) |
||||
else |
||||
echo "Secret file 'security_jwac' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/mysql_jixel_username ]; then |
||||
export MYSQL_JIXEL_USERNAME=$(cat /run/secrets/mysql_jixel_username) |
||||
else |
||||
echo "Secret file 'mysql_jixel_username' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/mysql_jixel_password ]; then |
||||
export MYSQL_JIXEL_PASSWORD=$(cat /run/secrets/mysql_jixel_password) |
||||
else |
||||
echo "Secret file 'mysql_jixel_password' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/mysql_geo_jixel_username ]; then |
||||
export MYSQL_GEO_JIXEL_USERNAME=$(cat /run/secrets/mysql_geo_jixel_username) |
||||
else |
||||
echo "Secret file 'mysql_geo_jixel_username' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/mysql_geo_jixel_password ]; then |
||||
export MYSQL_GEO_JIXEL_PASSWORD=$(cat /run/secrets/mysql_geo_jixel_password) |
||||
else |
||||
echo "Secret file 'mysql_geo_jixel_password' not found!" >&2 |
||||
fi |
||||
|
||||
################################################################################ |
||||
# |
||||
# Cake is a shell script for invoking CakePHP shell commands |
||||
# |
||||
# CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
||||
# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
# |
||||
# Licensed under The MIT License |
||||
# For full copyright and license information, please see the LICENSE.txt |
||||
# Redistributions of files must retain the above copyright notice. |
||||
# |
||||
# @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
# @link https://cakephp.org CakePHP(tm) Project |
||||
# @since 1.2.0 |
||||
# @license https://opensource.org/licenses/mit-license.php MIT License |
||||
# |
||||
################################################################################ |
||||
|
||||
# Canonicalize by following every symlink of the given name recursively |
||||
canonicalize() { |
||||
NAME="$1" |
||||
if [ -f "$NAME" ] |
||||
then |
||||
DIR=$(dirname -- "$NAME") |
||||
NAME=$(cd -P "$DIR" > /dev/null && pwd -P)/$(basename -- "$NAME") |
||||
fi |
||||
while [ -h "$NAME" ]; do |
||||
DIR=$(dirname -- "$NAME") |
||||
SYM=$(readlink "$NAME") |
||||
NAME=$(cd "$DIR" > /dev/null && cd "$(dirname -- "$SYM")" > /dev/null && pwd)/$(basename -- "$SYM") |
||||
done |
||||
echo "$NAME" |
||||
} |
||||
|
||||
# Find a CLI version of PHP |
||||
findCliPhp() { |
||||
for TESTEXEC in php php-cli /usr/local/bin/php |
||||
do |
||||
SAPI=$(echo "<?= PHP_SAPI ?>" | $TESTEXEC 2>/dev/null) |
||||
if [ "$SAPI" = "cli" ] |
||||
then |
||||
echo $TESTEXEC |
||||
return |
||||
fi |
||||
done |
||||
echo "Failed to find a CLI version of PHP; falling back to system standard php executable" >&2 |
||||
echo "php"; |
||||
} |
||||
|
||||
# If current path is a symlink, resolve to real path |
||||
realname="$0" |
||||
if [ -L "$realname" ] |
||||
then |
||||
realname=$(readlink -f "$0") |
||||
fi |
||||
|
||||
CONSOLE=$(dirname -- "$(canonicalize "$realname")") |
||||
APP=$(dirname "$CONSOLE") |
||||
|
||||
# If your CLI PHP is somewhere that this doesn't find, you can define a PHP environment |
||||
# variable with the correct path in it. |
||||
if [ -z "$PHP" ] |
||||
then |
||||
PHP=$(findCliPhp) |
||||
fi |
||||
|
||||
if [ "$(basename "$realname")" != 'cake' ] |
||||
then |
||||
exec "$PHP" "$CONSOLE"/cake.php "$(basename "$realname")" "$@" |
||||
else |
||||
exec "$PHP" "$CONSOLE"/cake.php "$@" |
||||
fi |
||||
|
||||
exit |
||||
@ -0,0 +1,93 @@
|
||||
#!/bin/bash |
||||
|
||||
httpd_user=${httpd_user:-apache} |
||||
httpd_uid=${httpd_uid:-48} |
||||
httpd_group=${httpd_group:-apache} |
||||
|
||||
useradd -u $httpd_uid -s /sbin/nologin $httpd_user |
||||
|
||||
export httpd_user |
||||
export httpd_group |
||||
|
||||
if [ -f /run/secrets/sentry_dsn ]; then |
||||
export SENTRY_DSN=$(cat /run/secrets/sentry_dsn) |
||||
else |
||||
echo "Secret file 'sentry_dsn' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/oidc_client_id ]; then |
||||
export OIDC_CLIENT_ID=$(cat /run/secrets/oidc_client_id) |
||||
else |
||||
echo "Secret file 'oidc_client_id' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/rabbitmq_username ]; then |
||||
export RABBITMQ_USERNAME=$(cat /run/secrets/rabbitmq_username) |
||||
else |
||||
echo "Secret file 'rabbitmq_username' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/rabbitmq_password ]; then |
||||
export RABBITMQ_PASSWORD=$(cat /run/secrets/rabbitmq_password) |
||||
else |
||||
echo "Secret file 'rabbitmq_password' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/geoserver_username ]; then |
||||
export GEOSERVER_USERNAME=$(cat /run/secrets/geoserver_username) |
||||
else |
||||
echo "Secret file 'geoserver_username' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/geoserver_password ]; then |
||||
export GEOSERVER_PASSWORD=$(cat /run/secrets/geoserver_password) |
||||
else |
||||
echo "Secret file 'geoserver_password' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/minio_access_key ]; then |
||||
export MINIO_ACCESS_KEY=$(cat /run/secrets/minio_access_key) |
||||
else |
||||
echo "Secret file 'minio_access_key' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/minio_secret_key ]; then |
||||
export MINIO_SECRET_KEY=$(cat /run/secrets/minio_secret_key) |
||||
else |
||||
echo "Secret file 'minio_secret_key' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/telegram_bot_token ]; then |
||||
export TELEGRAM_BOT_TOKEN=$(cat /run/secrets/telegram_bot_token) |
||||
else |
||||
echo "Secret file 'telegram_bot_token' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/security_jwuc ]; then |
||||
export SECURITY_JWUC=$(cat /run/secrets/security_jwuc) |
||||
else |
||||
echo "Secret file 'security_jwuc' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/security_jwac ]; then |
||||
export SECURITY_JWAC=$(cat /run/secrets/security_jwac) |
||||
else |
||||
echo "Secret file 'security_jwac' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/mysql_jixel_username ]; then |
||||
export MYSQL_JIXEL_USERNAME=$(cat /run/secrets/mysql_jixel_username) |
||||
else |
||||
echo "Secret file 'mysql_jixel_username' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/mysql_jixel_password ]; then |
||||
export MYSQL_JIXEL_PASSWORD=$(cat /run/secrets/mysql_jixel_password) |
||||
else |
||||
echo "Secret file 'mysql_jixel_password' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/mysql_geo_jixel_username ]; then |
||||
export MYSQL_GEO_JIXEL_USERNAME=$(cat /run/secrets/mysql_geo_jixel_username) |
||||
else |
||||
echo "Secret file 'mysql_geo_jixel_username' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/mysql_geo_jixel_password ]; then |
||||
export MYSQL_GEO_JIXEL_PASSWORD=$(cat /run/secrets/mysql_geo_jixel_password) |
||||
else |
||||
echo "Secret file 'mysql_geo_jixel_password' not found!" >&2 |
||||
fi |
||||
|
||||
chmod -R o+w /var/www/jixel/tmp/ |
||||
chmod -R o+w /var/www/jixel/logs/ |
||||
|
||||
/usr/sbin/php-fpm |
||||
chown -R $httpd_user:$httpd_group /run/php-fpm |
||||
/usr/sbin/httpd -DFOREGROUND |
||||
@ -0,0 +1,453 @@
|
||||
; Start a new pool named 'www'. |
||||
; the variable $pool can be used in any directive and will be replaced by the |
||||
; pool name ('www' here) |
||||
[www] |
||||
|
||||
; Per pool prefix |
||||
; It only applies on the following directives: |
||||
; - 'access.log' |
||||
; - 'slowlog' |
||||
; - 'listen' (unixsocket) |
||||
; - 'chroot' |
||||
; - 'chdir' |
||||
; - 'php_values' |
||||
; - 'php_admin_values' |
||||
; When not set, the global prefix (or @php_fpm_prefix@) applies instead. |
||||
; Note: This directive can also be relative to the global prefix. |
||||
; Default Value: none |
||||
;prefix = /path/to/pools/$pool |
||||
|
||||
; Unix user/group of processes |
||||
; Note: The user is mandatory. If the group is not set, the default user's group |
||||
; will be used. |
||||
; RPM: apache user chosen to provide access to the same directories as httpd |
||||
user = apache |
||||
; RPM: Keep a group allowed to write in log dir. |
||||
group = apache |
||||
|
||||
; The address on which to accept FastCGI requests. |
||||
; Valid syntaxes are: |
||||
; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on |
||||
; a specific port; |
||||
; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on |
||||
; a specific port; |
||||
; 'port' - to listen on a TCP socket to all addresses |
||||
; (IPv6 and IPv4-mapped) on a specific port; |
||||
; '/path/to/unix/socket' - to listen on a unix socket. |
||||
; Note: This value is mandatory. |
||||
listen = /run/php-fpm/www.sock |
||||
|
||||
; Set listen(2) backlog. |
||||
; Default Value: 511 |
||||
;listen.backlog = 511 |
||||
|
||||
; Set permissions for unix socket, if one is used. In Linux, read/write |
||||
; permissions must be set in order to allow connections from a web server. |
||||
; Default Values: user and group are set as the running user |
||||
; mode is set to 0660 |
||||
;listen.owner = nobody |
||||
;listen.group = nobody |
||||
;listen.mode = 0660 |
||||
|
||||
; When POSIX Access Control Lists are supported you can set them using |
||||
; these options, value is a comma separated list of user/group names. |
||||
; When set, listen.owner and listen.group are ignored |
||||
listen.acl_users = apache,nginx |
||||
;listen.acl_groups = |
||||
|
||||
; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect. |
||||
; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original |
||||
; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address |
||||
; must be separated by a comma. If this value is left blank, connections will be |
||||
; accepted from any ip address. |
||||
; Default Value: any |
||||
listen.allowed_clients = 127.0.0.1 |
||||
|
||||
; Specify the nice(2) priority to apply to the pool processes (only if set) |
||||
; The value can vary from -19 (highest priority) to 20 (lower priority) |
||||
; Note: - It will only work if the FPM master process is launched as root |
||||
; - The pool processes will inherit the master process priority |
||||
; unless it specified otherwise |
||||
; Default Value: no set |
||||
; process.priority = -19 |
||||
|
||||
; Set the process dumpable flag (PR_SET_DUMPABLE prctl) even if the process user |
||||
; or group is differrent than the master process user. It allows to create process |
||||
; core dump and ptrace the process for the pool user. |
||||
; Default Value: no |
||||
; process.dumpable = yes |
||||
|
||||
; Choose how the process manager will control the number of child processes. |
||||
; Possible Values: |
||||
; static - a fixed number (pm.max_children) of child processes; |
||||
; dynamic - the number of child processes are set dynamically based on the |
||||
; following directives. With this process management, there will be |
||||
; always at least 1 children. |
||||
; pm.max_children - the maximum number of children that can |
||||
; be alive at the same time. |
||||
; pm.start_servers - the number of children created on startup. |
||||
; pm.min_spare_servers - the minimum number of children in 'idle' |
||||
; state (waiting to process). If the number |
||||
; of 'idle' processes is less than this |
||||
; number then some children will be created. |
||||
; pm.max_spare_servers - the maximum number of children in 'idle' |
||||
; state (waiting to process). If the number |
||||
; of 'idle' processes is greater than this |
||||
; number then some children will be killed. |
||||
; ondemand - no children are created at startup. Children will be forked when |
||||
; new requests will connect. The following parameter are used: |
||||
; pm.max_children - the maximum number of children that |
||||
; can be alive at the same time. |
||||
; pm.process_idle_timeout - The number of seconds after which |
||||
; an idle process will be killed. |
||||
; Note: This value is mandatory. |
||||
pm = dynamic |
||||
|
||||
; The number of child processes to be created when pm is set to 'static' and the |
||||
; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. |
||||
; This value sets the limit on the number of simultaneous requests that will be |
||||
; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. |
||||
; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP |
||||
; CGI. The below defaults are based on a server without much resources. Don't |
||||
; forget to tweak pm.* to fit your needs. |
||||
; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' |
||||
; Note: This value is mandatory. |
||||
pm.max_children = 50 |
||||
|
||||
; The number of child processes created on startup. |
||||
; Note: Used only when pm is set to 'dynamic' |
||||
; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 |
||||
pm.start_servers = 5 |
||||
|
||||
; The desired minimum number of idle server processes. |
||||
; Note: Used only when pm is set to 'dynamic' |
||||
; Note: Mandatory when pm is set to 'dynamic' |
||||
pm.min_spare_servers = 5 |
||||
|
||||
; The desired maximum number of idle server processes. |
||||
; Note: Used only when pm is set to 'dynamic' |
||||
; Note: Mandatory when pm is set to 'dynamic' |
||||
pm.max_spare_servers = 35 |
||||
|
||||
; The number of seconds after which an idle process will be killed. |
||||
; Note: Used only when pm is set to 'ondemand' |
||||
; Default Value: 10s |
||||
;pm.process_idle_timeout = 10s; |
||||
|
||||
; The number of requests each child process should execute before respawning. |
||||
; This can be useful to work around memory leaks in 3rd party libraries. For |
||||
; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. |
||||
; Default Value: 0 |
||||
;pm.max_requests = 500 |
||||
|
||||
; The URI to view the FPM status page. If this value is not set, no URI will be |
||||
; recognized as a status page. It shows the following informations: |
||||
; pool - the name of the pool; |
||||
; process manager - static, dynamic or ondemand; |
||||
; start time - the date and time FPM has started; |
||||
; start since - number of seconds since FPM has started; |
||||
; accepted conn - the number of request accepted by the pool; |
||||
; listen queue - the number of request in the queue of pending |
||||
; connections (see backlog in listen(2)); |
||||
; max listen queue - the maximum number of requests in the queue |
||||
; of pending connections since FPM has started; |
||||
; listen queue len - the size of the socket queue of pending connections; |
||||
; idle processes - the number of idle processes; |
||||
; active processes - the number of active processes; |
||||
; total processes - the number of idle + active processes; |
||||
; max active processes - the maximum number of active processes since FPM |
||||
; has started; |
||||
; max children reached - number of times, the process limit has been reached, |
||||
; when pm tries to start more children (works only for |
||||
; pm 'dynamic' and 'ondemand'); |
||||
; Value are updated in real time. |
||||
; Example output: |
||||
; pool: www |
||||
; process manager: static |
||||
; start time: 01/Jul/2011:17:53:49 +0200 |
||||
; start since: 62636 |
||||
; accepted conn: 190460 |
||||
; listen queue: 0 |
||||
; max listen queue: 1 |
||||
; listen queue len: 42 |
||||
; idle processes: 4 |
||||
; active processes: 11 |
||||
; total processes: 15 |
||||
; max active processes: 12 |
||||
; max children reached: 0 |
||||
; |
||||
; By default the status page output is formatted as text/plain. Passing either |
||||
; 'html', 'xml' or 'json' in the query string will return the corresponding |
||||
; output syntax. Example: |
||||
; http://www.foo.bar/status |
||||
; http://www.foo.bar/status?json |
||||
; http://www.foo.bar/status?html |
||||
; http://www.foo.bar/status?xml |
||||
; |
||||
; By default the status page only outputs short status. Passing 'full' in the |
||||
; query string will also return status for each pool process. |
||||
; Example: |
||||
; http://www.foo.bar/status?full |
||||
; http://www.foo.bar/status?json&full |
||||
; http://www.foo.bar/status?html&full |
||||
; http://www.foo.bar/status?xml&full |
||||
; The Full status returns for each process: |
||||
; pid - the PID of the process; |
||||
; state - the state of the process (Idle, Running, ...); |
||||
; start time - the date and time the process has started; |
||||
; start since - the number of seconds since the process has started; |
||||
; requests - the number of requests the process has served; |
||||
; request duration - the duration in µs of the requests; |
||||
; request method - the request method (GET, POST, ...); |
||||
; request URI - the request URI with the query string; |
||||
; content length - the content length of the request (only with POST); |
||||
; user - the user (PHP_AUTH_USER) (or '-' if not set); |
||||
; script - the main script called (or '-' if not set); |
||||
; last request cpu - the %cpu the last request consumed |
||||
; it's always 0 if the process is not in Idle state |
||||
; because CPU calculation is done when the request |
||||
; processing has terminated; |
||||
; last request memory - the max amount of memory the last request consumed |
||||
; it's always 0 if the process is not in Idle state |
||||
; because memory calculation is done when the request |
||||
; processing has terminated; |
||||
; If the process is in Idle state, then informations are related to the |
||||
; last request the process has served. Otherwise informations are related to |
||||
; the current request being served. |
||||
; Example output: |
||||
; ************************ |
||||
; pid: 31330 |
||||
; state: Running |
||||
; start time: 01/Jul/2011:17:53:49 +0200 |
||||
; start since: 63087 |
||||
; requests: 12808 |
||||
; request duration: 1250261 |
||||
; request method: GET |
||||
; request URI: /test_mem.php?N=10000 |
||||
; content length: 0 |
||||
; user: - |
||||
; script: /home/fat/web/docs/php/test_mem.php |
||||
; last request cpu: 0.00 |
||||
; last request memory: 0 |
||||
; |
||||
; Note: There is a real-time FPM status monitoring sample web page available |
||||
; It's available in: @EXPANDED_DATADIR@/fpm/status.html |
||||
; |
||||
; Note: The value must start with a leading slash (/). The value can be |
||||
; anything, but it may not be a good idea to use the .php extension or it |
||||
; may conflict with a real PHP file. |
||||
; Default Value: not set |
||||
;pm.status_path = /status |
||||
|
||||
; The ping URI to call the monitoring page of FPM. If this value is not set, no |
||||
; URI will be recognized as a ping page. This could be used to test from outside |
||||
; that FPM is alive and responding, or to |
||||
; - create a graph of FPM availability (rrd or such); |
||||
; - remove a server from a group if it is not responding (load balancing); |
||||
; - trigger alerts for the operating team (24/7). |
||||
; Note: The value must start with a leading slash (/). The value can be |
||||
; anything, but it may not be a good idea to use the .php extension or it |
||||
; may conflict with a real PHP file. |
||||
; Default Value: not set |
||||
;ping.path = /ping |
||||
|
||||
; This directive may be used to customize the response of a ping request. The |
||||
; response is formatted as text/plain with a 200 response code. |
||||
; Default Value: pong |
||||
;ping.response = pong |
||||
|
||||
; The access log file |
||||
; Default: not set |
||||
;access.log = log/$pool.access.log |
||||
|
||||
; The access log format. |
||||
; The following syntax is allowed |
||||
; %%: the '%' character |
||||
; %C: %CPU used by the request |
||||
; it can accept the following format: |
||||
; - %{user}C for user CPU only |
||||
; - %{system}C for system CPU only |
||||
; - %{total}C for user + system CPU (default) |
||||
; %d: time taken to serve the request |
||||
; it can accept the following format: |
||||
; - %{seconds}d (default) |
||||
; - %{miliseconds}d |
||||
; - %{mili}d |
||||
; - %{microseconds}d |
||||
; - %{micro}d |
||||
; %e: an environment variable (same as $_ENV or $_SERVER) |
||||
; it must be associated with embraces to specify the name of the env |
||||
; variable. Some exemples: |
||||
; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e |
||||
; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e |
||||
; %f: script filename |
||||
; %l: content-length of the request (for POST request only) |
||||
; %m: request method |
||||
; %M: peak of memory allocated by PHP |
||||
; it can accept the following format: |
||||
; - %{bytes}M (default) |
||||
; - %{kilobytes}M |
||||
; - %{kilo}M |
||||
; - %{megabytes}M |
||||
; - %{mega}M |
||||
; %n: pool name |
||||
; %o: output header |
||||
; it must be associated with embraces to specify the name of the header: |
||||
; - %{Content-Type}o |
||||
; - %{X-Powered-By}o |
||||
; - %{Transfert-Encoding}o |
||||
; - .... |
||||
; %p: PID of the child that serviced the request |
||||
; %P: PID of the parent of the child that serviced the request |
||||
; %q: the query string |
||||
; %Q: the '?' character if query string exists |
||||
; %r: the request URI (without the query string, see %q and %Q) |
||||
; %R: remote IP address |
||||
; %s: status (response code) |
||||
; %t: server time the request was received |
||||
; it can accept a strftime(3) format: |
||||
; %d/%b/%Y:%H:%M:%S %z (default) |
||||
; The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag |
||||
; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t |
||||
; %T: time the log has been written (the request has finished) |
||||
; it can accept a strftime(3) format: |
||||
; %d/%b/%Y:%H:%M:%S %z (default) |
||||
; The strftime(3) format must be encapsuled in a %{<strftime_format>}t tag |
||||
; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t |
||||
; %u: remote user |
||||
; |
||||
; Default: "%R - %u %t \"%m %r\" %s" |
||||
;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%" |
||||
|
||||
; The log file for slow requests |
||||
; Default Value: not set |
||||
; Note: slowlog is mandatory if request_slowlog_timeout is set |
||||
slowlog = /var/log/php-fpm/www-slow.log |
||||
|
||||
; The timeout for serving a single request after which a PHP backtrace will be |
||||
; dumped to the 'slowlog' file. A value of '0s' means 'off'. |
||||
; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) |
||||
; Default Value: 0 |
||||
;request_slowlog_timeout = 0 |
||||
|
||||
; Depth of slow log stack trace. |
||||
; Default Value: 20 |
||||
;request_slowlog_trace_depth = 20 |
||||
|
||||
; The timeout for serving a single request after which the worker process will |
||||
; be killed. This option should be used when the 'max_execution_time' ini option |
||||
; does not stop script execution for some reason. A value of '0' means 'off'. |
||||
; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) |
||||
; Default Value: 0 |
||||
;request_terminate_timeout = 0 |
||||
|
||||
; Set open file descriptor rlimit. |
||||
; Default Value: system defined value |
||||
;rlimit_files = 1024 |
||||
|
||||
; Set max core size rlimit. |
||||
; Possible Values: 'unlimited' or an integer greater or equal to 0 |
||||
; Default Value: system defined value |
||||
;rlimit_core = 0 |
||||
|
||||
; Chroot to this directory at the start. This value must be defined as an |
||||
; absolute path. When this value is not set, chroot is not used. |
||||
; Note: you can prefix with '$prefix' to chroot to the pool prefix or one |
||||
; of its subdirectories. If the pool prefix is not set, the global prefix |
||||
; will be used instead. |
||||
; Note: chrooting is a great security feature and should be used whenever |
||||
; possible. However, all PHP paths will be relative to the chroot |
||||
; (error_log, sessions.save_path, ...). |
||||
; Default Value: not set |
||||
;chroot = |
||||
|
||||
; Chdir to this directory at the start. |
||||
; Note: relative path can be used. |
||||
; Default Value: current directory or / when chroot |
||||
;chdir = /var/www |
||||
|
||||
; Redirect worker stdout and stderr into main error log. If not set, stdout and |
||||
; stderr will be redirected to /dev/null according to FastCGI specs. |
||||
; Note: on highloaded environement, this can cause some delay in the page |
||||
; process time (several ms). |
||||
; Default Value: no |
||||
;catch_workers_output = yes |
||||
|
||||
; Clear environment in FPM workers |
||||
; Prevents arbitrary environment variables from reaching FPM worker processes |
||||
; by clearing the environment in workers before env vars specified in this |
||||
; pool configuration are added. |
||||
; Setting to "no" will make all environment variables available to PHP code |
||||
; via getenv(), $_ENV and $_SERVER. |
||||
; Default Value: yes |
||||
; clear_env = no |
||||
|
||||
; Limits the extensions of the main script FPM will allow to parse. This can |
||||
; prevent configuration mistakes on the web server side. You should only limit |
||||
; FPM to .php extensions to prevent malicious users to use other extensions to |
||||
; execute php code. |
||||
; Note: set an empty value to allow all extensions. |
||||
; Default Value: .php |
||||
;security.limit_extensions = .php .php3 .php4 .php5 .php7 |
||||
|
||||
; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from |
||||
; the current environment. |
||||
; Default Value: clean env |
||||
;env[HOSTNAME] = $HOSTNAME |
||||
;env[PATH] = /usr/local/bin:/usr/bin:/bin |
||||
;env[TMP] = /tmp |
||||
;env[TMPDIR] = /tmp |
||||
;env[TEMP] = /tmp |
||||
env[SENTRY_DSN] = "${SENTRY_DSN}" |
||||
env[OIDC_CLIENT_ID] = "${OIDC_CLIENT_ID}" |
||||
env[RABBITMQ_USERNAME] = "${RABBITMQ_USERNAME}" |
||||
env[RABBITMQ_PASSWORD] = "${RABBITMQ_PASSWORD}" |
||||
env[GEOSERVER_USERNAME] = "${GEOSERVER_USERNAME}" |
||||
env[GEOSERVER_PASSWORD] = "${GEOSERVER_PASSWORD}" |
||||
env[MINIO_ACCESS_KEY] = "${MINIO_ACCESS_KEY}" |
||||
env[MINIO_SECRET_KEY] = "${MINIO_SECRET_KEY}" |
||||
env[TELEGRAM_BOT_TOKEN] = "${TELEGRAM_BOT_TOKEN}" |
||||
env[SECURITY_JWUC] = "${SECURITY_JWUC}" |
||||
env[SECURITY_JWAC] = "${SECURITY_JWAC}" |
||||
env[MYSQL_JIXEL_USERNAME] = "${MYSQL_JIXEL_USERNAME}" |
||||
env[MYSQL_JIXEL_PASSWORD] = "${MYSQL_JIXEL_PASSWORD}" |
||||
env[MYSQL_GEO_JIXEL_USERNAME] = "${MYSQL_GEO_JIXEL_USERNAME}" |
||||
env[MYSQL_GEO_JIXEL_PASSWORD] = "${MYSQL_GEO_JIXEL_PASSWORD}" |
||||
|
||||
; Additional php.ini defines, specific to this pool of workers. These settings |
||||
; overwrite the values previously defined in the php.ini. The directives are the |
||||
; same as the PHP SAPI: |
||||
; php_value/php_flag - you can set classic ini defines which can |
||||
; be overwritten from PHP call 'ini_set'. |
||||
; php_admin_value/php_admin_flag - these directives won't be overwritten by |
||||
; PHP call 'ini_set' |
||||
; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no. |
||||
|
||||
; Defining 'extension' will load the corresponding shared extension from |
||||
; extension_dir. Defining 'disable_functions' or 'disable_classes' will not |
||||
; overwrite previously defined php.ini values, but will append the new value |
||||
; instead. |
||||
|
||||
; Note: path INI options can be relative and will be expanded with the prefix |
||||
; (pool, global or @prefix@) |
||||
|
||||
; Default Value: nothing is defined by default except the values in php.ini and |
||||
; specified at startup with the -d argument |
||||
;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com |
||||
;php_flag[display_errors] = off |
||||
php_admin_value[error_log] = /var/log/php-fpm/www-error.log |
||||
php_admin_flag[log_errors] = on |
||||
;php_admin_value[memory_limit] = 128M |
||||
|
||||
; Set the following data paths to directories owned by the FPM process user. |
||||
; |
||||
; Do not change the ownership of existing system directories, if the process |
||||
; user does not have write permission, create dedicated directories for this |
||||
; purpose. |
||||
; |
||||
; See warning about choosing the location of these directories on your system |
||||
; at http://php.net/session.save-path |
||||
php_value[session.save_handler] = files |
||||
php_value[session.save_path] = /var/lib/php/session |
||||
php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache |
||||
;php_value[opcache.file_cache] = /var/lib/php/opcache |
||||
@ -0,0 +1,16 @@
|
||||
<?php |
||||
/** |
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* |
||||
* Licensed under The MIT License |
||||
* For full copyright and license information, please see the LICENSE.txt |
||||
* Redistributions of files must retain the above copyright notice. |
||||
* |
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* @link https://cakephp.org CakePHP(tm) Project |
||||
* @since 0.10.0 |
||||
* @license https://opensource.org/licenses/mit-license.php MIT License |
||||
*/ |
||||
|
||||
require 'webroot' . DIRECTORY_SEPARATOR . 'index.php'; |
||||
@ -0,0 +1,39 @@
|
||||
ARG version |
||||
ARG branch=master |
||||
|
||||
FROM registrywgs.webgenesis.it/webgenesys/jixel/idrocapjixel:$version-$branch |
||||
ENV LANG en_US.UTF-8 |
||||
ENV LANGUAGE en_US:en |
||||
ENV LC_ALL en_US.UTF-8 |
||||
RUN echo $branch |
||||
RUN echo $version |
||||
|
||||
RUN mkdir /usr/local/ies-solutions |
||||
|
||||
RUN mkdir /usr/local/ies-solutions/jixel-cron/ |
||||
COPY ./jixel-cron.* /usr/local/ies-solutions/jixel-cron/ |
||||
|
||||
RUN mkdir /usr/local/ies-solutions/jixel-background-task-handler/ |
||||
COPY ./jbth.* /usr/local/ies-solutions/jixel-background-task-handler/ |
||||
|
||||
RUN mkdir /usr/local/ies-solutions/jixel-general-purpose-rabbit-consumer/ |
||||
COPY ./jgprc.* /usr/local/ies-solutions/jixel-general-purpose-rabbit-consumer/ |
||||
|
||||
WORKDIR /usr/local/ies-solutions/jixel-background-task-handler |
||||
|
||||
RUN dnf -y install python3-pip python3-devel python3-pycurl |
||||
RUN dnf -y install crontabs cronie cronie-anacron |
||||
|
||||
RUN pip3 install pika |
||||
RUN pip3 install rasterio |
||||
RUN pip3 install redis |
||||
|
||||
COPY ./jixel-background-task-handler.sh /usr/local/bin/jixel-background-task-handler |
||||
COPY ./jixel-cron.sh /usr/local/bin/jixel-cron |
||||
COPY ./jixel-general-purpose-rabbit-consumer.sh /usr/local/bin/jixel-general-purpose-rabbit-consumer |
||||
|
||||
RUN chmod 500 /usr/local/bin/jixel-background-task-handler |
||||
RUN chmod 500 /usr/local/bin/jixel-cron |
||||
RUN chmod 500 /usr/local/bin/jixel-general-purpose-rabbit-consumer |
||||
|
||||
CMD ["jixel-background-task-handler"] |
||||
@ -0,0 +1,152 @@
|
||||
import logging |
||||
import time |
||||
import json |
||||
import pika |
||||
import subprocess |
||||
import sys |
||||
import threading |
||||
import os |
||||
from distutils.util import strtobool |
||||
|
||||
class JixelBackgroundTaskHandler(): |
||||
|
||||
def __init__( |
||||
self, rabbitmq_username, rabbitmq_password, |
||||
rabbitmq_host, rabbitmq_port, rabbitmq_queue, |
||||
rabbitmq_heartbeat, execution_path, logger, |
||||
discarding_mode=False |
||||
): |
||||
self.rabbitmq_username = rabbitmq_username |
||||
self.rabbitmq_password = rabbitmq_password |
||||
self.rabbitmq_host = rabbitmq_host |
||||
self.rabbitmq_port = rabbitmq_port |
||||
self.rabbitmq_queue = rabbitmq_queue |
||||
self.rabbitmq_heartbeat = int(rabbitmq_heartbeat) |
||||
self.execution_path = execution_path |
||||
self.logger = logger |
||||
self.discarding_mode = strtobool(discarding_mode) |
||||
self.logger.info("JixelBackgroundTaskHandler - Initialization...") |
||||
self.credentials = pika.PlainCredentials( |
||||
self.rabbitmq_username , |
||||
self.rabbitmq_password |
||||
) |
||||
self.connection = pika.BlockingConnection( |
||||
pika.ConnectionParameters( |
||||
host=self.rabbitmq_host, |
||||
port=int(self.rabbitmq_port), |
||||
credentials=self.credentials,heartbeat=self.rabbitmq_heartbeat |
||||
) |
||||
) |
||||
self.channel = self.connection.channel() |
||||
self.logger.info("JixelBackgroundTaskHandler - Initialization completed successfully") |
||||
self.channel.queue_declare(queue=self.rabbitmq_queue, durable=True) |
||||
self.logger.info("JixelBackgroundTaskHandler - " + self.rabbitmq_queue + " queue declared") |
||||
self.channel.queue_declare(queue=self.rabbitmq_queue+'_errors', durable=True) |
||||
self.logger.info("JixelBackgroundTaskHandler - " + self.rabbitmq_queue + "_errors queue declared") |
||||
self.channel.basic_qos(prefetch_count=1) |
||||
self.logger.info("JixelBackgroundTaskHandler - Queue handler declared") |
||||
self.channel.basic_consume( |
||||
on_message_callback=self.__data_handler, |
||||
queue=self.rabbitmq_queue |
||||
) |
||||
|
||||
def consume(self): |
||||
|
||||
try: |
||||
self.channel.start_consuming() |
||||
except KeyboardInterrupt: |
||||
self.channel.stop_consuming() |
||||
|
||||
self.channel.close() |
||||
|
||||
def __execute_command(self, mr): |
||||
self.logger.info('JixelBackgroundTaskHandler - Processing thread is running:') |
||||
command = [self.execution_path + 'cake'] |
||||
command += mr['command'].split(' ') |
||||
command += [mr['data']] |
||||
self.logger.info('JixelBackgroundTaskHandler - Executing shell command:') |
||||
self.logger.info(command) |
||||
|
||||
try: |
||||
subprocess.check_call(command) |
||||
self.result = True |
||||
except subprocess.CalledProcessError as error: |
||||
self.logger.error('JixelBackgroundTaskHandler - An error as occured during processing:') |
||||
self.logger.error(error) |
||||
self.result = False |
||||
|
||||
def __data_processing(self, channel, mr): |
||||
self.logger.info(mr) |
||||
self.logger.info('JixelBackgroundTaskHandler - Starting processing thread:') |
||||
self.result = None |
||||
thread = threading.Thread(target=self.__execute_command, args=(mr,)) |
||||
thread.start() |
||||
|
||||
while thread.is_alive(): |
||||
self.connection.process_data_events() |
||||
|
||||
self.logger.info("JixelBackgroundTaskHandler - Result received:") |
||||
self.logger.info(self.result) |
||||
if (self.result is not True): |
||||
self.__send_error(json.dumps(mr)) |
||||
return self.result |
||||
|
||||
def __send_ack_nack(self, ack, channel, method): |
||||
if ack is True: |
||||
self.logger.info("JixelBackgroundTaskHandler - Ack performed") |
||||
channel.basic_ack(delivery_tag=method.delivery_tag) |
||||
else: |
||||
self.logger.info("JixelBackgroundTaskHandler - Nack performed BECAUSE ERRORS OCCURRED!") |
||||
channel.basic_reject(delivery_tag=method.delivery_tag) |
||||
|
||||
def __data_handler(self, channel, method, properties, body): |
||||
self.logger.info('JixelBackgroundTaskHandler - New message received:') |
||||
error = False |
||||
|
||||
try: |
||||
mr = json.loads(body.decode()) |
||||
error = not self.__data_processing(channel, mr) |
||||
except json.JSONDecodeError as error: |
||||
self.logger.error("JixelBackgroundTaskHandler - Malformed message") |
||||
self.logger.error(error) |
||||
self.logger.error("JixelBackgroundTaskHandler - This message will be removed from the queue") |
||||
self.__send_ack_nack(False, channel, method) |
||||
time.sleep(60) |
||||
return |
||||
|
||||
if self.result is True and error is False: |
||||
self.__send_ack_nack(True, channel, method) |
||||
else: |
||||
self.logger.error("JixelBackgroundTaskHandler - An error has occured during processing") |
||||
if self.discarding_mode is True: |
||||
self.logger.error("JixelBackgroundTaskHandler - Discarding mode enabled.") |
||||
self.__send_ack_nack(True, channel, method) |
||||
else: |
||||
self.__send_ack_nack(False, channel, method) |
||||
|
||||
time.sleep(5) |
||||
|
||||
self.logger.info("JixelBackgroundTaskHandler - Data handling complete. Waiting for new messages") |
||||
|
||||
def __send_error(self, message): |
||||
self.channel.basic_publish(exchange='', routing_key=self.rabbitmq_queue+'_errors', body=message) |
||||
|
||||
if __name__ == '__main__': |
||||
logger = logging.getLogger("JixelBackgroundTaskHandler") |
||||
logger.setLevel(logging.INFO) |
||||
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") |
||||
terminal_log = logging.StreamHandler(sys.stdout) |
||||
terminal_log.setFormatter(formatter) |
||||
logger.addHandler(terminal_log) |
||||
app = JixelBackgroundTaskHandler( |
||||
os.environ['RABBITMQ_USERNAME'], |
||||
os.environ['RABBITMQ_PASSWORD'], |
||||
os.environ['rabbitmq_host'], |
||||
os.environ['rabbitmq_port'], |
||||
os.environ['rabbitmq_queue'], |
||||
os.environ['rabbitmq_heartbeat'], |
||||
os.environ['execution_path'], |
||||
logger, |
||||
os.environ['discarding_mode'] |
||||
) |
||||
app.consume() |
||||
@ -0,0 +1,9 @@
|
||||
export rabbitmq_username='jixel' |
||||
export rabbitmq_password='jixel' |
||||
export rabbitmq_host='rabbitmq' |
||||
export rabbitmq_queue='background_tasks' |
||||
export rabbitmq_port='5672' |
||||
export execution_path='/var/www/gecos/bin/' |
||||
export rabbitmq_heartbeat=60 |
||||
export discarding_mode='False' |
||||
python3 ./jbth.py |
||||
@ -0,0 +1,169 @@
|
||||
import logging |
||||
import logging.handlers |
||||
import time |
||||
import json |
||||
import pika |
||||
import subprocess |
||||
import sys |
||||
import threading |
||||
import os |
||||
from distutils.util import strtobool |
||||
import shlex |
||||
|
||||
class JixelGeneralPurposeRabbitConsumer(): |
||||
|
||||
def __init__( |
||||
self, rabbitmq_username, rabbitmq_password, |
||||
rabbitmq_host, rabbitmq_vhost, rabbitmq_port, rabbitmq_queue, |
||||
rabbitmq_heartbeat, execution_path, execution_command, logger, |
||||
discarding_mode=False |
||||
): |
||||
self.rabbitmq_username = rabbitmq_username |
||||
self.rabbitmq_password = rabbitmq_password |
||||
self.rabbitmq_host = rabbitmq_host |
||||
self.rabbitmq_vhost = rabbitmq_vhost |
||||
self.rabbitmq_port = rabbitmq_port |
||||
self.rabbitmq_queue = rabbitmq_queue |
||||
self.rabbitmq_heartbeat = int(rabbitmq_heartbeat) |
||||
self.execution_path = execution_path |
||||
self.execution_command = execution_command |
||||
self.logger = logger |
||||
self.discarding_mode = strtobool(discarding_mode) |
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Initialization...") |
||||
self.credentials = pika.PlainCredentials( |
||||
self.rabbitmq_username , |
||||
self.rabbitmq_password |
||||
) |
||||
self.connection = pika.BlockingConnection( |
||||
pika.ConnectionParameters( |
||||
host=self.rabbitmq_host, |
||||
virtual_host=self.rabbitmq_vhost, |
||||
port=int(self.rabbitmq_port), |
||||
credentials=self.credentials,heartbeat=self.rabbitmq_heartbeat |
||||
) |
||||
) |
||||
self.channel = self.connection.channel() |
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Initialization completed successfully") |
||||
self.channel.queue_declare(queue=self.rabbitmq_queue, durable=True) |
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - " + self.rabbitmq_queue + " queue declared") |
||||
self.channel.queue_declare(queue=self.rabbitmq_queue+'_errors', durable=True) |
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - " + self.rabbitmq_queue + "_errors queue declared") |
||||
self.channel.basic_qos(prefetch_count=1) |
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Queue handler declared") |
||||
self.channel.basic_consume( |
||||
on_message_callback=self.__data_handler, |
||||
queue=self.rabbitmq_queue |
||||
) |
||||
|
||||
def consume(self): |
||||
|
||||
try: |
||||
self.channel.start_consuming() |
||||
except KeyboardInterrupt: |
||||
self.channel.stop_consuming() |
||||
|
||||
self.channel.close() |
||||
|
||||
def __execute_command(self, mr): |
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + ' - Processing thread is running:') |
||||
string_command = "{}cake {} '{}'".format(self.execution_path, self.execution_command, json.dumps(mr)) |
||||
command = shlex.split(string_command) |
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + ' - Executing shell command:') |
||||
self.logger.info(command) |
||||
|
||||
try: |
||||
completed_process = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
||||
if completed_process.stderr: |
||||
self.logger.error(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ':\n{}'.format(completed_process.stderr.decode('utf-8'))) |
||||
if completed_process.stdout: |
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ':\n{}'.format(completed_process.stdout.decode('utf-8'))) |
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ' - RETURN CODE: {}'.format(completed_process.returncode)) |
||||
completed_process.check_returncode() |
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ': Shell command successfully executed!') |
||||
self.result = True |
||||
except FileNotFoundError as error: |
||||
self.logger.exception(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ' - A FileNotFoundError error has occured during shell command execution:', stack_info=False, exc_info=False) |
||||
self.logger.exception(error, stack_info=False, exc_info=False) |
||||
return False |
||||
except subprocess.CalledProcessError as error: |
||||
self.logger.exception(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ' - A CalledProcessError has occured during processing:', stack_info=False, exc_info=False) |
||||
self.logger.exception(error, stack_info=False, exc_info=False) |
||||
self.result = False |
||||
|
||||
def __data_processing(self, channel, mr): |
||||
self.logger.info(mr) |
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + ' - Starting processing thread:') |
||||
self.result = None |
||||
thread = threading.Thread(target=self.__execute_command, args=(mr,)) |
||||
thread.start() |
||||
|
||||
while thread.is_alive(): |
||||
self.connection.process_data_events() |
||||
|
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Result received:") |
||||
self.logger.info(self.result) |
||||
if (self.result is not True): |
||||
self.__send_error(json.dumps(mr)) |
||||
return self.result |
||||
|
||||
def __send_ack_nack(self, ack, channel, method): |
||||
channel.basic_ack(delivery_tag=method.delivery_tag) |
||||
if ack is True: |
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Ack performed") |
||||
else: |
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Ack performed BUT ERRORS OCCURRED!") |
||||
|
||||
def __data_handler(self, channel, method, properties, body): |
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + ' - New message received:') |
||||
error = False |
||||
|
||||
try: |
||||
mr = json.loads(body.decode()) |
||||
error = not self.__data_processing(channel, mr) |
||||
except json.JSONDecodeError as error: |
||||
self.logger.exception(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Malformed message", stack_info=False, exc_info=False) |
||||
self.logger.exception(error, stack_info=False, exc_info=False) |
||||
self.logger.exception(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - This message will be removed from the queue", stack_info=False, exc_info=False) |
||||
self.__send_ack_nack(False, channel, method) |
||||
time.sleep(60) |
||||
return |
||||
|
||||
if self.result is True and error is False: |
||||
self.__send_ack_nack(True, channel, method) |
||||
else: |
||||
self.logger.error(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - An error has occured during processing") |
||||
if self.discarding_mode is True: |
||||
self.logger.error(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Discarding mode enabled.") |
||||
self.__send_ack_nack(True, channel, method) |
||||
else: |
||||
self.__send_ack_nack(False, channel, method) |
||||
|
||||
time.sleep(5) |
||||
|
||||
self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Data handling complete. Waiting for new messages") |
||||
|
||||
def __send_error(self, message): |
||||
self.channel.basic_publish(exchange='', routing_key=self.rabbitmq_queue+'_errors', body=message) |
||||
|
||||
if __name__ == '__main__': |
||||
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") |
||||
handler = logging.handlers.TimedRotatingFileHandler("{}{}".format(os.environ['logging_file_path'], os.environ['logging_name']), when=os.environ['logging_file_rotate_when'], interval=int(os.environ['logging_file_rotate_interval']), backupCount=int(os.environ['logging_file_backup_count'])) |
||||
handler.setFormatter(formatter) |
||||
logger = logging.getLogger(os.environ['logging_name']) |
||||
logger.addHandler(handler) |
||||
logger.setLevel(logging.DEBUG) |
||||
|
||||
app = JixelGeneralPurposeRabbitConsumer( |
||||
os.environ['RABBITMQ_USERNAME'], |
||||
os.environ['RABBITMQ_PASSWORD'], |
||||
os.environ['rabbitmq_host'], |
||||
os.environ['rabbitmq_vhost'], |
||||
os.environ['rabbitmq_port'], |
||||
os.environ['rabbitmq_queue'], |
||||
os.environ['rabbitmq_heartbeat'], |
||||
os.environ['execution_path'], |
||||
os.environ['execution_command'], |
||||
logger, |
||||
os.environ['discarding_mode'] |
||||
) |
||||
app.consume() |
||||
@ -0,0 +1,26 @@
|
||||
export rabbitmq_username='jixel' |
||||
export rabbitmq_password='jixel' |
||||
export rabbitmq_host='rabbitmq' |
||||
export rabbitmq_vhost='gp' |
||||
export rabbitmq_queue='gp' |
||||
export rabbitmq_port='5672' |
||||
export execution_path='/var/www/jixel/bin/' |
||||
export execution_command='gp' |
||||
export rabbitmq_heartbeat=60 |
||||
export discarding_mode='False' |
||||
|
||||
# Log file rotation policy: |
||||
# Current 'when' events supported: |
||||
# 'S' - Seconds |
||||
# 'M' - Minutes |
||||
# 'H' - Hours |
||||
# 'D' - Days |
||||
# 'midnight' - roll over at midnight |
||||
# 'W{0-6}' - roll over on a certain day; W0 - Monday, W1 - Tuesday, etc |
||||
export logging_file_rotate_when='H' |
||||
export logging_file_rotate_interval=24 |
||||
export logging_name='JixelGeneralPurposeRabbitConsumer' |
||||
export logging_file_path='/general_purpose_rabbit_consumer/logs/' |
||||
export logging_file_backup_count=30 |
||||
|
||||
python3 ./jgprc.py |
||||
@ -0,0 +1,12 @@
|
||||
#!/bin/bash |
||||
if [ -f /run/secrets/rabbitmq_username ]; then |
||||
export RABBITMQ_USERNAME=$(cat /run/secrets/rabbitmq_username) |
||||
else |
||||
echo "Secret file 'rabbitmq_username' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/rabbitmq_password ]; then |
||||
export RABBITMQ_PASSWORD=$(cat /run/secrets/rabbitmq_password) |
||||
else |
||||
echo "Secret file 'rabbitmq_password' not found!" >&2 |
||||
fi |
||||
/usr/bin/python3 /usr/local/ies-solutions/jixel-background-task-handler/jbth.py |
||||
@ -0,0 +1,5 @@
|
||||
#!/bin/bash |
||||
crond |
||||
crontab /usr/local/ies-solutions/jixel-cron/jixel-cron.txt |
||||
tail -f /usr/local/ies-solutions/jixel-cron/jixel-cron.txt |
||||
|
||||
@ -0,0 +1,6 @@
|
||||
# always put 3 rows: service called, date and the actual service called output: |
||||
* * * * * echo "/var/www/jixel/bin/cake" >> /usr/local/ies-solutions/jixel-cron/jixel-cron.log |
||||
* * * * * date >> /usr/local/ies-solutions/jixel-cron/jixel-cron.log |
||||
* * * * * /var/www/jixel/bin/cake >> /usr/local/ies-solutions/jixel-cron/jixel-cron.log |
||||
0 0 * * 0 rm -f /usr/local/ies-solutions/jixel-cron/jixel-cron.log |
||||
# keep this line empty! |
||||
@ -0,0 +1,12 @@
|
||||
#!/bin/bash |
||||
if [ -f /run/secrets/rabbitmq_username ]; then |
||||
export RABBITMQ_USERNAME=$(cat /run/secrets/rabbitmq_username) |
||||
else |
||||
echo "Secret file 'rabbitmq_username' not found!" >&2 |
||||
fi |
||||
if [ -f /run/secrets/rabbitmq_password ]; then |
||||
export RABBITMQ_PASSWORD=$(cat /run/secrets/rabbitmq_password) |
||||
else |
||||
echo "Secret file 'rabbitmq_password' not found!" >&2 |
||||
fi |
||||
/usr/bin/python3 /usr/local/ies-solutions/jixel-general-purpose-rabbit-consumer/jgprc.py |
||||
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0"?> |
||||
<ruleset name="App"> |
||||
<config name="installed_paths" value="../../cakephp/cakephp-codesniffer"/> |
||||
|
||||
<rule ref="CakePHP"/> |
||||
<rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingNativeTypeHint"> |
||||
<exclude-pattern>*/src/Controller/*</exclude-pattern> |
||||
</rule> |
||||
|
||||
<file>src/</file> |
||||
<file>tests/</file> |
||||
</ruleset> |
||||
@ -0,0 +1,6 @@
|
||||
parameters: |
||||
level: 8 |
||||
treatPhpDocTypesAsCertain: false |
||||
checkGenericClassInNonGenericObjectType: false |
||||
paths: |
||||
- src/ |
||||
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
colors="true" |
||||
processIsolation="false" |
||||
stopOnFailure="false" |
||||
bootstrap="tests/bootstrap.php" |
||||
cacheDirectory=".phpunit.cache" |
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.1/phpunit.xsd"> |
||||
<php> |
||||
<ini name="memory_limit" value="-1"/> |
||||
<ini name="apc.enable_cli" value="1"/> |
||||
</php> |
||||
|
||||
<!-- Add any additional test suites you want to run here --> |
||||
<testsuites> |
||||
<testsuite name="app"> |
||||
<directory>tests/TestCase/</directory> |
||||
</testsuite> |
||||
<!-- Add plugin test suites here. --> |
||||
</testsuites> |
||||
|
||||
<!-- Load extension for fixtures --> |
||||
<extensions> |
||||
<bootstrap class="Cake\TestSuite\Fixture\Extension\PHPUnitExtension"/> |
||||
</extensions> |
||||
|
||||
<!-- Ignore vendor tests in code coverage reports --> |
||||
<source> |
||||
<include> |
||||
<directory suffix=".php">src/</directory> |
||||
<directory suffix=".php">plugins/*/src/</directory> |
||||
</include> |
||||
<exclude> |
||||
<file>src/Console/Installer.php</file> |
||||
</exclude> |
||||
</source> |
||||
</phpunit> |
||||
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0"?> |
||||
<psalm |
||||
errorLevel="2" |
||||
resolveFromConfigFile="true" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xmlns="https://getpsalm.org/schema/config" |
||||
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" |
||||
> |
||||
<projectFiles> |
||||
<directory name="src" /> |
||||
<ignoreFiles> |
||||
<directory name="vendor" /> |
||||
</ignoreFiles> |
||||
</projectFiles> |
||||
</psalm> |
||||
@ -0,0 +1,279 @@
|
||||
# LANGUAGE translation of CakePHP Application |
||||
# Copyright YEAR NAME <EMAIL@ADDRESS> |
||||
# |
||||
#, fuzzy |
||||
msgid "" |
||||
msgstr "" |
||||
"Project-Id-Version: CakePHP 4.4.5\n" |
||||
"POT-Creation-Date: 2023-02-28 09:27+0000\n" |
||||
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" |
||||
"Last-Translator: NAME <EMAIL@ADDRESS>\n" |
||||
"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n" |
||||
"MIME-Version: 1.0\n" |
||||
"Content-Type: text/plain; charset=utf-8\n" |
||||
"Content-Transfer-Encoding: 8bit\n" |
||||
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" |
||||
|
||||
#: ./templates/Error/error400.php:39 |
||||
#: ./templates/Error/error500.php:43 |
||||
msgid "Error" |
||||
msgstr "" |
||||
|
||||
#: ./templates/Error/error400.php:40 |
||||
msgid "The requested address {0} was not found on this server." |
||||
msgstr "" |
||||
|
||||
#: ./templates/Error/error500.php:41 |
||||
#: ./vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php:361 |
||||
msgid "An Internal Error Has Occurred." |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Controller/Component/AuthComponent.php:462 |
||||
msgid "You are not authorized to access that location." |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php:359 |
||||
msgid "Not Found" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:390 |
||||
msgid "Missing or incorrect CSRF cookie type." |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:394 |
||||
msgid "Missing or invalid CSRF cookie." |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:417 |
||||
#: ./vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php:265 |
||||
msgid "CSRF token from either the request body or request headers did not match or is missing." |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php:247 |
||||
msgid "Missing or incorrect CSRF session key" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Http/Response.php:1489 |
||||
msgid "The requested file contains `..` and will not be read." |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Http/Response.php:1497 |
||||
msgid "The requested file was not found" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/Number.php:116 |
||||
msgid "{0,number,#,###.##} KB" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/Number.php:118 |
||||
msgid "{0,number,#,###.##} MB" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/Number.php:120 |
||||
msgid "{0,number,#,###.##} GB" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/Number.php:122 |
||||
msgid "{0,number,#,###.##} TB" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/Number.php:114 |
||||
msgid "{0,number,integer} Byte" |
||||
msgid_plural "{0,number,integer} Bytes" |
||||
msgstr[0] "" |
||||
msgstr[1] "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:86 |
||||
msgid "{0} from now" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:86 |
||||
msgid "{0} ago" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:89 |
||||
msgid "{0} after" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:89 |
||||
msgid "{0} before" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:120 |
||||
msgid "just now" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:157 |
||||
msgid "about a second ago" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:158 |
||||
msgid "about a minute ago" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:159 |
||||
msgid "about an hour ago" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:160 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:370 |
||||
msgid "about a day ago" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:161 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:371 |
||||
msgid "about a week ago" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:162 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:372 |
||||
msgid "about a month ago" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:163 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:373 |
||||
msgid "about a year ago" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:174 |
||||
msgid "in about a second" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:175 |
||||
msgid "in about a minute" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:176 |
||||
msgid "in about an hour" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:177 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:384 |
||||
msgid "in about a day" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:178 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:385 |
||||
msgid "in about a week" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:179 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:386 |
||||
msgid "in about a month" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:180 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:387 |
||||
msgid "in about a year" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:342 |
||||
msgid "today" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:409 |
||||
msgid "%s ago" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:410 |
||||
msgid "on %s" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:53 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:132 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:354 |
||||
msgid "{0} year" |
||||
msgid_plural "{0} years" |
||||
msgstr[0] "" |
||||
msgstr[1] "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:57 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:135 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:357 |
||||
msgid "{0} month" |
||||
msgid_plural "{0} months" |
||||
msgstr[0] "" |
||||
msgstr[1] "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:63 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:138 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:360 |
||||
msgid "{0} week" |
||||
msgid_plural "{0} weeks" |
||||
msgstr[0] "" |
||||
msgstr[1] "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:65 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:141 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:363 |
||||
msgid "{0} day" |
||||
msgid_plural "{0} days" |
||||
msgstr[0] "" |
||||
msgstr[1] "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:70 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:144 |
||||
msgid "{0} hour" |
||||
msgid_plural "{0} hours" |
||||
msgstr[0] "" |
||||
msgstr[1] "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:74 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:147 |
||||
msgid "{0} minute" |
||||
msgid_plural "{0} minutes" |
||||
msgstr[0] "" |
||||
msgstr[1] "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:78 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:150 |
||||
msgid "{0} second" |
||||
msgid_plural "{0} seconds" |
||||
msgstr[0] "" |
||||
msgstr[1] "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:63 |
||||
msgid "This value is already in use" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:110 |
||||
msgid "This value does not exist" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:232 |
||||
msgid "Cannot modify row: a constraint for the `{0}` association fails." |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:270 |
||||
msgid "The count does not match {0}{1}" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Utility/Text.php:923 |
||||
msgid "and" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2539 |
||||
msgid "This field is required" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2559 |
||||
#: ./vendor/cakephp/cakephp/src/View/Form/ArrayContext.php:249 |
||||
msgid "This field cannot be left empty" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2711 |
||||
msgid "The provided value is invalid" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:979 |
||||
msgid "Edit {0}" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:981 |
||||
msgid "New {0}" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:1917 |
||||
msgid "Submit" |
||||
msgstr "" |
||||
|
||||
File diff soppresso perché troppo grande
Load Diff
File diff soppresso perché troppo grande
Load Diff
File diff soppresso perché troppo grande
Load Diff
@ -0,0 +1,279 @@
|
||||
# LANGUAGE translation of CakePHP Application |
||||
# Copyright YEAR NAME <EMAIL@ADDRESS> |
||||
# |
||||
#, fuzzy |
||||
msgid "" |
||||
msgstr "" |
||||
"Project-Id-Version: CakePHP 4.4.5\n" |
||||
"POT-Creation-Date: 2023-02-28 09:27+0000\n" |
||||
"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" |
||||
"Last-Translator: NAME <EMAIL@ADDRESS>\n" |
||||
"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n" |
||||
"MIME-Version: 1.0\n" |
||||
"Content-Type: text/plain; charset=utf-8\n" |
||||
"Content-Transfer-Encoding: 8bit\n" |
||||
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" |
||||
|
||||
#: ./templates/Error/error400.php:39 |
||||
#: ./templates/Error/error500.php:43 |
||||
msgid "Error" |
||||
msgstr "Errore" |
||||
|
||||
#: ./templates/Error/error400.php:40 |
||||
msgid "The requested address {0} was not found on this server." |
||||
msgstr "L'indirizzo richiesto {0} non è stato trovato su questo server." |
||||
|
||||
#: ./templates/Error/error500.php:41 |
||||
#: ./vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php:361 |
||||
msgid "An Internal Error Has Occurred." |
||||
msgstr "Errore interno." |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Controller/Component/AuthComponent.php:462 |
||||
msgid "You are not authorized to access that location." |
||||
msgstr "Non sei autorizzato ad accedere a quella risorsa." |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php:359 |
||||
msgid "Not Found" |
||||
msgstr "Non Trovato" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:390 |
||||
msgid "Missing or incorrect CSRF cookie type." |
||||
msgstr "tipo di CSRF cookie mancante o incorretto." |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:394 |
||||
msgid "Missing or invalid CSRF cookie." |
||||
msgstr "CSRF cookie mancante o incorretto." |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:417 |
||||
#: ./vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php:265 |
||||
msgid "CSRF token from either the request body or request headers did not match or is missing." |
||||
msgstr "Il CSRF token è mancante o quello presente nel body non corrisponde." |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php:247 |
||||
msgid "Missing or incorrect CSRF session key" |
||||
msgstr "Chiave di sessione CSRF incorretta o mancante" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Http/Response.php:1489 |
||||
msgid "The requested file contains `..` and will not be read." |
||||
msgstr "Il file richiesto contiene `..` e quindi non verrà letto." |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Http/Response.php:1497 |
||||
msgid "The requested file was not found" |
||||
msgstr "Il file richiesto non è stato trovato" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/Number.php:116 |
||||
msgid "{0,number,#,###.##} KB" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/Number.php:118 |
||||
msgid "{0,number,#,###.##} MB" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/Number.php:120 |
||||
msgid "{0,number,#,###.##} GB" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/Number.php:122 |
||||
msgid "{0,number,#,###.##} TB" |
||||
msgstr "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/Number.php:114 |
||||
msgid "{0,number,integer} Byte" |
||||
msgid_plural "{0,number,integer} Bytes" |
||||
msgstr[0] "" |
||||
msgstr[1] "" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:86 |
||||
msgid "{0} from now" |
||||
msgstr "{0} da adesso" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:86 |
||||
msgid "{0} ago" |
||||
msgstr "{0} fa" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:89 |
||||
msgid "{0} after" |
||||
msgstr "{0} dopo" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:89 |
||||
msgid "{0} before" |
||||
msgstr "{0} prima" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:120 |
||||
msgid "just now" |
||||
msgstr "in questo momento" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:157 |
||||
msgid "about a second ago" |
||||
msgstr "circa un secondo fa" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:158 |
||||
msgid "about a minute ago" |
||||
msgstr "circa un minuto fa" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:159 |
||||
msgid "about an hour ago" |
||||
msgstr "circa un'ora fa" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:160 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:370 |
||||
msgid "about a day ago" |
||||
msgstr "circa un giorno fa" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:161 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:371 |
||||
msgid "about a week ago" |
||||
msgstr "circa una settimana fa" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:162 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:372 |
||||
msgid "about a month ago" |
||||
msgstr "circa un mese fa" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:163 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:373 |
||||
msgid "about a year ago" |
||||
msgstr "circa un anno fa" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:174 |
||||
msgid "in about a second" |
||||
msgstr "fra circa un secondo" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:175 |
||||
msgid "in about a minute" |
||||
msgstr "fra circa un minuto" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:176 |
||||
msgid "in about an hour" |
||||
msgstr "fra circa un'ora" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:177 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:384 |
||||
msgid "in about a day" |
||||
msgstr "fra circa un giorno" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:178 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:385 |
||||
msgid "in about a week" |
||||
msgstr "tra circa una settimana" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:179 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:386 |
||||
msgid "in about a month" |
||||
msgstr "tra circa un mese" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:180 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:387 |
||||
msgid "in about a year" |
||||
msgstr "tra circa un anno" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:342 |
||||
msgid "today" |
||||
msgstr "oggi" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:409 |
||||
msgid "%s ago" |
||||
msgstr "%s fa" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:410 |
||||
msgid "on %s" |
||||
msgstr "%s" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:53 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:132 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:354 |
||||
msgid "{0} year" |
||||
msgid_plural "{0} years" |
||||
msgstr[0] "{0} anno" |
||||
msgstr[1] "{0} anni" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:57 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:135 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:357 |
||||
msgid "{0} month" |
||||
msgid_plural "{0} months" |
||||
msgstr[0] "{0} mese" |
||||
msgstr[1] "{0} mesi" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:63 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:138 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:360 |
||||
msgid "{0} week" |
||||
msgid_plural "{0} weeks" |
||||
msgstr[0] "{0} settimana" |
||||
msgstr[1] "{0} settimane" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:65 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:141 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:363 |
||||
msgid "{0} day" |
||||
msgid_plural "{0} days" |
||||
msgstr[0] "{0} giorno" |
||||
msgstr[1] "{0} giorni" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:70 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:144 |
||||
msgid "{0} hour" |
||||
msgid_plural "{0} hours" |
||||
msgstr[0] "{0} ora" |
||||
msgstr[1] "{0} ore" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:74 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:147 |
||||
msgid "{0} minute" |
||||
msgid_plural "{0} minutes" |
||||
msgstr[0] "{0} minuto" |
||||
msgstr[1] "{0} minuti" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:78 |
||||
#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:150 |
||||
msgid "{0} second" |
||||
msgid_plural "{0} seconds" |
||||
msgstr[0] "{0} secondo" |
||||
msgstr[1] "{0} secondi" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:63 |
||||
msgid "This value is already in use" |
||||
msgstr "Questo valore è già in uso" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:110 |
||||
msgid "This value does not exist" |
||||
msgstr "Questo valore non esiste" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:232 |
||||
msgid "Cannot modify row: a constraint for the `{0}` association fails." |
||||
msgstr "Impossibile modificare: il vincolo per l'associazione `{0}` fallisce." |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:270 |
||||
msgid "The count does not match {0}{1}" |
||||
msgstr "Il conteggio non corrisponde {0}{1}" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Utility/Text.php:923 |
||||
msgid "and" |
||||
msgstr "e" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2539 |
||||
msgid "This field is required" |
||||
msgstr "Questo campo è richiesto" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2559 |
||||
#: ./vendor/cakephp/cakephp/src/View/Form/ArrayContext.php:249 |
||||
msgid "This field cannot be left empty" |
||||
msgstr "Questo campo non può essere lasciato vuoto" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2711 |
||||
msgid "The provided value is invalid" |
||||
msgstr "Il valore fornito non è valido" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:979 |
||||
msgid "Edit {0}" |
||||
msgstr "Modifica {0}" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:981 |
||||
msgid "New {0}" |
||||
msgstr "Nuovo {0}" |
||||
|
||||
#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:1917 |
||||
msgid "Submit" |
||||
msgstr "Salva" |
||||
|
||||
@ -0,0 +1,268 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* |
||||
* Licensed under The MIT License |
||||
* For full copyright and license information, please see the LICENSE.txt |
||||
* Redistributions of files must retain the above copyright notice. |
||||
* |
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* @link https://cakephp.org CakePHP(tm) Project |
||||
* @since 3.3.0 |
||||
* @license https://opensource.org/licenses/mit-license.php MIT License |
||||
*/ |
||||
namespace App; |
||||
|
||||
use Cake\Core\Configure; |
||||
use Cake\Core\ContainerInterface; |
||||
use Cake\Datasource\FactoryLocator; |
||||
use Cake\Error\Middleware\ErrorHandlerMiddleware; |
||||
use Cake\Http\BaseApplication; |
||||
use Cake\Http\Middleware\BodyParserMiddleware; |
||||
use Cake\Http\Middleware\CsrfProtectionMiddleware; |
||||
use Cake\Http\MiddlewareQueue; |
||||
use Cake\ORM\Locator\TableLocator; |
||||
use Cake\Routing\Middleware\AssetMiddleware; |
||||
use Cake\Routing\Middleware\RoutingMiddleware; |
||||
|
||||
use Authentication\AuthenticationService; |
||||
use Authentication\AuthenticationServiceInterface; |
||||
use Authentication\AuthenticationServiceProviderInterface; |
||||
use Authentication\Identifier\AbstractIdentifier; |
||||
use Authentication\Identifier\IdentifierInterface; |
||||
use Authentication\Middleware\AuthenticationMiddleware; |
||||
use Cake\Http\Middleware\EncryptedCookieMiddleware; |
||||
use Cake\Routing\Router; |
||||
use Psr\Http\Message\ServerRequestInterface; |
||||
use Cake\I18n\Middleware\LocaleSelectorMiddleware; |
||||
use App\Middleware\UserTimezoneDatetimeRequestDataMiddleware; |
||||
|
||||
/** |
||||
* Application setup class. |
||||
* |
||||
* This defines the bootstrapping logic and middleware layers you |
||||
* want to use in your application. |
||||
*/ |
||||
class Application extends BaseApplication implements AuthenticationServiceProviderInterface |
||||
{ |
||||
/** |
||||
* Load all the application configuration and bootstrap logic. |
||||
* |
||||
* @return void |
||||
*/ |
||||
public function bootstrap(): void |
||||
{ |
||||
// Call parent to load bootstrap from files. |
||||
parent::bootstrap(); |
||||
|
||||
$this->addPlugin('Authentication'); |
||||
|
||||
if (PHP_SAPI === 'cli') { |
||||
$this->bootstrapCli(); |
||||
} else { |
||||
FactoryLocator::add( |
||||
'Table', |
||||
(new TableLocator())->allowFallbackClass(false) |
||||
); |
||||
} |
||||
|
||||
/* |
||||
* Only try to load DebugKit in development mode |
||||
* Debug Kit should not be installed on a production system |
||||
*/ |
||||
if (Configure::read('debug')) { |
||||
Configure::write('DebugKit.safeTld', ['it']); |
||||
} |
||||
|
||||
// Load more plugins here |
||||
$this->addPlugin('Muffin/Trash'); |
||||
$this->addPlugin('CsvView'); |
||||
$this->addPlugin('CakeSentry'); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Returns a service provider instance. |
||||
* |
||||
* @param \Psr\Http\Message\ServerRequestInterface $request Request |
||||
* @return \Authentication\AuthenticationServiceInterface |
||||
*/ |
||||
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface |
||||
{ |
||||
$service = new AuthenticationService(); |
||||
|
||||
$fields = [ |
||||
AbstractIdentifier::CREDENTIAL_USERNAME => 'username', |
||||
AbstractIdentifier::CREDENTIAL_PASSWORD => 'password' |
||||
]; |
||||
|
||||
if (strpos($request->getPath(), '/api/') !== 0) { |
||||
// NORMAL REQUESTS |
||||
|
||||
// se si tratta della request "/notifications/index" non eseguire il redirect e restituisci 401! |
||||
if ($request->getPath() !== '/notifications/index') { |
||||
// Define where users should be redirected to when they are not authenticated |
||||
$service->setConfig([ |
||||
'unauthenticatedRedirect' => Router::url([ |
||||
'prefix' => false, |
||||
'plugin' => null, |
||||
'controller' => 'Users', |
||||
'action' => 'login', |
||||
]), |
||||
'queryParam' => 'redirect', |
||||
]); |
||||
} |
||||
|
||||
// Load the authenticators. Session should be first. |
||||
$service->loadAuthenticator('Authentication.Session'); |
||||
|
||||
$service->loadAuthenticator('Authentication.Cookie', [ |
||||
'fields' => $fields, |
||||
'loginUrl' => Router::url([ |
||||
'prefix' => false, |
||||
'plugin' => null, |
||||
'controller' => 'Users', |
||||
'action' => 'login', |
||||
]), |
||||
]); |
||||
|
||||
$service->loadAuthenticator('Authentication.Form', [ |
||||
'fields' => $fields, |
||||
'loginUrl' => Router::url([ |
||||
'prefix' => false, |
||||
'plugin' => null, |
||||
'controller' => 'Users', |
||||
'action' => 'login', |
||||
]), |
||||
]); |
||||
|
||||
// Load identifiers |
||||
$service->loadIdentifier('JixelPassword', [ |
||||
'fields' => $fields, |
||||
]); |
||||
} else { |
||||
// API REQUESTS |
||||
|
||||
if (strpos($request->getPath(), '/api/users/login') === 0) { |
||||
// API REQUEST LOGIN |
||||
|
||||
// Load the authenticators. |
||||
$service->loadAuthenticator('Authentication.Form', [ |
||||
'fields' => $fields, |
||||
'loginUrl' => Router::url([ |
||||
'prefix' => 'Api', |
||||
'plugin' => null, |
||||
'controller' => 'Users', |
||||
'action' => 'login', |
||||
]), |
||||
]); |
||||
|
||||
// Load identifiers |
||||
$service->loadIdentifier('Authentication.Password', compact('fields')); |
||||
} else { |
||||
// Load identifiers |
||||
$service->loadIdentifier('Authentication.JwtSubject', [ |
||||
'tokenField' => 'username', |
||||
]); |
||||
|
||||
// Load the authenticators |
||||
$service->loadAuthenticator('Authentication.Jwt', [ |
||||
'secretKey' => file_get_contents(Configure::read('App.jwt.keys.public')), |
||||
'algorithm' => Configure::read('App.jwt.algorithm'), |
||||
'returnPayload' => false |
||||
]); |
||||
} |
||||
} |
||||
return $service; |
||||
} |
||||
|
||||
/** |
||||
* Setup the middleware queue your application will use. |
||||
* |
||||
* @param \Cake\Http\MiddlewareQueue $middlewareQueue The middleware queue to setup. |
||||
* @return \Cake\Http\MiddlewareQueue The updated middleware queue. |
||||
*/ |
||||
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue |
||||
{ |
||||
$middlewareQueue |
||||
->add(new LocaleSelectorMiddleware(['it', 'en'])) |
||||
|
||||
// Catch any exceptions in the lower layers, |
||||
// and make an error page/response |
||||
->add(new ErrorHandlerMiddleware(Configure::read('Error'))) |
||||
|
||||
// Handle plugin/theme assets like CakePHP normally does. |
||||
->add(new AssetMiddleware([ |
||||
'cacheTime' => Configure::read('Asset.cacheTime'), |
||||
])) |
||||
|
||||
// Add routing middleware. |
||||
// If you have a large number of routes connected, turning on routes |
||||
// caching in production could improve performance. For that when |
||||
// creating the middleware instance specify the cache config name by |
||||
// using it's second constructor argument: |
||||
// `new RoutingMiddleware($this, '_cake_routes_')` |
||||
->add(new RoutingMiddleware($this)) |
||||
|
||||
// Parse various types of encoded request bodies so that they are |
||||
// available as array through $request->getData() |
||||
// https://book.cakephp.org/4/en/controllers/middleware.html#body-parser-middleware |
||||
->add(new BodyParserMiddleware()); |
||||
|
||||
// Cross Site Request Forgery (CSRF) Protection Middleware |
||||
// https://book.cakephp.org/4/en/security/csrf.html#cross-site-request-forgery-csrf-middleware |
||||
$csrf = new CsrfProtectionMiddleware(); |
||||
|
||||
// Token check will be skipped when callback returns `true`. |
||||
$csrf->skipCheckCallback(function ($request) { |
||||
// Skip token check for API URLs. |
||||
if ($request->getParam('prefix') === 'Api') { |
||||
return true; |
||||
} |
||||
// Skip token check for ajax calls. |
||||
if ($request->is('ajax')) { |
||||
return true; |
||||
} |
||||
}); |
||||
|
||||
// Ensure routing middleware is added to the queue before CSRF protection middleware. |
||||
$middlewareQueue->add($csrf) |
||||
// encryption/decryption management of listed cookies: |
||||
->add(new EncryptedCookieMiddleware(['CookieAuth'], Configure::read('Security.CookieEncryptionKey'))) |
||||
|
||||
// Add the AuthenticationMiddleware. It should be |
||||
// after routing and body parser. |
||||
->add(new AuthenticationMiddleware($this)) |
||||
->add(new UserTimezoneDatetimeRequestDataMiddleware()); |
||||
|
||||
return $middlewareQueue; |
||||
} |
||||
|
||||
/** |
||||
* Register application container services. |
||||
* |
||||
* @param \Cake\Core\ContainerInterface $container The Container to update. |
||||
* @return void |
||||
* @link https://book.cakephp.org/4/en/development/dependency-injection.html#dependency-injection |
||||
*/ |
||||
public function services(ContainerInterface $container): void |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* Bootstrapping for CLI application. |
||||
* |
||||
* That is when running commands. |
||||
* |
||||
* @return void |
||||
*/ |
||||
protected function bootstrapCli(): void |
||||
{ |
||||
$this->addOptionalPlugin('Cake/Repl'); |
||||
|
||||
// Load more plugins here |
||||
} |
||||
} |
||||
@ -0,0 +1,95 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Command; |
||||
|
||||
use Cake\Command\Command; |
||||
use Cake\Console\Arguments; |
||||
use Cake\Console\ConsoleIo; |
||||
use Cake\Console\ConsoleOptionParser; |
||||
use App\WGS\Geo\CadastralUtils; |
||||
|
||||
class AddCadastralCodeToUsesCommand extends Command |
||||
{ |
||||
/** |
||||
* Hook method for defining this command's option parser. |
||||
* |
||||
* @see https://book.cakephp.org/4/en/console-commands/commands.html#defining-arguments-and-options |
||||
* @param \Cake\Console\ConsoleOptionParser $parser The parser to be defined |
||||
* @return \Cake\Console\ConsoleOptionParser The built parser. |
||||
*/ |
||||
public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser |
||||
{ |
||||
$parser = parent::buildOptionParser($parser); |
||||
|
||||
$parser |
||||
->addArgument('chunk_size', [ |
||||
'help' => 'the amount of records to process in chunk (at least 10 which is the default value)', |
||||
'required' => false, |
||||
]); |
||||
return $parser; |
||||
} |
||||
|
||||
/* |
||||
* Implement this method with your command's logic. |
||||
* |
||||
* @param \Cake\Console\Arguments $args The command arguments. |
||||
* @param \Cake\Console\ConsoleIo $io The console io |
||||
* @return null|void|int The exit code or null for success |
||||
*/ |
||||
public function execute(Arguments $args, ConsoleIo $io) |
||||
{ |
||||
$chunkSize = (int)($args->getArgument('chunk_size') ?? 10); |
||||
if ($chunkSize < 10) $io->abort("Please specify a chunk size of at least 10!"); |
||||
$page = 1; |
||||
$total = 0; |
||||
$io->info("AddCadastralCodeToUsesCommand started!"); |
||||
$io->info("Chunk size is: $chunkSize"); |
||||
|
||||
do { |
||||
$intendedUses = $this->fetchTable('WaterDrawingIntendedUses')->find() |
||||
->where([ |
||||
// recuperiamo solo le entries di tipo uso IRRIGUO che non hanno il codice BELFIORE: |
||||
"WaterDrawingIntendedUses.water_drawing_intended_use_type_id" => 1, |
||||
"WaterDrawingIntendedUses.cadastral_code IS NULL", |
||||
|
||||
// devono però avere foglio e particella validi: |
||||
"WaterDrawingIntendedUses.cadastral_sheet IS NOT NULL", |
||||
"WaterDrawingIntendedUses.cadastral_parcel IS NOT NULL", |
||||
"WaterDrawingIntendedUses.cadastral_sheet <> ''", |
||||
"WaterDrawingIntendedUses.cadastral_parcel <> ''", |
||||
]) |
||||
->limit($chunkSize) |
||||
->page($page) |
||||
->all(); |
||||
|
||||
foreach($intendedUses as $intendedUse){ |
||||
$io->info("Processing WaterDrawingIntendedUse with ID: $intendedUse->id"); |
||||
// recuperiamo il codice BELFIORE dal primo delle derivazioni connesse alla pratica (se ve ne sono....): |
||||
$derivation = $this->fetchTable('WaterDrawingDerivations')->find()->where([ |
||||
'WaterDrawingDerivations.water_drawing_paperwork_id' => $intendedUse->water_drawing_paperwork_id |
||||
])->first(); |
||||
if (!isset($derivation->cadastral_code)) { |
||||
$io->warning('WARNING: related water_drawing_paperwork has no suitable water_drawing_derivations to get cadastral_code from -> SKIPPED!'); |
||||
continue; |
||||
} |
||||
$intendedUse->cadastral_code = $derivation->cadastral_code; |
||||
$intendedUse->vegetation_match_status = CadastralUtils::isParcelWithinVegetationArea(strtolower($intendedUse->cadastral_code), $intendedUse->cadastral_sheet, $intendedUse->cadastral_parcel) ? 1 : -1; |
||||
|
||||
if(!$this->fetchTable('WaterDrawingIntendedUses')->save($intendedUse, ['skipResetIsMismatch' => true])){ |
||||
$io->warning('WARNING: Error during save!'); |
||||
$io->warning(json_encode($intendedUse->getErrors())); |
||||
} |
||||
} |
||||
|
||||
$count = $intendedUses->count(); |
||||
$total += $count; |
||||
if ($count) $io->success("processed $count items for page $page"); |
||||
$page++; |
||||
} while ($count === $chunkSize); |
||||
|
||||
$io->success("total processed $total items!"); |
||||
return static::CODE_SUCCESS; |
||||
} |
||||
} |
||||
?> |
||||
@ -0,0 +1,44 @@
|
||||
<?php |
||||
namespace App\Command; |
||||
|
||||
use App\WGS\Geo\CadastralUtils; |
||||
use Cake\Command\Command; |
||||
use Cake\Console\Arguments; |
||||
use Cake\Console\ConsoleIo; |
||||
|
||||
class AddDerivationCoordinatesCommand extends Command |
||||
{ |
||||
/* |
||||
* Implement this method with your command's logic. |
||||
* |
||||
* @param \Cake\Console\Arguments $args The command arguments. |
||||
* @param \Cake\Console\ConsoleIo $io The console io |
||||
* @return null|void|int The exit code or null for success |
||||
*/ |
||||
public function execute(Arguments $args, ConsoleIo $io) |
||||
{ |
||||
$derivations = $this->fetchTable('WaterDrawingDerivations')->find()->where([ |
||||
'WaterDrawingDerivations.latitude' => '', |
||||
'WaterDrawingDerivations.longitude' => '', |
||||
'WaterDrawingDerivations.cadastral_code IS NOT NULL', |
||||
'WaterDrawingDerivations.cadastral_sheet IS NOT NULL', |
||||
'WaterDrawingDerivations.cadastral_parcel IS NOT NULL', |
||||
])->toArray(); |
||||
foreach($derivations as $derivation){ |
||||
$coordinates = CadastralUtils::getParcelCentroidCoordinates(strtolower($derivation->cadastral_code), (string) $derivation->cadastral_sheet, (string) $derivation->cadastral_parcel); |
||||
if(isset($coordinates)){ |
||||
$derivation = $this->fetchTable('WaterDrawingDerivations')->patchEntity($derivation, [ |
||||
'latitude' => $coordinates->latitude, |
||||
'longitude' => $coordinates->longitude, |
||||
'feature_collection' => '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":['. $coordinates->longitude .','. $coordinates->latitude .']},"properties":null}]}' |
||||
]); |
||||
if(!$this->fetchTable('WaterDrawingDerivations')->save($derivation)){ |
||||
$io->out(__('Errore durante il salvataggio.')); |
||||
$io->out(json_encode($derivation->getErrors())); |
||||
} |
||||
} |
||||
} |
||||
return static::CODE_SUCCESS; |
||||
} |
||||
} |
||||
?> |
||||
@ -0,0 +1,57 @@
|
||||
<?php |
||||
namespace App\Command; |
||||
|
||||
use Cake\Command\Command; |
||||
use Cake\Console\Arguments; |
||||
use Cake\Console\ConsoleIo; |
||||
use App\WGS\NotificationsHandler\NotificationsHandler; |
||||
|
||||
class CheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand extends Command |
||||
{ |
||||
/* |
||||
* Implement this method with your command's logic. |
||||
* |
||||
* @param \Cake\Console\Arguments $args The command arguments. |
||||
* @param \Cake\Console\ConsoleIo $io The console io |
||||
* @return null|void|int The exit code or null for success |
||||
*/ |
||||
public function execute(Arguments $args, ConsoleIo $io): int |
||||
{ |
||||
$io->info("\n\nCheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand: START!!!"); |
||||
|
||||
// prima recupero, per ogni pratica, le water_drawing_antimafia_certification_requests con ID massimo |
||||
// questo mi assicura di prendere in considerazione l'ultima richiesta fatta: |
||||
$latest_water_drawing_antimafia_certification_request_ids = $this->fetchTable('WaterDrawingAntimafiaCertificationRequests') |
||||
->find() |
||||
->select(['max_id' => 'MAX(WaterDrawingAntimafiaCertificationRequests.id)']) |
||||
->group('water_drawing_paperwork_id'); |
||||
|
||||
// quindi recuoero le pratiche per cui risulti l'ultima richiesta AM scaduta (termine dei 30gg) |
||||
// che sia in "stato richiesta" in modo da poter notificare i relativi utenti DRAR: |
||||
$to_be_notified_water_drawing_paperworks = $this->fetchTable('WaterDrawingPaperworks') |
||||
->find() |
||||
->matching('WaterDrawingAntimafiaCertificationRequests') |
||||
->where([ |
||||
'WaterDrawingAntimafiaCertificationRequests.id IN' => $latest_water_drawing_antimafia_certification_request_ids, |
||||
'WaterDrawingAntimafiaCertificationRequests.water_drawing_antimafia_certification_request_status_id' => 2, |
||||
'WaterDrawingAntimafiaCertificationRequests.created <= NOW() - INTERVAL 30 DAY' |
||||
]) |
||||
->toArray(); |
||||
|
||||
foreach($to_be_notified_water_drawing_paperworks as $waterDrawingPaperwork) { |
||||
// DISPATCH NOTIFICHE: |
||||
$io->info("\nCheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand: richiesta AM scaduta per pratica con ID: " . $waterDrawingPaperwork->id); |
||||
if (isset($waterDrawingPaperwork->drar_user_id)) { |
||||
$io->success("CheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand: Invio notifica a utente DRAR con ID: " . $waterDrawingPaperwork->drar_user_id); |
||||
// invio notifica a utente DRAR che aveva richiesto la certificazione antimafia perchè la richiesta è scaduta: |
||||
NotificationsHandler::dispatch($waterDrawingPaperwork->controllable_object_id, 'send_to_drar_user_antimafia_request_expired', ['drar_user_id' => $waterDrawingPaperwork->drar_user_id, 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); |
||||
} else { |
||||
$io->error("CheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand: LA PRATICA NON HA UTENTI DRAR ASSEGNATI !!!!!"); |
||||
} |
||||
} |
||||
|
||||
$io->info("\n\nCheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand: END!!!"); |
||||
return static::CODE_SUCCESS; |
||||
} |
||||
} |
||||
?> |
||||
@ -0,0 +1,144 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Command; |
||||
|
||||
use Cake\Command\Command; |
||||
use Cake\Console\Arguments; |
||||
use Cake\Console\ConsoleIo; |
||||
use Cake\Console\ConsoleOptionParser; |
||||
|
||||
/** |
||||
* CopyTranslations command. |
||||
*/ |
||||
class CopyTranslationsCommand extends Command |
||||
{ |
||||
private $pot_identifiers = []; |
||||
|
||||
/** |
||||
* Hook method for defining this command's option parser. |
||||
* |
||||
* @see https://book.cakephp.org/4/en/console-commands/commands.html#defining-arguments-and-options |
||||
* @param \Cake\Console\ConsoleOptionParser $parser The parser to be defined |
||||
* @return \Cake\Console\ConsoleOptionParser The built parser. |
||||
*/ |
||||
public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser |
||||
{ |
||||
$parser = parent::buildOptionParser($parser); |
||||
|
||||
$parser |
||||
->addArgument('template_filename', [ |
||||
'help' => '.POT Template file (with full or relative path)', |
||||
'required' => true, |
||||
]) |
||||
->addArgument('input_filename', [ |
||||
'help' => '.PO Input file (with full or relative path)', |
||||
'required' => true, |
||||
]) |
||||
->addArgument('output_filename', [ |
||||
'help' => 'Output PO file (with full or relative path)', |
||||
'required' => true, |
||||
]); |
||||
return $parser; |
||||
} |
||||
|
||||
/** |
||||
* Implement this method with your command's logic. |
||||
* |
||||
* @param \Cake\Console\Arguments $args The command arguments. |
||||
* @param \Cake\Console\ConsoleIo $io The console io |
||||
* @return null|void|int The exit code or null for success |
||||
*/ |
||||
public function execute(Arguments $args, ConsoleIo $io) |
||||
{ |
||||
$template_filename = $args->getArgument('template_filename'); |
||||
$input_filename = $args->getArgument('input_filename'); |
||||
$output_filename = $args->getArgument('output_filename'); |
||||
|
||||
$io->info("\n\ntemplate file path: $template_filename, input file path: $input_filename, output file path: $output_filename\n\n"); |
||||
|
||||
if (!file_exists($template_filename)) $io->abort("\n\n\nError: File \"$template_filename\" doesn't exists!"); |
||||
if (!file_exists($input_filename)) $io->abort("\n\n\nError: File \"$input_filename\" doesn't exists!"); |
||||
|
||||
// lettura pot e retrieving identifiers: |
||||
$template_filename_handle = fopen($template_filename, "r"); |
||||
if ($template_filename_handle) { |
||||
$pot_row_count = 0; |
||||
$io->info("\n\n\nFetching translation identifiers from template file \"$template_filename\":\n"); |
||||
while (($buffer = fgets($template_filename_handle, 4096)) !== false) { |
||||
if (substr($buffer, 0, 5) !== "msgid") continue; |
||||
$text = explode("\"\n", explode("msgid \"", $buffer)[1])[0]; |
||||
if ($text === "") continue; |
||||
++$pot_row_count; |
||||
$io->info("msgid at row $pot_row_count: $text"); |
||||
$this->pot_identifiers[$text] = ""; |
||||
} |
||||
if (!feof($template_filename_handle)) { |
||||
$io->abort("\n\n\nError: unexpected fgets() fail"); |
||||
} |
||||
fclose($template_filename_handle); |
||||
$io->success("\n\nNumber of identifiers successfully fetched from template file \"$template_filename\": $pot_row_count\n\n"); |
||||
} else { |
||||
$io->abort("\n\n\nError: Unable to Open File \"$template_filename\"!"); |
||||
} |
||||
|
||||
// lettura input file e retrieving translations (x gli identifiers che matchano): |
||||
$input_filename_handle = fopen($input_filename, "r"); |
||||
if ($input_filename_handle) { |
||||
$count = 0; |
||||
$last_identifier = null; |
||||
$io->info("\n\n\nRetrieving translations from input file \"$input_filename\":\n"); |
||||
while (($buffer = fgets($input_filename_handle, 4096)) !== false) { |
||||
if (substr($buffer, 0, 6) === "msgid ") { |
||||
$last_identifier = explode("\"\n", explode("msgid \"", $buffer)[1])[0]; |
||||
if ($last_identifier === "" || !isset($this->pot_identifiers[$last_identifier])) $last_identifier = null; |
||||
} |
||||
if (substr($buffer, 0, 6) === "msgstr" && isset($last_identifier)) { |
||||
$this->pot_identifiers[$last_identifier] = explode("\"\n", explode("msgstr \"", $buffer)[1])[0]; |
||||
if (!empty($this->pot_identifiers[$last_identifier])) ++$count; |
||||
$io->info("Retrieved translations so far: $count - Parsing: \"$last_identifier\" = \"" . $this->pot_identifiers[$last_identifier] . "\""); |
||||
} |
||||
} |
||||
if (!feof($input_filename_handle)) { |
||||
$io->abort("\n\n\nError: unexpected fgets() fail"); |
||||
} |
||||
fclose($input_filename_handle); |
||||
$io->success("\n\nSuccessfully retrieved $count translations from input po file \"$input_filename\"!\n\n"); |
||||
} else { |
||||
$io->abort("\n\n\nError: Unable to Open File \"$input_filename\"!"); |
||||
} |
||||
|
||||
// creazione file .PO di output partendo da struttura del .POT fornito e arricchito con le traduzioni recuperate dal file di input |
||||
$template_filename_handle = fopen($template_filename, "r"); |
||||
$output_filename_handle = fopen($output_filename, 'w'); |
||||
|
||||
if ($template_filename_handle) { |
||||
$count = 0; |
||||
$last_identifier = null; |
||||
$io->info("\n\n\nCreating new translation file \"$output_filename\":\n"); |
||||
while (($buffer = fgets($template_filename_handle, 4096)) !== false) { |
||||
if (substr($buffer, 0, 5) === "msgid") { |
||||
$last_identifier = explode("\"\n", explode("msgid \"", $buffer)[1])[0]; |
||||
if ($last_identifier !== "" && !empty($this->pot_identifiers[$last_identifier])) { |
||||
++$count; |
||||
} else { |
||||
$last_identifier = null; |
||||
} |
||||
} |
||||
if (substr($buffer, 0, 6) === "msgstr" && isset($last_identifier)) { |
||||
$io->info("Adding translation number: $count for identifier: \"$last_identifier\"" . " with translation: \"" . $this->pot_identifiers[$last_identifier] . "\""); |
||||
$buffer = "msgstr \"" . $this->pot_identifiers[$last_identifier] . "\"\n"; |
||||
} |
||||
fwrite($output_filename_handle, $buffer); |
||||
} |
||||
if (!feof($template_filename_handle)) { |
||||
$io->abort("\n\n\nError: unexpected fgets() fail"); |
||||
} |
||||
fclose($template_filename_handle); |
||||
fclose($output_filename_handle); |
||||
$io->success("\n\nSuccessfully created po file \"$output_filename\" with $count added translations!\n\n"); |
||||
} else { |
||||
$io->abort("\n\n\nError: Unable to Open File \"$template_filename\"!"); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,107 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Command; |
||||
|
||||
use Cake\Command\Command; |
||||
use Cake\Console\Arguments; |
||||
use Cake\Console\ConsoleIo; |
||||
use Cake\Console\ConsoleOptionParser; |
||||
use App\WGS\Geo\CadastralUtils; |
||||
use App\WGS\NotificationsHandler\NotificationsHandler; |
||||
|
||||
class IntendedUseVegetationCheckCommand extends Command |
||||
{ |
||||
/** |
||||
* Hook method for defining this command's option parser. |
||||
* |
||||
* @see https://book.cakephp.org/4/en/console-commands/commands.html#defining-arguments-and-options |
||||
* @param \Cake\Console\ConsoleOptionParser $parser The parser to be defined |
||||
* @return \Cake\Console\ConsoleOptionParser The built parser. |
||||
*/ |
||||
public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser |
||||
{ |
||||
$parser = parent::buildOptionParser($parser); |
||||
|
||||
$parser->addArgument('data', [ |
||||
'help' => 'the serialized data to process', |
||||
'required' => true, |
||||
]); |
||||
return $parser; |
||||
} |
||||
|
||||
/* |
||||
* Implement this method with your command's logic. |
||||
* |
||||
* @param \Cake\Console\Arguments $args The command arguments. |
||||
* @param \Cake\Console\ConsoleIo $io The console io |
||||
* @return null|void|int The exit code or null for success |
||||
*/ |
||||
public function execute(Arguments $args, ConsoleIo $io) |
||||
{ |
||||
$io->info("IntendedUseVegetationCheckCommand - JOB STARTED!"); |
||||
$data = $args->getArgument('data'); |
||||
$io->info("IntendedUseVegetationCheckCommand - received data: {$data}"); |
||||
|
||||
$deserialized_data = json_decode($data, true); |
||||
|
||||
if (empty($deserialized_data['water_drawing_paperwork_id'])) { |
||||
$io->abort("IntendedUseVegetationCheckCommand - water_drawing_paperwork_id is missing!"); |
||||
} |
||||
|
||||
$water_drawing_paperwork = $this->fetchTable('WaterDrawingPaperworks')->find()->where(['WaterDrawingPaperworks.id' => $deserialized_data['water_drawing_paperwork_id']])->first(); |
||||
if (!$water_drawing_paperwork) { |
||||
$io->abort("IntendedUseVegetationCheckCommand - water_drawing_paperwork with ID: {$deserialized_data['water_drawing_paperwork_id']} not found!"); |
||||
} |
||||
|
||||
$water_drawing_intended_uses = $this->fetchTable('WaterDrawingIntendedUses')->find()->where(['WaterDrawingIntendedUses.water_drawing_paperwork_id' => $water_drawing_paperwork->id])->all(); |
||||
|
||||
$intended_use_linked = count($water_drawing_intended_uses); |
||||
$intended_use_processed = 0; |
||||
|
||||
foreach ($water_drawing_intended_uses as $water_drawing_intended_use) { |
||||
$io->info("IntendedUseVegetationCheckCommand - checking linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id}, cadastral_code: {$water_drawing_intended_use->cadastral_code}, cadastral_sheet: {$water_drawing_intended_use->cadastral_sheet}, cadastral_parcel: {$water_drawing_intended_use->cadastral_parcel}, water_drawing_intended_use_type_id: {$water_drawing_intended_use->water_drawing_intended_use_type_id}..."); |
||||
if ($water_drawing_intended_use->water_drawing_intended_use_type_id != 1) { |
||||
$io->comment("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has water_drawing_intended_use_type_id: {$water_drawing_intended_use->water_drawing_intended_use_type_id} (must be 1), SKIPPED!"); |
||||
continue; |
||||
} |
||||
if (empty($water_drawing_intended_use->cadastral_code)) { |
||||
$io->comment("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has NO valid cadastral_code, SKIPPED!"); |
||||
continue; |
||||
} |
||||
if (empty($water_drawing_intended_use->cadastral_sheet)) { |
||||
$io->comment("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has NO valid cadastral_sheet, SKIPPED!"); |
||||
continue; |
||||
} |
||||
if (empty($water_drawing_intended_use->cadastral_parcel)) { |
||||
$io->comment("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has NO valid cadastral_parcel, SKIPPED!"); |
||||
continue; |
||||
} |
||||
$water_drawing_intended_use->vegetation_match_status = CadastralUtils::isParcelWithinVegetationArea(strtolower($water_drawing_intended_use->cadastral_code), $water_drawing_intended_use->cadastral_sheet, $water_drawing_intended_use->cadastral_parcel) ? 1 : -1; |
||||
if ($water_drawing_intended_use->vegetation_match_status == -1) { |
||||
$io->comment("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has NO MATCHING INTENDED USE!!!"); |
||||
} else { |
||||
$io->success("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has PERFECT MATCHING INTENDED USE!"); |
||||
} |
||||
if (!$this->fetchTable('WaterDrawingIntendedUses')->save($water_drawing_intended_use, ['skipResetIsMismatch' => true])) { |
||||
$io->error("IntendedUseVegetationCheckCommand - error saving processed water_drawing_intended_use with ID: {$water_drawing_intended_use->id}"); |
||||
} else { |
||||
$intended_use_processed++; |
||||
} |
||||
} |
||||
|
||||
$io->success("IntendedUseVegetationCheckCommand - checked {$intended_use_linked} linked intended uses and successfully processed {$intended_use_processed} of them!"); |
||||
|
||||
if (!empty($deserialized_data['notification_user_id'])) { |
||||
$user_to_be_notified_id = $deserialized_data['notification_user_id']; |
||||
$io->info("IntendedUseVegetationCheckCommand - sending notification to user with ID: {$user_to_be_notified_id}"); |
||||
NotificationsHandler::dispatch($water_drawing_paperwork->controllable_object_id, 'send_to_last_edit_user_intended_use_check_completed', ['last_edit_user_id' => $user_to_be_notified_id, 'link' => '/water_drawing_paperworks/view' . ($water_drawing_paperwork->scanned ? '_scan' : '') .'/' . $water_drawing_paperwork->id, 'water_drawing_paperwork_id' => $water_drawing_paperwork->id]); |
||||
} else { |
||||
$io->comment("IntendedUseVegetationCheckCommand - notification_user_id is missing, skipping notification!"); |
||||
} |
||||
|
||||
$io->info("IntendedUseVegetationCheckCommand - JOB ENDED!"); |
||||
return static::CODE_SUCCESS; |
||||
} |
||||
} |
||||
?> |
||||
@ -0,0 +1,65 @@
|
||||
<?php |
||||
namespace App\Command; |
||||
|
||||
use Cake\Command\Command; |
||||
use Cake\Console\Arguments; |
||||
use Cake\Console\ConsoleIo; |
||||
|
||||
class NormalizeApplicantProvinceCommand extends Command |
||||
{ |
||||
/* |
||||
* Implement this method with your command's logic. |
||||
* |
||||
* @param \Cake\Console\Arguments $args The command arguments. |
||||
* @param \Cake\Console\ConsoleIo $io The console io |
||||
* @return null|void|int The exit code or null for success |
||||
*/ |
||||
public function execute(Arguments $args, ConsoleIo $io): int |
||||
{ |
||||
$applicants = $this->fetchTable('Applicants')->find()->where(['Applicants.province IN' => ['Palermo', 'Catania', 'Caltanissetta', 'Enna', 'Ragusa', 'Agrigento', 'Messina', 'Siracusa', 'Trapani']])->toArray(); |
||||
foreach($applicants as $applicant){ |
||||
switch(strtolower($applicant->province)){ |
||||
case 'catania': |
||||
$province = 'CT'; |
||||
break; |
||||
case 'palermo': |
||||
$province = 'PA'; |
||||
break; |
||||
case 'caltanissetta': |
||||
$province = 'CL'; |
||||
break; |
||||
case 'enna': |
||||
$province = 'EN'; |
||||
break; |
||||
case 'ragusa': |
||||
$province = 'RG'; |
||||
break; |
||||
case 'siracusa': |
||||
$province = 'SR'; |
||||
break; |
||||
case 'trapani': |
||||
$province = 'TP'; |
||||
break; |
||||
case 'messina': |
||||
$province = 'ME'; |
||||
break; |
||||
case 'agrigento': |
||||
$province = 'AG'; |
||||
break; |
||||
} |
||||
if(!isset($province)) continue; |
||||
$applicant = $this->fetchTable('Applicants')->patchEntity($applicant, [ |
||||
'province' => $province |
||||
]); |
||||
if(!$this->fetchTable('Applicants')->save($applicant, [ |
||||
'checkRules' => false |
||||
])){ |
||||
$io->out(__('Errore durante il salvataggio')); |
||||
$io->out(json_encode($applicant->getErrors(), JSON_PRETTY_PRINT)); |
||||
} |
||||
$province = null; |
||||
} |
||||
return static::CODE_SUCCESS; |
||||
} |
||||
} |
||||
?> |
||||
@ -0,0 +1,65 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Command; |
||||
|
||||
use Cake\Command\Command; |
||||
use Cake\Console\Arguments; |
||||
use Cake\Console\ConsoleIo; |
||||
use Cake\Console\ConsoleOptionParser; |
||||
use App\WGS\NotificationsHandler\NotificationsHandler; |
||||
|
||||
/** |
||||
* NotificationsHandler command. |
||||
*/ |
||||
class NotificationsHandlerCommand extends Command |
||||
{ |
||||
/** |
||||
* Hook method for defining this command's option parser. |
||||
* |
||||
* @see https://book.cakephp.org/4/en/console-commands/commands.html#defining-arguments-and-options |
||||
* @param \Cake\Console\ConsoleOptionParser $parser The parser to be defined |
||||
* @return \Cake\Console\ConsoleOptionParser The built parser. |
||||
*/ |
||||
public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser |
||||
{ |
||||
$parser = parent::buildOptionParser($parser); |
||||
|
||||
$parser->addArgument('data', [ |
||||
'help' => 'the serialized data to process', |
||||
'required' => true, |
||||
]); |
||||
|
||||
return $parser; |
||||
} |
||||
|
||||
/** |
||||
* Implement this method with your command's logic. |
||||
* |
||||
* @param \Cake\Console\Arguments $args The command arguments. |
||||
* @param \Cake\Console\ConsoleIo $io The console io |
||||
* @return null|void|int The exit code or null for success |
||||
*/ |
||||
public function execute(Arguments $args, ConsoleIo $io): int |
||||
{ |
||||
$data = $args->getArgument('data'); |
||||
$io->info("NotificationsHandlerCommand - received data: {$data}"); |
||||
|
||||
$deserialized_data = json_decode($data, true); |
||||
|
||||
if (empty($deserialized_data['background_task_id'])) { |
||||
$io->abort("NotificationsHandlerCommand - background_task_id is missing!"); |
||||
} |
||||
|
||||
$background_task = $this->fetchTable('BackgroundTasks')->find()->where(['BackgroundTasks.id' => $deserialized_data['background_task_id']])->first(); |
||||
if (!$background_task) { |
||||
$io->abort("NotificationsHandlerCommand - background_task not found!"); |
||||
} |
||||
|
||||
$request = json_decode($background_task->data, true); |
||||
NotificationsHandler::executeDispatch($request['co_id'], $request['notification_code'], $request['options'], $request['group'], $request['user_logged']); |
||||
|
||||
$io->success("NotificationsHandlerCommand - successfully processed!"); |
||||
return static::CODE_SUCCESS; |
||||
} |
||||
} |
||||
@ -0,0 +1,98 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Command; |
||||
|
||||
use Cake\Command\Command; |
||||
use Cake\Console\Arguments; |
||||
use Cake\Console\ConsoleIo; |
||||
use Cake\Console\ConsoleOptionParser; |
||||
use App\WGS\SnapshotsHandler\SnapshotsHandler; |
||||
use Cake\Datasource\ConnectionManager; |
||||
|
||||
/** |
||||
* UnpackWaterDrawingPaperworkSnapshots command. |
||||
*/ |
||||
class UnpackWaterDrawingPaperworkSnapshotsCommand extends Command |
||||
{ |
||||
/** |
||||
* Hook method for defining this command's option parser. |
||||
* |
||||
* @see https://book.cakephp.org/4/en/console-commands/commands.html#defining-arguments-and-options |
||||
* @param \Cake\Console\ConsoleOptionParser $parser The parser to be defined |
||||
* @return \Cake\Console\ConsoleOptionParser The built parser. |
||||
*/ |
||||
public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser |
||||
{ |
||||
$parser = parent::buildOptionParser($parser); |
||||
$parser->setDescription('Unpacks water_drawing_paperworks from Snapshots and store them to unpacked_water_drawing_paperwork_snapshots table with the last unpacking version number available'); |
||||
|
||||
$parser |
||||
->addOptions([ |
||||
'limit' => [ |
||||
'short' => 'l', |
||||
'help' => 'Number of rows to process', |
||||
'boolean' => false, |
||||
'required' => true, |
||||
], |
||||
]); |
||||
|
||||
return $parser; |
||||
} |
||||
|
||||
/** |
||||
* Implement this method with your command's logic. |
||||
* |
||||
* @param \Cake\Console\Arguments $args The command arguments. |
||||
* @param \Cake\Console\ConsoleIo $io The console io |
||||
* @return null|void|int The exit code or null for success |
||||
*/ |
||||
public function execute(Arguments $args, ConsoleIo $io) |
||||
{ |
||||
$limit = $args->getOption('limit'); |
||||
if ($limit < 1) $io->abort("You must specify an Int number greater than ZERO!"); |
||||
$io->info("trying processing $limit items..."); |
||||
$lastWaterDrawingPaperworkUnpackingVersion = SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion(); |
||||
$io->info("lastWaterDrawingPaperworkUnpackingVersion: $lastWaterDrawingPaperworkUnpackingVersion"); |
||||
|
||||
$processed = 0; |
||||
$unpackable_water_drawing_paperwork_snapshots = $this->fetchTable('Snapshots')->find()->where(['Snapshots.controllable_object_type_id' => 9, 'OR' => ['Snapshots.unpacked_with_version is NULL', 'Snapshots.unpacked_with_version <>' => $lastWaterDrawingPaperworkUnpackingVersion]])->limit((int)$limit)->toArray(); |
||||
|
||||
$io->info("found " . count($unpackable_water_drawing_paperwork_snapshots) . " unpackable items."); |
||||
|
||||
if (count($unpackable_water_drawing_paperwork_snapshots) > 0) ConnectionManager::get('default')->begin(); |
||||
|
||||
$this->fetchTable('WaterDrawingPaperworks')->removeBehavior('Trash'); |
||||
|
||||
foreach ($unpackable_water_drawing_paperwork_snapshots as $unpackable_water_drawing_paperwork_snapshot) { |
||||
$io->info("\nUnpackedWaterDrawingPaperworkSnapshot entity:"); |
||||
$unpackedWaterDrawingPaperworkSnapshot = SnapshotsHandler::getUnpackedWaterDrawingPaperworkSnapshot($unpackable_water_drawing_paperwork_snapshot->id); |
||||
if (!$unpackedWaterDrawingPaperworkSnapshot) { |
||||
ConnectionManager::get('default')->rollback(); |
||||
$io->abort("\nError retrieving unpackedWaterDrawingPaperworkSnapshot!"); |
||||
} |
||||
$io->info(json_encode($unpackedWaterDrawingPaperworkSnapshot)); |
||||
$io->info("\nSaving unpacked water_drawing_paperwork snapshot to unpackedWaterDrawingPaperworkSnapshots table..."); |
||||
if (!$this->fetchTable('UnpackedWaterDrawingPaperworkSnapshots')->save($unpackedWaterDrawingPaperworkSnapshot)) { |
||||
ConnectionManager::get('default')->rollback(); |
||||
$io->abort("\nError saving unpackedWaterDrawingPaperworkSnapshot: " . json_encode($unpackedWaterDrawingPaperworkSnapshot->getErrors())); |
||||
} |
||||
$io->info("\nMarking and saving snapshot with ID " . $unpackable_water_drawing_paperwork_snapshot->id . " as unpacked with version: " . $lastWaterDrawingPaperworkUnpackingVersion); |
||||
$unpackable_water_drawing_paperwork_snapshot->unpacked_with_version = $lastWaterDrawingPaperworkUnpackingVersion; |
||||
if (!$this->fetchTable('Snapshots')->save($unpackable_water_drawing_paperwork_snapshot)) { |
||||
ConnectionManager::get('default')->rollback(); |
||||
$io->abort("\nError saving snapshot: " . json_encode($unpackable_water_drawing_paperwork_snapshot->getErrors())); |
||||
} |
||||
$processed++; |
||||
$io->success("\nSUCCESSFULLY PROCESSED: $processed !\n"); |
||||
} |
||||
|
||||
$this->fetchTable('WaterDrawingPaperworks')->addBehavior('Muffin/Trash.Trash'); |
||||
|
||||
$io->success("\nJOB IS DONE. REQUESTED: $limit, UNPACKABLE: " . count($unpackable_water_drawing_paperwork_snapshots) . " SUCCESSFULLY PROCESSED: $processed"); |
||||
|
||||
if (count($unpackable_water_drawing_paperwork_snapshots) > 0) ConnectionManager::get('default')->commit(); |
||||
|
||||
return static::CODE_SUCCESS; |
||||
} |
||||
} |
||||
@ -0,0 +1,250 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* |
||||
* Licensed under The MIT License |
||||
* For full copyright and license information, please see the LICENSE.txt |
||||
* Redistributions of files must retain the above copyright notice. |
||||
* |
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* @link https://cakephp.org CakePHP(tm) Project |
||||
* @since 3.0.0 |
||||
* @license https://opensource.org/licenses/mit-license.php MIT License |
||||
*/ |
||||
namespace App\Console; |
||||
|
||||
if (!defined('STDIN')) { |
||||
define('STDIN', fopen('php://stdin', 'r')); |
||||
} |
||||
|
||||
use Cake\Codeception\Console\Installer as CodeceptionInstaller; |
||||
use Cake\Utility\Security; |
||||
use Composer\IO\IOInterface; |
||||
use Composer\Script\Event; |
||||
use Exception; |
||||
|
||||
/** |
||||
* Provides installation hooks for when this application is installed through |
||||
* composer. Customize this class to suit your needs. |
||||
*/ |
||||
class Installer |
||||
{ |
||||
/** |
||||
* An array of directories to be made writable |
||||
*/ |
||||
public const WRITABLE_DIRS = [ |
||||
'logs', |
||||
'tmp', |
||||
'tmp/cache', |
||||
'tmp/cache/models', |
||||
'tmp/cache/persistent', |
||||
'tmp/cache/views', |
||||
'tmp/sessions', |
||||
'tmp/tests', |
||||
]; |
||||
|
||||
/** |
||||
* Does some routine installation tasks so people don't have to. |
||||
* |
||||
* @param \Composer\Script\Event $event The composer event object. |
||||
* @throws \Exception Exception raised by validator. |
||||
* @return void |
||||
*/ |
||||
public static function postInstall(Event $event): void |
||||
{ |
||||
$io = $event->getIO(); |
||||
|
||||
$rootDir = dirname(__DIR__, 2); |
||||
|
||||
static::createAppLocalConfig($rootDir, $io); |
||||
static::createWritableDirectories($rootDir, $io); |
||||
|
||||
static::setFolderPermissions($rootDir, $io); |
||||
static::setSecuritySalt($rootDir, $io); |
||||
|
||||
if (class_exists(CodeceptionInstaller::class)) { |
||||
CodeceptionInstaller::customizeCodeceptionBinary($event); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Create config/app_local.php file if it does not exist. |
||||
* |
||||
* @param string $dir The application's root directory. |
||||
* @param \Composer\IO\IOInterface $io IO interface to write to console. |
||||
* @return void |
||||
*/ |
||||
public static function createAppLocalConfig(string $dir, IOInterface $io): void |
||||
{ |
||||
$appLocalConfig = $dir . '/config/app_local.php'; |
||||
$appLocalConfigTemplate = $dir . '/config/app_local.example.php'; |
||||
if (!file_exists($appLocalConfig)) { |
||||
copy($appLocalConfigTemplate, $appLocalConfig); |
||||
$io->write('Created `config/app_local.php` file'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Create the `logs` and `tmp` directories. |
||||
* |
||||
* @param string $dir The application's root directory. |
||||
* @param \Composer\IO\IOInterface $io IO interface to write to console. |
||||
* @return void |
||||
*/ |
||||
public static function createWritableDirectories(string $dir, IOInterface $io): void |
||||
{ |
||||
foreach (static::WRITABLE_DIRS as $path) { |
||||
$path = $dir . '/' . $path; |
||||
if (!file_exists($path)) { |
||||
mkdir($path); |
||||
$io->write('Created `' . $path . '` directory'); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Set globally writable permissions on the "tmp" and "logs" directory. |
||||
* |
||||
* This is not the most secure default, but it gets people up and running quickly. |
||||
* |
||||
* @param string $dir The application's root directory. |
||||
* @param \Composer\IO\IOInterface $io IO interface to write to console. |
||||
* @return void |
||||
*/ |
||||
public static function setFolderPermissions(string $dir, IOInterface $io): void |
||||
{ |
||||
// ask if the permissions should be changed |
||||
if ($io->isInteractive()) { |
||||
$validator = function (string $arg): string { |
||||
if (in_array($arg, ['Y', 'y', 'N', 'n'])) { |
||||
return $arg; |
||||
} |
||||
throw new Exception('This is not a valid answer. Please choose Y or n.'); |
||||
}; |
||||
$setFolderPermissions = $io->askAndValidate( |
||||
'<info>Set Folder Permissions ? (Default to Y)</info> [<comment>Y,n</comment>]? ', |
||||
$validator, |
||||
10, |
||||
'Y' |
||||
); |
||||
|
||||
if (in_array($setFolderPermissions, ['n', 'N'])) { |
||||
return; |
||||
} |
||||
} |
||||
|
||||
// Change the permissions on a path and output the results. |
||||
$changePerms = function (string $path) use ($io): void { |
||||
$currentPerms = fileperms($path) & 0777; |
||||
$worldWritable = $currentPerms | 0007; |
||||
if ($worldWritable == $currentPerms) { |
||||
return; |
||||
} |
||||
|
||||
$res = chmod($path, $worldWritable); |
||||
if ($res) { |
||||
$io->write('Permissions set on ' . $path); |
||||
} else { |
||||
$io->write('Failed to set permissions on ' . $path); |
||||
} |
||||
}; |
||||
|
||||
$walker = function (string $dir) use (&$walker, $changePerms): void { |
||||
/** @phpstan-ignore-next-line */ |
||||
$files = array_diff(scandir($dir), ['.', '..']); |
||||
foreach ($files as $file) { |
||||
$path = $dir . '/' . $file; |
||||
|
||||
if (!is_dir($path)) { |
||||
continue; |
||||
} |
||||
|
||||
$changePerms($path); |
||||
$walker($path); |
||||
} |
||||
}; |
||||
|
||||
$walker($dir . '/tmp'); |
||||
$changePerms($dir . '/tmp'); |
||||
$changePerms($dir . '/logs'); |
||||
} |
||||
|
||||
/** |
||||
* Set the security.salt value in the application's config file. |
||||
* |
||||
* @param string $dir The application's root directory. |
||||
* @param \Composer\IO\IOInterface $io IO interface to write to console. |
||||
* @return void |
||||
*/ |
||||
public static function setSecuritySalt(string $dir, IOInterface $io): void |
||||
{ |
||||
$newKey = hash('sha256', Security::randomBytes(64)); |
||||
static::setSecuritySaltInFile($dir, $io, $newKey, 'app_local.php'); |
||||
} |
||||
|
||||
/** |
||||
* Set the security.salt value in a given file |
||||
* |
||||
* @param string $dir The application's root directory. |
||||
* @param \Composer\IO\IOInterface $io IO interface to write to console. |
||||
* @param string $newKey key to set in the file |
||||
* @param string $file A path to a file relative to the application's root |
||||
* @return void |
||||
*/ |
||||
public static function setSecuritySaltInFile(string $dir, IOInterface $io, string $newKey, string $file): void |
||||
{ |
||||
$config = $dir . '/config/' . $file; |
||||
$content = file_get_contents($config); |
||||
|
||||
/** @phpstan-ignore-next-line */ |
||||
$content = str_replace('__SALT__', $newKey, $content, $count); |
||||
|
||||
if ($count == 0) { |
||||
$io->write('No Security.salt placeholder to replace.'); |
||||
|
||||
return; |
||||
} |
||||
|
||||
$result = file_put_contents($config, $content); |
||||
if ($result) { |
||||
$io->write('Updated Security.salt value in config/' . $file); |
||||
|
||||
return; |
||||
} |
||||
$io->write('Unable to update Security.salt value.'); |
||||
} |
||||
|
||||
/** |
||||
* Set the APP_NAME value in a given file |
||||
* |
||||
* @param string $dir The application's root directory. |
||||
* @param \Composer\IO\IOInterface $io IO interface to write to console. |
||||
* @param string $appName app name to set in the file |
||||
* @param string $file A path to a file relative to the application's root |
||||
* @return void |
||||
*/ |
||||
public static function setAppNameInFile(string $dir, IOInterface $io, string $appName, string $file): void |
||||
{ |
||||
$config = $dir . '/config/' . $file; |
||||
$content = file_get_contents($config); |
||||
/** @phpstan-ignore-next-line */ |
||||
$content = str_replace('__APP_NAME__', $appName, $content, $count); |
||||
|
||||
if ($count == 0) { |
||||
$io->write('No __APP_NAME__ placeholder to replace.'); |
||||
|
||||
return; |
||||
} |
||||
|
||||
$result = file_put_contents($config, $content); |
||||
if ($result) { |
||||
$io->write('Updated __APP_NAME__ value in config/' . $file); |
||||
|
||||
return; |
||||
} |
||||
$io->write('Unable to update __APP_NAME__ value.'); |
||||
} |
||||
} |
||||
@ -0,0 +1,91 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
use App\Model\Entity\Attachment; |
||||
use Cake\Core\Configure; |
||||
use Cake\Http\Exception\MethodNotAllowedException; |
||||
use Cake\Http\Response; |
||||
use Cake\View\JsonView; |
||||
use Exception; |
||||
use Cake\Http\Client; |
||||
|
||||
class AiServicesController extends AppController |
||||
{ |
||||
private Client $client; |
||||
|
||||
public function initialize(): void |
||||
{ |
||||
parent::initialize(); |
||||
$this->viewBuilder()->setClassName(JsonView::class); |
||||
$this->client = new Client([ |
||||
'timeout' => 120 |
||||
]); |
||||
} |
||||
|
||||
public function autocomplete(): Response |
||||
{ |
||||
if (!$this->request->is('post')) { |
||||
$this->respond(405, "Method not allowed"); |
||||
} |
||||
|
||||
$isAiServiceEnabled = Configure::read('App.aiServiceEnabled'); |
||||
|
||||
if(!$isAiServiceEnabled) { |
||||
return $this->respond(403, "AI Service is disabled"); |
||||
} |
||||
|
||||
$request = $this->request->getData(); |
||||
$type = $request['type'] ?? null; |
||||
$documentHash = $request['documentHash'] ?? null; |
||||
|
||||
if (!$type || !$documentHash) { |
||||
return $this->respond(400, "Missing parameters"); |
||||
} |
||||
|
||||
$attachment = $this->findAttachment($documentHash); |
||||
|
||||
if (!$attachment) { |
||||
return $this->respond(404, "Attachment not found"); |
||||
} |
||||
|
||||
$file_name = $attachment->file_name; |
||||
$container_co_id = $attachment->container_controllable_object_id; |
||||
$path = Configure::read('App.attachmentsPath') . "/" . $container_co_id . "/" . $file_name; |
||||
$output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); |
||||
|
||||
if ($output === false) { |
||||
return $this->respond(404, "File not found or could not be opened"); |
||||
} |
||||
return $this->callAiServiceAndRespond($request['type'], $request['documentHash'], $output); |
||||
} |
||||
|
||||
private function callAiServiceAndRespond(string $type, string $documentHash, string $fileContent): Response |
||||
{ |
||||
try { |
||||
$postData = json_encode([ |
||||
'type' => $type, |
||||
'documentHash' => $documentHash, |
||||
'fileContent' => base64_encode($fileContent), |
||||
]); |
||||
$apiResponse = $this->client->post(Configure::read('App.aiServiceUrl'),$postData, ['type' => "json"]); |
||||
|
||||
if ($apiResponse->isOk()) { |
||||
return $this->respond(200, ['result' => $apiResponse->getJson()]); |
||||
} else { |
||||
return $this->respond($apiResponse->getStatusCode(), "API Error: " . $apiResponse->getStatusCode()); |
||||
} |
||||
} catch (Exception $e) { |
||||
return $this->respond(500, $e->getMessage()); |
||||
} |
||||
} |
||||
|
||||
private function findAttachment(string $documentHash): Attachment |
||||
{ |
||||
return $this->fetchTable('Attachments')->find() |
||||
->contain(['ContainerControllableObjects']) |
||||
->where(['file_name' => $documentHash]) |
||||
->first(); |
||||
} |
||||
} |
||||
@ -0,0 +1,74 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* |
||||
* Licensed under The MIT License |
||||
* For full copyright and license information, please see the LICENSE.txt |
||||
* Redistributions of files must retain the above copyright notice. |
||||
* |
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* @link https://cakephp.org CakePHP(tm) Project |
||||
* @since 0.2.9 |
||||
* @license https://opensource.org/licenses/mit-license.php MIT License |
||||
*/ |
||||
namespace App\Controller\Api; |
||||
|
||||
use Cake\Controller\Controller; |
||||
use Cake\Http\Response; |
||||
use App\Model\Entity\User; |
||||
|
||||
/** |
||||
* Application Controller |
||||
* |
||||
* Add your application-wide methods in the class below, your controllers |
||||
* will inherit them. |
||||
* |
||||
* @link https://book.cakephp.org/4/en/controllers.html#the-app-controller |
||||
*/ |
||||
class AppController extends Controller |
||||
{ |
||||
protected $nopaginate; |
||||
public ?User $logged_user = null; |
||||
|
||||
|
||||
/** |
||||
* Initialization hook method. |
||||
* |
||||
* Use this method to add common initialization code like loading components. |
||||
* |
||||
* e.g. `$this->loadComponent('FormProtection');` |
||||
* |
||||
* @return void |
||||
*/ |
||||
public function initialize(): void |
||||
{ |
||||
parent::initialize(); |
||||
|
||||
$this->loadComponent('Authentication.Authentication'); |
||||
|
||||
$this->logged_user = $this->Authentication->getIdentity(); |
||||
$this->nopaginate = $this->request->getQuery('nopaginate') !== null && $this->request->getQuery('nopaginate'); |
||||
} |
||||
|
||||
/** |
||||
* respond |
||||
* |
||||
* @param Int $code |
||||
* @param null|Object|Array|String $bodyResponse |
||||
* @param String $content |
||||
* @return Response |
||||
*/ |
||||
public function respond(Int $code = 200, null|Object|Array|String $bodyResponse = null, String $content = "application/json") : Response |
||||
{ |
||||
$bodyResponse = is_object($bodyResponse) || is_array($bodyResponse) ? $bodyResponse : ['result' => $bodyResponse]; |
||||
$response = $this->getResponse(); |
||||
$response = $response->withHeader('Access-Control-Allow-Origin', '*'); |
||||
$response = $response->withHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE, PUT'); |
||||
$response = $response->withHeader('Access-Control-Max-Age', '60'); |
||||
$response = $response->withHeader('Access-Control-Allow-Headers', 'x-requested-with, Content-Type, origin, authorization, accept, client-security-token'); |
||||
return $response->withStringBody(json_encode($bodyResponse))->withStatus($code)->withType($content); |
||||
} |
||||
} |
||||
@ -0,0 +1,53 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller\Api; |
||||
|
||||
use App\Controller\Api\AppController; |
||||
use Cake\Core\Configure; |
||||
|
||||
/** |
||||
* Attachments Controller |
||||
* |
||||
* @property \App\Model\Table\AttachmentsTable $Attachments |
||||
* @method \App\Model\Entity\Attachment[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class AttachmentsController extends AppController |
||||
{ |
||||
public function index() {return $this->respond(400, "not implemented");} |
||||
public function add() {return $this->respond(400, "not implemented");} |
||||
public function edit($id = null) {return $this->respond(400, "not implemented");} |
||||
public function delete($id = null) {return $this->respond(400, "not implemented");} |
||||
|
||||
/** |
||||
* View method |
||||
* |
||||
* @param string|null $hash Attachment hash. |
||||
* @return \Cake\Http\Response|void |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function view($hash) |
||||
{ |
||||
$attachment = $this->fetchTable('Attachments')->find() |
||||
->contain(['ContainerControllableObjects']) |
||||
->where(['file_name' => $hash]) |
||||
->first(); |
||||
|
||||
if (!$attachment) return $this->respond(404, __('Allegato non trovato')); |
||||
if (!$this->logged_user->canHandleAttachmentsForControllableObject($attachment->container_controllable_object)) return $this->respond(403, __('Non hai i permessi necessari per visionare l\'allegato')); |
||||
|
||||
$mimetype = $attachment->mimetype; |
||||
$file_name = $attachment->file_name; |
||||
$original_file_name = $attachment->original_file_name; |
||||
$container_co_id = $attachment->container_controllable_object_id; |
||||
$path = Configure::read('App.attachmentsPath') . "/" . $container_co_id . "/" . $file_name; |
||||
$output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); |
||||
$this->response = $this->response |
||||
->withAddedHeader('Content-Disposition', 'filename="' . $original_file_name . '"') |
||||
->withCharset('UTF-8') |
||||
->withType($mimetype) |
||||
->withStringBody($output); |
||||
|
||||
return $this->response; |
||||
} |
||||
} |
||||
@ -0,0 +1,70 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* |
||||
* Licensed under The MIT License |
||||
* For full copyright and license information, please see the LICENSE.txt |
||||
* Redistributions of files must retain the above copyright notice. |
||||
* |
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* @link https://cakephp.org CakePHP(tm) Project |
||||
* @since 3.3.4 |
||||
* @license https://opensource.org/licenses/mit-license.php MIT License |
||||
*/ |
||||
namespace App\Controller\Api; |
||||
|
||||
use Cake\Event\EventInterface; |
||||
|
||||
/** |
||||
* Error Handling Controller |
||||
* |
||||
* Controller used by ExceptionRenderer to render error responses. |
||||
*/ |
||||
class ErrorController extends AppController |
||||
{ |
||||
/** |
||||
* Initialization hook method. |
||||
* |
||||
* @return void |
||||
*/ |
||||
public function initialize(): void |
||||
{ |
||||
parent::initialize(); |
||||
} |
||||
|
||||
/** |
||||
* beforeFilter callback. |
||||
* |
||||
* @param \Cake\Event\EventInterface $event Event. |
||||
* @return \Cake\Http\Response|null|void |
||||
*/ |
||||
public function beforeFilter(EventInterface $event) |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* beforeRender callback. |
||||
* |
||||
* @param \Cake\Event\EventInterface $event Event. |
||||
* @return \Cake\Http\Response|null|void |
||||
*/ |
||||
public function beforeRender(EventInterface $event) |
||||
{ |
||||
parent::beforeRender($event); |
||||
|
||||
$this->viewBuilder()->setTemplatePath('Error'); |
||||
} |
||||
|
||||
/** |
||||
* afterFilter callback. |
||||
* |
||||
* @param \Cake\Event\EventInterface $event Event. |
||||
* @return \Cake\Http\Response|null|void |
||||
*/ |
||||
public function afterFilter(EventInterface $event) |
||||
{ |
||||
} |
||||
} |
||||
@ -0,0 +1,156 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller\Api; |
||||
|
||||
use App\Controller\Api\AppController; |
||||
use Cake\Core\Configure; |
||||
use Cake\I18n\DateTime; |
||||
|
||||
/** |
||||
* Notifications Controller |
||||
* |
||||
* @property \App\Model\Table\NotificationsTable $Notifications |
||||
* @method \App\Model\Entity\Notification[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class NotificationsController extends AppController |
||||
{ |
||||
public function view($id = null) {return $this->respond(400, "not implemented");} |
||||
public function delete($id = null) {return $this->respond(400, "not implemented");} |
||||
|
||||
/** |
||||
* index |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function index() |
||||
{ |
||||
$notifications = $this->fetchTable('Notifications')->find() |
||||
->contain(['NotificationTypes']) |
||||
->where(['user_id' => $this->logged_user->id, 'read_by_user IS NULL']) |
||||
->order(['created' => 'DESC']) |
||||
->formatResults(function (\Cake\Collection\CollectionInterface $notifications) { |
||||
return $notifications |
||||
->map(function ($notification) { |
||||
if ($notification->already_mapped) return $notification; |
||||
$notification->already_mapped = true; |
||||
$notification->setHidden(array_merge($notification->getHidden(), ['already_mapped'])); |
||||
$notification->info = json_decode($notification->info); |
||||
$webURL = Configure::read('App.weburl'); |
||||
$notification->info->weblink = $webURL . $notification->info->link; |
||||
$notification->info->link = '/api' . $notification->info->link; |
||||
return $notification; |
||||
}); |
||||
}); |
||||
|
||||
/** |
||||
* Default pagination settings. |
||||
* |
||||
* When calling paginate() these settings will be merged with the configuration |
||||
* you provide. |
||||
* |
||||
* - `maxLimit` - The maximum limit users can choose to view. Defaults to 100 |
||||
* - `limit` - The initial number of items per page. Defaults to 20. |
||||
* - `page` - The starting page, defaults to 1. |
||||
* - `allowedParameters` - A list of parameters users are allowed to set using request |
||||
* parameters. Modifying this list will allow users to have more influence |
||||
* over pagination, be careful with what you permit. |
||||
* - `sortableFields` - A list of fields which can be used for sorting. By |
||||
* default all table columns can be used for sorting. You can use this option |
||||
* to restrict sorting only by particular fields. If you want to allow |
||||
* sorting on either associated columns or calculated fields then you will |
||||
* have to explicitly specify them (along with other fields). Using an empty |
||||
* array will disable sorting alltogether. |
||||
* - `finder` - The table finder to use. Defaults to `all`. |
||||
* - `scope` - If specified this scope will be used to get the paging options |
||||
* from the query params passed to paginate(). Scopes allow namespacing the |
||||
* paging options and allows paginating multiple models in the same action. |
||||
* Default `null`. |
||||
* |
||||
* protected array $_defaultConfig = [ |
||||
* 'page' => 1, |
||||
* 'limit' => 20, |
||||
* 'maxLimit' => 100, |
||||
* 'allowedParameters' => ['limit', 'sort', 'page', 'direction'], |
||||
* 'sortableFields' => null, |
||||
* 'finder' => 'all', |
||||
* 'scope' => null, |
||||
* ]; |
||||
*/ |
||||
|
||||
try { |
||||
$paginated_notifications = $this->paginate($notifications, [ |
||||
'maxLimit' => 100, |
||||
'limit' => 100, |
||||
]); |
||||
return $this->respond(200, ['notifications' => $paginated_notifications, 'pagination' => $paginated_notifications->pagingParams()]); |
||||
} catch (\Cake\Http\Exception\NotFoundException $th) { |
||||
return $this->respond(404, ['result' => $th->getMessage()]); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* count |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function count() |
||||
{ |
||||
$notifications_count = $this->fetchTable('Notifications')->find() |
||||
->where(['user_id' => $this->logged_user->id, 'read_by_user IS NULL']) |
||||
->count(); |
||||
return $this->respond(200, ['count' => $notifications_count]); |
||||
} |
||||
|
||||
/** |
||||
* add |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function add() |
||||
{ |
||||
if (!$this->logged_user->hasCapability(['notifications.read_all'])) { |
||||
return $this->respond(403, ['capabilities' => ['notifications.read_all']]); |
||||
} |
||||
$userId = $this->logged_user->id; |
||||
$this->fetchTable('Notifications')->updateAll(['read_by_user' => DateTime::now()], ['read_by_user IS NULL', 'user_id' => $userId]); |
||||
return $this->respond(201, "all notifications has been marked as read"); |
||||
} |
||||
|
||||
/** |
||||
* edit |
||||
* |
||||
* @param Int $id |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function edit($id = null) |
||||
{ |
||||
$notification = $this->fetchTable('Notifications')->get($id); |
||||
$userId = $this->logged_user->id; |
||||
if($notification->user_id != $userId) |
||||
{ |
||||
return $this->respond(403, "access unauthorised"); |
||||
} |
||||
if($notification->read_by_user) |
||||
{ |
||||
return $this->respond(400, "notification has already been read"); |
||||
} |
||||
$notification->read_by_user = DateTime::now(); |
||||
|
||||
if(!$this->fetchTable('Notifications')->save($notification)) |
||||
{ |
||||
return $this->respond(400, ['error' => $notification->getErrors()]); |
||||
} |
||||
$notification->info = json_decode($notification->info); |
||||
return $this->respond(201, ['notification' => $notification]); |
||||
} |
||||
|
||||
public function check() |
||||
{ |
||||
$notifications_count = $this->fetchTable('Notifications')->find() |
||||
->where(['user_id' => $this->logged_user->id, 'read_by_user IS NULL']) |
||||
->count(); |
||||
return $this->respond(200, ['result' => $notifications_count != 0]); |
||||
|
||||
} |
||||
} |
||||
@ -0,0 +1,31 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller\Api; |
||||
|
||||
use App\Controller\Api\AppController; |
||||
|
||||
/** |
||||
* OrganisationTypes Controller |
||||
* |
||||
* @property \App\Model\Table\OrganisationTypesTable $OrganisationTypes |
||||
* @method \App\Model\Entity\OrganisationType[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class OrganisationTypesController extends AppController |
||||
{ |
||||
public function add($id = null) {return $this->respond(400, "not implemented");} |
||||
public function view($id = null) {return $this->respond(400, "not implemented");} |
||||
public function edit($id = null) {return $this->respond(400, "not implemented");} |
||||
public function delete($id = null) {return $this->respond(400, "not implemented");} |
||||
|
||||
/** |
||||
* index |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function index() |
||||
{ |
||||
$organisationTypes = $this->fetchTable('OrganisationTypes')->find('list')->order(['OrganisationTypes.description' => 'ASC']); |
||||
return $this->respond(200, ['organisation_types' => $organisationTypes]); |
||||
} |
||||
} |
||||
@ -0,0 +1,157 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller\Api; |
||||
|
||||
use App\Controller\Api\AppController; |
||||
use Cake\Core\Configure; |
||||
|
||||
/** |
||||
* Organisations Controller |
||||
* |
||||
* @property \App\Model\Table\OrganisationsTable $Organisations |
||||
* @method \App\Model\Entity\Organisation[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class OrganisationsController extends AppController |
||||
{ |
||||
public function add() {return $this->respond(400, "not implemented");} |
||||
public function edit($id = null) {return $this->respond(400, "not implemented");} |
||||
public function delete($id = null) {return $this->respond(400, "not implemented");} |
||||
|
||||
/** |
||||
* index |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function index() |
||||
{ |
||||
$options = ['type' => $this->request->getQuery('type') ?? null]; |
||||
|
||||
$user_can_index = $this->fetchTable('Organisations')->can_index($this->logged_user, $options); |
||||
|
||||
if (!$user_can_index) |
||||
{ |
||||
return $this->respond(403, $options['error']); |
||||
} |
||||
|
||||
$organisations = $this->fetchTable('Organisations') |
||||
->find($options['finder'], params: $options) |
||||
->contain(['Actors', 'OrganisationTypes']) |
||||
->formatResults(function (\Cake\Collection\CollectionInterface $organisations) { |
||||
return $organisations |
||||
->map(function ($organisation) { |
||||
if ($organisation->already_mapped) return $organisation; |
||||
$organisation->already_mapped = true; |
||||
$organisation->setHidden(array_merge($organisation->getHidden(), ['already_mapped', 'phone', 'mobile', 'fax', 'email', 'organisation_type_id', 'actor_id', 'incident_creator', 'pec', 'deleted', 'incident_default_tab', 'loggable_object_id', 'controllable_object_interface_id'])); |
||||
$organisation->actor->setHidden(array_merge($organisation->actor->getHidden(), ['actor_type_id', 'interoperability_identifier', 'incident_type_group_id', 'deleted'])); |
||||
return $organisation; |
||||
}); |
||||
}); |
||||
|
||||
$organisations = $this->fetchTable('Organisations')->applySearchParams($organisations, $this->request->getQueryParams()); |
||||
|
||||
/** |
||||
* Default pagination settings. |
||||
* |
||||
* When calling paginate() these settings will be merged with the configuration |
||||
* you provide. |
||||
* |
||||
* - `maxLimit` - The maximum limit users can choose to view. Defaults to 100 |
||||
* - `limit` - The initial number of items per page. Defaults to 20. |
||||
* - `page` - The starting page, defaults to 1. |
||||
* - `allowedParameters` - A list of parameters users are allowed to set using request |
||||
* parameters. Modifying this list will allow users to have more influence |
||||
* over pagination, be careful with what you permit. |
||||
* - `sortableFields` - A list of fields which can be used for sorting. By |
||||
* default all table columns can be used for sorting. You can use this option |
||||
* to restrict sorting only by particular fields. If you want to allow |
||||
* sorting on either associated columns or calculated fields then you will |
||||
* have to explicitly specify them (along with other fields). Using an empty |
||||
* array will disable sorting alltogether. |
||||
* - `finder` - The table finder to use. Defaults to `all`. |
||||
* - `scope` - If specified this scope will be used to get the paging options |
||||
* from the query params passed to paginate(). Scopes allow namespacing the |
||||
* paging options and allows paginating multiple models in the same action. |
||||
* Default `null`. |
||||
* |
||||
* protected array $_defaultConfig = [ |
||||
* 'page' => 1, |
||||
* 'limit' => 20, |
||||
* 'maxLimit' => 100, |
||||
* 'allowedParameters' => ['limit', 'sort', 'page', 'direction'], |
||||
* 'sortableFields' => null, |
||||
* 'finder' => 'all', |
||||
* 'scope' => null, |
||||
* ]; |
||||
*/ |
||||
|
||||
try { |
||||
$paginated_organisations = $this->paginate($organisations, [ |
||||
'maxLimit' => 100, |
||||
'limit' => 100, |
||||
'sortableFields' => ['Actors.description', 'OrganisationTypes.description', 'acronym', 'address', 'district', 'cap', 'province'], |
||||
'order' => [ |
||||
'Actors.description' => 'ASC' |
||||
], |
||||
]); |
||||
return $this->respond(200, ['organisations' => $paginated_organisations, 'pagination' => $paginated_organisations->pagingParams()]); |
||||
} catch (\Cake\Http\Exception\NotFoundException $th) { |
||||
return $this->respond(404, ['result' => $th->getMessage()]); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* view |
||||
* |
||||
* @param Int $id |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function view($id = null) |
||||
{ |
||||
$options = []; |
||||
|
||||
$organisation = $this->fetchTable('Organisations')->get($id, contain: ['Actors', 'OrganisationTypes']); |
||||
|
||||
$organisation->setHidden(array_merge($organisation->getHidden(), ['phone', 'mobile', 'fax', 'email', 'organisation_type_id', 'actor_id', 'incident_creator', 'pec', 'deleted', 'incident_default_tab', 'loggable_object_id', 'controllable_object_interface_id'])); |
||||
$organisation->actor->setHidden(array_merge($organisation->actor->getHidden(), ['actor_type_id', 'interoperability_identifier', 'incident_type_group_id', 'deleted'])); |
||||
|
||||
if (($this->logged_user->organisation_id == $id) && (!$organisation->can_view($this->logged_user, $options))) { |
||||
return $this->respond(403, $options['error']); |
||||
} |
||||
|
||||
$organisation->deliveries = $organisation->actor->getContactsList(); |
||||
|
||||
return $this->respond(200, ['organisation' => $organisation]); |
||||
} |
||||
|
||||
/** |
||||
* getPhoto |
||||
* |
||||
* @param String $file_name |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function getPhoto($file_name) |
||||
{ |
||||
$options = []; |
||||
|
||||
$organisation = $this->fetchTable('Organisations')->find() |
||||
->where(['Organisations.photo' => $file_name]) |
||||
->first(); |
||||
|
||||
if (!$organisation) { |
||||
return $this->respond(404, __('Organizzazione non trovata!')); |
||||
} |
||||
if (!$organisation->can_view($this->logged_user, $options)) { |
||||
return $this->respond(403, $options['error']); |
||||
} |
||||
|
||||
$mimetype = "image/jpeg"; |
||||
$path = Configure::read('App.organisationPhotoPath') . "/" . $file_name; |
||||
$output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); |
||||
$this->response = $this->response |
||||
->withType($mimetype) |
||||
->withStringBody($output); |
||||
|
||||
return $this->response; |
||||
} |
||||
} |
||||
@ -0,0 +1,67 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller\Api; |
||||
|
||||
use App\Controller\Api\AppController; |
||||
|
||||
/** |
||||
* Subscriptions Controller |
||||
* |
||||
* @property \App\Model\Table\PushNotificationsTable $PushNotifications |
||||
* @method \App\Model\Entity\PushNotification[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class SubscriptionsController extends AppController |
||||
{ |
||||
public function add() {return $this->respond(400, "not implemented");} |
||||
public function view($id = null) {return $this->respond(400, "not implemented");} |
||||
public function edit($id = null) {return $this->respond(400, "not implemented");} |
||||
public function delete($id = null) {return $this->respond(400, "not implemented");} |
||||
|
||||
/** |
||||
* subscribe |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function subscribe() |
||||
{ |
||||
$token = $this->request->getData('token') ?? null; |
||||
if (empty($token)) { |
||||
return $this->respond(400, ['error' => 'invalid subscribe token']); |
||||
} |
||||
$push_notification = $this->fetchTable('PushNotifications') |
||||
->newEntity([ |
||||
'value' => $token, |
||||
'enable_notifications' => true, |
||||
'delivery' => [ |
||||
'actor_id' => $this->logged_user->actor_id, |
||||
'delivery_type_id' => 0, |
||||
], |
||||
]); |
||||
|
||||
$result = $this->fetchTable('PushNotifications')->save($push_notification); |
||||
$status_code = is_object($result) && get_class($result) === "App\Model\Entity\PushNotification" ? 201 : 400; |
||||
$message = $status_code == 201 ? $push_notification : $push_notification->getErrors(); |
||||
return $this->respond($status_code, ['result' => $message]); |
||||
} |
||||
|
||||
/** |
||||
* unsubscribe |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function unsubscribe() |
||||
{ |
||||
$user_push_notification_tokens = $this->fetchTable('Deliveries') |
||||
->find() |
||||
->where(['Deliveries.actor_id' => $this->logged_user->actor_id, 'Deliveries.delivery_type_id' => 0]) |
||||
->all(); |
||||
|
||||
foreach ($user_push_notification_tokens as $user_push_notification_token) { |
||||
if (!$this->fetchTable('Deliveries')->delete($user_push_notification_token)) { |
||||
return $this->respond(500, ['result' => $user_push_notification_token->getErrors()]); |
||||
} |
||||
} |
||||
return $this->respond(200, ['unsubscribed' => $user_push_notification_tokens->count()]); |
||||
} |
||||
} |
||||
@ -0,0 +1,230 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller\Api; |
||||
|
||||
use App\Controller\Api\AppController; |
||||
use Cake\Event\EventInterface; |
||||
use Firebase\JWT\JWT; |
||||
use Cake\Core\Configure; |
||||
/** |
||||
* Users Controller |
||||
* |
||||
* @property \App\Model\Table\UsersTable $Users |
||||
* @method \App\Model\Entity\User[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class UsersController extends AppController |
||||
{ |
||||
public function beforeFilter(EventInterface $event) |
||||
{ |
||||
$this->Authentication->allowUnauthenticated(['login']); |
||||
} |
||||
|
||||
public function add() {return $this->respond(400, "not implemented");} |
||||
public function edit($id = null) {return $this->respond(400, "not implemented");} |
||||
public function delete($id = null) {return $this->respond(400, "not implemented");} |
||||
|
||||
/** |
||||
* index |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function index() |
||||
{ |
||||
$options = []; |
||||
|
||||
$user_can_index = $this->fetchTable('Users')->can_index($this->logged_user, $options); |
||||
|
||||
if (!$user_can_index) |
||||
{ |
||||
return $this->respond(403, $options['error']); |
||||
} |
||||
|
||||
$users = $this->fetchTable('Users') |
||||
->find($options['finder'], params: $options) |
||||
->contain(['UserActors', 'Organisations' => ['Actors']]) |
||||
->formatResults(function (\Cake\Collection\CollectionInterface $users) { |
||||
return $users |
||||
->map(function ($user) { |
||||
if ($user->already_mapped) return $user; |
||||
$user->already_mapped = true; |
||||
$user->setHidden(array_merge($user->getHidden(), ['already_mapped', 'organisation_id', 'phone', 'mobile', 'mobile2', 'email', 'notification_hash', 'fax', 'change_password', 'last_login', 'last_registered_request', 'from_mobile', 'last_ip_address', 'language_id', 'privacy', 'conditions', 'password_recovery_token', 'last_change_password', 'password_recovery_counter', 'email2', 'actor_id', 'ambiguity_verified', 'invalid_login_date', 'invalid_login_count', 'deleted', 'loggable_object_id', 'email2_wd'])); |
||||
$user->user_actor->setHidden(array_merge($user->user_actor->getHidden(), ['actor_type_id', 'interoperability_identifier', 'incident_type_group_id', 'deleted'])); |
||||
$user->organisation_description = $user->organisation->actor->description; |
||||
$user->birthday = $user->birthday?->format('d/m/Y'); |
||||
return $user; |
||||
}); |
||||
}); |
||||
|
||||
$users = $this->fetchTable('Users')->applySearchParams($users, $this->request->getQueryParams()); |
||||
|
||||
/** |
||||
* Default pagination settings. |
||||
* |
||||
* When calling paginate() these settings will be merged with the configuration |
||||
* you provide. |
||||
* |
||||
* - `maxLimit` - The maximum limit users can choose to view. Defaults to 100 |
||||
* - `limit` - The initial number of items per page. Defaults to 20. |
||||
* - `page` - The starting page, defaults to 1. |
||||
* - `allowedParameters` - A list of parameters users are allowed to set using request |
||||
* parameters. Modifying this list will allow users to have more influence |
||||
* over pagination, be careful with what you permit. |
||||
* - `sortableFields` - A list of fields which can be used for sorting. By |
||||
* default all table columns can be used for sorting. You can use this option |
||||
* to restrict sorting only by particular fields. If you want to allow |
||||
* sorting on either associated columns or calculated fields then you will |
||||
* have to explicitly specify them (along with other fields). Using an empty |
||||
* array will disable sorting alltogether. |
||||
* - `finder` - The table finder to use. Defaults to `all`. |
||||
* - `scope` - If specified this scope will be used to get the paging options |
||||
* from the query params passed to paginate(). Scopes allow namespacing the |
||||
* paging options and allows paginating multiple models in the same action. |
||||
* Default `null`. |
||||
* |
||||
* protected array $_defaultConfig = [ |
||||
* 'page' => 1, |
||||
* 'limit' => 20, |
||||
* 'maxLimit' => 100, |
||||
* 'allowedParameters' => ['limit', 'sort', 'page', 'direction'], |
||||
* 'sortableFields' => null, |
||||
* 'finder' => 'all', |
||||
* 'scope' => null, |
||||
* ]; |
||||
*/ |
||||
|
||||
try { |
||||
$paginated_users = $this->paginate($users, [ |
||||
'maxLimit' => 100, |
||||
'limit' => 100, |
||||
'sortableFields' => ['UserActors.description', 'username', 'surname', 'name', 'cap', 'gender'], |
||||
'order' => [ |
||||
'Users.surname' => 'ASC', |
||||
], |
||||
]); |
||||
return $this->respond(200, ['users' => $paginated_users, 'pagination' => $paginated_users->pagingParams()]); |
||||
} catch (\Cake\Http\Exception\NotFoundException $th) { |
||||
return $this->respond(404, ['result' => $th->getMessage()]); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* view |
||||
* |
||||
* @param Int $id |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function view($id) |
||||
{ |
||||
$options = []; |
||||
|
||||
$user = $this->fetchTable('Users')->get($id, contain: ['UserActors', 'Organisations' => ['Actors', 'OrganisationTypes']]); |
||||
|
||||
if ($user->id != $this->logged_user->id && (!$user->can_view($this->logged_user, $options))) { |
||||
return $this->respond(403, $options['error']); |
||||
} |
||||
|
||||
$user->setHidden(array_merge($user->getHidden(), ['fax', 'email', 'mobile2', 'mobile', 'email2', 'phone', 'organisation_id', 'notification_hash', 'change_password', 'last_login', 'last_registered_request', 'from_mobile', 'last_ip_address', 'language_id', 'privacy', 'conditions', 'password_recovery_token', 'last_change_password', 'password_recovery_counter', 'actor_id', 'ambiguity_verified', 'invalid_login_date', 'invalid_login_count', 'deleted', 'loggable_object_id', 'email2_wd'])); |
||||
$user->actor = $user->user_actor; |
||||
unset($user->user_actor); |
||||
$user->actor->setHidden(array_merge($user->actor->getHidden(), ['actor_type_id', 'interoperability_identifier', 'incident_type_group_id', 'deleted'])); |
||||
$user->organisation_description = null; |
||||
if ($user->hasValue('organisation')) { |
||||
$user->organisation->setHidden(array_merge($user->organisation->getHidden(), ['phone', 'mobile', 'fax', 'email', 'organisation_type_id', 'actor_id', 'incident_creator', 'pec', 'deleted', 'incident_default_tab', 'loggable_object_id', 'controllable_object_interface_id'])); |
||||
$user->organisation_description = $user->organisation->actor->description; |
||||
unset($user->organisation->actor); |
||||
} |
||||
|
||||
$user->deliveries = $user->actor->getContactsList(); |
||||
|
||||
return $this->respond(200, ['user' => $user]); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* login |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function login() |
||||
{ |
||||
$result = $this->Authentication->getResult(); |
||||
// If the user is logged in send them away. |
||||
if ($result->isValid()) { |
||||
$receivedData = $this->getRequest()->getData(); |
||||
$client_id = isset($receivedData['client_id']) && $receivedData['client_id'] != "" ? $receivedData['client_id'] : 'auto-' . bin2hex(random_bytes(32)); |
||||
$platform = isset($receivedData['platform']) ? $receivedData['platform'] : 'unknown'; |
||||
$tokenExpirationTime = Configure::read('App.jwt.expiration_time'); |
||||
|
||||
$token = JWT::encode([ |
||||
'sub' => $this->Authentication->getIdentity()->get('username'), |
||||
'user_id' => $this->Authentication->getIdentity()->get('id'), |
||||
'exp' => time() + $tokenExpirationTime, |
||||
'client_id' => $client_id, |
||||
'platform' => $platform, |
||||
], file_get_contents(Configure::read('App.jwt.keys.private')), Configure::read('App.jwt.algorithm')); |
||||
|
||||
$user = $this->fetchTable('Users')->get($this->Authentication->getIdentity()->get('id')); |
||||
$user->setHidden(['password', 'phone', 'mobile', 'mobile2', 'email', 'mobile_token_date', 'mobile_token', 'notification_hash', 'fax', 'change_password', 'last_login', 'last_registered_request', 'from_mobile', 'last_ip_address', 'position', 'position_date', 'ask_new_password', 'password_expiration', 'password_recovery_token', 'password_recovery_counter', 'email2', 'ambiguity_verified', 'invalid_login_date', 'invalid_login_count', 'deleted', 'loggable_object_id', 'email2_wd', 'make_volunteer', 'full_name', 'capabilities']); |
||||
|
||||
$user->mobile_menu = $this->fetchTable('MobileComponents') |
||||
->find() |
||||
->matching('Capabilities') |
||||
->where(['Capabilities.id IN' => $user->getCapabilityIds(true)]) |
||||
->order(['MobileComponents.id' => 'ASC']) |
||||
->distinct(['MobileComponents.menu_item']) |
||||
->select('MobileComponents.menu_item') |
||||
->toArray(); |
||||
|
||||
$user->notifications = $this->fetchTable('Notifications')->find() |
||||
->contain(['NotificationTypes']) |
||||
->where(['user_id' => $user->id, 'read_by_user IS NULL']) |
||||
->order(['created' => 'DESC']) |
||||
->formatResults(function (\Cake\Collection\CollectionInterface $notifications) { |
||||
return $notifications |
||||
->map(function ($notification) { |
||||
$notification->info = json_decode($notification->info); |
||||
$webURL = Configure::read('App.weburl'); |
||||
$notification->info->weblink = $webURL . $notification->info->link; |
||||
$notification->info->link = '/api' . $notification->info->link; |
||||
return $notification; |
||||
}); |
||||
})->count() != 0; |
||||
return $this->respond(200, ['token' => $token, 'user' => $user, 'mobile_menu' => $user->mobile_menu]); |
||||
} |
||||
if ($this->request->is('post')) { |
||||
return $this->respond(401, ['error' => 'invalid credentials']); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* getPhoto |
||||
* |
||||
* @param String $file_name |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function getPhoto($file_name) |
||||
{ |
||||
$options = []; |
||||
|
||||
$user = $this->fetchTable('Users')->find() |
||||
->where(['Users.photo' => $file_name]) |
||||
->first(); |
||||
|
||||
if (!$user) { |
||||
return $this->respond(404, __('Utente non trovato!')); |
||||
} |
||||
if (!$user->can_view($this->logged_user, $options)) { |
||||
return $this->respond(403, $options['error']); |
||||
} |
||||
|
||||
$mimetype = "image/jpeg"; |
||||
$path = Configure::read('App.organisationPhotoPath') . "/" . $file_name; |
||||
$output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); |
||||
$this->response = $this->response |
||||
->withType($mimetype) |
||||
->withStringBody($output); |
||||
|
||||
return $this->response; |
||||
} |
||||
} |
||||
@ -0,0 +1,75 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller\Api; |
||||
|
||||
use App\Controller\Api\AppController; |
||||
use App\WGS\Geo\Geocoding; |
||||
use App\WGS\Geo\GeoValidation; |
||||
use App\WGS\SnapshotsHandler\SnapshotsHandler; |
||||
use Cake\Event\EventInterface; |
||||
use Firebase\JWT\JWT; |
||||
use Cake\Core\Configure; |
||||
use Cake\I18n\DateTime; |
||||
|
||||
/** |
||||
* WaterDrawingDerivations Controller |
||||
* |
||||
* @property \App\Model\Table\WaterDrawingDerivationsTable $UseWaterDrawingDerivationsrs |
||||
* @method \App\Model\Entity\User[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class WaterDrawingDerivationsController extends AppController |
||||
{ |
||||
public function view($id){ |
||||
$waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->find()->where(['WaterDrawingDerivations.id' => $id])->first(); |
||||
if(!isset($waterDrawingDerivation)) return $this->respond(500, ['message' => 'Punto di derivazione non trovato.']); |
||||
return $this->respond(200, ['WaterDrawingDerivation' => $waterDrawingDerivation]); |
||||
} |
||||
|
||||
public function update_data(){ |
||||
$data = $this->request->getData(); |
||||
$waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->find()->where(['WaterDrawingDerivations.id' => $data['water_drawing_derivation_id']])->first(); |
||||
if(!isset($waterDrawingDerivation)) return $this->respond(500, ['message' => 'Punto di derivazione non trovato.']); |
||||
$waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->patchEntity($waterDrawingDerivation, [ |
||||
'annual_volume' => $data['volume'], |
||||
'average_flow_rate' => $data['portata'] |
||||
]); |
||||
if($this->fetchTable('WaterDrawingDerivations')->save($waterDrawingDerivation)){ |
||||
SnapshotsHandler::createSnapshot($waterDrawingDerivation->water_drawing_paperwork->controllable_object_id); |
||||
return $this->respond(200, ['message' => $waterDrawingDerivation]); |
||||
}else{ |
||||
return $this->respond(500, ['message' => 'KO', 'error' => $waterDrawingDerivation->getErrors()]); |
||||
} |
||||
} |
||||
|
||||
public function update_location(){ |
||||
$data = $this->request->getData(); |
||||
$waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->find()->contain(['WaterDrawingPaperworks'])->where(['WaterDrawingDerivations.id' => $data['water_drawing_derivation_id']])->first(); |
||||
if(!isset($waterDrawingDerivation)) return $this->respond(500, ['message' => 'Punto di derivazione non trovato.']); |
||||
$feature_collection = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $data['longitude'] . ',' . $data['latitude'] . ']},"properties":null}]}'; |
||||
if(!GeoValidation::isValidGeometry(json_decode($feature_collection))) return $this->respond(500, ['message' => 'Punto di derivazione non valido.']); |
||||
$reverse_geocoding = Geocoding::performGeocoding('reverse', ['format' => 'json', 'namedetails' => '1', 'lat' => $data['latitude'], 'lon' => $data['longitude']]); |
||||
if($reverse_geocoding['status_code']['http_code'] == '200'){ |
||||
$waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->patchEntity($waterDrawingDerivation, [ |
||||
'latitude' => $data['latitude'], |
||||
'longitude' => $data['longitude'], |
||||
'feature_collection' => '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $data['longitude'] . ',' . $data['latitude'] . ']},"properties":null}]}', |
||||
'location' => isset($reverse_geocoding['contents']['address']['road']) ? $reverse_geocoding['contents']['address']['road'] : '', |
||||
'district' => isset($reverse_geocoding['contents']['address']['town']) ? $reverse_geocoding['contents']['address']['town'] : '', |
||||
'description' => isset($reverse_geocoding['contents']['display_name']) ? $reverse_geocoding['contents']['display_name'] : '' |
||||
]); |
||||
}else{ |
||||
$waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->patchEntity($waterDrawingDerivation, [ |
||||
'latitude' => $data['latitude'], |
||||
'longitude' => $data['longitude'], |
||||
'feature_collection' => '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $data['longitude'] . ',' . $data['latitude'] . ']},"properties":null}]}' |
||||
]); |
||||
} |
||||
if($this->fetchTable('WaterDrawingDerivations')->save($waterDrawingDerivation)){ |
||||
SnapshotsHandler::createSnapshot($waterDrawingDerivation->water_drawing_paperwork->controllable_object_id); |
||||
return $this->respond(200, ['message' => 'OK']); |
||||
}else{ |
||||
return $this->respond(500, ['message' => 'KO', 'error' => $waterDrawingDerivation->getErrors()]); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,47 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller\Api; |
||||
|
||||
use App\Controller\Api\AppController; |
||||
use App\WGS\SnapshotsHandler\SnapshotsHandler; |
||||
use Cake\Event\EventInterface; |
||||
use Firebase\JWT\JWT; |
||||
use Cake\Core\Configure; |
||||
use Cake\I18n\DateTime; |
||||
|
||||
/** |
||||
* WaterDrawingMeasurements Controller |
||||
* |
||||
* @property \App\Model\Table\WaterDrawingMeasurementsTable $WaterDrawingMeasurements |
||||
* @method \App\Model\Entity\User[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class WaterDrawingMeasurementsController extends AppController |
||||
{ |
||||
public function add(){ |
||||
$data = $this->request->getData(); |
||||
$WaterDrawingMeasurement = $this->fetchTable('WaterDrawingMeasurements')->newEntity([ |
||||
'volume' => $data['volume'], |
||||
'water_drawing_meter_id' => $data['water_drawing_meter_id'], |
||||
'date' => DateTime::now(), |
||||
'user_id' => $this->logged_user->id |
||||
]); |
||||
if($this->fetchTable('WaterDrawingMeasurements')->save($WaterDrawingMeasurement)){ |
||||
$waterDrawingMeter = $this->fetchTable('WaterDrawingMeters')->get($data['water_drawing_meter_id'], contain: ['WaterDrawingIntendedUses' => ['WaterDrawingPaperworks']]); |
||||
SnapshotsHandler::createSnapshot($waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork->controllable_object_id); |
||||
return $this->respond(200, ['message' => __('Salvato con successo')]); |
||||
}else{ |
||||
return $this->respond(500, ['message' => __('Errore durante il salvataggio.'), 'error' => $WaterDrawingMeasurement->getErrors()]); |
||||
} |
||||
} |
||||
|
||||
public function last_index($id){ |
||||
$WaterDrawingMeasurements = $this->fetchTable('WaterDrawingMeasurements')->find()->contain(['Users'])->where(['WaterDrawingMeasurements.water_drawing_meter_id' => $id])->order(['WaterDrawingMeasurements.date' => 'DESC', 'WaterDrawingMeasurements.id' => 'DESC'])->limit(5)->formatResults( function ($result){ |
||||
return $result->map( function ($q) { |
||||
$q->date = $q->date?->format('d/m/Y'); |
||||
return $q; |
||||
}); |
||||
})->toArray(); |
||||
return $this->respond(200, ['WaterDaringMeasurements' => $WaterDrawingMeasurements]); |
||||
} |
||||
} |
||||
@ -0,0 +1,170 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller\Api; |
||||
|
||||
use App\Controller\Api\AppController; |
||||
use Cake\Event\EventInterface; |
||||
use Firebase\JWT\JWT; |
||||
use Cake\Core\Configure; |
||||
use Cake\I18n\DateTime; |
||||
|
||||
/** |
||||
* Users Controller |
||||
* |
||||
* @property \App\Model\Table\UsersTable $Users |
||||
* @method \App\Model\Entity\User[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class WaterDrawingPaperworksController extends AppController |
||||
{ |
||||
public function index() |
||||
{ |
||||
$options = []; |
||||
|
||||
$user_can_index = $this->fetchTable('WaterDrawingPaperworks')->can_index($this->logged_user, $options); |
||||
|
||||
if (!$user_can_index) |
||||
{ |
||||
return $this->respond(403, $options['error']); |
||||
} |
||||
|
||||
$waterDrawingPaperworks = $this->fetchTable('WaterDrawingPaperworks')->find() |
||||
->contain(['ControllableObjects', 'WaterDrawingPaperworkStatuses'])->matching('Applicants'); |
||||
if ($this->logged_user->hasOnlyLowerPriorityCapability([ |
||||
'documentation.water_drawing_paperworks.view', |
||||
'documentation.water_drawing_paperworks.view_own_province' |
||||
])) { |
||||
$waterDrawingPaperworks = $waterDrawingPaperworks->where(['authority_province' => $this->logged_user?->organisation_province]); |
||||
} |
||||
$waterDrawingPaperworks = $this->fetchTable('WaterDrawingPaperworks')->applySearchParams($waterDrawingPaperworks, $this->request->getQueryParams()); |
||||
|
||||
$waterDrawingPaperworks = $waterDrawingPaperworks->distinct(['WaterDrawingPaperworks.id'])->formatResults(function ($results){ |
||||
return $results->map(function ($row) { |
||||
if ($row->already_mapped) return $row; |
||||
$row->already_mapped = true; |
||||
$row->setHidden(array_merge($row->getHidden(), ['already_mapped'])); |
||||
$row->release_date = $row->release_date?->format('d/m/Y'); |
||||
$row->expiration_date = $row->expiration_date?->format('d/m/Y'); |
||||
$row->controllable_object->created = $row->controllable_object->created?->format('d/m/Y H:i:s'); |
||||
$row->controllable_object->modified = $row->controllable_object->modified?->format('d/m/Y H:i:s'); |
||||
return $row; |
||||
}); |
||||
}); |
||||
|
||||
/** |
||||
* Default pagination settings. |
||||
* |
||||
* When calling paginate() these settings will be merged with the configuration |
||||
* you provide. |
||||
* |
||||
* - `maxLimit` - The maximum limit users can choose to view. Defaults to 100 |
||||
* - `limit` - The initial number of items per page. Defaults to 20. |
||||
* - `page` - The starting page, defaults to 1. |
||||
* - `allowedParameters` - A list of parameters users are allowed to set using request |
||||
* parameters. Modifying this list will allow users to have more influence |
||||
* over pagination, be careful with what you permit. |
||||
* - `sortableFields` - A list of fields which can be used for sorting. By |
||||
* default all table columns can be used for sorting. You can use this option |
||||
* to restrict sorting only by particular fields. If you want to allow |
||||
* sorting on either associated columns or calculated fields then you will |
||||
* have to explicitly specify them (along with other fields). Using an empty |
||||
* array will disable sorting alltogether. |
||||
* - `finder` - The table finder to use. Defaults to `all`. |
||||
* - `scope` - If specified this scope will be used to get the paging options |
||||
* from the query params passed to paginate(). Scopes allow namespacing the |
||||
* paging options and allows paginating multiple models in the same action. |
||||
* Default `null`. |
||||
* |
||||
* protected array $_defaultConfig = [ |
||||
* 'page' => 1, |
||||
* 'limit' => 20, |
||||
* 'maxLimit' => 100, |
||||
* 'allowedParameters' => ['limit', 'sort', 'page', 'direction'], |
||||
* 'sortableFields' => null, |
||||
* 'finder' => 'all', |
||||
* 'scope' => null, |
||||
* ]; |
||||
*/ |
||||
|
||||
try { |
||||
$paginated_waterDrawingPaperworks = $this->paginate($waterDrawingPaperworks, [ |
||||
'maxLimit' => 25, |
||||
'sortableFields' => ['id', 'WaterDrawingPaperworkStatuses.description', 'district', 'release_date', 'concession_duration', 'expiration_date', 'ControllableObjects.created', 'ControllableObjects.modified'], |
||||
]); |
||||
return $this->respond(200, ['waterDrawingPaperworks' => $paginated_waterDrawingPaperworks, 'pagination' => $paginated_waterDrawingPaperworks->pagingParams()]); |
||||
} catch (\Cake\Http\Exception\NotFoundException $th) { |
||||
return $this->respond(404, ['result' => $th->getMessage()]); |
||||
} |
||||
} |
||||
|
||||
public function view($id){ |
||||
$options = []; |
||||
|
||||
$user_can_index = $this->fetchTable('WaterDrawingPaperworks')->can_index($this->logged_user, $options); |
||||
|
||||
if (!$user_can_index) |
||||
{ |
||||
return $this->respond(403, $options['error']); |
||||
} |
||||
$organisation = $this->getTableLocator()->get('Organisations')->find()->where(['Organisations.id' => $this->logged_user->organisation_id])->first(); |
||||
$waterDrawingPaperwork = $this->fetchTable('WaterDrawingPaperworks')->find() |
||||
->contain([ 'WaterDrawingArticles', 'WaterDrawingFees', 'GcUsers' => ['Organisations'], 'DrarUsers' => ['Organisations'], 'WaterDrawingReturnPoints', 'WaterDrawingDerivations' => ['WaterDrawingDerivationTypes'], 'WaterDrawingPaperworkStatuses', 'ControllableObjects' => ['Attachments' => ['Tags']], 'Applicants', |
||||
'WaterDrawingAntimafiaCertificationRequests' => |
||||
function ($q){ |
||||
return $q->contain(['WaterDrawingAntimafiaCertificationRequestStatuses', 'Users'])->orderDesc('WaterDrawingAntimafiaCertificationRequests.created'); |
||||
}, |
||||
]); |
||||
if ($this->logged_user->hasOnlyLowerPriorityCapability([ |
||||
'documentation.water_drawing_paperworks.view', |
||||
'documentation.water_drawing_paperworks.view_own_province' |
||||
])) { |
||||
$waterDrawingPaperwork = $waterDrawingPaperwork->where(['authority_province' => $this->logged_user?->organisation_province]); |
||||
} |
||||
$waterDrawingPaperwork = $waterDrawingPaperwork->where(['WaterDrawingPaperworks.id' => $id]) |
||||
->formatResults(function (\Cake\Collection\CollectionInterface $results) use ($organisation){ |
||||
return $results->map(function ($row) use ($organisation){ |
||||
$row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') && ( $this->logged_user->id == $row->gc_user_id && ($row->water_drawing_paperwork_status_id === -1 || $row->water_drawing_paperwork_status_id === -5 ) || ( $this->logged_user->id == $row->drar_user_id && $row->water_drawing_paperwork_status_id === -4 )); |
||||
$row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete'); |
||||
$row->can_validate = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate') && $row->water_drawing_paperwork_status_id === -3; |
||||
$row->can_send_to_drar = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') && $row->water_drawing_paperwork_status_id === -1 && $row->check_sdd && $row->gc_user_id == $this->logged_user->id; |
||||
$row->can_send_to_gc = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') && $row->water_drawing_paperwork_status_id === -4 && $row->check_dec && $row->drar_user_id == $this->logged_user->id; |
||||
$row->can_assign_to_drar = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.assign') && $row->water_drawing_paperwork_status_id <= -2 && $organisation->organisation_type_id == 6; |
||||
$row->can_assign_to_gc = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.assign') && isset($row->gc_user->organisation->organisation_type_id) && $organisation->organisation_type_id == $row->gc_user->organisation->organisation_type_id; |
||||
if($row->water_drawing_paperwork_status_id === -5){ |
||||
$row->can_add_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.add'); |
||||
$row->can_edit_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit'); |
||||
$row->can_view_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.view'); |
||||
$row->can_add_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment') ; |
||||
$row->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); |
||||
$row->can_add_meter = $this->logged_user->hasCapability('documentation.water_drawing_meters.add'); |
||||
$row->can_add_measurements = $this->logged_user->hasCapability('documentation.water_drawing_measurements.add'); |
||||
$row->can_view_measurements = true; |
||||
} |
||||
if($row->water_drawing_paperwork_status_id == -4){ |
||||
$row->can_add_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.add'); |
||||
$row->can_edit_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit'); |
||||
$row->can_view_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.view'); |
||||
$row->can_add_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment') ; |
||||
$row->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); |
||||
$row->can_submit_antimafia_request = ($this->logged_user->id == $row->drar_user_id) && (!isset($row->water_drawing_antimafia_certification_requests[0])); |
||||
$row->can_antimafia_request_to_anac = ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.antimafia_request')) && (isset($row->water_drawing_antimafia_certification_requests[0]) && ($row->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 1)); |
||||
$row->can_request_self_certification = ($this->logged_user->id == $row->drar_user_id) && (isset($row->water_drawing_antimafia_certification_requests[0]) && (new DateTime($row->water_drawing_antimafia_certification_requests[0]->created))->diffInDays(\Cake\I18n\DateTime::now()) > 30); |
||||
$row->can_upload_antimafia_attachment = (isset($row->water_drawing_antimafia_certification_requests[0]) && ( |
||||
( ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.antimafia_request')) && !($row->check_dam)) || |
||||
( ($this->logged_user->id == $row->gc_user_id) && $row->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 3) |
||||
)); |
||||
} |
||||
return $row; |
||||
}); |
||||
})->first(); |
||||
$waterDrawingPaperwork->water_drawing_meters = $this->getTableLocator()->get('WaterDrawingMeters')->find()->contain(['WaterDrawingIntendedUses', 'WaterDrawingToolTypes', 'WaterDrawingMeasurements' => function ($q){ |
||||
return $q->contain(['Users'])->orderDesc('WaterDrawingMeasurements.date')->limit(5); |
||||
}])->where(['WaterDrawingIntendedUses.water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'WaterDrawingMeters.removal_date IS NULL'])->formatResults(function ($results){ |
||||
return $results->map(function ($row){ |
||||
$row->installation_date = $row->installation_date?->format('d/m/Y'); |
||||
return $row; |
||||
}); |
||||
})->toArray(); |
||||
return $this->respond(200, ['result' => $waterDrawingPaperwork]); |
||||
} |
||||
} |
||||
@ -0,0 +1,424 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* |
||||
* Licensed under The MIT License |
||||
* For full copyright and license information, please see the LICENSE.txt |
||||
* Redistributions of files must retain the above copyright notice. |
||||
* |
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* @link https://cakephp.org CakePHP(tm) Project |
||||
* @since 0.2.9 |
||||
* @license https://opensource.org/licenses/mit-license.php MIT License |
||||
*/ |
||||
namespace App\Controller; |
||||
|
||||
use Cake\Controller\Controller; |
||||
use Cake\Event\EventInterface; |
||||
use App\Model\Entity\User; |
||||
use App\WGS\NotificationsHandler\NotificationsHandler; |
||||
use Cake\Core\Configure; |
||||
use Cake\Http\Response; |
||||
use Cake\ORM\Query; |
||||
use Cake\I18n\DateTime; |
||||
use Cake\I18n\I18n; |
||||
use Exception; |
||||
|
||||
/** |
||||
* Application Controller |
||||
* |
||||
* Add your application-wide methods in the class below, your controllers |
||||
* will inherit them. |
||||
* |
||||
* @link https://book.cakephp.org/4/en/controllers.html#the-app-controller |
||||
*/ |
||||
class AppController extends Controller |
||||
{ |
||||
public ?User $logged_user = null; |
||||
|
||||
/** |
||||
* Initialization hook method. |
||||
* |
||||
* Use this method to add common initialization code like loading components. |
||||
* |
||||
* e.g. `$this->loadComponent('FormProtection');` |
||||
* |
||||
* @return void |
||||
*/ |
||||
public function initialize(): void |
||||
{ |
||||
parent::initialize(); |
||||
|
||||
$this->loadComponent('Authentication.Authentication'); |
||||
$this->loadComponent('Flash'); |
||||
|
||||
// recuperiamo l'entità dello user (se loggato): |
||||
$this->logged_user = $this->Authentication->getIdentity(); |
||||
|
||||
// settiamo il locale come da preferenze utente (se specificato, altrimenti ci pensa il LocaleSelectorMiddleware): |
||||
if (!empty($this->logged_user->language_id)) I18n::setLocale($this->fetchTable('Languages')->get($this->logged_user->language_id)->language_code); |
||||
$this->set('locale', I18n::getLocale()); |
||||
|
||||
/* |
||||
* Enable the following component for recommended CakePHP form protection settings. |
||||
* see https://book.cakephp.org/4/en/controllers/components/form-protection.html |
||||
*/ |
||||
//$this->loadComponent('FormProtection'); |
||||
} |
||||
|
||||
public function beforeRender(EventInterface $event) |
||||
{ |
||||
if ($this->getRequest()->is(['json', 'xml', 'csv'])) { |
||||
$this->viewBuilder()->disableAutoLayout(); |
||||
} |
||||
|
||||
$sys_admin_menu_items = null; |
||||
$menu_sections = []; |
||||
$menu_items = []; |
||||
$logged_user_id = null; |
||||
$logged_user_description = null; |
||||
$logged_user_access_type_description = null; |
||||
$logged_user_timezone = null; |
||||
$logged_user_organisation_description = null; |
||||
$logged_user_photo = Configure::read('App.defaultUserPhoto'); |
||||
$user_notifications_count = 0; |
||||
$user_notifications = []; |
||||
|
||||
// bisogna recuperare le capabilities utente (se esiste un utente loggato) |
||||
if ($this->logged_user) { |
||||
// menu SYSADMIN da mostrare solo ai SYSADMIN: |
||||
$sys_admin_menu_items = [ |
||||
[ |
||||
'title' => __('SYSADMIN'), |
||||
'icon' => 'lock', |
||||
'menu_items' => [ |
||||
[ |
||||
'title' => __('Gestione competenze'), |
||||
'icon' => 'wrench', |
||||
'link' => '/capabilities', |
||||
], |
||||
[ |
||||
'title' => __('Test notifiche'), |
||||
'icon' => 'bell', |
||||
'link' => '/notifications/testAll', |
||||
'confirm' => __('Procedendo verranno inviate notifiche a tutti gli utenti e le organizzaioni che possiedono uno o più recapiti abilitati alle notifiche! Sei sicuro che vuoi continuare ?'), |
||||
'method' => 'POST', |
||||
], |
||||
], |
||||
|
||||
], |
||||
]; |
||||
if (!$this->logged_user->sys_admin) $sys_admin_menu_items = null; |
||||
|
||||
$logged_user_id = $this->logged_user->id; |
||||
$logged_user_description = $this->logged_user->name . ' ' . $this->logged_user->surname; |
||||
$logged_user_access_type_description = $this->logged_user->sys_admin ? 'sys_admin' : ($this->logged_user->passepartout ? 'passepartout' : ''); |
||||
$logged_user_timezone = $this->logged_user->timezone ?? Configure::read('App.defaultUserTimezone'); |
||||
if (isset($this->logged_user->organisation_id)) { |
||||
$logged_user_organisation_description = $this->fetchTable('Organisations')->get($this->logged_user->organisation_id, contain: ['Actors'])->actor->description; |
||||
} |
||||
if (!empty($this->logged_user->photo)) $logged_user_photo = Configure::read('App.userPhotoSrc') . "/" . $this->logged_user->photo; |
||||
|
||||
$user_notifications_count = $this->fetchTable('Notifications')->find()->where(['Notifications.user_id' => $this->logged_user->id, 'Notifications.read_by_user IS NULL'])->count(); |
||||
|
||||
$user_notifications = $this->fetchTable('Notifications') |
||||
->find() |
||||
->contain('NotificationTypes') |
||||
->where(['Notifications.user_id' => $this->logged_user->id, 'Notifications.read_by_user IS NULL']) |
||||
->order(['Notifications.created' => 'DESC']) |
||||
->all() |
||||
->reduce(function ($acc, $user_notification) { |
||||
$notification_info = json_decode($user_notification->info); |
||||
$body = strlen($notification_info->body) > 200 ? substr($notification_info->body, 0, 197) . '...' : $notification_info->body; |
||||
$icon = $user_notification->notification_type->icon ?? 'bell'; |
||||
$time_ago = (new DateTime($user_notification->created))->timeAgoInWords(); |
||||
$acc[] = ['id' => $user_notification->id, 'icon' => $icon, 'title' => $notification_info->title, 'body' => $body, 'time_ago' => $time_ago]; |
||||
return $acc; |
||||
}, []); |
||||
|
||||
$user_capabilityIds_query = $this->logged_user->getCapabilityIds(true); |
||||
|
||||
$menu_sections_subquery = $this->fetchTable('MenuSections') |
||||
->find() |
||||
->select(['MenuSections.id']) |
||||
->innerJoinWith('Capabilities') |
||||
->where(['Capabilities.id IN' => $user_capabilityIds_query]) |
||||
->distinct(['MenuSections.id']); |
||||
|
||||
$menu_sections = $this->fetchTable('MenuSections') |
||||
->find() |
||||
->where(['MenuSections.id IN' => $menu_sections_subquery]) |
||||
->order(['MenuSections.id' => 'ASC']) |
||||
->toArray(); |
||||
|
||||
if (count($menu_sections) > 0) { |
||||
// questo blocco controlla se nella request è presente il query param 'menu_section' |
||||
// se è presente e rappresenta un id di menu_section valido, lo settiamo in sessione utente |
||||
if ($this->getRequest()->getQuery('menu_section')) { |
||||
$valid_user_menu_section = $this->fetchTable('MenuSections')->find() |
||||
->matching('Capabilities') |
||||
->where(['Capabilities.id IN' => $user_capabilityIds_query, 'MenuSections.id' => $this->getRequest()->getQuery('menu_section')]) |
||||
->first(); |
||||
|
||||
$valid_user_menu_section_id = $valid_user_menu_section ? $valid_user_menu_section->id : $menu_sections[0]->id; |
||||
|
||||
$this->getRequest()->getSession()->write('menu_section', $valid_user_menu_section_id); |
||||
} |
||||
$menu_section_id = $this->getRequest()->getSession()->read('menu_section') ?? $menu_sections[0]->id; |
||||
|
||||
$menu_items_subquery = $this->fetchTable('MenuItems') |
||||
->find() |
||||
->select(['MenuItems.id']) |
||||
->innerJoinWith('Capabilities') |
||||
->where(['Capabilities.id IN' => $user_capabilityIds_query]) |
||||
->where(['MenuItems.menu_item_id IS NULL']) |
||||
->where(['MenuItems.menu_section_id' => $menu_section_id]) |
||||
->distinct(['MenuItems.id']); |
||||
|
||||
$menu_items = $this->fetchTable('MenuItems') |
||||
->find() |
||||
->where(['MenuItems.id IN' => $menu_items_subquery]) |
||||
->order(['MenuItems.menu_order' => 'ASC']) |
||||
->toArray(); |
||||
} |
||||
|
||||
if( $this->request->getPath() !== '/notifications/index' ) |
||||
{ |
||||
$privacy = $this->fetchTable('Privacy') |
||||
->find()->orderBy(['created' => 'DESC']) |
||||
->first(); |
||||
|
||||
if(isset($privacy)) |
||||
{ |
||||
$hasAcceptedPrivacy = $this->fetchTable('PrivacyUsers')->find()->where([ |
||||
'PrivacyUsers.user_id' => $this->logged_user->id, |
||||
'PrivacyUsers.privacy_id' => $privacy->id |
||||
])->first(); |
||||
|
||||
if( |
||||
!isset($hasAcceptedPrivacy) && |
||||
$this->request->getParam('controller') != 'Privacy' && |
||||
$this->request->getParam('action') != 'accept_privacy' |
||||
) { |
||||
return $this->redirect(['controller' => 'Privacy', 'action' => 'accept_privacy']); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
$this->set('menu_sections', $menu_sections); |
||||
$this->set('menu_items', $menu_items); |
||||
$this->set('sys_admin_menu_items', $sys_admin_menu_items); |
||||
$this->set('logged_user_id', $logged_user_id); |
||||
$this->set('logged_user_description', $logged_user_description); |
||||
$this->set('logged_user_access_type_description', $logged_user_access_type_description); |
||||
$this->set('logged_user_timezone', $logged_user_timezone); |
||||
$this->set('logged_user_organisation_description', $logged_user_organisation_description); |
||||
$this->set('logged_user_photo', $logged_user_photo); |
||||
$this->set('user_notifications_count', $user_notifications_count); |
||||
$this->set('user_notifications', $user_notifications); |
||||
} |
||||
|
||||
/** |
||||
* gen_random_code |
||||
* |
||||
* @param Int $length |
||||
* @return String |
||||
*/ |
||||
protected function gen_random_code(Int $length): String { |
||||
$characters = "abcdefghijklmnopqrstuvwxyzABCDERFGHIJKLMNOPQRSTUVWXYZ0123456789"; |
||||
$randomString = ""; |
||||
|
||||
for ($i = 0; $i < $length; $i++) { |
||||
$randomString .= $characters[mt_rand(0, strlen($characters)-1)]; |
||||
} |
||||
return $randomString; |
||||
} |
||||
|
||||
/** |
||||
* sendNotifications |
||||
* |
||||
* @param Int|Null $co_id |
||||
* @param String $notification_code |
||||
* @param Array $options |
||||
* @return void |
||||
*/ |
||||
protected function sendNotifications(Int|Null $co_id, String $notification_code, Array $options) |
||||
{ |
||||
NotificationsHandler::dispatch($co_id, $notification_code, $options, null, $this->logged_user->id ?? null); |
||||
} |
||||
|
||||
/** |
||||
* applyFilters |
||||
* |
||||
* @param Query $query |
||||
* @return Query |
||||
*/ |
||||
protected function applyFilters(Query $query): Query |
||||
{ |
||||
// recuperiamo i parametri per costruire la chiave per memorizzare i filtri in sessione. |
||||
// i filtri sono "scoped" per utente e per route. Quindi per ogni utente possiamo memorizzare |
||||
// filtri relativi a più liste. |
||||
$logged_user_id = $this->logged_user->id; |
||||
$controller = $this->request->getParam('controller'); |
||||
$action = $this->request->getParam('action'); |
||||
$filter_session_key = "filters-$logged_user_id-$controller-$action"; |
||||
|
||||
// recuperiamo i filtri o dal POST data (significa che sono stati appena applicati) |
||||
// o dalla sessione (se ci sono): |
||||
$filters = $this->request->is('post') ? $this->request->getData('filters') : $this->request->getSession()->read($filter_session_key); |
||||
\Cake\Log\Log::write("debug", 'applyFilters - ' . ($this->request->is('post') ? 'POST received' : 'SESSION retrieved') . ' filters: ' . json_encode($filters)); |
||||
|
||||
// ripuliamo i filtri eliminando prima i valori non validi per ciascun filtro |
||||
// e successivamente eliminiamo direttamente i fitri che non hanno valori validi (rimasti): |
||||
$filters = collection($filters ?? []) |
||||
->map(function ($filter_values, $filter_id) { |
||||
return collection($filter_values) |
||||
->filter(function ($filter_value) { |
||||
// il controllo con === "0" serve per evitare che il sanitiser elimini |
||||
// il valore "0" per filtri di tipo "bool" |
||||
return !empty($filter_value) || $filter_value === "0"; |
||||
}) |
||||
->reduce(function ($filter_values, $filter_value) { |
||||
$filter_values[] = $filter_value; |
||||
return $filter_values; |
||||
}, []); |
||||
}) |
||||
->filter(function ($filter_values, $filter_id) { |
||||
return !empty($filter_values); |
||||
}) |
||||
->toArray(); |
||||
|
||||
\Cake\Log\Log::write("debug", 'applyFilters - SANITISED filters: ' . json_encode($filters)); |
||||
|
||||
// se non si è riusciti a recuperare filtri |
||||
// o è stato richesto un reset dei filtri tramite POST |
||||
// o non ne sono rimasti a seguito della sanitizzazione, |
||||
// cancelliamo comunque la sessione alla chiave $filter_session_key |
||||
// ed usciamo senza applicare nulla alla query: |
||||
if (empty($filters)) { |
||||
\Cake\Log\Log::write("debug", "applyFilters - DELETING DATA SESSION with key '$filter_session_key'"); |
||||
$this->request->getSession()->delete($filter_session_key); |
||||
\Cake\Log\Log::write("debug", 'applyFilters - NO filters to appply!'); |
||||
return $query; |
||||
} |
||||
|
||||
// se abbiamo filtri validi e li abbiamo appena ricevuti (POST), li salviamo in sessione: |
||||
if ($this->request->is('post')) { |
||||
\Cake\Log\Log::write("debug", "applyFilters - WRITING DATA SESSION with key '$filter_session_key': " . json_encode($filters)); |
||||
$this->request->getSession()->write($filter_session_key, $filters); |
||||
} |
||||
|
||||
// array delle possibili associations da gestire nella query con ->leftJoinWith(). |
||||
// verrà popolato durante il processo di conversione da filtri a conditions: |
||||
$associations = []; |
||||
|
||||
// array delle conditions creato a partire dai filters ricevuti, da gestire nella query con ->where() |
||||
$conditions = collection($filters) |
||||
// qui trasformiamo i filtri in conditions in base alla tipologia di filtro ricevuto: |
||||
->map(function ($filter_values, $filter_id) use (&$associations) { |
||||
// recuperiamo le info sul filtro dalla table 'filters' avendo ricevuto l'id del filtro: |
||||
$filter = $this->fetchTable('Filters')->get((Int)explode("filter_id_", $filter_id)[1]); |
||||
// creazione della condizione in base al tipo di filtro: |
||||
switch ($filter->filter_type) { |
||||
case 'class': |
||||
case 'bool': |
||||
$condition = [$filter->search . ' IN' => $filter_values]; |
||||
break; |
||||
case 'text': |
||||
$condition = collection($filter_values) |
||||
->map(function ($filter_value) use ($filter) { |
||||
return [$filter->search . ' LIKE' => $filter_value]; |
||||
}) |
||||
->reduce(function ($conditions, $condition) { |
||||
$conditions['OR'][] = $condition; |
||||
return $conditions; |
||||
}, ['OR' => []]); |
||||
break; |
||||
case 'date': |
||||
$condition = collection($filter_values) |
||||
->map(function ($filter_value) use ($filter) { |
||||
$date_array = explode(" - ", $filter_value); |
||||
$from_date = $date_array[0]; |
||||
$to_date = $date_array[1]; |
||||
return [$filter->search . ' >=' => $from_date, $filter->search . ' <=' => $to_date]; |
||||
}) |
||||
->reduce(function ($conditions, $condition) { |
||||
$conditions['OR'][] = $condition; |
||||
return $conditions; |
||||
}, ['OR' => []]); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
// se il filtro è stato gestito e richiede una association, la inseriamo in apposito array: |
||||
if (!empty($condition) && !empty($filter->associations)) $associations[] = $filter->associations; |
||||
|
||||
// se il filtro non è stato gestito, restituiamo null; altrimenti restituiamo la condition |
||||
return $condition ?? null; |
||||
}) |
||||
// qui eliminiamo eventuali conditions null (generate da filtri non (al momento) gestiti: |
||||
->filter(function ($condition) { |
||||
return !empty($condition); |
||||
}) |
||||
// infine restituiamo l'array_values delle conditions ottenute: |
||||
->reduce(function ($conditions, $condition) { |
||||
$conditions[] = $condition; |
||||
return $conditions; |
||||
}, []); |
||||
|
||||
\Cake\Log\Log::write("debug", 'applyFilters - conditions applied: ' . json_encode($conditions)); |
||||
|
||||
if (count($conditions) > 0) $query = $query->where($conditions); |
||||
|
||||
\Cake\Log\Log::write("debug", 'applyFilters - associations applied: ' . json_encode($associations)); |
||||
|
||||
foreach ($associations as $association) { |
||||
$query = $query->leftJoinWith($association); |
||||
} |
||||
|
||||
if (count($associations) > 0) { |
||||
$main_table = $query->getRepository()->getAlias(); |
||||
$query = $query->distinct(["$main_table.id"]); |
||||
\Cake\Log\Log::write("debug", 'applyFilters - distinct applied: ' . "$main_table.id"); |
||||
} |
||||
|
||||
return $query; |
||||
} |
||||
|
||||
/** |
||||
* Respond with JSON |
||||
* |
||||
* @param int $statusCode HTTP status code |
||||
* @param null|object|array|string|null $responseBody Content of the response |
||||
* @param string $contentType Content type of the response, default "application/json" |
||||
* @return Response |
||||
*/ |
||||
public function respond(int $statusCode = 200, null|object|array|string $responseBody = null, string $contentType = "application/json") : Response |
||||
{ |
||||
$responseBody = is_object($responseBody) || is_array($responseBody) ? $responseBody : ['result' => $responseBody]; |
||||
|
||||
if ($paging = $this->request->getAttribute('paging')) { |
||||
$responseBody['pagination'] = $paging; |
||||
} |
||||
|
||||
try { |
||||
$encodedBody = json_encode($responseBody, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); |
||||
} catch (Exception $e) { |
||||
return $this->getResponse() |
||||
->withStatus(500) |
||||
->withStringBody(json_encode(['error' => 'Failed to encode JSON response'])) |
||||
->withType('application/json'); |
||||
} |
||||
|
||||
$response = $this->getResponse() |
||||
->withStatus($statusCode) |
||||
->withType($contentType) |
||||
->withStringBody($encodedBody); |
||||
|
||||
return $response; |
||||
} |
||||
} |
||||
@ -0,0 +1,112 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
use Cake\Http\Exception\ForbiddenException; |
||||
use Cake\View\JsonView; |
||||
|
||||
/** |
||||
* Applicants Controller |
||||
* |
||||
* @property \App\Model\Table\ApplicantsTable $Applicants |
||||
* @method \App\Model\Entity\Applicant[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class ApplicantsController extends AppController |
||||
{ |
||||
public function viewClasses(): array |
||||
{ |
||||
return [JsonView::class]; |
||||
} |
||||
|
||||
public function search_applicants(){ |
||||
$this->viewBuilder()->setClassName('Json'); |
||||
|
||||
$search = $this->request->getQueryParams('term'); |
||||
$applicants = $this->Applicants->find()->where([ |
||||
'Applicants.tax_code LIKE "%' . $search['term'] . '%" OR Applicants.name LIKE "%' . $search['term'] . '%" OR Applicants.surname LIKE "%' . $search['term'] . '%"' |
||||
])->formatResults(function ($results){ |
||||
return $results->map(function ($row) { |
||||
return ['id' => $row->id, 'text' => $row->tax_code . ' - ' . $row->name . ' ' . $row->surname]; |
||||
}); |
||||
})->toArray(); |
||||
$this->set(compact('applicants')); |
||||
$this->viewBuilder()->setOption('serialize', ['applicants'])->setOption('jsonOptions', JSON_FORCE_OBJECT); |
||||
} |
||||
|
||||
public function get_applicant($id){ |
||||
$applicant = $this->Applicants->get($id); |
||||
$this->set(compact('applicant')); |
||||
$this->viewBuilder()->setOption('serialize', ['applicant'])->setOption('jsonOptions', JSON_FORCE_OBJECT); |
||||
} |
||||
|
||||
public function edit($id, $water_id = null){ |
||||
$applicant = $this->Applicants->get($id); |
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$applicant = $this->Applicants->patchEntity($applicant, $this->request->getData()); |
||||
if ($this->Applicants->save($applicant)) { |
||||
$this->Flash->success(__('Il concessionario è stato aggiornato correttamente.')); |
||||
|
||||
return $this->redirect(['action' => 'view', $id]); |
||||
} |
||||
$this->Flash->error(__('Errore. Il concessionario non è stato salvato.')); |
||||
} |
||||
if(isset($water_id)){ |
||||
$waterDrawingPaperwork = $this->Applicants->WaterDrawingPaperworks->get($water_id); |
||||
$this->set(compact('waterDrawingPaperwork')); |
||||
} |
||||
$this->set(compact('applicant')); |
||||
} |
||||
|
||||
public function view($id){ |
||||
$applicant = $this->Applicants->get($id); |
||||
$this->set(compact('applicant')); |
||||
} |
||||
|
||||
// CITIZEN SECTION |
||||
|
||||
public function citizen_add(){ |
||||
if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
$applicant = $this->Applicants->newEmptyEntity(); |
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$data = $this->request->getData(); |
||||
$data['name'] = $this->logged_user->name; |
||||
$data['surname'] = $this->logged_user->surname; |
||||
$data['tax_code'] = $this->logged_user->tax_code; |
||||
$applicant = $this->Applicants->patchEntity($applicant, $data); |
||||
if ($this->Applicants->save($applicant)) { |
||||
$this->Flash->success(__('Il concessionario è stato creato correttamente.')); |
||||
|
||||
return $this->redirect(['action' => 'citizen_view']); |
||||
} |
||||
$this->Flash->error(__('Errore. Il concessionario non è stato salvato.')); |
||||
} |
||||
$user = $this->getTableLocator()->get('Users')->get($this->logged_user->id); |
||||
$this->set('user', $user); |
||||
$this->set(compact('applicant')); |
||||
} |
||||
|
||||
public function citizen_edit(){ |
||||
if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
$user = $this->getTableLocator()->get('Users')->get($this->logged_user->id); |
||||
$applicant = $this->Applicants->find()->where(['Applicants.tax_code' => $user->tax_code])->first(); |
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$applicant = $this->Applicants->patchEntity($applicant, $this->request->getData()); |
||||
if ($this->Applicants->save($applicant)) { |
||||
$this->Flash->success(__('Il concessionario è stato aggiornato correttamente.')); |
||||
|
||||
return $this->redirect(['action' => 'citizen_view']); |
||||
} |
||||
$this->Flash->error(__('Errore. Il concessionario non è stato salvato.')); |
||||
} |
||||
$this->set('user', $user); |
||||
$this->set(compact('applicant')); |
||||
} |
||||
|
||||
public function citizen_view(){ |
||||
if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
$user = $this->getTableLocator()->get('Users')->get($this->logged_user->id); |
||||
$applicant = $this->Applicants->find()->where(['Applicants.tax_code' => $user->tax_code])->first(); |
||||
if(!isset($applicant)) $this->redirect(['action' => 'citizen_add']); |
||||
$this->set(compact('applicant')); |
||||
} |
||||
} |
||||
@ -0,0 +1,98 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
use Cake\Core\Configure; |
||||
use Cake\Http\Exception\NotFoundException; |
||||
use Cake\Http\Exception\ForbiddenException; |
||||
use Cake\View\JsonView; |
||||
|
||||
|
||||
/** |
||||
* Attachments Controller |
||||
* |
||||
* @property \App\Model\Table\AttachmentsTable $Attachments |
||||
* @method \App\Model\Entity\Attachment[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class AttachmentsController extends AppController |
||||
{ |
||||
public function viewClasses(): array |
||||
{ |
||||
return [JsonView::class]; |
||||
} |
||||
|
||||
/** |
||||
* view |
||||
* |
||||
* @param Int $id |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function view($id) |
||||
{ |
||||
$withTrashed = $this->request->getQuery('withTrashed'); |
||||
$finder = !empty($withTrashed) ? 'withTrashed' : 'all'; |
||||
$attachment = $this->fetchTable('Attachments')->find($finder) |
||||
->contain(['ContainerControllableObjects']) |
||||
->where(['file_name' => $id]) |
||||
->first(); |
||||
|
||||
if (!$attachment) throw new NotFoundException(__('Allegato non trovato')); |
||||
if (!$this->logged_user->canHandleAttachmentsForControllableObject($attachment->container_controllable_object)) throw new ForbiddenException(__('Non hai i permessi necessari per visionare l\'allegato')); |
||||
|
||||
$mimetype = $attachment->mimetype; |
||||
$file_name = $attachment->file_name; |
||||
$original_file_name = $attachment->original_file_name; |
||||
$container_co_id = $attachment->container_controllable_object_id; |
||||
$path = Configure::read('App.attachmentsPath') . "/" . $container_co_id . "/" . $file_name; |
||||
$output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); |
||||
$this->response = $this->response |
||||
->withAddedHeader('Content-Disposition', 'filename="' . $original_file_name . '"') |
||||
->withCharset('UTF-8') |
||||
->withType($mimetype) |
||||
->withStringBody($output); |
||||
|
||||
return $this->response; |
||||
} |
||||
|
||||
/** |
||||
* markAsRelevant |
||||
* |
||||
* @param Int $id |
||||
* @throws NotFoundException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function markAsRelevant($id = null) |
||||
{ |
||||
$this->request->allowMethod(['post']); |
||||
$attachment = $this->fetchTable('Attachments')->find()->contain(['ContainerControllableObjects', 'ControllableObjects'])->where(['file_name' => $id])->first(); |
||||
|
||||
if(!$attachment) throw new NotFoundException(__('Allegato non trovato')); |
||||
if (!$this->logged_user->canHandleAttachmentsForControllableObject($attachment->container_controllable_object)) throw new ForbiddenException(__('Non hai i permessi necessari per visionare l\'allegato')); |
||||
|
||||
$attachment->relevant = !$attachment->relevant; |
||||
$attachment->controllable_object->id = $attachment->controllable_object->id; |
||||
$attachment->setDirty('controllable_object'); |
||||
$this->fetchTable('Attachments')->save($attachment); |
||||
$response = (object) []; |
||||
$response->result = true; |
||||
$response->relevant = $attachment->relevant; |
||||
$this->set('response', $response); |
||||
$this->viewBuilder()->setOption('serialize', 'response'); |
||||
} |
||||
|
||||
/** |
||||
* markAsDeleted |
||||
* |
||||
* @param Int $id |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function markAsDeleted($id = null) |
||||
{ |
||||
$this->response = $this->response |
||||
->withType('application/json') |
||||
->withStringBody(json_encode(['result' => "markAsDeleted attachment with id '$id'. Dummy method. please do not delete it!"])); |
||||
|
||||
return $this->response; |
||||
} |
||||
} |
||||
@ -0,0 +1,205 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
use Cake\Http\Exception\ForbiddenException; |
||||
use Cake\Datasource\ConnectionManager; |
||||
|
||||
/** |
||||
* Capabilities Controller |
||||
* |
||||
* @property \App\Model\Table\CapabilitiesTable $Capabilities |
||||
* @method \App\Model\Entity\Capability[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class CapabilitiesController extends AppController |
||||
{ |
||||
/** |
||||
* index |
||||
* |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function index() |
||||
{ |
||||
if (!$this->logged_user->sys_admin) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
$capabilities = $this->Capabilities->find('withTrashed') |
||||
->contain(['CapabilityGroups' => function ($q) { return $q->find('withTrashed'); }]); |
||||
|
||||
$capability_search = $this->request->getQuery('capability_search'); |
||||
if (!empty($capability_search)) { |
||||
$capabilities = $capabilities->where(['OR' => [ |
||||
'Capabilities.description LIKE' => "%$capability_search%", |
||||
'Capabilities.value LIKE' => "%$capability_search%", |
||||
'CapabilityGroups.description LIKE' => "%$capability_search%", |
||||
]]); |
||||
} |
||||
|
||||
$this->paginate = [ |
||||
'sortableFields' => ['description', 'value', 'priority', 'CapabilityGroups.description'], |
||||
]; |
||||
|
||||
$this->set('capabilities', $this->paginate($capabilities)); |
||||
$this->set('capability_search', $capability_search); |
||||
} |
||||
|
||||
/** |
||||
* hide |
||||
* |
||||
* @param Int $id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function hide($id) |
||||
{ |
||||
if (!$this->logged_user->sys_admin) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
$capability = $this->Capabilities->find('withTrashed')->where(['Capabilities.id' => $id])->first(); |
||||
$connection = ConnectionManager::get('default'); |
||||
$errSave = true; |
||||
$connection->begin(); |
||||
$capability->is_configurable = false; |
||||
if ($this->Capabilities->save($capability)) { |
||||
$capability_group = $this->Capabilities->CapabilityGroups->find('withTrashed') |
||||
->contain(['Capabilities' => function ($q) { return $q->find('withTrashed')->where(['Capabilities.is_configurable' => 1]); }]) |
||||
->where(['CapabilityGroups.id' => $capability->capability_group_id]) |
||||
->first(); |
||||
|
||||
if ($capability_group) { |
||||
if (count($capability_group->capabilities) == 0) { |
||||
$capability_group->is_configurable = false; |
||||
if ($this->Capabilities->CapabilityGroups->save($capability_group)) { |
||||
$errSave = false; |
||||
} |
||||
} else { |
||||
$errSave = false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (!$errSave) { |
||||
$this->Flash->success(__('Competenza "{0}" nascosta con successo!', $capability->description)); |
||||
$connection->commit(); |
||||
} else { |
||||
$this->Flash->error(__('Errore durante il tentativo di nascondere la Competenza "{0}"!', $capability->description)); |
||||
$connection->rollback(); |
||||
} |
||||
return $this->redirect(['action' => 'index', '?' => $this->request->getQueryParams()]); |
||||
} |
||||
|
||||
/** |
||||
* show |
||||
* |
||||
* @param Int $id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function show($id) |
||||
{ |
||||
if (!$this->logged_user->sys_admin) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
$capability = $this->Capabilities->find('withTrashed')->where(['Capabilities.id' => $id])->first(); |
||||
$connection = ConnectionManager::get('default'); |
||||
$errSave = true; |
||||
$connection->begin(); |
||||
$capability->is_configurable = true; |
||||
if ($this->Capabilities->save($capability)) { |
||||
$capability_group = $this->Capabilities->CapabilityGroups->find('withTrashed') |
||||
->where(['CapabilityGroups.id' => $capability->capability_group_id]) |
||||
->first(); |
||||
|
||||
if ($capability_group) { |
||||
$capability_group->is_configurable = true; |
||||
if ($this->Capabilities->CapabilityGroups->save($capability_group)) { |
||||
$errSave = false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (!$errSave) { |
||||
$this->Flash->success(__('Competenza "{0}" resa visibile con successo!', $capability->description)); |
||||
$connection->commit(); |
||||
} else { |
||||
$this->Flash->error(__('Errore durante il tentativo di rendere visibile la Competenza "{0}"!', $capability->description)); |
||||
$connection->rollback(); |
||||
} |
||||
return $this->redirect(['action' => 'index', '?' => $this->request->getQueryParams()]); |
||||
} |
||||
|
||||
/** |
||||
* delete |
||||
* |
||||
* @param Int $id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function delete($id) |
||||
{ |
||||
if (!$this->logged_user->sys_admin) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
$this->Capabilities->Permissions->addBehavior('Muffin/Trash.Trash'); |
||||
$capability = $this->Capabilities->find('withTrashed')->where(['Capabilities.id' => $id])->first(); |
||||
$connection = ConnectionManager::get('default'); |
||||
$errSave = true; |
||||
$connection->begin(); |
||||
if ($this->Capabilities->delete($capability)) { |
||||
$capability_group = $this->Capabilities->CapabilityGroups->find('withTrashed') |
||||
->contain(['Capabilities']) |
||||
->where(['CapabilityGroups.id' => $capability->capability_group_id]) |
||||
->first(); |
||||
|
||||
if ($capability_group) { |
||||
if (count($capability_group->capabilities) == 0) { |
||||
if ($this->Capabilities->CapabilityGroups->delete($capability_group)) { |
||||
$errSave = false; |
||||
} |
||||
} else { |
||||
$errSave = false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (!$errSave) { |
||||
$this->Flash->success(__('Competenza "{0}" cancellata con successo!', $capability->description)); |
||||
$connection->commit(); |
||||
} else { |
||||
$this->Flash->error(__('Errore durante la cancellazione della Competenza "{0}"!', $capability->description)); |
||||
$connection->rollback(); |
||||
} |
||||
return $this->redirect(['action' => 'index', '?' => $this->request->getQueryParams()]); |
||||
} |
||||
|
||||
/** |
||||
* restore |
||||
* |
||||
* @param Int $id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function restore($id) |
||||
{ |
||||
if (!$this->logged_user->sys_admin) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
$this->Capabilities->Permissions->addBehavior('Muffin/Trash.Trash'); |
||||
$capability = $this->Capabilities->find('withTrashed')->where(['Capabilities.id' => $id])->first(); |
||||
$connection = ConnectionManager::get('default'); |
||||
$errSave = true; |
||||
$connection->begin(); |
||||
if ($this->Capabilities->cascadingRestoreTrash($capability)) { |
||||
$capability_group = $this->Capabilities->CapabilityGroups->find('withTrashed') |
||||
->where(['CapabilityGroups.id' => $capability->capability_group_id]) |
||||
->first(); |
||||
|
||||
if ($capability_group) { |
||||
$capability_group->deleted = null; |
||||
if ($this->Capabilities->CapabilityGroups->save($capability_group)) { |
||||
$errSave = false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (!$errSave) { |
||||
$this->Flash->success(__('Competenza "{0}" ripristinata con successo!', $capability->description)); |
||||
$connection->commit(); |
||||
} else { |
||||
$this->Flash->error(__('Errore durante il ripristino della Competenza "{0}"!', $capability->description)); |
||||
$connection->rollback(); |
||||
} |
||||
return $this->redirect(['action' => 'index', '?' => $this->request->getQueryParams()]); |
||||
} |
||||
} |
||||
@ -0,0 +1,103 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller\Component; |
||||
|
||||
use Cake\Http\CallbackStream; |
||||
use Cake\ORM\Query\SelectQuery; |
||||
use Cake\Http\Response; |
||||
|
||||
trait StreamableCsvExportTrait |
||||
{ |
||||
/** |
||||
* Stream a CSV file to the browser fetching data in configurable chunk size. |
||||
* |
||||
* @param SelectQuery $query Query returning the dataset |
||||
* @param string $filename Name of the file to download |
||||
* @param array|null $extract Optional: extraction map to apply |
||||
* @param array|null $headers Optional: column keys to export (and order). $headers are taken in account ONLY when $extract is provided! |
||||
* @param array $csvOptions CSV formatting options: delimiter, enclosure, escape |
||||
* @param int $chunkSize Number of rows per DB page |
||||
* @param bool $bom whether CSV should contain UTF-8 BOM (Byte Order Mark) at the very beginning of file (for Excel compatibilty) |
||||
* @return Response |
||||
*/ |
||||
public function streamCsvResponse( |
||||
SelectQuery $query, |
||||
string $filename = 'export.csv', |
||||
?array $extract = null, |
||||
?array $headers = null, |
||||
array $csvOptions = [',', '"', '\\'], |
||||
int $chunkSize = 1000, |
||||
bool $bom = true |
||||
): Response { |
||||
$stream = new CallbackStream(function () use ($query, $extract, $headers, $csvOptions, $chunkSize, $bom) { |
||||
$out = fopen('php://output', 'w'); |
||||
|
||||
// Excel-friendly UTF-8 BOM |
||||
if ($bom) fwrite($out, "\xEF\xBB\xBF"); |
||||
|
||||
$page = 1; |
||||
$wroteHeader = false; |
||||
|
||||
// we disable CakePHP ORM istantiating Model Entities |
||||
$query->disableHydration(); |
||||
|
||||
do { |
||||
$results = $query |
||||
->limit($chunkSize) |
||||
->page($page) |
||||
->all(); |
||||
|
||||
foreach ($results as $rowArray) { |
||||
|
||||
if ($extract !== null) { |
||||
if (!$wroteHeader) { |
||||
// we use the provided $headers as column names, |
||||
// otherwise we fallback to $extract array keys when they are plain string or we use "Column $key" if they are not |
||||
$headerRow = $headers ?? array_map( |
||||
function($extract_value, $extract_index) { return is_string($extract_value) ? $extract_value : "Column $extract_index"; }, |
||||
$extract, |
||||
array_keys($extract) |
||||
); |
||||
fputcsv($out, $headerRow, ...$csvOptions); |
||||
$wroteHeader = true; |
||||
} |
||||
|
||||
$dataRow = []; |
||||
|
||||
// we use the provided $extractor to obtain the mapped values: |
||||
foreach ($extract as $column) { |
||||
if (is_callable($column)) { |
||||
$dataRow[] = $column($rowArray); |
||||
} elseif (is_string($column)) { |
||||
$dataRow[] = $rowArray[$column] ?? ''; |
||||
} else { |
||||
$dataRow[] = ''; |
||||
} |
||||
} |
||||
fputcsv($out, $dataRow, ...$csvOptions); |
||||
} else { |
||||
// there is no exctractor provided, we will take plain array keys as column names: |
||||
if (!$wroteHeader) { |
||||
fputcsv($out, array_keys($rowArray), ...$csvOptions); |
||||
$wroteHeader = true; |
||||
} |
||||
// there is no exctractor provided, we will take plain array values: |
||||
$rowValues = array_values($rowArray); |
||||
fputcsv($out, $rowValues, ...$csvOptions); |
||||
} |
||||
flush(); |
||||
} |
||||
$count = $results->count(); |
||||
$page++; |
||||
} while ($count === $chunkSize); |
||||
|
||||
fclose($out); |
||||
}); |
||||
|
||||
return $this->response |
||||
->withType('text/csv') |
||||
->withDownload($filename) |
||||
->withBody($stream); |
||||
} |
||||
} |
||||
@ -0,0 +1,56 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
/** |
||||
* ControllableObjects Controller |
||||
* |
||||
* @property \App\Model\Table\ControllableObjectsTable $ControllableObjects |
||||
* @method \App\Model\Entity\ControllableObject[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class ControllableObjectsController extends AppController |
||||
{ |
||||
/** |
||||
* getAttachments |
||||
* |
||||
* @param Int $co_id |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function getAttachments ($co_id = null) { |
||||
$attachments = $this->ControllableObjects->Attachments |
||||
->find() |
||||
->contain(['ControllableObjects' => ['Creator', 'Modifier', 'Locations']]) |
||||
->where(['Attachments.container_controllable_object_id' => $co_id]); |
||||
|
||||
if(!empty($this->request->getQuery('tags'))) { |
||||
$tags = explode(',', $this->request->getQuery('tags')); |
||||
$attachments = $attachments |
||||
->matching('Tags') |
||||
->where(['Tags.code IN' => $tags]); |
||||
} |
||||
|
||||
$showPrivateColumn = $attachments->all()->filter(function ($attachment) { return $attachment->private == 1; })->count() > 0; |
||||
|
||||
if (!$this->logged_user->canHandleAttachmentsForControllableObject($this->ControllableObjects->get($co_id))) { |
||||
$attachments = $attachments->where(['Attachments.id < 0']); |
||||
} |
||||
|
||||
$this->paginate = [ |
||||
'sortableFields' => ['Attachments.private', 'Attachments.original_file_name', 'Locations.description', 'Attachments.relevant', 'Attachments.original_file_size', 'Attachments.mimetype', 'Attachments.upload_date', 'Creator.surname'], |
||||
'limit' => 10, |
||||
'order' => [ |
||||
'Attachments.upload_date' => 'DESC' |
||||
], |
||||
]; |
||||
|
||||
if ($this->request->getQuery('removecurrentfiles') !== null) { |
||||
$this->set('removecurrentfiles', $this->request->getQuery('removecurrentfiles')); |
||||
} |
||||
|
||||
$this->viewBuilder()->setLayout('ajax'); |
||||
$this->set('numberOfAttachments', $attachments->count()); |
||||
$this->set('attachments', $this->paginate($attachments)); |
||||
$this->set('showPrivateColumn', $showPrivateColumn); |
||||
} |
||||
} |
||||
@ -0,0 +1,35 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* |
||||
* Licensed under The MIT License |
||||
* For full copyright and license information, please see the LICENSE.txt |
||||
* Redistributions of files must retain the above copyright notice. |
||||
* |
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* @link https://cakephp.org CakePHP(tm) Project |
||||
* @since 0.2.9 |
||||
* @license https://opensource.org/licenses/mit-license.php MIT License |
||||
*/ |
||||
namespace App\Controller; |
||||
|
||||
/** |
||||
* Static content controller |
||||
* |
||||
* This controller will render views from templates/Dashboard/ |
||||
* |
||||
*/ |
||||
class DashboardController extends AppController |
||||
{ |
||||
/** |
||||
* index |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function index () |
||||
{ |
||||
} |
||||
} |
||||
@ -0,0 +1,185 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
use Cake\Http\Exception\ForbiddenException; |
||||
|
||||
/** |
||||
* Deliveries Controller |
||||
* |
||||
* @property \App\Model\Table\DeliveriesTable $Deliveries |
||||
* @method \App\Model\Entity\Delivery[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class DeliveriesController extends AppController |
||||
{ |
||||
/** |
||||
* index |
||||
* |
||||
* @param Int $actor_id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function index($actor_id) |
||||
{ |
||||
$actor = $this->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); |
||||
|
||||
// se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": |
||||
if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); |
||||
|
||||
$actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); |
||||
if (!$this->logged_user->canViewContactsForActor($actor)) throw new ForbiddenException(__('Non hai i permessi per visualizzare i recapiti per {0}', $actor_type_description)); |
||||
|
||||
$mobile_phones = $this->Deliveries->MobilePhones->find() |
||||
->contain(['MobilePhoneDescriptions']) |
||||
->matching('Deliveries') |
||||
->where(['Deliveries.actor_id' => $actor_id]) |
||||
->all(); |
||||
|
||||
if (!$this->logged_user->canViewContactsForActor($actor, 'mobile_phone')) { |
||||
$mobile_phones = $mobile_phones->map(function ($mobile_phone) { |
||||
$mobile_phone->value = "**************"; |
||||
return $mobile_phone; |
||||
}); |
||||
} |
||||
|
||||
$faxes = $this->Deliveries->Faxes->find() |
||||
->contain(['FaxDescriptions']) |
||||
->matching('Deliveries') |
||||
->where(['Deliveries.actor_id' => $actor_id]) |
||||
->all(); |
||||
|
||||
if (!$this->logged_user->canViewContactsForActor($actor, 'fax')) { |
||||
$faxes = $faxes->map(function ($fax) { |
||||
$fax->value = "**************"; |
||||
return $fax; |
||||
}); |
||||
} |
||||
|
||||
$emails = $this->Deliveries->Emails->find() |
||||
->contain(['EmailDescriptions']) |
||||
->matching('Deliveries') |
||||
->where(['Deliveries.actor_id' => $actor_id]) |
||||
->all(); |
||||
|
||||
if (!$this->logged_user->canViewContactsForActor($actor, 'email')) { |
||||
$emails = $emails->map(function ($email) { |
||||
$email->value = "**************"; |
||||
return $email; |
||||
}); |
||||
} |
||||
|
||||
$phones = $this->Deliveries->Phones->find() |
||||
->contain(['PhoneDescriptions']) |
||||
->matching('Deliveries') |
||||
->where(['Deliveries.actor_id' => $actor_id]) |
||||
->all(); |
||||
|
||||
if (!$this->logged_user->canViewContactsForActor($actor, 'phone')) { |
||||
$phones = $phones->map(function ($phone) { |
||||
$phone->value = "**************"; |
||||
return $phone; |
||||
}); |
||||
} |
||||
|
||||
$telegram_chats = $this->Deliveries->TelegramChats->find() |
||||
->matching('Deliveries') |
||||
->where(['Deliveries.actor_id' => $actor_id]) |
||||
->all(); |
||||
|
||||
if (!$this->logged_user->canViewContactsForActor($actor, 'telegram_chat')) { |
||||
$telegram_chats = $telegram_chats->map(function ($telegram_chat) { |
||||
$telegram_chat->value = "**************"; |
||||
return $telegram_chat; |
||||
}); |
||||
} |
||||
|
||||
$pecs = $this->Deliveries->Pecs->find() |
||||
->contain(['PecDescriptions']) |
||||
->matching('Deliveries') |
||||
->where(['Deliveries.actor_id' => $actor_id]) |
||||
->all(); |
||||
|
||||
if (!$this->logged_user->canViewContactsForActor($actor, 'pec')) { |
||||
$pecs = $pecs->map(function ($pec) { |
||||
$pec->value = "**************"; |
||||
return $pec; |
||||
}); |
||||
} |
||||
|
||||
$can_add_mobile_phone = $this->logged_user->canAddContactsForActor($actor, 'mobile_phone'); |
||||
$can_edit_mobile_phone = $this->logged_user->canEditContactsForActor($actor, 'mobile_phone'); |
||||
$can_delete_mobile_phone = $this->logged_user->canDeleteContactsForActor($actor, 'mobile_phone'); |
||||
$can_add_fax = $this->logged_user->canAddContactsForActor($actor, 'fax'); |
||||
$can_edit_fax = $this->logged_user->canEditContactsForActor($actor, 'fax'); |
||||
$can_delete_fax = $this->logged_user->canDeleteContactsForActor($actor, 'fax'); |
||||
$can_add_email = $this->logged_user->canAddContactsForActor($actor, 'email'); |
||||
$can_edit_email = $this->logged_user->canEditContactsForActor($actor, 'email'); |
||||
$can_delete_email = $this->logged_user->canDeleteContactsForActor($actor, 'email'); |
||||
$can_add_phone = $this->logged_user->canAddContactsForActor($actor, 'phone'); |
||||
$can_edit_phone = $this->logged_user->canEditContactsForActor($actor, 'phone'); |
||||
$can_delete_phone = $this->logged_user->canDeleteContactsForActor($actor, 'phone'); |
||||
$can_add_telegram_chat = $this->logged_user->canAddContactsForActor($actor, 'telegram_chat'); |
||||
$can_edit_telegram_chat = $this->logged_user->canEditContactsForActor($actor, 'telegram_chat'); |
||||
$can_delete_telegram_chat = $this->logged_user->canDeleteContactsForActor($actor, 'telegram_chat'); |
||||
$can_add_pec = $this->logged_user->canAddContactsForActor($actor, 'pec'); |
||||
$can_edit_pec = $this->logged_user->canEditContactsForActor($actor, 'pec'); |
||||
$can_delete_pec = $this->logged_user->canDeleteContactsForActor($actor, 'pec'); |
||||
|
||||
$this->set(compact('actor', 'mobile_phones', 'faxes', 'emails', 'phones', 'telegram_chats', 'pecs', 'can_add_mobile_phone', 'can_edit_mobile_phone', 'can_delete_mobile_phone', 'can_add_fax', 'can_edit_fax', 'can_delete_fax', 'can_add_email', 'can_edit_email', 'can_delete_email', 'can_add_phone', 'can_edit_phone', 'can_delete_phone', 'can_add_telegram_chat', 'can_edit_telegram_chat', 'can_delete_telegram_chat', 'can_add_pec', 'can_edit_pec', 'can_delete_pec')); |
||||
} |
||||
|
||||
/** |
||||
* delete |
||||
* |
||||
* @param Int $id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function delete($id = null) |
||||
{ |
||||
$this->request->allowMethod(['post', 'delete']); |
||||
$delivery = $this->Deliveries->get($id, contain: ['DeliveryTypes', 'MobilePhones' => ['MobilePhoneDescriptions'], 'Faxes' => ['FaxDescriptions'], 'Emails' => ['EmailDescriptions'], 'Phones' => ['PhoneDescriptions'], 'TelegramChats', 'Pecs' => ['PecDescriptions']]); |
||||
|
||||
$actor = $this->Deliveries->Actors->get($delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); |
||||
|
||||
// se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": |
||||
if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); |
||||
|
||||
$actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); |
||||
if (!$this->logged_user->canDeleteContactsForActor($actor, $delivery->delivery_type->description)) throw new ForbiddenException(__('Non hai i permessi per eliminare i recapiti di questo tipo per {0}', $actor_type_description)); |
||||
|
||||
$contact_value = ""; |
||||
|
||||
switch ($delivery->delivery_type_id) { |
||||
case 1: |
||||
$contact_value = __('Cellulare ({0}): {1}', $delivery->mobile_phone->mobile_phone_description->description, $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->mobile_phone->value : "**************"); |
||||
break; |
||||
case 2: |
||||
$contact_value = __('Fax ({0}): {1}', $delivery->fax->fax_description->description, $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->fax->value: "**************"); |
||||
break; |
||||
case 3: |
||||
$contact_value = __('Email ({0}): {1}', $delivery->email->email_description->description, $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->email->value: "**************"); |
||||
break; |
||||
case 4: |
||||
$contact_value = __('Telefono ({0}): {1}', $delivery->phone->phone_description->description, $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->phone->value: "**************"); |
||||
break; |
||||
case 5: |
||||
$contact_value = __('Telegram Chat ID: {0}', $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->telegram_chat->value: "**************"); |
||||
break; |
||||
case 6: |
||||
$contact_value = __('PEC ({0}): {1}', $delivery->pec->pec_description->description, $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->pec->value: "**************"); |
||||
break; |
||||
default: |
||||
$contact_value = ""; |
||||
break; |
||||
} |
||||
|
||||
if ($this->Deliveries->delete($delivery)) { |
||||
$this->Flash->success(__('Il recapito "{0}" è stato cancellato con successo', $contact_value)); |
||||
} else { |
||||
$this->Flash->error(__('Errore durante la cancellazione del recapito {0}. Riprovare di nuovo.', $contact_value)); |
||||
} |
||||
|
||||
return $this->redirect(['action' => 'index', $delivery->actor_id]); |
||||
} |
||||
} |
||||
@ -0,0 +1,66 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
use App\Model\Table\DistrictsTable; |
||||
use App\WGS\Utils\Enum\ProvinceDistrictFields; |
||||
use App\WGS\Utils\Enum\Regions; |
||||
use App\WGS\Utils\Helper\ProvinceDistrictFieldHelper; |
||||
use Cake\View\JsonView; |
||||
use Exception; |
||||
|
||||
/** |
||||
* Applicants Controller |
||||
* |
||||
* @property DistrictsTable $Districts |
||||
* @method \App\Model\Entity\Applicant[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class DistrictsController extends AppController |
||||
{ |
||||
public function viewClasses(): array |
||||
{ |
||||
return [JsonView::class]; |
||||
} |
||||
|
||||
/** |
||||
* @throws Exception |
||||
*/ |
||||
public function search_districts() |
||||
{ |
||||
$this->viewBuilder()->setClassName('Json'); |
||||
$conditions = []; |
||||
$provinceCode = $this->request->getQuery(ProvinceDistrictFieldHelper::raw(ProvinceDistrictFields::PROVINCE_CODE)); |
||||
$term = $this->request->getQuery("term"); |
||||
$codeReg = ProvinceDistrictFieldHelper::getCodeRegByRegion(Regions::SICILY); |
||||
$regCodField = ProvinceDistrictFieldHelper::forDistricts(ProvinceDistrictFields::REGION_CODE); |
||||
$provCodeField = ProvinceDistrictFieldHelper::forDistricts(ProvinceDistrictFields::PROVINCE_CODE); |
||||
$queryDistrictFieldName = ProvinceDistrictFieldHelper::forDistricts(ProvinceDistrictFields::DISTRICT_FIELD_NAME); |
||||
|
||||
if($codeReg) { |
||||
$conditions[$regCodField] = $codeReg; |
||||
} |
||||
|
||||
if (isset($provinceCode)) { |
||||
$conditions[$provCodeField] = $provinceCode; |
||||
} |
||||
|
||||
$query = $this->Districts->find(); |
||||
|
||||
if ($term) { |
||||
$query->where(function ($exp) use ($term, $queryDistrictFieldName) { |
||||
return $exp->like($queryDistrictFieldName, "%$term%"); |
||||
}); |
||||
} |
||||
|
||||
if (!empty($conditions)) { |
||||
$query->where($conditions); |
||||
} |
||||
|
||||
$district_field = ProvinceDistrictFieldHelper::raw(ProvinceDistrictFields::DISTRICT_FIELD_NAME); |
||||
$districts = $query->find('list', keyField: $district_field, valueField: $district_field)->toArray(); |
||||
|
||||
$this->set(compact('districts')); |
||||
$this->viewBuilder()->setOption('serialize', ['districts'])->setOption('jsonOptions', JSON_FORCE_OBJECT); |
||||
} |
||||
} |
||||
@ -0,0 +1,78 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
use Cake\Http\Exception\ForbiddenException; |
||||
|
||||
/** |
||||
* Emails Controller |
||||
* |
||||
* @property \App\Model\Table\EmailsTable $Emails |
||||
*/ |
||||
class EmailsController extends AppController |
||||
{ |
||||
/** |
||||
* add |
||||
* |
||||
* @param Int $actor_id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function add($actor_id) |
||||
{ |
||||
$actor = $this->Emails->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); |
||||
// se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": |
||||
if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); |
||||
$actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); |
||||
if (!$this->logged_user->canAddContactsForActor($actor, 'email')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); |
||||
|
||||
$email = $this->Emails->newEntity([ |
||||
'delivery' => [ |
||||
'actor_id' => $actor_id, |
||||
'delivery_type_id' => 3, |
||||
], |
||||
], ['validate' => false]); |
||||
|
||||
if ($this->request->is('post')) { |
||||
$email = $this->Emails->patchEntity($email, $this->request->getData()); |
||||
if ($this->Emails->save($email)) { |
||||
$this->Flash->success(__('L\'Email è stata aggiunta con successo.')); |
||||
|
||||
return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); |
||||
} |
||||
$this->Flash->error(__('Errore durante l\'aggiunta dell\'Email')); |
||||
} |
||||
$emailDescriptions = $this->Emails->EmailDescriptions->find('list'); |
||||
$this->set(compact('actor', 'email', 'emailDescriptions')); |
||||
} |
||||
|
||||
/** |
||||
* edit |
||||
* |
||||
* @param Int $id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function edit($id = null) |
||||
{ |
||||
$email = $this->Emails->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); |
||||
|
||||
$actor = $this->Emails->Deliveries->Actors->get($email->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); |
||||
// se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": |
||||
if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); |
||||
$actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); |
||||
if (!$this->logged_user->canEditContactsForActor($actor, 'email')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); |
||||
|
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$email = $this->Emails->patchEntity($email, $this->request->getData()); |
||||
if ($this->Emails->save($email)) { |
||||
$this->Flash->success(__('L\'Email è stata modificata con successo.')); |
||||
|
||||
return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $email->delivery->actor_id]); |
||||
} |
||||
$this->Flash->error(__('Errore durante la modifica dell\'Email. Riprovare di nuovo')); |
||||
} |
||||
$emailDescriptions = $this->Emails->EmailDescriptions->find('list'); |
||||
$this->set(compact('actor', 'email', 'emailDescriptions')); |
||||
} |
||||
} |
||||
@ -0,0 +1,70 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
/** |
||||
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) |
||||
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* |
||||
* Licensed under The MIT License |
||||
* For full copyright and license information, please see the LICENSE.txt |
||||
* Redistributions of files must retain the above copyright notice. |
||||
* |
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) |
||||
* @link https://cakephp.org CakePHP(tm) Project |
||||
* @since 3.3.4 |
||||
* @license https://opensource.org/licenses/mit-license.php MIT License |
||||
*/ |
||||
namespace App\Controller; |
||||
|
||||
use Cake\Event\EventInterface; |
||||
|
||||
/** |
||||
* Error Handling Controller |
||||
* |
||||
* Controller used by ExceptionRenderer to render error responses. |
||||
*/ |
||||
class ErrorController extends AppController |
||||
{ |
||||
/** |
||||
* Initialization hook method. |
||||
* |
||||
* @return void |
||||
*/ |
||||
public function initialize(): void |
||||
{ |
||||
parent::initialize(); |
||||
} |
||||
|
||||
/** |
||||
* beforeFilter callback. |
||||
* |
||||
* @param \Cake\Event\EventInterface $event Event. |
||||
* @return \Cake\Http\Response|null|void |
||||
*/ |
||||
public function beforeFilter(EventInterface $event) |
||||
{ |
||||
} |
||||
|
||||
/** |
||||
* beforeRender callback. |
||||
* |
||||
* @param \Cake\Event\EventInterface $event Event. |
||||
* @return \Cake\Http\Response|null|void |
||||
*/ |
||||
public function beforeRender(EventInterface $event) |
||||
{ |
||||
parent::beforeRender($event); |
||||
|
||||
$this->viewBuilder()->setTemplatePath('Error'); |
||||
} |
||||
|
||||
/** |
||||
* afterFilter callback. |
||||
* |
||||
* @param \Cake\Event\EventInterface $event Event. |
||||
* @return \Cake\Http\Response|null|void |
||||
*/ |
||||
public function afterFilter(EventInterface $event) |
||||
{ |
||||
} |
||||
} |
||||
@ -0,0 +1,78 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
use Cake\Http\Exception\ForbiddenException; |
||||
|
||||
/** |
||||
* Faxes Controller |
||||
* |
||||
* @property \App\Model\Table\FaxesTable $Faxes |
||||
*/ |
||||
class FaxesController extends AppController |
||||
{ |
||||
/** |
||||
* add |
||||
* |
||||
* @param Int $actor_id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function add($actor_id) |
||||
{ |
||||
$actor = $this->Faxes->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); |
||||
// se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": |
||||
if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); |
||||
$actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); |
||||
if (!$this->logged_user->canAddContactsForActor($actor, 'fax')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); |
||||
|
||||
$fax = $this->Faxes->newEntity([ |
||||
'delivery' => [ |
||||
'actor_id' => $actor_id, |
||||
'delivery_type_id' => 2, |
||||
], |
||||
], ['validate' => false]); |
||||
|
||||
if ($this->request->is('post')) { |
||||
$fax = $this->Faxes->patchEntity($fax, $this->request->getData()); |
||||
if ($this->Faxes->save($fax)) { |
||||
$this->Flash->success(__('Il Fax è stato aggiunto con successo.')); |
||||
|
||||
return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); |
||||
} |
||||
$this->Flash->error(__('Errore durante l\'aggiunta del Fax')); |
||||
} |
||||
$faxDescriptions = $this->Faxes->FaxDescriptions->find('list'); |
||||
$this->set(compact('actor', 'fax', 'faxDescriptions')); |
||||
} |
||||
|
||||
/** |
||||
* edit |
||||
* |
||||
* @param Int $id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function edit($id = null) |
||||
{ |
||||
$fax = $this->Faxes->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); |
||||
|
||||
$actor = $this->Faxes->Deliveries->Actors->get($fax->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); |
||||
// se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": |
||||
if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); |
||||
$actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); |
||||
if (!$this->logged_user->canEditContactsForActor($actor, 'fax')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); |
||||
|
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$fax = $this->Faxes->patchEntity($fax, $this->request->getData()); |
||||
if ($this->Faxes->save($fax)) { |
||||
$this->Flash->success(__('Il Fax è stato modificato con successo.')); |
||||
|
||||
return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $fax->delivery->actor_id]); |
||||
} |
||||
$this->Flash->error(__('Errore durante la modifica del Fax. Riprovare di nuovo')); |
||||
} |
||||
$faxDescriptions = $this->Faxes->FaxDescriptions->find('list'); |
||||
$this->set(compact('actor', 'fax', 'faxDescriptions')); |
||||
} |
||||
} |
||||
@ -0,0 +1,25 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
/** |
||||
* Filters Controller |
||||
* |
||||
* @property \App\Model\Table\FiltersTable $Filters |
||||
* @method \App\Model\Entity\Filter[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class FiltersController extends AppController |
||||
{ |
||||
/** |
||||
* getFilterInput |
||||
* |
||||
* @param Int $filter_id |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function getFilterInput($filter_id) |
||||
{ |
||||
$this->set('filter_id', $filter_id); |
||||
$this->viewBuilder()->setLayout('ajax'); |
||||
} |
||||
} |
||||
@ -0,0 +1,236 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
use Cake\View\JsonView; |
||||
use App\View\CustomCsvView; |
||||
use Cake\I18n\DateTime; |
||||
use Cake\Http\Exception\ForbiddenException; |
||||
|
||||
/** |
||||
* Groups Controller |
||||
* |
||||
* @property \App\Model\Table\GroupsTable $Groups |
||||
* @method \App\Model\Entity\Group[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class GroupsController extends AppController |
||||
{ |
||||
public function viewClasses(): array |
||||
{ |
||||
return [JsonView::class, CustomCsvView::class]; |
||||
} |
||||
|
||||
/** |
||||
* index |
||||
* |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function index() |
||||
{ |
||||
if (!$this->logged_user->hasCapability('configuration.groups.read')) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$groups = $this->Groups->find() |
||||
->contain(['Actors', 'ChildGroups']); |
||||
|
||||
if (!$this->getRequest()->is(['json', 'xml', 'csv'])) { |
||||
$groups = $groups |
||||
->formatResults(function (\Cake\Collection\CollectionInterface $results) { |
||||
return $results->map(function ($row) { |
||||
$row->can_edit = $this->logged_user->hasCapability('configuration.groups.edit'); |
||||
$row->can_delete = $this->logged_user->hasCapability('configuration.groups.delete'); |
||||
$row->child_groups_csv = collection($row->child_groups)->reduce(function ($csv, $child_group) { return empty($csv) ? $child_group->description : ($csv . ', ' . $child_group->description); }, ''); |
||||
return $row; |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
$this->paginate = [ |
||||
'sortableFields' => ['description', 'is_default'], |
||||
]; |
||||
|
||||
$this->set('groups', $this->getRequest()->is(['json', 'xml', 'csv']) ? $groups : $this->paginate($groups)); |
||||
|
||||
if ($this->getRequest()->is('csv')) { |
||||
if (!$this->logged_user->hasCapability('configuration.groups.export_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
// docs here: https://github.com/FriendsOfCake/cakephp-csvview |
||||
$header = [ |
||||
__('Descrizione'), |
||||
__('Profilo Default'), |
||||
__('Profili Associati'), |
||||
]; |
||||
$extract = [ |
||||
'description', |
||||
function (array $row) { |
||||
return $row['is_default'] ? __('SI') : __('NO'); |
||||
}, |
||||
function (array $row) { |
||||
return collection($row['child_groups'])->reduce(function ($csv, $child_group) { return empty($csv) ? $child_group['description'] : ($csv . ', ' . $child_group['description']); }, ''); |
||||
}, |
||||
]; |
||||
$this->viewBuilder() |
||||
->setClassName(CustomCsvView::class) |
||||
->setOptions([ |
||||
'header' => $header, |
||||
'extract' => $extract, |
||||
]); |
||||
$dateTime = DateTime::now(); |
||||
$timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); |
||||
$this->setResponse($this->getResponse()->withDownload("profiles_$timestamp.csv")); |
||||
} |
||||
$this->viewBuilder()->setOption('serialize', 'groups'); |
||||
} |
||||
|
||||
/** |
||||
* view |
||||
* |
||||
* @param Int $id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function view($id = null) |
||||
{ |
||||
if (!$this->logged_user->hasCapability('configuration.groups.read')) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$group = $this->Groups->get($id, contain: ['Actors', 'ChildGroups']); |
||||
|
||||
$group->can_handle_capabilities = $this->logged_user->hasCapability('configuration.groups.capabilities'); |
||||
$group->can_edit = $this->logged_user->hasCapability('configuration.groups.edit'); |
||||
$group->can_delete = $this->logged_user->hasCapability('configuration.groups.delete'); |
||||
$group->child_groups_csv = collection($group->child_groups)->reduce(function ($csv, $child_group) { return empty($csv) ? $child_group->description : ($csv . ', ' . $child_group->description); }, ''); |
||||
|
||||
$this->set(compact('group')); |
||||
$this->viewBuilder()->setOption('serialize', 'group'); |
||||
} |
||||
|
||||
/** |
||||
* add |
||||
* |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function add() |
||||
{ |
||||
if (!$this->logged_user->hasCapability('configuration.groups.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$group = $this->Groups->newEmptyEntity(); |
||||
if ($this->request->is('post')) { |
||||
$group = $this->Groups->patchEntity($group, $this->request->getData()); |
||||
if ($this->Groups->save($group)) { |
||||
$this->Flash->success(__('Profilo Utente creato con successo.')); |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
$this->Flash->error(__('Errore durante la creazione del Profilo Utente')); |
||||
} |
||||
$child_groups = $this->fetchTable('Groups')->find('list')->contain(['Actors'])->order(['Groups.description' => 'ASC']); |
||||
$this->set(compact('group')); |
||||
$this->set(compact('child_groups')); |
||||
} |
||||
|
||||
/** |
||||
* edit |
||||
* |
||||
* @param Int $id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function edit($id = null) |
||||
{ |
||||
if (!$this->logged_user->hasCapability('configuration.groups.edit')) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$group = $this->Groups->get($id, contain: ['Actors', 'ChildGroups']); |
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$group = $this->Groups->patchEntity($group, $this->request->getData()); |
||||
if ($this->Groups->save($group)) { |
||||
$this->Flash->success(__('Profilo Utente "{0}" modificato con successo.', $group->description)); |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
$this->Flash->error(__('Errore durante la modifica del Profilo Utente "{0}". Riprovare di nuovo.', $group->description)); |
||||
} |
||||
$child_groups = $this->fetchTable('Groups')->find('list')->contain(['Actors'])->order(['Groups.description' => 'ASC']); |
||||
$this->set(compact('group')); |
||||
$this->set(compact('child_groups')); |
||||
} |
||||
|
||||
/** |
||||
* delete |
||||
* |
||||
* @param Int $id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function delete($id = null) |
||||
{ |
||||
if (!$this->logged_user->hasCapability('configuration.groups.delete')) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$this->request->allowMethod(['post', 'delete']); |
||||
$group = $this->Groups->get($id, contain: ['Actors']); |
||||
|
||||
if ($this->Groups->Actors->delete($group->actor)) { |
||||
$this->Flash->success(__('Il Profilo Utente "{0}" è stato cancellato con successo', $group->description)); |
||||
} else { |
||||
$errors = $group->actor->getErrors(); |
||||
if (isset($errors['is_editable']['checkGroupIsEditable'])) { |
||||
$errorMessage = $errors['is_editable']['checkGroupIsEditable']; |
||||
$this->Flash->error($errorMessage); |
||||
} else { |
||||
$this->Flash->error(__('Errore durante la cancellazione del Profilo Utente "{0}". Riprovare di nuovo.', $group->description)); |
||||
} |
||||
} |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
|
||||
/** |
||||
* handleCapabilities |
||||
* |
||||
* @param Int $id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function handleCapabilities($id = null) |
||||
{ |
||||
if (!$this->logged_user->hasCapability('configuration.groups.capabilities')) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$group = $this->Groups->get($id, contain: ['Actors']); |
||||
|
||||
$group_capability_ids = $this->Groups->Capabilities->find() |
||||
->select(['id']) |
||||
->matching('Groups') |
||||
->where(['Groups.id' => $id]); |
||||
|
||||
if (!$this->logged_user->sys_admin) { |
||||
$group_capability_ids = $group_capability_ids |
||||
->where(['Capabilities.is_configurable' => 1]); |
||||
} |
||||
|
||||
$group_capability_ids = $group_capability_ids |
||||
->distinct() |
||||
->all() |
||||
->extract('id') |
||||
->toArray(); |
||||
|
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$group = $this->Groups->patchEntity($group, $this->request->getData(), ['group_id' => $group->id]); |
||||
if ($this->Groups->save($group)) { |
||||
$this->Flash->success(__('Profilo Utente "{0}" modificato con successo.', $group->description)); |
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
$this->Flash->error(__('Errore durante la modifica del Profilo Utente "{0}". Riprovare di nuovo.', $group->description)); |
||||
} |
||||
|
||||
$capability_groups = $this->Groups->Capabilities->CapabilityGroups->find() |
||||
->contain(['Capabilities' => function ($q) { |
||||
if (!$this->logged_user->sys_admin) { |
||||
$q->where(['Capabilities.is_configurable' => 1]); |
||||
} |
||||
return $q->order(['Capabilities.capability_group_id' => 'ASC', 'Capabilities.priority_group_id' => 'ASC', 'Capabilities.priority' => 'ASC', 'Capabilities.description']); |
||||
}]) |
||||
->order(['CapabilityGroups.description' => 'ASC']); |
||||
|
||||
$this->set(compact('group', 'group_capability_ids', 'capability_groups')); |
||||
$this->viewBuilder()->setOption('serialize', 'group'); |
||||
} |
||||
} |
||||
@ -0,0 +1,187 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
use Cake\Core\Configure; |
||||
use Cake\Http\Client; |
||||
use Cake\Http\Response; |
||||
use App\WGS\Geo\Geocoding; |
||||
use App\WGS\Geo\GeoValidation; |
||||
use App\WGS\Geo\LocationAttributesRetriever; |
||||
use App\WGS\Geo\IntGeoResourceAttributesRetriever; |
||||
use App\WGS\Geo\ExtGeoResourceAttributesRetriever; |
||||
use Cake\Http\Exception\BadRequestException; |
||||
use Cake\Http\Exception\NotFoundException; |
||||
|
||||
/** |
||||
* Map Controller |
||||
* |
||||
*/ |
||||
class MapsController extends AppController |
||||
{ |
||||
private $geo_resources = []; |
||||
|
||||
/** |
||||
* geoserver_proxy |
||||
* |
||||
* @param String $query_parameters |
||||
* @return String |
||||
*/ |
||||
private function geoserver_proxy(String $query_parameters): String |
||||
{ |
||||
$url = Configure::read('App.geoserverUrl') . Configure::read('App.geoserverAPP') . 'wfs?'; |
||||
$query_parameters = str_replace([' ', '>'], ['%20', '%3E'], $query_parameters); |
||||
$url .= $query_parameters; |
||||
$http = new Client(); |
||||
$response = $http->get($url, [], [ |
||||
'auth' => ['username' => Configure::read('App.geoserverUsername'), 'password' => Configure::read('App.geoserverPassword')] |
||||
]); |
||||
return $response->getStringBody(); |
||||
} |
||||
|
||||
/** |
||||
* get_location_attributes |
||||
* |
||||
* @param String $lat |
||||
* @param String $lon |
||||
* @return ?Array |
||||
*/ |
||||
private function get_location_attributes(String $lat, String $lon): ?Array { |
||||
$feature_collection = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $lon . ',' . $lat . ']},"properties":null}]}'; |
||||
$location = $this->fetchTable('Locations')->newEntity([ |
||||
'feature_collection' => $feature_collection, |
||||
]); |
||||
$lar = new LocationAttributesRetriever($location); |
||||
$lar_result = $lar->retrieve()[0] ?? null; |
||||
return $lar_result; |
||||
} |
||||
|
||||
/** |
||||
* get_matching_geo_resources |
||||
* |
||||
* @param String $lat |
||||
* @param String $lon |
||||
* @return ?Array |
||||
*/ |
||||
private function get_matching_geo_resources(String $lat, String $lon): ?Array { |
||||
$feature_collection = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $lon . ',' . $lat . ']},"properties":null}]}'; |
||||
$matching_geo_resources = []; |
||||
// inizializziamo l'array $mapped_fields con un array associativo con KEY id del campo e VALUE '': |
||||
$mapped_fields = collection($this->geo_resources)->reduce(function ($acc, $geo_resource) { |
||||
return array_merge($acc, array_fill_keys(array_values($geo_resource['attributes_fields']), '')); |
||||
}, []); |
||||
|
||||
foreach ($this->geo_resources as $geo_resource) { |
||||
if (isset($geo_resource['external']) && is_bool($geo_resource['external']) && $geo_resource['external']) { |
||||
$grar = new ExtGeoResourceAttributesRetriever($geo_resource['url'], $geo_resource['lon_parameter_name'], $geo_resource['lat_parameter_name']); |
||||
$grar_result = $grar->retrieve($lon, $lat); |
||||
if (isset($grar_result)) { |
||||
// scremiamo il risultato proveniente dal servizio esterno considerando solo gli attributi che ci interessano: |
||||
$grar_result = array_intersect_key($grar_result, $geo_resource['attributes_fields']); |
||||
$matching_geo_resources[$geo_resource['url']] = $grar_result; |
||||
foreach ($grar_result as $attribute_name => $attribute_value) { |
||||
$mapped_fields[$geo_resource['attributes_fields'][$attribute_name]] = $attribute_value; |
||||
} |
||||
} |
||||
} else { |
||||
$grar = new IntGeoResourceAttributesRetriever($geo_resource['table_name'], $geo_resource['geometry_name'], array_keys($geo_resource['attributes_fields'])); |
||||
$grar_result = $grar->retrieve($feature_collection)[0] ?? null; |
||||
if (isset($grar_result)) { |
||||
$matching_geo_resources[$geo_resource['table_name']] = $grar_result; |
||||
foreach ($grar_result as $attribute_name => $attribute_value) { |
||||
$mapped_fields[$geo_resource['attributes_fields'][$attribute_name]] = $attribute_value; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return ['matching_geo_resources' => $matching_geo_resources, 'mapped_fields' => $mapped_fields]; |
||||
} |
||||
|
||||
/** |
||||
* map_geocoding_result_content |
||||
* |
||||
* @param Array $content |
||||
* @return Array |
||||
*/ |
||||
private function map_geocoding_result_content(Array $content): Array { |
||||
$array_content = explode(", ", $content['display_name'] ?? ''); |
||||
$index_cursor = count($array_content) - 1; |
||||
if ($index_cursor > 0) $nation = $array_content[$index_cursor--]; |
||||
if ($index_cursor > 0) $cap = (Int)$array_content[$index_cursor] > 0 ? $array_content[$index_cursor--] : ''; |
||||
if ($index_cursor > 0) $region = $array_content[$index_cursor--]; |
||||
if ($index_cursor > 0) $province = $array_content[$index_cursor--]; |
||||
if ($index_cursor > 0) $district = $array_content[$index_cursor--]; |
||||
$address = $content['namedetails']['name'] ?? ''; |
||||
$description = $content['display_name'] ?? ''; |
||||
$lat = $content['lat'] ?? ''; |
||||
$lon = $content['lon'] ?? ''; |
||||
return ['nation' => $nation ?? '', 'cap' => $cap ?? '', 'region' => $region ?? '', 'province' => $province ?? '', 'district' => $district ?? '', 'address' => $address, 'lat' => $lat, 'lon' => $lon, 'description' => $description]; |
||||
} |
||||
|
||||
/** |
||||
* index |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function index () { |
||||
if(!$this->logged_user->hasCapability(['confiiguration.maps.view'])) throw new BadRequestException(__('Non hai i permessi')); |
||||
} |
||||
|
||||
/** |
||||
* getWfs |
||||
* |
||||
* @return Response |
||||
*/ |
||||
public function getWfs(): Response { |
||||
if(!$this->logged_user->hasCapability(['confiiguration.maps.view'])) throw new BadRequestException(__('Non hai i permessi')); |
||||
$response = $this->geoserver_proxy($this->request->getUri()->getQuery()); |
||||
return $this->getResponse()->withStringBody($response)->withType("application/json"); |
||||
} |
||||
|
||||
/** |
||||
* geocode |
||||
* |
||||
* @throws BadRequestException |
||||
* @throws NotFoundException |
||||
* @return Response |
||||
*/ |
||||
public function geocode(): Response { |
||||
if(!$this->logged_user->hasCapability(['confiiguration.maps.view'])) throw new BadRequestException(__('Non hai i permessi')); |
||||
// geo_resources, se presente, contiene le info per mappare campi aggiuntivi con attributi di |
||||
// una o + geo-risorse in base a dove il punto specificato ricade: |
||||
$geo_resources = json_decode($this->request->getQuery('geo_resources') ?? '', true); |
||||
if ($geo_resources !== null && is_array($geo_resources) && count($geo_resources) > 0) $this->geo_resources = $geo_resources; |
||||
|
||||
if ($this->request->getQuery('address') === null) throw new BadRequestException('geocode error: invalid address'); |
||||
|
||||
$separator = null; |
||||
|
||||
if (count(collection(explode(" ", $this->request->getQuery('address')))->filter(function ($part) { return is_numeric(trim($part)); })->toArray()) === 2) { |
||||
$separator = " "; |
||||
} |
||||
|
||||
if (count(collection(explode(",", $this->request->getQuery('address')))->filter(function ($part) { return is_numeric(trim($part)); })->toArray()) === 2) { |
||||
$separator = ","; |
||||
} |
||||
|
||||
if ($separator !== null) { |
||||
$address_parts = explode($separator, $this->request->getQuery('address')); |
||||
$lat = $address_parts[0] > $address_parts[1] ? $address_parts[0] : $address_parts[1]; |
||||
$lon = $address_parts[0] > $address_parts[1] ? $address_parts[1] : $address_parts[0]; |
||||
$feature_collection = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $lon . ',' . $lat . ']},"properties":null}]}'; |
||||
if (!GeoValidation::isValidGeometry(json_decode($feature_collection))) throw new BadRequestException('invalid coordinates or out of boundary!'); |
||||
$reverse_geocoding = Geocoding::performGeocoding('reverse', ['format' => 'json', 'namedetails' => '1', 'lat' => $lat, 'lon' => $lon]); |
||||
if (!empty($reverse_geocoding['contents'])) { |
||||
$mapped_geocoding_result_content = $this->map_geocoding_result_content($reverse_geocoding['contents']); |
||||
} |
||||
$lar_result = $this->get_location_attributes($lat, $lon); |
||||
$content = ['geo_resources' => $this->get_matching_geo_resources($lat, $lon), 'nation' => $mapped_geocoding_result_content['nation'] ?? '', 'cap' => $mapped_geocoding_result_content['cap'] ?? '', 'region' => $lar_result['region'] ?? $mapped_geocoding_result_content['region'] ?? '', 'province' => $lar_result['county_name'] ?? $mapped_geocoding_result_content['province'] ?? '', 'district_code' => $lar_result['district_code'] ?? '', 'district' => $lar_result['district_name'] ?? $mapped_geocoding_result_content['district'] ?? '', 'address' => $mapped_geocoding_result_content['address'] ?? '', 'lat' => $lat, 'lon' => $lon, 'description' => !empty($mapped_geocoding_result_content['description']) ? $mapped_geocoding_result_content['description'] : __('Punto alle coordinate (EPSG:4326) Latitudine: {0}, Longitudine: {1}', $lat, $lon)]; |
||||
return $this->getResponse()->withStringBody(json_encode($content))->withType("application/json"); |
||||
} |
||||
|
||||
$geocoding = Geocoding::performGeocoding('search', ['format' => 'json', 'namedetails' => '1', 'q' => $this->request->getQuery('address')]); |
||||
if (empty($geocoding['contents'])) throw new NotFoundException('geocode error: no contents'); |
||||
return $this->getResponse()->withStringBody(json_encode($geocoding['contents']))->withType("application/json"); |
||||
} |
||||
} |
||||
@ -0,0 +1,79 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
use Cake\Http\Exception\ForbiddenException; |
||||
|
||||
/** |
||||
* MobilePhones Controller |
||||
* |
||||
* @property \App\Model\Table\MobilePhonesTable $MobilePhones |
||||
*/ |
||||
class MobilePhonesController extends AppController |
||||
{ |
||||
/** |
||||
* add |
||||
* |
||||
* @param Int $actor_id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function add($actor_id) |
||||
{ |
||||
$actor = $this->MobilePhones->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); |
||||
// se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": |
||||
if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); |
||||
$actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); |
||||
if (!$this->logged_user->canAddContactsForActor($actor, 'mobile_phone')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); |
||||
|
||||
$mobilePhone = $this->MobilePhones->newEntity([ |
||||
'delivery' => [ |
||||
'actor_id' => $actor_id, |
||||
'delivery_type_id' => 1, |
||||
], |
||||
], ['validate' => false]); |
||||
|
||||
if ($this->request->is('post')) { |
||||
$mobilePhone = $this->MobilePhones->patchEntity($mobilePhone, $this->request->getData()); |
||||
if ($this->MobilePhones->save($mobilePhone)) { |
||||
$this->Flash->success(__('Il Cellulare è stato aggiunto con successo.')); |
||||
|
||||
return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); |
||||
} |
||||
$this->Flash->error(__('Errore durante l\'aggiunta del Cellulare')); |
||||
} |
||||
$mobilePhoneDescriptions = $this->MobilePhones->MobilePhoneDescriptions->find('list'); |
||||
$this->set(compact('actor', 'mobilePhone', 'mobilePhoneDescriptions')); |
||||
} |
||||
|
||||
/** |
||||
* edit |
||||
* |
||||
* @param Int $id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function edit($id = null) |
||||
{ |
||||
$mobilePhone = $this->MobilePhones->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); |
||||
|
||||
$actor = $this->MobilePhones->Deliveries->Actors->get($mobilePhone->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); |
||||
// se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": |
||||
if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); |
||||
$actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); |
||||
if (!$this->logged_user->canEditContactsForActor($actor, 'mobile_phone')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); |
||||
|
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$mobilePhone = $this->MobilePhones->patchEntity($mobilePhone, $this->request->getData()); |
||||
if ($this->MobilePhones->save($mobilePhone)) { |
||||
$this->Flash->success(__('Il Cellulare è stato modificato con successo.')); |
||||
|
||||
return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $mobilePhone->delivery->actor_id]); |
||||
} |
||||
$this->Flash->error(__('Errore durante la modifica del Cellulare. Riprovare di nuovo')); |
||||
} |
||||
$mobilePhoneDescriptions = $this->MobilePhones->MobilePhoneDescriptions->find('list'); |
||||
$this->set(compact('actor', 'mobilePhone', 'mobilePhoneDescriptions')); |
||||
} |
||||
} |
||||
@ -0,0 +1,97 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
use Cake\I18n\DateTime; |
||||
use Cake\View\JsonView; |
||||
|
||||
/** |
||||
* Notifications Controller |
||||
* |
||||
* @property \App\Model\Table\NotificationsTable $Notifications |
||||
* @method \App\Model\Entity\Notification[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class NotificationsController extends AppController |
||||
{ |
||||
public function viewClasses(): array |
||||
{ |
||||
return [JsonView::class]; |
||||
} |
||||
|
||||
/** |
||||
* getUserNotifications |
||||
* |
||||
* @return Array |
||||
*/ |
||||
private function getUserNotifications() |
||||
{ |
||||
return $this->fetchTable('Notifications') |
||||
->find() |
||||
->contain('NotificationTypes') |
||||
->where(['Notifications.user_id' => $this->logged_user->id, 'Notifications.read_by_user IS NULL']) |
||||
->order(['Notifications.created' => 'DESC']) |
||||
->all() |
||||
->reduce(function ($acc, $user_notification) { |
||||
$notification_info = json_decode($user_notification->info); |
||||
$body = strlen($notification_info->body) > 200 ? substr($notification_info->body, 0, 197) . '...' : $notification_info->body; |
||||
$icon = $user_notification->notification_type->icon ?? 'bell'; |
||||
$time_ago = (new DateTime($user_notification->created))->timeAgoInWords(); |
||||
$acc[] = ['id' => $user_notification->id, 'icon' => $icon, 'title' => $notification_info->title, 'body' => $body, 'time_ago' => $time_ago]; |
||||
return $acc; |
||||
}, []); |
||||
} |
||||
|
||||
/** |
||||
* readAll |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function readAll() |
||||
{ |
||||
$this->fetchTable('Notifications')->updateAll(['read_by_user' => new DateTime()], ['user_id' => $this->logged_user->id, 'read_by_user IS NULL']); |
||||
$user_notifications = $this->getUserNotifications(); |
||||
$this->set('user_notifications', $user_notifications); |
||||
$this->viewBuilder()->setOption('serialize', 'user_notifications')->setLayout('ajax'); |
||||
} |
||||
|
||||
/** |
||||
* testAll |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function testAll() |
||||
{ |
||||
$this->request->allowMethod(['post']); |
||||
$this->sendNotifications(null, 'test_all', []); |
||||
return $this->redirect('/'); |
||||
} |
||||
|
||||
/** |
||||
* view |
||||
* |
||||
* @todo recuperare la specializzazione del CO e fare redirect alla view dell'oggetto specifico! |
||||
* @param Int $id |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function view($id) |
||||
{ |
||||
$notification = $this->fetchTable('Notifications')->get($id); |
||||
$notification->read_by_user = new DateTime(); |
||||
|
||||
if (!$this->fetchTable('Notifications')->save($notification)) { |
||||
$this->Flash->error(__('Errore durante la cancellazione della notifica')); |
||||
} |
||||
|
||||
$notification_info = json_decode($notification->info); |
||||
$link = !empty($notification_info->link) ? $notification_info->link : '/'; |
||||
return $this->redirect($link); |
||||
} |
||||
|
||||
public function index() |
||||
{ |
||||
$user_notifications = $this->getUserNotifications(); |
||||
$this->set('user_notifications', $user_notifications); |
||||
$this->viewBuilder()->setOption('serialize', 'user_notifications')->setLayout('ajax'); |
||||
} |
||||
} |
||||
@ -0,0 +1,204 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
use Cake\View\JsonView; |
||||
use App\View\CustomCsvView; |
||||
use Cake\I18n\DateTime; |
||||
use Cake\Http\Exception\ForbiddenException; |
||||
|
||||
/** |
||||
* Organisations Controller |
||||
* |
||||
* @property \App\Model\Table\OrganisationsTable $Organisations |
||||
* @method \App\Model\Entity\Organisation[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class OrganisationsController extends AppController |
||||
{ |
||||
public function viewClasses(): array |
||||
{ |
||||
return [JsonView::class, CustomCsvView::class]; |
||||
} |
||||
|
||||
/** |
||||
* index |
||||
* |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function index() |
||||
{ |
||||
if (!$this->logged_user->hasCapability('configuration.organisations.read')) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$organisations = $this->Organisations->find() |
||||
->contain(['OrganisationTypes', 'Actors']); |
||||
|
||||
$this->set('total_organisations', $organisations->count()); |
||||
// applichiamo gli eventuali filtri presenti: |
||||
$organisations = $this->applyFilters($organisations); |
||||
$this->set('filtered_organisations', $organisations->count()); |
||||
|
||||
if (!$this->getRequest()->is(['json', 'xml', 'csv'])) { |
||||
$organisations = $organisations |
||||
->formatResults(function (\Cake\Collection\CollectionInterface $results) { |
||||
return $results->map(function ($row) { |
||||
$row->can_edit = $this->logged_user->organisation_id == $row->id || $this->logged_user->hasCapability('configuration.organisations.edit'); |
||||
$row->can_delete = $this->logged_user->organisation_id == $row->id || $this->logged_user->hasCapability('configuration.organisations.delete'); |
||||
return $row; |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
$this->paginate = [ |
||||
'sortableFields' => ['Actors.description', 'acronym', 'OrganisationTypes.description', 'address', 'district', 'cap', 'province'], |
||||
]; |
||||
|
||||
$this->set('organisations', $this->getRequest()->is(['json', 'xml', 'csv']) ? $organisations : $this->paginate($organisations)); |
||||
|
||||
if ($this->getRequest()->is('csv')) { |
||||
if (!$this->logged_user->hasCapability('configuration.organisations.export_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
// docs here: https://github.com/FriendsOfCake/cakephp-csvview |
||||
$header = [ |
||||
__('Descrizione'), |
||||
__('Acronimo'), |
||||
__('Tipologia'), |
||||
__('Indirizzo'), |
||||
__('Comune'), |
||||
__('CAP'), |
||||
__('Provincia'), |
||||
__('Recapiti'), |
||||
]; |
||||
$extract = [ |
||||
function (array $row) { |
||||
return $row['actor']['description']; |
||||
}, |
||||
'acronym', |
||||
function (array $row) { |
||||
return $row['organisation_type']['description']; |
||||
}, |
||||
'address', |
||||
'district', |
||||
'cap', |
||||
'province', |
||||
function (array $row) { |
||||
return $row['actor']['contacts']; |
||||
}, |
||||
]; |
||||
$this->viewBuilder() |
||||
->setClassName(CustomCsvView::class) |
||||
->setOptions([ |
||||
'header' => $header, |
||||
'extract' => $extract, |
||||
]); |
||||
$dateTime = DateTime::now(); |
||||
$timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); |
||||
$this->setResponse($this->getResponse()->withDownload("organisations_$timestamp.csv")); |
||||
} |
||||
$this->viewBuilder()->setOption('serialize', 'organisations'); |
||||
} |
||||
|
||||
/** |
||||
* view |
||||
* |
||||
* @param Int $id |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function view($id = null) |
||||
{ |
||||
if ($this->logged_user->organisation_id != $id && !$this->logged_user->hasCapability('configuration.organisations.read')) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$organisation = $this->Organisations->get($id, contain: ['ControllableObjectInterfaces', 'OrganisationTypes', 'Actors']); |
||||
|
||||
$organisation->can_handle_contacts = $this->logged_user->canViewContactsForActor($this->Organisations->Actors->get($organisation->actor_id, contain: ['Organisations'])); |
||||
$organisation->can_edit = $this->logged_user->organisation_id == $id || $this->logged_user->hasCapability('configuration.organisations.edit'); |
||||
$organisation->can_delete = $this->logged_user->organisation_id == $id || $this->logged_user->hasCapability('configuration.organisations.delete'); |
||||
|
||||
$organisationTypes = $this->Organisations->OrganisationTypes->find('list')->order(['OrganisationTypes.description' => 'ASC']); |
||||
$this->set(compact('organisation', 'organisationTypes')); |
||||
} |
||||
|
||||
/** |
||||
* add |
||||
* |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function add() |
||||
{ |
||||
if (!$this->logged_user->hasCapability('configuration.organisations.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$organisation = $this->Organisations->newEmptyEntity(); |
||||
if ($this->request->is('post')) { |
||||
$organisation = $this->Organisations->patchEntity($organisation, $this->request->getData()); |
||||
if ($this->Organisations->save($organisation)) { |
||||
$this->Flash->success(__('Organizzazione creata con successo.')); |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
$errorMessage = $organisation->getError('attachment')[0] ?? ''; |
||||
$this->Flash->error(__('Errore durante la creazione dell\'organizzazione. ' . $errorMessage)); |
||||
} |
||||
$organisationTypes = $this->Organisations->OrganisationTypes->find('list')->order(['OrganisationTypes.description' => 'ASC']); |
||||
$this->set(compact('organisation', 'organisationTypes')); |
||||
} |
||||
|
||||
/** |
||||
* edit |
||||
* |
||||
* @param Int $id |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function edit($id = null) |
||||
{ |
||||
if ($this->logged_user->organisation_id != $id && !$this->logged_user->hasCapability('configuration.organisations.edit')) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$organisation = $this->Organisations->get($id, contain: ['Actors', 'ControllableObjectInterfaces', 'OrganisationTypes']); |
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$organisation = $this->Organisations->patchEntity($organisation, $this->request->getData()); |
||||
if ($this->Organisations->save($organisation)) { |
||||
$this->Flash->success(__('Organizzazione "{0}" modificata con successo.', $organisation->actor->description)); |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
$errMessage = $organisation->getError('attachment')[0] ?? ''; |
||||
$this->Flash->error(__('Errore durante la modifica dell\'organizzazione "{0}". Riprovare di nuovo. ', $organisation->actor->description) . $errMessage); |
||||
} |
||||
$organisationTypes = $this->Organisations->OrganisationTypes->find('list')->order(['OrganisationTypes.description' => 'ASC']); |
||||
$this->set(compact('organisation', 'organisationTypes')); |
||||
} |
||||
|
||||
/** |
||||
* delete |
||||
* |
||||
* @param Int $id |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function delete($id = null) |
||||
{ |
||||
if ($this->logged_user->organisation_id != $id && !$this->logged_user->hasCapability('configuration.organisations.delete')) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$this->request->allowMethod(['post', 'delete']); |
||||
$organisation = $this->Organisations->get($id, contain: ['Actors']); |
||||
|
||||
// controlliamo se il type è cittadini e preveniamo la possibilità di delete. |
||||
if($organisation->organisation_type_id === 7) { |
||||
$this->Flash->error(__('Impossibile eliminare l\'organizzazione "{0}".', $organisation->actor->description)); |
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
|
||||
$are_there_users_in_this_org = $this->fetchTable('Users')->find()->where(['Users.organisation_id' => $id])->count(); |
||||
if ($are_there_users_in_this_org > 0) { |
||||
$this->Flash->error(__('Impossibile eliminare l\'organizzazione "{0}". Ci sono {1} utenti collegati ad essa.', $organisation->actor->description, $are_there_users_in_this_org)); |
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
|
||||
if ($this->Organisations->Actors->delete($organisation->actor)) { |
||||
$this->Flash->success(__('L\'organizzazione "{0}" è stata cancellata con successo', $organisation->actor->description)); |
||||
} else { |
||||
$this->Flash->error(__('Errore durante la cancellazione dell\'organizzazione "{0}". Riprovare di nuovo.', $organisation->actor->description)); |
||||
} |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
} |
||||
@ -0,0 +1,78 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
use Cake\Http\Exception\ForbiddenException; |
||||
|
||||
/** |
||||
* Pecs Controller |
||||
* |
||||
* @property \App\Model\Table\PecsTable $Pecs |
||||
*/ |
||||
class PecsController extends AppController |
||||
{ |
||||
/** |
||||
* add |
||||
* |
||||
* @param Int $actor_id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function add($actor_id) |
||||
{ |
||||
$actor = $this->Pecs->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); |
||||
// se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": |
||||
if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); |
||||
$actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); |
||||
if (!$this->logged_user->canAddContactsForActor($actor, 'pec')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); |
||||
|
||||
$pec = $this->Pecs->newEntity([ |
||||
'delivery' => [ |
||||
'actor_id' => $actor_id, |
||||
'delivery_type_id' => 6, |
||||
], |
||||
], ['validate' => false]); |
||||
|
||||
if ($this->request->is('post')) { |
||||
$pec = $this->Pecs->patchEntity($pec, $this->request->getData()); |
||||
if ($this->Pecs->save($pec)) { |
||||
$this->Flash->success(__('La PEC è stata aggiunta con successo.')); |
||||
|
||||
return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); |
||||
} |
||||
$this->Flash->error(__('Errore durante l\'aggiunta della PEC')); |
||||
} |
||||
$pecDescriptions = $this->Pecs->PecDescriptions->find('list'); |
||||
$this->set(compact('actor', 'pec', 'pecDescriptions')); |
||||
} |
||||
|
||||
/** |
||||
* edit |
||||
* |
||||
* @param Int $id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function edit($id = null) |
||||
{ |
||||
$pec = $this->Pecs->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); |
||||
|
||||
$actor = $this->Pecs->Deliveries->Actors->get($pec->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); |
||||
// se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": |
||||
if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); |
||||
$actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); |
||||
if (!$this->logged_user->canEditContactsForActor($actor, 'pec')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); |
||||
|
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$pec = $this->Pecs->patchEntity($pec, $this->request->getData()); |
||||
if ($this->Pecs->save($pec)) { |
||||
$this->Flash->success(__('La PEC è stata modificata con successo.')); |
||||
|
||||
return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $pec->delivery->actor_id]); |
||||
} |
||||
$this->Flash->error(__('Errore durante la modifica della PEC. Riprovare di nuovo')); |
||||
} |
||||
$pecDescriptions = $this->Pecs->PecDescriptions->find('list'); |
||||
$this->set(compact('actor', 'pec', 'pecDescriptions')); |
||||
} |
||||
} |
||||
@ -0,0 +1,78 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
use Cake\Http\Exception\ForbiddenException; |
||||
|
||||
/** |
||||
* Phones Controller |
||||
* |
||||
* @property \App\Model\Table\PhonesTable $Phones |
||||
*/ |
||||
class PhonesController extends AppController |
||||
{ |
||||
/** |
||||
* add |
||||
* |
||||
* @param Int $actor_id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function add($actor_id) |
||||
{ |
||||
$actor = $this->Phones->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); |
||||
// se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": |
||||
if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); |
||||
$actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); |
||||
if (!$this->logged_user->canAddContactsForActor($actor, 'phone')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); |
||||
|
||||
$phone = $this->Phones->newEntity([ |
||||
'delivery' => [ |
||||
'actor_id' => $actor_id, |
||||
'delivery_type_id' => 4, |
||||
], |
||||
], ['validate' => false]); |
||||
|
||||
if ($this->request->is('post')) { |
||||
$phone = $this->Phones->patchEntity($phone, $this->request->getData()); |
||||
if ($this->Phones->save($phone)) { |
||||
$this->Flash->success(__('Il Telefono è stato aggiunto con successo.')); |
||||
|
||||
return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); |
||||
} |
||||
$this->Flash->error(__('Errore durante l\'aggiunta del Telefono')); |
||||
} |
||||
$phoneDescriptions = $this->Phones->PhoneDescriptions->find('list'); |
||||
$this->set(compact('actor', 'phone', 'phoneDescriptions')); |
||||
} |
||||
|
||||
/** |
||||
* edit |
||||
* |
||||
* @param Int $id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function edit($id = null) |
||||
{ |
||||
$phone = $this->Phones->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); |
||||
|
||||
$actor = $this->Phones->Deliveries->Actors->get($phone->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); |
||||
// se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": |
||||
if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); |
||||
$actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); |
||||
if (!$this->logged_user->canEditContactsForActor($actor, 'phone')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); |
||||
|
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$phone = $this->Phones->patchEntity($phone, $this->request->getData()); |
||||
if ($this->Phones->save($phone)) { |
||||
$this->Flash->success(__('Il Telefono è stato modificato con successo.')); |
||||
|
||||
return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $phone->delivery->actor_id]); |
||||
} |
||||
$this->Flash->error(__('Errore durante la modifica del Telefono. Riprovare di nuovo')); |
||||
} |
||||
$phoneDescriptions = $this->Phones->PhoneDescriptions->find('list'); |
||||
$this->set(compact('actor', 'phone', 'phoneDescriptions')); |
||||
} |
||||
} |
||||
@ -0,0 +1,174 @@
|
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
use Cake\Event\EventInterface; |
||||
use Cake\Http\Exception\ForbiddenException; |
||||
use Cake\Datasource\ConnectionManager; |
||||
use Exception; |
||||
|
||||
/** |
||||
* Privacy Controller |
||||
* |
||||
*/ |
||||
class PrivacyController extends AppController |
||||
{ |
||||
|
||||
public function beforeFilter(EventInterface $event) |
||||
{ |
||||
$this->Authentication->allowUnauthenticated(['view_public']); |
||||
} |
||||
|
||||
/** |
||||
* Index method |
||||
* |
||||
* @return \Cake\Http\Response|null|void Renders view |
||||
*/ |
||||
public function view_public() |
||||
{ |
||||
$privacy = $this->Privacy->findPrivacy(); |
||||
$this->viewBuilder()->setLayout('view_public'); |
||||
$this->set(compact('privacy')); |
||||
} |
||||
|
||||
/** |
||||
* View method |
||||
* |
||||
* @return \Cake\Http\Response|null|void Renders view |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function view() |
||||
{ |
||||
$breadcrumbs = $this->retrieveBreadcrumbs('view'); |
||||
$privacy = $this->Privacy->findPrivacy(); |
||||
$this->set(compact('privacy', 'breadcrumbs')); |
||||
} |
||||
|
||||
/** |
||||
* Edit method |
||||
* |
||||
* @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function edit() |
||||
{ |
||||
if (!$this->logged_user->hasCapability(['configuration.privacy.edit'])) { |
||||
throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
} |
||||
|
||||
$breadcrumbs = $this->retrieveBreadcrumbs('edit'); |
||||
$privacy = $this->Privacy->findPrivacy(); |
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$privacy = $this->Privacy->patchEntity($privacy, $this->request->getData()); |
||||
try { |
||||
$connection = ConnectionManager::get('default'); |
||||
$connection->begin(); |
||||
if ($this->Privacy->save($privacy)) { |
||||
$this->Privacy->PrivacyUsers->deleteAll(['privacy_id' => $privacy->id]); |
||||
$connection->commit(); |
||||
$this->Flash->success(__('La privacy è stata salvata con successo.')); |
||||
} else { |
||||
$connection->rollback(); |
||||
$this->Flash->error(__('La privacy non è stata salvata. Riprova, per favore.')); |
||||
} |
||||
} catch(Exception $e) { |
||||
$connection->rollback(); |
||||
$this->Flash->error(__('Errore. La privacy non è stata salvata.')); |
||||
} |
||||
} |
||||
$this->set(compact('privacy', 'breadcrumbs')); |
||||
} |
||||
|
||||
public function accept_privacy() |
||||
{ |
||||
$hasConsent = $this->Privacy->PrivacyUsers->hasConsent($this->logged_user->id); |
||||
if ($hasConsent) { |
||||
$this->Flash->error(__('Hai già accettato la privacy.')); |
||||
return $this->redirect(['controller' => 'Dashboard', 'action' => 'index']); |
||||
} |
||||
$breadcrumbs = $this->retrieveBreadcrumbs('accept_privacy'); |
||||
$privacy = $this->Privacy->findPrivacy(); |
||||
if (!$privacy) { |
||||
$this->Flash->error(__('La privacy non è disponibile.')); |
||||
return $this->redirect(['controller' => 'Dashboard', 'action' => 'index']); |
||||
} |
||||
|
||||
if ($this->request->is(['post', 'put', 'patch'])) { |
||||
if ($this->Privacy->PrivacyUsers->saveConsent($this->logged_user->id, $privacy->id)) { |
||||
$this->Flash->success(__('La privacy è stata accettata con successo.')); |
||||
$this->redirect(['controller' => 'Dashboard', 'action' => 'index']); |
||||
} else { |
||||
$this->Flash->error(__('Errore. La privacy non è stata accettata.')); |
||||
} |
||||
} |
||||
$this->set(compact('privacy', 'breadcrumbs')); |
||||
} |
||||
|
||||
private function retrieveBreadcrumbs(string $action): array |
||||
{ |
||||
$breadcrumbs = [ |
||||
'edit' => [ |
||||
[ |
||||
'title' => 'Home', |
||||
'icon' => 'fa fa-home', |
||||
'url' => '/', |
||||
], |
||||
[ |
||||
'title' => __('Configurazioni'), |
||||
'icon' => 'fa fa-wrench', |
||||
], |
||||
[ |
||||
'title' => __('Privacy'), |
||||
'icon' => 'fa fa-wrench', |
||||
], |
||||
[ |
||||
'title' => __('Modifica privacy'), |
||||
'icon' => 'fa fa-pencil-alt', |
||||
], |
||||
], |
||||
'view' => |
||||
[ |
||||
[ |
||||
'title' => 'Home', |
||||
'icon' => 'fa fa-home', |
||||
'url' => '/', |
||||
], |
||||
[ |
||||
'title' => __('Configurazioni'), |
||||
'icon' => 'fa fa-wrench', |
||||
], |
||||
[ |
||||
'title' => __('Privacy'), |
||||
'icon' => 'fa fa-wrench', |
||||
], |
||||
[ |
||||
'title' => __('Visualizza privacy'), |
||||
'icon' => 'fa fa-info', |
||||
], |
||||
], |
||||
'accept_privacy' => [ |
||||
[ |
||||
'title' => 'Home', |
||||
'icon' => 'fa fa-home', |
||||
'url' => '/', |
||||
], |
||||
[ |
||||
'title' => __('Configurazioni'), |
||||
'icon' => 'fa fa-wrench', |
||||
], |
||||
[ |
||||
'title' => __('Privacy'), |
||||
'icon' => 'fa fa-wrench', |
||||
], |
||||
[ |
||||
'title' => __('Visualizzazione privacy'), |
||||
'icon' => 'fa fa-info', |
||||
], |
||||
] |
||||
]; |
||||
|
||||
return $breadcrumbs[$action] ?? []; |
||||
} |
||||
} |
||||
@ -0,0 +1,91 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
use Cake\Http\Exception\ForbiddenException; |
||||
|
||||
/** |
||||
* Tags Controller |
||||
* |
||||
* @property \App\Model\Table\TagsTable $Tags |
||||
*/ |
||||
class TagsController extends AppController |
||||
{ |
||||
/** |
||||
* Index method |
||||
* |
||||
* @return \Cake\Http\Response|null|void Renders view |
||||
*/ |
||||
public function index() |
||||
{ |
||||
if (!$this->logged_user->hasCapability(['configuration.tags.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
$tags = $this->Tags->find()->formatResults(function (\Cake\Collection\CollectionInterface $results) { |
||||
return $results->map(function ($row) { |
||||
$row->can_edit = $this->logged_user->hasCapability('configuration.tags.edit'); |
||||
$row->can_view = $this->logged_user->hasCapability('configuration.tags.disable'); |
||||
return $row; |
||||
}); |
||||
}); |
||||
$tags = $this->paginate($tags); |
||||
$this->set(compact('tags')); |
||||
} |
||||
|
||||
/** |
||||
* View method |
||||
* |
||||
* @param string|null $id Tag id. |
||||
* @return \Cake\Http\Response|null|void Renders view |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function view($id = null) |
||||
{ |
||||
if (!$this->logged_user->hasCapability(['configuration.tags.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
$tag = $this->Tags->get($id); |
||||
$this->set(compact('tag')); |
||||
} |
||||
|
||||
/** |
||||
* Add method |
||||
* |
||||
* @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. |
||||
*/ |
||||
public function add() |
||||
{ |
||||
if (!$this->logged_user->hasCapability(['configuration.tags.add'])) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
$tag = $this->Tags->newEmptyEntity(); |
||||
if ($this->request->is('post')) { |
||||
$tag = $this->Tags->patchEntity($tag, $this->request->getData()); |
||||
if ($this->Tags->save($tag, ['associated' => ['ControllableObjects']])) { |
||||
$this->Flash->success(__('Il nuovo tag è stato creato')); |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
$this->Flash->error(__('Errore nella creazione del nuovo tag.') . json_encode($tag->getErrors())); |
||||
} |
||||
$this->set(compact('tag')); |
||||
} |
||||
|
||||
/** |
||||
* Edit method |
||||
* |
||||
* @param string|null $id Tag id. |
||||
* @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function edit($id = null) |
||||
{ |
||||
if (!$this->logged_user->hasCapability(['configuration.tags.edit'])) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
$tag = $this->Tags->find()->contain(['ControllableObjects'])->where(['Tags.id' => $id])->first(); |
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$tag = $this->Tags->patchEntity($tag, $this->request->getData(), ['filename_as_tag' => true, 'associated' => ['ControllableObjects' => ['associated' => ['Attachments']]]]); |
||||
if ($this->Tags->save($tag)) { |
||||
$this->Flash->success(__('Il tag è stato salvato.')); |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
$this->Flash->error(__('Errore durante il salvataggio del tag.') . json_encode($tag->getErrors())); |
||||
} |
||||
$this->set(compact('tag')); |
||||
} |
||||
} |
||||
@ -0,0 +1,76 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
use Cake\Http\Exception\ForbiddenException; |
||||
|
||||
/** |
||||
* TelegramChats Controller |
||||
* |
||||
* @property \App\Model\Table\TelegramChatsTable $TelegramChats |
||||
*/ |
||||
class TelegramChatsController extends AppController |
||||
{ |
||||
/** |
||||
* add |
||||
* |
||||
* @param Int $actor_id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function add($actor_id) |
||||
{ |
||||
$actor = $this->TelegramChats->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); |
||||
// se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": |
||||
if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); |
||||
$actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); |
||||
if (!$this->logged_user->canAddContactsForActor($actor, 'telegram_chat')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); |
||||
|
||||
$telegram_chat = $this->TelegramChats->newEntity([ |
||||
'delivery' => [ |
||||
'actor_id' => $actor_id, |
||||
'delivery_type_id' => 5, |
||||
], |
||||
], ['validate' => false]); |
||||
|
||||
if ($this->request->is('post')) { |
||||
$telegram_chat = $this->TelegramChats->patchEntity($telegram_chat, $this->request->getData()); |
||||
if ($this->TelegramChats->save($telegram_chat)) { |
||||
$this->Flash->success(__('La Chat Telegram è stata aggiunta con successo.')); |
||||
|
||||
return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); |
||||
} |
||||
$this->Flash->error(__('Errore durante l\'aggiunta della Chat Telegram')); |
||||
} |
||||
$this->set(compact('actor', 'telegram_chat')); |
||||
} |
||||
|
||||
/** |
||||
* edit |
||||
* |
||||
* @param Int $id |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function edit($id = null) |
||||
{ |
||||
$telegram_chat = $this->TelegramChats->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); |
||||
|
||||
$actor = $this->TelegramChats->Deliveries->Actors->get($telegram_chat->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); |
||||
// se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": |
||||
if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); |
||||
$actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); |
||||
if (!$this->logged_user->canEditContactsForActor($actor, 'telegram_chat')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); |
||||
|
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$telegram_chat = $this->TelegramChats->patchEntity($telegram_chat, $this->request->getData()); |
||||
if ($this->TelegramChats->save($telegram_chat)) { |
||||
$this->Flash->success(__('La Chat Telegram è stata modificata con successo.')); |
||||
|
||||
return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $telegram_chat->delivery->actor_id]); |
||||
} |
||||
$this->Flash->error(__('Errore durante la modifica della Chat Telegram. Riprovare di nuovo')); |
||||
} |
||||
$this->set(compact('actor', 'telegram_chat')); |
||||
} |
||||
} |
||||
@ -0,0 +1,624 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
use Cake\Event\EventInterface; |
||||
use Cake\View\JsonView; |
||||
use App\View\CustomCsvView; |
||||
use Cake\I18n\DateTime; |
||||
use Cake\Http\Exception\ForbiddenException; |
||||
use Cake\Http\Exception\NotFoundException; |
||||
use Cake\Core\Configure; |
||||
use App\WGS\Auth\OpenIdConnectClient; |
||||
|
||||
/** |
||||
* Users Controller |
||||
* |
||||
* @property \App\Model\Table\UsersTable $Users |
||||
* @method \App\Model\Entity\User[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class UsersController extends AppController |
||||
{ |
||||
public function beforeFilter(EventInterface $event) |
||||
{ |
||||
$this->Authentication->allowUnauthenticated(['logout', 'login', 'login_oidc', 'login_oidc_authenticated', 'passwordRecovery', 'chooseNewPassword', 'oneTimePassword', 'add_citizen', 'verify_citizen']); |
||||
} |
||||
|
||||
public function viewClasses(): array |
||||
{ |
||||
return [JsonView::class, CustomCsvView::class]; |
||||
} |
||||
|
||||
public function login_oidc() |
||||
{ |
||||
OpenIdConnectClient::authorize( |
||||
Configure::read('App.oidc.authUrl'), |
||||
Configure::read('App.oidc.clientId'), |
||||
Configure::read('App.oidc.scopes'), |
||||
Configure::read('App.oidc.redirectUri') |
||||
); |
||||
} |
||||
|
||||
public function login_oidc_authenticated() |
||||
{ |
||||
try { |
||||
$access_token = OpenIdConnectClient::get_access_token( |
||||
Configure::read('App.oidc.tokenUrl'), |
||||
Configure::read('App.oidc.issuer'), |
||||
Configure::read('App.oidc.clientId'), |
||||
Configure::read('App.oidc.clientSecret'), |
||||
Configure::read('App.oidc.redirectUri') |
||||
); |
||||
$userinfo = OpenIdConnectClient::get_user_info(Configure::read('App.oidc.userinfoUrl'), Configure::read('App.oidc.userinfo_claim_key'), $access_token); |
||||
$userinfo_claim_value = $userinfo[Configure::read('App.oidc.userinfo_claim_key')]; |
||||
$user = $this->Users->find()->where(['Users.' . Configure::read('App.oidc.usermodel_matching_attribute') => $userinfo_claim_value]); |
||||
if ($user->count() > 1) throw new \Exception(__('Non è stato possibile identificare in maniera univoca l\'utente in base all\'attributo \' {0} \' ricevuto dal provider', Configure::read('App.oidc.userinfo_claim_key'))); |
||||
$user = $user->first(); |
||||
$isUserVerified = $user?->is_verified ?? false; |
||||
if ($user && $isUserVerified) { |
||||
$this->Authentication->setIdentity($user); |
||||
} else { |
||||
if (!$user) { |
||||
$citizenRegistrationDTO = (new \App\WGS\Utils\Dto\Users\CitizenRegistrationDTO()) |
||||
->setShowAlert(true) |
||||
// attenzione!!!!!! se $userinfo_claim_value NON COINCIDE CON IL CF, NON FUNZIONA + !!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
->setFiscalCode($userinfo[Configure::read('App.oidc.userinfo_claim_key')] ?? '') |
||||
->setName($userinfo['given_name'] ?? '') |
||||
->setSurname($userinfo['family_name'] ?? '') |
||||
->setGender($userinfo['gender'] ?? '') |
||||
->setBirthdate($userinfo['birthdate'] ?? ''); |
||||
$this->request->getSession()->write('showCitizenRegistration', $citizenRegistrationDTO); |
||||
$errorMessage = __('Errore durante l\'autenticazione mediante {0} "Utente non trovato". Riprovare di nuovo o utilizzare le credenziali di accesso', Configure::read('App.oidc.idp_name', 'OpenID Connect')); |
||||
} else if ($user && !$isUserVerified) { |
||||
$errorMessage = __('Utente non verificato. Controlla la tua email per completare la verifica.'); |
||||
} |
||||
$this->Flash->error($errorMessage); |
||||
} |
||||
return $this->redirect('/'); |
||||
} catch (\Exception $e) { |
||||
$this->Flash->error(__('Errore durante l\'autenticazione mediante {0} "{1}". Riprovare di nuovo o utilizzare le credenziali di accesso', Configure::read('App.oidc.idp_name', 'OpenID Connect'), $e->getMessage())); |
||||
return $this->redirect('/'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* index |
||||
* |
||||
* @throws ForbiddenException |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function index() |
||||
{ |
||||
if (!$this->logged_user->hasCapability(['configuration.users.read', 'configuration.users.read_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$users = $this->Users->find() |
||||
->contain(['Actors', 'Organisations' => ['Actors', 'OrganisationActors']]); |
||||
|
||||
if (!$this->logged_user->hasCapability('configuration.users.read')) { |
||||
$users = $users->where(['Users.organisation_id' => $this->logged_user->organisation_id]); |
||||
} |
||||
|
||||
$this->set('total_users', $users->count()); |
||||
// applichiamo gli eventuali filtri presenti: |
||||
$users = $this->applyFilters($users); |
||||
$this->set('filtered_users', $users->count()); |
||||
|
||||
if (!$this->getRequest()->is(['json', 'xml', 'csv'])) { |
||||
$users = $users |
||||
->formatResults(function (\Cake\Collection\CollectionInterface $results) { |
||||
return $results->map(function ($row) { |
||||
$row->can_edit = $this->logged_user->id == $row->id || ($this->logged_user->organisation_id == $row->organisation_id && $this->logged_user->hasCapability('configuration.users.edit_foo')) || $this->logged_user->hasCapability('configuration.users.edit'); |
||||
$row->can_delete = $this->logged_user->id != $row->id && (($this->logged_user->organisation_id == $row->organisation_id && $this->logged_user->hasCapability('configuration.users.delete_foo')) || $this->logged_user->hasCapability('configuration.users.delete')); |
||||
return $row; |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
$this->paginate = [ |
||||
'sortableFields' => ['surname', 'name', 'username', 'OrganisationActors.description'], |
||||
]; |
||||
|
||||
$this->set('users', $this->getRequest()->is(['json', 'xml', 'csv']) ? $users : $this->paginate($users)); |
||||
|
||||
if ($this->getRequest()->is('csv')) { |
||||
if (!$this->logged_user->hasCapability('configuration.users.export_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
// docs here: https://github.com/FriendsOfCake/cakephp-csvview |
||||
$header = [ |
||||
__('Cognome'), |
||||
__('Nome'), |
||||
__('Username'), |
||||
__('Recapiti'), |
||||
__('Profili'), |
||||
__('Organizzazione'), |
||||
]; |
||||
$extract = [ |
||||
'surname', |
||||
'name', |
||||
'username', |
||||
function (array $row) { |
||||
return $row['actor']['contacts']; |
||||
}, |
||||
'profiles', |
||||
function (array $row) { |
||||
return $row['organisation']['organisation_actor']['description']; |
||||
}, |
||||
]; |
||||
$this->viewBuilder() |
||||
->setClassName(CustomCsvView::class) |
||||
->setOptions([ |
||||
'header' => $header, |
||||
'extract' => $extract, |
||||
]); |
||||
$dateTime = DateTime::now(); |
||||
$timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); |
||||
$this->setResponse($this->getResponse()->withDownload("users_$timestamp.csv")); |
||||
} |
||||
$this->viewBuilder()->setOption('serialize', 'users'); |
||||
} |
||||
|
||||
/** |
||||
* view |
||||
* |
||||
* @param Int $id |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function view($id = null) |
||||
{ |
||||
if ($this->logged_user->id != $id && !$this->logged_user->hasCapability(['configuration.users.read', 'configuration.users.read_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$user = $this->Users->get($id, contain: ['Actors', 'Languages', 'Organisations' => ['Actors']]); |
||||
|
||||
if (!$this->logged_user->hasCapability('configuration.users.read') && $this->logged_user->organisation_id != $user->organisation_id && $this->logged_user->id != $user->id) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$user->can_handle_contacts = $this->logged_user->canViewContactsForActor($this->Users->Actors->get($user->actor_id, contain: ['Users'])); |
||||
$user->can_edit = $this->logged_user->hasCapability('configuration.users.edit') || $this->logged_user->organisation_id == $user->organisation_id && $this->logged_user->hasCapability('configuration.users.edit_foo') || $this->logged_user->id == $user->id; |
||||
$user->can_delete = $this->logged_user->id != $user->id && (($this->logged_user->organisation_id == $user->organisation_id && $this->logged_user->hasCapability('configuration.users.delete_foo')) || $this->logged_user->hasCapability('configuration.users.delete')); |
||||
|
||||
$this->set(compact('user')); |
||||
$this->viewBuilder()->setOption('serialize', 'user'); |
||||
} |
||||
|
||||
/** |
||||
* add |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function add() |
||||
{ |
||||
if (!$this->logged_user->hasCapability(['configuration.users.add', 'configuration.users.add_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$can_view_profiles = $this->logged_user->hasCapability('configuration.groups.read'); |
||||
$can_handle_profiles = $can_view_profiles && ($this->logged_user->hasCapability('configuration.users.profiles') || $this->fetchTable('Users')->getAssociableUserGroups()->count() > 0); |
||||
|
||||
$user = $this->Users->newEmptyEntity(); |
||||
|
||||
$default_profiles = $this->Users->Groups->find() |
||||
->contain(['Actors']) |
||||
->where(['Groups.is_default' => 1]) |
||||
->all() |
||||
->toArray(); |
||||
|
||||
$user['groups'] = $default_profiles; |
||||
|
||||
if ($this->request->is('post')) { |
||||
$user = $this->Users->patchEntity($user, $this->request->getData()); |
||||
|
||||
if (!$can_handle_profiles) $user['groups'] = $default_profiles; |
||||
|
||||
if ($this->Users->save($user)) { |
||||
$this->Flash->success(__('Utente creato con successo.')); |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
$this->Flash->error(__('Errore durante la creazione dell\'utente')); |
||||
} |
||||
$organisations = $this->Users->Organisations->find('list')->contain(['Actors'])->order(['Actors.description' => 'ASC']); |
||||
if (!$this->logged_user->hasCapability('configuration.users.add')) $organisations = $organisations->where(['Organisations.id' => $this->logged_user->organisation_id]); |
||||
$languages = $this->Users->Languages->find('list'); |
||||
$groups = $this->fetchTable('Users')->getAssociableUserGroups(as_list: true)->order(['Groups.description' => 'ASC']); |
||||
$this->set('today', DateTime::now()); |
||||
$this->set(compact('user', 'organisations', 'languages', 'groups', 'can_view_profiles', 'can_handle_profiles')); |
||||
} |
||||
|
||||
/** |
||||
* edit |
||||
* |
||||
* @param Int $id |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function edit($id = null) |
||||
{ |
||||
if ($this->logged_user->id != $id && !$this->logged_user->hasCapability(['configuration.users.edit', 'configuration.users.edit_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$can_view_profiles = $this->logged_user->hasCapability('configuration.groups.read'); |
||||
$can_handle_profiles = $can_view_profiles && ($this->logged_user->hasCapability('configuration.users.profiles') || $this->fetchTable('Users')->getAssociableUserGroups()->count() > 0); |
||||
|
||||
$user = $this->Users->get($id, contain: ['Actors', 'Groups', 'Languages', 'Organisations' => ['Actors']]); |
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$user->setAccess('groups', $can_handle_profiles); |
||||
$user = $this->Users->patchEntity($user, $this->request->getData()); |
||||
|
||||
if ($this->Users->save($user)) { |
||||
$this->Flash->success(__('Utente "{0}" modificato con successo.', $user->actor->description)); |
||||
|
||||
return $this->logged_user->hasCapability(['configuration.users.read', 'configuration.users.read_foo']) ? $this->redirect(['action' => 'index']) : $this->redirect('/'); |
||||
} |
||||
$this->Flash->error(__('Errore durante la modifica dell\'utente "{0}". Riprovare di nuovo.', $user->actor->description)); |
||||
} |
||||
$organisations = $this->Users->Organisations->find('list')->contain(['Actors'])->order(['Actors.description' => 'ASC']); |
||||
if (!$this->logged_user->hasCapability('configuration.users.edit')) $organisations = $organisations->where(['Organisations.id' => $this->logged_user->organisation_id]); |
||||
$languages = $this->Users->Languages->find('list'); |
||||
$groups = $this->fetchTable('Users')->getAssociableUserGroups(as_list: true)->order(['Groups.description' => 'ASC']); |
||||
$this->set('today', DateTime::now()); |
||||
$this->set(compact('user', 'organisations', 'languages', 'groups', 'can_view_profiles', 'can_handle_profiles')); |
||||
} |
||||
|
||||
/** |
||||
* delete |
||||
* |
||||
* @param Int $id |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function delete($id = null) |
||||
{ |
||||
if (!$this->logged_user->hasCapability(['configuration.users.delete', 'configuration.users.delete_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$this->request->allowMethod(['post', 'delete']); |
||||
$user = $this->Users->get($id, contain: ['Actors']); |
||||
|
||||
if ($this->logged_user->id == $user->id || ($this->logged_user->organisation_id != $user->organisation_id && !$this->logged_user->hasCapability('configuration.users.delete'))) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
if ($this->Users->Actors->delete($user->actor)) { |
||||
$this->Flash->success(__('L\'utente "{0}" è stato cancellato con successo', $user->actor->description)); |
||||
} else { |
||||
$this->Flash->error(__('Errore durante la cancellazione dell\'utente "{0}". Riprovare di nuovo.', $user->actor->description)); |
||||
} |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
|
||||
/** |
||||
* login |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function login() |
||||
{ |
||||
$result = $this->Authentication->getResult(); |
||||
// If the user is logged in send them away. |
||||
if ($result->isValid()) { |
||||
$user = $this->Authentication->getIdentity(); |
||||
$user->timezone = $this->request->getData('user_timezone', Configure::read('App.defaultUserTimezone')); |
||||
// se per qualche motivo il form restituisce "" stringa vuota per il timezone, impostiamo invece il default! |
||||
if (empty($user->timezone)) $user->timezone = Configure::read('App.defaultUserTimezone'); |
||||
$this->fetchTable('Users')->save($user); |
||||
$target = $this->Authentication->getLoginRedirect() ?? '/'; |
||||
$this->request->getSession()->write("oidc", null); |
||||
return $this->redirect($target); |
||||
} |
||||
|
||||
if ($this->request->is('post')) { |
||||
$authError = $this->request->getSession()->read('AuthError'); |
||||
if ($authError) { |
||||
$this->Flash->error($authError); |
||||
$this->request->getSession()->delete('AuthError'); |
||||
} else { |
||||
$this->Flash->error('username e/o password errati'); |
||||
} |
||||
} |
||||
$login_citizen_registration = $this->request->getSession()->read('showCitizenRegistration'); |
||||
$this->set(compact('login_citizen_registration')); |
||||
$this->viewBuilder()->setLayout('CakeLte.login'); |
||||
$this->set('login_layout_link_label', __('Ho dimenticato la mia password')); |
||||
$this->set('login_layout_link_action', 'passwordRecovery'); |
||||
$this->set('login_layout_privacy_label', __('Visualizza Privacy Policy')); |
||||
$this->set('login_layout_privacy_link', 'view_public'); |
||||
if (isset($login_citizen_registration) && $login_citizen_registration->isShowAlert()) { |
||||
$login_citizen_registration_copy = clone $login_citizen_registration; |
||||
$login_citizen_registration_copy->setShowAlert(false); |
||||
$this->request->getSession()->write('showCitizenRegistration', $login_citizen_registration_copy); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* logout |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function logout() |
||||
{ |
||||
$this->Authentication->logout(); |
||||
|
||||
if ($this->request->getSession()->read('oidc')) { |
||||
OpenIdConnectClient::logout( |
||||
Configure::read('App.oidc.logoutUrl'), |
||||
Configure::read('App.oidc.clientId'), |
||||
Configure::read('App.oidc.postLogoutRedirectUri') |
||||
); |
||||
} |
||||
|
||||
$this->Flash->success(__('Logout eseguito con successo.')); |
||||
return $this->redirect(['controller' => 'Users', 'action' => 'login']); |
||||
} |
||||
|
||||
/** |
||||
* executePasswordRecovery |
||||
* |
||||
* @param \App\Model\Entity\User $user |
||||
* @param String $email |
||||
* @param String|Null $password_recovery_token |
||||
* @return String|Null |
||||
*/ |
||||
private function executePasswordRecovery(\App\Model\Entity\User $user, String $email, String|Null $password_recovery_token = null): String|Null |
||||
{ |
||||
$user->password_recovery_token = $password_recovery_token ?? sha1($this->gen_random_code(40)); |
||||
|
||||
if (!$this->Users->save($user)) return null; |
||||
|
||||
$options = []; |
||||
$options['user_id'] = $user->id; |
||||
$options['username'] = $user->username; |
||||
$options['email'] = $email; |
||||
$options['type'] = 'users'; |
||||
$options['password_recovery_token'] = $user->password_recovery_token; |
||||
$this->sendNotifications(null, 'password_recovery', $options); |
||||
return $user->password_recovery_token; |
||||
} |
||||
|
||||
/** |
||||
* passwordRecovery |
||||
* |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function passwordRecovery() |
||||
{ |
||||
if ($this->request->is('post')) |
||||
{ |
||||
if (empty($this->request->getData('email'))) { |
||||
$this->Flash->error(__('Inserire un indirizzo email valido!')); |
||||
return $this->redirect(['action' => 'passwordRecovery']); |
||||
} |
||||
|
||||
$email = $this->Users->Actors->Deliveries->Emails->find() |
||||
->contain(['Deliveries' => ['Actors' => ['Users']]]) |
||||
->where(['Emails.value' => $this->request->getData('email')]) |
||||
->first(); |
||||
|
||||
if (isset($email->delivery->actor->user)) |
||||
{ |
||||
$this->executePasswordRecovery($email->delivery->actor->user, $this->request->getData('email')); |
||||
$this->Flash->success(__('A breve riceverai un\'email all\'indirizzo "{0}" con le istruzioni per eseguire il reset della password per il tuo account con username "{1}".', $this->request->getData('email'), $email->delivery->actor->user->username)); |
||||
return $this->redirect(['action' => 'login']); |
||||
} |
||||
else |
||||
{ |
||||
$this->Flash->error(__('L\'indirizzo email inserito non risulta presente')); |
||||
return $this->redirect(['action' => 'passwordRecovery']); |
||||
} |
||||
} |
||||
$this->viewBuilder()->setLayout('CakeLte.login'); |
||||
$this->set('login_layout_link_label', __('Ritorna al login')); |
||||
$this->set('login_layout_link_action', 'login'); |
||||
$this->set('login_layout_privacy_label', __('Visualizza Privacy Policy')); |
||||
$this->set('login_layout_privacy_link', 'view_public'); |
||||
} |
||||
|
||||
/** |
||||
* chooseNewPassword |
||||
* |
||||
* @param String $token |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function chooseNewPassword($token) |
||||
{ |
||||
$user = $this->Users->find()->contain(['Actors', 'Organisations'])->where(['Users.password_recovery_token' => $token])->first(); |
||||
|
||||
if(!$user) |
||||
{ |
||||
$this->Flash->error(__('Impossibile completare la procedura di recupero password.')); |
||||
return $this->redirect(['action' => 'login']); |
||||
} |
||||
|
||||
if ($this->request->is('post')) |
||||
{ |
||||
if (!empty($this->request->getData('new_password')) && !empty($this->request->getData('confirm_new_password')) && $this->request->getData('new_password') == $this->request->getData('confirm_new_password')) { |
||||
$user_data = $user->toArray(); |
||||
$user_data['password'] = $this->request->getData('new_password'); |
||||
$user = $this->Users->patchEntity($user, $user_data, ['validate' => false]); |
||||
if (count($user->getError('password')) > 0) { |
||||
$this->Flash->error(implode(" - ", $user->getError('password'))); |
||||
return $this->redirect(['action' => 'chooseNewPassword', $token]); |
||||
} |
||||
|
||||
$user->password_recovery_token = null; |
||||
$user->last_change_password = new \DateTime(); |
||||
$user->password_recovery_counter = $user->password_recovery_counter+1; |
||||
|
||||
if ($this->Users->save($user)) { |
||||
$this->Flash->success('Password modificata con successo'); |
||||
return $this->redirect(['action' => 'login']); |
||||
} else { |
||||
$this->Flash->error(__('Impossibile cambiare la password')); |
||||
} |
||||
|
||||
} else { |
||||
$this->Flash->error(__('La nuova password non è valida e/o le 2 password non coincidono')); |
||||
} |
||||
} |
||||
|
||||
$this->viewBuilder()->setLayout('CakeLte.login'); |
||||
$this->set('login_layout_link_label', __('Ritorna al login')); |
||||
$this->set('login_layout_link_action', 'login'); |
||||
$this->set('login_layout_privacy_label', __('Visualizza Privacy Policy')); |
||||
$this->set('login_layout_privacy_link', 'view_public'); |
||||
} |
||||
|
||||
public function oneTimePassword(String $otp) { |
||||
$users = $this->fetchTable('Users')->find()->where(['Users.otp' => $otp]); |
||||
if ($users->count() != 1) { |
||||
$this->Flash->error(__('Codice OTP non valido o già utilizzato. Effettua il login.')); |
||||
return $this->redirect(['action' => 'login']); |
||||
} |
||||
|
||||
$user = $users->first(); |
||||
|
||||
// controllo che otp_expires sia un datetime valido e non scaduto: |
||||
if ($user->otp_expires === null || !is_object($user->otp_expires) || get_class($user->otp_expires) != "Cake\I18n\DateTime" || !$user->otp_expires->isWithinNext(Configure::read('App.oneTimePasswordExpirationHours', 1) . ' hours')) { |
||||
$user->otp = null; |
||||
$user->otp_redirect_url = null; |
||||
$user->otp_expires = null; |
||||
$this->fetchTable('Users')->save($user); |
||||
$this->Flash->error(__('Codice OTP scaduto. Effettua il login.')); |
||||
return $this->redirect(['action' => 'login']); |
||||
} |
||||
|
||||
if ($this->request->is('post')) |
||||
{ |
||||
$redirect_url = $user->otp_redirect_url ?? '/'; |
||||
$user->sys_admin = false; |
||||
$user->passepartout = false; |
||||
$user->otp = null; |
||||
$user->otp_redirect_url = null; |
||||
$user->otp_expires = null; |
||||
$this->fetchTable('Users')->save($user); |
||||
$this->getRequest()->getSession()->write('Auth', $user); |
||||
return $this->redirect($redirect_url); |
||||
} |
||||
$this->viewBuilder()->setLayout('CakeLte.login'); |
||||
$this->set('login_layout_link_label', __('Ritorna al login')); |
||||
$this->set('login_layout_link_action', 'login'); |
||||
$this->set('login_layout_privacy_label', __('Visualizza Privacy Policy')); |
||||
$this->set('login_layout_privacy_link', 'view_public'); |
||||
} |
||||
|
||||
/** |
||||
* getPhoto |
||||
* |
||||
* @param String $file_name |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function getPhoto($file_name) |
||||
{ |
||||
$photo_owner = $this->fetchTable('Users')->find()->where(['Users.photo' => $file_name])->first(); |
||||
|
||||
if (!$photo_owner) throw new NotFoundException(__('Foto utente non trovata!')); |
||||
|
||||
if ($this->logged_user->id != $photo_owner->id) { |
||||
if (!$this->logged_user->hasCapability(['configuration.users.read', 'configuration.users.read_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
if (!$this->logged_user->hasCapability(['configuration.users.read']) && $this->logged_user->organisation_id != $photo_owner->organisation_id) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
} |
||||
|
||||
$mimetype = "image/jpeg"; |
||||
$path = Configure::read('App.userPhotoPath') . "/" . $file_name; |
||||
$output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); |
||||
$this->response = $this->response |
||||
->withType($mimetype) |
||||
->withStringBody($output); |
||||
|
||||
return $this->response; |
||||
} |
||||
|
||||
/** |
||||
* deleteUserPhoto |
||||
* |
||||
* @param Int $user_id |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function deleteUserPhoto($user_id) |
||||
{ |
||||
$user = $this->Users->get($user_id); |
||||
$user->photo = null; |
||||
if (!$this->Users->save($user)) { |
||||
$this->Flash->error(__('Errore durante l\'eliminazione della foto utente!')); |
||||
} else { |
||||
$this->Flash->success(__('Foto utente eliminata con successo')); |
||||
} |
||||
return $this->redirect(['action' => 'view', $user_id]); |
||||
} |
||||
|
||||
/** |
||||
* add_citizen |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function add_citizen() |
||||
{ |
||||
$user = $this->Users->newEmptyEntity(); |
||||
$citizenRegistrationData = $this->request->getSession()->read('showCitizenRegistration'); |
||||
if ($this->request->is('post') || $this->request->is('put')) { |
||||
$data = $this->request->getData(); |
||||
$taxCode = $data['tax_code'] ?? null; |
||||
$name = $data['name'] ?? null; |
||||
$surname = $data['surname'] ?? null; |
||||
$birthday = $data['birthday'] ?? null; |
||||
$gender = $data['gender'] ?? null; |
||||
if ($taxCode && $citizenRegistrationData && $citizenRegistrationData?->getFiscalCode() !== '' && $citizenRegistrationData->getFiscalCode() != $taxCode) { |
||||
$this->Flash->error(__('Il codice fiscale inserito non corrisponde a quello fornito in fase di autenticazione. Riprovare.')); |
||||
} |
||||
elseif ($name && $citizenRegistrationData && $citizenRegistrationData?->getName() !== '' && $citizenRegistrationData->getName() != $name) { |
||||
$this->Flash->error(__('Il nome inserito non corrisponde a quello fornito in fase di autenticazione. Riprovare.')); |
||||
} |
||||
elseif ($surname && $citizenRegistrationData && $citizenRegistrationData?->getSurname() !== '' && $citizenRegistrationData->getSurname() != $surname) { |
||||
$this->Flash->error(__('Il cognome inserito non corrisponde a quello fornito in fase di autenticazione. Riprovare.')); |
||||
} |
||||
elseif ($birthday && $citizenRegistrationData && $citizenRegistrationData?->getBirthdate() !== '' && $citizenRegistrationData->getBirthdate() != $birthday) { |
||||
$this->Flash->error(__('La data di nascita inserita non corrisponde a quella fornita in fase di autenticazione. Riprovare.')); |
||||
} |
||||
elseif ($gender && $citizenRegistrationData && $citizenRegistrationData?->getGender() !== '' && $citizenRegistrationData->getGender() != $gender) { |
||||
$this->Flash->error(__('Il sesso inserito non corrisponde a quello fornito in fase di autenticazione. Riprovare.')); |
||||
} |
||||
else { |
||||
$newCitizen = $this->Users->createCitizen($user, $data); |
||||
if ($newCitizen) { |
||||
$emails = $newCitizen?->getEmailsWithNotifications() ?? []; |
||||
$notificationEmail = $emails[0] ?? null; |
||||
$successMessage = 'Utente creato con successo.'; |
||||
if ($notificationEmail) { |
||||
$options = [ |
||||
'user_id' => $newCitizen->id, |
||||
'username' => $newCitizen->username, |
||||
'email' => $notificationEmail->value, |
||||
'type' => 'users', |
||||
'verification_token' => $newCitizen->email_verification_code, |
||||
]; |
||||
$this->sendNotifications(null, 'verify-citizen-registration', $options); |
||||
$successMessage = 'Utente creato con successo. Riceverai un\'email per confermare la registrazione.'; |
||||
} |
||||
$this->request->getSession()->delete('showCitizenRegistration'); |
||||
$this->Flash->success(__($successMessage)); |
||||
return $this->redirect(['action' => 'login']); |
||||
} else { |
||||
$this->Flash->error(__('Errore durante la creazione dell\'utente')); |
||||
} |
||||
} |
||||
} |
||||
|
||||
$languages = $this->Users->Languages->find('list'); |
||||
$this->viewBuilder()->setLayout('CakeLte.login'); |
||||
$this->set([ |
||||
'today' => DateTime::now(), |
||||
'hideLogin' => true, |
||||
'user' => $user, |
||||
'languages' => $languages, |
||||
'citizenRegistrationData' => $citizenRegistrationData, |
||||
]); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* verify citizen |
||||
* @param string|null $token |
||||
* @return \Cake\Http\Response |
||||
*/ |
||||
public function verify_citizen(string|null $token) |
||||
{ |
||||
$token = $token ?? ''; |
||||
if ($this->Users->verifyCitizen($token)) { |
||||
$this->Flash->success(__('Utente verificato con successo.')); |
||||
return $this->redirect(['action' => 'login']); |
||||
} |
||||
|
||||
$this->Flash->error(__('Errore durante la verifica, si prega di riprovare.')); |
||||
return $this->redirect(['action' => 'login']); |
||||
} |
||||
} |
||||
@ -0,0 +1,124 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
/** |
||||
* WaterDrawingArticles Controller |
||||
* |
||||
* @property \App\Model\Table\WaterDrawingArticlesTable $WaterDrawingArticles |
||||
* @method \App\Model\Entity\WaterDrawingArticle[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class WaterDrawingArticlesController extends AppController |
||||
{ |
||||
/** |
||||
* Index method |
||||
* |
||||
* @return \Cake\Http\Response|null|void Renders view |
||||
*/ |
||||
public function index() |
||||
{ |
||||
$waterDrawingArticles = $this->WaterDrawingArticles->find()->formatResults(function (\Cake\Collection\CollectionInterface $results) { |
||||
return $results->map(function ($row) { |
||||
$row->can_edit = $this->logged_user->hasCapability('configuration.water_drawing_articles.edit'); |
||||
$row->can_delete = $this->logged_user->hasCapability('configuration.water_drawing_articles.delete'); |
||||
$row->can_disable = $this->logged_user->hasCapability('configuration.water_drawing_articles.disable'); |
||||
return $row; |
||||
}); |
||||
}); |
||||
$waterDrawingArticles = $this->paginate($waterDrawingArticles); |
||||
|
||||
$this->set(compact('waterDrawingArticles')); |
||||
} |
||||
|
||||
/** |
||||
* View method |
||||
* |
||||
* @param string|null $id Water Drawing Article id. |
||||
* @return \Cake\Http\Response|null|void Renders view |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function view($id = null) |
||||
{ |
||||
$waterDrawingArticle = $this->WaterDrawingArticles->get($id, contain: []); |
||||
$waterDrawingArticle->can_edit = $this->logged_user->hasCapability('configuration.water_drawing_articles.edit'); |
||||
$waterDrawingArticle->can_delete = $this->logged_user->hasCapability('configuration.water_drawing_articles.delete'); |
||||
$waterDrawingArticle->can_disable = $this->logged_user->hasCapability('configuration.water_drawing_articles.disable'); |
||||
$this->set(compact('waterDrawingArticle')); |
||||
} |
||||
|
||||
/** |
||||
* Add method |
||||
* |
||||
* @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. |
||||
*/ |
||||
public function add() |
||||
{ |
||||
$waterDrawingArticle = $this->WaterDrawingArticles->newEmptyEntity(); |
||||
if ($this->request->is('post')) { |
||||
$waterDrawingArticle = $this->WaterDrawingArticles->patchEntity($waterDrawingArticle, $this->request->getData()); |
||||
if ($this->WaterDrawingArticles->save($waterDrawingArticle)) { |
||||
$this->Flash->success(__('Articolo di legge salvato con successo.')); |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
$this->Flash->error(__('Errore durante il salvataggio dell\'articolo di legge. Riprovare di nuovo.')); |
||||
} |
||||
$this->set(compact('waterDrawingArticle')); |
||||
} |
||||
|
||||
/** |
||||
* Edit method |
||||
* |
||||
* @param string|null $id Water Drawing Article id. |
||||
* @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function edit($id = null) |
||||
{ |
||||
$waterDrawingArticle = $this->WaterDrawingArticles->get($id, contain: []); |
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$waterDrawingArticle = $this->WaterDrawingArticles->patchEntity($waterDrawingArticle, $this->request->getData()); |
||||
if ($this->WaterDrawingArticles->save($waterDrawingArticle)) { |
||||
$this->Flash->success(__('Articolo di legge modificato con successo.')); |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
$this->Flash->error(__('Errore durante la modifica dell\'articolo di legge. Riprovare di nuovo.')); |
||||
} |
||||
$this->set(compact('waterDrawingArticle')); |
||||
} |
||||
|
||||
/** |
||||
* Delete method |
||||
* |
||||
* @param string|null $id Water Drawing Article id. |
||||
* @return \Cake\Http\Response|null|void Redirects to index. |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function delete($id = null) |
||||
{ |
||||
$this->request->allowMethod(['post', 'delete']); |
||||
$waterDrawingArticle = $this->WaterDrawingArticles->get($id); |
||||
if ($this->WaterDrawingArticles->delete($waterDrawingArticle)) { |
||||
$this->Flash->success(__('L\'articolo di legge è stato cancellato con successo.')); |
||||
} else { |
||||
$this->Flash->error(__('Errore durante la cancellazione dell\'articolo di legge. Riprovare di nuovo.')); |
||||
} |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
|
||||
public function change_status($id){ |
||||
$waterDrawingArticle = $this->WaterDrawingArticles->get($id); |
||||
$waterDrawingArticle = $this->WaterDrawingArticles->patchEntity($waterDrawingArticle, [ |
||||
'disable' => $waterDrawingArticle->disable ? false : true |
||||
]); |
||||
if($this->WaterDrawingArticles->save($waterDrawingArticle)){ |
||||
$this->Flash->success( $waterDrawingArticle->disable ? __('Articolo disabilitato con successo.') : __('Articolo abilitato con successo.')); |
||||
}else{ |
||||
$this->Flash->error( $waterDrawingArticle->disable ? __('Errore durante l\'abilitazione dell\'articolo.') : __('Errore durante la disabilitazione dell\'articolo.')); |
||||
} |
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
} |
||||
@ -0,0 +1,123 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
use App\WGS\SnapshotsHandler\SnapshotsHandler; |
||||
|
||||
/** |
||||
* WaterDrawingDerivations Controller |
||||
* |
||||
* @property \App\Model\Table\WaterDrawingDerivationsTable $WaterDrawingDerivations |
||||
* @method \App\Model\Entity\WaterDrawingDerivation[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class WaterDrawingDerivationsController extends AppController |
||||
{ |
||||
/** |
||||
* Index method |
||||
* |
||||
* @return \Cake\Http\Response|null|void Renders view |
||||
*/ |
||||
public function index() |
||||
{ |
||||
$this->paginate = [ |
||||
'contain' => ['WaterDrawingDerivationTypes', 'WaterDrawingPaperworks'], |
||||
]; |
||||
$waterDrawingDerivations = $this->paginate($this->WaterDrawingDerivations); |
||||
|
||||
$this->set(compact('waterDrawingDerivations')); |
||||
} |
||||
|
||||
/** |
||||
* View method |
||||
* |
||||
* @param string|null $id Water Drawing Derivation id. |
||||
* @return \Cake\Http\Response|null|void Renders view |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function view($id = null) |
||||
{ |
||||
$waterDrawingDerivation = $this->WaterDrawingDerivations->find() |
||||
->contain(['WaterDrawingDerivationTypes', 'WaterDrawingPaperworks']) |
||||
->where(['WaterDrawingDerivations.id' => $id]) |
||||
->formatResults(function (\Cake\Collection\CollectionInterface $results){ |
||||
return $results->map(function ($row){ |
||||
$row->can_edit = true; |
||||
$row->can_delete = true; |
||||
return $row; |
||||
}); |
||||
})->first(); |
||||
|
||||
$this->set(compact('waterDrawingDerivation')); |
||||
} |
||||
|
||||
/** |
||||
* Add method |
||||
* |
||||
* @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. |
||||
*/ |
||||
public function add($water_drawing_paperwork_id) |
||||
{ |
||||
$waterDrawingDerivation = $this->WaterDrawingDerivations->newEmptyEntity(); |
||||
if ($this->request->is('post')) { |
||||
$waterDrawingDerivation = $this->WaterDrawingDerivations->patchEntity($waterDrawingDerivation, $this->request->getData()); |
||||
if ($this->WaterDrawingDerivations->save($waterDrawingDerivation)) { |
||||
$waterDrawingPaperworks = $this->WaterDrawingDerivations->WaterDrawingPaperworks->get($water_drawing_paperwork_id); |
||||
SnapshotsHandler::createSnapshot($waterDrawingPaperworks->controllable_object_id); |
||||
$this->Flash->success(__('Il punto di prelievo è stato salvato con successo')); |
||||
|
||||
return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingDerivation->water_drawing_paperwork_id]); |
||||
} |
||||
$this->Flash->error(__('Errore durante il salvataggio del punto di prelievo.')); |
||||
} |
||||
$waterDrawingDerivationTypes = $this->WaterDrawingDerivations->WaterDrawingDerivationTypes->find()->all()->combine('id','description')->toArray(); |
||||
$this->set(compact('waterDrawingDerivation', 'waterDrawingDerivationTypes', 'water_drawing_paperwork_id')); |
||||
} |
||||
|
||||
/** |
||||
* Edit method |
||||
* |
||||
* @param string|null $id Water Drawing Derivation id. |
||||
* @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function edit($id = null) |
||||
{ |
||||
$waterDrawingDerivation = $this->WaterDrawingDerivations->get($id, contain: ['WaterDrawingPaperworks']); |
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$waterDrawingDerivation = $this->WaterDrawingDerivations->patchEntity($waterDrawingDerivation, $this->request->getData()); |
||||
|
||||
if ($this->WaterDrawingDerivations->save($waterDrawingDerivation)) { |
||||
SnapshotsHandler::createSnapshot($waterDrawingDerivation->water_drawing_paperwork->controllable_object_id); |
||||
$this->Flash->success(__('Il punto di prelievo è stato salvato con successo')); |
||||
|
||||
return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingDerivation->water_drawing_paperwork_id]); |
||||
} |
||||
$this->Flash->error(__('Errore durante il salvataggio del punto di prelievo.')); |
||||
} |
||||
$waterDrawingDerivationTypes = $this->WaterDrawingDerivations->WaterDrawingDerivationTypes->find()->all()->combine('id', 'description')->toArray(); |
||||
$this->set(compact('waterDrawingDerivation', 'waterDrawingDerivationTypes')); |
||||
} |
||||
|
||||
/** |
||||
* Delete method |
||||
* |
||||
* @param string|null $id Water Drawing Derivation id. |
||||
* @return \Cake\Http\Response|null|void Redirects to index. |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function delete($id = null) |
||||
{ |
||||
$this->request->allowMethod(['post', 'delete']); |
||||
$waterDrawingDerivation = $this->WaterDrawingDerivations->get($id, contain: ['WaterDrawingPaperworks']); |
||||
if ($this->WaterDrawingDerivations->delete($waterDrawingDerivation)) { |
||||
SnapshotsHandler::createSnapshot($waterDrawingDerivation->water_drawing_paperwork->controllable_object_id); |
||||
$this->Flash->success(__('Il punto di prelievo è stato cancellato')); |
||||
return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingDerivation->water_drawing_paperwork_id]); |
||||
} else { |
||||
$this->Flash->error(__('Errore durante la cancellazione del punto di prelievo.')); |
||||
} |
||||
|
||||
return $this->redirect(['action' => 'view', $waterDrawingDerivation->id]); |
||||
} |
||||
} |
||||
@ -0,0 +1,174 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
use App\WGS\SnapshotsHandler\SnapshotsHandler; |
||||
use Cake\Http\Exception\ForbiddenException; |
||||
use Cake\I18n\DateTime; |
||||
use Cake\View\JsonView; |
||||
use App\View\CustomCsvView; |
||||
|
||||
/** |
||||
* WaterDrawingFees Controller |
||||
* |
||||
* @property \App\Model\Table\WaterDrawingFeesTable $WaterDrawingFees |
||||
* @method \App\Model\Entity\WaterDrawingFee[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class WaterDrawingFeesController extends AppController |
||||
{ |
||||
public function viewClasses(): array |
||||
{ |
||||
return [JsonView::class, CustomCsvView::class]; |
||||
} |
||||
|
||||
/** |
||||
* Index method |
||||
* |
||||
* @return \Cake\Http\Response|null|void Renders view |
||||
*/ |
||||
public function index($water_drawing_paperwork_id) |
||||
{ |
||||
if (!$this->logged_user->hasCapability(['documentation.water_drawing_fees.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
|
||||
$waterDrawingFees = $this->WaterDrawingFees->find()->contain(['WaterDrawingPayments'])->where(['WaterDrawingFees.water_drawing_paperwork_id' => $water_drawing_paperwork_id])->formatResults(function ($result){ |
||||
return $result->map(function ($row){ |
||||
$row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit'); |
||||
$row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_fees.delete') && (count($row->water_drawing_payments) == 0); |
||||
return $row; |
||||
}); |
||||
}); |
||||
$this->set('total_water_drawing_fees', $waterDrawingFees->count()); |
||||
// applichiamo gli eventuali filtri presenti: |
||||
$waterDrawingFees = $this->applyFilters($waterDrawingFees); |
||||
$this->set('filtered_water_drawing_fees', $waterDrawingFees->count()); |
||||
$waterDrawingFees = $this->paginate($waterDrawingFees); |
||||
|
||||
$this->set(compact('waterDrawingFees', 'water_drawing_paperwork_id')); |
||||
$this->set('can_export_csv', $this->logged_user->hasCapability('documentation.water_drawing_paperworks.export_csv_payment')); |
||||
|
||||
if ($this->getRequest()->is('csv')) { |
||||
if (!$this->logged_user->hasCapability('documentation.water_drawing_paperworks.export_csv_payment')) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
// docs here: https://github.com/FriendsOfCake/cakephp-csvview |
||||
$header = [ |
||||
__('Anno'), |
||||
__('Canone'), |
||||
__('Dovuto') |
||||
]; |
||||
$extract = [ |
||||
'year', |
||||
'amount', |
||||
'to_pay' |
||||
]; |
||||
$this->viewBuilder() |
||||
->setClassName(CustomCsvView::class) |
||||
->setOptions([ |
||||
'header' => $header, |
||||
'extract' => $extract, |
||||
]); |
||||
$dateTime = DateTime::now(); |
||||
$timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); |
||||
$this->setResponse($this->getResponse()->withDownload("water_drawing_fees_$water_drawing_paperwork_id-$timestamp.csv")); |
||||
} |
||||
|
||||
$this->viewBuilder()->setOption('serialize', 'waterDrawingFees'); |
||||
} |
||||
|
||||
/** |
||||
* View method |
||||
* |
||||
* @param string|null $id Water Drawing Fee id. |
||||
* @return \Cake\Http\Response|null|void Renders view |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function view($id = null) |
||||
{ |
||||
if (!$this->logged_user->hasCapability(['documentation.water_drawing_fees.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); |
||||
$waterDrawingFee = $this->WaterDrawingFees->find()->contain(['WaterDrawingPayments'])->where(['WaterDrawingFees.id' => $id])->formatResults(function ($result){ |
||||
return $result->map(function ($row){ |
||||
$row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit'); |
||||
$row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_fees.delete') && (count($row->water_drawing_payments) == 0); |
||||
return $row; |
||||
}); |
||||
})->first(); |
||||
|
||||
$waterDrawingPayments = $this->WaterDrawingFees->WaterDrawingPayments->find()->contain(['WaterDrawingFees', 'WaterDrawingPaymentTypes', 'Users'])->where(['WaterDrawingPayments.water_drawing_fee_id' => $id])->formatResults(function ($result){ |
||||
return $result->map(function ($row){ |
||||
$row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment'); |
||||
$row->can_view = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); |
||||
$row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_payment'); |
||||
return $row; |
||||
}); |
||||
}); |
||||
|
||||
$this->set(compact('waterDrawingFee', 'waterDrawingPayments')); |
||||
} |
||||
|
||||
/** |
||||
* Add method |
||||
* |
||||
* @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. |
||||
*/ |
||||
public function add($water_drawing_paperwork_id) |
||||
{ |
||||
$waterDrawingFee = $this->WaterDrawingFees->newEmptyEntity(); |
||||
if ($this->request->is('post')) { |
||||
$waterDrawingFee = $this->WaterDrawingFees->patchEntity($waterDrawingFee, $this->request->getData()); |
||||
if ($this->WaterDrawingFees->save($waterDrawingFee)) { |
||||
$waterDrawingPaperworks = $this->WaterDrawingFees->WaterDrawingPaperworks->get($water_drawing_paperwork_id); |
||||
SnapshotsHandler::createSnapshot($waterDrawingPaperworks->controllable_object_id); |
||||
$this->Flash->success(__('Il canone annuale è stato salvato.')); |
||||
|
||||
return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingFee->water_drawing_paperwork_id]); |
||||
} |
||||
$this->Flash->error(__('Errore. Il canone annuale non è stato salvato.')); |
||||
} |
||||
$this->set(compact('waterDrawingFee', 'water_drawing_paperwork_id')); |
||||
} |
||||
|
||||
/** |
||||
* Edit method |
||||
* |
||||
* @param string|null $id Water Drawing Fee id. |
||||
* @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function edit($id = null) |
||||
{ |
||||
$waterDrawingFee = $this->WaterDrawingFees->get($id); |
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$waterDrawingFee = $this->WaterDrawingFees->patchEntity($waterDrawingFee, $this->request->getData()); |
||||
if ($this->WaterDrawingFees->save($waterDrawingFee)) { |
||||
$this->Flash->success(__('Il canone annuale è stato salvato.')); |
||||
|
||||
return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingFee->water_drawing_paperwork_id]); |
||||
} |
||||
$this->Flash->error(__('Errore. Il canone annuale non è stato salvato.')); |
||||
} |
||||
$this->set(compact('waterDrawingFee')); |
||||
} |
||||
|
||||
/** |
||||
* Delete method |
||||
* |
||||
* @param string|null $id Water Drawing Fee id. |
||||
* @return \Cake\Http\Response|null|void Redirects to index. |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function delete($id = null) |
||||
{ |
||||
$this->request->allowMethod(['post', 'delete']); |
||||
$waterDrawingFee = $this->WaterDrawingFees->get($id, contain: ['WaterDrawingPayments']); |
||||
if(count($waterDrawingFee->water_drawing_payments) > 0){ |
||||
$this->Flash->error(__('Errore. Per poter eliminare il canone bisogna eliminare i pagamenti ad esso associati.')); |
||||
return $this->redirect(['action' => 'view', $id]); |
||||
} |
||||
if ($this->WaterDrawingFees->delete($waterDrawingFee)) { |
||||
$this->Flash->success(__('Il canone annuale è stato cancellato.')); |
||||
} else { |
||||
$this->Flash->error(__('Errore. Il canone annuale non è stato cancellato.')); |
||||
} |
||||
|
||||
return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingFee->water_drawing_paperwork_id]); |
||||
} |
||||
} |
||||
@ -0,0 +1,108 @@
|
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Controller; |
||||
|
||||
/** |
||||
* WaterDrawingIntendedUses Controller |
||||
* |
||||
* @property \App\Model\Table\WaterDrawingIntendedUsesTable $WaterDrawingIntendedUses |
||||
* @method \App\Model\Entity\WaterDrawingIntendedUse[]|\Cake\Datasource\ResultSetInterface paginate($object = null, array $settings = []) |
||||
*/ |
||||
class WaterDrawingIntendedUsesController extends AppController |
||||
{ |
||||
/** |
||||
* Index method |
||||
* |
||||
* @return \Cake\Http\Response|null|void Renders view |
||||
*/ |
||||
public function index() |
||||
{ |
||||
$this->paginate = [ |
||||
'contain' => ['WaterDrawingPaperworks', 'WaterDrawingIntendedUseTypes'], |
||||
]; |
||||
$waterDrawingIntendedUses = $this->paginate($this->WaterDrawingIntendedUses); |
||||
|
||||
$this->set(compact('waterDrawingIntendedUses')); |
||||
} |
||||
|
||||
/** |
||||
* View method |
||||
* |
||||
* @param string|null $id Water Drawing Intended Use id. |
||||
* @return \Cake\Http\Response|null|void Renders view |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function view($id = null) |
||||
{ |
||||
$waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->get($id, contain: ['WaterDrawingPaperworks', 'WaterDrawingIntendedUseTypes']); |
||||
|
||||
$this->set(compact('waterDrawingIntendedUse')); |
||||
} |
||||
|
||||
/** |
||||
* Add method |
||||
* |
||||
* @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. |
||||
*/ |
||||
public function add() |
||||
{ |
||||
$waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->newEmptyEntity(); |
||||
if ($this->request->is('post')) { |
||||
$waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->patchEntity($waterDrawingIntendedUse, $this->request->getData()); |
||||
if ($this->WaterDrawingIntendedUses->save($waterDrawingIntendedUse)) { |
||||
$this->Flash->success(__('The water drawing intended use has been saved.')); |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
$this->Flash->error(__('The water drawing intended use could not be saved. Please, try again.')); |
||||
} |
||||
$waterDrawingPaperworks = $this->WaterDrawingIntendedUses->WaterDrawingPaperworks->find('list')->all(); |
||||
$waterDrawingIntendedUseTypes = $this->WaterDrawingIntendedUses->WaterDrawingIntendedUseTypes->find('list')->all(); |
||||
$this->set(compact('waterDrawingIntendedUse', 'waterDrawingPaperworks', 'waterDrawingIntendedUseTypes')); |
||||
} |
||||
|
||||
/** |
||||
* Edit method |
||||
* |
||||
* @param string|null $id Water Drawing Intended Use id. |
||||
* @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function edit($id = null) |
||||
{ |
||||
$waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->get($id, contain: []); |
||||
if ($this->request->is(['patch', 'post', 'put'])) { |
||||
$waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->patchEntity($waterDrawingIntendedUse, $this->request->getData()); |
||||
if ($this->WaterDrawingIntendedUses->save($waterDrawingIntendedUse)) { |
||||
$this->Flash->success(__('The water drawing intended use has been saved.')); |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
$this->Flash->error(__('The water drawing intended use could not be saved. Please, try again.')); |
||||
} |
||||
$waterDrawingPaperworks = $this->WaterDrawingIntendedUses->WaterDrawingPaperworks->find('list')->all(); |
||||
$waterDrawingIntendedUseTypes = $this->WaterDrawingIntendedUses->WaterDrawingIntendedUseTypes->find('list')->all(); |
||||
$this->set(compact('waterDrawingIntendedUse', 'waterDrawingPaperworks', 'waterDrawingIntendedUseTypes')); |
||||
} |
||||
|
||||
/** |
||||
* Delete method |
||||
* |
||||
* @param string|null $id Water Drawing Intended Use id. |
||||
* @return \Cake\Http\Response|null|void Redirects to index. |
||||
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. |
||||
*/ |
||||
public function delete($id = null) |
||||
{ |
||||
$this->request->allowMethod(['post', 'delete']); |
||||
$waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->get($id); |
||||
if ($this->WaterDrawingIntendedUses->delete($waterDrawingIntendedUse)) { |
||||
$this->Flash->success(__('The water drawing intended use has been deleted.')); |
||||
} else { |
||||
$this->Flash->error(__('The water drawing intended use could not be deleted. Please, try again.')); |
||||
} |
||||
|
||||
return $this->redirect(['action' => 'index']); |
||||
} |
||||
} |
||||
Some files were not shown because too many files have changed in this diff Show More
Caricamento…
Reference in new issue