]> git.agnieray.net Git - galette.git/commitdiff
Social networks/contact externalization
authorJohan Cwiklinski <johan@x-tnd.be>
Sun, 24 Oct 2021 09:21:03 +0000 (11:21 +0200)
committerJohan Cwiklinski <johan@x-tnd.be>
Sun, 7 Nov 2021 08:17:31 +0000 (09:17 +0100)
Add socials feature, use Social and Replacement for preferences
Compat with old social values
Remove from preferences
SQL migration scripts
Drop old fields
Add tests
Add php80 functions
Fix preferences contact values
Test mail signature with social networks
Socials for members
Search in socials from "email, url, im" filter
Add socials on advanced search

closes #1585

39 files changed:
galette/composer.json
galette/composer.lock
galette/includes/fields_defs/members_fields.php
galette/includes/galette.inc.php
galette/install/scripts/mysql.sql
galette/install/scripts/pgsql.sql
galette/install/scripts/upgrade-to-0.96-mysql.sql [new file with mode: 0644]
galette/install/scripts/upgrade-to-0.96-pgsql.sql [new file with mode: 0644]
galette/lib/Galette/Controllers/Crud/MembersController.php
galette/lib/Galette/Controllers/GaletteController.php
galette/lib/Galette/Core/GaletteMail.php
galette/lib/Galette/Core/Preferences.php
galette/lib/Galette/Entity/Adherent.php
galette/lib/Galette/Entity/Social.php [new file with mode: 0644]
galette/lib/Galette/Features/Socials.php [new file with mode: 0644]
galette/lib/Galette/IO/CsvIn.php
galette/lib/Galette/IO/PdfMembersCards.php
galette/lib/Galette/Repository/Members.php
galette/templates/default/advanced_search.tpl
galette/templates/default/display_socials.tpl [new file with mode: 0644]
galette/templates/default/edit_socials.tpl [new file with mode: 0644]
galette/templates/default/forms_types.tpl
galette/templates/default/gestion_adherents.tpl
galette/templates/default/member.tpl
galette/templates/default/preferences.tpl
galette/templates/default/voir_adherent.tpl
galette/webroot/themes/default/galette.css
tests/Galette/Core/tests/units/Db.php
tests/Galette/Core/tests/units/Install.php
tests/Galette/Core/tests/units/Login.php
tests/Galette/Core/tests/units/Preferences.php
tests/Galette/Entity/tests/units/Adherent.php
tests/Galette/Entity/tests/units/FieldsConfig.php
tests/Galette/Entity/tests/units/ListsConfig.php
tests/Galette/Entity/tests/units/PdfModel.php
tests/Galette/Entity/tests/units/Social.php [new file with mode: 0644]
tests/Galette/IO/tests/units/CsvIn.php
tests/GaletteTestCase.php
tests/fixtures/tests_members.json

index 47570f086c97e13c4ddf147b17ad8d1ac29ffccb..7188763d5a1eeda862b1a773d5e9fb4a3bc6bc7e 100644 (file)
@@ -48,7 +48,8 @@
         "psr/container": "^1.0",
         "php-di/slim-bridge": "2.0.0",
         "doctrine/annotations": "^1.8",
-        "laminas/laminas-servicemanager": "3.7"
+        "laminas/laminas-servicemanager": "3.7",
+        "symfony/polyfill-php80": "^1.23"
     },
     "require-dev": {
         "atoum/atoum": "dev-master",
index 34aff016c4859a62a0ea025e19b0031456d45202..41ae74895e43de5277edfe6ee7943101e2d42f89 100644 (file)
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "58771c7f593b6023a54dbe5cd3fa9a99",
+    "content-hash": "abdb30cee5eeb0dad05c159a1c10880d",
     "packages": [
         {
             "name": "akrabat/rka-slim-session-middleware",
             },
             "time": "2019-02-15T01:44:54+00:00"
         },
+        {
+            "name": "symfony/polyfill-php80",
+            "version": "v1.23.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php80.git",
+                "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be",
+                "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.23-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php80\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ],
+                "classmap": [
+                    "Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Ion Bazan",
+                    "email": "ion.bazan@gmail.com"
+                },
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-07-28T13:41:28+00:00"
+        },
         {
             "name": "tecnickcom/tcpdf",
             "version": "6.4.2",
             ],
             "time": "2021-02-19T12:13:01+00:00"
         },
-        {
-            "name": "symfony/polyfill-php80",
-            "version": "v1.23.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-php80.git",
-                "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be",
-                "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=7.1"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-main": "1.23-dev"
-                },
-                "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Php80\\": ""
-                },
-                "files": [
-                    "bootstrap.php"
-                ],
-                "classmap": [
-                    "Resources/stubs"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Ion Bazan",
-                    "email": "ion.bazan@gmail.com"
-                },
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "polyfill",
-                "portable",
-                "shim"
-            ],
-            "support": {
-                "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1"
-            },
-            "funding": [
-                {
-                    "url": "https://symfony.com/sponsor",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://github.com/fabpot",
-                    "type": "github"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
-                    "type": "tidelift"
-                }
-            ],
-            "time": "2021-07-28T13:41:28+00:00"
-        },
         {
             "name": "symfony/service-contracts",
             "version": "v2.4.0",
index a5543e9d36b889c3b14d82d6c20753aa55a91a10..614f2480b28bcc947f4bbdf01e7dedf4048fa670 100644 (file)
@@ -181,38 +181,6 @@ $members_fields = array(
         'position' => 18,
         'category' => FieldsCategories::ADH_CATEGORY_CONTACT
     ),
-    'url_adh' => array(
-        'label'    => _T("Website:"),
-        'propname' => 'website',
-        'required' => false,
-        'visible'  => FieldsConfig::USER_WRITE,
-        'position' => 19,
-        'category' => FieldsCategories::ADH_CATEGORY_CONTACT
-    ),
-    'icq_adh' => array(
-        'label'    => _T("ICQ:"),
-        'propname' => 'icq',
-        'required' => false,
-        'visible'  => FieldsConfig::NOBODY,
-        'position' => 20,
-        'category' => FieldsCategories::ADH_CATEGORY_CONTACT
-    ),
-    'msn_adh' => array(
-        'label'    => _T("MSN:"),
-        'propname' => 'msn',
-        'required' => false,
-        'visible'  => FieldsConfig::NOBODY,
-        'position' => 22,
-        'category' => FieldsCategories::ADH_CATEGORY_CONTACT
-    ),
-    'jabber_adh' => array(
-        'label'    => _T("Jabber:"),
-        'propname' => 'jabber',
-        'required' => false,
-        'visible'  => FieldsConfig::USER_WRITE,
-        'position' => 21,
-        'category' => FieldsCategories::ADH_CATEGORY_CONTACT
-    ),
     'info_adh' => array(
         'label'    => _T("Other information (admin):"),
         'propname' => 'others_infos_admin',
index a31bf6b2467456373374af2b90411363e4cc7f8d..bdb7a7da6fb44d2a6b2faf384a2441c39e4b270c 100644 (file)
@@ -105,7 +105,7 @@ if (!defined('GALETTE_HIDE_VERSION')) {
 }
 
 define('GALETTE_COMPAT_VERSION', '0.9.5');
-define('GALETTE_DB_VERSION', '0.950');
+define('GALETTE_DB_VERSION', '0.960');
 if (!defined('GALETTE_MODE')) {
     define('GALETTE_MODE', \Galette\Core\Galette::MODE_PROD);
 }
index 9df82ad353fc1580ccc667d49ee1cd1dffac6e53..87fe5461c3314fcb70f1ed6623f1f165523b3707 100644 (file)
@@ -22,10 +22,6 @@ CREATE TABLE galette_adherents (
   tel_adh varchar(50) default NULL,
   gsm_adh varchar(50) default NULL,
   email_adh varchar(255) default NULL,
-  url_adh varchar(255) default NULL,
-  icq_adh varchar(20) default NULL, -- TODO: remove
-  msn_adh varchar(150) default NULL, -- TODO: remove
-  jabber_adh varchar(150) default NULL,
   info_adh text,
   info_public_adh text,
   prof_adh varchar(150) default NULL,
@@ -341,11 +337,23 @@ CREATE TABLE galette_tmplinks (
   PRIMARY KEY (target, id)
 ) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
 
+-- table for social networks
+DROP TABLE IF EXISTS galette_socials;
+CREATE TABLE galette_socials (
+  id_social int(10) unsigned NOT NULL auto_increment,
+  id_adh int(10) unsigned NULL,
+  type varchar(250) NOT NULL,
+  url varchar(255) DEFAULT NULL,
+  PRIMARY KEY (id_social),
+  KEY (type),
+  FOREIGN KEY (id_adh) REFERENCES  galette_adherents (id_adh) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
+
 -- table for database version
 DROP TABLE IF EXISTS galette_database;
 CREATE TABLE galette_database (
   version DECIMAL(4,3) NOT NULL
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-INSERT INTO galette_database(version) VALUES(0.95);
+INSERT INTO galette_database(version) VALUES(0.96);
 
 SET FOREIGN_KEY_CHECKS=1;
index 14881f0d9fbd75c86ec60d50e5e9ecc7c2e09e0b..0468df30b3ea76dc3036e9fbc4be275fb3bb89f1 100644 (file)
@@ -156,6 +156,15 @@ CREATE SEQUENCE galette_fields_categories_id_seq
     MINVALUE 1
     CACHE 1;
 
+-- sequence for socials
+DROP SEQUENCE IF EXISTS galette_socials_id_seq;
+CREATE SEQUENCE galette_socials_id_seq
+    START 1
+    INCREMENT 1
+    MAXVALUE 2147483647
+    MINVALUE 1
+    CACHE 1;
+
 -- Schema
 -- REMINDER: Create order IS important, dependencies first !!
 DROP TABLE IF EXISTS galette_paymenttypes;
@@ -200,10 +209,6 @@ CREATE TABLE galette_adherents (
     tel_adh character varying(50),
     gsm_adh character varying(50),
     email_adh character varying(255),
-    url_adh character varying(255),
-    icq_adh character varying(20), -- TODO: remove
-    msn_adh character varying(150), -- TODO: remove
-    jabber_adh character varying(150),
     info_adh text,
     info_public_adh text,
     prof_adh character varying(150),
@@ -478,9 +483,21 @@ CREATE TABLE galette_tmplinks (
   PRIMARY KEY (target, id)
 );
 
+-- table for social networks
+DROP TABLE IF EXISTS galette_socials;
+CREATE TABLE galette_socials (
+  id_social integer DEFAULT nextval('galette_socials_id_seq'::text) NOT NULL,
+  id_adh integer REFERENCES galette_adherents (id_adh) ON DELETE CASCADE ON UPDATE CASCADE,
+  type character varying(250) NOT NULL,
+  url character varying(255) DEFAULT NULL,
+  PRIMARY KEY (id_social)
+);
+-- add index on table to look for type
+CREATE INDEX galette_socials_idx ON galette_socials (type);
+
 -- table for database version
 DROP TABLE IF EXISTS galette_database;
 CREATE TABLE galette_database (
   version decimal NOT NULL
 );
-INSERT INTO galette_database (version) VALUES(0.95);
+INSERT INTO galette_database (version) VALUES(0.96);
diff --git a/galette/install/scripts/upgrade-to-0.96-mysql.sql b/galette/install/scripts/upgrade-to-0.96-mysql.sql
new file mode 100644 (file)
index 0000000..5aeb2a9
--- /dev/null
@@ -0,0 +1,40 @@
+CREATE TABLE galette_socials (
+     id_social int(10) unsigned NOT NULL auto_increment,
+     id_adh int(10) unsigned NULL,
+     type varchar(250) NOT NULL,
+     url varchar(255) DEFAULT NULL,
+     PRIMARY KEY (id_social),
+     KEY (type),
+     FOREIGN KEY (id_adh) REFERENCES  galette_adherents (id_adh) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
+
+-- migrate socials from preferences
+INSERT INTO galette_socials (id_adh, type, url) SELECT null, 'google+', val_pref FROM galette_preferences WHERE nom_pref = 'pref_googleplus' AND val_pref != '';
+INSERT INTO galette_socials (id_adh, type, url) SELECT null, 'facebook', val_pref FROM galette_preferences WHERE nom_pref = 'pref_facebook' AND val_pref != '';
+INSERT INTO galette_socials (id_adh, type, url) SELECT null, 'twitter', val_pref FROM galette_preferences WHERE nom_pref = 'pref_twitter' AND val_pref != '';
+INSERT INTO galette_socials (id_adh, type, url) SELECT null, 'linkedin', val_pref FROM galette_preferences WHERE nom_pref = 'pref_linkedin' AND val_pref != '';
+INSERT INTO galette_socials (id_adh, type, url) SELECT null, 'viadeo', val_pref FROM galette_preferences WHERE nom_pref = 'pref_viadeo' AND val_pref != '';
+-- cleanup preferences
+DELETE FROM galette_preferences WHERE
+    nom_pref = 'pref_googleplus'
+    OR nom_pref = 'pref_facebook'
+    OR nom_pref = 'pref_twitter'
+    OR nom_pref = 'pref_linkedin'
+    OR nom_pref = 'pref_viadeo';
+-- update pdf card address
+UPDATE galette_preferences SET val_pref = 0 WHERE nom_pref = 'pref_card_address' AND val_pref IN ('1', '2', '3', '4');
+
+-- migrate members socials
+INSERT INTO galette_socials (id_adh, type, url) SELECT id_adh, 'website', url_adh FROM galette_adherents WHERE url_adh != '';
+INSERT INTO galette_socials (id_adh, type, url) SELECT id_adh, 'icq', icq_adh FROM galette_adherents WHERE icq_adh != '';
+INSERT INTO galette_socials (id_adh, type, url) SELECT id_adh, 'msn', msn_adh FROM galette_adherents WHERE msn_adh != '';
+INSERT INTO galette_socials (id_adh, type, url) SELECT id_adh, 'jabber', jabber_adh FROM galette_adherents WHERE jabber_adh != '';
+-- cleanup members table
+ALTER TABLE galette_adherents DROP column url_adh;
+ALTER TABLE galette_adherents DROP column icq_adh;
+ALTER TABLE galette_adherents DROP column msn_adh;
+ALTER TABLE galette_adherents DROP column jabber_adh;
+-- cleanup fields config
+DELETE FROM galette_fields_config WHERE field_id IN ('url_adh', 'icq_adh', 'msn_adh', 'jabber_adh');
+
+UPDATE galette_database SET version = 0.960;
\ No newline at end of file
diff --git a/galette/install/scripts/upgrade-to-0.96-pgsql.sql b/galette/install/scripts/upgrade-to-0.96-pgsql.sql
new file mode 100644 (file)
index 0000000..a19b1cc
--- /dev/null
@@ -0,0 +1,48 @@
+-- sequence for socials
+CREATE SEQUENCE galette_socials_id_seq
+    START 1
+    INCREMENT 1
+    MAXVALUE 2147483647
+    MINVALUE 1
+    CACHE 1;
+
+CREATE TABLE galette_socials (
+ id_social integer DEFAULT nextval('galette_socials_id_seq'::text) NOT NULL,
+ id_adh integer REFERENCES galette_adherents (id_adh) ON DELETE CASCADE ON UPDATE CASCADE,
+ type character varying(250) NOT NULL,
+ url character varying(255) DEFAULT NULL,
+ PRIMARY KEY (id_social)
+);
+-- add index on table to look for type
+CREATE INDEX galette_socials_idx ON galette_socials (type);
+
+-- migrate socials from preferences
+INSERT INTO galette_socials (id_adh, type, url) SELECT null, 'google+', val_pref FROM galette_preferences WHERE nom_pref = 'pref_googleplus' AND val_pref != '';
+INSERT INTO galette_socials (id_adh, type, url) SELECT null, 'facebook', val_pref FROM galette_preferences WHERE nom_pref = 'pref_facebook' AND val_pref != '';
+INSERT INTO galette_socials (id_adh, type, url) SELECT null, 'twitter', val_pref FROM galette_preferences WHERE nom_pref = 'pref_twitter' AND val_pref != '';
+INSERT INTO galette_socials (id_adh, type, url) SELECT null, 'linkedin', val_pref FROM galette_preferences WHERE nom_pref = 'pref_linkedin' AND val_pref != '';
+INSERT INTO galette_socials (id_adh, type, url) SELECT null, 'viadeo', val_pref FROM galette_preferences WHERE nom_pref = 'pref_viadeo' AND val_pref != '';
+-- cleanup preferences
+DELETE FROM galette_preferences WHERE
+    nom_pref = 'pref_googleplus'
+    OR nom_pref = 'pref_facebook'
+    OR nom_pref = 'pref_twitter'
+    OR nom_pref = 'pref_linkedin'
+    OR nom_pref = 'pref_viadeo';
+-- update pdf card address
+UPDATE galette_preferences SET val_pref = 0 WHERE nom_pref = 'pref_card_address' AND val_pref IN ('1', '2', '3', '4');
+
+-- migrate members socials
+INSERT INTO galette_socials (id_adh, type, url) SELECT id_adh, 'website', url_adh FROM galette_adherents WHERE url_adh != '';
+INSERT INTO galette_socials (id_adh, type, url) SELECT id_adh, 'icq', icq_adh FROM galette_adherents WHERE icq_adh != '';
+INSERT INTO galette_socials (id_adh, type, url) SELECT id_adh, 'msn', msn_adh FROM galette_adherents WHERE msn_adh != '';
+INSERT INTO galette_socials (id_adh, type, url) SELECT id_adh, 'jabber', jabber_adh FROM galette_adherents WHERE jabber_adh != '';
+-- cleanup members table
+ALTER TABLE galette_adherents DROP column url_adh;
+ALTER TABLE galette_adherents DROP column icq_adh;
+ALTER TABLE galette_adherents DROP column msn_adh;
+ALTER TABLE galette_adherents DROP column jabber_adh;
+-- cleanup fields config table
+DELETE FROM galette_fields_config WHERE field_id IN ('url_adh', 'icq_adh', 'msn_adh', 'jabber_adh');
+
+UPDATE galette_database SET version = 0.960;
\ No newline at end of file
index 95135779b29724373c070da3fd3bb2bc64960567..0a62913e481f9f1e39c1b4ae9073ef031ad59c52 100644 (file)
@@ -49,6 +49,7 @@ use Galette\Entity\DynamicFieldsHandle;
 use Galette\Entity\Group;
 use Galette\Entity\Status;
 use Galette\Entity\FieldsConfig;
+use Galette\Entity\Social;
 use Galette\Filters\AdvancedMembersList;
 use Galette\Filters\MembersList;
 use Galette\IO\File;
@@ -165,6 +166,7 @@ class MembersController extends CrudController
                 'member'            => $member,
                 'self_adh'          => true,
                 'autocomplete'      => true,
+                'osocials'          => new Social($this->zdb),
                 // pseudo random int
                 'time'              => time(),
                 'titles_list'       => Titles::getList($this->zdb),
@@ -289,7 +291,8 @@ class MembersController extends CrudController
                 'pref_card_self'    => $this->preferences->pref_card_self,
                 'groups'            => Groups::getSimpleList(),
                 'time'              => time(),
-                'display_elements'  => $display_elements
+                'display_elements'  => $display_elements,
+                'osocials'          => new Social($this->zdb)
             )
         );
         return $response;
@@ -800,6 +803,13 @@ class MembersController extends CrudController
 
         $filters->setViewCommonsFilters($this->preferences, $this->view->getSmarty());
 
+        $social = new Social($this->zdb);
+        $types = $member->getMemberRegisteredTypes();
+        $social_types = [];
+        foreach ($types as $type) {
+            $social_types[$type] = $social->getSystemType($type);
+        }
+
         // display page
         $this->view->render(
             $response,
@@ -810,6 +820,7 @@ class MembersController extends CrudController
                 'search_fields'         => $fields,
                 'adh_dynamics'          => $adh_dynamics->getFields(),
                 'contrib_dynamics'      => $contrib_dynamics->getFields(),
+                'adh_socials'           => $social_types,
                 'statuts'               => $statuts->getList(),
                 'contributions_types'   => $ct->getList(),
                 'filters'               => $filters,
@@ -1175,7 +1186,8 @@ class MembersController extends CrudController
                 'fieldsets'         => $form_elements['fieldsets'],
                 'hidden_elements'   => $form_elements['hiddens'],
                 'parent_fields'     => $tpl_parent_fields,
-                'addchild'          => ($action === 'addchild')
+                'addchild'          => ($action === 'addchild'),
+                'osocials'          => new Social($this->zdb)
             ) + $route_params
         );
         return $response;
index 0688fe9f86798bebbd4bd5df4a1a039bf272da98..d71561372755346ae668099034b4686f84e80477 100644 (file)
@@ -36,6 +36,7 @@
 
 namespace Galette\Controllers;
 
+use Galette\Entity\Social;
 use Galette\Repository\PaymentTypes;
 use Slim\Http\Request;
 use Slim\Http\Response;
@@ -256,7 +257,8 @@ class GaletteController extends AbstractController
                     Members::ACTIVE_ACCOUNT     => _T("Active accounts"),
                     Members::INACTIVE_ACCOUNT   => _T("Inactive accounts")
                 ),
-                'paymenttypes'          => $ptlist
+                'paymenttypes'          => $ptlist,
+                'osocials'              => new Social($this->zdb)
             )
         );
         return $response;
index e304517a00647778b20a4049e9babcfd06c43ec2..8ad5993c4fb6c7fc9d8ab545f962578a07df8a55 100644 (file)
@@ -7,7 +7,7 @@
  *
  * PHP version 5
  *
- * Copyright © 2009-2014 The Galette Team
+ * Copyright © 2009-2021 The Galette Team
  *
  * This file is part of Galette (http://galette.tuxfamily.org).
  *
@@ -28,7 +28,7 @@
  * @package   Galette
  *
  * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2009-2014 The Galette Team
+ * @copyright 2009-2021 The Galette Team
  * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
  * @link      http://galette.tuxfamily.org
  * @since     Available since 0.7dev - 2009-12-10
@@ -47,7 +47,7 @@ use PHPMailer\PHPMailer\PHPMailer;
  * @name      GaletteMail
  * @package   Galette
  * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2009-2014 The Galette Team
+ * @copyright 2009-2021 The Galette Team
  * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
  * @link      http://galette.tuxfamily.org
  * @since     Available since 0.7dev - 2009-03-07
@@ -289,46 +289,19 @@ class GaletteMail
             );
         }
 
