if ($count_before != $count_after) {
foreach ($list as $member) {
+ if (!isset($members_list[$member->fingerprint])) {
+ continue;
+ }
$created = $members_list[$member->fingerprint];
foreach ($fields as $field) {
if (property_exists($member, $field)) {
- $this->assertEquals($created[$field], $member->$field);
+ if ($field === \Galette\Entity\Status::PK && $created[$field] === null) {
+ $this->assertNotNull($member->$field);
+ } else if ($field === 'pref_lang' && $created[$field] === null) {
+ $this->assertNotNull($member->$field);
+ } else {
+ $this->assertEquals($created[$field], $member->$field);
+ }
} else {
//manage dynamic fields
$matches = [];
$count_after = 10;
$this->doImportFileTest($fields, $file_name, $flash_messages, $members_list, $count_before, $count_after);
+
+ //test status import
+ $fields = ['nom_adh', 'ville_adh', 'fingerprint', \Galette\Entity\Status::PK];
+ $file_name = 'test-import-status-ko.csv';
+ $flash_messages = [
+ 'error_detected' => [
+ 'File does not comply with requirements.',
+ 'Status 42 does not exists!'
+ ]
+ ];
+ $members_list = [
+ 'FAKER_STATUS' => [
+ 'nom_adh' => 'Status tests name',
+ 'ville_adh' => 'Status tests city',
+ 'fingerprint' => 'FAKER_STATUS',
+ \Galette\Entity\Status::PK => 42 //non-existing status
+ ]
+ ];
+ $count_before = 10;
+ $count_after = 10;
+ $this->doImportFileTest($fields, $file_name, $flash_messages, $members_list, $count_before, $count_after);
+
+ $members_list['FAKER_STATUS'][\Galette\Entity\Status::PK] = 1; //existing status
+ $file_name = 'test-import-status-ok.csv';
+ $flash_messages = [
+ 'success_detected' => ["File '$file_name' has been successfully imported :)"]
+ ];
+ $count_after = 11;
+ $this->doImportFileTest($fields, $file_name, $flash_messages, $members_list, $count_before, $count_after);
+
+ //create with default status
+ $members_list = [
+ 'FAKER_DEF_STATUS' => [
+ 'nom_adh' => 'Member with default status',
+ 'ville_adh' => 'Member with default status city',
+ 'fingerprint' => 'FAKER_DEF_STATUS',
+ \Galette\Entity\Status::PK => null //no specified status
+ ]
+ ];
+ $file_name = 'test-import-default-status.csv';
+ $flash_messages = [
+ 'success_detected' => ["File '$file_name' has been successfully imported :)"]
+ ];
+ $count_before = 11;
+ $count_after = 12;
+ $this->doImportFileTest($fields, $file_name, $flash_messages, $members_list, $count_before, $count_after);
+
+ //check created member
+ $select = $this->zdb->select(\Galette\Entity\Adherent::TABLE);
+ $select->where(['fingerprint' => 'FAKER_DEF_STATUS']);
+ $result = $this->zdb->execute($select)->current();
+ $this->assertSame(
+ (int)($this->preferences->pref_statut ?? \Galette\Entity\Status::DEFAULT_STATUS),
+ $result[\Galette\Entity\Status::PK]
+ );
+
+ //test title import
+ $fields = ['nom_adh', 'ville_adh', 'fingerprint', 'titre_adh'];
+ $file_name = 'test-import-title-ko.csv';
+ $flash_messages = [
+ 'error_detected' => [
+ 'File does not comply with requirements.',
+ 'Title 42 does not exists!'
+ ]
+ ];
+ $members_list = [
+ 'FAKER_TITLE' => [
+ 'nom_adh' => 'Status tests name',
+ 'ville_adh' => 'Status tests city',
+ 'fingerprint' => 'FAKER_TITLE',
+ 'titre_adh' => 42 //non-existing title
+ ]
+ ];
+ $count_before = 12;
+ $count_after = 12;
+ $this->doImportFileTest($fields, $file_name, $flash_messages, $members_list, $count_before, $count_after);
+
+ $members_list['FAKER_TITLE']['titre_adh'] = \Galette\Entity\Title::MR; //existing title
+ $file_name = 'test-import-title-ok.csv';
+ $flash_messages = [
+ 'success_detected' => ["File '$file_name' has been successfully imported :)"]
+ ];
+ $count_after = 13;
+ $this->doImportFileTest($fields, $file_name, $flash_messages, $members_list, $count_before, $count_after);
+
+ //test email unicity
+ $fields = ['nom_adh', 'email_adh', 'fingerprint'];
+ $file_name = 'test-import-email-duplicate.csv';
+ $flash_messages = [
+ 'error_detected' => [
+ 'File does not comply with requirements.',
+ 'Email address mail@domain.com is already used! (from another member in import)'
+ ]
+ ];
+ $members_list = [
+ 'FAKER_MAIL_1' => [
+ 'nom_adh' => 'Member email 1',
+ 'email_adh' => 'mail@domain.com',
+ 'fingerprint' => 'FAKER_MAIL_1'
+ ],
+ 'FAKER_MAIL_12' => [
+ 'nom_adh' => 'Member email 2',
+ 'email_adh' => 'mail@domain.com',
+ 'fingerprint' => 'FAKER_MAIL_2'
+ ]
+ ];
+ $count_before = 13;
+ $count_after = 13;
+ $this->doImportFileTest($fields, $file_name, $flash_messages, $members_list, $count_before, $count_after);
+
+ $file_name = 'test-import-email-ok.csv';
+ $flash_messages = [
+ 'success_detected' => ["File '$file_name' has been successfully imported :)"]
+ ];
+ $members_list = [
+ 'FAKER_MAIL_1' => [
+ 'nom_adh' => 'Member email 1',
+ 'email_adh' => 'mail@domain.com',
+ 'fingerprint' => 'FAKER_MAIL_1'
+ ]
+ ];
+ $count_before = 13;
+ $count_after = 14;
+ $this->doImportFileTest($fields, $file_name, $flash_messages, $members_list, $count_before, $count_after);
+
+ //get created member
+ $select = $this->zdb->select(\Galette\Entity\Adherent::TABLE);
+ $select->where(['fingerprint' => 'FAKER_MAIL_1']);
+ $result = $this->zdb->execute($select)->current();
+ $this->assertSame('mail@domain.com', $result['email_adh']);
+
+ $file_name = 'test-import-email-duplicate-again.csv';
+ $flash_messages = [
+ 'error_detected' => [
+ 'File does not comply with requirements.',
+ 'Email address mail@domain.com is already used! (from member ' . $result['id_adh'] . ')'
+ ]
+ ];
+ $members_list = [
+ 'FAKER_MAIL_12' => [
+ 'nom_adh' => 'Member email 2',
+ 'email_adh' => 'mail@domain.com',
+ 'fingerprint' => 'FAKER_MAIL_2'
+ ]
+ ];
+ $count_before = 14;
+ $count_after = 14;
+ $this->doImportFileTest($fields, $file_name, $flash_messages, $members_list, $count_before, $count_after);
+
+ //test lang import
+ $fields = ['nom_adh', 'ville_adh', 'fingerprint', 'pref_lang'];
+ $file_name = 'test-import-lang-ko.csv';
+ $flash_messages = [
+ 'error_detected' => [
+ 'File does not comply with requirements.',
+ 'Lang NO_EX does not exists!'
+ ]
+ ];
+ $members_list = [
+ 'FAKER_LANG' => [
+ 'nom_adh' => 'Lang tests name',
+ 'ville_adh' => 'Lang tests city',
+ 'fingerprint' => 'FAKER_LANG',
+ 'pref_lang' => 'NO_EX' //non-existing lang
+ ]
+ ];
+ $count_before = 14;
+ $count_after = 14;
+ $this->doImportFileTest($fields, $file_name, $flash_messages, $members_list, $count_before, $count_after);
+
+ $members_list['FAKER_LANG']['pref_lang'] = 'fr_FR'; //existing title
+ $file_name = 'test-import-lang-ok.csv';
+ $flash_messages = [
+ 'success_detected' => ["File '$file_name' has been successfully imported :)"]
+ ];
+ $count_after = 15;
+ $this->doImportFileTest($fields, $file_name, $flash_messages, $members_list, $count_before, $count_after);
+
+ //create with default lang
+ $members_list = [
+ 'FAKER_DEF_LANG' => [
+ 'nom_adh' => 'Member with default lang',
+ 'ville_adh' => 'Member with default lang city',
+ 'fingerprint' => 'FAKER_DEF_LANG',
+ 'pref_lang' => null //no specified lang
+ ]
+ ];
+ $file_name = 'test-import-default-lang.csv';
+ $flash_messages = [
+ 'success_detected' => ["File '$file_name' has been successfully imported :)"]
+ ];
+ $count_before = 15;
+ $count_after = 16;
+ $this->doImportFileTest($fields, $file_name, $flash_messages, $members_list, $count_before, $count_after);
+
+ //check created member
+ $select = $this->zdb->select(\Galette\Entity\Adherent::TABLE);
+ $select->where(['fingerprint' => 'FAKER_DEF_LANG']);
+ $result = $this->zdb->execute($select)->current();
+ $this->assertSame(
+ $this->preferences->pref_lang,
+ $result['pref_lang']
+ );
}
/**
$this->doImportFileTest($fields, $file_name, $flash_messages, $members_list, $count_before, $count_after);
}
+ /**
+ * Test non existing file
+ *
+ * @return void
+ */
+ public function testNoFile(): void
+ {
+ $cin = new \Galette\IO\CsvIn($this->zdb);
+ $this->assertSame(
+ \Galette\IO\FileInterface::INVALID_FILE,
+ $cin->import(
+ $this->zdb,
+ $this->preferences,
+ $this->history,
+ 'non-existing-file.csv',
+ $this->members_fields,
+ $this->members_fields_cats,
+ true
+ )
+ );
+ $this->assertSame(
+ ['File non-existing-file.csv cannot be open!'],
+ $cin->getErrors()
+ );
+ }
+
+ /**
+ * Test empty file
+ *
+ * @return void
+ */
+ public function testEmptyFile(): void
+ {
+ $fields = ['nom_adh', 'ville_adh', 'fingerprint'];
+ $file_name = 'test-empty-file.csv';
+ $flash_messages = [
+ 'error_detected' => [
+ 'File does not comply with requirements.',
+ 'File is empty!'
+ ]
+ ];
+
+ $members_list = [];
+ $count_before = 0;
+ $count_after = 0;
+
+ $this->doImportFileTest($fields, $file_name, $flash_messages, $members_list, $count_before, $count_after);
+ }
+
+ /**
+ * Test missing columns
+ *
+ * @return void
+ */
+ public function testMissingColumn(): void
+ {
+ $csvin = new \Galette\IO\CsvIn($this->zdb);
+
+ $fields = ['nom_adh', 'ville_adh', 'fingerprint'];
+ $file_name = 'test-import-missing-column.csv';
+ $this->getModel($fields);
+
+ $contents = "\"" . implode("\";\"", $fields) . "\"\r\n";
+ $fields = ['nom_adh', 'fingerprint'];
+ $members_list = $this->getMemberData1();
+
+ foreach ($members_list as $member) {
+ $amember = [];
+ foreach ($fields as $field) {
+ $amember[$field] = $member[$field];
+ }
+ $contents .= "\"" . implode("\";\"", $amember) . "\"\r\n";
+ }
+
+ $path = GALETTE_CACHE_DIR . $file_name;
+ $this->assertIsInt(file_put_contents($path, $contents));
+ $_FILES['new_file'] = [
+ 'error' => UPLOAD_ERR_OK,
+ 'name' => $file_name,
+ 'tmp_name' => $path,
+ 'size' => filesize($path)
+ ];
+ $this->assertTrue($csvin->store($_FILES['new_file'], true));
+ $this->assertTrue(file_exists($csvin->getDestDir() . $csvin->getFileName()));
+
+ $this->assertSame(
+ \Galette\IO\FileInterface::INVALID_FILE,
+ $csvin->import(
+ $this->zdb,
+ $this->preferences,
+ $this->history,
+ $file_name,
+ $this->members_fields,
+ $this->members_fields_cats,
+ true
+ )
+ );
+ $this->assertSame(
+ ['Fields count mismatch... There should be 3 fields and there are 2 (row 1)'],
+ $csvin->getErrors()
+ );
+
+ $csvin = new \Galette\IO\CsvIn($this->zdb);
+ $file_name = 'test-import-missing-column-headers.csv';
+ $fields = ['nom_adh', 'fingerprint'];
+ $members_list = $this->getMemberData1();
+
+ $contents = "\"" . implode("\";\"", $fields) . "\"\r\n";
+ foreach ($members_list as $member) {
+ $amember = [];
+ foreach ($fields as $field) {
+ $amember[$field] = $member[$field];
+ }
+ $contents .= "\"" . implode("\";\"", $amember) . "\"\r\n";
+ }
+
+ $path = GALETTE_CACHE_DIR . $file_name;
+ $this->assertIsInt(file_put_contents($path, $contents));
+ $_FILES['new_file'] = [
+ 'error' => UPLOAD_ERR_OK,
+ 'name' => $file_name,
+ 'tmp_name' => $path,
+ 'size' => filesize($path)
+ ];
+ $this->assertTrue($csvin->store($_FILES['new_file'], true));
+ $this->assertTrue(file_exists($csvin->getDestDir() . $csvin->getFileName()));
+
+ $this->assertSame(
+ \Galette\IO\FileInterface::INVALID_FILE,
+ $csvin->import(
+ $this->zdb,
+ $this->preferences,
+ $this->history,
+ $file_name,
+ $this->members_fields,
+ $this->members_fields_cats,
+ true
+ )
+ );
+ $this->assertSame(
+ ['Fields count mismatch... There should be 3 fields and there are 2 (row 0)'],
+ $csvin->getErrors()
+ );
+ }
+
/**
* Get first set of member data
*
\Laminas\Db\Adapter\Adapter::QUERY_MODE_EXECUTE
);
+ $zdb->db->query(
+ 'TRUNCATE TABLE ' . PREFIX_DB . \Galette\Entity\Group::GROUPSUSERS_TABLE,
+ \Laminas\Db\Adapter\Adapter::QUERY_MODE_EXECUTE
+ );
+
$groups = self::groupsProvider();
foreach ($groups as $group) {
foreach ($group['children'] as $child) {
$this->assertFalse(\Galette\Repository\Groups::isUnique($this->zdb, 'Nord', $france));
$this->assertTrue(\Galette\Repository\Groups::isUnique($this->zdb, 'Creuse', $france));
}
+
+ /**
+ * Test members/groups
+ *
+ * @return void
+ */
+ public function testMembersGroups(): void
+ {
+ $groups = self::groupsProvider();
+ foreach ($groups as $group) {
+ $this->testCreateGroups($group['parent_name'], $group['children']);
+ }
+
+ $france = new \Galette\Entity\Group();
+ $this->assertTrue($france->loadFromName('France'));
+
+ $allemagne = new \Galette\Entity\Group();
+ $this->assertTrue($allemagne->loadFromName('Allemagne'));
+
+ $member = $this->getMemberOne();
+ $member->loadGroups();
+ $this->assertSame([], $member->managed_groups);
+ $this->assertSame([], $member->groups);
+
+ //add member to France and Allemagne groups, as simple member
+ $this->assertTrue(
+ \Galette\Repository\Groups::addMemberToGroups(
+ $member,
+ [
+ sprintf('%s|%s', $france->getId(), $france->getName()),
+ sprintf('%s|%s', $allemagne->getId(), $allemagne->getName())
+ ]
+ )
+ );
+
+ $member->loadGroups();
+ $this->assertSame([], $member->managed_groups);
+ $this->assertCount(2, $member->groups);
+
+ //Add as manager of France
+ $this->assertTrue(
+ \Galette\Repository\Groups::addMemberToGroups(
+ $member,
+ [
+ sprintf('%s|%s', $france->getId(), $france->getName())
+ ],
+ true
+ ),
+ );
+
+ $member->loadGroups();
+ $this->assertCount(1, $member->managed_groups);
+ $this->assertCount(2, $member->groups);
+
+ $member2 = $this->getMemberTwo();
+ //Add as manager of France
+ $this->assertTrue(
+ \Galette\Repository\Groups::addMemberToGroups(
+ $member2,
+ [
+ sprintf('%s|%s', $france->getId(), $france->getName())
+ ],
+ true
+ ),
+ );
+
+ $member2->loadGroups();
+ $this->assertCount(1, $member2->managed_groups);
+ $this->assertCount(0, $member2->groups);
+
+ $this->logSuperAdmin();
+ $this->login->impersonate($member2->id);
+
+ $groups = new \Galette\Repository\Groups($this->zdb, $this->login);
+ $users = $groups->getManagerUsers([$allemagne->getId()]);
+ $this->assertSame([$member->id], $users);
+ $users = $groups->getManagerUsers([$france->getId()]);
+ $this->assertSame([$member->id], $users);
+
+ \Galette\Repository\Groups::removeMemberFromGroups($member->id);
+ $member->loadGroups();
+ $this->assertSame([], $member->managed_groups);
+ $this->assertSame([], $member->groups);
+ }
}
--- /dev/null
+<?php
+
+/**
+ * Copyright © 2003-2024 The Galette Team
+ *
+ * This file is part of Galette (https://galette.eu).
+ *
+ * Galette is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Galette is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Galette. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Galette\Repository\test\units;
+
+use Galette\GaletteTestCase;
+
+/**
+ * Saved searches repository tests
+ *
+ * @author Johan Cwiklinski <johan@x-tnd.be>
+ */
+class SavedSearches extends GaletteTestCase
+{
+ protected int $seed = 20240417150507;
+
+ /**
+ * Tear down tests
+ *
+ * @return void
+ */
+ public function tearDown(): void
+ {
+ $this->zdb->db->query(
+ 'TRUNCATE TABLE ' . PREFIX_DB . \Galette\Entity\SavedSearch::TABLE,
+ \Laminas\Db\Adapter\Adapter::QUERY_MODE_EXECUTE
+ );
+ parent::tearDown();
+ }
+
+ /**
+ * Test getList
+ *
+ * @return void
+ * @throws \Throwable
+ */
+ public function testGetList(): void
+ {
+ global $i18n; // globals :(
+ $i18n = $this->i18n;
+ $i18n->changeLanguage('en_US');
+
+ $saved = new \Galette\Entity\SavedSearch($this->zdb, $this->login);
+ $searches = new \Galette\Repository\SavedSearches($this->zdb, $this->login);
+
+ $post = [
+ 'parameters' => [
+ 'filter_str' => '',
+ 'field_filter' => 0,
+ 'membership_filter' => 0,
+ 'filter_account' => 0,
+ 'roup_filter' => 0,
+ 'email_filter' => 5,
+ 'nbshow' => 10
+ ],
+ 'form' => 'Adherent',
+ 'name' => 'Simple search'
+ ];
+
+ //store search
+ $this->assertTrue($saved->check($post));
+ $this->assertTrue($saved->store());
+ $sid_1 = $saved->id;
+
+ $list = $searches->getList(true);
+ $this->assertIsArray($list);
+ $this->assertCount(1, $list);
+ $this->assertSame(1, $searches->getCount());
+
+ $result = array_pop($list);
+ $this->assertInstanceOf(\Galette\Entity\SavedSearch::class, $result);
+
+ $list = $searches->getList(false);
+ $this->assertInstanceOf(\Laminas\Db\ResultSet\ResultSet::class, $list);
+ $this->assertNotInstanceOf(\Galette\Entity\SavedSearch::class, $list->current());
+
+ //another one
+ $post['name'] = 'Another search';
+ $this->assertTrue($saved->store());
+ $sid_2 = $saved->id;
+ $this->assertCount(2, $searches->getList(true));
+ $this->assertSame(2, $searches->getCount());
+
+ $post['name'] = 'Last one';
+ $this->assertTrue($saved->store());
+ $sid_3 = $saved->id;
+ $this->assertCount(3, $searches->getList(true));
+ $this->assertSame(3, $searches->getCount());
+
+ $this->assertFalse($searches->remove([], $this->history));
+ $this->assertTrue($searches->remove($sid_2, $this->history));
+ $list = $searches->getList(true);
+ $this->assertCount(2, $list);
+ foreach ($list as $entry) {
+ $this->assertNotSame($sid_2, $entry->id);
+ }
+
+ $this->assertTrue($searches->remove([$sid_1, $sid_3], $this->history));
+ $list = $searches->getList(true);
+ $this->assertCount(0, $list);
+ }
+}
--- /dev/null
+<?php
+
+/**
+ * Copyright © 2003-2024 The Galette Team
+ *
+ * This file is part of Galette (https://galette.eu).
+ *
+ * Galette is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Galette is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Galette. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace Galette\Repository\test\units;
+
+use Galette\GaletteTestCase;
+
+/**
+ * Payment types repository tests
+ *
+ * @author Johan Cwiklinski <johan@x-tnd.be>
+ */
+class Titles extends GaletteTestCase
+{
+ protected int $seed = 20240417170519;
+
+ private array $remove = [];
+
+ /**
+ * Set up tests
+ *
+ * @return void
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+
+ $titles = new \Galette\Repository\Titles($this->zdb);
+ $res = $titles->installInit();
+ $this->assertTrue($res);
+ }
+
+ /**
+ * Tear down tests
+ *
+ * @return void
+ */
+ public function tearDown(): void
+ {
+ parent::tearDown();
+ $this->deleteTitles();
+ }
+
+ /**
+ * Delete payment type
+ *
+ * @return void
+ */
+ private function deleteTitles(): void
+ {
+ if (is_array($this->remove) && count($this->remove) > 0) {
+ $delete = $this->zdb->delete(\Galette\Entity\Title::TABLE);
+ $delete->where->in(\Galette\Entity\Title::PK, $this->remove);
+ $this->zdb->execute($delete);
+ }
+
+ //Clean logs
+ $this->zdb->db->query(
+ 'TRUNCATE TABLE ' . PREFIX_DB . \Galette\Core\History::TABLE,
+ \Laminas\Db\Adapter\Adapter::QUERY_MODE_EXECUTE
+ );
+ }
+
+ /**
+ * Test getList
+ *
+ * @return void
+ */
+ public function testGetList(): void
+ {
+ $titles = new \Galette\Repository\Titles($this->zdb);
+
+ $list = $titles->getList();
+ $this->assertCount(2, $list);
+
+ if ($this->zdb->isPostgres()) {
+ $select = $this->zdb->select(\Galette\Entity\PaymentType::TABLE . '_id_seq');
+ $select->columns(['last_value']);
+ $results = $this->zdb->execute($select);
+ $result = $results->current();
+ $this->assertGreaterThanOrEqual(1, $result->last_value, 'Incorrect titles sequence');
+ }
+
+ //add another one
+ $title = new \Galette\Entity\Title();
+ $title->short = 'Te.';
+ $title->long = 'Test';
+ $this->assertTrue($title->store($this->zdb));
+
+ $id = $title->id;
+ $this->remove[] = $id;
+
+ $list = $titles->getList();
+ $this->assertCount(3, $list);
+
+ //reinstall payment types
+ $titles->installInit();
+
+ $list = $titles->getList();
+ $this->assertCount(2, $list);
+
+ if ($this->zdb->isPostgres()) {
+ $select = $this->zdb->select(\Galette\Entity\PaymentType::TABLE . '_id_seq');
+ $select->columns(['last_value']);
+ $results = $this->zdb->execute($select);
+ $result = $results->current();
+ $this->assertGreaterThanOrEqual(
+ 1,
+ $result->last_value,
+ 'Incorrect title sequence ' . $result->last_value
+ );
+ }
+ }
+}