Commit 0654f9ed authored by Bastien Le Querrec's avatar Bastien Le Querrec

Merge branch 'preprod'

parents 632c578f 5619a40c
......@@ -12,6 +12,7 @@ app/env
.php_cs.cache
.DS_Store
__MAC
.vscode/
tests/_data
tests/_output
......
before_script:
- '[[ -d /srv/soutien/ ]] || mkdir -p /srv/soutien/'
- 'which git || (apt-get update -yq && apt-get install git -yqq)'
stages:
- test
- cleanup_test
- deploy
job test:
stage: test
variables:
GIT_SUBMODULE_STRATEGY: normal
SQL_HOST: "localhost"
SQL_PORT: "3306"
SQL_DATABASE: "test_$CI_BUILD_REF"
SQL_USER: "soutien"
SQL_PASSWORD: "soutien"
PHINX_PASSWORD: "$SQL_PASSWORD"
PHINX_USER: "$SQL_USER"
PHINX_DATABASE: "test_$CI_BUILD_REF"
PHINX_HOST: "$SQL_HOST"
PHINX_PORT: "$SQL_PORT"
SYSADMIN: "gitlab@email.com"
FDNNURL1: "https://secure.fd2n.org/fd2n/cb"
FDNNURL2: "https://secure.fdn2.org/fdn2/don"
BASE_DOMAIN: "dev.laquadrature.net"
SITE_ID: "XXXXXXXX"
CERTIFICATE: "XXXXXXXXXXXXXXXXXXXXXXXXx"
CTX_MODE: "TEST"
PIPLOME_PATH: "/var/www/site/pdf/"
PIPLOME_URL: "https://www.laquadrature.net/pdf/"
CAMPAIGN_START_DATE: "2016-11-10"
CAMPAIGN_BUDGET: "321000"
LOGS: "./"
SMTP_HOST: "smtp.example.com"
SMTP_PORT: "25"
SMTP_SECURITY: "none"
SMTP_USER: "user"
SMTP_PW: "password"
DEBUG: "0"
ENV: "test"
script:
- echo "SQL_PASSWORD=${SQL_PASSWORD}" > app/env
- echo "SQL_USER=${SQL_USER}" >> app/env
- echo "SQL_DATABASE=${SQL_DATABASE}" >> app/env
- make install
- make server-start
- make -k test
- make server-stop
- mysql -u $SQL_USER -p$SQL_PASSWORD -e "DROP DATABASE $SQL_DATABASE"
tags:
- preprod
cleanup test:
stage: cleanup_test
variables:
SQL_DATABASE: "test_$CI_BUILD_REF"
SQL_USER: "soutien"
SQL_PASSWORD: "soutien"
script:
- make server-stop
- mysql -u $SQL_USER -p$SQL_PASSWORD -e "DROP DATABASE $SQL_DATABASE"
when: on_failure
tags:
- preprod
job install:
stage: deploy
environment: preprod
variables:
PHINX_ENVIRONMENT: "development"
PROD_HOME: "/home/don/don/"
script:
- chmod a+x ci/install.sh
- ./ci/install.sh
stage: deploy
tags:
- preprod
only:
- preprod
job deploy:
stage: deploy
environment: production
variables:
PHINX_ENVIRONMENT: "production"
PROD_HOME: "/home/don/don/"
script:
- chmod a+x ci/install.sh
- ./ci/install.sh
stage: deploy
tags:
- prod
only:
- master
......@@ -44,7 +44,7 @@ and for developers you may also need :
This software uses:
* **PHP7.3** currently
* **PHP7.3**
* **phinx** to inject database schema and initial data / accounts into MySQL see https://phinx.org/
* **php-cs-fixer** to check php code for errors and fix coding standard issues, see https://github.com/FriendsOfPHP/PHP-CS-Fixer
* **doctrine/dbal** as ORM see https://github.com/doctrine/dbal
......@@ -63,7 +63,8 @@ Nginx configuration sample:
```
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php5.sock;
fastcgi_read_timeout 1d; #avoid timeout when importing bank data
fastcgi_pass unix:/run/php7.3.sock;
}
location / {
# try to serve file directly, fallback to index.php
......
......@@ -14,6 +14,7 @@ use LQDN\Command\UserCreateCommand;
use LQDN\Command\UserUpdateCumulCommand;
use LQDN\Command\AdminUpdateParentCommand;
use LQDN\Command\AdminUpdateTotalUsersCommand;
use LQDN\Exception\InvalidEmailException;
class Admin extends Controller
{
......@@ -34,6 +35,7 @@ class Admin extends Controller
100 => "Récurrent non validé",
101 => "Récurrent validé",
102 => "Récurrent remis",
//! 103 => "Refusé"
));
$f3->set('CT_STATUTS', array(
......@@ -50,7 +52,7 @@ class Admin extends Controller
99 => "résilié",
100 => "non applicable",
));
$f3->set('TAILLES', array(
0 => _('PlaceHolder -- ne pas utiliser') . ' S',
1 => _('Coupe Homme, Taille') . ' S',
......@@ -351,7 +353,7 @@ class Admin extends Controller
SET somme='".\Utils::asl($somme)."',
lang='".\Utils::asl($lang)."',
abo='".\Utils::asl($abo)."',
public='".\Utils::asl($public)."',
public='".\Utils::asl($public)."',
adresse_id='".$result['adresse_id']."'
WHERE id='".\Utils::asl($_POST['id'])."'");
}
......@@ -828,9 +830,9 @@ class Admin extends Controller
$result = $db->query("SELECT d.id AS id,
d.pdf AS pdf,
a.nom AS nom
FROM dons d
FROM dons d
INNER JOIN adresses a ON d.adresse_id = a.id
WHERE pdf<>''
WHERE pdf<>''
AND d.status IN (1,4,101)
AND d.user_id='".$contrepartie['user_id']."'");
if ($result) {
......@@ -1163,12 +1165,12 @@ class Admin extends Controller
break;
case 'update':
if ($f3->get('POST.test')=='1') {
$datas = $this->banque_update($f3, $_FILES['file']['tmp_name']);
$result = $datas['update'] . " dons récurrents mis à jour sur un total de ". $datas['total']." dons récurrents.";
$datas = $this->banque_update($f3, $_FILES['file']);
$result = $datas['update'] . " dons récurrents mis à jour sur un total de ". $datas['total']." dons récurrents (fichier : \"" . htmlentities($_FILES['file']['name']) . "\").";
$message = "Il s'agit d'un <b>test</b><br />";
} else {
$datas = $this->banque_update($f3, $_FILES['file']['tmp_name'], false);
$result = $datas['update'] . " dons récurrents mis à jour sur un total de ". $datas['total']." dons récurrents.";
$datas = $this->banque_update($f3, $_FILES['file'], false);
$result = $datas['update'] . " dons récurrents mis à jour sur un total de ". $datas['total']." dons récurrents (fichier : \"" . htmlentities($_FILES['file']['name']) . "\").";
}
if (count($datas['comptabilise'])>0 or count($datas['sans_cumul'])>0) {
$error = count($datas['comptabilise']) . " dons récurrents déjà comptabilisés et ". count($datas['sans_cumul'])." dons récurrents sans cumul.";
......@@ -1374,8 +1376,12 @@ class Admin extends Controller
return $datas;
}
public function banque_update($f3, $filename, $testing=true)
public function banque_update($f3, $file, $testing=true)
{
$log = new \Log('/banque_update.log');
$log->write('Processing recurrent donations on file "' . $file['name'] . '" (testing: ' . ($testing ? 'true' : 'false') . ')');
$filename = $file['tmp_name'];
$separator = ";";
$datas = array();
$update = 0;
......@@ -1412,7 +1418,7 @@ class Admin extends Controller
}
// On lit maintenant tout, ligne par ligne, afin de vérifier les informations bancaires pour chaque don.
while (($data = fgetcsv($handle, 1000, $separator)) !== false) {
while (($data = fgetcsv($handle, 10000, $separator)) !== false) {
if (count($data) <= 0) {
continue;
}
......@@ -1425,6 +1431,7 @@ class Admin extends Controller
if ($identifier && $transaction && $effect && $amount && $statut == false) {
continue;
}
//! "Refusé" status seems not be present in csv, is this really used?
if ($statut == 'Refusé' and !$testing) {
$db->query("UPDATE dons SET status = 103 WHERE id='".$transaction."'");
continue;
......@@ -1435,6 +1442,8 @@ class Admin extends Controller
$total ++;
$email = '';
$time_struct = strptime($effect, "%d/%m/%Y %H:%M:%S");
//! XXX WHY? month + 1 can make sense, but hour (always 00) + 1 or year (2020) + 1900 does not
//! what is the rationale, is this the next due date?
$new_effect = strftime("%Y-%m-%d %H:%M:%S", mktime(
$time_struct['tm_hour']+1,
$time_struct['tm_min'],
......@@ -1465,7 +1474,8 @@ class Admin extends Controller
if ($user and !$testing) {
$db->query("INSERT INTO identifiers(user_id, identifier) VALUES ('".$user['id']."', '".$identifier."')");
$email = $user['email'];
} else {
} elseif (!$testing) {
$log->write('Cannot find user for transaction id ' . $identifier . ', creating it...');
// No user, let's try to create the user
$email = '';
$pseudo = '';
......@@ -1476,16 +1486,22 @@ class Admin extends Controller
$email = $user_field . "@example.org";
$pseudo = $user_field;
}
//! hash seems to identify one email at one time
$hash = hash('sha256', date("%Y-%m-%d %H:%i:%d").$email);
if (!$testing) {
$log->write('Insert user: email "'.$email.'" pseudo "'.$pseudo.'" identifier "'.$identifier.'"');
try {
$f3->get('container')['command_handler']->handle(new UserCreateCommand($email, $hash, $pseudo, 0, 0));
};
} catch (InvalidEmailException $e) { // \Exception
$log->write("exception: ".$e);
throw $e;
}
}
} else {
$email = $result->fetch(\PDO::FETCH_ASSOC);
$email = $email['email'];
// On stocke l'email pour comptabiliser les dons
}
//! Counting email duplicates
if (array_key_exists($email, $emails)) {
$emails[$email] ++;
} else {
......@@ -1494,6 +1510,7 @@ class Admin extends Controller
// On a besoin de l'utilisateur
$user = $f3->get('container')['user_finder']->findByEmail($email);
// Récupération de l'id du bon abonnement
//! look for a validated donation, see if the recurrent donation is already scheduled
$stmt = $db->query("SELECT d.id AS id
FROM dons d
JOIN users u ON u.id = d.user_id
......@@ -1503,10 +1520,13 @@ class Admin extends Controller
$result = $stmt->fetch(\PDO::FETCH_ASSOC);
if (!$result) {
if ($testing) {
//! XXX WTF random transaction id!
$cumul = rand(50000, 70000);
} else {
// don non trouvé en statut 101. On le crée (la banque à raison)
// statut = cumul
//! FIXME bad naming cumul for transactions
//! It means that don.cumul is the id of parent transaction with 101 status
$f3->get('container')['command_handler']
->handle(new DonationCreateCommand(
$user['id'],
......@@ -1532,10 +1552,12 @@ class Admin extends Controller
AND d.datec='".$new_effect."'
AND d.cumul=".$cumul."
");
//! Does not sound like a good idea to match on a creation date...
if ($result) {
$combien = $result->fetch();
if ($combien[0]==0) {
$update ++;
$log->write('Insert don: user_id "'.$user['id'].'" identifier "'.$identifier.'" new effect "'.$new_effect.'" parent "'.$cumul.'"');
// Don récurrent non comptabilisé, on l'ajoute
if (!$testing) {
$query = "INSERT INTO dons (status,
......@@ -1551,8 +1573,6 @@ class Admin extends Controller
'".$user['id']."',
'".$cumul."',
'".$identifier."')";
}
if (!$testing) {
$db->query($query);
// On met alors à jour le cumul et le total de l'utilisateur concerné
$result = $db->query("UPDATE users
......@@ -1568,10 +1588,11 @@ class Admin extends Controller
}
fclose($handle);
}
$datas['update'] = $update;
$datas['total'] = $total;
$datas['comptabilise'] = $comptabilise;
$datas['sans_cumul'] = $sans_cumul;
$datas['total'] = $total; //! all recurrent transactions (validées + remisées)
$datas['update'] = $update; //! recurrent transactions remisées just added
$datas['comptabilise'] = $comptabilise; //! recurrent transactions remisées already added
$datas['sans_cumul'] = $sans_cumul; //! empty
$log->write('Processing recurrent donations finished on file "' . $file['name'] . '"');
return $datas;
}
......
......@@ -155,6 +155,7 @@ class Bank extends Controller
$user = $f3->get('container')['user_finder']->findById($don['user_id']);
$cb_log->write("Utilisation d'un utilisateur existant");
//! FIXME What if user not found? Must check it
// Ajout du nouveau don au cumul actuel
if ($status!=101) {
$cb_log->write("Ajout de ".$don['somme']);
......
......@@ -162,7 +162,7 @@ class Campaign extends Controller
"vads_action_mode" => "INTERACTIVE",
"vads_ctx_mode" => CTX_MODE,
// Autres codes possibles (page 16)
"vads_trans_id" => str_repeat("0", 6-strlen($id)).$id,
"vads_trans_id" => str_repeat("0", 6-strlen($id)).$id, // fill left zeros to have length 6
"vads_version" => "V2",
// Champs facultatifs
"vads_language" => $f3->get('lang'),
......
......@@ -58,7 +58,13 @@ class Controller
putenv("LANGUAGE=".$lang);
if (!setlocale(LC_ALL, $lang)) {
echo "<!-- setlocale $lang failed -->";
// try the UTF8 version
putenv("LC_MESSAGES=".$lang.".utf8");
putenv("LANG=".$lang.".utf8");
putenv("LANGUAGE=".$lang.".utf8");
if (!setlocale(LC_ALL, $lang.".utf8")) {
echo "<!-- setlocale $lang failed -->";
}
}
if (!textdomain("messages")) {
......
......@@ -2,8 +2,8 @@
<h2>Gestion banque</h2>
<check if="{{@result}}"><p class="result">{{@result | raw}}</p></check>
<check if="{{@SESSION.error}}"><message messages="{{@SESSION.error}}" class="alert alert-danger"/></check>
<check if="{{@SESSION.message}}"><message messages="{{@SESSION.message}}" class="alert alert-danger" /></p></check>
<check if="{{@SESSION.error}}"><message messages="{{@SESSION.error| raw }}" class="alert alert-danger"/></check>
<check if="{{@SESSION.message}}"><message messages="{{@SESSION.message| raw }}" class="alert alert-danger" /></p></check>
<section id="cbs">
<h3 >Mise à jour des dates d'expiration des CB</h3>
......
......@@ -22,6 +22,8 @@ git submodule update
composer install --no-dev
composer update
rm tmp/*.php
# Let's run the migrations
if [ -e "$HOME/phinx.yml" ]
then
......
......@@ -2,17 +2,17 @@
"name": "lqdn/soutien",
"description": "Site de soutien LQDN",
"require": {
"bcosca/fatfree": "^3.5",
"robmorgan/phinx": "^0.10.0",
"vlucas/phpdotenv": "^2.4",
"bcosca/fatfree": "^3.7.2",
"robmorgan/phinx": "^0.10.8",
"vlucas/phpdotenv": "^v2.6.6",
"pimple/pimple": "^3.0",
"doctrine/dbal": "^2.5",
"symfony/http-foundation": "^3.2",
"sentry/sentry": "^1.9"
"symfony/http-foundation": "^3.4.46",
"sentry/sentry": "^1.11.0"
},
"require-dev": {
"codeception/codeception": "^2.2",
"friendsofphp/php-cs-fixer": "^2.1"
"codeception/codeception": "^2.5.6",
"friendsofphp/php-cs-fixer": "^2.16.5"
},
"autoload": {
"psr-4": {
......@@ -27,7 +27,7 @@
"config": {
"preferred-install": "dist",
"platform": {
"php": "5.6.27"
"php": "7.3.0"
}
}
}
......@@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "598125773d9149c838a4286d49e2b029",
"content-hash": "fb8f251d5cea69faf768853f17539aae",
"packages": [
{
"name": "bcosca/fatfree",
"version": "3.6.4",
"version": "3.7.2",
"source": {
"type": "git",
"url": "https://github.com/bcosca/fatfree.git",
"reference": "dee4d73918a42076d5ac7db64d6d39706c7f328a"
"reference": "b51905e89d2bf970b34c4fbb37879eeb1572e76c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/bcosca/fatfree/zipball/dee4d73918a42076d5ac7db64d6d39706c7f328a",
"reference": "dee4d73918a42076d5ac7db64d6d39706c7f328a",
"url": "https://api.github.com/repos/bcosca/fatfree/zipball/b51905e89d2bf970b34c4fbb37879eeb1572e76c",
"reference": "b51905e89d2bf970b34c4fbb37879eeb1572e76c",
"shasum": ""
},
"require": {
......@@ -35,25 +35,26 @@
],
"description": "A powerful yet easy-to-use PHP micro-framework designed to help you build dynamic and robust Web applications - fast!",
"homepage": "http://fatfreeframework.com/",
"time": "2018-04-19T17:23:25+00:00"
"time": "2020-05-28T16:20:24+00:00"
},
{
"name": "cakephp/cache",
"version": "3.6.12",
"version": "3.9.3",
"source": {
"type": "git",
"url": "https://github.com/cakephp/cache.git",
"reference": "5941977c584843b9ddb32ec864a9483fbef88d52"
"reference": "e8ec4e77fb288adda318e08053f5f540870aeb9d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cakephp/cache/zipball/5941977c584843b9ddb32ec864a9483fbef88d52",
"reference": "5941977c584843b9ddb32ec864a9483fbef88d52",
"url": "https://api.github.com/repos/cakephp/cache/zipball/e8ec4e77fb288adda318e08053f5f540870aeb9d",
"reference": "e8ec4e77fb288adda318e08053f5f540870aeb9d",
"shasum": ""
},
"require": {
"cakephp/core": "^3.6.0",
"php": ">=5.6.0"
"php": ">=5.6.0",
"psr/simple-cache": "^1.0.0"
},
"type": "library",
"autoload": {
......@@ -78,20 +79,20 @@
"caching",
"cakephp"
],
"time": "2018-09-01T17:00:52+00:00"
"time": "2020-06-16T00:54:28+00:00"
},
{
"name": "cakephp/collection",
"version": "3.6.12",
"version": "3.9.3",
"source": {
"type": "git",
"url": "https://github.com/cakephp/collection.git",
"reference": "c5b3a3561eb92a5c25ffcc90ad3a1f193962065f"
"reference": "ddfff69d7bfa8b9b03eb7150097b0b06258fcaa3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cakephp/collection/zipball/c5b3a3561eb92a5c25ffcc90ad3a1f193962065f",
"reference": "c5b3a3561eb92a5c25ffcc90ad3a1f193962065f",
"url": "https://api.github.com/repos/cakephp/collection/zipball/ddfff69d7bfa8b9b03eb7150097b0b06258fcaa3",
"reference": "ddfff69d7bfa8b9b03eb7150097b0b06258fcaa3",
"shasum": ""
},
"require": {
......@@ -124,20 +125,20 @@
"collections",
"iterators"
],
"time": "2018-07-26T19:56:06+00:00"
"time": "2020-07-05T02:00:29+00:00"
},
{
"name": "cakephp/core",
"version": "3.6.12",
"version": "3.9.3",
"source": {
"type": "git",
"url": "https://github.com/cakephp/core.git",
"reference": "82741aeb90ca2fbbf9fbbd507d56d53b081db237"
"reference": "76b9450dc68c81f93bca7827cfbb42a53a5f7737"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cakephp/core/zipball/82741aeb90ca2fbbf9fbbd507d56d53b081db237",
"reference": "82741aeb90ca2fbbf9fbbd507d56d53b081db237",
"url": "https://api.github.com/repos/cakephp/core/zipball/76b9450dc68c81f93bca7827cfbb42a53a5f7737",
"reference": "76b9450dc68c81f93bca7827cfbb42a53a5f7737",
"shasum": ""
},
"require": {
......@@ -145,6 +146,7 @@
"php": ">=5.6.0"
},
"suggest": {
"cakephp/cache": "To use Configure::store() and restore().",
"cakephp/event": "To use PluginApplicationInterface or plugin applications."
},
"type": "library",
......@@ -173,31 +175,29 @@
"core",
"framework"
],
"time": "2018-07-26T19:56:06+00:00"
"time": "2020-06-16T00:54:28+00:00"
},
{
"name": "cakephp/database",
"version": "3.6.12",
"version": "3.9.3",
"source": {
"type": "git",
"url": "https://github.com/cakephp/database.git",
"reference": "1494d12bc2b42cb1e844936cbbdd686a5e36235d"
"reference": "6f4cd60f53e8b6559cc6782ff288cc6d2b8fe1d3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cakephp/database/zipball/1494d12bc2b42cb1e844936cbbdd686a5e36235d",
"reference": "1494d12bc2b42cb1e844936cbbdd686a5e36235d",
"url": "https://api.github.com/repos/cakephp/database/zipball/6f4cd60f53e8b6559cc6782ff288cc6d2b8fe1d3",
"reference": "6f4cd60f53e8b6559cc6782ff288cc6d2b8fe1d3",
"shasum": ""
},
"require": {
"cakephp/cache": "^3.6.0",
"cakephp/core": "^3.6.0",
"cakephp/datasource": "^3.6.0",
"cakephp/log": "^3.6.0",
"php": ">=5.6.0"
},
"suggest": {
"cakephp/log": "Require this if you want to use the built-in query logger"
},
"type": "library",
"autoload": {
"psr-4": {
......@@ -223,20 +223,20 @@
"database abstraction",
"pdo"
],
"time": "2018-09-28T10:56:48+00:00"
"time": "2020-10-04T00:34:57+00:00"
},
{
"name": "cakephp/datasource",
"version": "3.6.12",
"version": "3.9.3",
"source": {
"type": "git",
"url": "https://github.com/cakephp/datasource.git",
"reference": "44222238fa97e32d39e48bb2add4933ccffbd896"
"reference": "ef310daf569dc11ef473a9ba0c52429025f672ec"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cakephp/datasource/zipball/44222238fa97e32d39e48bb2add4933ccffbd896",
"reference": "44222238fa97e32d39e48bb2add4933ccffbd896",
"url": "https://api.github.com/repos/cakephp/datasource/zipball/ef310daf569dc11ef473a9ba0c52429025f672ec",
"reference": "ef310daf569dc11ef473a9ba0c52429025f672ec",
"shasum": ""
},
"require": {
......@@ -273,20 +273,65 @@
"entity",
"query"
],
"time": "2018-09-28T10:56:48+00:00"
"time": "2020-06-16T00:54:28+00:00"
},
{
"name": "cakephp/log",
"version": "3.9.3",
"source": {
"type": "git",
"url": "https://github.com/cakephp/log.git",
"reference": "02940591797475c2d384af12432561204d6ecdf9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cakephp/log/zipball/02940591797475c2d384af12432561204d6ecdf9",
"reference": "02940591797475c2d384af12432561204d6ecdf9",
"shasum": ""
},
"require": {
"cakephp/core": "^3.6.0",
"php": ">=5.6.0",
"psr/log": "^1.0.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Cake\\Log\\": "."
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "CakePHP Community",
"homepage": "https://github.com/cakephp/log/graphs/contributors"
}
],
"description": "CakePHP logging library with support for multiple different streams",
"homepage": "https://cakephp.org",
"keywords": [
"Streams",
"cakephp",
"log",
"logging"
],