-        if (trim($this->preferences->pref_mail_sign) != '') {
-            $patterns = array(
-                '/{NAME}/',
-                '/{WEBSITE}/',
-                '/{FACEBOOK}/',
-                '/{GOOGLEPLUS}/',
-                '/{TWITTER}/',
-                '/{LINKEDIN}/',
-                '/{VIADEO}/'
-            );
-
-            $replaces = array(
-                $this->preferences->pref_nom,
-                $this->preferences->pref_website,
-                $this->preferences->pref_facebook,
-                $this->preferences->pref_googleplus,
-                $this->preferences->pref_twitter,
-                $this->preferences->pref_linkedin,
-                $this->preferences->pref_viadeo
-            );
-
-            $sign = preg_replace(
-                $patterns,
-                $replaces,
-                $this->preferences->pref_mail_sign
-            );
-
+        $signature = $this->preferences->getMailSignature();
+        if ($signature != '') {
             if ($this->html) {
                 //we are sending html message
-                $tsign = "\r\n-- \r\n" . $sign;
                 //apply email sign to text version
-                $this->mail->AltBody .= $tsign;
+                $this->mail->AltBody .= $signature;
                 //then apply email sign to html version
                 $sign_style = 'color:grey;border-top:1px solid #ccc;margin-top:2em';
                 $hsign = '<div style="' . $sign_style . '">' .
-                    nl2br($sign) . '</div>';
+                    nl2br($signature) . '</div>';
                 $this->mail->Body .= $hsign;
             } else {
-                $sign = "\r\n-- \r\n" . $sign;
-                $this->mail->Body .= $sign;
+                $this->mail->Body .= $signature;
             }
         }
 
index 80e916cfb29db4cd5d3636d27eac2f39585887e7..66395fa14d119900df283421716208ae6dd2fb8e 100644 (file)
@@ -36,6 +36,9 @@
 namespace Galette\Core;
 
 use Galette\Entity\PaymentType;
+use Galette\Entity\Social;
+use Galette\Features\Replacements;
+use Galette\Features\Socials;
 use Throwable;
 use Analog\Analog;
 use Galette\Entity\Adherent;
@@ -116,11 +119,6 @@ use Galette\Repository\Members;
  * @property boolean $pref_bool_publicpages
  * @property integer $pref_publicpages_visibility
  * @property boolean $pref_bool_selfsubscribe
- * @property string $pref_googleplus
- * @property string $pref_facebook
- * @property string $pref_twitter
- * @property string $pref_viadeo
- * @property string $pref_linkedin
  * @property string $pref_mail_sign
  * @property string $pref_new_contrib_script
  * @property boolean $pref_bool_wrap_mails
@@ -145,7 +143,10 @@ use Galette\Repository\Members;
  */
 class Preferences
 {
-    private $zdb;
+    use Replacements;
+    use Socials;
+
+    protected $preferences; //redefined from Replacements feature - avoid circular dependency
     private $prefs;
     private $errors = [];
 
@@ -249,12 +250,7 @@ class Preferences
         'pref_bool_publicpages' => true,
         'pref_publicpages_visibility' => self::PUBLIC_PAGES_VISIBILITY_RESTRICTED,
         'pref_bool_selfsubscribe' => true,
-        'pref_googleplus' => '',
-        'pref_facebook' => '',
-        'pref_twitter' => '',
-        'pref_viadeo' => '',
-        'pref_linkedin' => '',
-        'pref_mail_sign' => "{NAME}\r\n\r\n{WEBSITE}\r\n{GOOGLEPLUS}\r\n{FACEBOOK}\r\n{TWITTER}\r\n{LINKEDIN}\r\n{VIADEO}",
+        'pref_mail_sign' => "{ASSO_NAME}\r\n\r\n{ASSO_WEBSITE}",
         /* New contribution script */
         'pref_new_contrib_script' => '',
         'pref_bool_wrap_mails' => true,
@@ -278,6 +274,9 @@ class Preferences
         'pref_bool_create_member' => false
     );
 
+    /** @var Social[] */
+    private $socials;
+
     // flagging required fields
     private $required = array(
         'pref_nom',
@@ -393,6 +392,7 @@ class Preferences
             foreach ($result as $pref) {
                 $this->prefs[$pref->nom_pref] = $pref->val_pref;
             }
+            $this->socials = Social::getListForMember(null);
             return true;
         } catch (Throwable $e) {
             Analog::log(
@@ -617,6 +617,8 @@ class Preferences
             }
         }
 
+        $this->checkSocials($values);
+
         return 0 === count($this->errors);
     }
 
@@ -807,6 +809,9 @@ class Preferences
                 'Preferences were successfully stored into database.',
                 Analog::INFO
             );
