diff --git a/app/Http/Controllers/LegacyController.php b/app/Http/Controllers/LegacyController.php
index 9f6fc8cbb..29068f9ed 100644
--- a/app/Http/Controllers/LegacyController.php
+++ b/app/Http/Controllers/LegacyController.php
@@ -11,8 +11,9 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class LegacyController extends Controller
{
- public function index(Request $request, $path = 'index.php')
+ public function index(Request $request)
{
+ $path = substr($request->getPathInfo(), 1);
$base_path = base_path('legacy');
// Fix per redirect all'API
diff --git a/app/Http/Controllers/RequirementsController.php b/app/Http/Controllers/RequirementsController.php
new file mode 100644
index 000000000..3979cc398
--- /dev/null
+++ b/app/Http/Controllers/RequirementsController.php
@@ -0,0 +1,149 @@
+ self::getRequirementsList()
+ ];
+
+ return view('config.requirements', $args);
+ }
+
+ public static function getRequirementsList($file = null)
+ {
+ $requirements = self::getRequirements($file);
+
+ $list = [
+ tr('Apache') => $requirements['apache'],
+ tr('PHP (_VERSION_)', [
+ '_VERSION_' => phpversion(),
+ ]) => $requirements['php'],
+ tr('Percorsi di servizio') => $requirements['paths'],
+ ];
+
+ return $list;
+ }
+
+ public static function getRequirements($file = null)
+ {
+ if (empty($file) && isset(self::$requirements)) {
+ return self::$requirements;
+ }
+
+ $list = config('requirements');
+ if (!empty($file)) {
+ $file = realpath($file);
+ if (string_starts_with($file)) {
+ $list = include $file;
+ }
+ }
+
+ // Apache
+ if (function_exists('apache_get_modules')) {
+ $available_modules = apache_get_modules();
+ }
+
+ $apache = $list['apache'];
+ foreach ($apache as $name => $values) {
+ $status = isset($available_modules) ? in_array($name, $available_modules) : false;
+ $status = isset($values['server']) && isset($_SERVER[$values['server']]) ? $_SERVER[$values['server']] == 'On' : $status;
+
+ $apache[$name]['description'] = tr('Il modulo Apache _MODULE_ deve essere abilitato', [
+ '_MODULE_' => ''.$name.' ',
+ ]);
+ $apache[$name]['status'] = $status;
+ }
+
+ // PHP
+ $php = $list['php'];
+ foreach ($php as $name => $values) {
+ if ($values['type'] == 'ext') {
+ $description = !empty($values['required']) ? tr("L'estensione PHP _EXT_ deve essere abilitata", [
+ '_EXT_' => ''.$name.' ',
+ ]) : tr("E' consigliata l'abilitazione dell'estensione PHP _EXT_", [
+ '_EXT_' => ''.$name.' ',
+ ]);
+
+ $status = extension_loaded($name);
+ } else {
+ $suggested = str_replace(['>', '<'], '', $values['suggested']);
+ $value = ini_get($name);
+
+ $description = tr("Valore consigliato per l'impostazione PHP: _VALUE_ (Valore attuale: _INI_)", [
+ '_VALUE_' => $suggested,
+ '_INI_' => ini_get($name),
+ ]);
+
+ $suggested = strpos($suggested, 'B') !== false ? $suggested : $suggested.'B';
+ $value = strpos($value, 'B') !== false ? $value : $value.'B';
+
+ $ini = FileSystem::convertBytes($value);
+ $real = FileSystem::convertBytes($suggested);
+
+ if (starts_with($values['suggested'], '>')) {
+ $status = $ini >= substr($real, 1);
+ } elseif (starts_with($values['suggested'], '<')) {
+ $status = $ini <= substr($real, 1);
+ } else {
+ $status = ($real == $ini);
+ }
+
+ $php[$name]['value'] = $value;
+
+ if (is_bool($suggested)) {
+ $suggested = !empty($suggested) ? 'On' : 'Off';
+ }
+ }
+
+ $php[$name]['description'] = $description;
+ $php[$name]['status'] = $status;
+ }
+
+ // Percorsi di servizio
+ $paths = [];
+ foreach ($list['directories'] as $name) {
+ $status = is_writable(base_path().DIRECTORY_SEPARATOR.$name);
+ $description = tr('Il percorso _PATH_ deve risultare accessibile da parte del gestionale (permessi di lettura e scrittura)', [
+ '_PATH_' => ''.$name.' ',
+ ]);
+
+ $paths[$name]['description'] = $description;
+ $paths[$name]['status'] = $status;
+ }
+
+ $result = [
+ 'apache' => $apache,
+ 'php' => $php,
+ 'paths' => $paths,
+ ];
+
+ if (empty($file)) {
+ self::$requirements = $result;
+ }
+
+ return $result;
+ }
+
+ public static function isSatisfied()
+ {
+ $general_status = true;
+
+ $requirements = self::getRequirements();
+ foreach ($requirements as $key => $values) {
+ foreach ($values as $value) {
+ $general_status &= !empty($value['required']) ? $value['status'] : true;
+ }
+ }
+
+ return $general_status;
+ }
+}
diff --git a/app/Http/Middleware/EnsureConfiguration.php b/app/Http/Middleware/EnsureConfiguration.php
index 38e3da0e4..e60eb95a1 100644
--- a/app/Http/Middleware/EnsureConfiguration.php
+++ b/app/Http/Middleware/EnsureConfiguration.php
@@ -4,6 +4,7 @@ namespace App\Http\Middleware;
use App\Http\Controllers\ConfigurationController;
use App\Http\Controllers\InitializationController;
+use App\Http\Controllers\RequirementsController;
use Closure;
use Illuminate\Http\Request;
@@ -21,6 +22,12 @@ class EnsureConfiguration
return $next($request);
}
+ // Test sui requisiti del gestionale
+ $result = $this->checkRequirements($route);
+ if ($result !== null) {
+ return $result;
+ }
+
// Test della connessione al database
$result = $this->checkConfiguration($route);
if ($result !== null) {
@@ -42,9 +49,28 @@ class EnsureConfiguration
return $next($request);
}
+ protected function checkRequirements($route)
+ {
+ $configuration_paths = ['requirements'];
+ $requirements_satisfied = RequirementsController::isSatisfied();
+
+ if ($requirements_satisfied) {
+ // Redirect nel caso in cui i requisiti siano soddisfatti
+ if (in_array($route->getName(), $configuration_paths)) {
+ return redirect(route('configuration'));
+ }
+ } else {
+ // Redirect per requisiti incompleti
+ if (!in_array($route->getName(), $configuration_paths)) {
+ return redirect(route('requirements'));
+ }
+ }
+
+ return null;
+ }
+
protected function checkConfiguration($route)
{
- // Test della connessione al database
$configuration_paths = ['configuration', 'configuration-save', 'configuration-test'];
$configuration_completed = ConfigurationController::isConfigured();
diff --git a/app/Http/Middleware/Language.php b/app/Http/Middleware/Language.php
index f7b971ac1..926c69bcb 100644
--- a/app/Http/Middleware/Language.php
+++ b/app/Http/Middleware/Language.php
@@ -11,8 +11,6 @@ class Language
/**
* Handle an incoming request.
*
- * @param \Illuminate\Http\Request $request
- * @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
diff --git a/app/View/Components/Input.php b/app/View/Components/Input.php
index 4f99fa0f4..4aa85a064 100644
--- a/app/View/Components/Input.php
+++ b/app/View/Components/Input.php
@@ -12,7 +12,7 @@ class Input extends Component
/**
* Create a new component instance.
*
- * @param string $name
+ * @param string $name
* @param string|null $id
* @param string|null $value
* @param bool|string $required
diff --git a/app/View/Components/Inputs/Number.php b/app/View/Components/Inputs/Number.php
index 3a19447af..d74d486bd 100644
--- a/app/View/Components/Inputs/Number.php
+++ b/app/View/Components/Inputs/Number.php
@@ -10,13 +10,13 @@ class Number extends Input
/**
* Create a new component instance.
*
- * @param string $name
+ * @param string $name
* @param string|null $id
* @param string|null $value
* @param bool|string $required
* @param string|null $label
* @param string|null $placeholder
- * @param null $minValue
+ * @param null $minValue
*/
public function __construct(
$name,
@@ -44,7 +44,7 @@ class Number extends Input
$decimals = setting('Cifre decimali per quantità');
// Se non è previsto un valore minimo, lo imposta a 1
- $minValue = isset($minValue) ? $minValue : '0.'.str_repeat('0', $decimals - 1).'1';
+ $minValue = isset($minValue) ? $minValue : '0.'.str_repeat('0', $decimals - 1).'1';
$this->set([
'decimals' => $decimals,
diff --git a/app/View/Components/Inputs/Select.php b/app/View/Components/Inputs/Select.php
index e1d6ce7db..f1cd69150 100644
--- a/app/View/Components/Inputs/Select.php
+++ b/app/View/Components/Inputs/Select.php
@@ -13,7 +13,6 @@ class Select extends Component
*/
public function __construct()
{
- //
}
/**
diff --git a/app/helpers.php b/app/helpers.php
index 6fef497a2..b824b56b2 100644
--- a/app/helpers.php
+++ b/app/helpers.php
@@ -2,8 +2,6 @@
/**
* Gets the current locale.
- *
- * @return string
*/
function locale(): string
{
@@ -12,13 +10,11 @@ function locale(): string
/**
* Get the language portion of the locale.
- * (ex. en_GB returns en)
- *
- * @return string
+ * (ex. en_GB returns en).
*/
function localeLanguage(): string
{
$locale = locale();
- return substr($locale, 0, strpos($locale, "_"));
+ return substr($locale, 0, strpos($locale, '_'));
}
diff --git a/composer.json b/composer.json
index 75318a80b..681d514b5 100644
--- a/composer.json
+++ b/composer.json
@@ -16,6 +16,7 @@
"type": "project",
"require": {
"php": "^7.3|^8.0",
+ "ext-apache": "*",
"ext-curl": "*",
"ext-dom": "*",
"ext-fileinfo": "*",
@@ -117,6 +118,7 @@
"Plugins\\DettagliArticolo\\": ["legacy/plugins/dettagli_articolo/custom/src/", "legacy/plugins/dettagli_articolo/src/"],
"App\\": "app/",
+ "Modules\\": "modules/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
},
diff --git a/config/requirements.php b/config/requirements.php
new file mode 100644
index 000000000..5a0135756
--- /dev/null
+++ b/config/requirements.php
@@ -0,0 +1,61 @@
+ [
+ 'zip' => [
+ 'type' => 'ext',
+ 'required' => 1,
+ ],
+ 'mbstring' => [
+ 'type' => 'ext',
+ 'required' => 1,
+ ],
+ 'pdo_mysql' => [
+ 'type' => 'ext',
+ 'required' => 1,
+ ],
+ 'dom' => [
+ 'type' => 'ext',
+ 'required' => 1,
+ ],
+ 'xsl' => [
+ 'type' => 'ext',
+ 'required' => 1,
+ ],
+ 'openssl' => [
+ 'type' => 'ext',
+ 'required' => 1,
+ ],
+ 'intl' => [
+ 'type' => 'ext',
+ 'required' => 1,
+ ],
+ 'curl' => [
+ 'type' => 'ext',
+ 'required' => 1,
+ ],
+ 'soap' => [
+ 'type' => 'ext',
+ 'required' => 1,
+ ],
+
+ 'upload_max_filesize' => [
+ 'type' => 'value',
+ 'suggested' => '>32M',
+ ],
+ 'post_max_size' => [
+ 'type' => 'value',
+ 'suggested' => '>32M',
+ ],
+ ],
+ 'apache' => [
+ 'mod_rewrite' => [
+ 'server' => 'HTTP_MOD_REWRITE',
+ ],
+ ],
+ 'directories' => [
+ 'backup',
+ 'files',
+ 'logs',
+ ],
+];
diff --git a/legacy b/legacy
index 01a293d36..5730434cc 160000
--- a/legacy
+++ b/legacy
@@ -1 +1 @@
-Subproject commit 01a293d3650fcf96d8617fab2b14a0c193bca6d9
+Subproject commit 5730434cc63c67880049f6adb116791dc8af8a5b
diff --git a/modules/Aggiornamenti/Config/config.php b/modules/Aggiornamenti/Config/config.php
new file mode 100644
index 000000000..b361208df
--- /dev/null
+++ b/modules/Aggiornamenti/Config/config.php
@@ -0,0 +1,5 @@
+ 'Aggiornamenti'
+];
diff --git a/modules/Aggiornamenti/Database/Migrations/.gitkeep b/modules/Aggiornamenti/Database/Migrations/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/modules/Aggiornamenti/Database/Seeders/.gitkeep b/modules/Aggiornamenti/Database/Seeders/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/modules/Aggiornamenti/Database/Seeders/AggiornamentiDatabaseSeeder.php b/modules/Aggiornamenti/Database/Seeders/AggiornamentiDatabaseSeeder.php
new file mode 100644
index 000000000..6b7f2a782
--- /dev/null
+++ b/modules/Aggiornamenti/Database/Seeders/AggiornamentiDatabaseSeeder.php
@@ -0,0 +1,21 @@
+call("OthersTableSeeder");
+ }
+}
diff --git a/modules/Aggiornamenti/Database/factories/.gitkeep b/modules/Aggiornamenti/Database/factories/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/modules/Aggiornamenti/Entities/.gitkeep b/modules/Aggiornamenti/Entities/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/modules/Aggiornamenti/Http/Aggiornamento.php b/modules/Aggiornamenti/Http/Aggiornamento.php
new file mode 100644
index 000000000..ea32e44b4
--- /dev/null
+++ b/modules/Aggiornamenti/Http/Aggiornamento.php
@@ -0,0 +1,466 @@
+directory = $directory ?: Zip::getExtractionDirectory();
+
+ if (!$this->isCoreUpdate() && empty($this->componentUpdates())) {
+ throw new InvalidArgumentException();
+ }
+ }
+
+ /**
+ * Pulisce la cartella di estrazione.
+ */
+ public function delete()
+ {
+ delete($this->directory);
+ }
+
+ /**
+ * Restituisce il percorso impostato per l'aggiornamento corrente.
+ *
+ * @return string
+ */
+ public function getDirectory()
+ {
+ return $this->directory;
+ }
+
+ /**
+ * Controlla se l'aggiornamento è di tipo globale.
+ *
+ * @return bool
+ */
+ public function isCoreUpdate()
+ {
+ return file_exists($this->directory.'/VERSION');
+ }
+
+ public function getChangelog()
+ {
+ if ($this->isCoreUpdate()) {
+ $changelog = self::readChangelog($this->getDirectory(), Update::getVersion());
+ } else {
+ $changelogs = [];
+ $elements = $this->componentUpdates();
+
+ $list = array_merge($elements['modules'], $elements['plugins']);
+ foreach ($list as $element) {
+ $changelog = self::readChangelog($element['path'], $element['version']);
+
+ if (!empty($changelog)) {
+ $changelogs[] = '
+
'.$element['info']['name'].'
+ '.$changelog;
+ }
+ }
+
+ $changelog = implode(' ', $changelogs);
+ }
+
+ return $changelog;
+ }
+
+ public function getRequirements()
+ {
+ $file = $this->directory.'/config/requirements.php';
+ $result = Requirements::getRequirementsList($file);
+
+ return $result;
+ }
+
+ public function getVersion()
+ {
+ return Update::getFile($this->getDirectory().'/VERSION');
+ }
+
+ /**
+ * Individua i componenti indipendenti che compongono l'aggiornamento.
+ *
+ * @return array
+ */
+ public function componentUpdates()
+ {
+ if (!isset($this->components)) {
+ $finder = Finder::create()
+ ->files()
+ ->ignoreDotFiles(true)
+ ->ignoreVCS(true)
+ ->in($this->directory);
+
+ $files = $finder->name('MODULE')->name('PLUGIN');
+
+ $results = [];
+ foreach ($files as $file) {
+ $is_module = basename($file->getRealPath()) == 'MODULE';
+ $is_plugin = basename($file->getRealPath()) == 'PLUGIN';
+
+ $info = Ini::readFile($file->getRealPath());
+ $installed = module($info['name']);
+ if ($is_module) {
+ $type = 'modules';
+ } elseif ($is_plugin) {
+ $type = 'plugins';
+ }
+
+ if (!isset($results[$type])) {
+ $results[$type] = [];
+ }
+ $results[$type][] = [
+ 'path' => dirname($file->getRealPath()),
+ 'config' => $file->getRealPath(),
+ 'is_installed' => !empty($installed),
+ 'current_version' => !empty($installed) ? $installed->version : null,
+ 'info' => $info,
+ ];
+ }
+
+ $this->components = $results;
+ }
+
+ return $this->components;
+ }
+
+ /**
+ * Effettua l'aggiornamento.
+ */
+ public function execute()
+ {
+ if ($this->isCoreUpdate()) {
+ $this->executeCore();
+ } else {
+ $components = $this->componentUpdates();
+
+ foreach ((array) $components['modules'] as $module) {
+ $this->executeModule($module);
+ }
+
+ foreach ((array) $components['plugins'] as $plugin) {
+ $this->executeModule($plugin);
+ }
+ }
+
+ $this->delete();
+ }
+
+ /**
+ * Completa l'aggiornamento globale secondo la procedura apposita.
+ */
+ public function executeCore()
+ {
+ // Salva il file di configurazione
+ $config = file_get_contents(DOCROOT.'/config.inc.php');
+
+ // Copia i file dalla cartella temporanea alla root
+ copyr($this->directory, DOCROOT);
+
+ // Ripristina il file di configurazione dell'installazione
+ file_put_contents(DOCROOT.'/config.inc.php', $config);
+ }
+
+ /**
+ * Completa l'aggiornamento con le informazioni specifiche per i moduli.
+ *
+ * @param array $module
+ */
+ public function executeModule($module)
+ {
+ // Informazioni dal file di configurazione
+ $info = $module['info'];
+
+ // Informazioni aggiuntive per il database
+ $insert = [
+ 'parent' => module($info['parent']),
+ 'icon' => $info['icon'],
+ ];
+
+ $id = $this->executeComponent($module['path'], 'modules', 'zz_modules', $insert, $info, $module['is_installed']);
+
+ if (!empty($id)) {
+ // Fix per i permessi di amministratore
+ $element = Module::find($id);
+
+ $element->groups()->syncWithoutDetaching($this->groups());
+ }
+ }
+
+ /**
+ * Instanzia un aggiornamento sulla base di uno zip indicato.
+ * Controlla inoltre che l'aggiornamento sia fattibile.
+ *
+ * @param string $file
+ *
+ * @throws DowngradeException
+ * @throws InvalidArgumentException
+ *
+ * @return static
+ */
+ public static function make($file)
+ {
+ $extraction_dir = Zip::extract($file);
+
+ $update = new static($extraction_dir);
+
+ if ($update->isCoreUpdate()) {
+ $version = Update::getFile($update->getDirectory().'/VERSION');
+ $current = Update::getVersion();
+
+ if (version_compare($current, $version) >= 0) {
+ $update->delete();
+
+ throw new DowngradeException();
+ }
+ } else {
+ $components = $update->componentUpdates();
+
+ foreach ((array) $components['modules'] as $module) {
+ if (version_compare($module['current_version'], $module['info']['version']) >= 0) {
+ delete($module['path']);
+ }
+ }
+
+ foreach ((array) $components['plugins'] as $plugin) {
+ if (version_compare($plugin['current_version'], $plugin['info']['version']) >= 0) {
+ delete($plugin['path']);
+ }
+ }
+ }
+
+ // Instanzia nuovamente l'oggetto
+ return new static($extraction_dir);
+ }
+
+ /**
+ * Controlla se è disponibile un aggiornamento nella repository GitHub.
+ *
+ * @return string|bool
+ */
+ public static function isAvailable()
+ {
+ $release = self::getLastRelease();
+
+ $version = ltrim($release['tag_name'], 'v');
+ $current = Update::getVersion();
+
+ $result = false;
+ if (version_compare($current, $version) < 0) {
+ $result = $version.($release['prerelease'] ? ' (beta)' : '');
+ }
+
+ // Aggiornamento cache dedicata
+ Cache::pool('Ultima versione di OpenSTAManager disponibile')->set($result);
+
+ return $result;
+ }
+
+ /**
+ * Scarica la release più recente (se presente).
+ *
+ * @return static
+ */
+ public static function download()
+ {
+ if (self::isAvailable() === false) {
+ return null;
+ }
+
+ $directory = Zip::getExtractionDirectory();
+ $file = $directory.'/release.zip';
+ directory($directory);
+
+ $release = self::getLastRelease();
+ self::getClient()->request('GET', $release['assets'][0]['browser_download_url'], ['sink' => $file]);
+
+ $update = self::make($file);
+ delete($file);
+
+ return $update;
+ }
+
+ /**
+ * Restituisce i contenuti JSON dell'API del progetto.
+ *
+ * @return array
+ */
+ public static function checkFiles()
+ {
+ $date = date('Y-m-d', filemtime(DOCROOT.'/core.php'));
+
+ // Individuazione dei file tramite data di modifica
+ $files = Finder::create()
+ ->date('<= '.$date)
+ ->sortByName()
+ ->in(DOCROOT)
+ ->exclude([
+ 'node_modules',
+ 'tests',
+ 'tmp',
+ 'vendor',
+ ])
+ ->name('*.php')
+ ->notPath('*custom*')
+ ->files();
+
+ return iterator_to_array($files);
+ }
+
+ /**
+ * Restituisce il changelog presente nel percorso indicato a partire dalla versione specificata.
+ *
+ * @param string $path
+ * @param string $version
+ *
+ * @return string
+ */
+ protected static function readChangelog($path, $version = null)
+ {
+ $result = file_get_contents($path.'/CHANGELOG.md');
+
+ $start = strpos($result, '## ');
+ $result = substr($result, $start);
+ if (!empty($version)) {
+ $last = strpos($result, '## '.$version.' ');
+
+ if ($last !== false) {
+ $result = substr($result, 0, $last);
+ }
+ }
+
+ $result = Parsedown::instance()->text($result);
+ $result = str_replace(['h4>', 'h3>', 'h2>'], ['p>', 'b>', 'h4>'], $result);
+
+ return $result;
+ }
+
+ /**
+ * Completa l'aggiornamento del singolo componente come previsto dai parametri indicati.
+ *
+ * @param string $directory Percorso di copia dei contenuti
+ * @param string $table Tabella interessata dall'aggiornamento
+ * @param array $insert Informazioni per la registrazione
+ * @param array $info Contenuti della configurazione
+ * @param bool $is_installed
+ *
+ * @return int|null
+ */
+ protected function executeComponent($path, $directory, $table, $insert, $info, $is_installed = false)
+ {
+ // Copia dei file nella cartella relativa
+ copyr($path, DOCROOT.'/'.$directory.'/'.$info['directory']);
+
+ // Eventuale registrazione nel database
+ if (empty($is_installed)) {
+ $dbo = database();
+
+ $dbo->insert($table, array_merge($insert, [
+ 'name' => $info['name'],
+ 'title' => !empty($info['title']) ? $info['title'] : $info['name'],
+ 'directory' => $info['directory'],
+ 'options' => $info['options'],
+ 'version' => $info['version'],
+ 'compatibility' => $info['compatibility'],
+ 'order' => 100,
+ 'default' => 0,
+ 'enabled' => 1,
+ ]));
+
+ return $dbo->lastInsertedID();
+ }
+ }
+
+ /**
+ * Resituisce i permessi di default da impostare all'installazione del componente.
+ *
+ * @return array
+ */
+ protected function groups()
+ {
+ if (!isset($this->groups)) {
+ $groups = Group::where('nome', 'Amministratori')->get();
+
+ $result = [];
+ foreach ($groups as $group) {
+ $result[$group->id] = [
+ 'permission_level' => 'rw',
+ ];
+ }
+
+ $this->groups = $result;
+ }
+
+ return $this->groups;
+ }
+
+ /**
+ * Restituisce l'oggetto per la connessione all'API del progetto.
+ *
+ * @return Client
+ */
+ protected static function getClient()
+ {
+ if (!isset(self::$client)) {
+ self::$client = new Client([
+ 'base_uri' => 'https://api.github.com/repos/devcode-it/openstamanager/',
+ 'verify' => false,
+ ]);
+ }
+
+ return self::$client;
+ }
+
+ /**
+ * Restituisce i contenuti JSON dell'API del progetto.
+ *
+ * @return array
+ * @throws \GuzzleHttp\Exception\GuzzleException
+ */
+ protected static function getLastRelease()
+ {
+ $response = self::getClient()->request('GET', 'releases');
+ $body = $response->getBody();
+
+ // Impostazione per l'utilizzo o meno di versioni non stabili
+ $prerelease = intval(setting('Abilita canale pre-release per aggiornamenti'));
+
+ // Ricerca dell'ultima release del tipi specificato
+ $releases = json_decode($body, true) ?: [];
+ foreach ($releases as $release) {
+ if ($release['prerelease'] == $prerelease) {
+ return $release;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/modules/Aggiornamenti/Http/Controllers/AggiornamentiController.php b/modules/Aggiornamenti/Http/Controllers/AggiornamentiController.php
new file mode 100644
index 000000000..39fb57842
--- /dev/null
+++ b/modules/Aggiornamenti/Http/Controllers/AggiornamentiController.php
@@ -0,0 +1,249 @@
+ $update,
+ 'update_version' => $update->getVersion(),
+ 'update_requirements' => $update->getRequirements(),
+ ];
+
+ return view('aggiornamenti::update', $args);
+ } catch (InvalidArgumentException $e) {
+ }
+
+ $custom = $this->customComponents();
+ $tables = $this->customTables();
+
+ // Aggiornamenti
+ $alerts = [];
+
+ if (!extension_loaded('zip')) {
+ $alerts[tr('Estensione ZIP')] = tr('da abilitare');
+ }
+
+ $upload_max_filesize = ini_get('upload_max_filesize');
+ $upload_max_filesize = str_replace(['k', 'M'], ['000', '000000'], $upload_max_filesize);
+ // Dimensione minima: 32MB
+ if ($upload_max_filesize < 32000000) {
+ $alerts['upload_max_filesize'] = '32MB';
+ }
+
+ $post_max_size = ini_get('post_max_size');
+ $post_max_size = str_replace(['k', 'M'], ['000', '000000'], $post_max_size);
+ // Dimensione minima: 32MB
+ if ($post_max_size < 32000000) {
+ $alerts['post_max_size'] = '32MB';
+ }
+
+ $args = [
+ 'module' => module('Aggiornamenti'),
+ 'custom' => $custom,
+ 'tables' => $tables,
+ 'alerts' => $alerts,
+ 'enable_updates' => setting('Attiva aggiornamenti'),
+ 'requirements' => RequirementsController::getRequirementsList(),
+ ];
+
+ return view('aggiornamenti::index', $args);
+ }
+
+ /**
+ * Controlla se il database presenta alcune sezioni personalizzate.
+ *
+ * @return array
+ */
+ public function customStructure()
+ {
+ $results = [];
+
+ $dirs = [
+ 'modules',
+ 'templates',
+ 'plugins',
+ ];
+
+ // Controlli di personalizzazione fisica
+ foreach ($dirs as $dir) {
+ $files = glob(base_dir().'/'.$dir.'/*/custom/*.{php,html}', GLOB_BRACE);
+ $recursive_files = glob(base_dir().'/'.$dir.'/*/custom/**/*.{php,html}', GLOB_BRACE);
+
+ $files = array_merge($files, $recursive_files);
+
+ foreach ($files as $file) {
+ $file = str_replace(base_dir().'/', '', $file);
+ $result = explode('/custom/', $file)[0];
+
+ if (!in_array($result, $results)) {
+ $results[] = $result;
+ }
+ }
+ }
+
+ // Gestione cartella include
+ $files = glob(base_dir().'/include/custom/*.{php,html}', GLOB_BRACE);
+ $recursive_files = glob(base_dir().'/include/custom/**/*.{php,html}', GLOB_BRACE);
+
+ $files = array_merge($files, $recursive_files);
+
+ foreach ($files as $file) {
+ $file = str_replace(base_dir().'/', '', $file);
+ $result = explode('/custom/', $file)[0];
+
+ if (!in_array($result, $results)) {
+ $results[] = $result;
+ }
+ }
+
+ return $results;
+ }
+
+ /**
+ * Controlla se il database presenta alcune sezioni personalizzate.
+ *
+ * @return array
+ */
+ protected function customTables()
+ {
+ $tables = include base_dir().'/update/tables.php';
+
+ $names = [];
+ foreach ($tables as $table) {
+ $names[] = prepare($table);
+ }
+
+ $database = database();
+
+ $results = $database->fetchArray('SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '.prepare($database->getDatabaseName()).' AND TABLE_NAME NOT IN ('.implode(',', $names).") AND TABLE_NAME != 'updates'");
+
+ return array_column($results, 'TABLE_NAME');
+ }
+
+ /**
+ * Controlla se il database presenta alcune sezioni personalizzate.
+ *
+ * @return array
+ */
+ protected function customDatabase()
+ {
+ $database = database();
+ $modules = $database->fetchArray("SELECT name, CONCAT('modules/', directory) AS directory FROM zz_modules WHERE options2 != ''");
+ $plugins = $database->fetchArray("SELECT name, CONCAT('plugins/', directory) AS directory FROM zz_plugins WHERE options2 != ''");
+
+ $results = array_merge($modules, $plugins);
+
+ return $results;
+ }
+
+ protected function customComponents()
+ {
+ $database_check = $this->customDatabase();
+ $structure_check = $this->customStructure();
+
+ $list = [];
+ foreach ($database_check as $element) {
+ $pos = array_search($element['directory'], $structure_check);
+
+ $list[] = [
+ 'path' => $element['directory'],
+ 'database' => true,
+ 'directory' => $pos !== false,
+ ];
+
+ if ($pos !== false) {
+ unset($structure_check[$pos]);
+ }
+ }
+
+ foreach ($structure_check as $element) {
+ $list[] = [
+ 'path' => $element,
+ 'database' => false,
+ 'directory' => true,
+ ];
+ }
+
+ return $list;
+ }
+
+ public function create(Request $request)
+ {
+ if (!setting('Attiva aggiornamenti')) {
+ die(tr('Accesso negato'));
+ }
+
+ try {
+ $update = Aggiornamento::make($_FILES['blob']['tmp_name']);
+ } catch (DowngradeException $e) {
+ flash()->error(tr('Il pacchetto contiene una versione precedente del gestionale'));
+ } catch (InvalidArgumentException $e) {
+ flash()->error(tr('Il pacchetto contiene solo componenti già installate e aggiornate'));
+ }
+ }
+
+ public function check(Request $request)
+ {
+ $result = Aggiornamento::isAvailable();
+ $result = $result === false ? 'none' : $result;
+
+ return $result;
+ }
+
+ public function download(Request $request)
+ {
+ Aggiornamento::download();
+ }
+
+ public function execute(Request $request)
+ {
+ try {
+ $update = new Aggiornamento();
+
+ $update->execute();
+ } catch (InvalidArgumentException $e) {
+ }
+
+ $route = $this->router->urlFor('module', [
+ 'module_id' => $args['module_id'],
+ ]);
+ $response = $response->withRedirect($route);
+
+ return $response;
+ }
+
+ public function cancel(Request $request)
+ {
+ try {
+ $update = new Aggiornamento();
+
+ $update->delete();
+ } catch (InvalidArgumentException $e) {
+ }
+
+ $route = $this->router->urlFor('module', [
+ 'module_id' => $args['module_id'],
+ ]);
+ $response = $response->withRedirect($route);
+
+ return $response;
+ }
+}
diff --git a/modules/Aggiornamenti/Http/Controllers/ControlliAggiuntiviController.php b/modules/Aggiornamenti/Http/Controllers/ControlliAggiuntiviController.php
new file mode 100644
index 000000000..9aff8cef3
--- /dev/null
+++ b/modules/Aggiornamenti/Http/Controllers/ControlliAggiuntiviController.php
@@ -0,0 +1,14 @@
+.
+ */
+
+namespace Modules\Aggiornamenti\Http;
+
+use GuzzleHttp\Client;
+use Hooks\CachedManager;
+use Update;
+
+/**
+ * Hook dedicato all'individuazione di nuove versioni del gestionale, pubblicate sulla repository ufficiale di GitHub.
+ */
+class UpdateHook extends CachedManager
+{
+ protected static $client = null;
+
+ public function getCacheName()
+ {
+ return 'Ultima versione di OpenSTAManager disponibile';
+ }
+
+ public function cacheData()
+ {
+ return self::isAvailable();
+ }
+
+ public function response()
+ {
+ $update = $this->getCache()->content;
+ if ($update == Update::getVersion()) {
+ $update = null;
+ }
+
+ $module = module('Aggiornamenti');
+ $link = base_url().'/controller.php?id_module='.$module->id;
+
+ $message = tr("E' disponibile la versione _VERSION_ del gestionale", [
+ '_VERSION_' => $update,
+ ]);
+
+ return [
+ 'icon' => 'fa fa-download text-info',
+ 'link' => $link,
+ 'message' => $message,
+ 'show' => !empty($update),
+ ];
+ }
+
+ /**
+ * Controlla se è disponibile un aggiornamento nella repository GitHub.
+ *
+ * @return array|bool
+ */
+ public static function isAvailable()
+ {
+ $api = self::getAPI();
+
+ if (!$api['prerelease'] or setting('Abilita canale pre-release per aggiornamenti')) {
+ $version[0] = ltrim($api['tag_name'], 'v');
+ $version[1] = !empty($api['prerelease']) ? 'beta' : 'stabile';
+ $current = Update::getVersion();
+
+ if (version_compare($current, $version[0]) < 0) {
+ return $version;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Restituisce l'oggetto per la connessione all'API del progetto.
+ *
+ * @return Client
+ */
+ protected static function getClient()
+ {
+ if (!isset(self::$client)) {
+ self::$client = new Client([
+ 'base_uri' => 'https://api.github.com/repos/devcode-it/openstamanager/',
+ 'verify' => false,
+ ]);
+ }
+
+ return self::$client;
+ }
+
+ /**
+ * Restituisce i contenuti JSON dell'API del progetto.
+ *
+ * @return array
+ */
+ protected static function getAPI()
+ {
+ $response = self::getClient()->request('GET', 'releases');
+ $body = $response->getBody();
+
+ return json_decode($body, true)[0];
+ }
+}
diff --git a/modules/Aggiornamenti/Providers/AggiornamentiServiceProvider.php b/modules/Aggiornamenti/Providers/AggiornamentiServiceProvider.php
new file mode 100644
index 000000000..23df46575
--- /dev/null
+++ b/modules/Aggiornamenti/Providers/AggiornamentiServiceProvider.php
@@ -0,0 +1,112 @@
+registerTranslations();
+ $this->registerConfig();
+ $this->registerViews();
+ $this->loadMigrationsFrom(module_path($this->moduleName, 'Database/Migrations'));
+ }
+
+ /**
+ * Register the service provider.
+ *
+ * @return void
+ */
+ public function register()
+ {
+ $this->app->register(RouteServiceProvider::class);
+ }
+
+ /**
+ * Register config.
+ *
+ * @return void
+ */
+ protected function registerConfig()
+ {
+ $this->publishes([
+ module_path($this->moduleName, 'Config/config.php') => config_path($this->moduleNameLower . '.php'),
+ ], 'config');
+ $this->mergeConfigFrom(
+ module_path($this->moduleName, 'Config/config.php'), $this->moduleNameLower
+ );
+ }
+
+ /**
+ * Register views.
+ *
+ * @return void
+ */
+ public function registerViews()
+ {
+ $viewPath = resource_path('views/modules/' . $this->moduleNameLower);
+
+ $sourcePath = module_path($this->moduleName, 'Resources/views');
+
+ $this->publishes([
+ $sourcePath => $viewPath
+ ], ['views', $this->moduleNameLower . '-module-views']);
+
+ $this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower);
+ }
+
+ /**
+ * Register translations.
+ *
+ * @return void
+ */
+ public function registerTranslations()
+ {
+ $langPath = resource_path('lang/modules/' . $this->moduleNameLower);
+
+ if (is_dir($langPath)) {
+ $this->loadTranslationsFrom($langPath, $this->moduleNameLower);
+ } else {
+ $this->loadTranslationsFrom(module_path($this->moduleName, 'Resources/lang'), $this->moduleNameLower);
+ }
+ }
+
+ /**
+ * Get the services provided by the provider.
+ *
+ * @return array
+ */
+ public function provides()
+ {
+ return [];
+ }
+
+ private function getPublishableViewPaths(): array
+ {
+ $paths = [];
+ foreach (\Config::get('view.paths') as $path) {
+ if (is_dir($path . '/modules/' . $this->moduleNameLower)) {
+ $paths[] = $path . '/modules/' . $this->moduleNameLower;
+ }
+ }
+ return $paths;
+ }
+}
diff --git a/modules/Aggiornamenti/Providers/RouteServiceProvider.php b/modules/Aggiornamenti/Providers/RouteServiceProvider.php
new file mode 100644
index 000000000..2f6c1d2ac
--- /dev/null
+++ b/modules/Aggiornamenti/Providers/RouteServiceProvider.php
@@ -0,0 +1,69 @@
+mapApiRoutes();
+
+ $this->mapWebRoutes();
+ }
+
+ /**
+ * Define the "web" routes for the application.
+ *
+ * These routes all receive session state, CSRF protection, etc.
+ *
+ * @return void
+ */
+ protected function mapWebRoutes()
+ {
+ Route::middleware('web')
+ ->namespace($this->moduleNamespace)
+ ->group(module_path('Aggiornamenti', '/Routes/web.php'));
+ }
+
+ /**
+ * Define the "api" routes for the application.
+ *
+ * These routes are typically stateless.
+ *
+ * @return void
+ */
+ protected function mapApiRoutes()
+ {
+ Route::prefix('api')
+ ->middleware('api')
+ ->namespace($this->moduleNamespace)
+ ->group(module_path('Aggiornamenti', '/Routes/api.php'));
+ }
+}
diff --git a/modules/Aggiornamenti/Resources/assets/.gitkeep b/modules/Aggiornamenti/Resources/assets/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/modules/Aggiornamenti/Resources/assets/js/app.js b/modules/Aggiornamenti/Resources/assets/js/app.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/modules/Aggiornamenti/Resources/assets/sass/app.scss b/modules/Aggiornamenti/Resources/assets/sass/app.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/modules/Aggiornamenti/Resources/lang/.gitkeep b/modules/Aggiornamenti/Resources/lang/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/modules/Aggiornamenti/Resources/views/index.blade.php b/modules/Aggiornamenti/Resources/views/index.blade.php
new file mode 100644
index 000000000..c765453f1
--- /dev/null
+++ b/modules/Aggiornamenti/Resources/views/index.blade.php
@@ -0,0 +1,222 @@
+@extends('modules.base')
+
+@section('module_content')
+ @if(!empty($custom) or !empty($tables))
+
+
+
+
+
+ @if(!empty($custom))
+
+
+ {{ tr('Percorso') }}
+ {{ tr('Cartella personalizzata') }}
+ {{ tr('Database personalizzato') }}
+
+
+ @foreach($custom as $element)
+
+ {{ $element['path'] }}
+ {{ $element['directory'] ? tr('Si') : tr('No') }}
+ {{ $element['database'] ? tr('Si') : tr('No') }}
+
+ @endforeach
+
+
+
{{ tr("Si sconsiglia l'aggiornamento senza il supporto dell'assistenza ufficiale") }}.
+ @else
+
{{ tr('Non ci sono strutture personalizzate') }}.
+ @endif
+
+ @if(!empty($tables))
+
+
+ {{ tr('Attenzione!') }} {{ tr('Ci sono delle tabelle non previste nella versione standard del gestionale: _LIST_', [
+ '_LIST_' => implode(', ', $tables),
+ ]) }}
+
+ @endif
+
+
+
+@endif
+
+@if(!empty($alerts))
+
+
{{ tr('Devi modificare il seguenti parametri del file di configurazione PHP (_FILE_) per poter caricare gli aggiornamenti', ['_FILE_' => 'php.ini ']) }}:
+
+ @foreach($alerts as $key => $value)
+ {{ $key }} = {{ $value }}
+ @endforeach
+
+
+@endif
+
+
+
+
+
+
+
+
+
+
+
+ {{ tr('Controlla file') }}
+
+
+ {{ tr('Controlla database') }}
+
+
+ {{ tr('Controlla gestionale') }}
+
+
+
+
+
+
+
+
+
+
+ @if(extension_loaded('curl'))
+
+
+ {{ tr('Ricerca') }}
+
+
+ @else
+
+ {{ tr('Estensione curl non supportata') }}.
+
+ @endif
+
+
+
{{ tr("E' stato individuato un nuovo aggiornamento") }}: .
+
{{ tr('Attenzione: la versione individuata è in fase sperimentale, e pertanto può presentare diversi bug e malfunzionamenti') }}.
+
+
{!! tr('Scaricalo manualmente (_LINK_) oppure in automatico', ['_LINK_' => 'https://github.com/devcode-it/openstamanager/releases ']) !!}:
+
+
+ {{ tr('Scarica') }}
+
+
+
+
+
{{ tr('Nessun aggiornamento presente') }}.
+
+
+
+
+
+
+
+
+
+
{{ tr('Requisiti') }}
+
+ @include('config.requirements-list')
+
+@endsection
diff --git a/modules/Aggiornamenti/Resources/views/update.blade.php b/modules/Aggiornamenti/Resources/views/update.blade.php
new file mode 100644
index 000000000..e61b1a265
--- /dev/null
+++ b/modules/Aggiornamenti/Resources/views/update.blade.php
@@ -0,0 +1,137 @@
+{% extends "layouts/base.twig" %}
+
+{% block body_class %}hold-transition login-page{% endblock %}
+{% block title %}{{ 'Aggiornamento'|trans }}{% endblock %}
+
+{% block body %}
+
+
+
+
+
+
+ {% if update.isCoreUpdate() %}
+
{{ "Il pacchetto selezionato contiene un aggiornamento dell'intero gestionale"|trans }}.
+
{{ "Si consiglia vivamente di effettuare un backup dell'installazione prima di procedere"|trans }}.
+
+
+ {{ 'Crea backup'|trans }}
+
+
+
+
+
+
{{ 'OpenSTAManager versione _VERSION_'|trans({'_VERSION_': update.getVersion()}) }}
+
+ {% include 'config/list.twig' with {requirements: update.getRequirements()} only %}
+
+ {% else %}
+ {% set elements = update.componentUpdates() %}
+
+
+
+ {{ 'Attenzione!'|trans }} {{ 'Verranno aggiornate le sole componenti del pacchetto che non sono già installate e aggiornate'|trans }}.
+
+
+ {% if elements.modules is not empty %}
+
{{ 'Il pacchetto selezionato comprende i seguenti moduli'|trans }}:
+
+
+ {% for element in elements.modules %}
+
+ {{ element['info']['version'] }}
+
+ {% if element.is_installed %}
+ {{ 'Installato'|trans }} ';
+ {% endif %}
+
+ {{ element['info']['name'] }}
+
+ {% endfor %}
+
+
+ {% endif %}
+
+ {% if elements.plugins is not empty %}
+
{{ 'Il pacchetto selezionato comprende i seguenti plugin'|trans }}:
+
';
+
+ {% for element in elements.plugins %}
+
+ {{ element['info']['version'] }}
+
+ {% if element.is_installed %}
+ {{ 'Installato'|trans }} ';
+ {% endif %}
+
+ {{ element['info']['name'] }}
+
+ {% endfor %}
+
+
+ {% endif %}
+ {% endif %}
+
+
+
+
+ {% set changelog = update.getChangelog() %}
+
+ {% if changelog is not empty %}
+ {{ changelog|raw }}
+ {% else %}
+
{{ 'Nessuna changelog individuabile'|trans }}.
+ {% endif %}
+
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
diff --git a/modules/Aggiornamenti/Routes/api.php b/modules/Aggiornamenti/Routes/api.php
new file mode 100644
index 000000000..4a6bccb17
--- /dev/null
+++ b/modules/Aggiornamenti/Routes/api.php
@@ -0,0 +1,18 @@
+get('/aggiornamenti', function (Request $request) {
+ return $request->user();
+});
\ No newline at end of file
diff --git a/modules/Aggiornamenti/Routes/web.php b/modules/Aggiornamenti/Routes/web.php
new file mode 100644
index 000000000..c4c46c63e
--- /dev/null
+++ b/modules/Aggiornamenti/Routes/web.php
@@ -0,0 +1,35 @@
+group(function () {
+ Route::get('', [AggiornamentiController::class, 'index']);
+
+ Route::post('controllo-versione', [AggiornamentiController::class, 'check'])
+ ->name('controllo-versione');
+
+ Route::post('scarica-aggiornamento', [AggiornamentiController::class, 'download'])
+ ->name('scarica-aggiornamento');
+
+ Route::get('checksum', [ControlliAggiuntiviController::class, 'checksum'])
+ ->name('checksum');
+ Route::get('database', [ControlliAggiuntiviController::class, 'database'])
+ ->name('database');
+ Route::get('controlli', [ControlliAggiuntiviController::class, 'controlli'])
+ ->name('controlli');
+ });
diff --git a/modules/Aggiornamenti/Tests/Feature/.gitkeep b/modules/Aggiornamenti/Tests/Feature/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/modules/Aggiornamenti/Tests/Unit/.gitkeep b/modules/Aggiornamenti/Tests/Unit/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/modules/Aggiornamenti/composer.json b/modules/Aggiornamenti/composer.json
new file mode 100644
index 000000000..8a10ecb54
--- /dev/null
+++ b/modules/Aggiornamenti/composer.json
@@ -0,0 +1,24 @@
+{
+ "name": "devcode-it/osm-aggiornamenti-module",
+ "description": "",
+ "authors": [{
+ "name": "DevCode s.n.c.",
+ "email": "info@openstamanager.com"
+ }],
+ "require": {
+ "erusev/parsedown": "^1.7"
+ },
+ "extra": {
+ "laravel": {
+ "providers": [],
+ "aliases": {
+
+ }
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Modules\\Aggiornamenti\\": ""
+ }
+ }
+}
diff --git a/modules/Aggiornamenti/module.json b/modules/Aggiornamenti/module.json
new file mode 100644
index 000000000..f24dea0b8
--- /dev/null
+++ b/modules/Aggiornamenti/module.json
@@ -0,0 +1,13 @@
+{
+ "name": "Aggiornamenti",
+ "alias": "aggiornamenti",
+ "description": "",
+ "keywords": [],
+ "priority": 0,
+ "providers": [
+ "Modules\\Aggiornamenti\\Providers\\AggiornamentiServiceProvider"
+ ],
+ "aliases": {},
+ "files": [],
+ "requires": []
+}
diff --git a/modules/Aggiornamenti/package.json b/modules/Aggiornamenti/package.json
new file mode 100644
index 000000000..4599509fe
--- /dev/null
+++ b/modules/Aggiornamenti/package.json
@@ -0,0 +1,17 @@
+{
+ "private": true,
+ "scripts": {
+ "dev": "npm run development",
+ "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
+ "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
+ "watch-poll": "npm run watch -- --watch-poll",
+ "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
+ "prod": "npm run production",
+ "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
+ },
+ "devDependencies": {
+ "cross-env": "^7.0",
+ "laravel-mix": "^5.0.1",
+ "laravel-mix-merge-manifest": "^0.1.2"
+ }
+}
diff --git a/modules/Aggiornamenti/webpack.mix.js b/modules/Aggiornamenti/webpack.mix.js
new file mode 100644
index 000000000..6d37eedd1
--- /dev/null
+++ b/modules/Aggiornamenti/webpack.mix.js
@@ -0,0 +1,14 @@
+const dotenvExpand = require('dotenv-expand');
+dotenvExpand(require('dotenv').config({ path: '../../.env'/*, debug: true*/}));
+
+const mix = require('laravel-mix');
+require('laravel-mix-merge-manifest');
+
+mix.setPublicPath('../../public').mergeManifest();
+
+mix.js(__dirname + '/Resources/assets/js/app.js', 'js/aggiornamenti.js')
+ .sass( __dirname + '/Resources/assets/sass/app.scss', 'css/aggiornamenti.css');
+
+if (mix.inProduction()) {
+ mix.version();
+}
diff --git a/modules/listini/bulk.php b/modules/listini/bulk.php
deleted file mode 100644
index d2825c5da..000000000
--- a/modules/listini/bulk.php
+++ /dev/null
@@ -1,26 +0,0 @@
-query('UPDATE mg_prezzi_articoli SET sconto_percentuale='.prepare($sconto).' WHERE id='.prepare($id_record));
- }
- flash()->info(tr('Sconti modificati correttamente!'));
- break;
-}
-
-return [
- 'aggiorna-listino' => [
- 'text' => ''.tr('Modifica sconto').' ',
- 'data' => [
- 'title' => tr('Inserisci lo sconto per questi articoli'),
- 'msg' => '{[ "type": "text", "label": "'.tr('Nuovo sconto').' ","icon-after":"%", "name": "sconto" ]}',
- 'button' => tr('Modifica'),
- 'class' => 'btn btn-lg btn-warning',
- 'blank' => false,
- ],
- ],
-];
diff --git a/modules/ordini/add_preventivo.php b/modules/ordini/add_preventivo.php
deleted file mode 100644
index 9b7f28137..000000000
--- a/modules/ordini/add_preventivo.php
+++ /dev/null
@@ -1,85 +0,0 @@
-.
- */
-
-include_once __DIR__.'/../../core.php';
-
-use Modules\Ordini\Ordine;
-use Modules\Preventivi\Preventivo;
-
-$documento_finale = Ordine::find($id_record);
-$dir = $documento_finale->direzione;
-
-$id_documento = get('id_documento');
-if (!empty($id_documento)) {
- $documento = Preventivo::find($id_documento);
-
- $options = [
- 'op' => 'add_documento',
- 'type' => 'preventivo',
- 'button' => tr('Aggiungi'),
- 'documento' => $documento,
- 'documento_finale' => $documento_finale,
- 'tipo_documento_finale' => Ordine::class,
- ];
-
- echo App::load('importa.php', [], $options, true);
-
- return;
-}
-
-$id_anagrafica = $documento_finale->idanagrafica;
-
-echo '
-
-
- {[ "type": "select", "label": "'.tr('Preventivo').'", "name": "id_documento", "ajax-source": "preventivi", "select-options": {"idanagrafica": '.$id_anagrafica.', "stato": "is_fatturabile=1 OR is_completato"} ]}
-
-
-
-
-
-
-
-
- '.tr('Caricamento in corso').'...
-
';
-
-$file = basename(__FILE__);
-echo '
-
-
-';
diff --git a/modules/ordini/bulk.php b/modules/ordini/bulk.php
deleted file mode 100644
index 6643676c2..000000000
--- a/modules/ordini/bulk.php
+++ /dev/null
@@ -1,133 +0,0 @@
-.
- */
-
-include_once __DIR__.'/../../core.php';
-
-use Modules\Ordini\Ordine;
-use Modules\Fatture\Fattura;
-use Modules\Fatture\Stato;
-use Modules\Fatture\Tipo;
-
-$module_fatture = 'Fatture di vendita';
-
-
-// Segmenti
-$id_fatture = Modules::get($module_fatture)['id'];
-if (!isset($_SESSION['module_'.$id_fatture]['id_segment'])) {
- $segments = Modules::getSegments($id_fatture);
- $_SESSION['module_'.$id_fatture]['id_segment'] = isset($segments[0]['id']) ? $segments[0]['id'] : null;
-}
-$id_segment = $_SESSION['module_'.$id_fatture]['id_segment'];
-
-switch (post('op')) {
- case 'crea_fattura':
- $documenti = collect();
- $numero_totale = 0;
- $descrizione_tipo = 'Fattura immediata di vendita';
-
- $tipo_documento = Tipo::where('descrizione', $descrizione_tipo)->first();
-
- $stato_documenti_accodabili = Stato::where('descrizione', 'Bozza')->first();
- $accodare = post('accodare');
-
- $data = date('Y-m-d');
- $id_segment = post('id_segment');
-
- // Lettura righe selezionate
- foreach ($id_records as $id) {
- $documento_import = Ordine::find($id);
- $anagrafica = $documento_import->anagrafica;
- $id_anagrafica = $anagrafica->id;
-
- // Proseguo solo se i documenti scelti sono fatturabili
- $ordine = $dbo->fetchOne('SELECT or_statiordine.descrizione AS stato FROM or_ordini LEFT JOIN or_statiordine ON or_ordini.idstatoordine=or_statiordine.id WHERE or_ordini.id='.prepare($id))['stato'];
- if (!in_array($ordine, ['Fatturato', 'Evaso', 'Bozza', 'In attesa di conferma', 'Annullato'])) {
- $righe = $documento_import->getRighe();
- if (!empty($righe)) {
- ++$numero_totale;
-
- // Ricerca fattura per anagrafica tra le registrate
- $fattura = $documenti->first(function ($item, $key) use ($id_anagrafica) {
- return $item->anagrafica->id == $id_anagrafica;
- });
-
- // Ricerca fattura per anagrafica se l'impostazione di accodamento è selezionata
- if (!empty($accodare) && empty($fattura)) {
- $fattura = Fattura::where('idanagrafica', $id_anagrafica)
- ->where('idstatodocumento', $stato_documenti_accodabili->id)
- ->where('idtipodocumento', $tipo_documento->id)
- ->first();
-
- if (!empty($fattura)) {
- $documenti->push($fattura);
- }
- }
-
- // Creazione fattura per anagrafica
- if (empty($fattura)) {
- $fattura = Fattura::build($anagrafica, $tipo_documento, $data, $id_segment);
- $documenti->push($fattura);
- }
-
- // Inserimento righe
- foreach ($righe as $riga) {
- $qta = $riga->qta_rimanente;
-
- if ($qta > 0) {
- //Fix per idconto righe fattura
- $riga->idconto = $fattura->idconto;
- $copia = $riga->copiaIn($fattura, $qta);
-
- // Aggiornamento seriali dalla riga dell'ordine
- if ($copia->isArticolo()) {
- $copia->serials = $riga->serials;
- }
- }
- }
- }
- }
- }
-
- if ($numero_totale > 0) {
- flash()->info(tr('_NUM_ ordini fatturati!', [
- '_NUM_' => $numero_totale,
- ]));
- } else {
- flash()->warning(tr('Nessun ordine fatturato!'));
- }
- break;
-}
-if ($module['name'] == 'Ordini cliente') {
-$operations['crea_fattura'] = [
- 'text' => ' '.tr('Fattura _TYPE_', ['_TYPE_' => strtolower($module['name'])]),
- 'data' => [
- 'title' => tr('Fatturare i _TYPE_ selezionati?', ['_TYPE_' => strtolower($module['name'])]),
- 'msg' => '{[ "type": "checkbox", "label": "'.tr('Aggiungere alle _TYPE_ non ancora emesse?', ['_TYPE_' => strtolower($module_fatture)]).'", "placeholder": "'.tr('Aggiungere alle _TYPE_ nello stato bozza?', ['_TYPE_' => strtolower($module_fatture)]).' ", "name": "accodare" ]}
- {[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "values": "query=SELECT id, name AS descrizione FROM zz_segments WHERE id_module=\''.$id_fatture.'\' AND is_fiscale = 1 ORDER BY name", "value": "'.$id_segment.'" ]}',
- 'button' => tr('Procedi'),
- 'class' => 'btn btn-lg btn-warning',
- 'blank' => false,
- ],
- ];
-}
-if($operations){
- return $operations;
-} else {
- return;
-}
\ No newline at end of file
diff --git a/modules/tipi_documento/actions.php b/modules/tipi_documento/actions.php
deleted file mode 100644
index 59a708bea..000000000
--- a/modules/tipi_documento/actions.php
+++ /dev/null
@@ -1,115 +0,0 @@
-.
- */
-
-include_once __DIR__.'/../../core.php';
-
-switch (filter('op')) {
- case 'update':
- $descrizione = filter('descrizione');
- $dir = filter('dir');
- $codice_tipo_documento_fe = filter('codice_tipo_documento_fe');
-
- if (isset($descrizione) && isset($dir) && isset($codice_tipo_documento_fe)) {
- if ($dbo->fetchNum('SELECT * FROM `co_tipidocumento` WHERE `dir`='.prepare($dir).' AND `codice_tipo_documento_fe`='.prepare($codice_tipo_documento_fe).' AND `id`!='.prepare($id_record)) == 0) {
-
- $predefined = post('predefined');
- if (!empty($predefined)) {
- $dbo->query('UPDATE co_tipidocumento SET predefined = 0 WHERE dir = '.prepare($dir));
- }
-
- $dbo->update('co_tipidocumento', [
- 'descrizione' => $descrizione,
- 'dir' => $dir,
- 'codice_tipo_documento_fe' => $codice_tipo_documento_fe,
- 'help' => filter('help'),
- 'predefined' => $predefined,
- 'enabled' => post('enabled'),
- ], ['id' => $id_record]);
-
- flash()->info(tr('Salvataggio completato!'));
- } else {
- flash()->error(tr("E' già presente una tipologia di _TYPE_ con la stessa combinazione di direzione e tipo documento FE", [
- '_TYPE_' => 'tipo documento',
- ]));
- }
- } else {
- flash()->error(tr('Ci sono stati alcuni errori durante il salvataggio'));
- }
-
- break;
-
- case 'add':
- $descrizione = filter('descrizione');
- $dir = filter('dir');
- $codice_tipo_documento_fe = filter('codice_tipo_documento_fe');
-
- if (isset($descrizione) && isset($dir) && isset($codice_tipo_documento_fe)) {
- if ($dbo->fetchNum('SELECT * FROM `co_tipidocumento` WHERE `dir`='.prepare($dir).' AND `codice_tipo_documento_fe`='.prepare($codice_tipo_documento_fe)) == 0) {
- $dbo->insert('co_tipidocumento', [
- 'descrizione' => $descrizione,
- 'dir' => $dir,
- 'codice_tipo_documento_fe' => $codice_tipo_documento_fe,
- ]);
- $id_record = $dbo->lastInsertedID();
-
- if (isAjaxRequest()) {
- echo json_encode(['id' => $id_record, 'text' => $descrizione]);
- }
-
- flash()->info(tr('Aggiunta nuova tipologia di _TYPE_', [
- '_TYPE_' => 'tipo documento',
- ]));
- } else {
- flash()->error(tr("E' già presente una tipologia di _TYPE_ con la stessa combinazione di direzione e tipo documento FE", [
- '_TYPE_' => 'tipo documento',
- ]));
- }
- } else {
- flash()->error(tr('Ci sono stati alcuni errori durante il salvataggio'));
- }
-
- break;
-
- case 'delete':
-
- $documenti = $dbo->fetchNum('SELECT id FROM co_documenti WHERE idtipodocumento ='.prepare($id_record));
-
- if (isset($id_record) && empty($documenti)) {
- $dbo->query('DELETE FROM `co_tipidocumento` WHERE `id`='.prepare($id_record));
- flash()->info(tr('Tipologia di _TYPE_ eliminata con successo.', [
- '_TYPE_' => 'tipo documento',
- ]));
- } else {
-
- $dbo->update('co_tipidocumento', [
- 'deleted_at' => date(),
- 'predefined' => 0,
- 'enabled' => 0,
- ], ['id' => $id_record]);
-
- flash()->info(tr('Tipologia di _TYPE_ eliminata con successo.', [
- '_TYPE_' => 'tipo documento',
- ]));
-
-
- //flash()->error(tr('Sono presenti dei documenti collegati a questo tipo documento'));
- }
-
- break;
-}
\ No newline at end of file
diff --git a/modules/tipi_documento/add.php b/modules/tipi_documento/add.php
deleted file mode 100644
index 5dd4e2052..000000000
--- a/modules/tipi_documento/add.php
+++ /dev/null
@@ -1,46 +0,0 @@
-.
- */
-
-include_once __DIR__.'/../../core.php';
-
-?>
\ No newline at end of file
diff --git a/modules/tipi_documento/ajax/select.php b/modules/tipi_documento/ajax/select.php
deleted file mode 100644
index 9946a3e69..000000000
--- a/modules/tipi_documento/ajax/select.php
+++ /dev/null
@@ -1,37 +0,0 @@
-.
- */
-
-include_once __DIR__.'/../../../core.php';
-
-switch ($resource) {
- case 'tipi_documento':
- $query = 'SELECT id, descrizione FROM co_tipidocumento |where| ORDER BY descrizione ASC';
-
- $where[] = 'co_tipidocumento.enabled = 1';
- $where[] = 'dir='.$superselect['dir'];
-
- foreach ($elements as $element) {
- $filter[] = 'id='.prepare($element);
- }
- if (!empty($search)) {
- $search_fields[] = 'descrizione LIKE '.prepare('%'.$search.'%');
- }
-
- break;
-}
diff --git a/modules/tipi_documento/edit.php b/modules/tipi_documento/edit.php
deleted file mode 100644
index ab5d4a437..000000000
--- a/modules/tipi_documento/edit.php
+++ /dev/null
@@ -1,78 +0,0 @@
-.
- */
-
-include_once __DIR__.'/../../core.php';
-
-?>
-
-fetchNum('SELECT id FROM co_documenti WHERE idtipodocumento='.prepare($id_record));
-
-if (!empty($numero_documenti)) {
- echo '
-
- '.tr('Ci sono _NUM_ documenti collegati', [
- '_NUM_' => $numero_documenti,
- ]).'.
-
';
-}
-?>
-
-
-
-
diff --git a/modules/tipi_documento/init.php b/modules/tipi_documento/init.php
deleted file mode 100644
index e68f56050..000000000
--- a/modules/tipi_documento/init.php
+++ /dev/null
@@ -1,24 +0,0 @@
-.
- */
-
-include_once __DIR__.'/../../core.php';
-
-if (isset($id_record)) {
- $record = $dbo->fetchOne('SELECT * FROM `co_tipidocumento` WHERE id='.prepare($id_record));
-}
diff --git a/modules_statuses.json b/modules_statuses.json
new file mode 100644
index 000000000..d3f8f809b
--- /dev/null
+++ b/modules_statuses.json
@@ -0,0 +1,3 @@
+{
+ "Aggiornamenti": true
+}
diff --git a/resources/views/components/inputs/checkbox.blade.php b/resources/views/components/inputs/checkbox.blade.php
index bea415e32..fe6e79748 100644
--- a/resources/views/components/inputs/checkbox.blade.php
+++ b/resources/views/components/inputs/checkbox.blade.php
@@ -8,7 +8,7 @@
'value' => $value,
'required' => $required,
'data-parsley-errors-container' => '#'.$unique_id.'-errors'
- ]) }} onchange="$(this).parent().find(\'[type = hidden]\').val(+this.checked).trigger(\'change\')"/>
+ ]) }} onchange="$(this).parent().find('[type = hidden]').val(+this.checked).trigger('change')"/>