From 7e44ddc785498db409d7763befc26ed6f271c5b4 Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Sat, 14 Apr 2018 15:08:14 +0200 Subject: [PATCH] feat(market): fdroid market Signed-off-by: Thierry Bugier --- front/fdroidapplication.form.php | 77 +++ front/fdroidapplication.php | 54 ++ front/fdroidmarket.form.php | 100 ++++ front/fdroidmarket.php | 54 ++ hook.php | 34 +- inc/entityconfig.class.php | 11 + inc/fdroidapplication.class.php | 380 ++++++++++++++ inc/fdroidmarket.class.php | 207 ++++++++ inc/file.class.php | 9 +- inc/fleet.class.php | 11 +- inc/menu.class.php | 30 +- inc/menuinterface.class.php | 41 ++ inc/package.class.php | 14 + inc/profile.class.php | 17 +- ...{installer.class.php => install.class.php} | 213 ++++---- install/mysql/plugin_flyvemdm_empty.sql | 37 ++ install/update_to_develop.php | 122 +++++ install/upgrade/update_to_dev.php | 491 ------------------ install/upgrade_to_2.0.php | 490 +++++++++++++++++ setup.php | 3 + tests/src/Flyvemdm/Tests/CommonTestCase.php | 50 ++ tests/suite-install/Config.php | 13 +- tests/suite-integration/ProfileRight.php | 2 + tests/suite-uninstall/Config.php | 1 - .../PluginFlyvemdmFdroidApplication.php | 290 +++++++++++ tests/suite-unit/PluginFlyvemdmPackage.php | 10 +- tpl/agentComputerInfo.html.twig | 2 +- tpl/fdroidapplication.html.twig | 31 ++ tpl/fdroidmarket.html.twig | 6 + 29 files changed, 2177 insertions(+), 623 deletions(-) create mode 100644 front/fdroidapplication.form.php create mode 100644 front/fdroidapplication.php create mode 100644 front/fdroidmarket.form.php create mode 100644 front/fdroidmarket.php create mode 100644 inc/fdroidapplication.class.php create mode 100644 inc/fdroidmarket.class.php create mode 100644 inc/menuinterface.class.php rename install/{installer.class.php => install.class.php} (90%) create mode 100644 install/update_to_develop.php delete mode 100644 install/upgrade/update_to_dev.php create mode 100644 install/upgrade_to_2.0.php create mode 100644 tests/suite-unit/PluginFlyvemdmFdroidApplication.php create mode 100644 tpl/fdroidapplication.html.twig create mode 100644 tpl/fdroidmarket.html.twig diff --git a/front/fdroidapplication.form.php b/front/fdroidapplication.form.php new file mode 100644 index 00000000..457e6edf --- /dev/null +++ b/front/fdroidapplication.form.php @@ -0,0 +1,77 @@ +isActivated('flyvemdm')) { + Html::displayNotFoundError(); +} + +Session::checkRight('flyvemdm:flyvemdm', PluginFlyvemdmProfile::RIGHT_FLYVEMDM_USE); + +if (!isset($_GET['id'])) { + $_GET['id'] = ''; +} + +if (!isset($_GET['withtemplate'])) { + $_GET['withtemplate'] = ''; +} + +$fdroidApplication = new PluginFlyvemdmFDroidApplication(); +if (isset($_POST['import'])) { + unset($_POST['_skip_checks']); + $fdroidApplication->update(['id' => $_POST['id'], 'import_status' => 'to_import']); + Html::back(); +} else { + $fdroidApplication->check($_GET['id'], READ); + Html::header( + PluginFlyvemdmFDroidApplication::getTypeName(Session::getPluralNumber()), + '', + 'admin', + PluginFlyvemdmMenu::class, + 'fdroid application' + ); + + $menu = new PluginFlyvemdmMenu(); + $menu->displayMenu('mini'); + + $fdroidApplication->display([ + 'id' => $_GET['id'], + 'withtemplate' => $_GET['withtemplate'] + ]); + + // Footer + if (strstr($_SERVER['PHP_SELF'], 'popup')) { + Html::popFooter(); + } else { + Html::footer(); + } +} diff --git a/front/fdroidapplication.php b/front/fdroidapplication.php new file mode 100644 index 00000000..8e972122 --- /dev/null +++ b/front/fdroidapplication.php @@ -0,0 +1,54 @@ +isActivated('flyvemdm')) { + Html::displayNotFoundError(); +} + +Session::checkRight("flyvemdm:flyvemdm", PluginFlyvemdmProfile::RIGHT_FLYVEMDM_USE); +Session::checkRight("flyvemdm:fdroidapplication", READ); + +Html::header( + PluginFlyvemdmFDroidApplication::getTypeName(Session::getPluralNumber()), + '', + 'admin', + PluginFlyvemdmMenu::class, + 'fdroid application' +); + +$menu = new PluginFlyvemdmMenu(); +$menu->displayMenu('mini'); + +Search::show(PluginFlyvemdmFDroidApplication::class); + +Html::footer(); diff --git a/front/fdroidmarket.form.php b/front/fdroidmarket.form.php new file mode 100644 index 00000000..b101694d --- /dev/null +++ b/front/fdroidmarket.form.php @@ -0,0 +1,100 @@ +isActivated('flyvemdm')) { + Html::displayNotFoundError(); +} + +Session::checkRight('flyvemdm:flyvemdm', PluginFlyvemdmProfile::RIGHT_FLYVEMDM_USE); + +if (!isset($_GET['id'])) { + $_GET['id'] = ''; +} + +if (!isset($_GET['withtemplate'])) { + $_GET['withtemplate'] = ''; +} + +$market = new PluginFlyvemdmFDroidMarket(); +if (isset($_POST["add"])) { + $market->check(-1, CREATE, $_POST); + if ($newID = $market->add($_POST)) { + if ($_SESSION['glpibackcreated']) { + Html::redirect($market->getFormURL() . "?id=" . $newID); + } + } + Html::back(); +} else if (isset($_POST["update"])) { + $market->check($_POST['id'], UPDATE); + $market->update($_POST); + Html::back(); +} else if (isset($_POST["purge"])) { + $market->check($_POST['id'], PURGE); + $market->delete($_POST, 1); + $market->redirectToList(); +} else if (isset($_POST['refresh'])) { + $fdroidMarket = new PluginFlyvemdmFDroidMarket(); + $fdroidMarket->getFromDB((int) $_POST['id']); + $volume = $fdroidMarket->updateRepository(); + Html::back(); +} else { + if (isset($_GET['search'])) { + $criterias = array_intersect_key($_GET, ['criteria' => null, 'metacriteria' => null]); + $_SESSION['glpisearch'][PluginFlyvemdmFDroidApplication::class] = $criterias; + } else if (isset($_GET['reset'])) { + unset($_SESSION['glpisearch'][PluginFlyvemdmFDroidApplication::class]); + } + $market->check($_GET['id'], READ); + Html::header( + PluginFlyvemdmFDroidApplication::getTypeName(Session::getPluralNumber()), + '', + 'admin', + PluginFlyvemdmMenu::class, + 'fdroid market' + ); + + $menu = new PluginFlyvemdmMenu(); + $menu->displayMenu('mini'); + + $market->display([ + 'id' => $_GET['id'], + 'withtemplate' => $_GET['withtemplate'] + ]); + + // Footer + if (strstr($_SERVER['PHP_SELF'], 'popup')) { + Html::popFooter(); + } else { + Html::footer(); + } +} diff --git a/front/fdroidmarket.php b/front/fdroidmarket.php new file mode 100644 index 00000000..13435763 --- /dev/null +++ b/front/fdroidmarket.php @@ -0,0 +1,54 @@ +isActivated('flyvemdm')) { + Html::displayNotFoundError(); +} + +Session::checkRight('flyvemdm:flyvemdm', PluginFlyvemdmProfile::RIGHT_FLYVEMDM_USE); +Session::checkRight('flyvemdm:fdroidmarket', READ); + +Html::header( + PluginFlyvemdmFDroidMarket::getTypeName(Session::getPluralNumber()), + '', + 'admin', + PluginFlyvemdmMenu::class, + 'fdroid market'); + +$menu = new PluginFlyvemdmMenu(); +$menu->displayMenu('mini'); + +Search::show(PluginFlyvemdmFDroidMarket::class); + +Html::footer(); + diff --git a/hook.php b/hook.php index 0ad828eb..bda7d3c9 100644 --- a/hook.php +++ b/hook.php @@ -33,12 +33,15 @@ * Entry point for installation process */ function plugin_flyvemdm_install() { - global $DB; - - require_once(PLUGIN_FLYVEMDM_ROOT . "/install/installer.class.php"); - $installer = new PluginFlyvemdmInstaller(); - - return $installer->install(); + $version = plugin_version_flyvemdm(); + $migration = new Migration($version['version']); + require_once(PLUGIN_FLYVEMDM_ROOT . "/install/install.class.php"); + spl_autoload_register([PluginFlyvemdmInstall::class, 'autoload']); + $install = new PluginFlyvemdmInstall(); + if (!$install->isPluginInstalled()) { + return $install->install($migration); + } + return $install->upgrade($migration); } /** @@ -46,10 +49,10 @@ function plugin_flyvemdm_install() { * @return boolean True if success */ function plugin_flyvemdm_uninstall() { - require_once(PLUGIN_FLYVEMDM_ROOT . "/install/installer.class.php"); - $installer = new PluginFlyvemdmInstaller(); + require_once(PLUGIN_FLYVEMDM_ROOT . "/install/install.class.php"); + $install = new PluginFlyvemdmInstall(); - return $installer->uninstall(); + return $install->uninstall(); } /** @@ -129,13 +132,16 @@ function plugin_flyvemdm_addDefaultSelect($itemtype) { * @param string $itemtype Itemtype * @return string */ -function plugin_Flyvemdm_addDefaultJoin($itemtype) { +function plugin_Flyvemdm_addDefaultJoin($itemtype, $ref_table, &$already_link_tables) { switch ($itemtype) { case PluginFlyvemdmGeolocation::class: - return PluginFlyvemdmGeolocation::addDefaultJoin(); + return PluginFlyvemdmGeolocation::addDefaultJoin($ref_table, $already_link_tables); case PluginFlyvemdmAgent::class: - return PluginFlyvemdmAgent::addDefaultJoin(); + return PluginFlyvemdmAgent::addDefaultJoin($ref_table, $already_link_tables); + + case PluginFlyvemdmFDroidApplication::class: + return PluginFlyvemdmFDroidApplication::addDefaultJoin($ref_table, $already_link_tables); } } @@ -151,6 +157,10 @@ function plugin_Flyvemdm_addDefaultWhere($itemtype) { case PluginFlyvemdmAgent::class: return PluginFlyvemdmAgent::addDefaultWhere(); + + case PluginFlyvemdmFDroidApplication::class: { + return PluginFlyvemdmFDroidApplication::addDefaultWhere(); + } } } diff --git a/inc/entityconfig.class.php b/inc/entityconfig.class.php index 78a1088f..7ab6075a 100644 --- a/inc/entityconfig.class.php +++ b/inc/entityconfig.class.php @@ -86,6 +86,17 @@ static function canUpdate() { } } + function getRights($interface = 'central') { + $values = [ + READ => __('Read'), + self::RIGHT_FLYVEMDM_DEVICE_COUNT_LIMIT => __('Write device limit'), + self::RIGHT_FLYVEMDM_APP_DOWNLOAD_URL => __('Set agent download URL'), + self::RIGHT_FLYVEMDM_INVITATION_TOKEN_LIFE => __('Set invitation tiken lifetime'), + ]; + + return $values; + } + /** * Actions done after the getFromDB method */ diff --git a/inc/fdroidapplication.class.php b/inc/fdroidapplication.class.php new file mode 100644 index 00000000..e74353dd --- /dev/null +++ b/inc/fdroidapplication.class.php @@ -0,0 +1,380 @@ + __('No import', 'flyvemdm'), + 'to_import' => __('To import', 'flyvemdm'), + 'imported' => __('Imported', 'flyvemdm'), + ]; + } + + /** + * Return the picture file for the menu + * @return string + */ + public static function getMenuPicture() { + return ''; + } + + /** + * Returns the name of the type + * @param integer $count + * @return string + */ + static function getTypeName($count = 0) { + return _n('F-Droid application', 'F-Droid applications', $count); + } + + /** + * @see CommonGLPI::getTabNameForItem() + * + * @since version 9.1 + * @param CommonGLPI $item + * @param integer $withtemplate + * @return array|string + */ + public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) { + if (static::canView()) { + switch ($item->getType()) { + case PluginFlyvemdmFDroidMarket::class: + if (!$withtemplate) { + $nb = 0; + $fleetId = $item->getID(); + $pluralNumber = Session::getPluralNumber(); + if ($_SESSION['glpishow_count_on_tabs']) { + $DbUtil = new DbUtils(); + $nb = $DbUtil->countElementsInTable(static::getTable(), ['plugin_flyvemdm_fdroidmarkets_id' => $fleetId]); + } + return self::createTabEntry(self::getTypeName($pluralNumber), $nb); + } + break; + } + } + + return ''; + } + + static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) { + switch (get_class($item)) { + case PluginFlyvemdmFDroidMarket::class: + self::showForFDroidMarket($item); + return true; + break; + } + + return false; + } + + public function getAdditionalLinks() { + return []; + } + + function getRights($interface = 'central') { + $values = [ + READ => __('Read'), + UPDATE => __('Update'), + ]; + + return $values; + } + + /** + * get Cron description parameter for this class + * @param $name string name of the task + * @return array of string + **/ + static function cronInfo($name) { + switch ($name) { + case 'DownloadApplications' : + return ['description' => __('download applications from the market')]; + } + } + + /** + * Maitnains a local list of all apps available in the repository + * This algorithm is limited and cannot handle a huge quantity of applications + * @param CronTask $cronTask + * @return number + */ + public static function cronDownloadApplications(CronTask $cronTask) { + global $DB; + + $cronStatus = 0; + + $cronTask->log('Download applications to import from F-Droid'); + + $fDroidApplication = new PluginFlyvemdmFDroidApplication(); + $request = [ + 'FROM' => PluginFlyvemdmFDroidApplication::getTable(), + 'WHERE' => ['import_status' => 'to_import'] + ]; + $package = new PluginFlyvemdmPackage(); + $market = new PluginFlyvemdmFDroidMarket(); + foreach ($DB->request($request) as $row) { + if ($package->getFromDBByCrit(['name' => $row['name']])) { + continue; + } + $market->getFromDB($row[$market::getForeignKeyField()]); + $baseUrl = dirname($market->getField('url')); + + $file = GLPI_TMP_DIR . "/" . $row['filename']; + file_put_contents($file, file_get_contents("$baseUrl/" . $row['filename'])); + $_POST['_file'][0] = $row['filename']; + if ($package->add($row)) { + $fDroidApplication->update([ + 'id' => $row['id'], + 'import_status' => 'imported', + ]); + } else { + Toolbox::logInFile('php-errors', 'Failed to import an application from a F-Droid like market'); + } + $cronStatus = 1; + } + + return $cronStatus; + } + + /** + * Imports an application in the database, or updates an existing one + * @param array $input + * @return integer|false ID of the imported item or false on error + */ + public static function import($input) { + $marketFk = PluginFlyvemdmFDroidMarket::getForeignKeyField(); + if (!isset($input['name']) || !isset($input[$marketFk])) { + return false; + } + + $application = new self(); + $application->getFromDBByCrit([ + 'name' => $input['name'], + $marketFk => $input[$marketFk], + ]); + if ($application->isNewItem()) { + return $application->add($input); + } + + $input['id'] = $application->getID(); + $input['is_available'] = '1'; + if ($application->update($input) === false) { + return false; + } + return $application->getID(); + } + + public function prepareInputForUpdate($input) { + if (isset($input['_skip_checks'])) { + return $input; + } + + if (!isset($input['import_status'])) { + $input['import_status'] = 'no_import'; + } + + return $input; + } + + public function showForm($ID, $options = []) { + $options['canUpdate'] = (!$this->isNewID($ID)) && ($this->canUpdate() > 0); + $this->initForm($ID, $options); + $this->showFormHeader($options); + $fields = $this->fields; + + $importStatuses = static::getEnumImportStatus(); + $fields['import_status'] = $importStatuses[$fields['import_status']]; + + $data = [ + 'withTemplate' => (isset($options['withtemplate']) && $options['withtemplate'] ? '*' : ''), + 'isNewID' => $this->isNewID($ID), + 'canUpdate' => $options['canUpdate'], + 'fdroidapplication' => $fields, + ]; + + $twig = plugin_flyvemdm_getTemplateEngine(); + echo $twig->render('fdroidapplication.html.twig', $data); + + if (PluginFlyvemdmPackage::canCreate()) { + $options['addbuttons'] = [ + 'import' => __('Import the package', 'flyvemdm'), + ]; + } + $this->showFormButtons($options); + } + + public static function showForFDroidMarket(CommonDBTM $item, $withtemplate = '') { + global $CFG_GLPI, $DB; + + if (!$item->canView()) { + return false; + } + + $searchParams = []; + if (isset($_SESSION['glpisearch'][PluginFlyvemdmFDroidApplication::class])) { + $searchParams = $_SESSION['glpisearch'][PluginFlyvemdmFDroidApplication::class]; + } + $searchParams = Search::manageParams(PluginFlyvemdmApplication::class, $searchParams); + $searchParams['showbookmark'] = false; + $searchParams['target'] = PluginFlyvemdmFDroidMarket::getFormUrlWithID($item->getID()); + $searchParams['addhidden'] = [ + 'id' => $item->getID(), + PluginFlyvemdmFDroidMarket::getForeignKeyField() => $item->getID(), + ]; + Search::showGenericSearch(PluginFlyvemdmFDroidApplication::class, $searchParams); + + Search::showList(PluginFlyvemdmFDroidApplication::class, $searchParams); + } + + public function getSearchOptionsNew() { + return $this->rawSearchOptions(); + } + + public function rawSearchOptions() { + if (method_exists('CommonDBTM', 'rawSearchOptions')) { + $tab = parent::rawSearchOptions(); + } else { + $tab = parent::getSearchOptionsNew(); + } + + $tab[] = [ + 'id' => '2', + 'table' => $this->getTable(), + 'field' => 'id', + 'name' => __('ID'), + 'massiveaction' => false, + 'datatype' => 'number' + ]; + + $tab[] = [ + 'id' => '3', + 'table' => $this->getTable(), + 'field' => 'alias', + 'name' => __('Alias', 'flyvemdm'), + 'massiveaction' => false, + 'datatype' => 'string' + ]; + + $tab[] = [ + 'id' => '4', + 'table' => $this->getTable(), + 'field' => 'version', + 'name' => __('Version', 'flyvemdm'), + 'massiveaction' => false, + 'datatype' => 'string' + ]; + + $tab[] = [ + 'id' => '6', + 'table' => $this->getTable(), + 'field' => 'filesize', + 'name' => __('Size'), + 'massiveaction' => false, + 'datatype' => 'number' + ]; + + $tab[] = [ + 'id' => '7', + 'table' => $this->getTable(), + 'field' => 'import_status', + 'name' => __('Import status', 'flyvemdm'), + 'searchtype' => ['equals', 'notequals'], + 'massiveaction' => false, + 'datatype' => 'specific' + ]; + + $tab[] = [ + 'id' => '8', + 'table' => $this::getTable(), + 'field' => PluginFlyvemdmFDroidMarket::getForeignKeyField(), + 'name' => __('FDroid market', 'flyvemdm'), + 'massiveaction' => false, + ]; + + return $tab; + } + + public static function addDefaultJoin($ref_table, $already_link_tables) { + $join = ''; + + $table = PluginFlyvemdmFDroidMarket::getTable(); + $fkTable = PluginFlyvemdmFDroidMarket::getForeignKeyField(); + $join = "LEFT JOIN `$table` ON `$table`.`id`=`$ref_table`.`$fkTable` "; + + return $join; + } + + public static function addDefaultWhere() { + $where = ''; + + $fkFDroidMarket = PluginFlyvemdmFDroidMarket::getForeignKeyField(); + if (isset($_GET['id'])) { + $fDfroidMarketId = (int) $_GET['id']; + $where = " `$fkFDroidMarket` = '$fDfroidMarketId'"; + } + return $where; + } + + public static function getSpecificValueToSelect($field, $name = '', $values = '', array $options = []) { + if (!is_array($values)) { + $values = [$field => $values]; + } + switch ($field) { + case 'import_status': + $elements = self::getEnumImportStatus(); + $output = Dropdown::showFromArray( + $name, + $elements, + [ + 'display' => false, + 'value' => $values[$field] + ] + ); + return $output; + break; + } + return parent::getSpecificValueToSelect($field, $name, $values, $options); + } +} diff --git a/inc/fdroidmarket.class.php b/inc/fdroidmarket.class.php new file mode 100644 index 00000000..824f7dc4 --- /dev/null +++ b/inc/fdroidmarket.class.php @@ -0,0 +1,207 @@ +addDefaultFormTab($tab); + if (!$this->isNewItem()) { + $this->addStandardTab(PluginFlyvemdmFDroidApplication::class, $tab, $options); + } + $this->addStandardTab(Notepad::class, $tab, $options); + $this->addStandardTab(Log::class, $tab, $options); + + return $tab; + } + + /** + * get Cron description parameter for this class + * @param $name string name of the task + * @return array of string + */ + static function cronInfo($name) { + switch ($name) { + case 'UpdateRepositories' : + return ['description' => __('Updates the list of applications')]; + } + } + + /** + * Maitnains a local list of all apps available in the repository + * This algorithm is limited and cannot handle a huge quantity of applications + * @param CronTask $cronTask + * @return integer + */ + public static function cronUpdateRepositories(CronTask $cronTask) { + global $DB; + + $cronStatus = 0; + $cronTask->log('Update the list of applications available from F-Droid like repositories'); + + $request = [ + 'FROM' => static::getTable(), + ]; + foreach ($DB->request($request) as $row) { + $fdroidMarket = new static(); + $fdroidMarket->getFromResultSet($row); + $volume = $fdroidMarket->updateRepository(); + $cronTask->addVolume($volume); + $cronStatus = 1; + } + + return $cronStatus; + } + + /** + * Updates the list of applications from a F Droid like repository + * @return integer + */ + private function updateRepository() { + global $DB; + + $volume = 0; + $xml = file_get_contents($this->fields['url']); + $fdroid = simplexml_load_string($xml); + unset($xml); + + if (isset($fdroid->application)) { + $marketFk = $this::getForeignKeyField(); + $fdroidApplication = new PluginFlyvemdmFDroidApplication(); + $DB->query("UPDATE `" . PluginFlyvemdmFDroidApplication::getTable() . "` SET `is_available` = '0' WHERE `$marketFk`=" . $this->getID()); + foreach ($fdroid->application as $application) { + $input = [ + 'name' => Toolbox::addslashes_deep($application->name), + 'package_name' => Toolbox::addslashes_deep($application->id), + 'entities_id' => $this->fields['entities_id'], + 'is_recursive' => $this->fields['is_recursive'], + $marketFk => $this->getID(), + 'alias' => Toolbox::addslashes_deep($application->name), + 'version' => Toolbox::addslashes_deep($application->package[0]->version), + 'version_code' => Toolbox::addslashes_deep($application->package[0]->versioncode), + 'filesize' => Toolbox::addslashes_deep($application->package[0]->size), + 'filename' => Toolbox::addslashes_deep($application->package[0]->apkname), + 'desc' => Toolbox::addslashes_deep($application->desc), + ]; + if (isCommandline()) { + // TRANS: %1$s is the name of the application being updated %2$s is the name of the repository + echo sprintf(__('Updating application %1$s in repository %2$s', 'flyvemdm'), $input['name'], $this->getField('name')) . PHP_EOL; + } + PluginFlyvemdmFDroidApplication::import($input); + } + + // Delete applications vanished from the repo + $criteria = [$marketFk => $this->getID(), 'is_available' => '0']; + if (isCommandline()) { + $dbUtils = new DbUtils(); + $deleteCount = $dbUtils->countElementsInTable(PluginFlyvemdmFDroidApplication::getTable(), $criteria); + } + $fdroidApplication->deleteByCriteria($criteria); + $volume = count($fdroid->application) + $deleteCount; + } + + return $volume; + } + + public function showForm($ID, $options = []) { + $this->initForm($ID, $options); + $this->showFormHeader($options); + $fields = $this->fields; + + $data = [ + 'withTemplate' => (isset($options['withtemplate']) && $options['withtemplate'] ? '*' : ''), + 'isNewID' => $this->isNewID($ID), + 'fdroidmarket' => $fields, + 'importButton' => Html::submit(_x('button', 'Import'), ['name' => 'import']), + 'canImport' => PluginFlyvemdmPackage::canCreate(), + ]; + + $twig = plugin_flyvemdm_getTemplateEngine(); + echo $twig->render('fdroidmarket.html.twig', $data); + + if (!$this->isNewID($ID)) { + $options['addbuttons'] = [ + 'refresh' => _x('button', 'Import'), + ]; + } + $this->showFormButtons($options); + } + + public function getSearchOptionsNew() { + $tab = parent::getSearchOptionsNew(); + + $tab[] = [ + 'id' => '2', + 'table' => $this->getTable(), + 'field' => 'id', + 'name' => __('ID'), + 'massiveaction' => false, + 'datatype' => 'number' + ]; + + return $tab; + + } +} \ No newline at end of file diff --git a/inc/file.class.php b/inc/file.class.php index 89eeaf46..dc031db7 100644 --- a/inc/file.class.php +++ b/inc/file.class.php @@ -70,6 +70,10 @@ public static function getMenuPicture() { return 'fa-file'; } + public function getAdditionalLinks() { + return []; + } + public function addNeededInfoToInput($input) { $input['entities_id'] = $_SESSION['glpiactive_entity']; @@ -253,9 +257,6 @@ public function pre_deleteItem() { ]); } - /** - * Actions done after the getFromFB method - */ public function post_getFromDB() { // Check the user can view this itemtype and can view this item if ($this->canView() && $this->canViewItem()) { @@ -304,7 +305,6 @@ public function showForm($ID, array $options = []) { $this->initForm($ID, $options); $this->showFormHeader($options); - $twig = plugin_flyvemdm_getTemplateEngine(); $fields = $this->fields; $fields['filesize'] = ''; if (!$this->isNewID($ID)) { @@ -319,6 +319,7 @@ public function showForm($ID, array $options = []) { 'upload' => Html::file(['name' => 'file', 'display' => false]), 'comment' => $fields['comment'], ]; + $twig = plugin_flyvemdm_getTemplateEngine(); echo $twig->render('file.html.twig', $data); $this->showFormButtons($options); diff --git a/inc/fleet.class.php b/inc/fleet.class.php index 4d866087..fbe34f49 100644 --- a/inc/fleet.class.php +++ b/inc/fleet.class.php @@ -84,6 +84,10 @@ public static function getMenuPicture() { return 'fa-group'; } + public function getAdditionalLinks() { + return []; + } + /** * @see CommonGLPI::defineTabs() */ @@ -122,7 +126,6 @@ public function showForm($ID, array $options = []) { $this->initForm($ID, $options); $this->showFormHeader($options); - $twig = plugin_flyvemdm_getTemplateEngine(); $fields = $this->fields; $objectName = $DbUtil->autoName($this->fields["name"], "name", (isset($options['withtemplate']) && $options['withtemplate'] == 2), @@ -131,10 +134,12 @@ public function showForm($ID, array $options = []) { ['value' => $objectName, 'display' => false]); $fields['is_default'] = $fields['is_default'] ? __('No') : __('Yes'); $data = [ - 'withTemplate' => (isset($options['withtemplate']) && $options['withtemplate'] ? "*" : ""), - 'fleet' => $fields, + 'withTemplate' => (isset($options['withtemplate']) && $options['withtemplate'] ? "*" : ""), + 'isNewID' => $this->isNewID($ID), + 'fleet' => $fields, ]; + $twig = plugin_flyvemdm_getTemplateEngine(); echo $twig->render('fleet.html.twig', $data); $this->showFormButtons($options); diff --git a/inc/menu.class.php b/inc/menu.class.php index b7ab5d1a..6e076520 100644 --- a/inc/menu.class.php +++ b/inc/menu.class.php @@ -112,6 +112,12 @@ public function displayMenu($type = 'dashboard') { 'pic' => PluginFlyvemdmFile::getMenuPicture(), ], ], + __('Markets', 'flyvemdm') => [ + PluginFlyvemdmFDroidMarket::getTypeName($pluralNumber) => [ + 'link' => Toolbox::getItemTypeSearchURL(PluginFlyvemdmFDroidMarket::class), + 'pic' => PluginFlyvemdmFDroidMarket::getMenuPicture(), + ], + ], __('Configuration', 'flyvemdm') => [ __('General') => [ 'link' => Toolbox::getItemTypeFormURL(PluginFlyvemdmConfig::class) . '?forcetab='.PluginFlyvemdmConfig::class.'$2', @@ -134,17 +140,20 @@ public function displayMenu($type = 'dashboard') { */ public static function getMenuContent() { $front_flyvemdm = "/plugins/flyvemdm/front"; + $pics_flyvemdm = "/plugins/flyvemdm/pics"; $menu = []; $menu['title'] = self::getMenuName(); $menu['page'] = "$front_flyvemdm/menu.php"; $itemtypes = [ - PluginFlyvemdmAgent::class => 'agent', - PluginFlyvemdmPackage::class => 'package', - PluginFlyvemdmFile::class => 'file', - PluginFlyvemdmFleet::class => 'fleet', - PluginFlyvemdmInvitation::class => 'invitation', + PluginFlyvemdmAgent::class => 'agent', + PluginFlyvemdmPackage::class => 'package', + PluginFlyvemdmFile::class => 'file', + PluginFlyvemdmFleet::class => 'fleet', + PluginFlyvemdmInvitation::class => 'invitation', + PluginFlyvemdmFDroidMarket::class => 'fdroid market', + PluginFlyvemdmFDroidApplication::class => 'fdroid application', ]; $pluralNumber = Session::getPluralNumber(); @@ -155,6 +164,17 @@ public static function getMenuContent() { if ($itemtype::canCreate()) { $menu['options'][$option]['links']['add'] = $itemtype::getFormURL(false); } + + // MenuInterface not yet used + // Issue: cannot use font awesome because GLPI escapes the picture + // if the picture string does not starts with "getAdditionalLinks(); + foreach ($links as $link) { + $image = $link['pic']; + $menu['options'][$option]['links'][$image] = $link['link']; + } + } } return $menu; } diff --git a/inc/menuinterface.class.php b/inc/menuinterface.class.php new file mode 100644 index 00000000..17d403bd --- /dev/null +++ b/inc/menuinterface.class.php @@ -0,0 +1,41 @@ +deleteByCriteria([ 'itemtype' => $this->getType(), 'items_id' => $this->getID(), ]); + + // Reset import status in the linked F-Droid store + $fDroidApplication = new PluginFlyvemdmFDroidApplication(); + if ($fDroidApplication->getFromDBByCrit(['name' => $this->fields['name']])) { + $fDroidApplication->update([ + 'id' => $fDroidApplication->getID(), + 'import_status' => 'no_import', + ]); + } } /** diff --git a/inc/profile.class.php b/inc/profile.class.php index e3edc3eb..41decf0e 100644 --- a/inc/profile.class.php +++ b/inc/profile.class.php @@ -54,9 +54,12 @@ public static function purgeProfiles(Profile $prof) { $plugprof->deleteByCriteria(['profiles_id' => $prof->getField("id")]); } - /** - * @see Profile::showForm() - */ + function getRights($interface = 'central') { + $values = [self::RIGHT_FLYVEMDM_USE => __('Use Flyve MDM')]; + + return $values; + } + public function showForm($ID, $options = []) { if (!Profile::canView()) { return false; @@ -92,9 +95,6 @@ public function showForm($ID, $options = []) { $this->showLegend(); } - /** - * @see Profile::getTabNameForItem() - */ public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) { if ($item->getType() == 'Profile') { return __('Flyve MDM', 'flyvemdm'); @@ -102,9 +102,6 @@ public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) { return ''; } - /** - * @see Profile::displayTabContentForItem - */ public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) { if ($item->getType() == 'Profile') { $profile = new self(); @@ -161,6 +158,8 @@ public function getAssetsRights() { PluginFlyvemdmPolicy::class, PluginFlyvemdmPolicyCategory::class, PluginFlyvemdmWellknownpath::class, + PluginFlyvemdmFDroidMarket::class, + PluginFlyvemdmFDroidApplication::class, ]; $rights = []; diff --git a/install/installer.class.php b/install/install.class.php similarity index 90% rename from install/installer.class.php rename to install/install.class.php index 5544b88d..0440c933 100644 --- a/install/installer.class.php +++ b/install/install.class.php @@ -39,36 +39,12 @@ * @since 0.1.0 * */ -class PluginFlyvemdmInstaller { +class PluginFlyvemdmInstall { const DEFAULT_CIPHERS_LIST = 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK'; const BACKEND_MQTT_USER = 'flyvemdm-backend'; - // Order of this array is mandatory due tu dependancies on install and uninstall - protected static $itemtypesToInstall = [ - 'mqttuser', - // Must be before config because config creates a mqtt user for the plugin - 'mqttacl', - // Must be before config because config creates a mqtt ACL for the plugin - 'config', - 'entityconfig', - 'mqttlog', - 'agent', - 'package', - 'file', - 'fleet', - 'profile', - 'notificationtargetinvitation', - 'geolocation', - 'policy', - 'policycategory', - 'fleet_policy', - 'wellknownpath', - 'invitation', - 'invitationlog', - ]; - protected static $currentVersion = null; protected $migration; @@ -78,7 +54,7 @@ class PluginFlyvemdmInstaller { * @param string $classname * @return bool */ - public function autoload($classname) { + public static function autoload($classname) { // useful only for installer GLPI autoloader already handles inc/ folder $filename = dirname(__DIR__) . '/inc/' . strtolower(str_replace('PluginFlyvemdm', '', $classname)) . '.class.php'; @@ -95,52 +71,34 @@ public function autoload($classname) { * @return boolean true (assume success, needs enhancement) * */ - public function install() { + public function install(Migration $migration) { global $DB; + $this->migration = $migration; spl_autoload_register([__CLASS__, 'autoload']); - $this->migration = new Migration(PLUGIN_FLYVEMDM_VERSION); - $this->migration->setVersion(PLUGIN_FLYVEMDM_VERSION); - - // adding DB model from sql file - // TODO : migrate in-code DB model setup here - if (self::getCurrentVersion() == '') { - // Setup DB model - $dbFile = PLUGIN_FLYVEMDM_ROOT . "/install/mysql/plugin_flyvemdm_empty.sql"; - if (!$DB->runFile($dbFile)) { - $this->migration->displayWarning("Error creating tables : " . $DB->error(), true); - return false; - } + $this->installSchema(); + $this->createInitialConfig(); + $this->migration->executeMigration(); + $this->installUpgradeCommonTasks(); - $this->createInitialConfig(); - } else { - if (PluginFlyvemdmCommon::endsWith(PLUGIN_FLYVEMDM_VERSION, - "-dev") || (version_compare(self::getCurrentVersion(), - PLUGIN_FLYVEMDM_VERSION) != 0)) { - // TODO : Upgrade (or downgrade) - $this->upgrade(self::getCurrentVersion()); - } - } + return true; + } - $this->migration->executeMigration(); + protected function installSchema() { + global $DB; + + $this->migration->displayMessage("create database schema"); + + $dbFile = __DIR__ . '/mysql/plugin_flyvemdm_empty.sql'; + if (!$DB->runFile($dbFile)) { + $this->migration->displayWarning("Error creating tables : " . $DB->error(), true); + return false; + } if (version_compare(GLPI_VERSION, '9.3.0') >= 0) { $this->migrateToInnodb(); } - $this->createDirectories(); - $this->createFirstAccess(); - $this->createGuestProfileAccess(); - $this->createAgentProfileAccess(); - $this->createDefaultFleet(); - $this->createPolicies(); - $this->createNotificationTargetInvitation(); - $this->createJobs(); - $this->createRootEntityConfig(); - $this->createDisplayPreferences(); - - Config::setConfigurationValues('flyvemdm', ['version' => PLUGIN_FLYVEMDM_VERSION]); - return true; } @@ -198,25 +156,45 @@ public function createDirectories() { } // Create cache directory for the template engine - PluginFlyvemdmCommon::recursiveRmdir(FLYVEMDM_TEMPLATE_CACHE_PATH); - if (!mkdir(FLYVEMDM_TEMPLATE_CACHE_PATH, 0770, true)) { - $this->migration->displayWarning("Cannot create " . FLYVEMDM_TEMPLATE_CACHE_PATH . " directory"); + if (!file_exists(FLYVEMDM_TEMPLATE_CACHE_PATH)) { + if (!mkdir(FLYVEMDM_TEMPLATE_CACHE_PATH, 0770, true)) { + $this->migration->displayWarning("Cannot create " . FLYVEMDM_TEMPLATE_CACHE_PATH . " directory"); + } } } /** * @return null|string */ - public static function getCurrentVersion() { - if (self::$currentVersion === null) { - $config = \Config::getConfigurationValues('flyvemdm', ['version']); - if (!isset($config['version'])) { - self::$currentVersion = ''; - } else { - self::$currentVersion = $config['version']; + public function getSchemaVersion() { + if ($this->isPluginInstalled()) { + $config = Config::getConfigurationValues('flyvemdm', ['schema_version']); + if (!isset($config['schema_version'])) { + return '0.0'; } + return $config['schema_version']; } - return self::$currentVersion; + + return null; + } + + /** + * is the plugin already installed ? + * + * @return boolean + */ + public function isPluginInstalled() { + global $DB; + + // Check tables of the plugin between 1.1 and 2.0 releases + $result = $DB->query("SHOW TABLES LIKE 'glpi_plugin_flyvemdm_%'"); + if ($result) { + if ($DB->numrows($result) > 0) { + return true; + } + } + + return false; } protected function createRootEntityConfig() { @@ -257,6 +235,8 @@ protected function createFirstAccess() { PluginFlyvemdmInvitation::$rightname => ALLSTANDARDRIGHT, PluginFlyvemdmInvitationLog::$rightname => READ, PluginFlyvemdmTaskstatus::$rightname => READ, + PluginFlyvemdmFDroidApplication::$rightname => READ | UPDATE | READNOTE | UPDATENOTE, + PluginFlyvemdmFDroidMarket::$rightname => ALLSTANDARDRIGHT | READNOTE | UPDATENOTE, ]; $profileRight->updateProfileRights($_SESSION['glpiactiveprofile']['id'], $newRights); @@ -495,22 +475,53 @@ public function createNotificationTargetInvitation() { /** * Upgrade the plugin to the current code version * - * @param string $fromVersion + * @param string version to upgrade from */ - protected function upgrade($fromVersion) { - switch ($fromVersion) { - case '2.0.0': - // Example : upgrade to version 3.0.0 - // $this->upgradeOneStep('3.0.0'); - case '3.0.0': - // Example : upgrade to version 4.0.0 - // $this->upgradeOneStep('4.0.0'); - - default: + public function upgrade(Migration $migration) { + spl_autoload_register([__CLASS__, 'autoload']); + + $this->migration = $migration; + $fromSchemaVersion = $this->getSchemaVersion(); + + switch ($fromSchemaVersion) { + case '0.0': + // Upgrade to 2.0 + $this->upgradeOneStep('2.0'); + + case '2.0': + // Example : upgrade to version 2.1 + // $this->upgradeOneStep('2.1'); + + case '3.0': + // Example : upgrade to version 3.0 + // $this->upgradeOneStep('3.0'); + } - if (PluginFlyvemdmCommon::endsWith(PLUGIN_FLYVEMDM_VERSION, "-dev")) { - $this->upgradeOneStep('dev'); + if (!PLUGIN_FLYVEMDM_IS_OFFICIAL_RELEASE) { + $this->upgradeOneStep('develop'); } + $this->installUpgradeCommonTasks(); + return true; + } + + private function installUpgradeCommonTasks() { + $this->createDirectories(); + $this->createFirstAccess(); + $this->createGuestProfileAccess(); + $this->createAgentProfileAccess(); + $this->createDefaultFleet(); + $this->createPolicies(); + $this->createNotificationTargetInvitation(); + $this->createJobs(); + $this->createRootEntityConfig(); + $this->createDisplayPreferences(); + + Config::setConfigurationValues( + 'flyvemdm', [ + 'version' => PLUGIN_FLYVEMDM_VERSION, + 'schema_version' => PLUGIN_FLYVEMDM_SCHEMA_VERSION, + ] + ); } /** @@ -519,21 +530,19 @@ protected function upgrade($fromVersion) { * @param string $toVersion */ protected function upgradeOneStep($toVersion) { - ini_set("max_execution_time", "0"); ini_set("memory_limit", "-1"); $suffix = str_replace('.', '_', $toVersion); - $includeFile = __DIR__ . "/upgrade/update_to_$suffix.php"; + $includeFile = __DIR__ . "/update_to_$suffix.php"; if (is_readable($includeFile) && is_file($includeFile)) { include_once $includeFile; - $updateFunction = "plugin_flyvemdm_update_to_$suffix"; - if (function_exists($updateFunction)) { - $this->migration->addNewMessageArea("Upgrade to $toVersion"); - $updateFunction($this->migration); - $this->migration->executeMigration(); - $this->migration->displayMessage('Done'); - } + $updateClass = "PluginFlyvemdmUpgradeTo$suffix"; + $this->migration->addNewMessageArea("Upgrade to $toVersion"); + $upgradeStep = new $updateClass(); + $upgradeStep->upgrade($this->migration); + $this->migration->executeMigration(); + $this->migration->displayMessage('Done'); } } @@ -543,6 +552,18 @@ protected function createJobs() { 'comment' => __('Parse uploaded applications to collect metadata', 'flyvemdm'), 'mode' => CronTask::MODE_EXTERNAL, ]); + + CronTask::Register(PluginFlyvemdmFDroidMarket::class, 'UpdateRepositories', DAY_TIMESTAMP, + [ + 'comment' => __('Update the list of applications available from F-Droid like repositories', 'flyvemdm'), + 'mode' => CronTask::MODE_EXTERNAL + ]); + + CronTask::Register(PluginFlyvemdmFDroidApplication::class, 'DownloadApplications', DAY_TIMESTAMP, + [ + 'comment' => __('Imports applications for deployment', 'flyvemdm'), + 'mode' => CronTask::MODE_EXTERNAL + ]); } /** @@ -812,6 +833,8 @@ protected function deleteTables() { PluginFlyvemdmPolicyCategory::getTable(), PluginFlyvemdmWellknownpath::getTable(), PluginFlyvemdmTaskstatus::getTable(), + PluginFlyvemdmFDroidApplication::getTable(), + PluginFlyvemdmFDroidMarket::getTable(), ]; foreach ($tables as $table) { diff --git a/install/mysql/plugin_flyvemdm_empty.sql b/install/mysql/plugin_flyvemdm_empty.sql index 4afebbb3..e778cc3a 100644 --- a/install/mysql/plugin_flyvemdm_empty.sql +++ b/install/mysql/plugin_flyvemdm_empty.sql @@ -259,3 +259,40 @@ CREATE TABLE `glpi_plugin_flyvemdm_taskstatuses` ( INDEX `plugin_flyvemdm_agents_id` (`plugin_flyvemdm_agents_id`), INDEX `plugin_flyvemdm_tasks_id` (`plugin_flyvemdm_tasks_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- Export de la structure de table glpi-flyvemdm. glpi_plugin_flyvemdm_fdroidapplications +DROP TABLE IF EXISTS `glpi_plugin_flyvemdm_fdroidapplications`; +CREATE TABLE `glpi_plugin_flyvemdm_fdroidapplications` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL DEFAULT '', + `package_name` varchar(255) NOT NULL DEFAULT '', + `entities_id` int(11) NOT NULL DEFAULT '0', + `is_recursive` tinyint(1) NOT NULL DEFAULT '0', + `plugin_flyvemdm_fdroidmarkets_id` int(11) NOT NULL DEFAULT '0', + `plugin_flyvemdm_packages_id` int(11) NOT NULL DEFAULT '0', + `alias` varchar(255) NOT NULL DEFAULT '', + `version` varchar(255) NOT NULL DEFAULT '', + `version_code` varchar(255) NOT NULL DEFAULT '', + `date_mod` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `desc` text NOT NULL, + `filename` varchar(255) NOT NULL DEFAULT '', + `filesize` int(11) NOT NULL DEFAULT '0', + `import_status` enum('no_import','to_import','imported') NOT NULL DEFAULT 'no_import', + `is_available` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Does the application exists in the store ?', + PRIMARY KEY (`id`), + KEY `entities_id` (`entities_id`), + KEY `plugin_flyvemdm_fdroidmarkets_id` (`plugin_flyvemdm_fdroidmarkets_id`), + KEY `plugin_flyvemdm_packages_id` (`plugin_flyvemdm_packages_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- Export de la structure de table glpi-flyvemdm. glpi_plugin_flyvemdm_fdroidmarkets +DROP TABLE IF EXISTS `glpi_plugin_flyvemdm_fdroidmarkets`; +CREATE TABLE `glpi_plugin_flyvemdm_fdroidmarkets` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL DEFAULT '', + `entities_id` int(11) NOT NULL DEFAULT '0', + `is_recursive` tinyint(1) NOT NULL DEFAULT '0', + `url` varchar(255) NOT NULL DEFAULT '' COMMENT 'URL to index.xml of the market', + PRIMARY KEY (`id`), + KEY `entities_id` (`entities_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; diff --git a/install/update_to_develop.php b/install/update_to_develop.php new file mode 100644 index 00000000..dc735ebf --- /dev/null +++ b/install/update_to_develop.php @@ -0,0 +1,122 @@ +setVersion(PLUGIN_FLYVEMDM_VERSION); + + $profileRight = new ProfileRight(); + // Merge new rights into current profile + $profiles_id = $_SESSION['glpiactiveprofile']['id']; + $currentRights = ProfileRight::getProfileRights($profiles_id); + $newRights = array_merge($currentRights, [ + PluginFlyvemdmFDroidMarket::$rightname => ALLSTANDARDRIGHT | READNOTE | UPDATENOTE, + PluginFlyvemdmFDroidApplication::$rightname => READ | UPDATE | READNOTE | UPDATENOTE, + ]); + $profileRight->updateProfileRights($profiles_id, $newRights); + + // Create table for F-Droid application + $query = "CREATE TABLE IF NOT EXISTS `glpi_plugin_flyvemdm_fdroidapplications` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL DEFAULT '', + `package_name` varchar(255) NOT NULL DEFAULT '', + `entities_id` int(11) NOT NULL DEFAULT '0', + `is_recursive` tinyint(1) NOT NULL DEFAULT '0', + `plugin_flyvemdm_fdroidmarkets_id` int(11) NOT NULL DEFAULT '0', + `plugin_flyvemdm_packages_id` int(11) NOT NULL DEFAULT '0', + `alias` varchar(255) NOT NULL DEFAULT '', + `version` varchar(255) NOT NULL DEFAULT '', + `version_code` varchar(255) NOT NULL DEFAULT '', + `date_mod` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `desc` text NOT NULL, + `filename` varchar(255) NOT NULL DEFAULT '', + `filesize` int(11) NOT NULL DEFAULT '0', + `import_status` enum('no_import','to_import','imported') NOT NULL DEFAULT 'no_import', + `is_available` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Does the applciation e xists in the store ?', + PRIMARY KEY (`id`), + KEY `entities_id` (`entities_id`), + KEY `plugin_flyvemdm_fdroidmarkets_id` (`plugin_flyvemdm_fdroidmarkets_id`), + KEY `plugin_flyvemdm_packages_id` (`plugin_flyvemdm_packages_id`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + "; + $DB->query($query) or plugin_flyvemdm_upgrade_error($migration); + + // Update enum if needed + $table = 'glpi_plugin_flyvemdm_fdroidapplications'; + $enumImportStatus = PluginFlyvemdmFDroidApplication::getEnumImportStatus(); + $currentEnumImportStatus = PluginFlyvemdmCommon::getEnumValues($table, 'import_status'); + if (count($currentEnumImportStatus) > 0) { + // The field exists + if (count($currentEnumImportStatus) != count($enumImportStatus)) { + reset($enumImportStatus); + $defaultValue = key($enumImportStatus); + $enumImportStatus = "'" . implode("', '", array_keys($enumImportStatus)) . "'"; + $query = "ALTER TABLE `$table` + CHANGE COLUMN `import_status` `import_status` + ENUM($enumImportStatus) + NOT NULL DEFAULT '$defaultValue'"; + $DB->query($query) or plugin_flyvemdm_upgrade_error($migration); + } + } else { + // The field does not exists + reset($enumImportStatus); + $defaultValue = key($enumImportStatus); + $enumImportStatus = "'" . implode("', '", array_keys($enumImportStatus)) . "'"; + $query = "ALTER TABLE `$table` + ADD COLUMN `import_status` + ENUM($enumImportStatus) + NOT NULL DEFAULT '$defaultValue'"; + $DB->query($query) or plugin_flyvemdm_upgrade_error($migration); + } + + // Create table for F-Droid + $query = "CREATE TABLE IF NOT EXISTS `glpi_plugin_flyvemdm_fdroidmarkets` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL DEFAULT '', + `entities_id` int(11) NOT NULL DEFAULT '0', + `is_recursive` tinyint(1) NOT NULL DEFAULT '0', + `url` varchar(255) NOT NULL DEFAULT '' COMMENT 'URL to index.xml of the market', + PRIMARY KEY (`id`), + KEY `entities_id` (`entities_id`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + "; + $DB->query($query) or plugin_flyvemdm_upgrade_error($migration); + } +} \ No newline at end of file diff --git a/install/upgrade/update_to_dev.php b/install/upgrade/update_to_dev.php deleted file mode 100644 index ad05392d..00000000 --- a/install/upgrade/update_to_dev.php +++ /dev/null @@ -1,491 +0,0 @@ -setVersion(PLUGIN_FLYVEMDM_VERSION); - - $profileRight = new ProfileRight(); - - // Merge new rights into current profile - $profiles_id = $_SESSION['glpiactiveprofile']['id']; - $currentRights = ProfileRight::getProfileRights($profiles_id); - $newRights = array_merge($currentRights, [ - PluginFlyvemdmInvitation::$rightname => ALLSTANDARDRIGHT , - PluginFlyvemdmInvitationlog::$rightname => READ, - PluginFlyvemdmGeolocation::$rightname => ALLSTANDARDRIGHT | READNOTE | UPDATENOTE, - ]); - $profileRight->updateProfileRights($profiles_id, $newRights); - - $migration->setContext('flyvemdm'); - $migration->addConfig([ - 'default_agent_url' => PLUGIN_FLYVEMDM_AGENT_DOWNLOAD_URL, - 'show_wizard' => '0', - 'debug_save_inventory' => '0', - 'android_bugcollecctor_url' => '', - 'android_bugcollector_login' => '', - 'android_bugcollector_passwd' => '', - 'invitation_deeplink' => PLUGIN_FLYVEMDM_DEEPLINK, - ]); - - $config = Config::getConfigurationValues('flyvemdm', ['mqtt_broker_tls']); - if (isset($config['mqtt_broker_tls'])) { - if ($config['mqtt_broker_tls'] !== '0') { - $config['mqtt_broker_tls_port'] = $config['mqtt_broker_port']; - $config['mqtt_broker_port'] = '1883'; - } else { - $config['mqtt_broker_tls_port'] = '8883'; - } - // Split TLS setting for client in one hand and backend in the other hand - $config['mqtt_tls_for_clients'] = $config['mqtt_broker_tls']; - $config['mqtt_tls_for_backend'] = $config['mqtt_broker_tls']; - Config::setConfigurationValues('flyvemdm', $config); - Config::deleteConfigurationValues('flyvemdm', ['mqtt_broker_tls']); - } - - // remove download base URL setting - Config::deleteConfigurationValues('flyvemdm', ['deploy_base_url']); - - // update Entity config table - $table = 'glpi_plugin_flyvemdm_entityconfigs'; - $migration->addField($table, 'support_name', 'text', ['after' => 'agent_token_life']); - $migration->addField($table, 'support_phone', 'string', ['after' => 'support_name']); - $migration->addField($table, 'support_website', 'string', ['after' => 'support_phone']); - $migration->addField($table, 'support_email', 'string', ['after' => 'support_website']); - $migration->addField($table, 'support_address', 'text', ['after' => 'support_email']); - $migration->addKey($table, 'entities_id', 'entities_id'); - - // update Agent table - $table = 'glpi_plugin_flyvemdm_agents'; - if (!$DB->fieldExists($table, 'enroll_status')) { - $query = "ALTER TABLE `$table` - ADD COLUMN `enroll_status` ENUM('enrolled', 'unenrolling', 'unenrolled') NOT NULL DEFAULT 'enrolled' AFTER `lock`"; - $DB->query($query) or plugin_flyvemdm_upgrade_error($migration); - } - $migration->addField($table, 'version', 'string', ['after' => 'name']); - $migration->addField($table, 'users_id', 'integer', ['after' => 'computers_id']); - $migration->addField($table, 'is_online', 'integer', ['after' => 'last_contact']); - $migration->addField($table, 'has_system_permission', 'bool', ['after' => 'mdm_type']); - $migration->addKey($table, 'computers_id', 'computers_id'); - $migration->addKey($table, 'users_id', 'users_id'); - $migration->addKey($table, 'entities_id', 'entities_id'); - $migration->changeField($table, 'wipe', 'wipe', 'bool'); - $migration->changeField($table, 'lock', 'lock', 'bool'); - - $enumMdmType = PluginFlyvemdmAgent::getEnumMdmType(); - $currentEnumMdmType = PluginFlyvemdmCommon::getEnumValues($table, 'mdm_type'); - if (count($currentEnumMdmType) > 0) { - // The field exists - if (count($currentEnumMdmType) != count($enumMdmType)) { - reset($enumMdmType); - $defaultValue = key($enumMdmType); - $enumMdmType = "'" . implode("', '", array_keys($enumMdmType)) . "'"; - $query = "ALTER TABLE `$table` - CHANGE COLUMN `mdm_type` `mdm_type` - ENUM($enumMdmType) - NOT NULL DEFAULT '$defaultValue'"; - $DB->query($query) or plugin_flyvemdm_upgrade_error($migration); - } - } else { - // The field does not exists - reset($enumMdmType); - $defaultValue = key($enumMdmType); - $enumMdmType = "'" . implode("', '", array_keys($enumMdmType)) . "'"; - $query = "ALTER TABLE `$table` - ADD COLUMN `mdm_type` - ENUM($enumMdmType) - NOT NULL DEFAULT '$defaultValue'"; - $DB->query($query) or plugin_flyvemdm_upgrade_error($migration); - } - - // Create task status table - $table = 'glpi_plugin_flyvemdm_taskstatuses'; - $query = "CREATE TABLE IF NOT EXISTS `$table` ( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `name` VARCHAR(255) NOT NULL DEFAULT '', - `date_creation` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', - `date_mod` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', - `plugin_flyvemdm_agents_id` INT(11) NOT NULL DEFAULT '0', - `plugin_flyvemdm_tasks_id` INT(11) NOT NULL DEFAULT '0', - `status` VARCHAR(255) NOT NULL DEFAULT '', - PRIMARY KEY (`id`), - KEY `plugin_flyvemdm_agents_id` (`plugin_flyvemdm_agents_id`), - KEY `plugin_flyvemdm_tasks_id` (`plugin_flyvemdm_tasks_id`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;"; - $DB->query($query) or plugin_flyvemdm_upgrade_error($migration); - - $migration->addKey($table, 'plugin_flyvemdm_agents_id', 'plugin_flyvemdm_agents_id'); - $migration->addKey($table, 'plugin_flyvemdm_tasks_id', 'plugin_flyvemdm_tasks_id'); - - // update Policy table - $table = 'glpi_plugin_flyvemdm_policies'; - $migration->addField($table, 'recommended_value', 'string', ['after' => 'default_value']); - $migration->addField($table, 'is_android_system', 'bool', ['after' => 'recommended_value']); - $migration->addField($table, 'android_min_version', 'string', ['after' => 'is_android_system', 'value' => '0']); - $migration->addField($table, 'android_max_version', 'string', ['after' => 'android_min_version', 'value' => '0']); - $migration->addField($table, 'apple_min_version', 'string', ['after' => 'android_max_version', 'value' => '0']); - $migration->addField($table, 'apple_max_version', 'string', ['after' => 'apple_min_version', 'value' => '0']); - $migration->addKey($table, 'group', 'group'); - $migration->addKey($table, 'plugin_flyvemdm_policycategories_id', 'plugin_flyvemdm_policycategories_id'); - $migration->dropField($table, 'is_android_policy'); - $migration->dropField($table, 'is_apple_policy'); - - // Rename and update fleet_policy into task - $table = 'glpi_plugin_flyvemdm_tasks'; - $migration->renameTable('glpi_plugin_flyvemdm_fleets_policies', $table); - $migration->changeField($table, 'plugin_flyvemdm_fleets_policies_id', 'plugin_flyvemdm_tasks_id', - 'integer'); - $migration->addKey($table, 'plugin_flyvemdm_policies_id', 'plugin_flyvemdm_policies_id'); - - // Upgrade schema to apply policies on fleets and agents - if (!$DB->fieldExists($table, 'items_id_applied')) { - $migration->changeField($table, 'plugin_flyvemdm_fleets_id', 'items_id_applied', 'integer'); - $migration->dropKey($table, 'plugin_flyvemdm_fleets_id'); - $migration->addField($table, 'itemtype_applied', 'string', ['after' => 'id']); - $migration->addKey($table, ['itemtype_applied', 'items_id_applied'], 'FK_applied'); - // All tasks already created were applied on fleets - $migration->addPostQuery("UPDATE `$table` SET `itemtype_applied` = 'PluginFlyvemdmFleet'"); - $migration->executeMigration(); - } - - $table = 'glpi_plugin_flyvemdm_policies'; - $policies = [ - 'disableFmRadio', - 'disableVoiceMail', - 'disableCallAutoAnswer', - 'disableVoiceDictation', - 'disableUsbOnTheGo', - 'resetPassword', - 'inventoryFrequency', - 'disableSmsMms', - 'disableStreamVoiceCall', - 'disableCreateVpnProfiles', - ]; - $tasksTable = 'glpi_plugin_flyvemdm_tasks'; - $fleetTable = 'glpi_plugin_flyvemdm_fleets'; - $agentsTable = 'glpi_plugin_flyvemdm_agents'; - $request = [ - 'FIELDS' => [ - $table => ['symbol'], - $tasksTable => ['id', 'itemtype_applied', 'items_id_applied'], - $fleetTable => ['entities_id'], - ], - 'FROM' => $table, - 'INNER JOIN' => [ - $tasksTable => [ - 'FKEY' => [ - $tasksTable => 'plugin_flyvemdm_policies_id', - $table => 'id', - ], - ], - ], - 'LEFT JOIN' => [ - $fleetTable => [ - 'itemtype_applied' => 'PluginFlyvemdmFleet', - 'FKEY' => [ - $tasksTable => 'items_id_applied', - $fleetTable => 'id', - ], - ], - $agentsTable => [ - 'itemtype_applied' => 'PluginFlyvemdmAgent', - 'FKEY' => [ - $tasksTable => 'items_id_applied', - $agentsTable => 'id', - ], - ], - ], - 'WHERE' => [ - 'symbol' => $policies, - ], - ]; - $result = $DB->request($request); - if (count($result) > 0) { - $mqttClient = PluginFlyvemdmMqttclient::getInstance(); - foreach ($result as $data) { - switch ($data['itemtype_applied']) { - case PluginFlyvemdmFleet::class: - $type = 'fleet'; - $entityId = $data['entities_id']; - break; - - case PluginFlyvemdmAgent::class: - $agent = new PluginFlyvemdmAgent(); - $agent->getFromDB($data['items_id_applied']); - $type = 'agent'; - $entityId = $agent->getEntityID(); - break; - - default: - $type = ''; - } - if ($type === '') { - continue; - } - $topic = implode('/', [ - '/', - $entityId, - $type, - $data['items_id_applied'], - 'Policy', - $data['symbol'], - 'Task', - $data['id'] - ]); - $mqttClient->publish($topic, null, 0, 1); - } - } - $policiesStr = implode("','", $policies); - $migration->addPostQuery("DELETE FROM `$table` WHERE `symbol` IN ('" . $policiesStr . "')"); - - // update Applications table - $table = 'glpi_plugin_flyvemdm_packages'; - $migration->addField($table, 'parse_status', "enum('pending', 'parsed', 'failed') NOT NULL DEFAULT 'pending'", - ['after' => 'dl_filename', 'default' => 'pending']); - $migration->addfield($table, 'plugin_orion_tasks_id', 'integer', ['after' => 'dl_filename']); - $migration->changeField($table, 'name', 'package_name', 'string'); - $migration->migrationOneTable($table); - $migration->dropField($table, 'filesize'); - $migration->addField($table, 'name', 'string', ['after' => 'id']); - $migration->addKey($table, 'entities_id', 'entities_id'); - $migration->addPostQuery("UPDATE `$table` SET `parse_status` = 'parsed'"); - $migration->addPostQuery("UPDATE `$table` SET `name` = `package_name`"); - - $result = $DB->request(['FROM' => $table, 'LIMIT' => '1']); - if ($result->count() > 0) { - $result->rewind(); - $row = $result->current(); - if (strpos($row['filename'], 'flyvemdm/package/') !== 0) { - // If there is at least one package and the path does starts with the new prefix, then update all the table - $migration->addPostQuery("UPDATE `$table` SET `filename` = CONCAT('flyvemdm/package/', `filename`)"); - } - } - - $table = 'glpi_plugin_flyvemdm_files'; - $migration->addKey($table, 'entities_id', 'entities_id'); - $migration->addField($table, 'comment', 'text'); - - // Add display preferences for PluginFlyvemdmFile - $query = "SELECT * FROM `glpi_displaypreferences` - WHERE `itemtype` = 'PluginFlyvemdmFile' - AND `users_id`='0'"; - $result=$DB->query($query); - if ($DB->numrows($result) == '0') { - $query = "INSERT INTO `glpi_displaypreferences` (`id`, `itemtype`, `num`, `rank`, `users_id`) - VALUES (NULL, 'PluginFlyvemdmFile', '1', '1', '0'), - (NULL, 'PluginFlyvemdmFile', '4', '2', '0');"; - $DB->query($query); - } - - $table = 'glpi_plugin_flyvemdm_fleets'; - $migration->addField($table, 'is_recursive', 'bool'); - $migration->addKey($table, 'entities_id', 'entities_id'); - - $table = 'glpi_plugin_flyvemdm_geolocations'; - $migration->addKey($table, 'computers_id', 'computers_id'); - - $table = 'glpi_plugin_flyvemdm_mqttacls'; - $migration->addKey($table, 'plugin_flyvemdm_mqttusers_id', 'plugin_flyvemdm_mqttusers_id'); - - $table = 'glpi_plugin_flyvemdm_policycategories'; - $migration->addKey($table, 'plugin_flyvemdm_policycategories_id', 'plugin_flyvemdm_policycategories_id'); - - // Create invitation log table - $table = 'glpi_plugin_flyvemdm_invitationlogs'; - $query = "CREATE TABLE IF NOT EXISTS `$table` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `plugin_flyvemdm_invitations_id` int(11) NOT NULL DEFAULT '0', - `date_creation` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', - `event` varchar(255) NOT NULL DEFAULT '', - PRIMARY KEY (`id`), - INDEX `plugin_flyvemdm_invitations_id` (`plugin_flyvemdm_invitations_id`), - INDEX `date_creation` (`date_creation`) - ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;"; - $DB->query($query) or plugin_flyvemdm_upgrade_error($migration); - $migration->addKey($table, 'plugin_flyvemdm_invitations_id', 'plugin_flyvemdm_invitations_id'); - - $table = 'glpi_plugin_flyvemdm_invitations'; - if (!$DB->fieldExists($table, 'name')) { - $invitationName = _n('Invitation', 'Invitations', 1, 'flyvemdm'); - $migration->addField($table, 'name', 'string', ['after' => 'id']); - $migration->addPostQuery("UPDATE `$table` SET `name` = '$invitationName'"); - } - $migration->addKey($table, 'users_id', 'users_id'); - $migration->addKey($table, 'entities_id', 'entities_id'); - $migration->addKey($table, 'documents_id', 'documents_id'); - - // drop Mqtt Update queue - $cronTask = new CronTask(); - $cronTask->deleteByCriteria(['itemtype' => 'PluginFlyvemdmMqttupdatequeue']); - $table = 'glpi_plugin_flyvemdm_mqttupdatequeues'; - $migration->dropTable($table); - - // Fix PascalCase symbols - $query = "UPDATE `glpi_plugin_flyvemdm_policies` - SET `symbol` = 'maximumFailedPasswordsForWipe' - WHERE `symbol`='MaximumFailedPasswordsForWipe'"; - $DB->query($query); - $query = "UPDATE `glpi_plugin_flyvemdm_policies` - SET `symbol` = 'maximumTimeToLock' - WHERE `symbol`='MaximumTimeToLock'"; - $DB->query($query); - - // change MQTT topics tree layout : remove leading slash - $mqttClient = PluginFlyvemdmMqttclient::getInstance(); - $request = [ - 'FIELDS' => [ - 'glpi_plugin_flyvemdm_agents' => ['entities_id'], - 'glpi_computers' => ['serial'], - ], - 'FROM' => 'glpi_plugin_flyvemdm_agents', - 'INNER JOIN' => [ - 'glpi_computers' => ['FKEY' => [ - 'glpi_plugin_flyvemdm_agents' => 'computers_id', - 'glpi_computers' => 'id' - ]] - ], - 'WHERE' => ['lock' => ['<>' => '0']] - ]; - $mqttMessage = ['lock' => 'now']; - $mqttMessage = json_encode($mqttMessage, JSON_UNESCAPED_SLASHES); - foreach ($DB->request($request) as $row) { - $topic = implode('/', [ - $row['entities_id'], - 'agent', - $row['serial'], - 'Command', - 'Lock', - ]); - $mqttClient->publish($topic, $mqttMessage, 0, 1); - $mqttClient->publish('/' . $topic, null, 0, 1); - } - - // re-use previous request array - $request['WHERE'] = ['wipe' => ['<>' => '0']]; - $mqttMessage = ['wipe' => 'now']; - $mqttMessage = json_encode($mqttMessage, JSON_UNESCAPED_SLASHES); - foreach ($DB->request($request) as $row) { - $topic = implode('/', [ - $row['entities_id'], - 'agent', - $row['serial'], - 'Command', - 'Wipe', - ]); - $mqttClient->publish($topic, $mqttMessage, 0, 1); - $mqttClient->publish('/' . $topic, null, 0, 1); - } - - // re-use previous request array - $request['WHERE'] = ['enroll_status' => ['=' => 'unenrolling']]; - $mqttMessage = ['unenroll' => 'now']; - $mqttMessage = json_encode($mqttMessage, JSON_UNESCAPED_SLASHES); - foreach ($DB->request($request) as $row) { - $topic = implode('/', [ - $row['entities_id'], - 'agent', - $row['serial'], - 'Command', - 'Unenroll', - ]); - $mqttClient->publish($topic, $mqttMessage, 0, 1); - $mqttClient->publish('/' . $topic, null, 0, 1); - } - - $request = [ - 'FIELDS' => [ - 'glpi_plugin_flyvemdm_tasks' => ['id', 'itemtype_applied', 'items_id_applied', 'plugin_flyvemdm_policies_id', 'itemtype', 'items_id', 'value'], - 'glpi_plugin_flyvemdm_policies' => ['symbol'], - 'glpi_plugin_flyvemdm_fleets' => ['entities_id'] - ], - 'FROM' => 'glpi_plugin_flyvemdm_tasks', - 'INNER JOIN' => [ - 'glpi_plugin_flyvemdm_policies' => [ - 'FKEY' => [ - 'glpi_plugin_flyvemdm_tasks' => 'plugin_flyvemdm_policies_id', - 'glpi_plugin_flyvemdm_policies' => 'id' - ] - ], - 'glpi_plugin_flyvemdm_fleets' => [ - 'FKEY' => [ - 'glpi_plugin_flyvemdm_tasks' => 'items_id_applied', - 'glpi_plugin_flyvemdm_fleets' => 'id' - ] - ] - ], - 'WHERE' => [ - 'glpi_plugin_flyvemdm_tasks.itemtype_applied' => 'PluginFlyvemdmFleet' - ] - ]; - foreach ($DB->request($request) as $row) { - switch ($row['itemtype_applied']) { - case PluginFlyvemdmFleet::class: - $type = 'fleet'; - break; - - case PluginFlyvemdmAgent::class: - $type = 'agent'; - break; - - default: - $type = ''; - } - if ($type === '') { - continue; - } - $topic = implode('/', [ - $row['entities_id'], - 'fleet', - $row['items_id_applied'], - 'Policy', - $row['symbol'], - ]); - $policyFactory = new PluginFlyvemdmPolicyFactory(); - $appliedPolicy = $policyFactory->createFromDBByID($row['plugin_flyvemdm_policies_id']); - $policyMessage = $appliedPolicy->getMqttMessage( - $row['value'], - $row['itemtype'], - $row['items_id'] - ); - $policyMessage['taskId'] = $row['id']; - $encodedMessage = json_encode($policyMessage, JSON_UNESCAPED_SLASHES); - $mqttClient->publish("$topic/Task/" . $row['id'], $encodedMessage, 0, 1); - $mqttClient->publish('/' . $topic, null, 0, 1); - } -} diff --git a/install/upgrade_to_2.0.php b/install/upgrade_to_2.0.php new file mode 100644 index 00000000..920191f2 --- /dev/null +++ b/install/upgrade_to_2.0.php @@ -0,0 +1,490 @@ + ALLSTANDARDRIGHT , + PluginFlyvemdmInvitationlog::$rightname => READ, + PluginFlyvemdmGeolocation::$rightname => ALLSTANDARDRIGHT | READNOTE | UPDATENOTE, + ]); + $profileRight->updateProfileRights($profiles_id, $newRights); + + $migration->setContext('flyvemdm'); + $migration->addConfig([ + 'default_agent_url' => PLUGIN_FLYVEMDM_AGENT_DOWNLOAD_URL, + 'show_wizard' => '0', + 'debug_save_inventory' => '0', + 'android_bugcollecctor_url' => '', + 'android_bugcollector_login' => '', + 'android_bugcollector_passwd' => '', + 'invitation_deeplink' => PLUGIN_FLYVEMDM_DEEPLINK, + ]); + + $config = Config::getConfigurationValues('flyvemdm', ['mqtt_broker_tls']); + if (isset($config['mqtt_broker_tls'])) { + if ($config['mqtt_broker_tls'] !== '0') { + $config['mqtt_broker_tls_port'] = $config['mqtt_broker_port']; + $config['mqtt_broker_port'] = '1883'; + } else { + $config['mqtt_broker_tls_port'] = '8883'; + } + // Split TLS setting for client in one hand and backend in the other hand + $config['mqtt_tls_for_clients'] = $config['mqtt_broker_tls']; + $config['mqtt_tls_for_backend'] = $config['mqtt_broker_tls']; + Config::setConfigurationValues('flyvemdm', $config); + Config::deleteConfigurationValues('flyvemdm', ['mqtt_broker_tls']); + } + + // remove download base URL setting + Config::deleteConfigurationValues('flyvemdm', ['deploy_base_url']); + + // update Entity config table + $table = 'glpi_plugin_flyvemdm_entityconfigs'; + $migration->addField($table, 'support_name', 'text', ['after' => 'agent_token_life']); + $migration->addField($table, 'support_phone', 'string', ['after' => 'support_name']); + $migration->addField($table, 'support_website', 'string', ['after' => 'support_phone']); + $migration->addField($table, 'support_email', 'string', ['after' => 'support_website']); + $migration->addField($table, 'support_address', 'text', ['after' => 'support_email']); + $migration->addKey($table, 'entities_id', 'entities_id'); + + // update Agent table + $table = 'glpi_plugin_flyvemdm_agents'; + if (!$DB->fieldExists($table, 'enroll_status')) { + $query = "ALTER TABLE `$table` + ADD COLUMN `enroll_status` ENUM('enrolled', 'unenrolling', 'unenrolled') NOT NULL DEFAULT 'enrolled' AFTER `lock`"; + $DB->query($query) or plugin_flyvemdm_upgrade_error($migration); + } + $migration->addField($table, 'version', 'string', ['after' => 'name']); + $migration->addField($table, 'users_id', 'integer', ['after' => 'computers_id']); + $migration->addField($table, 'is_online', 'integer', ['after' => 'last_contact']); + $migration->addField($table, 'has_system_permission', 'bool', ['after' => 'mdm_type']); + $migration->addKey($table, 'computers_id', 'computers_id'); + $migration->addKey($table, 'users_id', 'users_id'); + $migration->addKey($table, 'entities_id', 'entities_id'); + $migration->changeField($table, 'wipe', 'wipe', 'bool'); + $migration->changeField($table, 'lock', 'lock', 'bool'); + + $enumMdmType = PluginFlyvemdmAgent::getEnumMdmType(); + $currentEnumMdmType = PluginFlyvemdmCommon::getEnumValues($table, 'mdm_type'); + if (count($currentEnumMdmType) > 0) { + // The field exists + if (count($currentEnumMdmType) != count($enumMdmType)) { + reset($enumMdmType); + $defaultValue = key($enumMdmType); + $enumMdmType = "'" . implode("', '", array_keys($enumMdmType)) . "'"; + $query = "ALTER TABLE `$table` + CHANGE COLUMN `mdm_type` `mdm_type` + ENUM($enumMdmType) + NOT NULL DEFAULT '$defaultValue'"; + $DB->query($query) or plugin_flyvemdm_upgrade_error($migration); + } + } else { + // The field does not exists + reset($enumMdmType); + $defaultValue = key($enumMdmType); + $enumMdmType = "'" . implode("', '", array_keys($enumMdmType)) . "'"; + $query = "ALTER TABLE `$table` + ADD COLUMN `mdm_type` + ENUM($enumMdmType) + NOT NULL DEFAULT '$defaultValue'"; + $DB->query($query) or plugin_flyvemdm_upgrade_error($migration); + } + + // Create task status table + $table = 'glpi_plugin_flyvemdm_taskstatuses'; + $query = "CREATE TABLE IF NOT EXISTS `$table` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL DEFAULT '', + `date_creation` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `date_mod` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + `plugin_flyvemdm_agents_id` INT(11) NOT NULL DEFAULT '0', + `plugin_flyvemdm_tasks_id` INT(11) NOT NULL DEFAULT '0', + `status` VARCHAR(255) NOT NULL DEFAULT '', + PRIMARY KEY (`id`), + KEY `plugin_flyvemdm_agents_id` (`plugin_flyvemdm_agents_id`), + KEY `plugin_flyvemdm_tasks_id` (`plugin_flyvemdm_tasks_id`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;"; + $DB->query($query) or plugin_flyvemdm_upgrade_error($migration); + + $migration->addKey($table, 'plugin_flyvemdm_agents_id', 'plugin_flyvemdm_agents_id'); + $migration->addKey($table, 'plugin_flyvemdm_tasks_id', 'plugin_flyvemdm_tasks_id'); + + // update Policy table + $table = 'glpi_plugin_flyvemdm_policies'; + $migration->addField($table, 'recommended_value', 'string', ['after' => 'default_value']); + $migration->addField($table, 'is_android_system', 'bool', ['after' => 'recommended_value']); + $migration->addField($table, 'android_min_version', 'string', ['after' => 'is_android_system', 'value' => '0']); + $migration->addField($table, 'android_max_version', 'string', ['after' => 'android_min_version', 'value' => '0']); + $migration->addField($table, 'apple_min_version', 'string', ['after' => 'android_max_version', 'value' => '0']); + $migration->addField($table, 'apple_max_version', 'string', ['after' => 'apple_min_version', 'value' => '0']); + $migration->addKey($table, 'group', 'group'); + $migration->addKey($table, 'plugin_flyvemdm_policycategories_id', 'plugin_flyvemdm_policycategories_id'); + $migration->dropField($table, 'is_android_policy'); + $migration->dropField($table, 'is_apple_policy'); + + // Rename and update fleet_policy into task + $table = 'glpi_plugin_flyvemdm_tasks'; + $migration->renameTable('glpi_plugin_flyvemdm_fleets_policies', $table); + $migration->changeField($table, 'plugin_flyvemdm_fleets_policies_id', 'plugin_flyvemdm_tasks_id', + 'integer'); + $migration->addKey($table, 'plugin_flyvemdm_policies_id', 'plugin_flyvemdm_policies_id'); + + // Upgrade schema to apply policies on fleets and agents + if (!$DB->fieldExists($table, 'items_id_applied')) { + $migration->changeField($table, 'plugin_flyvemdm_fleets_id', 'items_id_applied', 'integer'); + $migration->dropKey($table, 'plugin_flyvemdm_fleets_id'); + $migration->addField($table, 'itemtype_applied', 'string', ['after' => 'id']); + $migration->addKey($table, ['itemtype_applied', 'items_id_applied'], 'FK_applied'); + // All tasks already created were applied on fleets + $migration->addPostQuery("UPDATE `$table` SET `itemtype_applied` = 'PluginFlyvemdmFleet'"); + $migration->executeMigration(); + } + + $table = 'glpi_plugin_flyvemdm_policies'; + $policies = [ + 'disableFmRadio', + 'disableVoiceMail', + 'disableCallAutoAnswer', + 'disableVoiceDictation', + 'disableUsbOnTheGo', + 'resetPassword', + 'inventoryFrequency', + 'disableSmsMms', + 'disableStreamVoiceCall', + 'disableCreateVpnProfiles', + ]; + $tasksTable = 'glpi_plugin_flyvemdm_tasks'; + $fleetTable = 'glpi_plugin_flyvemdm_fleets'; + $agentsTable = 'glpi_plugin_flyvemdm_agents'; + $request = [ + 'FIELDS' => [ + $table => ['symbol'], + $tasksTable => ['id', 'itemtype_applied', 'items_id_applied'], + $fleetTable => ['entities_id'], + ], + 'FROM' => $table, + 'INNER JOIN' => [ + $tasksTable => [ + 'FKEY' => [ + $tasksTable => 'plugin_flyvemdm_policies_id', + $table => 'id', + ], + ], + ], + 'LEFT JOIN' => [ + $fleetTable => [ + 'itemtype_applied' => 'PluginFlyvemdmFleet', + 'FKEY' => [ + $tasksTable => 'items_id_applied', + $fleetTable => 'id', + ], + ], + $agentsTable => [ + 'itemtype_applied' => 'PluginFlyvemdmAgent', + 'FKEY' => [ + $tasksTable => 'items_id_applied', + $agentsTable => 'id', + ], + ], + ], + 'WHERE' => [ + 'symbol' => $policies, + ], + ]; + $result = $DB->request($request); + if (count($result) > 0) { + $mqttClient = PluginFlyvemdmMqttclient::getInstance(); + foreach ($result as $data) { + switch ($data['itemtype_applied']) { + case PluginFlyvemdmFleet::class: + $type = 'fleet'; + $entityId = $data['entities_id']; + break; + + case PluginFlyvemdmAgent::class: + $agent = new PluginFlyvemdmAgent(); + $agent->getFromDB($data['items_id_applied']); + $type = 'agent'; + $entityId = $agent->getEntityID(); + break; + + default: + $type = ''; + } + if ($type === '') { + continue; + } + $topic = implode('/', [ + '/', + $entityId, + $type, + $data['items_id_applied'], + 'Policy', + $data['symbol'], + 'Task', + $data['id'] + ]); + $mqttClient->publish($topic, null, 0, 1); + } + } + $policiesStr = implode("','", $policies); + $migration->addPostQuery("DELETE FROM `$table` WHERE `symbol` IN ('" . $policiesStr . "')"); + + // update Applications table + $table = 'glpi_plugin_flyvemdm_packages'; + $migration->addField($table, 'parse_status', "enum('pending', 'parsed', 'failed') NOT NULL DEFAULT 'pending'", + ['after' => 'dl_filename', 'default' => 'pending']); + $migration->addfield($table, 'name', 'string', ['after' => 'id']); + $migration->migrationOneTable($table); + $migration->dropField($table, 'filesize'); + $migration->addField($table, 'name', 'string', ['after' => 'id']); + $migration->addKey($table, 'entities_id', 'entities_id'); + $migration->addPostQuery("UPDATE `$table` SET `parse_status` = 'parsed'"); + $migration->addPostQuery("UPDATE `$table` SET `name` = `package_name`"); + + $result = $DB->request(['FROM' => $table, 'LIMIT' => '1']); + if ($result->count() > 0) { + $result->rewind(); + $row = $result->current(); + if (strpos($row['filename'], 'flyvemdm/package/') !== 0) { + // If there is at least one package and the path does starts with the new prefix, then update all the table + $migration->addPostQuery("UPDATE `$table` SET `filename` = CONCAT('flyvemdm/package/', `filename`)"); + } + } + + $table = 'glpi_plugin_flyvemdm_files'; + $migration->addKey($table, 'entities_id', 'entities_id'); + $migration->addField($table, 'comment', 'text'); + + // Add display preferences for PluginFlyvemdmFile + $query = "SELECT * FROM `glpi_displaypreferences` + WHERE `itemtype` = 'PluginFlyvemdmFile' + AND `users_id`='0'"; + $result=$DB->query($query); + if ($DB->numrows($result) == '0') { + $query = "INSERT INTO `glpi_displaypreferences` (`id`, `itemtype`, `num`, `rank`, `users_id`) + VALUES (NULL, 'PluginFlyvemdmFile', '1', '1', '0'), + (NULL, 'PluginFlyvemdmFile', '4', '2', '0');"; + $DB->query($query); + } + + $table = 'glpi_plugin_flyvemdm_fleets'; + $migration->addField($table, 'is_recursive', 'bool'); + $migration->addKey($table, 'entities_id', 'entities_id'); + + $table = 'glpi_plugin_flyvemdm_geolocations'; + $migration->addKey($table, 'computers_id', 'computers_id'); + + $table = 'glpi_plugin_flyvemdm_mqttacls'; + $migration->addKey($table, 'plugin_flyvemdm_mqttusers_id', 'plugin_flyvemdm_mqttusers_id'); + + $table = 'glpi_plugin_flyvemdm_policycategories'; + $migration->addKey($table, 'plugin_flyvemdm_policycategories_id', 'plugin_flyvemdm_policycategories_id'); + + // Create invitation log table + $table = 'glpi_plugin_flyvemdm_invitationlogs'; + $query = "CREATE TABLE IF NOT EXISTS `$table` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `plugin_flyvemdm_invitations_id` int(11) NOT NULL DEFAULT '0', + `date_creation` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + `event` varchar(255) NOT NULL DEFAULT '', + PRIMARY KEY (`id`), + INDEX `plugin_flyvemdm_invitations_id` (`plugin_flyvemdm_invitations_id`), + INDEX `date_creation` (`date_creation`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;"; + $DB->query($query) or plugin_flyvemdm_upgrade_error($migration); + $migration->addKey($table, 'plugin_flyvemdm_invitations_id', 'plugin_flyvemdm_invitations_id'); + + $table = 'glpi_plugin_flyvemdm_invitations'; + if (!$DB->fieldExists($table, 'name')) { + $invitationName = _n('Invitation', 'Invitations', 1, 'flyvemdm'); + $migration->addField($table, 'name', 'string', ['after' => 'id']); + $migration->addPostQuery("UPDATE `$table` SET `name` = '$invitationName'"); + } + $migration->addKey($table, 'users_id', 'users_id'); + $migration->addKey($table, 'entities_id', 'entities_id'); + $migration->addKey($table, 'documents_id', 'documents_id'); + + // drop Mqtt Update queue + $cronTask = new CronTask(); + $cronTask->deleteByCriteria(['itemtype' => 'PluginFlyvemdmMqttupdatequeue']); + $table = 'glpi_plugin_flyvemdm_mqttupdatequeues'; + $migration->dropTable($table); + + // Fix PascalCase symbols + $query = "UPDATE `glpi_plugin_flyvemdm_policies` + SET `symbol` = 'maximumFailedPasswordsForWipe' + WHERE `symbol`='MaximumFailedPasswordsForWipe'"; + $DB->query($query); + $query = "UPDATE `glpi_plugin_flyvemdm_policies` + SET `symbol` = 'maximumTimeToLock' + WHERE `symbol`='MaximumTimeToLock'"; + $DB->query($query); + + // change MQTT topics tree layout : remove leading slash + $mqttClient = PluginFlyvemdmMqttclient::getInstance(); + $request = [ + 'FIELDS' => [ + 'glpi_plugin_flyvemdm_agents' => ['entities_id'], + 'glpi_computers' => ['serial'], + ], + 'FROM' => 'glpi_plugin_flyvemdm_agents', + 'INNER JOIN' => [ + 'glpi_computers' => ['FKEY' => [ + 'glpi_plugin_flyvemdm_agents' => 'computers_id', + 'glpi_computers' => 'id' + ]] + ], + 'WHERE' => ['lock' => ['<>' => '0']] + ]; + $mqttMessage = ['lock' => 'now']; + $mqttMessage = json_encode($mqttMessage, JSON_UNESCAPED_SLASHES); + foreach ($DB->request($request) as $row) { + $topic = implode('/', [ + $row['entities_id'], + 'agent', + $row['serial'], + 'Command', + 'Lock', + ]); + $mqttClient->publish($topic, $mqttMessage, 0, 1); + $mqttClient->publish('/' . $topic, null, 0, 1); + } + + // re-use previous request array + $request['WHERE'] = ['wipe' => ['<>' => '0']]; + $mqttMessage = ['wipe' => 'now']; + $mqttMessage = json_encode($mqttMessage, JSON_UNESCAPED_SLASHES); + foreach ($DB->request($request) as $row) { + $topic = implode('/', [ + $row['entities_id'], + 'agent', + $row['serial'], + 'Command', + 'Wipe', + ]); + $mqttClient->publish($topic, $mqttMessage, 0, 1); + $mqttClient->publish('/' . $topic, null, 0, 1); + } + + // re-use previous request array + $request['WHERE'] = ['enroll_status' => ['=' => 'unenrolling']]; + $mqttMessage = ['unenroll' => 'now']; + $mqttMessage = json_encode($mqttMessage, JSON_UNESCAPED_SLASHES); + foreach ($DB->request($request) as $row) { + $topic = implode('/', [ + $row['entities_id'], + 'agent', + $row['serial'], + 'Command', + 'Unenroll', + ]); + $mqttClient->publish($topic, $mqttMessage, 0, 1); + $mqttClient->publish('/' . $topic, null, 0, 1); + } + + $request = [ + 'FIELDS' => [ + 'glpi_plugin_flyvemdm_tasks' => ['id', 'itemtype_applied', 'items_id_applied', 'plugin_flyvemdm_policies_id', 'itemtype', 'items_id', 'value'], + 'glpi_plugin_flyvemdm_policies' => ['symbol'], + 'glpi_plugin_flyvemdm_fleets' => ['entities_id'] + ], + 'FROM' => 'glpi_plugin_flyvemdm_tasks', + 'INNER JOIN' => [ + 'glpi_plugin_flyvemdm_policies' => [ + 'FKEY' => [ + 'glpi_plugin_flyvemdm_tasks' => 'plugin_flyvemdm_policies_id', + 'glpi_plugin_flyvemdm_policies' => 'id' + ] + ], + 'glpi_plugin_flyvemdm_fleets' => [ + 'FKEY' => [ + 'glpi_plugin_flyvemdm_tasks' => 'items_id_applied', + 'glpi_plugin_flyvemdm_fleets' => 'id' + ] + ] + ], + 'WHERE' => [ + 'glpi_plugin_flyvemdm_tasks.itemtype_applied' => 'PluginFlyvemdmFleet' + ] + ]; + foreach ($DB->request($request) as $row) { + switch ($row['itemtype_applied']) { + case PluginFlyvemdmFleet::class: + $type = 'fleet'; + break; + + case PluginFlyvemdmAgent::class: + $type = 'agent'; + break; + + default: + $type = ''; + } + if ($type === '') { + continue; + } + $topic = implode('/', [ + $row['entities_id'], + 'fleet', + $row['items_id_applied'], + 'Policy', + $row['symbol'], + ]); + $policyFactory = new PluginFlyvemdmPolicyFactory(); + $appliedPolicy = $policyFactory->createFromDBByID($row['plugin_flyvemdm_policies_id']); + $policyMessage = $appliedPolicy->getMqttMessage( + $row['value'], + $row['itemtype'], + $row['items_id'] + ); + $policyMessage['taskId'] = $row['id']; + $encodedMessage = json_encode($policyMessage, JSON_UNESCAPED_SLASHES); + $mqttClient->publish("$topic/Task/" . $row['id'], $encodedMessage, 0, 1); + $mqttClient->publish('/' . $topic, null, 0, 1); + } + } +} \ No newline at end of file diff --git a/setup.php b/setup.php index a097266c..2e62b0ff 100644 --- a/setup.php +++ b/setup.php @@ -29,7 +29,10 @@ * ------------------------------------------------------------------------------ */ +// Version of the plugin define('PLUGIN_FLYVEMDM_VERSION', 'develop'); +// Schema version of this version +define('PLUGIN_FLYVEMDM_SCHEMA_VERSION', '2.0'); // is or is not an official release of the plugin define('PLUGIN_FLYVEMDM_IS_OFFICIAL_RELEASE', false); // Minimal GLPI version, inclusive diff --git a/tests/src/Flyvemdm/Tests/CommonTestCase.php b/tests/src/Flyvemdm/Tests/CommonTestCase.php index cbfa8f5c..6ad77356 100644 --- a/tests/src/Flyvemdm/Tests/CommonTestCase.php +++ b/tests/src/Flyvemdm/Tests/CommonTestCase.php @@ -186,6 +186,56 @@ protected function createFleet($input) { return $fleet; } + /** + * @param array $input input data + * @return \PluginFlyvemdmTask + */ + protected function createTask($input) { + $task = $this->newMockInstance(\PluginFlyvemdmTask::class, '\MyMock'); + $task->getMockController()->post_addItem = function () {}; + $taskId = $task->add($input); + $this->boolean($task->isNewItem())->isFalse(); + + $task = new \PluginFlyvemdmTask(); + $task->getFromDB($taskId); + + return $task; + } + + /** + * @param string $policySymbol + * @return array + */ + protected function createFleetAndTask($policySymbol = 'storageEncryption') { + $fleet = $this->createFleet(['name' => $this->getUniqueString()]); + $policy = $this->newMockInstance(\PluginFlyvemdmPolicy::class, '\MyMock'); + $policy->getFromDbBySymbol($policySymbol); + $task = $this->createTask([ + 'value' => '0', + 'plugin_flyvemdm_policies_id' => $policy->getID(), + 'itemtype_applied' => \PluginFlyvemdmFleet::class, + 'items_id_applied' => $fleet->getID(), + 'itemtype' => '', + 'items_id' => '', + ]); + return [$fleet, $task]; + } + + /** + * @return array + */ + protected function createAgentTaskstatus() { + list($fleet, $task) = $this->createFleetAndTask(); + $agent = $this->createAgent(); + $agent->update([\PluginFlyvemdmFleet::getForeignKeyField() => $fleet->getID()]); + $taskStatus = $this->newMockInstance(\PluginFlyvemdmTaskStatus::class, '\MyMock'); + $taskStatus->getFromDBByCrit([ + \PluginFlyvemdmAgent::getForeignKeyField() => $agent->getID(), + \PluginFlyvemdmTask::getForeignKeyField() => $task->getID(), + ]); + return [$taskStatus, $fleet, $task]; + } + /** * Create a new enrolled agent in the database * diff --git a/tests/suite-install/Config.php b/tests/suite-install/Config.php index c77b154e..c6490f82 100644 --- a/tests/suite-install/Config.php +++ b/tests/suite-install/Config.php @@ -50,7 +50,8 @@ public function beforeTestMethod($method) { case 'testUpgradePlugin': $this->olddb = new \DB(); - $this->olddb->dbdefault = 'glpiupgradetest'; + $this->string(getenv('OLDDBNAME')); + $this->olddb->dbdefault = getenv('OLDDBNAME'); $this->olddb->connect(); $this->boolean($this->olddb->connected)->isTrue(); break; @@ -113,6 +114,16 @@ public function testInstallPlugin() { $plugin->activate($plugin->fields['id']); $this->boolean($plugin->isActivated($pluginName))->isTrue('Cannot enable the plugin'); + // Check version and schema version are in the configuration + $config = \Config::getConfigurationValues( + $pluginName, [ + 'version', + 'schema_version' + ] + ); + $this->string($config['version']); + $this->string($config['schema_version']); + // Enable debug mode for enrollment messages \Config::setConfigurationValues($pluginName, ['debug_enrolment' => '1']); diff --git a/tests/suite-integration/ProfileRight.php b/tests/suite-integration/ProfileRight.php index e32186d4..cf18d42a 100644 --- a/tests/suite-integration/ProfileRight.php +++ b/tests/suite-integration/ProfileRight.php @@ -94,6 +94,8 @@ public function testSuperAdminProfileRights() { \PluginFlyvemdmInvitation::$rightname => ALLSTANDARDRIGHT, \PluginFlyvemdmInvitationLog::$rightname => READ, \PluginFlyvemdmTaskstatus::$rightname => READ, + \PluginFlyvemdmFDroidApplication::$rightname => READ | UPDATE | READNOTE | UPDATENOTE, + \PluginFlyvemdmFDroidMarket::$rightname => ALLSTANDARDRIGHT | READNOTE | UPDATENOTE, ]; $profileRight = $this->newTestedInstance(); diff --git a/tests/suite-uninstall/Config.php b/tests/suite-uninstall/Config.php index 4be84def..6b001826 100644 --- a/tests/suite-uninstall/Config.php +++ b/tests/suite-uninstall/Config.php @@ -37,7 +37,6 @@ class Config extends CommonTestCase { public function beforeTestMethod($method) { - $this->resetState(); parent::beforeTestMethod($method); $this->setupGLPIFramework(); } diff --git a/tests/suite-unit/PluginFlyvemdmFdroidApplication.php b/tests/suite-unit/PluginFlyvemdmFdroidApplication.php new file mode 100644 index 00000000..3955e7f6 --- /dev/null +++ b/tests/suite-unit/PluginFlyvemdmFdroidApplication.php @@ -0,0 +1,290 @@ +login('glpi', 'glpi'); + break; + } + } + + public function afterTestMethod($method) { + switch ($method) { + case 'testPrepareInputForAdd': + case 'testPrepareInputForUpdate': + case 'testDisplayTabContentForItem': + case 'testGetTabNameForItem': + parent::afterTestMethod($method); + \Session::destroy(); + break; + } + } + + /** + * @tags testGetEnumImportStatus + */ + public function testGetEnumImportStatus() { + $output = \PluginFlyvemdmFDroidApplication::getEnumImportStatus(); + $this->array($output)->size->isEqualTo(3); + $this->array($output)->hasKeys([ + 'no_import', + 'to_import', + 'imported', + ]); + } + + /** + * @tags testGetMenuPicture + */ + public function testGetMenuPicture() { + $output = \PluginFlyvemdmFDroidApplication::getMenuPicture(); + $this->string($output)->isEqualTo(''); + } + + public function providerGetTypeName() { + return [ + 'none' => [ + 0, + 'F-Droid applications', + ], + 'singular' => [ + 1, + 'F-Droid application', + ], + 'plural' => [ + 2, + 'F-Droid applications', + ], + ]; + } + + /** + * @tags testGetTypeName + * @dataProvider providerGetTypeName + */ + public function testGetTypeName($count, $expected) { + $output = \PluginFlyvemdmFDroidApplication::getTypeName($count); + $this->string($output)->isEqualTo($expected); + } + + public function providerGetTabNameForItem() { + return [ + [ + new \PluginFlyvemdmFDroidMarket(), + 0, + 'F-Droid applications', + ], + [ + new \PluginFlyvemdmFDroidMarket(), + 1, + '', + ], + [ + new \PluginFlyvemdmInvitation(), + 0, + '', + ], + ]; + } + + /** + * @dataProvider providerGetTabNameForItem + * @tags testGetTabNameForItem + */ + public function testGetTabNameForItem($item, $withTemplate, $expected) { + $instance = $this->newTestedInstance(); + $output = $instance->getTabNameForItem($item, $withTemplate); + $this->string($output)->isEqualTo($expected); + } + + public function providerDisplayTabContentForItem() { + return [ + 'no app for a market' => [ + 'item' => new \PluginFlyvemdmFDroidMarket(), + 'expected' => 'There is no application yet', + ], + ]; + } + + /** + * @tags testGetAdditionalLinks + */ + public function testGetAdditionalLinks() { + $instance = $this->newTestedInstance(); + $output = $instance->getAdditionalLinks(); + $this->array($output)->size->isEqualTo(0); + } + + /** + * @tags testGetRights + */ + public function testGetRights() { + $instance = $this->newTestedInstance(); + $result = $instance->getRights(); + $this->array($result)->containsValues([ + 'Read', + 'Update', + ]) + ->hasKeys([READ, UPDATE]); + } + + public function providerCronInfo() { + return [ + [ + 'DownloadApplications', + ['description' => __('download applications from the market')], + ], + [ + 'SomethingElse', + null, + ], + ]; + } + + /** + * @tags testCronInfo + * @dataProvider providerCronInfo + */ + public function testCronInfo($name, $expected) { + $output = \PluginFlyvemdmFDroidApplication::cronInfo($name); + if ($expected !== null) { + $this->array($output)->size->isEqualTo(1); + $this->array($output) + ->hasKey('description') + ->contains('download applications from the market'); + } else { + $this->variable($output)->isNull(); + } + } + + public function providerTestImport() { + $instance = $this->newTestedInstance(); + $applicationName = 'I exist' . $this->getUniqueString(); + $applicationName2 = 'I miss' . $this->getUniqueString(); + $id = $instance->add([ + 'name' => $applicationName + ]); + $this->boolean($instance->isNewItem())->isFalse(); + $market = new \PluginFlyvemdmFDroidMarket(); + $market->add([ + 'name' => $this->getUniqueString(), + ]); + $this->boolean($market->isNewItem())->isFalse(); + return [ + 'no name' => [ + 'input' => [ + 'plugin_flyvemdm_fdroidmarkets_id' => $market->getID(), + ], + 'expected' => false, + ], + 'no repository' => [ + 'input' => [ + 'name' => 'something', + ], + 'expected' => false, + ], + 'existing item' => [ + 'input' => [ + 'name' => $applicationName, + 'plugin_flyvemdm_fdroidmarkets_id' => $market->getID(), + ], + 'expected' => $id, + ], + 'not existing item' => [ + 'input' => [ + 'name' => $applicationName2, + 'plugin_flyvemdm_fdroidmarkets_id' => $market->getID(), + ], + 'expected' => $id, + ], + ]; + } + + /** + * @tags testImport + * @dataProvider providerTestImport + */ + public function testImport($input, $expected) { + $output = \PluginFlyvemdmFDroidApplication::import($input); + if ($expected === false) { + $this->variable($output)->isEqualTo($expected); + $this->boolean($output); + } else { + $this->integer($output); + $instance = $this->newTestedInstance(); + $this->boolean($instance->getFromDB($output))->isTrue(); + } + } + + public function providerPrepareInputForUpdate() { + return [ + 'no checks' => [ + 'input' => [ + '_skip_checks' => '', + 'something' => 'random', + ], + 'expected' => [ + '_skip_checks' => '', + 'something' => 'random', + ] + ], + 'checks' => [ + 'input' => [ + 'something' => 'random', + ], + 'expected' => [ + 'something' => 'random', + 'import_status' => 'no_import', + ] + ], + ]; + } + + /** + * @dataProvider providerPrepareInputForUpdate + */ + public function testPrepareInputForUpdate($input, $expected) { + $instance = $this->newTestedInstance(); + $output = $instance->prepareInputForUpdate($input); + $this->array($output)->size->isEqualTo(count($expected)); + $this->array($output)->hasKeys(array_keys($expected)); + } +} \ No newline at end of file diff --git a/tests/suite-unit/PluginFlyvemdmPackage.php b/tests/suite-unit/PluginFlyvemdmPackage.php index 01b34cd8..dc0e6e8d 100644 --- a/tests/suite-unit/PluginFlyvemdmPackage.php +++ b/tests/suite-unit/PluginFlyvemdmPackage.php @@ -138,4 +138,12 @@ public function testPostGetFromDB($argument) { } } -} \ No newline at end of file + public function testGetSpecificValueToDisplay() { + // @see http://png-pixel.com/ + $png = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='; + + $instance = $this->newTestedInstance(); + $output = $instance::getSpecificValueToDisplay('icon', ['icon' => $png]); + $this->string($output)->isEqualTo(''); + } +} diff --git a/tpl/agentComputerInfo.html.twig b/tpl/agentComputerInfo.html.twig index 29a8b6fc..013b8596 100644 --- a/tpl/agentComputerInfo.html.twig +++ b/tpl/agentComputerInfo.html.twig @@ -1,6 +1,6 @@ - + {% embed "_agentInfo.html.twig" %}{% endembed %}
{{ __('Flyve MDM') }}{{ __('Flyve MDM', 'flyvemdm') }}
\ No newline at end of file diff --git a/tpl/fdroidapplication.html.twig b/tpl/fdroidapplication.html.twig new file mode 100644 index 00000000..d05ef3a0 --- /dev/null +++ b/tpl/fdroidapplication.html.twig @@ -0,0 +1,31 @@ +{% if not isNewID %} + + {% if not package.icon %} {% else %} {% endif %} + + +{% endif %} + + {{ __('Name') }}{{ withTemplate }} + {{ fdroidapplication.name }} + {{ __('Alias', 'flyvemdm') }} + {{ fdroidapplication.alias }} + + + {{ __('Version') }} + {{ fdroidapplication.version }} + {{ __('file size', 'flyvemdm') }} + {{ fdroidapplication.filesize|fileSize }} + + + {{ __('Description', 'flyvemdm') }} + {{ fdroidapplication.desc|raw }} + + + {{ __('Import status', 'flyvemdm') }} + + + {{ __('Import status', 'flyvemdm') }} + {{ fdroidapplication.import_status }} + diff --git a/tpl/fdroidmarket.html.twig b/tpl/fdroidmarket.html.twig new file mode 100644 index 00000000..bbfa2f13 --- /dev/null +++ b/tpl/fdroidmarket.html.twig @@ -0,0 +1,6 @@ + + {{ __('Name') }}{{ withTemplate }} + + {{ __('URL', 'flyvemdm') }} + +