+
+            $this->storeSocials(null);
+
             return true;
         } catch (Throwable $e) {
             $this->zdb->connection->rollBack();
@@ -977,6 +982,8 @@ class Preferences
         } elseif (in_array($name, $virtuals)) {
             $virtual = str_replace('vpref_', 'pref_', $name);
             return explode(',', $this->prefs[$virtual]);
+        } elseif ($name === 'socials') {
+            return $this->socials;
         } else {
             Analog::log(
                 'Preference `' . $name . '` is not set or is forbidden',
@@ -1148,4 +1155,143 @@ class Preferences
     {
         return $this->errors;
     }
+
+    /**
+     * Build legend array
+     *
+     * @return array
+     */
+    public function getLegend(): array
+    {
+        $legend = [];
+
+        $legend['main'] = [
+            'title'     => _T('Main information'),
+            'patterns'  => $this->getMainPatterns()
+        ];
+
+        $s_patterns = $this->getSignaturePatterns(false);
+        if (count($s_patterns)) {
+            $legend['socials'] = [
+                'title' => _T('Social networks'),
+                'patterns' => $this->getSignaturePatterns(false)
+            ];
+        }
+
+        return $legend;
+    }
+
+    /**
+     * Get email signature
+     *
+     * @return string
+     */
+    public function getMailSignature(): string
+    {
+        global $router;
+
+        $signature = $this->pref_mail_sign;
+
+        if (trim($signature) == '') {
+            return '';
+        }
+
+        $this->setPreferences($this)->setRouter($router);
+        $this->setPatterns(
+            $this->getMainPatterns() + $this->getSignaturePatterns()
+        );
+        $this
+            ->setMain()
+            ->setSocialReplacements();
+
+        $signature = $this->proceedReplacements($signature);
+
+        return "\r\n-- \r\n" . $signature;
+    }
+
+    /**
+     * Get patterns for mail signature
+     *
+     * @param boolean $legacy Whether to load legacy patterns
+     *
+     * @return array
+     */
+    protected function getSignaturePatterns($legacy = true): array
+    {
+        $s_patterns = [];
+        $social = new Social($this->zdb);
+
+        $types = $this->getCoreRegisteredTypes() + $social->getSystemTypes(false);
+
+        foreach ($types as $type) {
+            $s_patterns['asso_social_' . $type] = [
+                'title' => $social->getSystemType($type),
+                'pattern' => '/{ASSO_SOCIAL_' . strtoupper($type) . '}/'
+            ];
+        }
+
+        if ($legacy === true) {
+            $main = $this->getMainPatterns();
+            $s_patterns['_asso_name'] = [
+                'title'     => $main['asso_name']['title'],
+                'pattern'   => '/{NAME}/'
+            ];
+
+            $s_patterns['_asso_website'] = [
+                'title'     => $main['asso_website']['title'],
+                'pattern'   => '/{WEBSITE}/'
+            ];
+
+            foreach ([Social::FACEBOOK, Social::TWITTER, Social::LINKEDIN, Social::VIADEO] as $legacy_type) {
+                $s_patterns['_asso_social_' . $legacy_type] = [
+                    'title' => $s_patterns['asso_social_' . $legacy_type]['title'],
+                    'pattern' => '/{' . strtoupper($legacy_type) . '}/'
+                ];
+            }
+        }
+
+        return $s_patterns;
+    }
+
+    /**
+     * Set emails replacements
+     *
+     * @return $this
+     */
+    public function setSocialReplacements(): self
+    {
+        $replacements = [];
+
+        $done_replacements = $this->getReplacements();
+        $replacements['_asso_name'] = $done_replacements['asso_name'];
+        $replacements['asso_website'] = $this->pref_website;
+        $replacements['_asso_website'] = $replacements['asso_website'];
+
+        $social = new Social($this->zdb);
+        $types = $this->getCoreRegisteredTypes() + $social->getSystemTypes(false);
+
+        foreach ($types as $type) {
+            $replace_value = null;
+            $socials = Social::getListForMember(null, $type);
+            if (count($socials)) {
+                $replace_value = '';
+                foreach ($socials as $social) {
+                    if ($replace_value != '') {
+                        $replace_value .= ', ';
+                    }
+                    $replace_value .= $social->url;
+                }
+            }
+            $replacements['asso_social_' . strtolower($type)] = $replace_value;
+        }
+
+
+        foreach ([Social::FACEBOOK, Social::TWITTER, Social::LINKEDIN, Social::VIADEO] as $legacy_type) {
+            $replacements['_asso_social_' . $legacy_type] = $replacements['asso_social_' . $legacy_type];
+        }
+
+        $this->setReplacements($replacements);
+
+        return $this;
+    }
 }
index 974ba2d09ba2e4bcd8d56f1ba206b3962da9f0a1..72be6ff8a317bef6633a4ab861e37b00126170e9 100644 (file)
@@ -36,6 +36,7 @@
 
 namespace Galette\Entity;
 
+use Galette\Features\Socials;
 use Throwable;
 use Analog\Analog;
 use Laminas\Db\Sql\Expression;
@@ -86,10 +87,6 @@ use Galette\Features\Dynamics;
  * @property string $phone
  * @property string $gsm
  * @property string $email
- * @property string $website
- * @property string $msn
- * @property string $icq
- * @property string $jabber
  * @property string $gnupgid
  * @property string $fingerprint
  * @property string $login
@@ -120,10 +117,13 @@ use Galette\Features\Dynamics;
  * @property string $contribstatus State of member contributions
  * @property string $days_remaining
  * @property-read integer $parent_id
+ * @property Social $social Social networks/Contact
+ *
  */
 class Adherent
 {
     use Dynamics;
+    use Socials;
 
     public const TABLE = 'adherents';
     public const PK = 'id_adh';
@@ -162,10 +162,6 @@ class Adherent
     private $_phone;
     private $_gsm;
     private $_email;
-    private $_website;
-    private $_msn; /** TODO: remove */
-    private $_icq; /** TODO: remove */
-    private $_jabber; /** TODO: remove */
     private $_gnupgid;
     private $_fingerprint;
     //Galette relative information
@@ -188,6 +184,7 @@ class Adherent
     private $_parent;
     private $_children;
     private $_duplicate = false;
+    private $_socials;
 
     private $_row_classes;
 
@@ -198,7 +195,8 @@ class Adherent
         'dues'      => true,
         'parent'    => false,
         'children'  => false,
-        'dynamics'  => false
+        'dynamics'  => false,
+        'socials'   => false
     );
 
     private $zdb;
@@ -390,16 +388,7 @@ class Adherent
         $this->_phone = $r->tel_adh;
         $this->_gsm = $r->gsm_adh;
         $this->_email = $r->email_adh;
-        $this->_website = $r->url_adh;
-        /** TODO: remove */
-        $this->_msn = $r->msn_adh;
-        /** TODO: remove */
-        $this->_icq = $r->icq_adh;
-        /** TODO: remove */
-        $this->_jabber = $r->jabber_adh;
-        /** TODO: remove */
         $this->_gnupgid = $r->gpgid;
-        /** TODO: remove */
         $this->_fingerprint = $r->fingerprint;
         //Galette relative information
         $this->_appears_in_list = ($r->bool_display_info == 1) ? true : false;
@@ -449,6 +438,10 @@ class Adherent
         if ($this->_deps['dynamics'] === true) {
             $this->loadDynamicFields();
         }
+
+        if ($this->_deps['socials'] === true) {
+            $this->loadSocials();
+        }
     }
 
     /**
@@ -512,6 +505,16 @@ class Adherent
         $this->_managed_groups = Groups::loadManagedGroups($this->_id);
     }
 
+    /**
+     * Load member social network/contact information
+     *
+     * @return void
+     */
+    public function loadSocials()
+    {
+        $this->_socials = Social::getListForMember($this->_id);
+    }
+
     /**
      * Retrieve status from preferences
      *
@@ -1179,6 +1182,7 @@ class Adherent
         }
 
         $this->dynamicsCheck($values, $required, $disabled);
+        $this->checkSocials($values);
 
         if (count($this->errors) > 0) {
             Analog::log(
@@ -1289,7 +1293,6 @@ class Adherent
                 }
                 break;
             case 'email_adh':
-            case 'msn_adh':
                 if (!GaletteMail::isValidEmail($value)) {
                     $this->errors[] = _T("- Non-valid E-Mail address!") .
                         ' (' . $this->getFieldLabel($field) . ')';
@@ -1319,13 +1322,6 @@ class Adherent
                     }
                 }
                 break;
-            case 'url_adh':
-                if ($value == 'http://' || $value == 'https://') {
-                    $this->$prop = '';
-                } elseif (!isValidWebUrl($value)) {
-                    $this->errors[] = _T("- Non-valid Website address! Maybe you've skipped the http://?");
-                }
-                break;
             case 'login_adh':
                 /** FIXME: add a preference for login length */
                 if (strlen($value) < 2) {
@@ -1596,6 +1592,7 @@ class Adherent
             //dynamic fields
             if ($success) {
                 $success = $this->dynamicsStore();
+                $this->storeSocials($this->id);
             }
 
             //send event at the end of process, once all has been stored
@@ -1659,9 +1656,11 @@ class Adherent
         $virtuals = array(
             'sadmin', 'sstaff', 'sdue_free', 'sappears_in_list', 'sactive',
             'stitle', 'sstatus', 'sfullname', 'sname', 'saddress',
-            'rbirthdate', 'sgender', 'contribstatus'
+            'rbirthdate', 'sgender', 'contribstatus',
         );
 
+        $socials = array('website', 'msn', 'jabber', 'icq');
+
         if (in_array($name, $forbidden)) {
             switch ($name) {
                 case 'admin':
@@ -1744,6 +1743,12 @@ class Adherent
             }
         }
 
+        //for backward compatibility
+        if (in_array($name, $socials)) {
+            $values = Social::getListForMember($this->_id, $name);
+            return $values[0] ?? null;
+        }
+
         if (substr($name, 0, 1) !== '_') {
             $rname = '_' . $name;
         } else {
diff --git a/galette/lib/Galette/Entity/Social.php b/galette/lib/Galette/Entity/Social.php
new file mode 100644 (file)
index 0000000..1084bb3
--- /dev/null
@@ -0,0 +1,386 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Social networks/Contacts
+ *
+ * PHP version 5
+ *
+ * Copyright © 2021 The Galette Team
+ *
+ * This file is part of Galette (http://galette.tuxfamily.org).
+ *
+ * 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/>.
+ *
+ * @category  Entity
+ * @package   Galette
+ *
+ * @author    Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2021 The Galette Team
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @link      http://galette.tuxfamily.org
+ * @since     Available since 0.9.6dev - 2021-10-23
+ */
+
+namespace Galette\Entity;
+
+use Galette\Core\GaletteMail;
+use Galette\Features\I18n;
+use Laminas\Db\ResultSet\ResultSet;
+use Laminas\Db\Sql\Expression;
+use Throwable;
+use Galette\Core\Db;
+use Analog\Analog;
+
+/**
+ * Social networks/Contacts
+ *
+ * @category  Entity
+ * @name      Social
+ * @package   Galette
+ * @author    Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2021 The Galette Team
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @link      http://galette.tuxfamily.org
+ * @since     Available since 0.9.6dev - 2021-10-23
+ */
+
+class Social
+{
+    use I18n;
+
+    public const TABLE = 'socials';
+    public const PK = 'id_social';
+
+    public const MASTODON = 'mastodon';
+    public const TWITTER = 'twitter';
+    public const FACEBOOK = 'facebook';
+    public const LINKEDIN = 'linkedin';
+    public const VIADEO = 'viadeo';
+    public const JABBER = 'jabber';
+    public const ICQ = 'icq';
+    public const WEBSITE = 'website';
+    public const BLOG = 'blog';
+
+    /** @var Db */
+    private $zdb;
+    /** @var int */
+    private $id;
+    /** @var string */
+    private $type;
+    /** @var string */
+    private $url;
+    /** @var int */
+    private $id_adh;
+    /** @var Adherent */
+    private $member;
+
+    /**
+     * Main constructor
+     *
+     * @param Db    $zdb  Database instance
+     * @param mixed $args Arguments
+     */
+    public function __construct(Db $zdb, $args = null)
+    {
+        $this->zdb = $zdb;
+        if (is_int($args)) {
+            $this->load($args);
+        } elseif (is_object($args)) {
+            $this->loadFromRs($args);
+        }
+    }
+
+    /**
+     * Load a social from its identifier
+     *
+     * @param integer $id Identifier
+     *
+     * @return void
+     */
+    private function load(int $id): void
+    {
+        try {
+            $select = $this->zdb->select(self::TABLE);
+            $select->limit(1)->where(self::PK . ' = ' . $id);
+
+            $results = $this->zdb->execute($select);
+            $res = $results->current();
+            $this->loadFromRs($res);
+        } catch (Throwable $e) {
+            Analog::log(
+                'An error occurred loading social #' . $id . "Message:\n" .
+                $e->getMessage(),
+                Analog::ERROR
+            );
+        }
+    }
+
+    /**
+     * Get socials for a member
+     *
+     * @param int|null    $id_adh Member id
+     * @param string|null $type   Type to retrieve
+     *
+     * @return array
+     *
+     * @throws Throwable
+     */
+    public static function getListForMember(int $id_adh = null, string $type = null): array
+    {
+        global $zdb;
+
+        try {
+            $select = $zdb->select(self::TABLE);
+
+            if ($id_adh === null) {
+                $select->where(Adherent::PK . ' IS NULL');
+            } else {
+                $select->where([Adherent::PK => $id_adh]);
+            }
+
+            if ($type !== null) {
+                $select->where(['type' => $type]);
+            }
+
+            $select->order(self::PK);
+
+            $results = $zdb->execute($select);
+            $socials = [];
+            foreach ($results as $r) {
+                $socials[$r->{self::PK}] = new Social($zdb, $r);
+            }
+            return $socials;
+        } catch (Throwable $e) {
+            Analog::log(
+                'An error occurred loading socials for member #' . $id_adh . "Message:\n" .
+                $e->getMessage(),
+                Analog::ERROR
+            );
+            throw $e;
+        }
+    }
+
+    /**
+     * Load social from a db ResultSet
+     *
+     * @param ResultSet $rs ResultSet
+     *
+     * @return void
+     */
+    private function loadFromRs($rs)
+    {
+        $this->id = $rs->{self::PK};
+        $this->setLinkedMember((int)$rs->{Adherent::PK});
+        $this->type = $rs->type;
+        $this->url = $rs->url;
+    }
+
+    /**
+     * Store social in database
+     *
+     * @return boolean
+     */
+    public function store(): bool
+    {
+        try {
+            if ($this->id !== null && $this->id > 0) {
+                $update = $this->zdb->update(self::TABLE);
+                $update->set(['url' => $this->url])->where(
+                    self::PK . '=' . $this->id
+                );
+                $this->zdb->execute($update);
+            } else {
+                $insert = $this->zdb->insert(self::TABLE);
+                $id_adh = $this->{Adherent::PK} > 0 ? $this->{Adherent::PK} : new Expression('NULL');
+                $insert->values([
+                    'type'          => $this->type,
+                    'url'           => $this->url,
+                    Adherent::PK    => $id_adh
+                ]);
+                $add = $this->zdb->execute($insert);
+                if (!$add->count() > 0) {
+                    Analog::log('Not stored!', Analog::ERROR);
+                    return false;
+                }
+
+                $this->id = $this->zdb->getLastGeneratedValue($this);
+                if (!in_array($this->type, $this->getSystemTypes(false))) {
+                    $this->addTranslation($this->type);
+                }
+            }
+            return true;
+        } catch (Throwable $e) {
+            Analog::log(
+                'An error occurred storing social: ' . $e->getMessage(),
+                Analog::ERROR
+            );
+            throw $e;
+        }
+    }
+
+    /**
+     * Remove current social
+     *
+     * @param array|null $ids IDs to remove, default to current id
+     *
+     * @return boolean
+     */
+    public function remove(array $ids = null): bool
+    {
+        if ($ids == null) {
+            $ids[] = $this->id;
+        }
+
+        try {
+            $delete = $this->zdb->delete(self::TABLE);
+            $delete->where([self::PK => $ids]);
+            $this->zdb->execute($delete);
+            Analog::log(
+                'Social #' . implode(', #', $ids)  . ' deleted successfully.',
+                Analog::INFO
+            );
+            return true;
+        } catch (Throwable $e) {
+            Analog::log(
+                'Unable to delete social #' . implode(', #', $ids) . ' | ' . $e->getMessage(),
+                Analog::ERROR
+            );
+            throw $e;
+        }
+    }
+
+    /**
+     * Getter
+     *
+     * @param string $name Property name
+     *
+     * @return mixed
+     */
+    public function __get(string $name)
+    {
+        return $this->$name;
+    }
+
+    /**
+     * Display URL the best way
+     *
+     * @return string
+     */
+    public function displayUrl(): string
+    {
+        if (isValidWebUrl($this->url)) {
+            return sprintf('<a href="%1$s">%1$s</a>', $this->url);
+        }
+
+        if (GaletteMail::isValidEmail($this->url)) {
+            return sprintf('<a href="mailto:%1$s">%1$s</a>', $this->url);
+        }
+
+        return $this->url;
+    }
+
+    /**
+     * Set type
+     *
+     * @param string $type Type
+     *
+     * @return $this
+     */
+    public function setType(string $type): self
+    {
+        $this->type = $type;
+        return $this;
+    }
+
+    /**
+     * Set linked member
+     *
+     * @param int|null $id Member id
+     *
+     * @return $this
+     */
+    public function setLinkedMember(int $id = null): self
+    {
+        $this->{Adherent::PK} = $id;
+        if ($this->{Adherent::PK} > 0) {
+            $this->member = new Adherent($this->zdb, $this->{Adherent::PK});
+        }
+        return $this;
+    }
+
+    /**
+     * Set URL
+     *
+     * @param string $url Value to set
+     *
+     * @return $this
+     */
+    public function setUrl(string $url): self
+    {
+        $this->url = $url;
+        return $this;
+    }
+
+    /**
+     * Get system social types
+     *
+     * @param boolean $translated Return translated types (default) or not
+     *
+     * @return array
+     */
+    public function getSystemTypes(bool $translated = true): array
+    {
+        if ($translated) {
+            $systypes = [
+                self::MASTODON => _T('Mastodon'),
+                self::TWITTER => _T('Twitter'),
+                self::FACEBOOK => _T('Facebook'),
+                self::LINKEDIN => _T('LinkedIn'),
+                self::VIADEO => _T('Viadeo'),
+                self::JABBER => _T('Jabber'),
+                self::ICQ => _T('ICQ'),
+                self::WEBSITE => _T('Website'),
+                self::BLOG => _T('Blog')
+            ];
+        } else {
+            $systypes = [
+                self::MASTODON => 'mastodon',
+                self::TWITTER => 'twitter',
+                self::FACEBOOK => 'facebook',
+                self::LINKEDIN => 'linkedin',
+                self::VIADEO => 'viadeo',
+                self::JABBER => 'jabber',
+                self::ICQ => 'icq',
+                self::WEBSITE => 'website',
+                self::BLOG => 'blog'
+            ];
+        }
+        return $systypes;
+    }
+
+    /**
+     * Get system social types
+     *
+     * @param string  $type       Social type
+     * @param boolean $translated Return translated types (default) or not
+     *
+     * @return string
+     */
+    public function getSystemType(string $type, bool $translated = true): string
+    {
+        return $this->getSystemTypes($translated)[$type] ?? _T($type);
+    }
+}
diff --git a/galette/lib/Galette/Features/Socials.php b/galette/lib/Galette/Features/Socials.php
new file mode 100644 (file)
index 0000000..f66e376
--- /dev/null
@@ -0,0 +1,166 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Socials feature
+ *
+ * PHP version 5
+ *
+ * Copyright © 2021 The Galette Team
+ *
+ * This file is part of Galette (http://galette.tuxfamily.org).
+ *
+ * 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/>.
+ *
+ * @category  Entity
+ * @package   Galette
+ *
+ * @author    Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2021 The Galette Team
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @link      https://galette.eu
+ * @since     2021-10-25
+ */
+
+namespace Galette\Features;
+
+use Galette\Entity\Adherent;
+use Galette\Entity\Social;
+
+/**
+ * Replacements feature
+ *
+ * @category  Features
+ * @name      Replacements
+ * @package   Galette
+ * @author    Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2020-2021 The Galette Team
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @link      http://galette.eu
+ * @since     2020-12-20
+ */
+
+trait Socials
+{
+    protected $socials_input = [];
+
+    /**
+     * Check socials
+     *
+     * @param array $post User input
+     *
+     * @return void
+     */
+    protected function checkSocials(array $post)
+    {
+        $this->socials_input = [];
+        foreach ($post as $key => $value) {
+            if (str_starts_with($key, 'social_')) {
+                $this->socials_input[$key] = $value;
+            }
+        }
+    }
+
+    /**
+     * Store social networks/contacts
+     *
+     * @param int|null $id ID
+     *
+     * @return bool
+     */
+    protected function storeSocials(int $id = null): bool
+    {
+        $existings = Social::getListForMember($id);
+        foreach ($this->socials_input as $key => $value) {
+            if (
+                str_starts_with($key, 'social_new_type')
+                && !empty($value)
+                && isset($this->socials_input[str_replace('_type', '_value', $key)])
+                && !empty($this->socials_input[str_replace('_type', '_value', $key)])
+            ) {
+                //new social network
+                $new_index = (int)str_replace('social_new_type_', '', $key);
+                $social = new Social($this->zdb);
+                $social
+                    ->setType($value)
+                    ->setLinkedMember($id)
+                    ->setUrl($this->socials_input['social_new_value_' . $new_index])
+                    ->store();
+            } elseif (str_starts_with($key, 'social_') && !str_starts_with($key, 'social_new_')) {
+                //existing social network
+                $social_id = (int)str_replace('social_', '', $key);
+                $social = $existings[$social_id];
+                if ($value != $social->url) {
+                    $social
+                        ->setUrl($value)
+                        ->store();
+                }
+                unset($existings[$social_id]);
+            }
+        }
+
+        if (count($existings)) {
+            $social = new Social($this->zdb);
+            $social->remove(array_keys($existings));
+        }
+
+        return true;
+    }
+
+    /**
+     * Get core registered types
+     * @return array
+     */
+    protected function getCoreRegisteredTypes(): array
+    {
+        return $this->getRegisteredTypes(true);
+    }
+
+    /**
+     * Get member registered types
+     *
+     * @return array
+     */
+    public function getMemberRegisteredTypes(): array
+    {
+        return $this->getRegisteredTypes(false);
+    }
+
+    /**
+     * Get registered types
+     *
+     * @param bool $core True for core type, false for members ones
+     *
+     * @return array
+     */
+    protected function getRegisteredTypes(bool $core): array
+    {
+        $select = $this->zdb->select(Social::TABLE, 's');
+        $select->quantifier('DISTINCT')->columns(['type']);
+        if ($core === true) {
+            $select->where(Adherent::PK . ' IS NULL');
+        } else {
+            $select->where(Adherent::PK . ' IS NOT NULL');
+        }
+
+        $results = $this->zdb->execute($select);
+        $types = [];
+        foreach ($results as $result) {
+            $types[$result->type] = $result->type;
+        }
+
+        return $types;
+    }
+}
index 0e5c6b7bd9acdac4b6ec3ae9b8d6c51bfdfec1d9..4831da6bc9ade8c4ad75d3ca16f957fadc0e3d05 100644 (file)
@@ -84,7 +84,6 @@ class CsvIn extends Csv implements FileInterface
         'tel_adh',
         'gsm_adh',
         'email_adh',
-        'url_adh',
         'prof_adh',
         'pseudo_adh',
         'societe_adh',
index 580f6e688e3c8c66d2d706e6b6d13b8cb6046059..eabe4758176b1f7d98e8f793abe00e75b1b1683d 100644 (file)
@@ -7,7 +7,7 @@
  *
  * PHP version 5
  *
- * Copyright © 2014 The Galette Team
+ * Copyright © 2021 The Galette Team
  *
  * This file is part of Galette (http://galette.tuxfamily.org).
  *
@@ -28,7 +28,7 @@
  * @package   Galette
  *
  * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2014 The Galette Team
+ * @copyright 2021 The Galette Team
  * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
  * @link      http://galette.tuxfamily.org
  * @since     Available since 0.8.2dev - 2014-11-30
@@ -48,7 +48,7 @@ use Analog\Analog;
  * @package   Galette
  * @abstract  Class for expanding TCPDF.
  * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2014 The Galette Team
+ * @copyright 2021 The Galette Team
  * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
  * @link      http://galette.tuxfamily.org
  * @since     Available since 0.8.2dev - 2014-11-30
@@ -147,7 +147,7 @@ class PdfMembersCards extends Pdf
         $this->nbcol = self::getCols();
         // Number of rows
         $this->nbrow = self::getRows();
-        // Spacing betweeen cards
+        // Spacing between cards
         $this->hspacing = $this->preferences->pref_card_hspace;
         $this->vspacing = $this->preferences->pref_card_vspace;
 
@@ -211,18 +211,6 @@ class PdfMembersCards extends Pdf
                 case 0:
                     $email .= $member->email;
                     break;
-                case 1:
-                    $email .= $member->msn;
-                    break;
-                case 2:
-                    $email .= $member->jabber;
-                    break;
-                case 3:
-                    $email .= $member->website;
-                    break;
-                case 4:
-                    $email .= $member->icq;
-                    break;
                 case 5:
                     $email .= $member->zipcode . ' - ' . $member->town;
                     break;
index 36d0deb92d05d1a934cf7574c5c30507ff1cde93..0e68ef1ff0c330b71d4ee5b55a8361f419fe1252 100644 (file)
@@ -36,6 +36,7 @@
 
 namespace Galette\Repository;
 
+use Galette\Entity\Social;
 use Throwable;
 use Galette\DynamicFields\DynamicField;
 use Galette\Entity\DynamicFieldsHandle;
@@ -617,6 +618,11 @@ class Members
                         array('p' => PREFIX_DB . Status::TABLE),
                         'a.' . Status::PK . '=p.' . Status::PK,
                         array()
+                    )->join(
+                        array('so' => PREFIX_DB . Social::TABLE),
+                        'a.' . Adherent::PK . '=so.' . Adherent::PK,
+                        array(),
+                        $select::JOIN_LEFT
                     );
                     break;
                 case self::SHOW_EXPORT:
@@ -631,6 +637,11 @@ class Members
                     $select->join(
                         array('p' => PREFIX_DB . Status::TABLE),
                         'a.' . Status::PK . '=p.' . Status::PK
+                    )->join(
+                        array('so' => PREFIX_DB . Social::TABLE),
+                        'a.' . Adherent::PK . '=so.' . Adherent::PK,
+                        array(),
+                        $select::JOIN_LEFT
                     )->join(
                         array('gr' => PREFIX_DB . Group::GROUPSUSERS_TABLE),
                         'a.' . Adherent::PK . '=gr.' . Adherent::PK,
@@ -1056,13 +1067,7 @@ class Members
                             '(' .
                             'LOWER(email_adh) LIKE ' . $token
                             . ' OR ' .
-                            'LOWER(url_adh) LIKE ' . $token
-                            . ' OR ' .
-                            'LOWER(msn_adh) LIKE ' . $token
-                            . ' OR ' .
-                            'LOWER(icq_adh) LIKE ' . $token
-                            . ' OR ' .
-                            'LOWER(jabber_adh) LIKE ' . $token
+                            'LOWER(so.url) LIKE ' . $token
                             . ')'
                         );
                         break;
@@ -1437,6 +1442,15 @@ class Members
                     $fs['field'] = 'val';
                 }
 
+                //handle socials networks
+                if (strpos($fs['field'], 'socials_') === 0) {
+                    //social networks
+                    $type = str_replace('socials_', '', $fs['field']);
+                    $prefix = 'so.';
+                    $fs['field'] = 'url';
+                    $select->where(['so.type' => $type]);
+                }
+
                 if ($dyn_field && $dyn_field instanceof \Galette\DynamicFields\Boolean) {
                     if ($fs['search'] != 0) {
                         $qry .= $prefix . $fs['field'] . $qop . ' ' .
index 776094ec68f2380126b6bcc057bf811798482555..4c8767959b4654d28296c4963592beb42f6e6648 100644 (file)
         {/if}
                             <option value="dyn_{$field->getId()}"{if $fs.field eq $rid} selected="selected"{/if}>{$field->getName()}</option>
     {/foreach}
+    {foreach from=$adh_socials item=$label key=$type}
+        {assign var=rid value="socials_$type"}
+        {if $fs.field eq $rid}
+            {assign var=cur_field value=$type}
+        {/if}
+        <option value="socials_{$type}"{if $fs.field eq $rid} selected="selected"{/if}>{$label}</option>
+    {/foreach}
+
                         </select>
     {* may not be defined *}
     {if !isset($cur_field)}{assign var=cur_field value=null}{/if}
diff --git a/galette/templates/default/display_socials.tpl b/galette/templates/default/display_socials.tpl
new file mode 100644 (file)
index 0000000..2a233ef
--- /dev/null
@@ -0,0 +1,11 @@
+{if $socials|@count > 0}
+        <table class="details" id="social">
+            <caption class="ui-state-active ui-corner-top">{_T string="Social networks"}</caption>
+    {foreach item=social from=$socials}
+            <tr>
+                <th>{$social->getSystemType($social->type)}</th>
+                <td>{$social->displayUrl()}</td>
+            </tr>
+    {/foreach}
+        </table>
+{/if}
diff --git a/galette/templates/default/edit_socials.tpl b/galette/templates/default/edit_socials.tpl
new file mode 100644 (file)
index 0000000..58d31da
--- /dev/null
@@ -0,0 +1,83 @@
+<fieldset class="{if isset($social_fieldset_class)}{$social_fieldset_class}{else}cssform{/if}" id="social">
+    <legend{if isset($social_fieldset_legend_class)} class="{$social_fieldset_legend_class}"{/if}>{_T string="Social networks"}</legend>
+    <div>
+    {foreach item=social from=$socials}
+        <p>
+            <label for="social_{$social->id}" class="bline">{$social->getSystemType($social->type)}</label>
+            <span>
+                <input type="text" name="social_{$social->id}" id="social_{$social->id}" value="{$social->url}" class="large"/>
+                <a href="#" class="fright tooltip delete delsocial">
+                    <i class="fas fa-trash-alt"></i>
+                    <span class="sr-only">{_T string="Remove %type" pattern="/%type/" replace=$social->getSystemType($social->type)}</span>
+                </a>
+            </span>
+        </p>
+    {/foreach}
+    <p>
+        <span class="bline">{_T string="Add new social network"}</span>
+        <span>
+            <select name="social_new_type_1" id="social_new_type_1" class="nochosen socials_selector">
+                <option value="">{_T string="Choose or enter your own..."}</option>
+    {foreach item=social_type from=$osocials->getSystemTypes(false)}
+                <option value="{$social_type}">{$osocials->getSystemType($social_type)}</option>
+    {/foreach}
+            </select>
+            <input type="text" name="social_new_value_1" id="social_new_value_1" value="" size="50"/>
+            <a href="#" class="fright tooltip action addsocial">
+                <i class="fas fa-plus-square"></i>
+                <span class="sr-only">{_T string="Add"}</span>
+            </a>
+        </span>
+        <script type="text/javascript">
+            var _selectize = function(selector) {
+                if ( !selector ) {
+                    selector = '.socials_selector';
+                }
+
+                $(selector).selectize({
+                    maxItems: 1,
+                    create: true,
+                    createOnBlur: true
+                });
+            }
+
+            $('.addsocial').click(function(e){
+                e.preventDefault();
+                $('.socials_selector').each(function(){ // do this for every select with the 'combobox' class
+                    var _this = $(this);
+                    if (_this[0].selectize) { // requires [0] to select the proper object
+                        var value = $(this).val(); // store the current value of the select/input
+                        _this[0].selectize.destroy(); // destroys selectize()
+                        _this.val(value);  // set back the value of the select/input
+                    }
+                });
+
+                var _newindex = $(this).parents('fieldset').find('p:last select').attr('id').replace('social_new_type_', '');
+                ++_newindex;
+                $(this).parents('p')
+                    .clone() // copy
+                    .insertAfter('#social p:last') // where
+                    .find('select').attr('id', 'social_new_type_' + _newindex).attr('name', 'social_new_type_' + _newindex)
+                    .parent().find('input').attr('id', 'social_new_value_' + _newindex).attr('name', 'social_new_value_' + _newindex)
+                    .parent().find('.addsocial').remove()
+                ;
+
+                _selectize();
+            });
+
+            var _rmFilter = function(elt) {
+                if ( typeof elt == 'undefined') {
+                    elt = $('#social p');
+                }
+                elt.find('.delsocial').click(function(e){
+                    e.preventDefault();
+                    var _this = $(this);
+                    _this.parents('p').remove();
+                });
+            }
+            _rmFilter();
+            _selectize();
+        </script>
+    </p>
+    </div>
+</fieldset>
\ No newline at end of file
index 15038d044f178d9be4d60d81e1408590d9d841a3..3d70a8dd8ddeea53563e794f4faf938699316af6 100644 (file)
                         {if $entry->field_id eq 'gpgid'}
                             {assign var="size" value="8"}
                         {/if}
-                        {if $entry->field_id eq 'email_adh'
-                            or $entry->field_id eq 'msn_adh'
-                            or $entry->field_id eq 'jabber_adh'
-                            or $entry->field_id eq 'url_adh'}
+                        {if $entry->field_id eq 'email_adh'}
                             {assign var="size" value="30"}
                         {/if}
                         {if $entry->field_id eq 'fingerprint'}
@@ -78,7 +75,7 @@
                         {/if}
                         {if $entry->field_id eq 'bool_display_info'}
                             {assign var="title" value={_T string="Do member want to appear publically?"}}
-                            {assign var="tip" value={_T string="If you check this box (and if you are up to date with your contributions), your full name, website address ad other information will be publically visible on the members list.<br/>If you've uploaded a photo, it will be displayed on the trombinoscope page.<br/>Note that administrators can disabled public pages, this setting will have no effect in that case."}}
+                            {assign var="tip" value={_T string="If you check this box (and if you are up to date with your contributions), your full name and other information will be publically visible on the members list.<br/>If you've uploaded a photo, it will be displayed on the trombinoscope page.<br/>Note that administrators can disabled public pages, this setting will have no effect in that case."}}
                             {assign var="checked" value=$member->appearsInMembersList()}
                         {/if}
                         {if $entry->field_id eq 'login_adh'}
index d6ec1b61d7bf8d91bbe73384f4af3f9c35c905b9..453d4de7b09b2965e37e4e2e5f0a2f7bd2874736 100644 (file)
@@ -199,14 +199,6 @@ We have to use a template file, so Smarty will do its work (like replacing varia
             {else}
                         <img src="{base_url}/{$template_subdir}images/icon-empty.png" alt="" width="16" height="16"/>
             {/if}
-            {if $member->website != ''}
-                        <a href="{$member->website}" class="tooltip">
-                            <img src="{base_url}/{$template_subdir}images/icon-website.png" alt="" width="16" height="16"/>
-                            <span class="sr-only">{_T string="Website"}<span>
-                        </a>
-            {else}
-                        <img src="{base_url}/{$template_subdir}images/icon-empty.png" alt="" width="16" height="16"/>
-            {/if}
             {if $member->isAdmin()}
                         <span class="tooltip">
                             <img src="{base_url}/{$template_subdir}images/icon-star.png" alt="" width="16" height="16"/>
@@ -278,12 +270,10 @@ We have to use a template file, so Smarty will do its work (like replacing varia
                 but for notw, that works as excpected.
             *}
             {if not empty($value)}
-                {if $column->field_id eq 'email_adh' or $column->field_id eq 'msn_adh'}
+                {if $column->field_id eq 'email_adh'}
                                 <a href="mailto:{$value}">{$value}</a>
                 {elseif $column->field_id eq 'tel_adh' or $column->field_id eq 'gsm_adh'}
                                 <a href="tel:{$value}">{$value}</a>
-                {elseif $column->field_id eq 'url_adh'}
-                                <a href="{$value}">{$value}</a>
                 {elseif $column->field_id eq 'parent_id'}
                                 <a href="{path_for name="member" data=["id" => $member->parent]}">{memberName id=$member->parent}</a>
                 {elseif $column->field_id eq 'ddn_adh'}
@@ -420,8 +410,8 @@ We have to use a template file, so Smarty will do its work (like replacing varia
                     <tr>
                         <th><img src="{base_url}/{$template_subdir}images/icon-mail.png" alt="{_T string="Mail"}" width="16" height="16"/></th>
                         <td class="back">{_T string="Send an email"}</td>
-                        <th><img src="{base_url}/{$template_subdir}images/icon-website.png" alt="{_T string="Website"}" width="16" height="16"/></th>
-                        <td class="back">{_T string="Visit website"}</td>
+                        <th><img src="{base_url}/{$template_subdir}images/icon-company.png" alt="{_T string="Is a company"}" width="16" height="16"/></th>
+                        <td class="back">{_T string="Is a company"}</td>
                     </tr>
 
                     <tr>
@@ -430,10 +420,6 @@ We have to use a template file, so Smarty will do its work (like replacing varia
                         <th><img src="{base_url}/{$template_subdir}images/icon-female.png" alt="{_T string="Is a woman"}" width="16" height="16"/></th>
                         <td class="back">{_T string="Is a woman"}</td>
                     </tr>
-                    <tr>
-                        <th><img src="{base_url}/{$template_subdir}images/icon-company.png" alt="{_T string="Is a company"}" width="16" height="16"/></th>
-                        <td class="back">{_T string="Is a company"}</td>
-                    </tr>
                     <tr>
                         <th><img src="{base_url}/{$template_subdir}images/icon-star.png" alt="{_T string="Admin"}" width="16" height="16"/></th>
                         <td class="back">{_T string="Admin"}</td>
index 14a2692b4d29444728e8592feaef016ad19a19d6..ed5e07883564f817f251b8c5bdf99c61bbfe87fd 100644 (file)
@@ -56,6 +56,8 @@
     {* Dynamic entries *}
     {include file="edit_dynamic_fields.tpl" object=$member}
 
+    {include file="edit_socials.tpl" socials=$member->socials social_fieldset_class="galette_form" social_fieldset_legend_class="ui-state-active ui-corner-top"}
+
                     <p>
     {if !$member->id && !$self_adh}
         {if ($login->isAdmin() or $login->isStaff())}
index b91e273bd1d34ed0d7a9d31ce438375b088fab38..37c30906c238ca55b50bf05ca02e5eaad291c79d 100644 (file)
 
             </fieldset>
 
-            <fieldset class="cssform" id="social">
-                <legend>{_T string="Social networks"}</legend>
-                <p>
-                    <label for="pref_googleplus" class="bline">{_T string="Google+"}</label>
-                    <input type="text" name="pref_googleplus" id="pref_googleplus" value="{$pref.pref_googleplus}" class="large"/>
-                </p>
-                <p>
-                    <label for="pref_facebook" class="bline">{_T string="Facebook"}</label>
-                    <input type="text" name="pref_facebook" id="pref_facebook" value="{$pref.pref_facebook}" class="large"/>
-                </p>
-                <p>
-                    <label for="pref_twitter" class="bline">{_T string="Twitter"}</label>
-                    <input type="text" name="pref_twitter" id="pref_twitter" value="{$pref.pref_twitter}" class="large"/>
-                </p>
-                <p>
-                    <label for="pref_linkedin" class="bline">{_T string="LinkedIn"}</label>
-                    <input type="text" name="pref_linkedin" id="pref_linkedin" value="{$pref.pref_linkedin}" class="large"/>
-                </p>
-                <p>
-                    <label for="pref_viadeo" class="bline">{_T string="Viadeo"}</label>
-                    <input type="text" name="pref_viadeo" id="pref_viadeo" value="{$pref.pref_viadeo}" class="large"/>
-                </p>
-            </fieldset>
+            {assign var="socials" value=$preferences->socials}
+            {include file="edit_socials.tpl"}
 
             <fieldset class="cssform" id="parameters">
                 <legend>{_T string="Galette's parameters"}</legend>
                         <input type="password" name="pref_mail_smtp_password" id="pref_mail_smtp_password" value="{$pref.pref_mail_smtp_password}" autocomplete="off" maxlength="100" size="30"{if isset($required.pref_mail_smtp_password) and $required.pref_mail_smtp_password eq 1} required="required"{/if}/>
                     </p>
                 </div>
-                <p>
+                <p id="mail_sign">
                     <label for="pref_mail_sign" class="bline tooltip vtop">{_T string="Mail signature"}</label>
                     <span class="tip">{_T string="The text that will be automatically set as signature for all outgoing emails.<br/>Variables are quoted with braces, are upper case, and will be replaced automatically.<br/>Refer to the doc to know what variables ara available. "}</span>
                     <textarea name="pref_mail_sign" id="pref_mail_sign">{$pref.pref_mail_sign}</textarea>
                     <label for="pref_card_address" class="bline">{_T string="Address type:"}</label>
                     <select name="pref_card_address" id="pref_card_address">
                         <option value="0" {if $pref.pref_card_address eq 0}selected="selected"{/if}>{_T string="Email"}</option>
-                        <option value="1" {if $pref.pref_card_address eq 1}selected="selected"{/if}>{_T string="MSN"}</option>
-                        <option value="2" {if $pref.pref_card_address eq 2}selected="selected"{/if}>{_T string="Jabber"}</option>
-                        <option value="3" {if $pref.pref_card_address eq 3}selected="selected"{/if}>{_T string="Web Site"}</option>
-                        <option value="4" {if $pref.pref_card_address eq 4}selected="selected"{/if}>{_T string="ICQ"}</option>
                         <option value="5" {if $pref.pref_card_address eq 5}selected="selected"{/if}>{_T string="Zip - Town"}</option>
                         <option value="6" {if $pref.pref_card_address eq 6}selected="selected"{/if}>{_T string="Nickname"}</option>
                         <option value="7" {if $pref.pref_card_address eq 7}selected="selected"{/if}>{_T string="Profession"}</option>
                         <em>* {_T string="None"}</em> {_T string="for no strength enforcement"}<br/>
                         <em>* {_T string="Weak"}</em> {_T string="require at least one matched rule"}<br/>
                         <em>* {_T string="Medium"}</em> {_T string="require at least two matched rules"}<br/>
-                        <em>* {_T string="Strong"}</em> {_T string="require at least three matched rules (recommended for most usages)"}</br/>
+                        <em>* {_T string="Strong"}</em> {_T string="require at least three matched rules (recommended for most usages)"}<br/>
                         <em>* {_T string="Very Strong"}</em> {_T string="requires all rules."}<br/><br/>
                         {_T string="Rules include lower case characters, upper case characters, numbers, and special characters."}<br/><br/>
                         {_T string="Note that with any enforcement level, user cannot use his personal information (name, login, ...) as password."}
         </form>
 
         {include file="telemetry.tpl" part="dialog"}
+        {include file="replacements_legend.tpl" legends=$preferences->getLegend() cur_ref='prefs'}
 {/block}
 
 {block name="javascripts"}
                     });
                 });
 
+                _addLegenButton('#mail_sign');
+                _handleLegend();
+
                 {include file="js_pwdcheck.tpl" selector="#pref_admin_pass"}
                 {include file="js_pwdcheck.tpl" selector="#test_password_strength" extra_data="pref_password_length: \$('#pref_password_length').val(),pref_password_blacklist: \$('#pref_password_blacklist').is(':checked'),pref_password_strength: \$('#pref_password_strength').val(),"}
 
index fdc8463ee30d126a8a70742628647e92d9e5bc50..8d4d8112d870ee0b026c549310b39f3209c310c8 100644 (file)
@@ -183,12 +183,10 @@ We have to use a template file, so Smarty will do its work (like replacing varia
                     <i class="fas fa-venus fa-fw"></i>
             {/if}
         {/if}
-        {if $element->field_id eq 'email_adh' or $element->field_id eq 'msn_adh'}
+        {if $element->field_id eq 'email_adh'}
                         <a href="mailto:{$value}">{$value}</a>
         {elseif $element->field_id eq 'tel_adh' or $element->field_id eq 'gsm_adh'}
                         <a href="tel:{$value}">{$value}</a>
-        {elseif $element->field_id eq 'url_adh'}
-                        <a href="{$value}">{$value}</a>
         {elseif $element->field_id eq 'ddn_adh'}
                         {$value} {$member->getAge()}
         {else}
@@ -233,6 +231,8 @@ We have to use a template file, so Smarty will do its work (like replacing varia
 {/foreach}
 
 {include file="display_dynamic_fields.tpl" object=$member}
+{include file="display_socials.tpl" socials=$member->socials}
+
         <a href="#" id="back2top">{_T string="Back to top"}</a>
     </div>
 {/block}
index 222327672013a73fcddcfa4cec9cd835e36decbd..4903b92ef373e2dd3d144adfd0786dae3abbe6c9 100644 (file)
@@ -834,6 +834,10 @@ legend .tab-button {
     font-size:1.1em;
 }
 
+p#mail_sign {
+    position: relative;
+}
+
 /* =/ Main Galette styles */
 
 /* == Groups stuff */
index 6fd7d4164cead5974330c02f917220ad1e3b6675..a8d8053d293707a5993f78999023bd66e75b2054 100644 (file)
@@ -7,7 +7,7 @@
  *
  * PHP version 5
  *
- * Copyright © 2013-2014 The Galette Team
+ * Copyright © 2013-2021 The Galette Team
  *
  * This file is part of Galette (http://galette.tuxfamily.org).
  *
@@ -28,7 +28,7 @@
  * @package   GaletteTests
  *
  * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2013-2014 The Galette Team
+ * @copyright 2013-2021 The Galette Team
  * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
  * @version   SVN: $Id$
  * @link      http://galette.tuxfamily.org
@@ -46,7 +46,7 @@ use atoum;
  * @name      Db
  * @package   GaletteTests
  * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2013-2014 The Galette Team
+ * @copyright 2013-2021 The Galette Team
  * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
  * @link      http://galette.tuxfamily.org
  * @since     2013-02-05
@@ -542,6 +542,7 @@ class Db extends atoum
             'galette_types_cotisation',
             'galette_paymenttypes',
             'galette_database',
+            'galette_socials',
             'galette_statuts',
             'galette_texts',
             'galette_logs',
index b3efd802ec2bd200add01961b97ed3e65809e2b6..bd28345b9ebc5653eb783721be428c76c57eda89 100644 (file)
@@ -141,7 +141,8 @@ class Install extends atoum
             '0.93'  => 'upgrade-to-0.93-pgsql.sql',
             '0.931' => 'upgrade-to-0.931-pgsql.sql',
             '0.94'  => 'upgrade-to-0.94-pgsql.sql',
-            '0.95'  => 'upgrade-to-0.95-pgsql.sql'
+            '0.95'  => 'upgrade-to-0.95-pgsql.sql',
+            '0.96'  => 'upgrade-to-0.96-pgsql.sql'
         );
 
         $this->array($update_scripts)
index ae4bd1c990a1a155949d41f9aaf49cad3312dd45..7eef42eda5123987421ca23debafc7f35de9224c 100644 (file)
@@ -285,7 +285,6 @@ class Login extends GaletteTestCase
                 'pseudo_adh' => 'elisabeth50',
                 'pays_adh' => 'Géorgie',
                 'tel_adh' => '05 05 20 88 04',
-                'url_adh' => 'http://www.gay.com/tempora-nemo-quidem-laudantium-dolores',
                 'activite_adh' => true,
                 'id_statut' => 6,
                 'date_crea_adh' => '2019-09-02',
index 9e60112dd749a4aedcb6d6de6b54100ade328c09..bad9e28def36f2c424827e1b6a73194d40b3ee77 100644 (file)
@@ -55,6 +55,8 @@ class Preferences extends atoum
 {
     private $preferences = null;
     private $zdb;
+    private $login;
+    private $mocked_router;
 
     /**
      * Set up tests
@@ -65,10 +67,25 @@ class Preferences extends atoum
      */
     public function beforeTestMethod($method)
     {
-        $this->zdb = new \Galette\Core\Db();
-        $this->preferences = new \Galette\Core\Preferences(
-            $this->zdb
-        );
+        $this->mocked_router = new \mock\Slim\Router();
+        $this->calling($this->mocked_router)->pathFor = function ($name, $params) {
+            return $name;
+        };
+
+        $app =  new \Galette\Core\SlimApp();
+        $plugins = new \Galette\Core\Plugins();
+        require GALETTE_BASE_PATH . '/includes/dependencies.php';
+        $container = $app->getContainer();
+        $_SERVER['HTTP_HOST'] = '';
+
+        $this->zdb = $container->get('zdb');
+        $this->login = $container->get('login');
+        $this->preferences = $container->get('preferences');
+        $container->set('router', $this->mocked_router);
+        $container->set(Slim\Router::class, $this->mocked_router);
+
+        global $router;
+        $router = $this->mocked_router;
     }
 
     /**
@@ -83,6 +100,9 @@ class Preferences extends atoum
         if (TYPE_DB === 'mysql') {
             $this->array($this->zdb->getWarnings())->isIdenticalTo([]);
         }
+
+        $delete = $this->zdb->delete(\Galette\Entity\Social::TABLE);
+        $this->zdb->execute($delete);
     }
 
     /**
@@ -200,7 +220,7 @@ class Preferences extends atoum
         $delete = $this->zdb->delete(\Galette\Core\Preferences::TABLE);
         $delete->where(
             array(
-                \Galette\Core\Preferences::PK => 'pref_facebook'
+                \Galette\Core\Preferences::PK => 'pref_footer'
             )
         );
         $this->zdb->execute($delete);
@@ -208,24 +228,24 @@ class Preferences extends atoum
         $delete = $this->zdb->delete(\Galette\Core\Preferences::TABLE);
         $delete->where(
             array(
-                \Galette\Core\Preferences::PK => 'pref_viadeo'
+                \Galette\Core\Preferences::PK => 'pref_new_contrib_script'
             )
         );
         $this->zdb->execute($delete);
 
         $this->preferences->load();
-        $fb = $this->preferences->pref_facebook;
-        $viadeo = $this->preferences->pref_viadeo;
+        $footer = $this->preferences->pref_footer;
+        $new_contrib_script = $this->preferences->pref_new_contrib_script;
 
-        $this->boolean($fb)->isFalse();
-        $this->boolean($viadeo)->isFalse();
+        $this->boolean($footer)->isFalse();
+        $this->boolean($new_contrib_script)->isFalse();
 
         $prefs = new \Galette\Core\Preferences($this->zdb);
-        $fb = $prefs->pref_facebook;
-        $viadeo = $prefs->pref_viadeo;
+        $footer = $prefs->pref_footer;
+        $new_contrib_script = $prefs->pref_new_contrib_script;
 
-        $this->variable($fb)->isIdenticalTo('');
-        $this->variable($viadeo)->isIdenticalTo('');
+        $this->variable($footer)->isIdenticalTo('');
+        $this->variable($new_contrib_script)->isIdenticalTo('');
     }
 
     /**
@@ -409,4 +429,180 @@ class Preferences extends atoum
         $this->preferences->$prop = $color;
         $this->string($this->preferences->$prop)->isIdenticalTo($expected);
     }
+
+    /**
+     * Test social networks
+     *
+     * @return void
+     */
+    public function testSocials()
+    {
+        $preferences = [];
+        foreach ($this->preferences->getDefaults() as $key => $value) {
+            $preferences[$key] = $value;
+        }
+
+        $preferences = array_merge($preferences, [
+            'pref_nom' => 'Galette',
+            'pref_ville' => 'Avignon',
+            'pref_cp' => '84000',
+            'pref_adresse' => 'Palais des Papes',
+            'pref_adresse2' => 'Au milieu',
+            'pref_pays' => 'France'
+        ]);
+
+        //will create 2 social networks in table
+        $post = [
+            'notasocial' => 'notasocial', //must be ignored
+            'social_new_type_1' => \Galette\Entity\Social::MASTODON,
+            'social_new_value_1' => 'Galette mastodon URL',
+            'social_new_type_2' => \Galette\Entity\Social::JABBER,
+            'social_new_value_2' => 'Galette jabber ID',
+            'social_new_type_3' => \Galette\Entity\Social::FACEBOOK,
+            'social_new_value_3' => '', //empty value, no entry
+            'social_new_type_4' => \Galette\Entity\Social::BLOG, //no value, no entry
+        ];
+
+        $post = array_merge($preferences, $post);
+
+        $this->boolean($this->preferences->check($post, $this->login))->isTrue(print_r($this->preferences->getErrors(), true));
+        $this->boolean($this->preferences->store())->isTrue();
+
+        $socials = \Galette\Entity\Social::getListForMember(null);
+        $this->array($socials)->hasSize(2);
+
+        $this->array(\Galette\Entity\Social::getListForMember(null, \Galette\Entity\Social::MASTODON))->hasSize(1);
+        $this->array(\Galette\Entity\Social::getListForMember(null, \Galette\Entity\Social::JABBER))->hasSize(1);
+        $this->array(\Galette\Entity\Social::getListForMember(null, \Galette\Entity\Social::FACEBOOK))->hasSize(0);
+        $this->array(\Galette\Entity\Social::getListForMember(null, \Galette\Entity\Social::BLOG))->hasSize(0);
+
+        //create one new social network
+        $post = [
+            'social_new_type_1' => \Galette\Entity\Social::FACEBOOK,
+            'social_new_value_1' => 'Galette does not have facebook',
+        ];
+
+        //existing social networks, change jabber ID
+        foreach ($socials as $social) {
+            $post['social_' . $social->id] = $social->url . ($social->type == \Galette\Entity\Social::JABBER ? ' - modified' : '');
+        }
+
+        $post = array_merge($preferences, $post);
+
+        $this->boolean($this->preferences->check($post, $this->login))->isTrue(print_r($this->preferences->getErrors(), true));
+        $this->boolean($this->preferences->store())->isTrue();
+
+        $socials = \Galette\Entity\Social::getListForMember(null);
+        $this->array($socials)->hasSize(3);
+
+        $search = \Galette\Entity\Social::getListForMember(null, \Galette\Entity\Social::MASTODON);
+        $this->array($search)->hasSize(1);
+        $masto = array_pop($search);
+        $this->string($masto->url)->isIdenticalTo('Galette mastodon URL');
+
+        $search = \Galette\Entity\Social::getListForMember(null, \Galette\Entity\Social::JABBER);
+        $this->array($search)->hasSize(1);
+        $jabber = array_pop($search);
+        $this->string($jabber->url)->isIdenticalTo('Galette jabber ID - modified');
+
+        $search = \Galette\Entity\Social::getListForMember(null, \Galette\Entity\Social::FACEBOOK);
+        $this->array($search)->hasSize(1);
+        $facebook = array_pop($search);
+        $this->string($facebook->url)->isIdenticalTo('Galette does not have facebook');
+
+        $post = [];
+
+        //existing social networks, drop mastodon
+        foreach ($socials as $social) {
+            if ($social->type != \Galette\Entity\Social::MASTODON) {
+                $post['social_' . $social->id] = $social->url;
+            }
+        }
+
+        $post = array_merge($preferences, $post);
+        $this->boolean($this->preferences->check($post, $this->login))->isTrue(print_r($this->preferences->getErrors(), true));
+        $this->boolean($this->preferences->store())->isTrue();
+
+        $socials = \Galette\Entity\Social::getListForMember(null);
+        $this->array($socials)->hasSize(2);
+
+        $this->array(\Galette\Entity\Social::getListForMember(null, \Galette\Entity\Social::MASTODON))->hasSize(0);
+        $this->array(\Galette\Entity\Social::getListForMember(null, \Galette\Entity\Social::JABBER))->hasSize(1);
+        $this->array(\Galette\Entity\Social::getListForMember(null, \Galette\Entity\Social::FACEBOOK))->hasSize(1);
+    }
+
+    /**
+     * Test email signature
+     *
+     * @return void
+     */
+    public function testGetMailSignature()
+    {
+        $this->string($this->preferences->getMailSignature())->isIdenticalTo("\r\n-- \r\nGalette\r\n\r\n");
+
+        $this->preferences->pref_website = 'https://galette.eu';
+        $this->string($this->preferences->getMailSignature())->isIdenticalTo("\r\n-- \r\nGalette\r\n\r\nhttps://galette.eu");
+
+        //with legacy values
+        $this->preferences->pref_mailsign = "NAME}\r\n\r\n{WEBSITE}\r\n{GOOGLEPLUS}\r\n{FACEBOOK}\r\n{TWITTER}\r\n{LINKEDIN}\r\n{VIADEO}";
+        $this->string($this->preferences->getMailSignature())->isIdenticalTo("\r\n-- \r\nGalette\r\n\r\nhttps://galette.eu");
+
+        $social = new \Galette\Entity\Social($this->zdb);
+        $this->boolean(
+            $social
+                ->setType(\Galette\Entity\Social::MASTODON)
+                ->setUrl('https://framapiaf.org/@galette')
+                ->setLinkedMember(null)
+                ->store()
+        )->isTrue();
+        $this->array(\Galette\Entity\Social::getListForMember(null, \Galette\Entity\Social::MASTODON))->hasSize(1);
+
+        $this->preferences->pref_mail_sign = "{ASSO_NAME}\r\n\r\n{ASSO_WEBSITE} - {ASSO_SOCIAL_MASTODON}";
+        $this->string($this->preferences->getMailSignature())->isIdenticalTo("\r\n-- \r\nGalette\r\n\r\nhttps://galette.eu - https://framapiaf.org/@galette");
+
+        $social = new \Galette\Entity\Social($this->zdb);
+        $this->boolean(
+            $social
+                ->setType(\Galette\Entity\Social::MASTODON)
+                ->setUrl('Galette mastodon URL - the return')
+                ->setLinkedMember(null)
+                ->store()
+        )->isTrue();
+        $this->array(\Galette\Entity\Social::getListForMember(null, \Galette\Entity\Social::MASTODON))->hasSize(2);
+        $this->string($this->preferences->getMailSignature())->isIdenticalTo("\r\n-- \r\nGalette\r\n\r\nhttps://galette.eu - https://framapiaf.org/@galette, Galette mastodon URL - the return");
+    }
+
+    /**
+     * Test getLegend
+     *
+     * @return void
+     */
+    public function testGetLegend()
+    {
+        $legend = $this->preferences->getLegend();
+        $this->array($legend)->hasSize(2);
+        $this->array($legend['main']['patterns'])->hasSize(8);
+        $this->array($legend['socials']['patterns'])->hasSize(9);
+        $this->array($legend['socials']['patterns']['asso_social_mastodon'])->isIdenticalTo([
+            'title' => __('Mastodon'),
+            'pattern' => '/{ASSO_SOCIAL_MASTODON}/'
+        ]);
+
+        $social = new \Galette\Entity\Social($this->zdb);
+        $this->boolean(
+            $social
+                ->setType('mynewtype')
+                ->setUrl('Galette specific social network URL')
+                ->setLinkedMember(null)
+                ->store()
+        )->isTrue();
+
+        $legend = $this->preferences->getLegend();
+        $this->array($legend)->hasSize(2);
+        $this->array($legend['socials']['patterns'])->hasSIze(10)->hasKey('asso_social_mynewtype');
+        $this->array($legend['socials']['patterns']['asso_social_mynewtype'])->isIdenticalTo([
+            'title' => 'mynewtype',
+            'pattern' => '/{ASSO_SOCIAL_MYNEWTYPE}/'
+        ]);
+    }
 }
index 54ac7b621fbd82309683bf01abc627b573d7a526..1efb1897d7eec73384f92c466d64f33112901663 100644 (file)
@@ -96,7 +96,8 @@ class Adherent extends GaletteTestCase
             'dues'      => true,
             'parent'    => false,
             'children'  => false,
-            'dynamics'  => false
+            'dynamics'  => false,
+            'socials'   => false
         ];
 
         $this->adh = new \Galette\Entity\Adherent($this->zdb);
@@ -155,7 +156,8 @@ class Adherent extends GaletteTestCase
             'dues'      => false,
             'parent'    => false,
             'children'  => false,
-            'dynamics'  => false
+            'dynamics'  => false,
+            'socials'   => false
         ];
         $this->array($adh->deps)->isIdenticalTo($expected);
 
@@ -165,7 +167,8 @@ class Adherent extends GaletteTestCase
             'dues'      => true,
             'parent'    => false,
             'children'  => true,
-            'dynamics'  => true
+            'dynamics'  => true,
+            'socials'   => false
         ];
         $adh
             ->enableDep('dues')
@@ -179,7 +182,8 @@ class Adherent extends GaletteTestCase
             'dues'      => true,
             'parent'    => false,
             'children'  => false,
-            'dynamics'  => true
+            'dynamics'  => true,
+            'socials'   => false
         ];
         $adh->disableDep('children');
         $this->array($adh->deps)->isIdenticalTo($expected);
@@ -193,7 +197,8 @@ class Adherent extends GaletteTestCase
             'dues'      => true,
             'parent'    => true,
             'children'  => true,
-            'dynamics'  => true
+            'dynamics'  => true,
+            'socials'   => true
         ];
         $adh->enableAllDeps('children');
         $this->array($adh->deps)->isIdenticalTo($expected);
