Make Framadate compatible with PostgreSQL and great again !

* Move the database handling to Doctrine DBAL
* Move Migrations to Doctrine Migrations
* Rename migrations for Doctrine Migrations Uses
* Fix Migrations
* Change config parameters, introduce db name, host and port parameters and get rid of database url
* Change install form for this
* Add a CLI command to make migrations
* Add config.test.php to be used with APP_ENV=test for testing

Signed-off-by: Thomas Citharel <tcit@tcit.fr>

CS

Signed-off-by: Thomas Citharel <tcit@tcit.fr>

Add sqlite to CI and execute migration in test env

Signed-off-by: Thomas Citharel <tcit@tcit.fr>

Typo

Signed-off-by: Thomas Citharel <tcit@tcit.fr>

SQLite is already inside the image...

Signed-off-by: Thomas Citharel <tcit@tcit.fr>

Rebase two new migrations

Signed-off-by: Thomas Citharel <tcit@tcit.fr>

Move from trait to abstract class and remove legacy migration table after checks

Signed-off-by: Thomas Citharel <tcit@tcit.fr>

CS

Signed-off-by: Thomas Citharel <tcit@tcit.fr>

Move doctrine command path inside CI

Signed-off-by: Thomas Citharel <tcit@tcit.fr>

Move abstract migration class to correct namespace and remove unused command

Signed-off-by: Thomas Citharel <tcit@tcit.fr>

CS

Signed-off-by: Thomas Citharel <tcit@tcit.fr>

Check for legacy migration table existence

Signed-off-by: Thomas Citharel <tcit@tcit.fr>

Check if legacy migration table exists before deleting it

Signed-off-by: Thomas Citharel <tcit@tcit.fr>

Add messages for skipped migrations and fix an issue with MySQL ERR_NO_DATE Migration

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2018-04-18 16:16:22 +02:00
parent c4e9cb59d3
commit 006a191544
No known key found for this signature in database
GPG Key ID: A061B9DDE0CA0773
59 changed files with 3238 additions and 1950 deletions

1
.gitignore vendored
View File

@ -24,3 +24,4 @@ Thumbs.db
.project .project
.idea/ .idea/
*.iml *.iml
test_database.sqlite

View File

@ -12,6 +12,7 @@ test:
- composer install -o --no-interaction --no-progress --prefer-dist - composer install -o --no-interaction --no-progress --prefer-dist
- mkdir tpl_c - mkdir tpl_c
- php vendor/bin/php-cs-fixer fix --verbose --dry-run - php vendor/bin/php-cs-fixer fix --verbose --dry-run
- APP_ENV=test bin/doctrine migrations:migrate --no-interaction -vvv
- vendor/bin/phpunit --bootstrap app/tests/bootstrap.php --debug app/tests - vendor/bin/phpunit --bootstrap app/tests/bootstrap.php --debug app/tests
cache: cache:
paths: paths:

View File

@ -17,116 +17,64 @@
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft) * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/ */
use Framadate\Migration\AddColumn_collect_mail_In_poll; use Doctrine\DBAL\Migrations\Configuration\Configuration;
use Framadate\Migration\AddColumn_hidden_In_poll_For_0_9; use Doctrine\DBAL\Migrations\Migration;
use Framadate\Migration\AddColumn_mail_In_vote; use Doctrine\DBAL\Migrations\OutputWriter;
use Framadate\Migration\AddColumn_receiveNewComments_For_0_9; use Doctrine\DBAL\Migrations\Tools\Console\Helper\MigrationStatusInfosHelper;
use Framadate\Migration\AddColumn_uniqId_In_vote_For_0_9;
use Framadate\Migration\AddColumn_ValueMax_In_poll_For_1_1;
use Framadate\Migration\AddColumns_password_hash_And_results_publicly_visible_In_poll_For_0_9;
use Framadate\Migration\Alter_Comment_table_adding_date;
use Framadate\Migration\Alter_Comment_table_for_name_length;
use Framadate\Migration\Fix_MySQL_No_Zero_Date;
use Framadate\Migration\From_0_0_to_0_8_Migration;
use Framadate\Migration\From_0_8_to_0_9_Migration;
use Framadate\Migration\Generate_uniqId_for_old_votes;
use Framadate\Migration\Increase_pollId_size;
use Framadate\Migration\Migration;
use Framadate\Migration\RPadVotes_from_0_8;
use Framadate\Utils; use Framadate\Utils;
include_once __DIR__ . '/../app/inc/init.php'; require_once __DIR__ . '/../app/inc/init.php';
set_time_limit(300); class MigrationLogger {
private $log;
// List a Migration sub classes to execute public function __construct()
$migrations = [ {
new From_0_0_to_0_8_Migration(), $this->log = '';
new From_0_8_to_0_9_Migration(),
new AddColumn_receiveNewComments_For_0_9(),
new AddColumn_uniqId_In_vote_For_0_9(),
new AddColumn_hidden_In_poll_For_0_9(),
new AddColumn_ValueMax_In_poll_For_1_1(),
new Generate_uniqId_for_old_votes(),
new RPadVotes_from_0_8(),
new Alter_Comment_table_for_name_length(),
new Alter_Comment_table_adding_date(),
new AddColumns_password_hash_And_results_publicly_visible_In_poll_For_0_9(),
new Increase_pollId_size(),
new AddColumn_ValueMax_In_poll_For_1_1(),
new Fix_MySQL_No_Zero_Date(),
new AddColumn_mail_In_vote(),
new AddColumn_collect_mail_In_poll()
];
// ---------------------------------------
// Check if MIGRATION_TABLE already exists
/** @var \Framadate\FramaDB $connect */
$tables = $connect->allTables();
$pdo = $connect->getPDO();
$prefixedMigrationTable = Utils::table(MIGRATION_TABLE);
if (!in_array($prefixedMigrationTable, $tables, true)) {
$pdo->exec('
CREATE TABLE IF NOT EXISTS `' . $prefixedMigrationTable . '` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` TEXT NOT NULL,
`execute_date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
)
ENGINE = MyISAM
DEFAULT CHARSET = utf8;');
}
$selectStmt = $pdo->prepare('SELECT id FROM `' . $prefixedMigrationTable . '` WHERE name=?');
$insertStmt = $pdo->prepare('INSERT INTO `' . $prefixedMigrationTable . '` (name) VALUES (?)');
$countSucceeded = 0;
$countFailed = 0;
$countSkipped = 0;
// Loop on every Migration sub classes
$success = [];
$fail = [];
foreach ($migrations as $migration) {
$className = get_class($migration);
// Check if $className is a Migration sub class
if (!$migration instanceof Migration) {
$smarty->assign('error', 'The class ' . $className . ' is not a sub class of Framadate\\Migration\\Migration.');
$smarty->display('error.tpl');
exit;
} }
// Check if the Migration is already executed public function addLine($message)
$selectStmt->execute([$className]); {
$executed = $selectStmt->rowCount(); $this->log .= $message . "\n";
$selectStmt->closeCursor(); }
if (!$executed && $migration->preCondition($pdo)) { public function getLog()
$migration->execute($pdo); {
if ($insertStmt->execute([$className])) { return $this->log;
$countSucceeded++;
$success[] = $migration->description();
} else {
$countFailed++;
$fail[] = $migration->description();
}
} else {
$countSkipped++;
} }
} }
$countTotal = $countSucceeded + $countFailed + $countSkipped; $executing = false;
$migration = null;
$output = '';
$smarty->assign('success', $success); if (isset($_POST['execute'])) {
$smarty->assign('fail', $fail); $executing = true;
}
$smarty->assign('countSucceeded', $countSucceeded); $migrationsDirectory = __DIR__ . '/../app/classes/Framadate/Migrations';
$smarty->assign('countFailed', $countFailed); $log = new MigrationLogger();
$smarty->assign('countSkipped', $countSkipped);
$smarty->assign('countTotal', $countTotal);
$smarty->assign('time', $total_time = round((microtime(true)-$_SERVER['REQUEST_TIME_FLOAT']), 4));
$configuration = new Configuration($connect, new OutputWriter(function ($message) use ($log) {
$log->addLine($message);
}));
$configuration->setMigrationsTableName(Utils::table(MIGRATION_TABLE) . '_new');
$configuration->setMigrationsDirectory($migrationsDirectory);
$configuration->setMigrationsNamespace('DoctrineMigrations');
$configuration->registerMigrationsFromDirectory($migrationsDirectory);
if ($executing) {
$migration = new Migration($configuration);
$migration->migrate();
$output = trim(strip_tags($log->getLog()));
}
$infos = (new MigrationStatusInfosHelper($configuration))->getMigrationsInfos();
$smarty->assign('countTotal', $infos['Available Migrations']);
$smarty->assign('countExecuted', $infos['Executed Migrations']);
$smarty->assign('countWaiting', $infos['New Migrations']);
$smarty->assign('executing', $executing);
$smarty->assign('title', __('Admin', 'Migration')); $smarty->assign('title', __('Admin', 'Migration'));
$smarty->assign('output', $output);
$smarty->assign('time', round((microtime(true)-$_SERVER['REQUEST_TIME_FLOAT']), 4));
$smarty->display('admin/migration.tpl'); $smarty->display('admin/migration.tpl');

View File

@ -0,0 +1,54 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace Framadate;
use Doctrine\DBAL\Migrations\AbstractMigration as DoctrineAbstractMigration;
use Doctrine\DBAL\Schema\Schema;
abstract class AbstractMigration extends DoctrineAbstractMigration
{
/**
* @param Schema $schema
* @param $class
* @throws \Doctrine\DBAL\DBALException
* @throws \Doctrine\DBAL\Schema\SchemaException
* @return bool
*/
public function legacyCheck(Schema $schema, $class)
{
/**
* If there's no legacy table, we can go on
*/
if (!$schema->hasTable(Utils::table(MIGRATION_TABLE))) {
return false;
}
$migration_table = $schema->getTable(Utils::table(MIGRATION_TABLE));
/**
* We check the migration table
*/
if ($migration_table->hasColumn('name')) {
/** @var $stmt \Doctrine\DBAL\Driver\Statement */
$stmt = $this->connection->prepare('SELECT * FROM ' . Utils::table(MIGRATION_TABLE) . ' WHERE name = ?');
$stmt->execute([$class]);
return $stmt->rowCount() > 0;
}
return false;
}
}

View File

