Commit e2ddddd8 authored by Fabrice Gangler's avatar Fabrice Gangler 🎨
Browse files

Comptoir v2.8.0

parents aa9fe39b 0cef98db
Pipeline #10035 passed with stage
in 5 minutes and 13 seconds
......@@ -5,6 +5,20 @@ Tous les changements notables de ce projet sont documentés dans ce fichier.
Le format s'appuie sur [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
et le projet suit [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [2.8.0](https://gitlab.adullact.net/Comptoir/Comptoir-srv/tags/v2.8.0) - 2020-06-15
### Added
* [#903](https://gitlab.adullact.net/Comptoir/Comptoir-srv/issues/903) Ajout du bouton modifier pour la cartographie
* [#917](https://gitlab.adullact.net/Comptoir/Comptoir-srv/issues/917) Page d'un utilisateur : afficher les données de la cartographie
* [#918](https://gitlab.adullact.net/Comptoir/Comptoir-srv/issues/918) Page d'un logiciel : afficher les données de la cartographie
### Fixed
* [#910](https://gitlab.adullact.net/Comptoir/Comptoir-srv/issues/910) Traitement correcte des langues utilisateur non supportées par l'application
* [#914](https://gitlab.adullact.net/Comptoir/Comptoir-srv/issues/914) Cartographie : corriger les chaines de textes non traduites
* [#915](https://gitlab.adullact.net/Comptoir/Comptoir-srv/issues/915) Cartographie : modification des textes (titres, boutons, tableaux, ...)
* [#919](https://gitlab.adullact.net/Comptoir/Comptoir-srv/issues/919) Cartographie : le formulaire s'affiche uniquement si on est déjà déclaré comme utilisateur du logiciel
* [#898](https://gitlab.adullact.net/Comptoir/Comptoir-srv/issues/898) Correction du bug des boutons non utilisables après l'édition de son profil
## [2.7.0](https://gitlab.adullact.net/Comptoir/Comptoir-srv/tags/v2.7.0) - 2020-05-29
......
......@@ -25,7 +25,7 @@ INSERT INTO public.taxonomys (id, parent_id, title_i18n_en, title_i18n_fr, descr
INSERT INTO public.taxonomys (id, parent_id, title_i18n_en, title_i18n_fr, description_i18n_en, description_i18n_fr, created, modified) VALUES (20, 3, 'Office automation', 'Bureautique', null, null, '2020-01-31 15:12:58.000000', '2020-01-31 15:12:58.000000');
INSERT INTO public.taxonomys (id, parent_id, title_i18n_en, title_i18n_fr, description_i18n_en, description_i18n_fr, created, modified) VALUES (21, 3, 'Web', 'Web', null, null, '2020-01-31 15:12:58.000000', '2020-01-31 15:12:58.000000');
INSERT INTO public.taxonomys (id, parent_id, title_i18n_en, title_i18n_fr, description_i18n_en, description_i18n_fr, created, modified) VALUES (22, 3, 'Infrastructure', 'Infrastructure', null, null, '2020-01-31 15:12:58.000000', '2020-01-31 15:12:58.000000');
INSERT INTO public.taxonomys (id, parent_id, title_i18n_en, title_i18n_fr, description_i18n_en, description_i18n_fr, created, modified) VALUES (23, 3, 'Développement', 'Development', null, null, '2020-01-31 15:12:58.000000', '2020-01-31 15:12:58.000000');
INSERT INTO public.taxonomys (id, parent_id, title_i18n_en, title_i18n_fr, description_i18n_en, description_i18n_fr, created, modified) VALUES (23, 3, 'Development', 'Développement', null, null, '2020-01-31 15:12:58.000000', '2020-01-31 15:12:58.000000');
INSERT INTO public.taxonomys (id, parent_id, title_i18n_en, title_i18n_fr, description_i18n_en, description_i18n_fr, created, modified) VALUES (24, 3, 'Multimedia', 'Multimedia', null, null, '2020-01-31 15:12:58.000000', '2020-01-31 15:12:58.000000');
ALTER SEQUENCE taxonomys_id_seq RESTART WITH 50;
# How to upgrade from v2.5.0 to v2.6.0
# How to upgrade from v2.6.0 to v2.7.0
## 1) First backup (DB + images files)
......@@ -64,7 +64,8 @@ ls -lh /home/comptoir/Comptoir-EXPORT/
# Backup main directory
cd /home/comptoir/
tar -czvf Comptoir-srv_BACKUP_2020.04.09_03h05.tar.gz Comptoir-srv
DATE=$(date +"%Y.%m.%d_%Hh%M")
tar -czvf "Comptoir-srv_BACKUP_${DATE}.tar.gz" Comptoir-srv
```
## 5) Update source code
......@@ -177,5 +178,5 @@ sudo su comptoir
# Clean up
cd /home/comptoir/
rm -rvf tmp_migration/
rm -v Comptoir-srv_BACKUP_2020.04.09_03h05.tar.gz
rm -v Comptoir-srv_BACKUP_*.tar.gz
```
# How to upgrade from v2.7.0 to v2.8.0
## 1) First backup (DB + images files)
```bash
# (1) user comptoir
sudo su comptoir
# First backup (DB + images files)
/home/comptoir/Comptoir-srv/bin/COMPTOIR_export_DB_data_AND_images.sh
/home/comptoir/Comptoir-srv/bin/COMPTOIR_export_DB_structure_only.sh
ls -lh /home/comptoir/Comptoir-EXPORT/
```
## 2) Preloading vendor directory
```bash
# (1) use the user "comptoir"
sudo su comptoir
# Preloading vendor
mkdir /home/comptoir/tmp_migration
cd /home/comptoir/tmp_migration
git clone https://gitlab.adullact.net/Comptoir/Comptoir-srv.git
mv Comptoir-srv/ Comptoir_tmp_update_vendor
cd Comptoir_tmp_update_vendor/
git checkout origin/master
git log --decorate --oneline --graph --all
composer check-platform-reqs
composer validate
composer install
```
## 3) Activate maintenance site
see:
[www-maintenance-comptoir](https://gitlab.adullact.net/Adullact-prive/comptoir-prive/www-maintenance-comptoir)
(private repository)
```bash
# (1) use your user
# Activate maintenance site
sudo a2dissite 25-https_comptoir-du-libre.org.conf
sudo a2ensite 30-503-MAINTENANCE_https_comptoir-du-libre.org.conf
sudo service apache2 reload
# on your computer, the following command lines
# must retrun an HTTP 500 response
curl -v https://comptoir-du-libre.org/
curl -v https://comptoir-du-libre.org/notFoundPage
```
## 4) Backup before migration (DB + images files + main directory)
```bash
# (1) user comptoir
sudo su comptoir
# Second backup (DB + images files)
/home/comptoir/Comptoir-srv/bin/COMPTOIR_export_DB_data_AND_images.sh
/home/comptoir/Comptoir-srv/bin/COMPTOIR_export_DB_structure_only.sh
ls -lh /home/comptoir/Comptoir-EXPORT/
# Backup main directory
cd /home/comptoir/
DATE=$(date +"%Y.%m.%d_%Hh%M")
tar -czvf "Comptoir-srv_BACKUP_${DATE}.tar.gz" Comptoir-srv
```
## 5) Update source code
```bash
# (1) user comptoir
sudo su comptoir
# Update source code
cd /home/comptoir/Comptoir-srv
rm -rvf vendor/
git remote -v
git remote update -p
git checkout origin/master
git log --decorate --oneline --graph --all
```
## 6) Update vendor directory + clean cache
```bash
# (1) user comptoir
sudo su comptoir
# Update vendor directory (see step 2 "Preloading vendor directory")
cd /home/comptoir/Comptoir-srv
rm -rvf vendor/
mv -v ../tmp_migration/Comptoir_tmp_update_vendor/vendor ./
# Clean cache
cd /home/comptoir/Comptoir-srv
bin/cake cache clear_all
```
## 7) Apply migration of the database (new tables, adding fields, ...)
The following changes must be recorded in the [production version tracking](https://gitlab.adullact.net/Adullact-prive/comptoir-prive/Exploitation-Comptoir/-/blob/master/Suivi-versions-PROD.md) file.
```bash
# (1) user comptoir
sudo su comptoir
# Apply migration of the database (new tables, adding fields, ...)
cd /home/comptoir/Comptoir-srv
bin/cake migrations migrate
# Now you can apply additional changes in SQL with pgsl
# ---> nothing to do here for this version
```
## 8) Update config files
The following changes must be recorded in the [production version tracking](https://gitlab.adullact.net/Adullact-prive/comptoir-prive/Exploitation-Comptoir/-/blob/master/Suivi-versions-PROD.md) file.
see:
[commit 0ecfad95](https://gitlab.adullact.net/Comptoir/Comptoir-srv/-/commit/0ecfad951986c89e98fc93684682e88e3808140e#db083217133df62cac95237c2e964e0a9e319847_50_50)
"FEAT(mapping)!: adding edit button"
```bash
# (1) user comptoir
sudo su comptoir
# Apply additional changes in config files
cd /home/comptoir/Comptoir-srv
vim config/comptoir.php
vim config/app.php # ---> nothing to do here for this version
```
## 9) Enable the main website
see:
[www-maintenance-comptoir](https://gitlab.adullact.net/Adullact-prive/comptoir-prive/www-maintenance-comptoir)
(private repository)
```bash
# (1) use your user
# Enable the main website
sudo a2dissite 30-503-MAINTENANCE_https_comptoir-du-libre.org.conf
sudo a2ensite 25-https_comptoir-du-libre.org.conf
sudo service apache2 reload
# on your computer, the first following command line
# must return an HTTP 200 response code
# and the second return an HTTP 404 response code.
curl -v https://comptoir-du-libre.org/
curl -v https://comptoir-du-libre.org/notFoundPage
```
## 10) Backup after upgraded
```bash
# (1) user comptoir
sudo su comptoir
# Backup after upgraded (DB + images files)
/home/comptoir/Comptoir-srv/bin/COMPTOIR_export_DB_data_AND_images.sh
/home/comptoir/Comptoir-srv/bin/COMPTOIR_export_DB_structure_only.sh
ls -lh /home/comptoir/Comptoir-EXPORT/
```
## 11) Clean up
```bash
# (1) user comptoir
sudo su comptoir
# Clean up
cd /home/comptoir/
rm -rvf tmp_migration/
rm -v Comptoir-srv_BACKUP_*.tar.gz
```
......@@ -24,7 +24,7 @@ INSERT INTO public.taxonomys (id, parent_id, title_i18n_en, title_i18n_fr, descr
INSERT INTO public.taxonomys (id, parent_id, title_i18n_en, title_i18n_fr, description_i18n_en, description_i18n_fr, created, modified) VALUES (20, 3, 'Office automation', 'Bureautique', null, null, '2020-01-31 15:12:58.000000', '2020-01-31 15:12:58.000000');
INSERT INTO public.taxonomys (id, parent_id, title_i18n_en, title_i18n_fr, description_i18n_en, description_i18n_fr, created, modified) VALUES (21, 3, 'Web', 'Web', null, null, '2020-01-31 15:12:58.000000', '2020-01-31 15:12:58.000000');
INSERT INTO public.taxonomys (id, parent_id, title_i18n_en, title_i18n_fr, description_i18n_en, description_i18n_fr, created, modified) VALUES (22, 3, 'Infrastructure', 'Infrastructure', null, null, '2020-01-31 15:12:58.000000', '2020-01-31 15:12:58.000000');
INSERT INTO public.taxonomys (id, parent_id, title_i18n_en, title_i18n_fr, description_i18n_en, description_i18n_fr, created, modified) VALUES (23, 3, 'Développement', 'Development', null, null, '2020-01-31 15:12:58.000000', '2020-01-31 15:12:58.000000');
INSERT INTO public.taxonomys (id, parent_id, title_i18n_en, title_i18n_fr, description_i18n_en, description_i18n_fr, created, modified) VALUES (23, 3, 'Development', 'Développement', null, null, '2020-01-31 15:12:58.000000', '2020-01-31 15:12:58.000000');
INSERT INTO public.taxonomys (id, parent_id, title_i18n_en, title_i18n_fr, description_i18n_en, description_i18n_fr, created, modified) VALUES (24, 3, 'Multimedia', 'Multimedia', null, null, '2020-01-31 15:12:58.000000', '2020-01-31 15:12:58.000000');
ALTER SEQUENCE taxonomys_id_seq RESTART WITH 50;
......@@ -256,7 +256,9 @@ Configure::write('MAX_DISPLAY', 3);
Configure::write('Session', [
'defaults' => 'php',
'cookie' => 'ComptoirDuLibre',
'timeout' => 60 // 60 minutes
// Time of inactivity allowed for a user before automatic disconnection
'timeout' => 180 // 3 h = 3 x 60 minutes
]);
// Limit value for software datas
......@@ -279,7 +281,7 @@ Configure::write(
Configure::write(
'VERSION',
[
"footer" => "v2.7.0"
"footer" => "v2.8.0"
]
);
......
......@@ -47,6 +47,15 @@ return [
],
// Some kind of ACL for views
'ACL' => [
'TaxonomysSoftwares' => [
'mappingForm' => [
'Administration' => true,
'Association' => false,
'Person' => false,
'Company' => false,
'Unknown' => true,
],
],
'Users' => [
'add' => [
'Administration' => false,
......
......@@ -5,6 +5,7 @@ namespace App\Cache;
use App\Network\Exception\RelationshipNotFoundException;
use App\Network\Exception\UserTypeNotFoundException;
use Cake\ORM\TableRegistry;
use Cake\Utility\Text;
/**
* A trait that provides methods for some database cache
......@@ -16,6 +17,146 @@ trait AppCacheTrait
*/
private $appCache = [];
/////////// Taxonomy //////////////////////////////////////////////////////////////////////////////////////////
/**
* Returns mapping first levels
* @return array example: [<taxonId> => <taxonName>, ...]
*/
final public function getMappingFirstLevels(string $lang = 'en')
{
if (!isset($this->appCache['mappingFirstLevels'][$lang])
|| !array($this->appCache['mappingFirstLevels'][$lang])) {
$this->getMappingFromCache($lang);
}
return $this->appCache['mappingFirstLevels'][$lang];
}
/**
* Returns mapping data
* example:
* [ <taxonId_1> => [ 'slug' => <taxonSlug>,
* 'title' => <taxonTitle>,
* 'desc => <description>,
* 'children' => [<taxonId> => <taxonName>, ...], ]
* <taxonId_4> => [ 'slug' => <taxonSlug>,
* 'title' => <taxonTitle>,
* 'desc => <description>,
* 'id_parent' => <taxonParenId> ]
*
* @return array
*/
final public function getMappingTaxons(string $lang = 'en')
{
if (!isset($this->appCache['mappingTaxons'][$lang]) || !array($this->appCache['mappingTaxons'][$lang])) {
$this->getMappingFromCache($lang);
}
return $this->appCache['mappingTaxons'][$lang];
}
/**
* Returns mapping data, filtered from provided taxon IDs.
* Parent taxons are included.
*
* example:
* [ <taxonId_1> => [ 'slug' => <taxonSlug>,
* 'title' => <taxonTitle>,
* 'desc => <description>,
* 'children' => [<taxonId> => <taxonName>, ...], ]
* <taxonId_4> => [ 'slug' => <taxonSlug>,
* 'title' => <taxonTitle>,
* 'desc => <description>,
* 'id_parent' => <taxonParenId> ]
*
* @param array $taxonIds example: [<taxonId_4>, <taxonId_5>, ...]
* @param string $lang (optional) language code, by default it's 'en'
* @return array
*/
final public function getMappingTaxonsWithTaxonIdsFilter(array $taxonIds, string $lang = 'en')
{
$taxonIds = array_flip($taxonIds);
$data = $this->getMappingTaxons($lang);
$filteredData = [];
$parentList = [];
// Filtring except first level taxons
foreach ($data as $taxonId => $taxonData) {
if (!isset($taxonData['id_parent'])) { // First level
$parentList[$taxonId] = $taxonData;
} elseif (isset($taxonIds[$taxonId])) {
$filteredData[$taxonId] = $taxonData;
}
}
// Filtring for first level taxons
foreach ($parentList as $parentId => $parentData) {
foreach ($parentData['children'] as $childId => $child) {
if (!isset($taxonIds[$childId])) {
unset($parentList[$parentId]['children'][$childId]);
}
}
if (count($parentList[$parentId]['children']) === 0) {
unset($parentList[$parentId]);
}
}
$filteredData = $parentList + $filteredData;
return $filteredData;
}
/**
* Populate:
* - $this->appCache['mappingTaxons'][$lang]
* - $this->appCache['mappingFirstLevels'][$lang]
*
* @param string $lang
* @return void
*/
private function getMappingFromCache(string $lang = 'en')
{
$this->initAppCache();
if (isset($this->appCache['mappingTaxons'][$lang]) && array($this->appCache['mappingTaxons'][$lang])) {
return;
}
$titlePropertie = "title_i18n_$lang";
$descPropertie = "description_i18n_$lang";
$mapping = [];
$mappingFirstLevels = [];
$registry = TableRegistry::get("Taxonomys");
$taxonomys = $registry->find('all');
foreach ($taxonomys as $taxonomy) {
$id = $taxonomy->id;
$title = $taxonomy->$titlePropertie; // property "title_i18n_fr" or "title_i18n_en"
$desc = $taxonomy->$descPropertie; // property "description_i18n_fr" or "description_i18n_en"
$mapping[$id]['slug'] = strtolower(Text::slug($title));
$mapping[$id]['title'] = $title ;
$mapping[$id]['desc'] = $desc ;
if (is_null($taxonomy->parent_id)) {
$mappingFirstLevels[$id] = $title;
} else {
$idParent = $taxonomy->parent_id;
$mapping[$id]['id_parent'] = $idParent ;
$mapping[$idParent]['children'][$id] = $title;
}
}
ksort($mappingFirstLevels);
foreach ($mapping as $id => $dataTaxon) {
if (isset($mapping[$id]['children'])) {
asort($mapping[$id]['children']);
}
}
$this->appCache['mappingFirstLevels'][$lang] = $mappingFirstLevels;
$this->appCache['mappingTaxons'][$lang] = $mapping;
}
/////////// Relationships //////////////////////////////////////////////////////////////////////////////////////////
/**
* Get relationships list
*
......@@ -23,9 +164,7 @@ trait AppCacheTrait
*/
final protected function getRelationshipsListFromCache()
{
if (!isset($this->appCache)) {
$this->appCache = [];
}
$this->initAppCache();
if (!isset($this->appCache['relationships']) || !array($this->appCache['relationships'])) {
$registry = TableRegistry::get('Relationships');
$result = $registry->find("all")->toList();
......@@ -54,6 +193,9 @@ trait AppCacheTrait
}
}
/////////// User type //////////////////////////////////////////////////////////////////////////////////////////////
/**
* Get user types list
*
......@@ -61,9 +203,7 @@ trait AppCacheTrait
*/
final protected function getUserTypesListFromCache()
{
if (!isset($this->appCache)) {
$this->appCache = [];
}
$this->initAppCache();
if (!isset($this->appCache['userTypes']) || !array($this->appCache['userTypes'])) {
$registry = TableRegistry::get('userTypes');
$result = $registry->find("all")->toList();
......@@ -91,4 +231,17 @@ trait AppCacheTrait
throw new UserTypeNotFoundException("The relationship with the cd (nameSlug) [ $name ] does not exist");
}
}
//////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////
/**
* Initializes property $this->appCache, if it does not exist
*/
final protected function initAppCache()
{
if (!isset($this->appCache)) {
$this->appCache = [];
}
}
}
......@@ -319,6 +319,9 @@ class SoftwaresController extends AppController
]
);
// Load mapping data if available for current software and populate view data
$this->commonMappingForCurrentSoftware($software->id);
$this->set(compact(['software']));
$this->set('_serialize', ['software']);
......@@ -359,6 +362,32 @@ class SoftwaresController extends AppController
}
}
/**
* Load mapping data if available for given software ID and populate view data
* @param int $softwareId
*/
protected function commonMappingForCurrentSoftware(int $softwareId)
{
// Get taxonomy records grouped by taxon ID for this software
$this->loadModel("TaxonomysSoftwares");
$taxonomiesSoftware = $this->TaxonomysSoftwares->getListBySofwareId($softwareId);
// Load mapping data if necessary
$mappingFirstLevels = [];
$mappingTaxons = [];
if (count($taxonomiesSoftware) > 0) {
$taxonIds = array_keys($taxonomiesSoftware);
$mappingFirstLevels = $this->getMappingFirstLevels($this->selectedLanguage);
$mappingTaxons = $this->getMappingTaxonsWithTaxonIdsFilter($taxonIds, $this->selectedLanguage);
}
// Populate view data
$this->set(compact(['mappingFirstLevels']));
$this->set(compact(['mappingTaxons']));
$this->set(compact(['taxonomiesSoftware']));
$this->set('_serialize', ['taxonomiesSoftware','mappingTaxons','mappingFirstLevels']);
}
/**
* Add method
*
......
......@@ -43,7 +43,7 @@ class CommonTaxonomyController extends MetaTaxonomyController
{
$firstLink = [
'name' => __d('Breadcrumbs', 'Taxonomy.index'),
'url' => $this->getBaseUrl(false)
'url' => $this->getBaseUrl('mapping', false)
];
array_unshift($links, $firstLink);
parent::setBreadcrumbs($links);
......
......@@ -159,23 +159,6 @@ class MetaTaxonomyController extends AppController
return false;
}
/**
* Before render callback.
* Called after the controller action is run, but before the view is rendered.
*
* Used to set view variables that are required on every request:
* - viewBaseUrl
*
* @param Event $event The beforeRender event.
* @return void
*/
public function beforeRender(Event $event)
{
parent::beforeRender($event);
$this->set('viewBaseUrl', $this->getBaseUrl());
}
/**
* Business rules that define if current user is editor
*
......@@ -197,91 +180,4 @@ class MetaTaxonomyController extends AppController
}
return false;
}
/**
* Returns the base URL of the mapping based on the user's language
*
* @param bool $withLanguagePrefix (optional) add the language prefix in the URL, by default it's true
* @return string base URL of the mapping based on the user's language.
*/
final protected function getBaseUrl($withLanguagePrefix = true)
{
$url = '';
if ($withLanguagePrefix === true) {
$url .= '/'.$this->selectedLanguage .'/';
}
if ($this->selectedLanguage === 'fr') {
$url .= 'cartographie/';
} else {
$url .= 'mapping/';
}
return $url ;
}
/**
* Return mapping first levels
* @return array
*/
final protected function getmappingFirstLevels()
{
if (!is_array($this->mappingTaxons) || count($this->mappingTaxons) === 0) {
$this->loadMappingData();
}