@@ -228,7 +233,8 @@ class Adherent extends GaletteTestCase
             'dues'      => false,
             'parent'    => false,
             'children'  => false,
-            'dynamics'  => false
+            'dynamics'  => false,
+            'socials'   => false
         ];
         $adh = new \Galette\Entity\Adherent(
             $this->zdb,
@@ -335,20 +341,6 @@ class Adherent extends GaletteTestCase
         $check = $adh->check($data, [], []);
         $this->array($check)->isIdenticalTo($expected);
 
-        $data = [
-            'email_adh' => '',
-            'url_adh'   => 'mywebsite'
-        ];
-        $expected = ['- Non-valid Website address! Maybe you\'ve skipped the http://?'];
-        $check = $adh->check($data, [], []);
-        $this->array($check)->isIdenticalTo($expected);
-
-        $data = ['url_adh' => 'http://'];
-        $expected = ['- Non-valid Website address! Maybe you\'ve skipped the http://?'];
-        $check = $adh->check($data, [], []);
-        $this->boolean($check)->isTrue($expected);
-        $this->variable($adh->_website)->isIdenticalTo('');
-
         $data = ['login_adh' => 'a'];
         $expected = ['- The username must be composed of at least 2 characters!'];
         $check = $adh->check($data, [], []);
index df4916cf235178ecccf69c0203077ed37fb879f9..6658476bc248307dcfb9bde3885b5d6687b70a71 100644 (file)
@@ -7,7 +7,7 @@
  *
  * PHP version 5
  *
- * Copyright © 2013-2014 The Galette Team
+ * Copyright © 2016-2021 The Galette Team
  *
  * This file is part of Galette (http://galette.tuxfamily.org).
  *
@@ -28,7 +28,7 @@
  * @package   GaletteTests
  *
  * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2016 The Galette Team
+ * @copyright 2016-2021 The Galette Team
  * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
  * @version   SVN: $Id$
  * @link      http://galette.tuxfamily.org
@@ -46,7 +46,7 @@ use atoum;
  * @name      FieldsConfig
  * @package   GaletteTests
  * @author    Johan Cwiklinski <johan@x-tnd.be>
- * @copyright 2016 The Galette Team
+ * @copyright 2016-2021 The Galette Team
  * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
  * @link      http://galette.tuxfamily.org
  * @since     2016-09-24
@@ -186,7 +186,7 @@ class FieldsConfig extends atoum
         $this->array($categorized[\Galette\Entity\FieldsCategories::ADH_CATEGORY_GALETTE])
             ->hasSize(11);
         $this->array($categorized[\Galette\Entity\FieldsCategories::ADH_CATEGORY_CONTACT])
-            ->hasSize(15);
+            ->hasSize(11);
     }
 
     /**
@@ -255,12 +255,12 @@ class FieldsConfig extends atoum
         $town['required'] = false;
         $town['visible'] = \Galette\Entity\FieldsConfig::NOBODY;
 
-        //jabber
-        $jabber = $fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_CONTACT][10];
-        $jabber['position'] = count($fields[1]);
-        unset($fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_CONTACT][10]);
-        $jabber['category'] = \Galette\Entity\FieldsCategories::ADH_CATEGORY_IDENTITY;
-        $fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_IDENTITY][] = $jabber;
+        //gsm
+        $gsm = $fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_CONTACT][6];
+        $gsm['position'] = count($fields[1]);
+        unset($fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_CONTACT][6]);
+        $gsm['category'] = \Galette\Entity\FieldsCategories::ADH_CATEGORY_IDENTITY;
+        $fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_IDENTITY][] = $gsm;
 
         $this->boolean($fields_config->setFields($fields))->isTrue();
 
@@ -271,8 +271,8 @@ class FieldsConfig extends atoum
         $this->boolean($town['required'])->isFalse();
         $this->integer($town['visible'])->isIdenticalTo(\Galette\Entity\FieldsConfig::NOBODY);
 
-        $jabber2 = $fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_IDENTITY][12];
-        $this->array($jabber2)->isIdenticalTo($jabber);
+        $gsm2 = $fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_IDENTITY][12];
+        $this->array($gsm2)->isIdenticalTo($gsm);
     }
 
     /**
@@ -391,7 +391,7 @@ class FieldsConfig extends atoum
 
         $this->object($elements[1])->isInstanceOf('\stdClass');
         $this->integer($elements[1]->id)->isIdenticalTo(3);
-        $this->array($elements[1]->elements)->hasSize(10);
+        $this->array($elements[1]->elements)->hasSize(8);
 
         $this->object($elements[2])->isInstanceOf('\stdClass');
         $this->integer($elements[2]->id)->isIdenticalTo(2);
@@ -415,7 +415,7 @@ class FieldsConfig extends atoum
 
         $this->object($elements[1])->isInstanceOf('\stdClass');
         $this->integer($elements[1]->id)->isIdenticalTo(3);
-        $this->array($elements[1]->elements)->hasSize(10);
+        $this->array($elements[1]->elements)->hasSize(8);
 
         $this->object($elements[2])->isInstanceOf('\stdClass');
         $this->integer($elements[2]->id)->isIdenticalTo(2);
@@ -454,7 +454,7 @@ class FieldsConfig extends atoum
 
         $this->object($elements['fieldsets'][1])->isInstanceOf('\stdClass');
         $this->integer($elements['fieldsets'][1]->id)->isIdenticalTo(3);
-        $this->array($elements['fieldsets'][1]->elements)->hasSize(11);
+        $this->array($elements['fieldsets'][1]->elements)->hasSize(9);
 
         $this->object($elements['fieldsets'][2])->isInstanceOf('\stdClass');
         $this->integer($elements['fieldsets'][2]->id)->isIdenticalTo(2);
@@ -485,7 +485,7 @@ class FieldsConfig extends atoum
 
         $this->object($elements['fieldsets'][1])->isInstanceOf('\stdClass');
         $this->integer($elements['fieldsets'][1]->id)->isIdenticalTo(3);
-        $this->array($elements['fieldsets'][1]->elements)->hasSize(11);
+        $this->array($elements['fieldsets'][1]->elements)->hasSize(9);
 
         $mail = $elements['fieldsets'][1]->elements['email_adh'];
         $this->boolean($mail->required)->isFalse(); //email is not required per default
@@ -523,7 +523,7 @@ class FieldsConfig extends atoum
 
         $this->object($elements['fieldsets'][1])->isInstanceOf('\stdClass');
         $this->integer($elements['fieldsets'][1]->id)->isIdenticalTo(3);
-        $this->array($elements['fieldsets'][1]->elements)->hasSize(11);
+        $this->array($elements['fieldsets'][1]->elements)->hasSize(9);
 
         $mail = $elements['fieldsets'][1]->elements['email_adh'];
         $this->boolean($mail->required)->isTrue(); //email is required for self subscription
index 6cc0f020c23e99177c5b96f3281f939f34e1d9b9..1bde22bfdcd3a44d397f4deca3ecb1417123553f 100644 (file)
@@ -209,12 +209,12 @@ class ListsConfig extends atoum
         $town['required'] = false;
         $town['visible'] = \Galette\Entity\FieldsConfig::NOBODY;
 
-        //jabber
-        $jabber = $fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_CONTACT][10];
-        $jabber['position'] = count($fields[1]);
-        unset($fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_CONTACT][10]);
-        $jabber['category'] = \Galette\Entity\FieldsCategories::ADH_CATEGORY_IDENTITY;
-        $fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_IDENTITY][] = $jabber;
+        //gsm
+        $gsm = $fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_CONTACT][5]; //6 in FieldsConfig but 5 here.
+        $gsm['position'] = count($fields[1]);
+        unset($fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_CONTACT][5]); //6 in FieldsConfig but 5 here.
+        $gsm['category'] = \Galette\Entity\FieldsCategories::ADH_CATEGORY_IDENTITY;
+        $fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_IDENTITY][] = $gsm;
 
         $this->boolean($lists_config->setFields($fields))->isTrue();
 
@@ -225,9 +225,9 @@ class ListsConfig extends atoum
         $this->boolean($town['required'])->isFalse();
         $this->integer($town['visible'])->isIdenticalTo(\Galette\Entity\FieldsConfig::NOBODY);
 
-        $jabber2 = $fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_IDENTITY][10]; //12 in FieldsConfig but 10 here
-        $this->array($jabber2)->isIdenticalTo($jabber);
-        // /copied from FieldsConfig::testSetFields to ensure it works as excpeted from here.
+        $gsm2 = $fields[\Galette\Entity\FieldsCategories::ADH_CATEGORY_IDENTITY][10]; //12 in FieldsConfig but 10 here
+        $this->array($gsm2)->isIdenticalTo($gsm);
+        // /copied from FieldsConfig::testSetFields to ensure it works as expected from here.
     }
 
     /**
index 42d03d1ff0516620f5fb89e88a4047328ac299a9..6bfa46d5e6ae5d265963d177f8a7b8977f502f9f 100644 (file)
@@ -341,7 +341,6 @@ class PdfModel extends GaletteTestCase
             'pseudo_adh' => 'ubertrand',
             'pays_adh' => 'Antarctique',
             'tel_adh' => '0439153432',
-            'url_adh' => 'http://bouchet.com/',
             'activite_adh' => true,
             'id_statut' => 9,
             'date_crea_adh' => '2020-06-10',
diff --git a/tests/Galette/Entity/tests/units/Social.php b/tests/Galette/Entity/tests/units/Social.php
new file mode 100644 (file)
index 0000000..71feef5
--- /dev/null
@@ -0,0 +1,198 @@
+<?php
+
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Socials tests
+ *
+ * PHP version 5
+ *
+ * Copyright © 2021 The Galette Team
+ *
+ * This file is part of Galette (http://galette.tuxfamily.org).
+ *
+ * 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/>.
+ *
+ * @category  Entity
+ * @package   GaletteTests
+ *
+ * @author    Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2019 The Galette Team
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @version   SVN: $Id$
+ * @link      http://galette.tuxfamily.org
+ * @since     2021-10-26
+ */
+
+namespace Galette\Entity\test\units;
+
+use Galette\GaletteTestCase;
+
+/**
+ * Status tests
+ *
+ * @category  Entity
+ * @name      Social
+ * @package   GaletteTests
+ * @author    Johan Cwiklinski <johan@x-tnd.be>
+ * @copyright 2021 The Galette Team
+ * @license   http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
+ * @link      http://galette.tuxfamily.org
+ * @since     2021-10-26
+ */
+class Social extends GaletteTestCase
+{
+    protected $seed = '25568744158';
+
+    /**
+     * Tear down tests
+     *
+     * @param string $method Calling method
+     *
+     * @return void
+     */
+    public function afterTestMethod($method)
+    {
+        parent::afterTestMethod($method);
+
+        $this->deleteSocials();
+
+        //drop dynamic translations
+        $delete = $this->zdb->delete(\Galette\Core\L10n::TABLE);
+        $this->zdb->execute($delete);
+
+        $delete = $this->zdb->delete(\Galette\Entity\Adherent::TABLE);
+        $delete->where(['fingerprint' => 'FAKER' . $this->seed]);
+        $this->zdb->execute($delete);
+
+        $this->cleanHistory();
+    }
+
+    /**
+     * Delete socials
+     *
+     * @return void
+     */
+    private function deleteSocials()
+    {
+        $delete = $this->zdb->delete(\Galette\Entity\Social::TABLE);
+        $this->zdb->execute($delete);
+    }
+
+    /**
+     * Test social object
+     *
+     * @return void
+     */
+    public function testObject()
+    {
+        $social = new \Galette\Entity\Social($this->zdb);
+
+        //setters and getters
+        $this->object($social->setType('mytype'))->isInstanceOf('\Galette\Entity\Social');
+        $this->string($social->type)->isIdenticalTo('mytype');
+
+        $this->object($social->setUrl('myurl'))->isInstanceOf('\Galette\Entity\Social');
+        $this->string($social->url)->isIdenticalTo('myurl');
+
+        //null as member id for Galette main preferences
+        $this->object($social->setLinkedMember(null))->isInstanceOf('\Galette\Entity\Social');
+        $this->variable($social->id_adh)->isNull();
+        $this->variable($social->member)->isNull();
+
+        $this->getMemberTwo();
+        $this->object($social->setLinkedMember($this->adh->id))->isInstanceOf(\Galette\Entity\Social::class);
+        $this->integer($social->id_adh)->isIdenticalTo($this->adh->id);
+        $this->object($social->member)->isInstanceOf(\Galette\Entity\Adherent::class);
+        $this->string($social->member->name)->isIdenticalTo($this->adh->name);
+    }
+
+    /**
+     * Test socials "system" types
+     *
+     * @return void
+     */
+    public function testGetSystemTypes()
+    {
+        $social = new \Galette\Entity\Social($this->zdb);
+        $this->array($social->getSystemTypes())->hasSize(9);
+        $this->array($social->getSystemTypes())->isIdenticalTo($social->getSystemTypes(true));
+        $this->array($social->getSystemTypes(false))->hasSize(9);
+
+        $this->string($social->getSystemType(\Galette\Entity\Social::TWITTER))->isIdenticalTo('Twitter');
+        $this->string($social->getSystemType(\Galette\Entity\Social::TWITTER, false))->isIdenticalTo('twitter');
+    }
+
+    /**
+     * Test getListForMember
+     *
+     * @return void
+     */
+    public function testGetListForMember(): void
+    {
+        $this->array(\Galette\Entity\Social::getListForMember(null))->isEmpty();
+
+        $this->getMemberTwo();
+        $this->array(\Galette\Entity\Social::getListForMember($this->adh->id))->isEmpty();
+
+        $social = new \Galette\Entity\Social($this->zdb);
+        $this->boolean(
+            $social
+                ->setType(\Galette\Entity\Social::MASTODON)
+                ->setUrl('mastodon URL')
+                ->setLinkedMember($this->adh->id)
+                ->store()
+        )->isTrue();
+
+        $socials = \Galette\Entity\Social::getListForMember($this->adh->id);
+        $this->array($socials)->HasSize(1);
+        $social = array_pop($socials);
+        $this->string($social->type)->isIdenticalTo(\Galette\Entity\Social::MASTODON);
+        $this->integer($social->id_adh)->isIdenticalTo($this->adh->id);
+        $this->string($social->url)->isIdenticalTo('mastodon URL');
+
+        $social = new \Galette\Entity\Social($this->zdb);
+        $this->boolean(
+            $social
+                ->setType(\Galette\Entity\Social::MASTODON)
+                ->setUrl('Galette mastodon URL')
+                ->setLinkedMember(null)
+                ->store()
+        )->isTrue();
+
+        $social = new \Galette\Entity\Social($this->zdb);
+        $this->boolean(
+            $social
+                ->setType(\Galette\Entity\Social::JABBER)
+                ->setUrl('Galette jabber')
+                ->setLinkedMember(null)
+                ->store()
+        )->isTrue();
+
+        $social = new \Galette\Entity\Social($this->zdb);
+        $this->boolean(
+            $social
+                ->setType(\Galette\Entity\Social::MASTODON)
+                ->setUrl('Another Galette mastodon URL')
+                ->setLinkedMember(null)
+                ->store()
+        )->isTrue();
+
+        $this->array(\Galette\Entity\Social::getListForMember(null))->hasSize(3);
+        $this->array(\Galette\Entity\Social::getListForMember(null, \Galette\Entity\Social::JABBER))->hasSize(1);
+
+        $this->boolean($social->remove())->isTrue();
+        $this->array(\Galette\Entity\Social::getListForMember(null))->hasSize(2);
+    }
+}
index 254157542a2ef4d4ea5f2f0287e19f042343f26d..9aa2b685035918e3b5e88d63a7d806cb79cde0c5 100644 (file)
@@ -581,7 +581,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'tgonzalez',
                 'pays_adh' => null,
                 'tel_adh' => '+33 8 93 53 99 52',
-                'url_adh' => null,
                 'activite_adh' => true,
                 'id_statut' => 9,
                 'date_crea_adh' => '2020-03-09',
@@ -609,7 +608,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'agnes.evrard',
                 'pays_adh' => null,
                 'tel_adh' => '0288284193',
-                'url_adh' => 'https://leroux.fr/omnis-autem-suscipit-consequuntur-possimus-sint-iste-beatae.html',
                 'activite_adh' => true,
                 'id_statut' => 9,
                 'date_crea_adh' => '2019-11-29',
@@ -637,7 +635,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'fgay',
                 'pays_adh' => null,
                 'tel_adh' => '+33 7 45 45 19 81',
-                'url_adh' => null,
                 'activite_adh' => true,
                 'id_statut' => 8,
                 'date_crea_adh' => '2019-02-03',
@@ -665,7 +662,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'chauvin.guillaume',
                 'pays_adh' => 'Hong Kong',
                 'tel_adh' => '+33 5 48 57 32 28',
-                'url_adh' => null,
                 'activite_adh' => true,
                 'id_statut' => 1,
                 'date_crea_adh' => '2017-11-20',
@@ -695,7 +691,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'sauvage.dorothee',
                 'pays_adh' => 'Bangladesh',
                 'tel_adh' => '+33 4 75 14 66 56',
-                'url_adh' => null,
                 'activite_adh' => false,
                 'id_statut' => 9,
                 'date_crea_adh' => '2018-08-16',
@@ -723,7 +718,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'andre.guillou',
                 'pays_adh' => null,
                 'tel_adh' => '09 26 70 06 55',
-                'url_adh' => 'http://www.hoarau.fr/quis-neque-ducimus-quidem-et',
                 'activite_adh' => true,
                 'id_statut' => 9,
                 'date_crea_adh' => '2018-09-28',
@@ -751,7 +745,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'ferreira.rene',
                 'pays_adh' => 'Tuvalu',
                 'tel_adh' => '+33 (0)7 47 56 89 70',
-                'url_adh' => null,
                 'activite_adh' => true,
                 'id_statut' => 9,
                 'date_crea_adh' => '2018-01-13',
@@ -779,7 +772,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'roger27',
                 'pays_adh' => 'Antilles néerlandaises',
                 'tel_adh' => '0922523762',
-                'url_adh' => null,
                 'activite_adh' => true,
                 'id_statut' => 9,
                 'date_crea_adh' => '2020-02-13',
@@ -809,7 +801,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'julien.isabelle',
                 'pays_adh' => 'Mexique',
                 'tel_adh' => '0809527977',
-                'url_adh' => null,
                 'activite_adh' => true,
                 'id_statut' => 9,
                 'date_crea_adh' => '2019-06-26',
@@ -837,7 +828,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'louis.pruvost',
                 'pays_adh' => null,
                 'tel_adh' => '+33 (0)6 80 24 46 58',
-                'url_adh' => null,
                 'activite_adh' => true,
                 'id_statut' => 9,
                 'date_crea_adh' => '2020-08-09',
@@ -877,7 +867,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'olivier.roux',
                 'pays_adh' => 'République Dominicaine',
                 'tel_adh' => '08 95 04 73 14',
-                'url_adh' => null,
                 'activite_adh' => true,
                 'id_statut' => 9,
                 'date_crea_adh' => '2020-07-31',
@@ -905,7 +894,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'hchevalier',
                 'pays_adh' => 'Kiribati',
                 'tel_adh' => '04 55 49 80 92',
-                'url_adh' => 'http://www.leblanc.com/nemo-non-rerum-commodi-sequi-ut',
                 'activite_adh' => true,
                 'id_statut' => 1,
                 'date_crea_adh' => '2020-06-02',
@@ -933,7 +921,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'abarre',
                 'pays_adh' => 'Kirghizistan',
                 'tel_adh' => '07 47 63 11 31',
-                'url_adh' => 'https://www.jacques.com/fuga-voluptatem-tenetur-rem-possimus',
                 'activite_adh' => true,
                 'id_statut' => 9,
                 'date_crea_adh' => '2020-10-28',
@@ -961,7 +948,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'frederique.bernier',
                 'pays_adh' => null,
                 'tel_adh' => '+33 2 50 03 01 12',
-                'url_adh' => null,
                 'activite_adh' => true,
                 'id_statut' => 9,
                 'date_crea_adh' => '2020-08-14',
@@ -989,7 +975,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'stoussaint',
                 'pays_adh' => 'Îles Mineures Éloignées des États-Unis',
                 'tel_adh' => '+33 (0)1 30 50 01 54',
-                'url_adh' => 'http://www.lemaitre.org/dolorum-recusandae-non-eum-non',
                 'activite_adh' => true,
                 'id_statut' => 3,
                 'date_crea_adh' => '2018-12-05',
@@ -1019,7 +1004,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'virginie.jacquet',
                 'pays_adh' => null,
                 'tel_adh' => '0393209420',
-                'url_adh' => null,
                 'activite_adh' => true,
                 'id_statut' => 9,
                 'date_crea_adh' => '2018-02-17',
@@ -1047,7 +1031,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'diallo.sebastien',
                 'pays_adh' => null,
                 'tel_adh' => '+33 5 72 28 24 81',
-                'url_adh' => null,
                 'activite_adh' => true,
                 'id_statut' => 9,
                 'date_crea_adh' => '2020-03-16',
@@ -1075,7 +1058,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'helene59',
                 'pays_adh' => null,
                 'tel_adh' => '0383453389',
-                'url_adh' => 'http://www.lesage.com/et-aperiam-labore-est-libero-voluptatem.html',
                 'activite_adh' => true,
                 'id_statut' => 9,
                 'date_crea_adh' => '2020-02-03',
@@ -1103,7 +1085,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'wpierre',
                 'pays_adh' => null,
                 'tel_adh' => '01 32 14 47 74',
-                'url_adh' => null,
                 'activite_adh' => true,
                 'id_statut' => 9,
                 'date_crea_adh' => '2020-03-28',
@@ -1131,7 +1112,6 @@ class CsvIn extends GaletteTestCase
                 'pseudo_adh' => 'gerard66',
                 'pays_adh' => null,
                 'tel_adh' => '+33 1 46 04 81 87',
-                'url_adh' => 'http://www.thierry.com/',
                 'activite_adh' => true,
                 'id_statut' => 5,
                 'date_crea_adh' => '2019-05-16',
index 6497ef8887907d4e8d5f2dc01cc72855653ae70d..2da5d565aa05bf1f2cc55b4ed033a327115d2575 100644 (file)
@@ -208,7 +208,6 @@ abstract class GaletteTestCase extends atoum
             'pseudo_adh' => 'ubertrand',
             'pays_adh' => 'Antarctique',
             'tel_adh' => '0439153432',
-            'url_adh' => 'http://bouchet.com/',
             'activite_adh' => true,
             'id_statut' => 9,
             'date_crea_adh' => '2020-06-10',
@@ -255,7 +254,6 @@ abstract class GaletteTestCase extends atoum
             'pseudo_adh' => 'vallet.camille',
             'pays_adh' => null,
             'tel_adh' => '05 59 53 59 43',
-            'url_adh' => 'http://bodin.net/omnis-ratione-sint-dolorem-architecto',
             'activite_adh' => true,
             'id_statut' => 9,
             'date_crea_adh' => '2019-05-20',
@@ -330,7 +328,6 @@ abstract class GaletteTestCase extends atoum
             'cp_adh' => '39 069',
             'pays_adh' => 'Antarctique',
             'tel_adh' => '0439153432',
-            'url_adh' => 'http://bouchet.com/',
             'activite_adh' => true,
             'id_statut' => 9,
             'pref_lang' => 'en_US',
@@ -436,7 +433,6 @@ abstract class GaletteTestCase extends atoum
             'pseudo_adh' => 'vallet.camille',
             'pays_adh' => '',
             'tel_adh' => '05 59 53 59 43',
-            'url_adh' => 'http://bodin.net/omnis-ratione-sint-dolorem-architecto',
             'activite_adh' => true,
             'id_statut' => 9,
             'pref_lang' => 'ca',
index 82ce0552c28a3f3546b69cd7fbcdb63c04c66ae5..f7673495f9a032f4fe4e11f19f39741b43396de9 100644 (file)
@@ -20,7 +20,6 @@
         "pseudo_adh": "marcetienne25",
         "pays_adh": null,
         "tel_adh": "+33 2 93 73 14 36",
-        "url_adh": "http:\/\/www.perrin.net\/",
         "activite_adh": true,
         "id_statut": 9,
         "date_crea_adh": "2017-08-07",
@@ -49,7 +48,6 @@
         "pays_adh": "Bangladesh",
         "societe_adh": "Galette, Inc.",
         "tel_adh": "+33 (0)5 41 65 71 46",
-        "url_adh": "http:\/\/coulon.fr\/eos-nesciunt-consectetur-dolores-omnis-provident-explicabo",
         "activite_adh": true,
         "id_statut": 1,
         "date_crea_adh": "2017-08-07",
@@ -77,7 +75,6 @@
         "pseudo_adh": "nleclerc",
         "pays_adh": null,
         "tel_adh": "0895352968",
-        "url_adh": null,
         "activite_adh": true,
         "id_statut": 9,
         "date_crea_adh": "2017-08-07",
         "pseudo_adh": "benjamin.germain",
         "pays_adh": "Autriche",
         "tel_adh": "+33 5 56 55 02 16",
-        "url_adh": "http:\/\/www.bourgeois.fr\/accusamus-sapiente-est-quia-facilis-quas-exercitationem.html",
         "activite_adh": true,
         "id_statut": 5,
         "date_crea_adh": "2017-08-07",
         "pseudo_adh": "martine56",
         "pays_adh": "Autriche",
         "tel_adh": "+33 5 56 55 02 16",
-        "url_adh": "http:\/\/www.bourgeois.fr\/accusamus-sapiente-est-quia-facilis-quas-exercitationem.html",
         "activite_adh": true,
         "id_statut": 5,
         "date_crea_adh": "2017-08-07",
         "pseudo_adh": "laetitia.sanchez",
         "pays_adh": "Norv\u00e8ge",
         "tel_adh": "0129447169",
-        "url_adh": null,
         "activite_adh": true,
         "id_statut": 9,
         "date_crea_adh": "2017-08-07",
         "pseudo_adh": "elodie.bigot",
         "pays_adh": "Montserrat",
         "tel_adh": "+33 6 87 22 98 19",
-        "url_adh": null,
         "activite_adh": false,
         "id_statut": 4,
         "date_crea_adh": "2017-08-07",
         "pseudo_adh": "victoire64",
         "pays_adh": null,
         "tel_adh": "03 43 89 01 97",
-        "url_adh": null,
         "activite_adh": true,
         "id_statut": 9,
         "date_crea_adh": "2017-08-07",
         "pays_adh": "Ouzb\u00e9kistan",
         "societe_adh": "Galette, Inc.",
         "tel_adh": "+33 (0)8 06 28 91 89",
-        "url_adh": "http:\/\/paris.net\/",
         "activite_adh": true,
         "id_statut": 9,
         "date_crea_adh": "2017-08-07",
         "pseudo_adh": "dramos",
         "pays_adh": "Danemark",
         "tel_adh": "+33 (0)1 03 04 16 21",
-        "url_adh": "http:\/\/www.lopes.com\/",
         "activite_adh": true,
         "id_statut": 6,
         "date_crea_adh": "2017-08-07",