@ -42,11 +42,25 @@ class FramaDB {
/** /**
* Find all tables in database. * Find all tables in database.
* *
* @return array The array of table names * @return array|false The array of table names
*/ */
function allTables() { public function allTables()
$result = $this->pdo->query('SHOW TABLES'); {
$schemas = $result->fetchAll(\PDO::FETCH_COLUMN); $driver = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
switch ($driver) {
case 'mysql':
$result = $this->pdo->query('SHOW TABLES');
$schemas = $result->fetchAll(\PDO::FETCH_COLUMN);
break;
case 'pgsql':
$result = $this->pdo->query(
"SELECT table_name FROM information_schema.tables WHERE table_schema='public'"
);
$schemas = $result->fetchAll(\PDO::FETCH_COLUMN);
break;
default:
return false;
}
return $schemas; return $schemas;
} }

View File

@ -1,75 +0,0 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace Framadate\Migration;
use Framadate\Utils;
/**
* This migration adds the field hidden on the poll table.
*
* @package Framadate\Migration
* @version 0.9
*/
class AddColumn_hidden_In_poll_For_0_9 implements Migration {
function __construct() {
}
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
function description() {
return 'Add column "hidden" in table "vote" for version 0.9';
}
/**
* This method could check if the execute method should be called.
* It is called before the execute method.
*
* @param \PDO $pdo The connection to database
* @return bool true is the Migration should be executed.
*/
function preCondition(\PDO $pdo) {
$stmt = $pdo->query('SHOW TABLES');
$tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
// Check if tables of v0.9 are presents
$diff = array_diff([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')], $tables);
return count($diff) === 0;
}
/**
* This method is called only one time in the migration page.
*
* @param \PDO $pdo The connection to database
* @return bool true is the execution succeeded
*/
function execute(\PDO $pdo) {
$this->alterPollTable($pdo);
return true;
}
private function alterPollTable(\PDO $pdo) {
$pdo->exec('
ALTER TABLE `' . Utils::table('poll') . '`
ADD `hidden` TINYINT( 1 ) NOT NULL DEFAULT "0"');
}
}

View File

@ -1,76 +0,0 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace Framadate\Migration;
use Framadate\Utils;
/**
* This migration adds the field receiveNewComments on the poll table.
*
* @package Framadate\Migration
* @version 0.9
*/
class AddColumn_receiveNewComments_For_0_9 implements Migration {
function __construct() {
}
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
function description() {
return 'Add column "receiveNewComments" for version 0.9';
}
/**
* This method could check if the execute method should be called.
* It is called before the execute method.
*
* @param \PDO $pdo The connection to database
* @return bool true is the Migration should be executed.
*/
function preCondition(\PDO $pdo) {
$stmt = $pdo->query('SHOW TABLES');
$tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
// Check if tables of v0.9 are presents
$diff = array_diff([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')], $tables);
return count($diff) === 0;
}
/**
* This method is called only one time in the migration page.
*
* @param \PDO $pdo The connection to database
* @return bool true is the execution succeeded
*/
function execute(\PDO $pdo) {
$this->alterPollTable($pdo);
return true;
}
private function alterPollTable(\PDO $pdo) {
$pdo->exec('
ALTER TABLE `' . Utils::table('poll') . '`
ADD `receiveNewComments` TINYINT(1) DEFAULT \'0\'
AFTER `receiveNewVotes`');
}
}

View File

@ -1,77 +0,0 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace Framadate\Migration;
use Framadate\Utils;
/**
* This migration adds the field uniqId on the vote table.
*
* @package Framadate\Migration
* @version 0.9
*/
class AddColumn_uniqId_In_vote_For_0_9 implements Migration {
function __construct() {
}
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
function description() {
return 'Add column "uniqId" in table "vote" for version 0.9';
}
/**
* This method could check if the execute method should be called.
* It is called before the execute method.
*
* @param \PDO $pdo The connection to database
* @return bool true is the Migration should be executed.
*/
function preCondition(\PDO $pdo) {
$stmt = $pdo->query('SHOW TABLES');
$tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
// Check if tables of v0.9 are presents
$diff = array_diff([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')], $tables);
return count($diff) === 0;
}
/**
* This method is called only one time in the migration page.
*
* @param \PDO $pdo The connection to database
* @return bool true is the execution succeeded
*/
function execute(\PDO $pdo) {
$this->alterPollTable($pdo);
return true;
}
private function alterPollTable(\PDO $pdo) {
$pdo->exec('
ALTER TABLE `' . Utils::table('vote') . '`
ADD `uniqId` CHAR(16) NOT NULL
AFTER `id`,
ADD INDEX (`uniqId`) ;');
}
}

View File

@ -1,76 +0,0 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace Framadate\Migration;
use Framadate\Utils;
/**
* This migration adds the fields password_hash and results_publicly_visible on the poll table.
*
* @package Framadate\Migration
* @version 0.9
*/
class AddColumns_password_hash_And_results_publicly_visible_In_poll_For_0_9 implements Migration {
function __construct() {
}
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
function description() {
return 'Add columns "password_hash" and "results_publicly_visible" in table "vote" for version 0.9';
}
/**
* This method could check if the execute method should be called.
* It is called before the execute method.
*
* @param \PDO $pdo The connection to database
* @return bool true is the Migration should be executed.
*/
function preCondition(\PDO $pdo) {
$stmt = $pdo->query('SHOW TABLES');
$tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
// Check if tables of v0.9 are presents
$diff = array_diff([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')], $tables);
return count($diff) === 0;
}
/**
* This method is called only one time in the migration page.
*
* @param \PDO $pdo The connection to database
* @return bool true is the execution succeeded
*/
function execute(\PDO $pdo) {
$this->alterPollTable($pdo);
return true;
}
private function alterPollTable(\PDO $pdo) {
$pdo->exec('
ALTER TABLE `' . Utils::table('poll') . '`
ADD `password_hash` VARCHAR(255) NULL DEFAULT NULL ,
ADD `results_publicly_visible` TINYINT(1) NULL DEFAULT NULL');
}
}

View File

@ -1,70 +0,0 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace Framadate\Migration;
use Framadate\Utils;
/**
* This migration sets Poll.end_date to NULL by default
*
* @package Framadate\Migration
* @version 1.1
*/
class Fix_MySQL_No_Zero_Date implements Migration {
function __construct() {
}
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
function description() {
return 'Sets Poll end_date to NULL by default (work around MySQL NO_ZERO_DATE)';
}
/**
* This method could check if the execute method should be called.
* It is called before the execute method.
*
* @param \PDO $pdo The connection to database
* @return bool true if the Migration should be executed.
*/
function preCondition(\PDO $pdo) {
$stmt = $pdo->prepare("SELECT Column_Default from Information_Schema.Columns where Table_Name = ? AND Column_Name = ?;");
$stmt->bindValue(1, Utils::table('poll'));
$stmt->bindValue(2, 'end_date');
$stmt->execute();
$default = $stmt->fetch(\PDO::FETCH_COLUMN);
$driver_name = $pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
return $default !== null && $driver_name === 'mysql';
}
/**
* This method is called only one time in the migration page.
*
* @param \PDO $pdo The connection to database
* @return bool|void if the execution succeeded
*/
function execute(\PDO $pdo) {
$pdo->exec('ALTER TABLE ' . Utils::table('poll') . ' MODIFY end_date TIMESTAMP NULL DEFAULT NULL;');
}
}

View File

@ -1,108 +0,0 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace Framadate\Migration;
use Framadate\Utils;
/**
* Class From_0_0_to_0_8_Migration
*
* @package Framadate\Migration
* @version 0.8
*/
class From_0_0_to_0_8_Migration implements Migration {
function __construct() {
}
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
function description() {
return 'First installation of the Framadate application (v0.8)';
}
/**
* This method could check if the execute method should be called.
* It is called before the execute method.
*
* @param \PDO $pdo The connection to database
* @return bool true is the Migration should be executed.
*/
function preCondition(\PDO $pdo) {
$stmt = $pdo->query('SHOW TABLES like \'' . TABLENAME_PREFIX . '%\''); //issue187 : pouvoir installer framadate dans une base contenant d'autres tables.
$tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
// Check if there is no tables but the MIGRATION_TABLE one
$diff = array_diff($tables, [Utils::table(MIGRATION_TABLE)]);
return count($diff) === 0;
}
/**
* This method is called only one time in the migration page.
*
* @param \PDO $pdo The connection to database
* @return bool true is the execution succeeded
*/
function execute(\PDO $pdo) {
$pdo->exec('
CREATE TABLE IF NOT EXISTS `sondage` (
`id_sondage` char(16) NOT NULL,
`commentaires` text,
`mail_admin` varchar(128) DEFAULT NULL,
`nom_admin` varchar(64) DEFAULT NULL,
`titre` text,
`id_sondage_admin` char(24) DEFAULT NULL,
`date_creation` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`date_fin` timestamp NULL DEFAULT NULL,
`format` varchar(2) DEFAULT NULL,
`mailsonde` tinyint(1) DEFAULT \'0\',
`statut` int(11) NOT NULL DEFAULT \'1\' COMMENT \'1 = actif ; 0 = inactif ; \',
UNIQUE KEY `id_sondage` (`id_sondage`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;');
$pdo->exec('
CREATE TABLE IF NOT EXISTS `sujet_studs` (
`id_sondage` char(16) NOT NULL,
`sujet` text,
KEY `id_sondage` (`id_sondage`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;');
$pdo->exec('
CREATE TABLE IF NOT EXISTS `comments` (
`id_comment` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_sondage` char(16) NOT NULL,
`comment` text NOT NULL,
`usercomment` text,
PRIMARY KEY (`id_comment`),
KEY `id_sondage` (`id_sondage`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;');
$pdo->exec('
CREATE TABLE IF NOT EXISTS `user_studs` (
`id_users` int(11) unsigned NOT NULL AUTO_INCREMENT,
`nom` varchar(64) NOT NULL,
`id_sondage` char(16) NOT NULL,
`reponses` text NOT NULL,
PRIMARY KEY (`id_users`),
KEY `id_sondage` (`id_sondage`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;');
}
}

View File

@ -1,292 +0,0 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace Framadate\Migration;
use Framadate\Utils;
/**
* This class executes the aciton in database to migrate data from version 0.8 to 0.9.
*
* @package Framadate\Migration
* @version 0.9
*/
class From_0_8_to_0_9_Migration implements Migration {
function __construct() {
}
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
function description() {
return 'From 0.8 to 0.9';
}
/**
* This method could check if the execute method should be called.
* It is called before the execute method.
*
* @param \PDO $pdo The connection to database
* @return bool true is the Migration should be executed.
*/
function preCondition(\PDO $pdo) {
$stmt = $pdo->query('SHOW TABLES');
$tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
// Check if tables of v0.8 are presents
$diff = array_diff(['sondage', 'sujet_studs', 'comments', 'user_studs'], $tables);
return count($diff) === 0;
}
/**
* This method is called only one time in the migration page.
*
* @param \PDO $pdo The connection to database
* @return bool true is the execution succeeded
*/
function execute(\PDO $pdo) {
$this->createPollTable($pdo);
$this->createCommentTable($pdo);
$this->createSlotTable($pdo);
$this->createVoteTable($pdo);
$pdo->beginTransaction();
$this->migrateFromSondageToPoll($pdo);
$this->migrateFromCommentsToComment($pdo);
$this->migrateFromSujetStudsToSlot($pdo);
$this->migrateFromUserStudsToVote($pdo);
$pdo->commit();
$this->dropOldTables($pdo);
return true;
}
private function createPollTable(\PDO $pdo) {
$pdo->exec('
CREATE TABLE IF NOT EXISTS `' . Utils::table('poll') . '` (
`id` CHAR(16) NOT NULL,
`admin_id` CHAR(24) NOT NULL,
`title` TEXT NOT NULL,
`description` TEXT,
`admin_name` VARCHAR(64) DEFAULT NULL,
`admin_mail` VARCHAR(128) DEFAULT NULL,
`creation_date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`end_date` TIMESTAMP NULL DEFAULT NULL,
`format` VARCHAR(1) DEFAULT NULL,
`editable` TINYINT(1) DEFAULT \'0\',
`receiveNewVotes` TINYINT(1) DEFAULT \'0\',
`active` TINYINT(1) DEFAULT \'1\',
PRIMARY KEY (`id`)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8');
}
private function migrateFromSondageToPoll(\PDO $pdo) {
$select = $pdo->query('
SELECT
`id_sondage`,
`id_sondage_admin`,
`titre`,
`commentaires`,
`nom_admin`,
`mail_admin`,
`date_creation`,
`date_fin`,
SUBSTR(`format`, 1, 1) AS `format`,
CASE SUBSTR(`format`, 2, 1)
WHEN \'+\' THEN 1
ELSE 0 END AS `editable`,
`mailsonde`,
CASE SUBSTR(`format`, 2, 1)
WHEN \'-\' THEN 0
ELSE 1 END AS `active`
FROM sondage');
$insert = $pdo->prepare('
INSERT INTO `' . Utils::table('poll') . '`
(`id`, `admin_id`, `title`, `description`, `admin_name`, `admin_mail`, `creation_date`, `end_date`, `format`, `editable`, `receiveNewVotes`, `active`)
VALUE (?,?,?,?,?,?,?,?,?,?,?,?)');
while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
$insert->execute([
$row->id_sondage,
$row->id_sondage_admin,
$this->unescape($row->titre),
$this->unescape($row->commentaires),
$this->unescape($row->nom_admin),
$this->unescape($row->mail_admin),
$row->date_creation,
$row->date_fin,
$row->format,
$row->editable,
$row->mailsonde,
$row->active
]);
}
}
private function createSlotTable(\PDO $pdo) {
$pdo->exec('
CREATE TABLE IF NOT EXISTS `' . Utils::table('slot') . '` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`poll_id` CHAR(16) NOT NULL,
`title` TEXT,
`moments` TEXT,
PRIMARY KEY (`id`),
KEY `poll_id` (`poll_id`)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8');
}
private function migrateFromSujetStudsToSlot(\PDO $pdo) {
$stmt = $pdo->query('SELECT * FROM sujet_studs');
$sujets = $stmt->fetchAll();
$slots = [];
foreach ($sujets as $sujet) {
$newSlots = $this->transformSujetToSlot($sujet);
foreach ($newSlots as $newSlot) {
$slots[] = $newSlot;
}
}
$prepared = $pdo->prepare('INSERT INTO ' . Utils::table('slot') . ' (`poll_id`, `title`, `moments`) VALUE (?,?,?)');
foreach ($slots as $slot) {
$prepared->execute([
$slot->poll_id,
$this->unescape($slot->title),
!empty($slot->moments) ? $this->unescape($slot->moments) : null
]);
}
}
private function createCommentTable(\PDO $pdo) {
$pdo->exec('
CREATE TABLE IF NOT EXISTS `' . Utils::table('comment') . '` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`poll_id` CHAR(16) NOT NULL,
`name` TEXT,
`comment` TEXT NOT NULL,
PRIMARY KEY (`id`),
KEY `poll_id` (`poll_id`)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8');
}
private function migrateFromCommentsToComment(\PDO $pdo) {
$select = $pdo->query('
SELECT
`id_sondage`,
`usercomment`,
`comment`
FROM `comments`');
$insert = $pdo->prepare('
INSERT INTO `' . Utils::table('comment') . '` (`poll_id`, `name`, `comment`)
VALUE (?,?,?)');
while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
$insert->execute([
$row->id_sondage,
$this->unescape($row->usercomment),
$this->unescape($row->comment)
]);
}
}
private function createVoteTable(\PDO $pdo) {
$pdo->exec('
CREATE TABLE IF NOT EXISTS `' . Utils::table('vote') . '` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`poll_id` CHAR(16) NOT NULL,
`name` VARCHAR(64) NOT NULL,
`choices` TEXT NOT NULL,
PRIMARY KEY (`id`),
KEY `poll_id` (`poll_id`)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8');
}
private function migrateFromUserStudsToVote(\PDO $pdo) {
$select = $pdo->query('
SELECT
`id_sondage`,
`nom`,
REPLACE(REPLACE(REPLACE(`reponses`, 1, \'X\'), 2, 1), \'X\', 2) reponses
FROM `user_studs`');
$insert = $pdo->prepare('
INSERT INTO `' . Utils::table('vote') . '` (`poll_id`, `name`, `choices`)
VALUE (?,?,?)');
while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
$insert->execute([
$row->id_sondage,
$this->unescape($row->nom),
$row->reponses
]);
}
}
private function transformSujetToSlot($sujet) {
$slots = [];
$ex = explode(',', $sujet->sujet);
$isDatePoll = strpos($sujet->sujet, '@');
$lastSlot = null;
foreach ($ex as $atomicSlot) {
if ($isDatePoll === false) { // Classic poll
$slot = new \stdClass();
$slot->poll_id = $sujet->id_sondage;
$slot->title = $atomicSlot;
$slots[] = $slot;
} else { // Date poll
$values = explode('@', $atomicSlot);
if ($lastSlot === null || $lastSlot->title !== $values[0]) {
$lastSlot = new \stdClass();
$lastSlot->poll_id = $sujet->id_sondage;
$lastSlot->title = $values[0];
$lastSlot->moments = count($values) === 2 ? $values[1] : '-';
$slots[] = $lastSlot;
} else {
$lastSlot->moments .= ',' . (count($values) === 2 ? $values[1] : '-');
}
}
}
return $slots;
}
private function dropOldTables(\PDO $pdo) {
$pdo->exec('DROP TABLE `comments`');
$pdo->exec('DROP TABLE `sujet_studs`');
$pdo->exec('DROP TABLE `user_studs`');
$pdo->exec('DROP TABLE `sondage`');
}
private function unescape($value) {
return stripslashes(html_entity_decode($value, ENT_QUOTES));
}
}

View File

@ -1,80 +0,0 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace Framadate\Migration;
use Framadate\Security\Token;
use Framadate\Utils;
/**
* This migration generate uniqId for all legacy votes.
*
* @package Framadate\Migration
* @version 0.9
*/
class Generate_uniqId_for_old_votes implements Migration {
function __construct() {
}
function description() {
return 'Generate "uniqId" in "vote" table for all legacy votes';
}
function preCondition(\PDO $pdo) {
$stmt = $pdo->query('SHOW TABLES');
$tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
// Check if tables of v0.9 are presents
$diff = array_diff([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')], $tables);
return count($diff) === 0;
}
/**
* This methode is called only one time in the migration page.
*
* @param \PDO $pdo The connection to database
* @return bool true is the execution succeeded
*/
function execute(\PDO $pdo) {
$pdo->beginTransaction();
$this->generateUniqIdsForEmptyOnes($pdo);
$pdo->commit();
return true;
}
private function generateUniqIdsForEmptyOnes($pdo) {
$select = $pdo->query('
SELECT `id`
FROM `' . Utils::table('vote') . '`
WHERE `uniqid` = \'\'');
$update = $pdo->prepare('
UPDATE `' . Utils::table('vote') . '`
SET `uniqid` = :uniqid
WHERE `id` = :id');
while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
$token = Token::getToken(16);
$update->execute([
'uniqid' => $token,
'id' => $row->id
]);
}
}
}

View File

@ -1,66 +0,0 @@
<?php
namespace Framadate\Migration;
use Framadate\Utils;
class Increase_pollId_size implements Migration {
function __construct() {
}
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
function description() {
return 'Increase the size of id column in poll table';
}
/**
* This method could check if the execute method should be called.
* It is called before the execute method.
*
* @param \PDO $pdo The connection to database
* @return bool true if the Migration should be executed
*/
function preCondition(\PDO $pdo) {
return true;
}
/**
* This methode is called only one time in the migration page.
*
* @param \PDO $pdo The connection to database
* @return bool true if the execution succeeded
*/
function execute(\PDO $pdo) {
$this->alterCommentTable($pdo);
$this->alterPollTable($pdo);
$this->alterSlotTable($pdo);
$this->alterVoteTable($pdo);
}
private function alterCommentTable(\PDO $pdo) {
$pdo->exec('
ALTER TABLE `' . Utils::table('comment') . '`
CHANGE `poll_id` `poll_id` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;');
}
private function alterPollTable(\PDO $pdo) {
$pdo->exec('
ALTER TABLE `' . Utils::table('poll') . '`
CHANGE `id` `id` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;');
}
private function alterSlotTable(\PDO $pdo) {
$pdo->exec('
ALTER TABLE `' . Utils::table('slot') . '`
CHANGE `poll_id` `poll_id` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;');
}
private function alterVoteTable(\PDO $pdo) {
$pdo->exec('
ALTER TABLE `' . Utils::table('vote') . '`
CHANGE `poll_id` `poll_id` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;');
}
}

View File

@ -1,66 +0,0 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace Framadate\Migration;
use Framadate\Utils;
/**
* This migration RPad votes from version 0.8.
* Because some votes does not have enough values for their poll.
*
* @package Framadate\Migration
* @version 0.9
*/
class RPadVotes_from_0_8 implements Migration {
function description() {
return 'RPad votes from version 0.8.';
}
function preCondition(\PDO $pdo) {
$stmt = $pdo->query('SHOW TABLES');
$tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
// Check if tables of v0.9 are presents
$diff = array_diff([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')], $tables);
return count($diff) === 0;
}
function execute(\PDO $pdo) {
$pdo->beginTransaction();
$this->rpadVotes($pdo);
$pdo->commit();
return true;
}
private function rpadVotes($pdo) {
$pdo->exec('UPDATE ' . Utils::table('vote') . ' fv
INNER JOIN (
SELECT v.id, RPAD(v.choices, inn.slots_count, \'0\') new_choices
FROM ' . Utils::table('vote') . ' v
INNER JOIN
(SELECT s.poll_id, SUM(IFNULL(LENGTH(s.moments) - LENGTH(REPLACE(s.moments, \',\', \'\')) + 1, 1)) slots_count
FROM ' . Utils::table('slot') . ' s
GROUP BY s.poll_id
ORDER BY s.poll_id) inn ON inn.poll_id = v.poll_id
WHERE LENGTH(v.choices) != inn.slots_count
) computed ON fv.id = computed.id
SET fv.choices = computed.new_choices');
}
}

View File

@ -0,0 +1,99 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Framadate\AbstractMigration;
/**
* Class From_0_0_to_0_8_Migration
*
* @package Framadate\Migration
* @version 0.8
*/
class Version20150101000000 extends AbstractMigration
{
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
public function description()
{
return 'First installation of the Framadate application (v0.8)';
}
/**
* This method is called only one time in the migration page.
*
* @param Schema $schema
* @throws \Doctrine\DBAL\DBALException
* @throws \Doctrine\DBAL\Migrations\SkipMigrationException
* @throws \Doctrine\DBAL\Schema\SchemaException
* @return void true is the execution succeeded
*/
public function up(Schema $schema)
{
$this->skipIf($this->legacyCheck($schema,'Framadate\Migration\From_0_0_to_0_8_Migration'), 'Migration has been executed in an earlier database migration system');
$sondage = $schema->createTable('sondage');
$sondage->addColumn('id_sondage', 'string');
$sondage->addColumn('commentaires', 'text');
$sondage->addColumn('mail_admin', 'string', ['notnull' => false]);
$sondage->addColumn('nom_admin', 'string', ['notnull' => false]);
$sondage->addColumn('titre', 'text');
$sondage->addColumn('id_sondage_admin', 'string', ['notnull' => false]);
$sondage->addColumn('date_creation', 'datetime', ['default' => (new \DateTime())->format('Y-m-d H:i:s')]);
$sondage->addColumn('date_fin', 'datetime', ['notnull' => false]);
$sondage->addColumn('format', 'string', ['notnull' => false]);
$sondage->addColumn('mailsonde', 'boolean', ['default' => false]);
$sondage->addColumn('statut', 'integer', ['default' => '1']);
$sondage->addUniqueIndex(['id_sondage'], 'sondage_index_id_sondage');
$sujetStuds = $schema->createTable('sujet_studs');
$sujetStuds->addColumn('id_sondage', 'string');
$sujetStuds->addColumn('sujet', 'text');
$sujetStuds->addIndex(['id_sondage'], 'sujet_studs_index_id_sondage');
$comments = $schema->createTable('comments');
$schema->createSequence('comments_seq');
$comments->addColumn('id_comment', 'integer', ['autoincrement' => true]);
$comments->addColumn('id_sondage', 'string');
$comments->addColumn('comment', 'text');
$comments->addColumn('usercomment', 'text', ['notnull' => false]);
$comments->addUniqueIndex(['id_comment'], 'comments_index_id_comment');
$comments->addIndex(['id_sondage'], 'comments_index_id_sondage');
$userStuds = $schema->createTable('user_studs');
$schema->createSequence('user_studs_seq');
$userStuds->addColumn('id_users', 'integer', ['autoincrement' => true]);
$userStuds->addColumn('nom', 'string');
$userStuds->addColumn('id_sondage', 'string');
$userStuds->addColumn('reponses', 'text');
$userStuds->addUniqueIndex(['id_users'], 'user_studs_index_id_users');
$userStuds->addIndex(['id_sondage'], 'user_studs_index_id_sondage');
}
public function down(Schema $schema)
{
$this->addSql('DROP TABLE sondage');
$this->addSql('DROP TABLE sujet_studs');
$this->addSql('DROP TABLE comments');
$this->addSql('DROP TABLE user_studs');
}
}

View File

@ -0,0 +1,160 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Framadate\AbstractMigration;
use Framadate\Utils;
/**
* This class executes the aciton in database to migrate data from version 0.8 to 0.9.
*
* @package Framadate\Migration
* @version 0.9
*/
class Version20150102000000 extends AbstractMigration
{
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
public function description()
{
return 'From 0.8 to 0.9 first part';
}
/**
* @param Schema $schema
* @throws \Doctrine\DBAL\DBALException
* @throws \Doctrine\DBAL\Migrations\SkipMigrationException
* @throws \Doctrine\DBAL\Schema\SchemaException
*/
public function up(Schema $schema)
{
$this->skipIf($this->legacyCheck($schema,'Framadate\Migration\From_0_8_to_0_9_Migration'), 'Migration has been executed in an earlier database migration system');
foreach (['sondage', 'sujet_studs', 'comments', 'user_studs'] as $table) {
$this->skipIf(!$schema->hasTable($table), 'Missing table ' . $table);
}
$this->createPollTable($schema);
$this->createCommentTable($schema);
$this->createSlotTable($schema);
$this->createVoteTable($schema);
}
public function down(Schema $schema)
{
$sondage = $schema->createTable('sondage');
$sondage->addColumn('id_sondage', 'string');
$sondage->addColumn('commentaires', 'text');
$sondage->addColumn('mail_admin', 'string', ['notnull' => false]);
$sondage->addColumn('nom_admin', 'string', ['notnull' => false]);
$sondage->addColumn('titre', 'text');
$sondage->addColumn('id_sondage_admin', 'string', ['notnull' => false]);
$sondage->addColumn('date_creation', 'datetime', ['default' => (new \DateTime())->format('Y-m-d H:i:s')]);
$sondage->addColumn('date_fin', 'datetime', ['notnull' => false]);
$sondage->addColumn('format', 'string', ['notnull' => false]);
$sondage->addColumn('mailsonde', 'boolean', ['default' => false]);
$sondage->addColumn('statut', 'integer', ['default' => '1']);
$sondage->addUniqueIndex(['id_sondage'], 'sondage_index_id_sondage');
$sujetStuds = $schema->createTable('sujet_studs');
$sujetStuds->addColumn('id_sondage', 'string');
$sujetStuds->addColumn('sujet', 'text');
$sujetStuds->addIndex(['id_sondage'], 'sujet_studs_index_id_sondage');
$comments = $schema->createTable('comments');
$schema->createSequence('comments_seq');
$comments->addColumn('id_comment', 'integer', ['autoincrement' => true]);
$comments->addColumn('id_sondage', 'string');
$comments->addColumn('comment', 'text');
$comments->addColumn('usercomment', 'text', ['notnull' => false]);
$comments->addUniqueIndex(['id_comment'], 'comments_index_id_comment');
$comments->addIndex(['id_sondage'], 'comments_index_id_sondage');
$userStuds = $schema->createTable('user_studs');
$schema->createSequence('user_studs_seq');
$userStuds->addColumn('id_users', 'integer', ['autoincrement' => true]);
$userStuds->addColumn('nom', 'string');
$userStuds->addColumn('id_sondage', 'string');
$userStuds->addColumn('reponses', 'text');
$userStuds->addUniqueIndex(['id_users'], 'user_studs_index_id_users');
$userStuds->addIndex(['id_sondage'], 'user_studs_index_id_sondage');
$schema->dropTable(Utils::table('poll'));
$schema->dropTable(Utils::table('comment'));
$schema->dropTable(Utils::table('vote'));
$schema->dropTable(Utils::table('slot'));
}
private function createPollTable(Schema $schema)
{
$poll = $schema->createTable(Utils::table('poll'));
$poll->addColumn('id', 'string');
$poll->addColumn('admin_id', 'string');
$poll->addColumn('title', 'text');
$poll->addColumn('description', 'text', ['notnull' => false]);
$poll->addColumn('admin_name', 'string');
$poll->addColumn('admin_mail', 'string', ['notnull' => false]);
$poll->addColumn('creation_date', 'datetime', ['default' => (new \DateTime())->format('Y-m-d H:i:s')]);
$poll->addColumn('end_date', 'datetime', ['notnull' => false]);
$poll->addColumn('format', 'string', ['default' => null, 'notnull' => false]);
$poll->addColumn('editable', 'integer', ['default' => 0]);
$poll->addColumn('receiveNewVotes', 'boolean', ['default' => false]);
$poll->addColumn('active', 'boolean', ['default' => true]);
$poll->addUniqueIndex(['id'], 'poll_index_id');
}
private function createSlotTable(Schema $schema)
{
$slot = $schema->createTable(Utils::table('slot'));
$schema->createSequence('slot_seq');
$slot->addColumn('id', 'integer', ['autoincrement' => true]);
$slot->addColumn('poll_id', 'string');
$slot->addColumn('title', 'text');
$slot->addColumn('moments', 'text', ['notnull' => false]);
$slot->addUniqueIndex(['id'], 'slot_index_id');
$slot->addIndex(['poll_id'], 'slot_index_poll_id');
}
private function createCommentTable(Schema $schema)
{
$comment = $schema->createTable(Utils::table('comment'));
$schema->createSequence('comment_seq');
$comment->addColumn('id', 'integer', ['autoincrement' => true]);
$comment->addColumn('poll_id', 'string');
$comment->addColumn('name', 'text', ['notnull' => false]);
$comment->addColumn('comment', 'text');
$comment->addUniqueIndex(['id'], 'comment_index_id');
$comment->addIndex(['poll_id'], 'comment_index_poll_id');
}
private function createVoteTable(Schema $schema)
{
$vote = $schema->createTable(Utils::table('vote'));
$schema->createSequence('vote_seq');
$vote->addColumn('id', 'integer', ['autoincrement' => true]);
$vote->addColumn('poll_id', 'string');
$vote->addColumn('name', 'string');
$vote->addColumn('choices', 'string');
$vote->addUniqueIndex(['id'], 'vote_index_id');
$vote->addIndex(['poll_id'], 'vote_index_poll_id');
}
}

View File

@ -0,0 +1,263 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Framadate\AbstractMigration;
use Framadate\Utils;
/**
* This class executes the aciton in database to migrate data from version 0.8 to 0.9.
*
* @package Framadate\Migration
* @version 0.9
*/
class Version20150102100000 extends AbstractMigration
{
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
public function description()
{
return 'From 0.8 to 0.9 second part';
}
/**
* @param Schema $schema
* @throws \Doctrine\DBAL\DBALException
* @throws \Doctrine\DBAL\Migrations\SkipMigrationException
* @throws \Doctrine\DBAL\Schema\SchemaException
*/
public function up(Schema $schema)
{
$this->skipIf($this->legacyCheck($schema,'Framadate\Migration\From_0_8_to_0_9_Migration'), 'Migration has been executed in an earlier database migration system');
foreach ([Utils::table('poll'), Utils::table('comment'), Utils::table('slot'), Utils::table('vote')] as $table) {
$this->skipIf(!$schema->hasTable($table), 'Missing table ' . $table);
}
$this->migrateFromSondageToPoll();
$this->migrateFromCommentsToComment();
$this->migrateFromSujetStudsToSlot();
//$this->migrateFromUserStudsToVote();
$this->dropOldTables($schema);
}
public function down(Schema $schema)
{
$sondage = $schema->createTable('sondage');
$sondage->addColumn('id_sondage', 'string');
$sondage->addColumn('commentaires', 'text');
$sondage->addColumn('mail_admin', 'string', ['notnull' => false]);
$sondage->addColumn('nom_admin', 'string', ['notnull' => false]);
$sondage->addColumn('titre', 'text');
$sondage->addColumn('id_sondage_admin', 'string', ['notnull' => false]);
$sondage->addColumn('date_creation', 'datetime', ['default' => (new \DateTime())->format('Y-m-d H:i:s')]);
$sondage->addColumn('date_fin', 'datetime', ['notnull' => false]);
$sondage->addColumn('format', 'string', ['notnull' => false]);
$sondage->addColumn('mailsonde', 'boolean', ['default' => false]);
$sondage->addColumn('statut', 'integer', ['default' => '1']);
$sondage->addUniqueIndex(['id_sondage'], 'sondage_index_id_sondage');
$sujetStuds = $schema->createTable('sujet_studs');
$sujetStuds->addColumn('id_sondage', 'string');
$sujetStuds->addColumn('sujet', 'text');
$sujetStuds->addIndex(['id_sondage'], 'sujet_studs_index_id_sondage');
$comments = $schema->createTable('comments');
$schema->createSequence('comments_seq');
$comments->addColumn('id_comment', 'integer', ['autoincrement' => true]);
$comments->addColumn('id_sondage', 'string');
$comments->addColumn('comment', 'text');
$comments->addColumn('usercomment', 'text', ['notnull' => false]);
$comments->addUniqueIndex(['id_comment'], 'comments_index_id_comment');
$comments->addIndex(['id_sondage'], 'comments_index_id_sondage');
$userStuds = $schema->createTable('user_studs');
$schema->createSequence('user_studs_seq');
$userStuds->addColumn('id_users', 'integer', ['autoincrement' => true]);
$userStuds->addColumn('nom', 'string');
$userStuds->addColumn('id_sondage', 'string');
$userStuds->addColumn('reponses', 'text');
$userStuds->addUniqueIndex(['id_users'], 'user_studs_index_id_users');
$userStuds->addIndex(['id_sondage'], 'user_studs_index_id_sondage');
$schema->dropTable(Utils::table('poll'));
$schema->dropTable(Utils::table('comment'));
$schema->dropTable(Utils::table('vote'));
$schema->dropTable(Utils::table('slot'));
}
private function migrateFromSondageToPoll()
{
$select = $this->connection->query('
SELECT
id_sondage,
id_sondage_admin,
titre,
commentaires,
nom_admin,
mail_admin,
date_creation,
date_fin,
SUBSTR(format, 1, 1) AS format,
CASE SUBSTR(format, 2, 1)
WHEN \'+\' THEN 1
ELSE 0 END AS editable,
mailsonde,
CASE SUBSTR(format, 2, 1)
WHEN \'-\' THEN 0
ELSE 1 END AS active
FROM sondage');
$insert = $this->connection->prepare('
INSERT INTO ' . Utils::table('poll') . '
(id, admin_id, title, description, admin_name, admin_mail, creation_date, end_date, format, editable, receiveNewVotes, active)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)');
while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
$insert->execute([
$row->id_sondage,
$row->id_sondage_admin,
$this->unescape($row->titre),
$this->unescape($row->commentaires),
$this->unescape($row->nom_admin),
$this->unescape($row->mail_admin),
$row->date_creation,
$row->date_fin,
$row->format,
$row->editable,
$row->mailsonde,
$row->active
]);
}
}
private function migrateFromSujetStudsToSlot()
{
$stmt = $this->connection->query('SELECT * FROM sujet_studs');
$sujets = $stmt->fetchAll();
$slots = [];
foreach ($sujets as $sujet) {
$newSlots = $this->transformSujetToSlot($sujet);
foreach ($newSlots as $newSlot) {
$slots[] = $newSlot;
}
}
$prepared = $this->connection->prepare('INSERT INTO ' . Utils::table('slot') . ' (poll_id, title, moments) VALUES (?,?,?)');
foreach ($slots as $slot) {
$prepared->execute([
$slot->poll_id,
$this->unescape($slot->title),
!empty($slot->moments) ? $this->unescape($slot->moments) : null
]);
}
}
private function migrateFromCommentsToComment()
{
$select = $this->connection->query('
SELECT
id_sondage,
usercomment,
comment
FROM comments');
$insert = $this->connection->prepare('
INSERT INTO ' . Utils::table('comment') . ' (poll_id, name, comment)
VALUES (?,?,?)');
while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
$insert->execute([
$row->id_sondage,
$this->unescape($row->usercomment),
$this->unescape($row->comment)
]);
}
}
private function migrateFromUserStudsToVote()
{
$select = $this->connection->query('
SELECT
id_sondage,
nom,
REPLACE(REPLACE(REPLACE(reponses, 1, \'X\'), 2, 1), \'X\', 2) reponses
FROM user_studs');
$insert = $this->connection->prepare('
INSERT INTO ' . Utils::table('vote') . ' (poll_id, name, choices)
VALUES (?,?,?)');
while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
$insert->execute([
$row->id_sondage,
$this->unescape($row->nom),
$row->reponses
]);
}
}
private function transformSujetToSlot($sujet)
{
$slots = [];
$ex = explode(',', $sujet->sujet);
$isDatePoll = strpos($sujet->sujet, '@');
$lastSlot = null;
foreach ($ex as $atomicSlot) {
if ($isDatePoll === false) { // Classic poll
$slot = new \stdClass();
$slot->poll_id = $sujet->id_sondage;
$slot->title = $atomicSlot;
$slots[] = $slot;
} else { // Date poll
$values = explode('@', $atomicSlot);
if ($lastSlot === null || $lastSlot->title !== $values[0]) {
$lastSlot = new \stdClass();
$lastSlot->poll_id = $sujet->id_sondage;
$lastSlot->title = $values[0];
$lastSlot->moments = count($values) === 2 ? $values[1] : '-';
$slots[] = $lastSlot;
} else {
$lastSlot->moments .= ',' . (count($values) === 2 ? $values[1] : '-');
}
}
}
return $slots;
}
private function dropOldTables(Schema $schema)
{
$schema->dropTable('comments');
$schema->dropTable('sujet_studs');
$schema->dropTable('user_studs');
$schema->dropTable('sondage');
}
private function unescape($value)
{
return stripslashes(html_entity_decode($value, ENT_QUOTES));
}
}

View File

@ -0,0 +1,70 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Framadate\AbstractMigration;
use Framadate\Utils;
/**
* This migration adds the field receiveNewComments on the poll table.
*
* @package Framadate\Migration
* @version 0.9
*/
class Version20150117000000 extends AbstractMigration
{
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
public function description()
{
return 'Add column "receiveNewComments" for version 0.9';
}
/**
* @param Schema $schema
* @throws \Doctrine\DBAL\Migrations\SkipMigrationException
* @throws \Doctrine\DBAL\Schema\SchemaException
* @throws \Doctrine\DBAL\DBALException
*/
public function up(Schema $schema)
{
$this->skipIf($this->legacyCheck($schema,'Framadate\Migration\AddColumn_receiveNewComments_For_0_9'), 'Migration has been executed in an earlier database migration system');
foreach ([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')] as $table) {
$this->skipIf(!$schema->hasTable($table), 'Missing table ' . $table);
}
$pollTable = $schema->getTable(Utils::table('poll'));
$this->skipIf($pollTable->hasColumn('receiveNewComments'), 'Column receiveNewComments already exists');
$pollTable->addColumn('receiveNewComments', 'boolean', ['default' => false]);
}
/**
* @param Schema $schema
* @throws \Doctrine\DBAL\Schema\SchemaException
*/
public function down(Schema $schema)
{
$pollTable = $schema->getTable(Utils::table('poll'));
$pollTable->dropColumn('receiveNewComments');
}
}

View File

@ -0,0 +1,76 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Framadate\AbstractMigration;
use Framadate\Utils;
/**
* This migration adds the field uniqId on the vote table.
*
* @package Framadate\Migration
* @version 0.9
*/
class Version20150402000000 extends AbstractMigration
{
private $indexUniqIdName = 'IDX_vote_uniqId';
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
public function description()
{
return 'Add column "uniqId" in table "vote" for version 0.9';
}
/**
* @param Schema $schema
* @throws \Doctrine\DBAL\Migrations\SkipMigrationException
* @throws \Doctrine\DBAL\Schema\SchemaException
* @throws \Doctrine\DBAL\DBALException
*/
public function up(Schema $schema)
{
$this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\AddColumn_uniqId_In_vote_For_0_9'), 'Migration has been executed in an earlier database migration system');
foreach ([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')] as $table) {
$this->skipIf(!$schema->hasTable($table), 'Missing table ' . $table);
}
$voteTable = $schema->getTable(Utils::table('vote'));
$this->skipIf($voteTable->hasColumn('uniqId'), 'Column uniqId already existing');
$voteTable->addColumn('uniqId', 'string', ['length' => 16]);
$voteTable->addIndex(['uniqId'], $this->indexUniqIdName);
}
/**
* @param Schema $schema
* @throws \Doctrine\DBAL\Schema\SchemaException
*/
public function down(Schema $schema)
{
$voteTable = $schema->getTable(Utils::table('vote'));
$voteTable->dropIndex($this->indexUniqIdName);
$voteTable->dropColumn('uniqId');
}
}

View File

@ -0,0 +1,72 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Framadate\AbstractMigration;
use Framadate\Utils;
/**
* This migration adds the field hidden on the poll table.
*
* @package Framadate\Migration
* @version 0.9
*/
class Version20150405000000 extends AbstractMigration
{
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
public function description()
{
return 'Add column "hidden" in table "vote" for version 0.9';
}
/**
* @param Schema $schema
* @throws \Doctrine\DBAL\Migrations\SkipMigrationException
* @throws \Doctrine\DBAL\Schema\SchemaException
* @throws \Doctrine\DBAL\DBALException
*/
public function up(Schema $schema)
{
$this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\AddColumn_hidden_In_poll_For_0_9'), 'Migration has been executed in an earlier database migration system');
foreach ([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')] as $table) {
$this->skipIf(!$schema->hasTable($table), 'Missing table ' . $table);
}
$pollTable = $schema->getTable(Utils::table('poll'));
$this->skipIf($pollTable->hasColumn('hidden'), 'Column hidden already existing in table poll');
$pollTable->addColumn('hidden', 'boolean', ['default' => false, 'notnull' => true]);
}
/**
* @param Schema $schema
* @throws \Doctrine\DBAL\Schema\SchemaException
*/
public function down(Schema $schema)
{
$pollTable = $schema->getTable(Utils::table('poll'));
$pollTable->dropColumn('hidden');
}
}

View File

@ -0,0 +1,78 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Framadate\AbstractMigration;
use Framadate\Security\Token;
use Framadate\Utils;
/**
* This migration generate uniqId for all legacy votes.
*
* @package Framadate\Migration
* @version 0.9
*/
class Version20150624000000 extends AbstractMigration
{
public function description()
{
return 'Generate "uniqId" in "vote" table for all legacy votes';
}
/**
* @param Schema $schema
* @throws \Doctrine\DBAL\DBALException
* @throws \Doctrine\DBAL\Migrations\SkipMigrationException
*/
public function up(Schema $schema)
{
$this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\Generate_uniqId_for_old_votes'), 'Migration has been executed in an earlier database migration system');
foreach ([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')] as $table) {
$this->skipIf(!$schema->hasTable($table), 'Missing table ' . $table);
}
$this->connection->beginTransaction();
$select = $this->connection->query('
SELECT id
FROM ' . Utils::table('vote') . '
WHERE uniqid = \'\'');
$update = $this->connection->prepare('
UPDATE ' . Utils::table('vote') . '
SET uniqid = :uniqid
WHERE id = :id');
while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
$token = Token::getToken(16);
$update->execute([
'uniqid' => $token,
'id' => $row->id
]);
}
$this->connection->commit();
}
public function down(Schema $schema)
{
// TODO: Implement down() method.
}
}

View File

@ -0,0 +1,102 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Rapha<EFBFBD>l DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est r<EFBFBD>gi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Rapha<EFBFBD>l DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Framadate\AbstractMigration;
use Framadate\Utils;
/**
* This migration RPad votes from version 0.8.
* Because some votes does not have enough values for their poll.
*
* @package Framadate\Migration
* @version 0.9
*/
class Version20150918000000 extends AbstractMigration
{
public function description()
{
return 'RPad votes from version 0.8.';
}
/**
* @param Schema $schema
* @throws \Doctrine\DBAL\DBALException
* @throws \Doctrine\DBAL\Migrations\SkipMigrationException
* @throws \Doctrine\DBAL\Schema\SchemaException
*/
public function up(Schema $schema)
{
$this->skipIf(
$this->legacyCheck($schema, 'Framadate\Migration\RPadVotes_from_0_8'),
'Migration has been executed in an earlier database migration system'
);
foreach ([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table(
'comment'
)] as $table) {
$this->skipIf(!$schema->hasTable($table), 'Missing table ' . $table);
}
$driver_name = $this->connection->getDatabasePlatform()->getName();
switch ($driver_name) {
case 'mysql':
$this->addSql(
'UPDATE ' . Utils::table('vote') . ' fv
INNER JOIN (
SELECT v.id, RPAD(v.choices, inn.slots_count, \'0\') new_choices
FROM ' . Utils::table('vote') . ' v
INNER JOIN
(SELECT s.poll_id, SUM(IFNULL(LENGTH(s.moments) - LENGTH(REPLACE(s.moments, \',\', \'\')) + 1, 1)) slots_count
FROM ' . Utils::table('slot') . ' s
GROUP BY s.poll_id
ORDER BY s.poll_id) inn ON inn.poll_id = v.poll_id
WHERE LENGTH(v.choices) != inn.slots_count
) computed ON fv.id = computed.id
SET fv.choices = computed.new_choices'
);
break;
case 'postgresql':
$this->addSql(
"UPDATE " . Utils::table('vote') . " fv
SET choices = computed.new_choices
FROM (
SELECT v.id, RPAD(v.choices::text, inn.slots_count::int, '0') new_choices
FROM " . Utils::table('vote') . " v
INNER JOIN
(SELECT s.poll_id, SUM(coalesce(LENGTH(s.moments) - LENGTH(REPLACE(s.moments, ',', '')) + 1, 1)) slots_count
FROM " . Utils::table('slot') . " s
GROUP BY s.poll_id
ORDER BY s.poll_id) inn ON inn.poll_id = v.poll_id
WHERE LENGTH(v.choices) != inn.slots_count
) computed WHERE fv.id = computed.id"
);
break;
default:
$this->skipIf(true, "Not on MySQL or PostgreSQL");
break;
}
}
public function down(Schema $schema)
{
// TODO: Implement down() method.
}
}

View File

@ -16,8 +16,11 @@
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft) * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/ */
namespace Framadate\Migration; namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Types\Type;
use Framadate\AbstractMigration;
use Framadate\Utils; use Framadate\Utils;
/** /**
@ -26,45 +29,43 @@ use Framadate\Utils;
* @package Framadate\Migration * @package Framadate\Migration
* @version 1.0 * @version 1.0
*/ */
class Alter_Comment_table_for_name_length implements Migration { class Version20151012075900 extends AbstractMigration
function __construct() { {
}
/** /**
* This method should describe in english what is the purpose of the migration class. * This method should describe in english what is the purpose of the migration class.
* *
* @return string The description of the migration class * @return string The description of the migration class
*/ */
function description() { public function description()
{
return 'Alter the comment table to set a length to the name column.'; return 'Alter the comment table to set a length to the name column.';
} }
/** /**
* This method could check if the execute method should be called. * @param Schema $schema
* It is called before the execute method. * @throws \Doctrine\DBAL\Schema\SchemaException
* * @throws \Doctrine\DBAL\DBALException
* @param \PDO $pdo The connection to database * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
* @return bool true is the Migration should be executed.
*/ */
function preCondition(\PDO $pdo) { public function up(Schema $schema)
return true; {
$this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\Alter_Comment_table_for_name_length'), 'Migration has been executed in an earlier database migration system');
$commentTable = $schema->getTable(Utils::table('comment'));
$commentTable->changeColumn('name', ['default' => null, 'notnull' => false]);
$commentTable->changeColumn('name', ['type' => Type::getType('string'), 'length' => 64, 'notnull' => true]);
} }
/** /**
* This methode is called only one time in the migration page. * @param Schema $schema
* * @throws \Doctrine\DBAL\Schema\SchemaException
* @param \PDO $pdo The connection to database * @throws \Doctrine\DBAL\DBALException
* @return bool true is the execution succeeded
*/ */
function execute(\PDO $pdo) { public function down(Schema $schema)
$this->alterCommentTable($pdo); {
$commentTable = $schema->getTable(Utils::table('comment'));
return true; $commentTable->changeColumn('name', ['type' => Type::getType('string')]);
}
private function alterCommentTable(\PDO $pdo) {
$pdo->exec('
ALTER TABLE `' . Utils::table('comment') . '`
CHANGE `name` `name` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ;');
} }
} }

View File

@ -16,8 +16,10 @@
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft) * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/ */
namespace Framadate\Migration; namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Framadate\AbstractMigration;
use Framadate\Utils; use Framadate\Utils;
/** /**
@ -26,45 +28,42 @@ use Framadate\Utils;
* @package Framadate\Migration * @package Framadate\Migration
* @version 1.0 * @version 1.0
*/ */
class Alter_Comment_table_adding_date implements Migration { class Version20151012082600 extends AbstractMigration
function __construct() { {
}
/** /**
* This method should describe in english what is the purpose of the migration class. * This method should describe in english what is the purpose of the migration class.
* *
* @return string The description of the migration class * @return string The description of the migration class
*/ */
function description() { public function description()
{
return 'Alter the comment table to add a date column.'; return 'Alter the comment table to add a date column.';
} }
/** /**
* This method could check if the execute method should be called. * @param Schema $schema
* It is called before the execute method. * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
* * @throws \Doctrine\DBAL\Schema\SchemaException
* @param \PDO $pdo The connection to database * @throws \Doctrine\DBAL\DBALException
* @return bool true is the Migration should be executed.
*/ */
function preCondition(\PDO $pdo) { public function up(Schema $schema)
return true; {
$this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\Alter_Comment_table_adding_date'), 'Migration has been executed in an earlier database migration system');
$commentTable = $schema->getTable(Utils::table('comment'));
$this->skipIf($commentTable->hasColumn('date'), 'Column date in comment table already exists');
$commentTable->addColumn('date', 'datetime', ['default' => 0]);
} }
/** /**
* This methode is called only one time in the migration page. * @param Schema $schema
* * @throws \Doctrine\DBAL\Schema\SchemaException
* @param \PDO $pdo The connection to database
* @return bool true is the execution succeeded
*/ */
function execute(\PDO $pdo) { public function down(Schema $schema)
$this->alterCommentTable($pdo); {
$commentTable = $schema->getTable(Utils::table('comment'));
return true; $commentTable->dropColumn('comment');
}
private function alterCommentTable(\PDO $pdo) {
$pdo->exec('
ALTER TABLE `' . Utils::table('comment') . '`
ADD `date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ;');
} }
} }

View File

@ -0,0 +1,72 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Framadate\AbstractMigration;
use Framadate\Utils;
/**
* This migration adds the fields password_hash and results_publicly_visible on the poll table.
*
* @package Framadate\Migration
* @version 0.9
*/
class Version20151028000000 extends AbstractMigration
{
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
public function description()
{
return 'Add columns "password_hash" and "results_publicly_visible" in table "vote" for version 0.9';
}
/**
* @param Schema $schema
* @throws \Doctrine\DBAL\Migrations\SkipMigrationException
* @throws \Doctrine\DBAL\Schema\SchemaException
* @throws \Doctrine\DBAL\DBALException
*/
public function up(Schema $schema)
{
$this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\AddColumns_password_hash_And_results_publicly_visible_In_poll_For_0_9'), 'Migration has been executed in an earlier database migration system');
$pollTable = $schema->getTable(Utils::table('poll'));
$this->skipIf($pollTable->hasColumn('password_hash'), 'Column password_hash in table poll already exists');
$this->skipIf($pollTable->hasColumn('results_publicly_visible'), 'Column results_publicly_visible in table poll already exists');
$pollTable->addColumn('password_hash', 'string', ['notnull' => false]);
$pollTable->addColumn('results_publicly_visible', 'boolean', ['notnull' => false]);
}
/**
* @param Schema $schema
* @throws \Doctrine\DBAL\Schema\SchemaException
*/
public function down(Schema $schema)
{
$pollTable = $schema->getTable(Utils::table('poll'));
$pollTable->dropColumn('password_hash');
$pollTable->dropColumn('results_publicly_visible');
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Types\Type;
use Framadate\AbstractMigration;
use Framadate\Utils;
class Version20151205000000 extends AbstractMigration
{
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
public function description()
{
return 'Increase the size of id column in poll table';
}
/**
* @param Schema $schema
* @throws \Doctrine\DBAL\Schema\SchemaException
* @throws \Doctrine\DBAL\DBALException
* @throws \Doctrine\DBAL\Migrations\SkipMigrationException
*/
public function up(Schema $schema)
{
$this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\Increase_pollId_size'), 'Migration has been executed in an earlier database migration system');
$commentTable = $schema->getTable(Utils::table('comment'));
$commentTable->changeColumn('poll_id', ['type' => Type::getType('string'), 'length' => 64, 'notnull' => true]);
$pollTable = $schema->getTable(Utils::table('poll'));
$pollTable->changeColumn('id', ['type' => Type::getType('string'), 'length' => 64, 'notnull' => true]);
$slotTable = $schema->getTable(Utils::table('slot'));
$slotTable->changeColumn('poll_id', ['type' => Type::getType('string'), 'length' => 64, 'notnull' => true]);
$voteTable = $schema->getTable(Utils::table('vote'));
$voteTable->changeColumn('poll_id', ['type' => Type::getType('string'), 'length' => 64, 'notnull' => true]);
}
public function down(Schema $schema)
{
// TODO: Implement down() method.
}
}

View File

@ -16,8 +16,10 @@
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft) * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/ */
namespace Framadate\Migration; namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Framadate\AbstractMigration;
use Framadate\Utils; use Framadate\Utils;
/** /**
@ -26,45 +28,38 @@ use Framadate\Utils;
* @package Framadate\Migration * @package Framadate\Migration
* @version 0.9 * @version 0.9
*/ */
class AddColumn_ValueMax_In_poll_For_1_1 implements Migration { class Version20180220000000 extends AbstractMigration
function __construct() { {
}
/** /**
* This method should describe in english what is the purpose of the migration class. * This method should describe in english what is the purpose of the migration class.
* *
* @return string The description of the migration class * @return string The description of the migration class
*/ */
function description() { public function description()
{
return 'Add column "ValueMax" in table "vote" for version 0.9'; return 'Add column "ValueMax" in table "vote" for version 0.9';
} }
/** /**
* This method could check if the execute method should be called. * @param Schema $schema
* It is called before the execute method. * @throws \Doctrine\DBAL\Schema\SchemaException
* * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
* @param \PDO $pdo The connection to database * @throws \Doctrine\DBAL\DBALException
* @return bool true is the Migration should be executed.
*/ */
function preCondition(\PDO $pdo) { public function up(Schema $schema)
return true; {
$this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\AddColumn_ValueMax_In_poll_For_1_1'), 'Migration has been executed in an earlier database migration system');
$pollTable = $schema->getTable(Utils::table('poll'));
$pollTable->addColumn('ValueMax', 'smallint', ['default' => null, 'notnull' => false]);
} }
/** /**
* This method is called only one time in the migration page. * @param Schema $schema
* * @throws \Doctrine\DBAL\Schema\SchemaException
* @param \PDO $pdo The connection to database
* @return bool true is the execution succeeded
*/ */
function execute(\PDO $pdo) { public function down(Schema $schema)
$this->alterPollTable($pdo); {
$pollTable = $schema->getTable(Utils::table('poll'));
return true; $pollTable->dropColumn('ValueMax');
}
private function alterPollTable(\PDO $pdo) {
$pdo->exec('
ALTER TABLE `' . Utils::table('poll') . '`
ADD `ValueMax` TINYINT NULL;');
} }
} }

View File

@ -0,0 +1,88 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
namespace DoctrineMigrations;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Schema\Schema;
use Framadate\AbstractMigration;
use Framadate\Utils;
/**
* This migration sets Poll.end_date to NULL by default
*
* @package Framadate\Migration
* @version 1.1
*/
class Version20180411000000 extends AbstractMigration
{
/**
* This method should describe in english what is the purpose of the migration class.
*
* @return string The description of the migration class
*/
public function description()
{
return 'Sets Poll end_date to NULL by default (work around MySQL NO_ZERO_DATE)';
}
/**
* This method could check if the execute method should be called.
* It is called before the execute method.
*
* @param Connection|\PDO $connection The connection to database
* @return bool true if the Migration should be executed.
*/
public function preCondition(Connection $connection)
{
$driver_name = $connection->getWrappedConnection()->getAttribute(\PDO::ATTR_DRIVER_NAME);
if ($driver_name === 'mysql') {
$stmt = $connection->prepare(
"SELECT Column_Default from Information_Schema.Columns where Table_Name = ? AND Column_Name = ?;"
);
$stmt->bindValue(1, Utils::table('poll'));
$stmt->bindValue(2, 'end_date');
$stmt->execute();
$default = $stmt->fetch(\PDO::FETCH_COLUMN);
return $default === null;
}
return true;
}
/**
* @param Schema $schema
* @throws \Doctrine\DBAL\Schema\SchemaException
* @throws \Doctrine\DBAL\Migrations\SkipMigrationException
* @throws \Doctrine\DBAL\DBALException
*/
public function up(Schema $schema)
{
// We don't disable this migration even if legacy because it wasn't working correctly before
// $this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\Fix_MySQL_No_Zero_Date'), 'Migration has been executed in an earlier database migration system');
$this->skipIf($this->preCondition($this->connection), "Database server isn't MySQL or poll end_date default value was already NULL");
$poll = $schema->getTable(Utils::table('poll'));
$poll->changeColumn('end_date', ['default' => null, 'notnull' => false]);
}
public function down(Schema $schema)
{
// nothing
}
}

View File

@ -16,55 +16,50 @@
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft) * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/ */
namespace Framadate\Migration; namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Framadate\AbstractMigration;
use Framadate\Utils; use Framadate\Utils;
/** /**
* This migration adds the field uniqId on the vote table. * This migration adds the column collect_users_mail in the poll table
* *
* @package Framadate\Migration * @package Framadate\Migration
* @version 0.9 * @version 1.2
*/ */
class AddColumn_collect_mail_In_poll implements Migration { class Version20180419170000 extends AbstractMigration
function __construct() { {
}
/** /**
* This method should describe in english what is the purpose of the migration class. * This method should describe in english what is the purpose of the migration class.
* *
* @return string The description of the migration class * @return string The description of the migration class
*/ */
function description() { public function description()
{
return 'Add column collect_users_mail in table poll'; return 'Add column collect_users_mail in table poll';
} }
/** /**
* This method could check if the execute method should be called. * @param Schema $schema
* It is called before the execute method. * @throws \Doctrine\DBAL\Schema\SchemaException
* * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
* @param \PDO $pdo The connection to database * @throws \Doctrine\DBAL\DBALException
* @return bool true is the Migration should be executed.
*/ */
function preCondition(\PDO $pdo) { public function up(Schema $schema)
return true; {
$this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\AddColumn_collect_mail_In_poll'), 'Migration has been executed in an earlier database migration system');
$poll = $schema->getTable(Utils::table('poll'));
$poll->addColumn('collect_users_mail', 'boolean', ['default' => false]);
} }
/** /**
* This method is called only one time in the migration page. * @param Schema $schema
* * @throws \Doctrine\DBAL\Schema\SchemaException
* @param \PDO $pdo The connection to database
* @return bool true is the execution succeeded
*/ */
function execute(\PDO $pdo) { public function down(Schema $schema)
$this->alterVoteTable($pdo); {
$poll = $schema->getTable(Utils::table('poll'));
return true; $poll->dropColumn('collect_users_mail');
}
private function alterVoteTable(\PDO $pdo) {
$pdo->exec('
ALTER TABLE `' . Utils::table('poll') . '`
ADD `collect_users_mail` TINYINT DEFAULT 0;');
} }
} }

View File

@ -16,55 +16,50 @@
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft) * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/ */
namespace Framadate\Migration; namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Framadate\AbstractMigration;
use Framadate\Utils; use Framadate\Utils;
/** /**
* This migration adds the field uniqId on the vote table. * This migration adds the column mail in the vote table
* *
* @package Framadate\Migration * @package Framadate\Migration
* @version 0.9 * @version 1.2
*/ */
class AddColumn_mail_In_vote implements Migration { class Version20180419180000 extends AbstractMigration
function __construct() { {
}
/** /**
* This method should describe in english what is the purpose of the migration class. * This method should describe in english what is the purpose of the migration class.
* *
* @return string The description of the migration class * @return string The description of the migration class
*/ */
function description() { public function description()
{
return 'Add column mail in table vote'; return 'Add column mail in table vote';
} }
/** /**
* This method could check if the execute method should be called. * @param Schema $schema
* It is called before the execute method. * @throws \Doctrine\DBAL\Schema\SchemaException
* * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
* @param \PDO $pdo The connection to database * @throws \Doctrine\DBAL\DBALException
* @return bool true is the Migration should be executed.
*/ */
function preCondition(\PDO $pdo) { public function up(Schema $schema)
return true; {
$this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\AddColumn_collect_mail_In_poll'), 'Migration has been executed in an earlier database migration system');
$vote = $schema->getTable(Utils::table('vote'));
$vote->addColumn('mail', 'string', ['default' => null, 'notnull' => false]);
} }
/** /**
* This method is called only one time in the migration page. * @param Schema $schema
* * @throws \Doctrine\DBAL\Schema\SchemaException
* @param \PDO $pdo The connection to database
* @return bool true is the execution succeeded
*/ */
function execute(\PDO $pdo) { public function down(Schema $schema)
$this->alterVoteTable($pdo); {
$vote = $schema->getTable(Utils::table('vote'));
return true; $vote->dropColumn('mail');
}
private function alterVoteTable(\PDO $pdo) {
$pdo->exec('
ALTER TABLE `' . Utils::table('vote') . '`
ADD `mail` VARCHAR(320) DEFAULT NULL;');
} }
} }

View File

@ -16,31 +16,45 @@
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft) * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/ */
namespace Framadate\Migration; namespace DoctrineMigrations;
interface Migration { use Doctrine\DBAL\Schema\Schema;
use Framadate\AbstractMigration;
use Framadate\Utils;
/**
* This migration adds the column mail in the vote table
*
* @package Framadate\Migration
* @version 1.2
*/
class Version20180419190000 extends AbstractMigration
{
/** /**
* This method should describe in english what is the purpose of the migration class. * This method should describe in english what is the purpose of the migration class.
* *
* @return string The description of the migration class * @return string The description of the migration class
*/ */
function description(); public function description()
{
return 'Remove the old migration table';
}
/** /**
* This method could check if the execute method should be called. * @param Schema $schema
* It is called before the execute method. * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
*
* @param \PDO $pdo The connection to database
* @return bool true if the Migration should be executed
*/ */
function preCondition(\PDO $pdo); public function up(Schema $schema)
{
$this->skipIf(!$schema->hasTable(Utils::table(MIGRATION_TABLE)), "The old migration table wasn't created, no need to delete it.");
$schema->dropTable(Utils::table(MIGRATION_TABLE));
}
/** /**
* This methode is called only one time in the migration page. * @param Schema $schema
*
* @param \PDO $pdo The connection to database
* @return bool true if the execution succeeded
*/ */
function execute(\PDO $pdo); public function down(Schema $schema)
{
// No need to recreate legacy migration table
}
} }

View File

@ -1,43 +1,69 @@
<?php <?php
namespace Framadate\Repositories; namespace Framadate\Repositories;
use Framadate\FramaDB; use Doctrine\DBAL\Connection;
abstract class AbstractRepository { abstract class AbstractRepository {
/** /**
* @var FramaDB * @var Connection
*/ */
private $connect; protected $connect;
/** /**
* PollRepository constructor. * PollRepository constructor.
* @param FramaDB $connect * @param Connection $connect
*/ */
function __construct(FramaDB $connect) { public function __construct(Connection $connect) {
$this->connect = $connect; $this->connect = $connect;
$this->connect->setFetchMode(\PDO::FETCH_OBJ);
} }
public function beginTransaction() { public function beginTransaction()
{
$this->connect->beginTransaction(); $this->connect->beginTransaction();
} }
public function commit() { /**
* @throws \Doctrine\DBAL\ConnectionException
*/
public function commit()
{
$this->connect->commit(); $this->connect->commit();
} }
function rollback() { /**
* @throws \Doctrine\DBAL\ConnectionException
*/
public function rollback()
{
$this->connect->rollback(); $this->connect->rollback();
} }
public function prepare($sql) { /**
* @param string $sql
* @throws \Doctrine\DBAL\DBALException
* @return bool|\Doctrine\DBAL\Driver\Statement|\PDOStatement
*/
public function prepare($sql)
{
return $this->connect->prepare($sql); return $this->connect->prepare($sql);
} }
function query($sql) { /**
* @param string $sql
* @throws \Doctrine\DBAL\DBALException
* @return bool|\Doctrine\DBAL\Driver\Statement|\PDOStatement
*/
public function query($sql)
{
return $this->connect->query($sql); return $this->connect->query($sql);
} }
function lastInsertId() { /**
* @return string
*/
public function lastInsertId()
{
return $this->connect->lastInsertId(); return $this->connect->lastInsertId();
} }
} }

View File

@ -1,16 +1,16 @@
<?php <?php
namespace Framadate\Repositories; namespace Framadate\Repositories;
use Framadate\FramaDB;
use Framadate\Utils; use Framadate\Utils;
class CommentRepository extends AbstractRepository { class CommentRepository extends AbstractRepository {
function __construct(FramaDB $connect) { /**
parent::__construct($connect); * @param $poll_id
} * @throws \Doctrine\DBAL\DBALException
* @return array
function findAllByPollId($poll_id) { */
$prepared = $this->prepare('SELECT * FROM `' . Utils::table('comment') . '` WHERE poll_id = ? ORDER BY id'); public function findAllByPollId($poll_id) {
$prepared = $this->prepare('SELECT * FROM ' . Utils::table('comment') . ' WHERE poll_id = ? ORDER BY id');
$prepared->execute([$poll_id]); $prepared->execute([$poll_id]);
return $prepared->fetchAll(); return $prepared->fetchAll();
@ -24,32 +24,44 @@ class CommentRepository extends AbstractRepository {
* @param $comment * @param $comment
* @return bool * @return bool
*/ */
function insert($poll_id, $name, $comment) { function insert($poll_id, $name, $comment)
$prepared = $this->prepare('INSERT INTO `' . Utils::table('comment') . '` (poll_id, name, comment) VALUES (?,?,?)'); {
return $this->connect->insert(Utils::table('comment'), ['poll_id' => $poll_id, 'name' => $name, 'comment' => $comment]) > 0;
return $prepared->execute([$poll_id, $name, $comment]);
} }
function deleteById($poll_id, $comment_id) { /**
$prepared = $this->prepare('DELETE FROM `' . Utils::table('comment') . '` WHERE poll_id = ? AND id = ?'); * @param $poll_id
* @param $comment_id
return $prepared->execute([$poll_id, $comment_id]); * @throws \Doctrine\DBAL\Exception\InvalidArgumentException
* @return bool
*/
function deleteById($poll_id, $comment_id)
{
return $this->connect->delete(Utils::table('comment'), ['poll_id' => $poll_id, 'id' => $comment_id]) > 0;
} }
/** /**
* Delete all comments of a given poll. * Delete all comments of a given poll.
* *
* @param $poll_id int The ID of the given poll. * @param $poll_id int The ID of the given poll.
* @return bool|null true if action succeeded. * @throws \Doctrine\DBAL\Exception\InvalidArgumentException
* @return bool true if action succeeded.
*/ */
function deleteByPollId($poll_id) { function deleteByPollId($poll_id)
$prepared = $this->prepare('DELETE FROM `' . Utils::table('comment') . '` WHERE poll_id = ?'); {
return $this->connect->delete(Utils::table('comment'), ['poll_id' => $poll_id]) > 0;
return $prepared->execute([$poll_id]);
} }
public function exists($poll_id, $name, $comment) { /**
$prepared = $this->prepare('SELECT 1 FROM `' . Utils::table('comment') . '` WHERE poll_id = ? AND name = ? AND comment = ?'); * @param $poll_id
* @param $name
* @param $comment
* @throws \Doctrine\DBAL\DBALException
* @return bool
*/
public function exists($poll_id, $name, $comment)
{
$prepared = $this->prepare('SELECT 1 FROM ' . Utils::table('comment') . ' WHERE poll_id = ? AND name = ? AND comment = ?');
$prepared->execute([$poll_id, $name, $comment]); $prepared->execute([$poll_id, $name, $comment]);
return $prepared->rowCount() > 0; return $prepared->rowCount() > 0;

View File

@ -1,25 +1,45 @@
<?php <?php
namespace Framadate\Repositories; namespace Framadate\Repositories;
use Framadate\FramaDB;
use Framadate\Utils; use Framadate\Utils;
use PDO; use PDO;
class PollRepository extends AbstractRepository { class PollRepository extends AbstractRepository {
function __construct(FramaDB $connect) { /**
parent::__construct($connect); * @param $poll_id
* @param $admin_poll_id
* @param $form
*/
public function insertPoll($poll_id, $admin_poll_id, $form)
{
$this->connect->insert(Utils::table('poll'), [
'id' => $poll_id,
'admin_id' => $admin_poll_id,
'title' => $form->title,
'description' => $form->description,
'admin_name' => $form->admin_name,
'admin_mail' => $form->admin_mail,
'end_date' => (new \DateTime)->setTimestamp($form->end_date)->format('Y-m-d H:i:s'),
'format' => $form->format,
'editable' => ($form->editable>=0 && $form->editable<=2) ? $form->editable : 0,
'receiveNewVotes' => $form->receiveNewVotes ? 1 : 0,
'receiveNewComments' => $form->receiveNewComments ? 1 : 0,
'hidden' => $form->hidden ? 1 : 0,
'password_hash' => $form->password_hash,
'results_publicly_visible' => $form->results_publicly_visible ? 1 : 0,
'ValueMax' => $form->ValueMax,
'collect_users_mail' => $form->collect_users_mail? 1 : 0,
]);
} }
public function insertPoll($poll_id, $admin_poll_id, $form) { /**
$sql = 'INSERT INTO `' . Utils::table('poll') . '` * @param $poll_id
(id, admin_id, title, description, admin_name, admin_mail, end_date, format, editable, receiveNewVotes, receiveNewComments, hidden, password_hash, results_publicly_visible, ValueMax, collect_users_mail) * @throws \Doctrine\DBAL\DBALException
VALUES (?,?,?,?,?,?,FROM_UNIXTIME(?),?,?,?,?,?,?,?,?,?)'; * @return mixed
$prepared = $this->prepare($sql); */
$prepared->execute([$poll_id, $admin_poll_id, $form->title, $form->description, $form->admin_name, $form->admin_mail, $form->end_date, $form->format, ($form->editable>=0 && $form->editable<=2) ? $form->editable : 0, $form->receiveNewVotes ? 1 : 0, $form->receiveNewComments ? 1 : 0, $form->hidden ? 1 : 0, $form->password_hash, $form->results_publicly_visible ? 1 : 0, $form->ValueMax, $form->collect_users_mail? 1 : 0]); public function findById($poll_id)
} {
$prepared = $this->prepare('SELECT * FROM ' . Utils::table('poll') . ' WHERE id = ?');
function findById($poll_id) {
$prepared = $this->prepare('SELECT * FROM `' . Utils::table('poll') . '` WHERE id = ?');
$prepared->execute([$poll_id]); $prepared->execute([$poll_id]);
$poll = $prepared->fetch(); $poll = $prepared->fetch();
@ -28,8 +48,13 @@ class PollRepository extends AbstractRepository {
return $poll; return $poll;
} }
/**
* @param $admin_poll_id
* @throws \Doctrine\DBAL\DBALException
* @return mixed
*/
public function findByAdminId($admin_poll_id) { public function findByAdminId($admin_poll_id) {
$prepared = $this->prepare('SELECT * FROM `' . Utils::table('poll') . '` WHERE admin_id = ?'); $prepared = $this->prepare('SELECT * FROM ' . Utils::table('poll') . ' WHERE admin_id = ?');
$prepared->execute([$admin_poll_id]); $prepared->execute([$admin_poll_id]);
$poll = $prepared->fetch(); $poll = $prepared->fetch();
@ -38,42 +63,75 @@ class PollRepository extends AbstractRepository {
return $poll; return $poll;
} }
/**
* @param $poll_id
* @throws \Doctrine\DBAL\DBALException
* @return bool
*/
public function existsById($poll_id) { public function existsById($poll_id) {
$prepared = $this->prepare('SELECT 1 FROM `' . Utils::table('poll') . '` WHERE id = ?'); $prepared = $this->prepare('SELECT 1 FROM ' . Utils::table('poll') . ' WHERE id = ?');
$prepared->execute([$poll_id]); $prepared->execute([$poll_id]);
return $prepared->rowCount() > 0; return $prepared->rowCount() > 0;
} }
/**
* @param $admin_poll_id
* @throws \Doctrine\DBAL\DBALException
* @return bool
*/
public function existsByAdminId($admin_poll_id) { public function existsByAdminId($admin_poll_id) {
$prepared = $this->prepare('SELECT 1 FROM `' . Utils::table('poll') . '` WHERE admin_id = ?'); $prepared = $this->prepare('SELECT 1 FROM ' . Utils::table('poll') . ' WHERE admin_id = ?');
$prepared->execute([$admin_poll_id]); $prepared->execute([$admin_poll_id]);
return $prepared->rowCount() > 0; return $prepared->rowCount() > 0;
} }
function update($poll) { /**
$prepared = $this->prepare('UPDATE `' . Utils::table('poll') . '` SET title=?, admin_name=?, admin_mail=?, description=?, end_date=?, active=?, editable=?, hidden=?, password_hash=?, results_publicly_visible=? WHERE id = ?'); * @param $poll
* @return bool
return $prepared->execute([$poll->title, $poll->admin_name, $poll->admin_mail, $poll->description, $poll->end_date, $poll->active, ($poll->editable>=0 && $poll->editable<=2) ? $poll->editable : 0, $poll->hidden ? 1 : 0, $poll->password_hash, $poll->results_publicly_visible ? 1 : 0, $poll->id]); */
public function update($poll)
{
return $this->connect->update(Utils::table('poll'), [
'title' => $poll->title,
'admin_name' => $poll->admin_name,
'admin_mail' => $poll->admin_mail,
'description' => $poll->description,
'end_date' => $poll->end_date, # TODO : Harmonize dates between here and insert
'active' => $poll->active,
'editable' => $poll->editable >= 0 && $poll->editable <= 2 ? $poll->editable : 0,
'hidden' => $poll->hidden ? 1 : 0,
'password_hash' => $poll->password_hash,
'results_publicly_visible' => $poll->results_publicly_visible ? 1 : 0
], [
'id' => $poll->id
]) > 0;
} }
function deleteById($poll_id) { /**
$prepared = $this->prepare('DELETE FROM `' . Utils::table('poll') . '` WHERE id = ?'); * @param $poll_id
* @throws \Doctrine\DBAL\Exception\InvalidArgumentException
return $prepared->execute([$poll_id]); * @return bool
*/
public function deleteById($poll_id)
{
return $this->connect->delete(Utils::table('poll'), ['id' => $poll_id]) > 0;
} }
/** /**
* Find old polls. Limit: 20. * Find old polls. Limit: 20.
* *
* @param int $limit
* @throws \Doctrine\DBAL\DBALException
* @return array Array of old polls * @return array Array of old polls
*/ */
public function findOldPolls() { public function findOldPolls($limit = 20)
$prepared = $this->prepare('SELECT * FROM `' . Utils::table('poll') . '` WHERE DATE_ADD(`end_date`, INTERVAL ' . PURGE_DELAY . ' DAY) < NOW() AND `end_date` != 0 LIMIT 20'); {
$prepared->execute([]); $prepared = $this->prepare('SELECT * FROM ' . Utils::table('poll') . ' WHERE DATE_ADD(end_date, INTERVAL ? DAY) < NOW() AND end_date != 0 LIMIT ?');
$prepared->execute([PURGE_DELAY, $limit]);
return $prepared->fetchAll(); return $prepared->fetchAll();
} }
@ -84,52 +142,53 @@ class PollRepository extends AbstractRepository {
* @param array $search Array of search : ['id'=>..., 'title'=>..., 'name'=>..., 'mail'=>...] * @param array $search Array of search : ['id'=>..., 'title'=>..., 'name'=>..., 'mail'=>...]
* @param int $start The number of first entry to select * @param int $start The number of first entry to select
* @param int $limit The number of entries to find * @param int $limit The number of entries to find
* @throws \Doctrine\DBAL\DBALException
* @return array The found polls * @return array The found polls
*/ */
public function findAll($search, $start, $limit) { public function findAll($search, $start, $limit) {
// Polls // Polls
$request = ""; $request = "";
$request .= "SELECT p.*,"; $request .= "SELECT p.*,";
$request .= " (SELECT count(1) FROM `" . Utils::table('vote') . "` v WHERE p.id=v.poll_id) votes"; $request .= " (SELECT count(1) FROM " . Utils::table('vote') . " v WHERE p.id=v.poll_id) votes";
$request .= " FROM `" . Utils::table('poll') . "` p"; $request .= " FROM " . Utils::table('poll') . " p";
$request .= " WHERE 1"; $request .= " WHERE 1";
$values = []; $values = [];
if (!empty($search["poll"])) { if (!empty($search["poll"])) {
$request .= " AND p.id LIKE :poll"; $request .= " AND p.id LIKE :poll";
$values["poll"] = "{$search["poll"]}%"; $values["poll"] = "{$search["poll"]}%";
} }
$fields = [ $fields = [
// key of $search => column name // key of $search => column name
"title" => "title", "title" => "title",
"name" => "admin_name", "name" => "admin_name",
"mail" => "admin_mail", "mail" => "admin_mail",
]; ];
foreach ($fields as $searchKey => $columnName) { foreach ($fields as $searchKey => $columnName) {
if (empty($search[$searchKey])) { if (empty($search[$searchKey])) {
continue; continue;
} }
$request .= " AND p.$columnName LIKE :$searchKey"; $request .= " AND p.$columnName LIKE :$searchKey";
$values[$searchKey] = "%{$search[$searchKey]}%"; $values[$searchKey] = "%{$search[$searchKey]}%";
} }
$request .= " ORDER BY p.title ASC"; $request .= " ORDER BY p.title ASC";
$request .= " LIMIT :start, :limit"; $request .= " LIMIT :start, :limit";
$prepared = $this->prepare($request); $prepared = $this->prepare($request);
foreach ($values as $searchKey => $value) { foreach ($values as $searchKey => $value) {
$prepared->bindParam(":$searchKey", $value, PDO::PARAM_STR); $prepared->bindParam(":$searchKey", $value, PDO::PARAM_STR);
} }
$prepared->bindParam(':start', $start, PDO::PARAM_INT); $prepared->bindParam(':start', $start, PDO::PARAM_INT);
$prepared->bindParam(':limit', $limit, PDO::PARAM_INT); $prepared->bindParam(':limit', $limit, PDO::PARAM_INT);
$prepared->execute(); $prepared->execute();
return $prepared->fetchAll(); return $prepared->fetchAll();
@ -139,26 +198,28 @@ class PollRepository extends AbstractRepository {
* Find all polls that are created with the given admin mail. * Find all polls that are created with the given admin mail.
* *
* @param string $mail Email address of the poll admin * @param string $mail Email address of the poll admin
* @throws \Doctrine\DBAL\DBALException
* @return array The list of matching polls * @return array The list of matching polls
*/ */
public function findAllByAdminMail($mail) { public function findAllByAdminMail($mail) {
$prepared = $this->prepare('SELECT * FROM `' . Utils::table('poll') . '` WHERE admin_mail = :admin_mail'); $prepared = $this->prepare('SELECT * FROM ' . Utils::table('poll') . ' WHERE admin_mail = :admin_mail');
$prepared->execute(['admin_mail' => $mail]); $prepared->execute(['admin_mail' => $mail]);
return $prepared->fetchAll(); return $prepared->fetchAll();
} }
/** /**
* Get the total number of polls in databse. * Get the total number of polls in database.
* *
* @param array $search Array of search : ['id'=>..., 'title'=>..., 'name'=>...] * @param array $search Array of search : ['id'=>..., 'title'=>..., 'name'=>...]
* @throws \Doctrine\DBAL\DBALException
* @return int The number of polls * @return int The number of polls
*/ */
public function count($search = null) { public function count($search = null) {
// Total count // Total count
$prepared = $this->prepare(' $prepared = $this->prepare('
SELECT count(1) nb SELECT count(1) nb
FROM `' . Utils::table('poll') . '` p FROM ' . Utils::table('poll') . ' p
WHERE (:id = "" OR p.id LIKE :id) WHERE (:id = "" OR p.id LIKE :id)
AND (:title = "" OR p.title LIKE :title) AND (:title = "" OR p.title LIKE :title)
AND (:name = "" OR p.admin_name LIKE :name) AND (:name = "" OR p.admin_name LIKE :name)

View File

@ -18,7 +18,7 @@
*/ */
namespace Framadate\Repositories; namespace Framadate\Repositories;
use Framadate\FramaDB; use Doctrine\DBAL\Connection;
class RepositoryFactory { class RepositoryFactory {
private static $connect; private static $connect;
@ -29,9 +29,9 @@ class RepositoryFactory {
private static $commentRepository; private static $commentRepository;
/** /**
* @param FramaDB $connect * @param Connection $connect
*/ */
static function init(FramaDB $connect) { static function init(Connection $connect) {
self::$connect = $connect; self::$connect = $connect;
} }

View File

@ -4,28 +4,23 @@
* is not distributed with this file, you can obtain one at * is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
* *
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Rapha<EFBFBD>l DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft) * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
* *
* ============================= * =============================
* *
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence * Ce logiciel est r<EFBFBD>gi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
* *
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Rapha<EFBFBD>l DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft) * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/ */
namespace Framadate\Repositories; namespace Framadate\Repositories;
use Framadate\FramaDB;
use Framadate\Utils; use Framadate\Utils;
class SlotRepository extends AbstractRepository { class SlotRepository extends AbstractRepository {
function __construct(FramaDB $connect) {
parent::__construct($connect);
}
/** /**
* Insert a bulk of slots. * Insert a bulk of slots.
* *
@ -33,11 +28,9 @@ class SlotRepository extends AbstractRepository {
* @param array $choices * @param array $choices
*/ */
public function insertSlots($poll_id, $choices) { public function insertSlots($poll_id, $choices) {
$prepared = $this->prepare('INSERT INTO `' . Utils::table('slot') . '` (poll_id, title, moments) VALUES (?, ?, ?)');
foreach ($choices as $choice) { foreach ($choices as $choice) {
// We prepared the slots (joined by comas) // We prepared the slots (joined by comas)
$joinedSlots = ''; $joinedSlots = null;
$first = true; $first = true;
foreach ($choice->getSlots() as $slot) { foreach ($choice->getSlots() as $slot) {
if ($first) { if ($first) {
@ -49,16 +42,18 @@ class SlotRepository extends AbstractRepository {
} }
// We execute the insertion // We execute the insertion
if (empty($joinedSlots)) { $this->connect->insert(Utils::table('slot'), ['poll_id' => $poll_id, 'title' => $choice->getName(), 'moments' => $joinedSlots]);
$prepared->execute([$poll_id, $choice->getName(), null]);
} else {
$prepared->execute([$poll_id, $choice->getName(), $joinedSlots]);
}
} }
} }
function listByPollId($poll_id) { /**
$prepared = $this->prepare('SELECT * FROM `' . Utils::table('slot') . '` WHERE poll_id = ? ORDER BY id'); * @param $poll_id
* @throws \Doctrine\DBAL\DBALException
* @return array
*/
public function listByPollId($poll_id)
{
$prepared = $this->prepare('SELECT * FROM ' . Utils::table('slot') . ' WHERE poll_id = ? ORDER BY id');
$prepared->execute([$poll_id]); $prepared->execute([$poll_id]);
return $prepared->fetchAll(); return $prepared->fetchAll();
@ -69,10 +64,11 @@ class SlotRepository extends AbstractRepository {
* *
* @param $poll_id int The ID of the poll * @param $poll_id int The ID of the poll
* @param $datetime int The datetime of the slot * @param $datetime int The datetime of the slot
* @throws \Doctrine\DBAL\DBALException
* @return mixed Object The slot found, or null * @return mixed Object The slot found, or null
*/ */
function findByPollIdAndDatetime($poll_id, $datetime) { function findByPollIdAndDatetime($poll_id, $datetime) {
$prepared = $this->prepare('SELECT * FROM `' . Utils::table('slot') . '` WHERE poll_id = ? AND SUBSTRING_INDEX(title, \'@\', 1) = ?'); $prepared = $this->prepare('SELECT * FROM ' . Utils::table('slot') . ' WHERE poll_id = ? AND SUBSTRING_INDEX(title, \'@\', 1) = ?');
$prepared->execute([$poll_id, $datetime]); $prepared->execute([$poll_id, $datetime]);
$slot = $prepared->fetch(); $slot = $prepared->fetch();
@ -89,10 +85,9 @@ class SlotRepository extends AbstractRepository {
* @param $moments mixed|null The moments joined with "," * @param $moments mixed|null The moments joined with ","
* @return bool true if action succeeded * @return bool true if action succeeded
*/ */
function insert($poll_id, $title, $moments) { function insert($poll_id, $title, $moments)
$prepared = $this->prepare('INSERT INTO `' . Utils::table('slot') . '` (poll_id, title, moments) VALUES (?,?,?)'); {
return $this->connect->insert(Utils::table('slot'), ['poll_id' => $poll_id, 'title' => $title, 'moments' => $moments]) > 0;
return $prepared->execute([$poll_id, $title, $moments]);
} }
/** /**
@ -103,10 +98,9 @@ class SlotRepository extends AbstractRepository {
* @param $newMoments mixed The new moments * @param $newMoments mixed The new moments
* @return bool|null true if action succeeded. * @return bool|null true if action succeeded.
*/ */
function update($poll_id, $datetime, $newMoments) { function update($poll_id, $datetime, $newMoments)
$prepared = $this->prepare('UPDATE `' . Utils::table('slot') . '` SET moments = ? WHERE poll_id = ? AND title = ?'); {
return $this->connect->update(Utils::table('slot'), ['moments' => $newMoments], ['poll_id' => $poll_id, 'title' => $datetime]) > 0;
return $prepared->execute([$newMoments, $poll_id, $datetime]);
} }
/** /**
@ -114,15 +108,21 @@ class SlotRepository extends AbstractRepository {
* *
* @param $poll_id int The ID of the poll * @param $poll_id int The ID of the poll
* @param $datetime mixed The datetime of the slot * @param $datetime mixed The datetime of the slot
* @throws \Doctrine\DBAL\DBALException
* @return bool
*/ */
function deleteByDateTime($poll_id, $datetime) { public function deleteByDateTime($poll_id, $datetime)
$prepared = $this->prepare('DELETE FROM `' . Utils::table('slot') . '` WHERE poll_id = ? AND title = ?'); {
$prepared->execute([$poll_id, $datetime]); return $this->connect->delete(Utils::table('slot'), ['poll_id' => $poll_id, 'title' => $datetime]) > 0;
} }
function deleteByPollId($poll_id) { /**
$prepared = $this->prepare('DELETE FROM `' . Utils::table('slot') . '` WHERE poll_id = ?'); * @param $poll_id
* @throws \Doctrine\DBAL\DBALException
return $prepared->execute([$poll_id]); * @return bool
*/
public function deleteByPollId($poll_id)
{
return $this->connect->delete(Utils::table('slot'), ['poll_id' => $poll_id]) > 0;
} }
} }

View File

@ -5,26 +5,35 @@ use Framadate\FramaDB;
use Framadate\Utils; use Framadate\Utils;
class VoteRepository extends AbstractRepository { class VoteRepository extends AbstractRepository {
function __construct(FramaDB $connect) { /**
parent::__construct($connect); * @param $poll_id
} * @throws \Doctrine\DBAL\DBALException
* @return array
function allUserVotesByPollId($poll_id) { */
$prepared = $this->prepare('SELECT * FROM `' . Utils::table('vote') . '` WHERE poll_id = ? ORDER BY id'); public function allUserVotesByPollId($poll_id)
{
$prepared = $this->prepare('SELECT * FROM ' . Utils::table('vote') . ' WHERE poll_id = ? ORDER BY id');
$prepared->execute([$poll_id]); $prepared->execute([$poll_id]);
return $prepared->fetchAll(); return $prepared->fetchAll();
} }
function insertDefault($poll_id, $insert_position) { /**
$prepared = $this->prepare('UPDATE `' . Utils::table('vote') . '` SET choices = CONCAT(SUBSTRING(choices, 1, ?), " ", SUBSTRING(choices, ?)) WHERE poll_id = ?'); //#51 : default value for unselected vote * @param $poll_id
* @param $insert_position
* @throws \Doctrine\DBAL\DBALException
* @return bool
*/
public function insertDefault($poll_id, $insert_position)
{
# TODO : Handle this on PHP's side
$prepared = $this->prepare('UPDATE ' . Utils::table('vote') . ' SET choices = CONCAT(SUBSTRING(choices, 1, ?), " ", SUBSTRING(choices, ?)) WHERE poll_id = ?'); //#51 : default value for unselected vote
return $prepared->execute([$insert_position, $insert_position + 1, $poll_id]); return $prepared->execute([$insert_position, $insert_position + 1, $poll_id]);
} }
function insert($poll_id, $name, $choices, $token, $mail) { function insert($poll_id, $name, $choices, $token, $mail) {
$prepared = $this->prepare('INSERT INTO `' . Utils::table('vote') . '` (poll_id, name, choices, uniqId, mail) VALUES (?,?,?,?,?)'); $this->connect->insert(Utils::table('vote'), ['poll_id' => $poll_id, 'name' => $name, 'choices' => $choices, 'uniqId' => $token, 'mail' => $mail]);
$prepared->execute([$poll_id, $name, $choices, $token, $mail]);
$newVote = new \stdClass(); $newVote = new \stdClass();
$newVote->poll_id = $poll_id; $newVote->poll_id = $poll_id;
@ -32,33 +41,38 @@ class VoteRepository extends AbstractRepository {
$newVote->name = $name; $newVote->name = $name;
$newVote->choices = $choices; $newVote->choices = $choices;
$newVote->uniqId = $token; $newVote->uniqId = $token;
$newVote->mail=$mail; $newVote->mail=$mail;
return $newVote; return $newVote;
} }
function deleteById($poll_id, $vote_id) { /**
$prepared = $this->prepare('DELETE FROM `' . Utils::table('vote') . '` WHERE poll_id = ? AND id = ?'); * @param $poll_id
* @param $vote_id
return $prepared->execute([$poll_id, $vote_id]); * @throws \Doctrine\DBAL\DBALException
* @return bool
*/
public function deleteById($poll_id, $vote_id)
{
return $this->connect->delete(Utils::table('vote'), ['poll_id' => $poll_id, 'id' => $vote_id]) > 0;
} }
public function deleteOldVotesByPollId($poll_id, $votesToDelete) { public function deleteOldVotesByPollId($poll_id, $votesToDelete) {
$prepared = $this->prepare('DELETE FROM `' . Utils::table('vote') . '` WHERE poll_id = ? ORDER BY `poll_id` ASC LIMIT ' . $votesToDelete); $prepared = $this->prepare('DELETE FROM `' . Utils::table('vote') . '` WHERE poll_id = ? ORDER BY `poll_id` ASC LIMIT ' . $votesToDelete);
return $prepared->execute([$poll_id]); return $prepared->execute([$poll_id]);
} }
/** /**
* Delete all votes of a given poll. * Delete all votes of a given poll.
* *
* @param $poll_id int The ID of the given poll. * @param $poll_id int The ID of the given poll.
* @throws \Doctrine\DBAL\DBALException
* @return bool|null true if action succeeded. * @return bool|null true if action succeeded.
*/ */
function deleteByPollId($poll_id) { public function deleteByPollId($poll_id)
$prepared = $this->prepare('DELETE FROM `' . Utils::table('vote') . '` WHERE poll_id = ?'); {
return $this->connect->delete(Utils::table('vote'), ['poll_id' => $poll_id]) > 0;
return $prepared->execute([$poll_id]);
} }
/** /**
@ -66,18 +80,33 @@ class VoteRepository extends AbstractRepository {
* *
* @param $poll_id int The ID of the poll * @param $poll_id int The ID of the poll
* @param $index int The index of the vote into the poll * @param $index int The index of the vote into the poll
* @throws \Doctrine\DBAL\DBALException
* @return bool|null true if action succeeded. * @return bool|null true if action succeeded.
*/ */
function deleteByIndex($poll_id, $index) { public function deleteByIndex($poll_id, $index)
$prepared = $this->prepare('UPDATE `' . Utils::table('vote') . '` SET choices = CONCAT(SUBSTR(choices, 1, ?), SUBSTR(choices, ?)) WHERE poll_id = ?'); {
$prepared = $this->prepare('UPDATE ' . Utils::table('vote') . ' SET choices = CONCAT(SUBSTR(choices, 1, ?), SUBSTR(choices, ?)) WHERE poll_id = ?');
return $prepared->execute([$index, $index + 2, $poll_id]); return $prepared->execute([$index, $index + 2, $poll_id]);
} }
function update($poll_id, $vote_id, $name, $choices, $mail) { /**
$prepared = $this->prepare('UPDATE `' . Utils::table('vote') . '` SET choices = ?, name = ?, mail = ? WHERE poll_id = ? AND id = ?'); * @param $poll_id
* @param $vote_id
return $prepared->execute([$choices, $name, $mail, $poll_id, $vote_id]); * @param $name
* @param $choices
* @return bool
*/
public function update($poll_id, $vote_id, $name, $choices, $mail)
{
return $this->connect->update(Utils::table('vote'), [
'choices' => $choices,
'name' => $name,
'mail' => $mail,
], [
'poll_id' => $poll_id,
'id' => $vote_id,
]) > 0;
} }
/** /**
@ -85,24 +114,26 @@ class VoteRepository extends AbstractRepository {
* *
* @param int $poll_id ID of the poll * @param int $poll_id ID of the poll
* @param string $name Name of the vote * @param string $name Name of the vote
* @throws \Doctrine\DBAL\DBALException
* @return bool true if vote already exists * @return bool true if vote already exists
*/ */
public function existsByPollIdAndName($poll_id, $name) { public function existsByPollIdAndName($poll_id, $name) {
$prepared = $this->prepare('SELECT 1 FROM `' . Utils::table('vote') . '` WHERE poll_id = ? AND name = ?'); $prepared = $this->prepare('SELECT 1 FROM ' . Utils::table('vote') . ' WHERE poll_id = ? AND name = ?');
$prepared->execute([$poll_id, $name]); $prepared->execute([$poll_id, $name]);
return $prepared->rowCount() > 0; return $prepared->rowCount() > 0;
} }
/** /**
* Check if name is already used for the given poll and another vote. * Check if name is already used for the given poll and another vote.
* *
* @param int $poll_id ID of the poll * @param int $poll_id ID of the poll
* @param string $name Name of the vote * @param string $name Name of the vote
* @param int $vote_id ID of the current vote * @param int $vote_id ID of the current vote
* @throws \Doctrine\DBAL\DBALException
* @return bool true if vote already exists * @return bool true if vote already exists
*/ */
public function existsByPollIdAndNameAndVoteId($poll_id, $name, $vote_id) { public function existsByPollIdAndNameAndVoteId($poll_id, $name, $vote_id) {
$prepared = $this->prepare('SELECT 1 FROM `' . Utils::table('vote') . '` WHERE poll_id = ? AND name = ? AND id != ?'); $prepared = $this->prepare('SELECT 1 FROM ' . Utils::table('vote') . ' WHERE poll_id = ? AND name = ? AND id != ?');
$prepared->execute([$poll_id, $name, $vote_id]); $prepared->execute([$poll_id, $name, $vote_id]);
return $prepared->rowCount() > 0; return $prepared->rowCount() > 0;
} }

View File

@ -1,10 +1,9 @@
<?php <?php
namespace Framadate\Services; namespace Framadate\Services;
use Doctrine\DBAL\Connection;
use Framadate\Exception\MomentAlreadyExistsException; use Framadate\Exception\MomentAlreadyExistsException;
use Framadate\FramaDB;
use Framadate\Repositories\RepositoryFactory; use Framadate\Repositories\RepositoryFactory;
use Framadate\Utils;
/** /**
* Class AdminPollService * Class AdminPollService
@ -21,7 +20,7 @@ class AdminPollService {
private $voteRepository; private $voteRepository;
private $commentRepository; private $commentRepository;
function __construct(FramaDB $connect, PollService $pollService, LogService $logService) { function __construct(Connection $connect, PollService $pollService, LogService $logService) {
$this->connect = $connect; $this->connect = $connect;
$this->pollService = $pollService; $this->pollService = $pollService;
$this->logService = $logService; $this->logService = $logService;
@ -35,7 +34,7 @@ class AdminPollService {
global $config; global $config;
if ($poll->end_date > $poll->creation_date) { if ($poll->end_date > $poll->creation_date) {
return $this->pollRepository->update($poll); return $this->pollRepository->update($poll);
} }
return false; return false;
} }
@ -295,11 +294,10 @@ class AdminPollService {
} elseif ($datetime < $rowDatetime) { } elseif ($datetime < $rowDatetime) {
// We have to insert before this slot // We have to insert before this slot
break; break;
} }
$result->insert += count($moments); $result->insert += count($moments);
} }
return $result; return $result;
} }
} }

View File

@ -17,6 +17,9 @@
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft) * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/ */
namespace Framadate\Services; namespace Framadate\Services;
use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\DriverManager;
use Framadate\Utils; use Framadate\Utils;
use Smarty; use Smarty;
@ -33,7 +36,9 @@ class InstallService {
'cleanUrl' => true, 'cleanUrl' => true,
// Database configuration // Database configuration
'dbConnectionString' => 'mysql:host=<HOST>;dbname=<SCHEMA>;port=3306', 'dbName' => 'framadate',
'dbPort' => 3306,
'dbHost' => 'localhost',
'dbUser' => 'root', 'dbUser' => 'root',
'dbPassword' => '', 'dbPassword' => '',
'dbPrefix' => 'fd_', 'dbPrefix' => 'fd_',
@ -50,12 +55,12 @@ class InstallService {
public function install(Smarty &$smarty) { public function install(Smarty &$smarty) {
// Check values are present // Check values are present
if (empty($this->fields['appName']) || empty($this->fields['appMail']) || empty($this->fields['defaultLanguage']) || empty($this->fields['dbConnectionString']) || empty($this->fields['dbUser'])) { if (empty($this->fields['appName']) || empty($this->fields['appMail']) || empty($this->fields['defaultLanguage']) || empty($this->fields['dbName']) || empty($this->fields['dbHost']) || empty($this->fields['dbPort']) || empty($this->fields['dbUser'])) {
return $this->error('MISSING_VALUES'); return $this->error('MISSING_VALUES');
} }
// Connect to database // Connect to database
$connect = $this->connectTo($this->fields['dbConnectionString'], $this->fields['dbUser'], $this->fields['dbPassword']); $connect = $this->connectTo($this->fields);
if (!$connect) { if (!$connect) {
return $this->error('CANT_CONNECT_TO_DATABASE'); return $this->error('CANT_CONNECT_TO_DATABASE');
} }
@ -68,13 +73,25 @@ class InstallService {
return $this->ok(); return $this->ok();
} }
function connectTo($connectionString, $user, $password) { /**
* @param $fields
* @return \Doctrine\DBAL\Connection|null
*/
function connectTo($fields) {
$doctrineConfig = new Configuration();
$connectionParams = [
'dbname' => $fields['dbName'],
'user' => $fields['dbUser'],
'password' => $fields['dbPassword'],
'host' => $fields['dbHost'],
'driver' => $fields['dbDriver'],
'charset' => $fields['dbDriver'] === 'pdo_mysql' ? 'utf8mb4' : 'utf8',
];
try { try {
$pdo = @new \PDO($connectionString, $user, $password); return DriverManager::getConnection($connectionParams, $doctrineConfig);
$pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_OBJ); } catch (DBALException $e) {
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); $logger = new LogService();
return $pdo; $logger->log('ERROR', $e->getMessage());
} catch(\Exception $e) {
return null; return null;
} }
} }
@ -91,6 +108,7 @@ class InstallService {
/** /**
* @param $content * @param $content
* @return bool|int
*/ */
function writeToFile($content) { function writeToFile($content) {
return @file_put_contents(CONF_FILENAME, $content); return @file_put_contents(CONF_FILENAME, $content);

View File

@ -18,11 +18,12 @@
*/ */
namespace Framadate\Services; namespace Framadate\Services;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Framadate\Exception\AlreadyExistsException; use Framadate\Exception\AlreadyExistsException;
use Framadate\Exception\ConcurrentEditionException; use Framadate\Exception\ConcurrentEditionException;
use Framadate\Exception\ConcurrentVoteException; use Framadate\Exception\ConcurrentVoteException;
use Framadate\Form; use Framadate\Form;
use Framadate\FramaDB;
use Framadate\Repositories\RepositoryFactory; use Framadate\Repositories\RepositoryFactory;
use Framadate\Security\Token; use Framadate\Security\Token;
@ -35,7 +36,7 @@ class PollService {
private $voteRepository; private $voteRepository;
private $commentRepository; private $commentRepository;
function __construct(FramaDB $connect, LogService $logService) { function __construct(Connection $connect, LogService $logService) {
$this->connect = $connect; $this->connect = $connect;
$this->logService = $logService; $this->logService = $logService;
$this->pollRepository = RepositoryFactory::pollRepository(); $this->pollRepository = RepositoryFactory::pollRepository();
@ -48,6 +49,7 @@ class PollService {
* Find a poll from its ID. * Find a poll from its ID.
* *
* @param $poll_id int The ID of the poll * @param $poll_id int The ID of the poll
* @throws \Doctrine\DBAL\DBALException
* @return \stdClass|null The found poll, or null * @return \stdClass|null The found poll, or null
*/ */
function findById($poll_id) { function findById($poll_id) {
@ -66,8 +68,18 @@ class PollService {
return null; return null;
} }
function allCommentsByPollId($poll_id) { /**
return $this->commentRepository->findAllByPollId($poll_id); * @param $poll_id
* @return array
*/
public function allCommentsByPollId($poll_id)
{
try {
return $this->commentRepository->findAllByPollId($poll_id);
} catch (DBALException $e) {
$this->logService->log('error', $e->getMessage());
return null;
}
} }
function allVotesByPollId($poll_id) { function allVotesByPollId($poll_id) {

View File

@ -1,6 +1,7 @@
<?php <?php
namespace Framadate\Services; namespace Framadate\Services;
use Framadate\FramaDB; use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException;
use Framadate\Repositories\RepositoryFactory; use Framadate\Repositories\RepositoryFactory;
/** /**
@ -15,7 +16,7 @@ class PurgeService {
private $voteRepository; private $voteRepository;
private $commentRepository; private $commentRepository;
function __construct(FramaDB $connect, LogService $logService) { function __construct(Connection $connect, LogService $logService) {
$this->logService = $logService; $this->logService = $logService;
$this->pollRepository = RepositoryFactory::pollRepository(); $this->pollRepository = RepositoryFactory::pollRepository();
$this->slotRepository = RepositoryFactory::slotRepository(); $this->slotRepository = RepositoryFactory::slotRepository();
@ -36,23 +37,34 @@ class PurgeService {
* *
* @return bool true is action succeeded * @return bool true is action succeeded
*/ */
function purgeOldPolls() { public function purgeOldPolls() {
$oldPolls = $this->pollRepository->findOldPolls(); try {
$count = count($oldPolls); $oldPolls = $this->pollRepository->findOldPolls();
$count = count($oldPolls);
if ($count > 0) { if ($count > 0) {
$this->logService->log('EXPIRATION', 'Going to purge ' . $count . ' poll(s)...'); $this->logService->log('EXPIRATION', 'Going to purge ' . $count . ' poll(s)...');
foreach ($oldPolls as $poll) { foreach ($oldPolls as $poll) {
if ($this->purgePollById($poll->id)) { if ($this->purgePollById($poll->id)) {
$this->logService->log('EXPIRATION_SUCCESS', 'id: ' . $poll->id . ', title:' . $poll->title . ', format: ' . $poll->format . ', admin: ' . $poll->admin_name); $this->logService->log(
} else { 'EXPIRATION_SUCCESS',
$this->logService->log('EXPIRATION_FAILED', 'id: ' . $poll->id . ', title:' . $poll->title . ', format: ' . $poll->format . ', admin: ' . $poll->admin_name); 'id: ' . $poll->id . ', title:' . $poll->title . ', format: ' . $poll->format . ', admin: ' . $poll->admin_name
);
} else {
$this->logService->log(
'EXPIRATION_FAILED',
'id: ' . $poll->id . ', title:' . $poll->title . ', format: ' . $poll->format . ', admin: ' . $poll->admin_name
);
}
} }
} }
}
return $count; return $count;
} catch (DBALException $e) {
$this->logService->log('ERROR', $e->getMessage());
return false;
}
} }
public function cleanDemoPoll() { public function cleanDemoPoll() {
@ -78,22 +90,25 @@ class PurgeService {
* @param $poll_id int The ID of the poll * @param $poll_id int The ID of the poll
* @return bool true is action succeeded * @return bool true is action succeeded
*/ */
function purgePollById($poll_id) { private function purgePollById($poll_id) {
$done = true; $done = true;
$this->pollRepository->beginTransaction(); try {
$done &= $this->commentRepository->deleteByPollId($poll_id); $this->pollRepository->beginTransaction();
$done &= $this->voteRepository->deleteByPollId($poll_id); $done &= $this->commentRepository->deleteByPollId($poll_id);
$done &= $this->slotRepository->deleteByPollId($poll_id); $done &= $this->voteRepository->deleteByPollId($poll_id);
$done &= $this->pollRepository->deleteById($poll_id); $done &= $this->slotRepository->deleteByPollId($poll_id);
$done &= $this->pollRepository->deleteById($poll_id);
if ($done) { if ($done) {
$this->pollRepository->commit(); $this->pollRepository->commit();
} else { } else {
$this->pollRepository->rollback(); $this->pollRepository->rollback();
}
} catch (DBALException $e) {
$this->logService->log('ERROR', $e->getMessage());
} }
return $done; return $done;
} }
} }

View File

@ -25,13 +25,16 @@ class Utils {
* @return string Server name * @return string Server name
*/ */
public static function get_server_name() { public static function get_server_name() {
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '';
$serverPort = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : '';
$scheme = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')) ? 'https' : 'http'; $scheme = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')) ? 'https' : 'http';
$port = in_array($_SERVER['SERVER_PORT'], ['80', '443'], true) ? '' : ':' . $_SERVER['SERVER_PORT']; $port = in_array($serverPort, ['80', '443'], true) ? '' : ':' . $serverPort;
$dirname = dirname($_SERVER['SCRIPT_NAME']); $dirname = dirname($_SERVER['SCRIPT_NAME']);
$dirname = $dirname === '\\' ? '/' : $dirname . '/'; $dirname = $dirname === '\\' ? '/' : $dirname . '/';
$dirname = str_replace('/admin', '', $dirname); $dirname = str_replace('/admin', '', $dirname);
$dirname = str_replace('/action', '', $dirname); $dirname = str_replace('/action', '', $dirname);
$server_name = (defined('APP_URL') ? APP_URL : $_SERVER['SERVER_NAME']) . $port . $dirname; $server_name = (defined('APP_URL') ? APP_URL : $serverName) . $port . $dirname;
return $scheme . '://' . preg_replace('#//+#', '/', $server_name); return $scheme . '://' . preg_replace('#//+#', '/', $server_name);
} }

116
app/inc/config.test.php Normal file
View File

@ -0,0 +1,116 @@
<?php
/**
* This software is governed by the CeCILL-B license. If a copy of this license
* is not distributed with this file, you can obtain one at
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
*
* Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
* Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
*
* =============================
*
* Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
* ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
* http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
*
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/
// Fully qualified domain name of your webserver.
// If this is unset or empty, the servername is determined automatically.
// You *have to set this* if you are running Framadate behind a reverse proxy.
// const APP_URL = '<www.mydomain.fr>';
// Application name
const NOMAPPLICATION = 'Framadate';
// Database administrator email
const ADRESSEMAILADMIN = 'admin@app.tld';
// Email for automatic responses (you should set it to "no-reply")
const ADRESSEMAILREPONSEAUTO = 'no@reply';
// Database driver
const DB_DRIVER = 'pdo_sqlite';
// Database name
const DB_NAME = 'framadate';
// Database host
const DB_HOST = '';
// Database port
const DB_PORT = '';
// Database user
const DB_USER = '';
// Database password
const DB_PASSWORD = '';
// Table name prefix
const TABLENAME_PREFIX = 'fd_';
// Name of the table that stores migration script already executed
const MIGRATION_TABLE = 'framadate_migration';
// Default Language
const DEFAULT_LANGUAGE = 'fr';
// List of supported languages, fake constant as arrays can be used as constants only in PHP >=5.6
$ALLOWED_LANGUAGES = [
'fr' => 'Français',
'en' => 'English',
'oc' => 'Occitan',
'es' => 'Español',
'de' => 'Deutsch',
'nl' => 'Dutch',
'it' => 'Italiano',
'br' => 'Brezhoneg',
];
// Path to image file with the title
const IMAGE_TITRE = 'images/logo-framadate.png';
// Clean URLs, boolean
const URL_PROPRE = false;
// Use REMOTE_USER data provided by web server
const USE_REMOTE_USER = true;
// Path to the log file
const LOG_FILE = 'admin/stdout.log';
// Days (after expiration date) before purging a poll
const PURGE_DELAY = 60;
// Max slots per poll
const MAX_SLOTS_PER_POLL = 366;
// Number of seconds before we allow to resend an "Remember Edit Link" email.
const TIME_EDIT_LINK_EMAIL = 60;
// Config
$config = [
/* general config */
'use_smtp' => false, // use email for polls creation/modification/responses notification
'smtp_options' => [
'host' => 'localhost', // SMTP server (you could add many servers (main and backup for example) : use ";" like separator
'auth' => false, // Enable SMTP authentication
'username' => '', // SMTP username
'password' => '', // SMTP password
'secure' => '', // Enable encryption (false, tls or ssl)
'port' => 25, // TCP port to connect to
],
/* home */
'show_what_is_that' => true, // display "how to use" section
'show_the_software' => true, // display technical information about the software
'show_cultivate_your_garden' => true, // display "development and administration" information
/* create_classic_poll.php / create_date_poll.php */
'default_poll_duration' => 180, // default values for the new poll duration (number of days).
/* create_classic_poll.php */
'user_can_add_img_or_link' => true, // user can add link or URL when creating his poll.
'markdown_editor_by_default' => true, // The markdown editor for the description is enabled by default
'provide_fork_awesome' => true, // Whether the build-in fork-awesome should be provided
];

View File

@ -16,8 +16,12 @@
* Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
* Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft) * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
*/ */
use Framadate\FramaDB;
use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\DriverManager;
use Framadate\Repositories\RepositoryFactory; use Framadate\Repositories\RepositoryFactory;
use Framadate\Services\LogService;
// Autoloading of dependencies with Composer // Autoloading of dependencies with Composer
require_once __DIR__ . '/../../vendor/autoload.php'; require_once __DIR__ . '/../../vendor/autoload.php';
@ -32,17 +36,41 @@ if (ini_get('date.timezone') === '') {
} }
define('ROOT_DIR', __DIR__ . '/../../'); define('ROOT_DIR', __DIR__ . '/../../');
define('CONF_FILENAME', ROOT_DIR . '/app/inc/config.php');
$path = '/app/inc/config.php';
if (getenv('APP_ENV') === 'test') {
$path = '/app/inc/config.test.php';
}
define('CONF_FILENAME', ROOT_DIR . $path);
require_once __DIR__ . '/constants.php'; require_once __DIR__ . '/constants.php';
if (is_file(CONF_FILENAME)) { if (is_file(CONF_FILENAME)) {
@include_once __DIR__ . '/config.php'; @include_once CONF_FILENAME;
// Connection to database // Connection to database
$connect = new FramaDB(DB_CONNECTION_STRING, DB_USER, DB_PASSWORD); $doctrineConfig = new Configuration();
RepositoryFactory::init($connect); $connectionParams = [
$err = 0; 'dbname' => DB_NAME,
'user' => DB_USER,
'password' => DB_PASSWORD,
'host' => DB_HOST,
'driver' => DB_DRIVER,
'charset' => DB_DRIVER === 'pdo_mysql' ? 'utf8mb4' : 'utf8',
];
if (DB_DRIVER === 'pdo_sqlite') {
$connectionParams['path'] = 'test_database.sqlite';
}
try {
$connect = DriverManager::getConnection($connectionParams, $doctrineConfig);
RepositoryFactory::init($connect);
$err = 0;
} catch (DBALException $e) {
$logger = new LogService();
$logger->log('ERROR', $e->getMessage());
}
} else { } else {
define('NOMAPPLICATION', 'Framadate'); define('NOMAPPLICATION', 'Framadate');
define('DEFAULT_LANGUAGE', 'fr'); define('DEFAULT_LANGUAGE', 'fr');

View File

@ -25,11 +25,14 @@ $smarty->setCompileDir(ROOT_DIR . COMPILE_DIR);
$smarty->setCacheDir(ROOT_DIR . '/cache/'); $smarty->setCacheDir(ROOT_DIR . '/cache/');
$smarty->caching = false; $smarty->caching = false;
$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '';
$smarty->assign('APPLICATION_NAME', NOMAPPLICATION); $smarty->assign('APPLICATION_NAME', NOMAPPLICATION);
$smarty->assign('SERVER_URL', Utils::get_server_name()); $smarty->assign('SERVER_URL', Utils::get_server_name());
$smarty->assign('SCRIPT_NAME', $_SERVER['SCRIPT_NAME']); $smarty->assign('SCRIPT_NAME', $_SERVER['SCRIPT_NAME']);
$smarty->assign('TITLE_IMAGE', IMAGE_TITRE); $smarty->assign('TITLE_IMAGE', IMAGE_TITRE);
$smarty->assign('use_nav_js', strstr($_SERVER['SERVER_NAME'], 'framadate.org'));
$smarty->assign('use_nav_js', strstr($serverName, 'framadate.org'));
$smarty->assign('provide_fork_awesome', !isset($config['provide_fork_awesome']) || $config['provide_fork_awesome']); $smarty->assign('provide_fork_awesome', !isset($config['provide_fork_awesome']) || $config['provide_fork_awesome']);
$smarty->assign('locale', $locale); $smarty->assign('locale', $locale);
$smarty->assign('langs', $ALLOWED_LANGUAGES); $smarty->assign('langs', $ALLOWED_LANGUAGES);

View File

@ -1,32 +1,35 @@
<?php <?php
namespace Framadate\Services; namespace Framadate\Services;
use Framadate\FramaTestCase; use Framadate\FramaTestCase;
class InputServiceUnitTest extends FramaTestCase class InputServiceUnitTest extends FramaTestCase
{ {
public function liste_emails() { public function liste_emails()
{
return [ return [
// valids addresses // valids addresses
"valid address" => ["example@example.com", "example@example.com"], "valid address" => ["example@example.com", "example@example.com"],
"local address" => ["test@localhost", "test@localhost"], "local address" => ["test@localhost", "test@localhost"],
"IP address" => ["ip.email@127.0.0.1", "ip.email@127.0.0.1"], "IP address" => ["ip.email@127.0.0.1", "ip.email@127.0.0.1"],
"with spaces arround" => [" with@spaces ", "with@spaces"], "with spaces arround" => [" with@spaces ", "with@spaces"],
"unicode caracters" => ["unicode.éà@idn-œ.com", "unicode.éà@idn-œ.com"], "unicode caracters" => ["unicode.éà@idn-œ.com", "unicode.éà@idn-œ.com"],
// invalids addresses // invalids addresses
"without domain" => ["without-domain", FALSE], "without domain" => ["without-domain", FALSE],
"space inside" => ["example example@example.com", FALSE], "space inside" => ["example example@example.com", FALSE],
"forbidden chars" => ["special_chars.@example.com", FALSE], "forbidden chars" => ["special_chars.@example.com", FALSE],
]; ];
} }
/** /**
* @dataProvider liste_emails * @dataProvider liste_emails
*/ */
public function test_filterMail($email, $expected) { public function test_filterMail($email, $expected)
$inputService = new InputService(); {
$filtered = $inputService->filterMail($email); $inputService = new InputService();
$filtered = $inputService->filterMail($email);
$this->assertSame($expected, $filtered); $this->assertSame($expected, $filtered);
} }
} }

58
bin/doctrine Executable file
View File

@ -0,0 +1,58 @@
#!/usr/bin/env php
<?php
use Doctrine\DBAL\Migrations\Configuration\Configuration;
use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper;
use Framadate\Utils;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Style\SymfonyStyle;
try {
require_once __DIR__ . '/../app/inc/init.php';
$input = new ArgvInput();
$output = new ConsoleOutput();
$style = new SymfonyStyle($input, $output);
if ($connect === null) {
throw new \Exception("Undefined database connection\n");
}
// replace the ConsoleRunner::run() statement with:
$cli = new Application('Doctrine Command Line Interface', VERSION);
$cli->setCatchExceptions(true);
$helperSet = new HelperSet(
[
'db' => new ConnectionHelper($connect),
'question' => new QuestionHelper(),
]
);
$cli->setHelperSet($helperSet);
$migrateCommand = new \Doctrine\DBAL\Migrations\Tools\Console\Command\MigrateCommand();
$statusCommand = new \Doctrine\DBAL\Migrations\Tools\Console\Command\StatusCommand();
$migrationsDirectory = __DIR__ . '/../app/classes/Framadate/Migrations';
$configuration = new Configuration($connect);
$configuration->setMigrationsTableName(Utils::table(MIGRATION_TABLE) . '_new');
$configuration->setMigrationsDirectory($migrationsDirectory);
$configuration->setMigrationsNamespace('DoctrineMigrations');
$configuration->registerMigrationsFromDirectory($migrationsDirectory);
$migrateCommand->setMigrationConfiguration($configuration);
$statusCommand->setMigrationConfiguration($configuration);
// Register All Doctrine Commands
$cli->addCommands([$migrateCommand, $statusCommand]);
// Runs console application
$cli->run($input, $output);
} catch (\Exception $e) {
$style->error($e->getMessage());
}

View File

@ -62,7 +62,10 @@
"ircmaxell/password-compat": "dev-master", "ircmaxell/password-compat": "dev-master",
"roave/security-advisories": "dev-master", "roave/security-advisories": "dev-master",
"erusev/parsedown": "^1.7", "erusev/parsedown": "^1.7",
"egulias/email-validator": "~2.1" "egulias/email-validator": "~2.1",
"doctrine/dbal": "^2.5",
"doctrine/migrations": "^1.5",
"sensiolabs/ansi-to-html": "^1.1"
}, },
"require-dev": { "require-dev": {

1480
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -36,6 +36,9 @@
"Expiration date": "Expiry date", "Expiration date": "Expiry date",
"Fail": "Fail", "Fail": "Fail",
"Failed:": "Failed:", "Failed:": "Failed:",
"Status": "Status",
"Waiting": "Waiting",
"Executed": "Executed",
"Format": "Format", "Format": "Format",
"Installation": "Installation", "Installation": "Installation",
"Logs": "Logs", "Logs": "Logs",
@ -237,8 +240,11 @@
"AppName": "Application name", "AppName": "Application name",
"CleanUrl": "Clean URL", "CleanUrl": "Clean URL",
"Database": "Database name", "Database": "Database name",
"DbConnectionString": "Connection string", "DbDriver": "Database driver",
"DbHost": "Database hostname",
"DbName": "Database name",
"DbPassword": "Password", "DbPassword": "Password",
"DbPort": "Database port",
"DbPrefix": "Prefix", "DbPrefix": "Prefix",
"DbUser": "User", "DbUser": "User",
"DefaultLanguage": "Default language", "DefaultLanguage": "Default language",

View File

@ -54,6 +54,9 @@
"Summary": "Résumé", "Summary": "Résumé",
"Title": "Titre", "Title": "Titre",
"Votes": "Votes", "Votes": "Votes",
"Status": "Statut",
"Waiting": "En attente",
"Executed": "Exécutées",
"polls in the database at this time": "sondages dans la base actuellement" "polls in the database at this time": "sondages dans la base actuellement"
}, },
"Check": { "Check": {
@ -237,8 +240,11 @@
"AppName": "Nom de l'application", "AppName": "Nom de l'application",
"CleanUrl": "URL propres", "CleanUrl": "URL propres",
"Database": "Base de données", "Database": "Base de données",
"DbConnectionString": "Chaîne de connexion", "DbDriver": "Pilote de la base de données",
"DbHost": "Nom d'hôte",
"DbName": "Nom de la base de données",
"DbPassword": "Mot de passe", "DbPassword": "Mot de passe",
"DbPort": "Port du serveur",
"DbPrefix": "Préfixe", "DbPrefix": "Préfixe",
"DbUser": "Utilisateur·rice", "DbUser": "Utilisateur·rice",
"DefaultLanguage": "Langue par défaut", "DefaultLanguage": "Langue par défaut",

View File

@ -54,6 +54,9 @@
"Summary": "Résumé", "Summary": "Résumé",
"Title": "Titre", "Title": "Titre",
"Votes": "Votes", "Votes": "Votes",
"Status": "Statut",
"Waiting": "En attente",
"Executed": "Exécutées",
"polls in the database at this time": "sondages dans la base actuellement" "polls in the database at this time": "sondages dans la base actuellement"
}, },
"Check": { "Check": {
@ -237,8 +240,11 @@
"AppName": "Nom de l'application", "AppName": "Nom de l'application",
"CleanUrl": "URL propres", "CleanUrl": "URL propres",
"Database": "Base de données", "Database": "Base de données",
"DbConnectionString": "Chaîne de connexion", "DbDriver": "Pilote de la base de données",
"DbHost": "Nom d'hôte",
"DbName": "Nom de la base de données",
"DbPassword": "Mot de passe", "DbPassword": "Mot de passe",
"DbPort": "Port du serveur",
"DbPrefix": "Préfixe", "DbPrefix": "Préfixe",
"DbUser": "Utilisateur·rice", "DbUser": "Utilisateur·rice",
"DefaultLanguage": "Langue par défaut", "DefaultLanguage": "Langue par défaut",

View File

@ -31,11 +31,20 @@ const ADRESSEMAILADMIN = '{$appMail}';
// Email for automatic responses (you should set it to "no-reply") // Email for automatic responses (you should set it to "no-reply")
const ADRESSEMAILREPONSEAUTO = '{$responseMail}'; const ADRESSEMAILREPONSEAUTO = '{$responseMail}';
// Database server name, leave empty to use a socket // Database driver
const DB_CONNECTION_STRING = '{$dbConnectionString}'; const DB_DRIVER = '{$dbDriver}';
// Database name
const DB_NAME = '{$dbName}';
// Database host
const DB_HOST = '{$dbHost}';
// Database port
const DB_PORT = '{$dbPort}';
// Database user // Database user
const DB_USER= '{$dbUser}'; const DB_USER = '{$dbUser}';
// Database password // Database password
const DB_PASSWORD = '{$dbPassword|addslashes_single_quote}'; const DB_PASSWORD = '{$dbPassword|addslashes_single_quote}';

View File

@ -17,38 +17,53 @@
<label for="appName" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'AppName')}</label> <label for="appName" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'AppName')}</label>
<input type="text" class="form-control" id="appName" name="appName" value="{$fields['appName']}" autofocus required> <input type="text" class="form-control" id="appName" name="appName" value="{$fields['appName']}" autofocus required>
</div> </div>
<p class="help-block">Le nom de l'application qui sera notamment utilisé dans les emails.</p>
</div> </div>
<div class="form-group"> <div class="row">
<div class="input-group"> <div class="col-md-6">
<label for="appMail" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'AppMail')}</label> <div class="form-group">
<input type="email" class="form-control" id="appMail" name="appMail" value="{$fields['appMail']}" required> <div class="input-group">
<label for="appMail" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'AppMail')}</label>
<input type="email" class="form-control" id="appMail" name="appMail" value="{$fields['appMail']}" required>
</div>
<p class="help-block">L'adresse email de l'administrateur qui sera fournie en cas de souci.</p>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<div class="input-group">
<label for="responseMail" class="input-group-addon">{__('Installation', 'ResponseMail')}</label>
<input type="email" class="form-control" id="responseMail" name="responseMail" value="{$fields['responseMail']}">
</div>
<p class="help-block">L'adresse de réponse des couriels envoyés par l'application.</p>
</div>
</div> </div>
</div> </div>
<div class="form-group"> <div class="row">
<div class="input-group"> <div class="col-md-6">
<label for="responseMail" class="input-group-addon">{__('Installation', 'ResponseMail')}</label> <div class="form-group">
<input type="email" class="form-control" id="responseMail" name="responseMail" value="{$fields['responseMail']}"> <div class="input-group">
<label for="defaultLanguage" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'DefaultLanguage')}</label>
<select type="email" class="form-control" id="defaultLanguage" name="defaultLanguage" required>
{foreach $langs as $lang=>$label}
<option value="{$lang}" {if $lang==$fields['defaultLanguage']}selected{/if}>{$label}</option>
{/foreach}
</select>
</div>
</div>
</div> </div>
</div> <div class="col-md-6">
<div class="form-group"> <div class="input-group">
<div class="input-group"> <label for="cleanUrl" class="input-group-addon">{__('Installation', 'CleanUrl')}</label>
<label for="defaultLanguage" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'DefaultLanguage')}</label>
<select type="email" class="form-control" id="defaultLanguage" name="defaultLanguage" required>
{foreach $langs as $lang=>$label}
<option value="{$lang}" {if $lang==$fields['defaultLanguage']}selected{/if}>{$label}</option>
{/foreach}
</select>
</div>
</div>
<div class="input-group"> <div class="form-control">
<label for="cleanUrl" class="input-group-addon">{__('Installation', 'CleanUrl')}</label> <input type="checkbox" id="cleanUrl" name="cleanUrl" {($fields['cleanUrl']) ? 'checked' : ''}>
<p class="help-block">Utiliser la réécriture d'URL pour obtenir de belles URLs.</p>
<div class="form-control"> </div>
<input type="checkbox" id="cleanUrl" name="cleanUrl" {($fields['cleanUrl']) ? 'checked' : ''}> </div>
</div> </div>
</div> </div>
</div> </div>
@ -56,38 +71,91 @@
<fieldset> <fieldset>
<legend>{__('Installation', 'Database')}</legend> <legend>{__('Installation', 'Database')}</legend>
<div class="form-group"> <div class="form-group">
<div class="input-group"> {__('Installation', 'DbDriver')}
<label for="dbConnectionString" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'DbConnectionString')}</label> <div class="radio">
<input type="text" class="form-control" id="dbConnectionString" name="dbConnectionString" value="{$fields['dbConnectionString']}" required> <label>
<input type="radio" name="dbDriver" id="dbDriver_mysql" value="pdo_mysql" checked>
MySQL
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="dbDriver" id="dbDriver_pgsql" value="pdo_pgsql">
PostgreSQL
</label>
</div>
</div>
<div class="row">
<div class="col-md-8">
<div class="form-group">
<div class="input-group">
<label for="dbHost" class="input-group-addon">{__('Installation', 'DbHost')}</label>
<input type="text" class="form-control" id="dbHost" name="dbHost" value="{$fields['dbHost']}" required>
</div>
<p class="help-block">Le nom d'hôte du serveur de base de données, <code>localhost</code> si le serveur est le même.</p>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<div class="input-group">
<label for="dbPort" class="input-group-addon">{__('Installation', 'DbPort')}</label>
<input type="text" class="form-control" id="dbPort" name="dbPort" value="{$fields['dbPort']}">
</div>
<p class="help-block">Port 3306 par défaut pour MySQL, 5432 pour PostgreSQL</p>
</div>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="input-group"> <div class="input-group">
<label for="dbUser" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'DbUser')}</label> <label for="dbName" class="input-group-addon">{__('Installation', 'DbName')}</label>
<input type="text" class="form-control" id="dbUser" name="dbUser" value="{$fields['dbUser']}" required> <input type="text" class="form-control" id="dbName" name="dbName" value="{$fields['dbName']}">
</div> </div>
</div> </div>
<div class="form-group"> <div class="row">
<div class="input-group"> <div class="col-md-6">
<label for="dbPassword" class="input-group-addon">{__('Installation', 'DbPassword')}</label> <div class="form-group">
<input type="password" class="form-control" id="dbPassword" name="dbPassword" value="{$fields['dbPassword']}"> <div class="input-group">
<label for="dbUser" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'DbUser')}</label>
<input type="text" class="form-control" id="dbUser" name="dbUser" value="{$fields['dbUser']}" required>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<div class="input-group">
<label for="dbPassword" class="input-group-addon">{__('Installation', 'DbPassword')}</label>
<input type="password" class="form-control" id="dbPassword" name="dbPassword" value="{$fields['dbPassword']}">
</div>
</div>
</div> </div>
</div> </div>
<div class="form-group"> <div class="row">
<div class="input-group"> <div class="col-md-6">
<label for="dbPrefix" class="input-group-addon">{__('Installation', 'DbPrefix')}</label> <div class="form-group">
<input type="text" class="form-control" id="dbPrefix" name="dbPrefix" value="{$fields['dbPrefix']}"> <div class="input-group">
<label for="dbPrefix" class="input-group-addon">{__('Installation', 'DbPrefix')}</label>
<input type="text" class="form-control" id="dbPrefix" name="dbPrefix" value="{$fields['dbPrefix']}">
</div>
<p class="help-block">Le préfixe à appliquer devant les tables</p>
</div>
</div> </div>
</div>
<div class="form-group"> <div class="col-md-6">
<div class="input-group"> <div class="form-group">
<label for="migrationTable" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'MigrationTable')}</label> <div class="input-group">
<input type="text" class="form-control" id="migrationTable" name="migrationTable" value="{$fields['migrationTable']}" required> <label for="migrationTable" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'MigrationTable')}</label>
<input type="text" class="form-control" id="migrationTable" name="migrationTable" value="{$fields['migrationTable']}" required>
</div>
<p class="help-block">La table utilisée pour stocker les migrations</p>
</div>
</div> </div>
</div> </div>
</fieldset> </fieldset>

View File

@ -1,39 +1,36 @@
{extends 'admin/admin_page.tpl'} {extends 'admin/admin_page.tpl'}
{block 'admin_main'} {block 'admin_main'}
{if $executing}
<div class="row">
<pre>{$output}</pre>
<div class="col-xs-12 well well-sm">
{__('Generic', 'Page generated in')} {$time} {__('Generic', 'seconds')}
</div>
</div>
{/if}
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-4">
<h2>{__('Admin', 'Status')}</h2>
{if $countExecuted === $countTotal}
<div class="alert alert-success">
No migrations to execute
</div>
{else}
<div class="alert alert-danger">
<form method="POST">
<button type="submit" class="btn btn-danger btn-lg" name="execute">Execute migration</button>
</form>
<br />
{$countWaiting|html} migrations available.
</div>
{/if}
</div>
<div class="col-xs-12 col-md-4"> <div class="col-xs-12 col-md-4">
<h2>{__('Admin', 'Summary')}</h2> <h2>{__('Admin', 'Summary')}</h2>
{__('Admin', 'Succeeded:')} <span class="label label-warning">{$countSucceeded|html} / {$countTotal|html}</span> {__('Admin', 'Waiting')} <span class="label label-warning">{$countWaiting|html} / {$countTotal|html}</span>
<br/> <br/>
{__('Admin', 'Failed:')} <span class="label label-danger">{$countFailed|html} / {$countTotal|html}</span> {__('Admin', 'Executed')} <span class="label label-success">{$countExecuted|html} / {$countTotal|html}</span>
<br/>
{__('Admin', 'Skipped:')} <span class="label label-info">{$countSkipped|html} / {$countTotal|html}</span>
</div>
<div class="col-xs-12 col-md-4">
<h2>{__('Admin', 'Success')}</h2>
<ul>
{foreach $success as $s}
<li>{$s|html}</li>
{foreachelse}
<li>{__('Admin', 'Nothing')}</li>
{/foreach}
</ul>
</div>
<div class="col-xs-12 col-md-4">
<h2>{__('Admin', 'Fail')}</h2>
<ul>
{foreach $fail as $f}
<li>{$f|html}</li>
{foreachelse}
<li>{__('Admin', 'Nothing')}</li>
{/foreach}
</ul>
</div>
<div class="col-xs-12 well well-sm">
{__('Generic', 'Page generated in')} {$time} {__('Generic', 'seconds')}
</div> </div>
</div> </div>
{/block} {/block}

View File

@ -199,7 +199,7 @@
{foreach $slots as $id=>$slot} {foreach $slots as $id=>$slot}
<td class="bg-info" headers="C{$id}"> <td class="bg-info" headers="C{$id}">
<ul class="list-unstyled choice"> <ul class="list-unstyled choice">
{if $poll->ValueMax eq NULL || $best_choices['y'][$i] lt $poll->ValueMax} {if $poll->valuemax eq NULL || $best_choices['y'][$i] lt $poll->valuemax}
<li class="yes"> <li class="yes">
<input type="radio" id="y-choice-{$id}" name="choices[{$id}]" value="2" <input type="radio" id="y-choice-{$id}" name="choices[{$id}]" value="2"
{(!isset($selectedNewVotes[$id]) || ("2" !== $selectedNewVotes[$id])) ? "" : " checked"} {(!isset($selectedNewVotes[$id]) || ("2" !== $selectedNewVotes[$id])) ? "" : " checked"}

View File

@ -258,7 +258,7 @@
<td class="bg-info" headers="M{$headersM[$i]} D{$headersD[$i]} H{$headersH[$i]}"> <td class="bg-info" headers="M{$headersM[$i]} D{$headersD[$i]} H{$headersH[$i]}">
<ul class="list-unstyled choice"> <ul class="list-unstyled choice">
{if $poll->ValueMax eq NULL || $best_choices['y'][$i] lt $poll->ValueMax} {if $poll->valuemax eq NULL || $best_choices['y'][$i] lt $poll->valuemax}
<li class="yes"> <li class="yes">
<input type="radio" id="y-choice-{$i}" name="choices[{$i}]" value="2" <input type="radio" id="y-choice-{$i}" name="choices[{$i}]" value="2"
{(!isset($selectedNewVotes[$i]) || ("2" !== $selectedNewVotes[$i])) ? "" : " checked"} {(!isset($selectedNewVotes[$i]) || ("2" !== $selectedNewVotes[$i])) ? "" : " checked"}

View File

@ -17,7 +17,6 @@
{block name=main} {block name=main}
{* Messages *} {* Messages *}
{include 'part/messages.tpl'} {include 'part/messages.tpl'}