From cc5c663608fda85d097d530f57096d5292dee678 Mon Sep 17 00:00:00 2001 From: Pascal Meunier Date: Mon, 27 Apr 2026 16:48:50 -0400 Subject: [PATCH 1/4] created plugin to add users to a D1 nations group if they login from an IP address from one of those nations --- core/plugins/user/d1/d1.php | 97 +++++++++++++++++++ core/plugins/user/d1/d1.xml | 16 +++ .../language/en-GB/en-GB.plg_user_d1.sys.ini | 2 + .../Migration20260421000000PlgUserD1.php | 33 +++++++ 4 files changed, 148 insertions(+) create mode 100644 core/plugins/user/d1/d1.php create mode 100644 core/plugins/user/d1/d1.xml create mode 100644 core/plugins/user/d1/language/en-GB/en-GB.plg_user_d1.sys.ini create mode 100644 core/plugins/user/d1/migrations/Migration20260421000000PlgUserD1.php diff --git a/core/plugins/user/d1/d1.php b/core/plugins/user/d1/d1.php new file mode 100644 index 00000000000..39f26d528c9 --- /dev/null +++ b/core/plugins/user/d1/d1.php @@ -0,0 +1,97 @@ +onUserLogin($user, $options); + } + + /** + * This method should handle any login logic and report back to the subject + * + * @param array $user holds the user data + * @param array $options holding options (remember, autoregister, group) + * @return bool + */ + public function onUserLogin($user, $options = array()) + { + $ip = $_SERVER['REMOTE_ADDR']; + + $gdb = \Hubzero\Geocode\Geocode::getGeoDBO(); + + if (!$gdb) + { + Log::debug('plgUserD1: geo database unavailable, skipping group update for [' . User::get('username') . '].'); + return; + } + + $gdb->setQuery( + "SELECT cg.countrygroup FROM ipcountry ic" . + " JOIN countrygroup cg ON ic.countrySHORT = cg.countrycode" . + " WHERE ic.ipfrom <= INET_ATON(" . $gdb->quote($ip) . ")" . + " AND ic.ipto >= INET_ATON(" . $gdb->quote($ip) . ")" + ); + $countrygroup = $gdb->loadResult(); + + if (!$countrygroup) + { + return; + } + + if ($countrygroup == 'D1') + { + Log::debug($ip . ' is in a D1 nation, adding [' . User::get('username') . '] to group [d1_nation].'); + + $group = \Hubzero\User\Group::getInstance('d1_nation'); + + if (is_object($group)) + { + $group->add('members', array(User::get('id'))); + $group->update(); + } + else + { + Log::debug('group [d1_nation] does not exist, member addition failed.'); + } + } + else + { + Log::debug($ip . ' has countrygroup [' . $countrygroup . '], leaving [' . User::get('username') . '] membership to group [d1_nation] unchanged.'); + } + } + + public function onAfterDeleteUser($user, $success, $msg) + { + return $this->onUserAfterDelete($user, $success, $msg); + } + + /** + * Method is called after user data is deleted from the database + * + * @param array $user holds the user data + * @param bool $success true if user was successfully stored in the database + * @param string $msg message + */ + public function onUserAfterDelete($user, $success, $msg) + { + $group = \Hubzero\User\Group::getInstance('d1_nation'); + + if (is_object($group)) + { + $group->remove('members', array($user['id'])); + $group->update(); + } + } +} diff --git a/core/plugins/user/d1/d1.xml b/core/plugins/user/d1/d1.xml new file mode 100644 index 00000000000..63863ee3e9e --- /dev/null +++ b/core/plugins/user/d1/d1.xml @@ -0,0 +1,16 @@ + + + plg_user_d1 + HUBzero + hubzero.org + support@hubzero.org + Copyright (c) 2005-2020 The Regents of the University of California. + http://opensource.org/licenses/MIT MIT + PLG_USER_D1_XML_DESCRIPTION + + d1.php + + + language/en-GB/en-GB.plg_user_d1.sys.ini + + diff --git a/core/plugins/user/d1/language/en-GB/en-GB.plg_user_d1.sys.ini b/core/plugins/user/d1/language/en-GB/en-GB.plg_user_d1.sys.ini new file mode 100644 index 00000000000..886989f33f9 --- /dev/null +++ b/core/plugins/user/d1/language/en-GB/en-GB.plg_user_d1.sys.ini @@ -0,0 +1,2 @@ +PLG_USER_D1="User - D1" +PLG_USER_D1_XML_DESCRIPTION="Adds users to the d1_nation group on login when their IP resolves to a D1 country group via the ipcountry and countrygroup tables." diff --git a/core/plugins/user/d1/migrations/Migration20260421000000PlgUserD1.php b/core/plugins/user/d1/migrations/Migration20260421000000PlgUserD1.php new file mode 100644 index 00000000000..683dee58b30 --- /dev/null +++ b/core/plugins/user/d1/migrations/Migration20260421000000PlgUserD1.php @@ -0,0 +1,33 @@ +addPluginEntry('user', 'd1'); + } + + /** + * Down + **/ + public function down() + { + $this->deletePluginEntry('user', 'd1'); + } +} From aabc06a61817b35e0db30de517c2fbc4c4b1c63f Mon Sep 17 00:00:00 2001 From: Pascal Meunier Date: Tue, 5 May 2026 10:49:55 -0400 Subject: [PATCH 2/4] At login, if the user is a member of d1_approved, the plugin now removes them from d1_nation and returns without doing any geo database lookup --- core/plugins/user/d1/d1.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/core/plugins/user/d1/d1.php b/core/plugins/user/d1/d1.php index 39f26d528c9..d482a4cc508 100644 --- a/core/plugins/user/d1/d1.php +++ b/core/plugins/user/d1/d1.php @@ -27,6 +27,23 @@ public function onLoginUser($user, $options = array()) */ public function onUserLogin($user, $options = array()) { + $approved = \Hubzero\User\Group::getInstance('d1_approved'); + + if (is_object($approved) && $approved->isMember(User::get('id'))) + { + Log::debug('plgUserD1: [' . User::get('username') . '] is in d1_approved, removing from d1_nation and skipping geo check.'); + + $nation = \Hubzero\User\Group::getInstance('d1_nation'); + + if (is_object($nation)) + { + $nation->remove('members', array(User::get('id'))); + $nation->update(); + } + + return; + } + $ip = $_SERVER['REMOTE_ADDR']; $gdb = \Hubzero\Geocode\Geocode::getGeoDBO(); From 2ee749fdbbb52812922c0e32be40c18e0bf120d9 Mon Sep 17 00:00:00 2001 From: Pascal Meunier Date: Tue, 5 May 2026 11:12:40 -0400 Subject: [PATCH 3/4] renamed d1_approved to d1_override --- core/plugins/user/d1/d1.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/plugins/user/d1/d1.php b/core/plugins/user/d1/d1.php index d482a4cc508..20cff79d6bd 100644 --- a/core/plugins/user/d1/d1.php +++ b/core/plugins/user/d1/d1.php @@ -27,11 +27,11 @@ public function onLoginUser($user, $options = array()) */ public function onUserLogin($user, $options = array()) { - $approved = \Hubzero\User\Group::getInstance('d1_approved'); + $approved = \Hubzero\User\Group::getInstance('d1_override'); if (is_object($approved) && $approved->isMember(User::get('id'))) { - Log::debug('plgUserD1: [' . User::get('username') . '] is in d1_approved, removing from d1_nation and skipping geo check.'); + Log::debug('plgUserD1: [' . User::get('username') . '] is in d1_override, removing from d1_nation and skipping geo check.'); $nation = \Hubzero\User\Group::getInstance('d1_nation'); From c666fb53836595e10a938c66962d4111e94c8e95 Mon Sep 17 00:00:00 2001 From: Pascal Meunier Date: Tue, 5 May 2026 11:13:05 -0400 Subject: [PATCH 4/4] migration now creates the groups d1_override and d1_nation --- .../Migration20260421000000PlgUserD1.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/core/plugins/user/d1/migrations/Migration20260421000000PlgUserD1.php b/core/plugins/user/d1/migrations/Migration20260421000000PlgUserD1.php index 683dee58b30..f956a00d70b 100644 --- a/core/plugins/user/d1/migrations/Migration20260421000000PlgUserD1.php +++ b/core/plugins/user/d1/migrations/Migration20260421000000PlgUserD1.php @@ -21,6 +21,18 @@ class Migration20260421000000PlgUserD1 extends Base public function up() { $this->addPluginEntry('user', 'd1'); + + if ($this->db->tableExists('#__xgroups')) + { + foreach (array('d1_nation', 'd1_override') as $cn) + { + $this->db->setQuery( + "INSERT IGNORE INTO `#__xgroups` (cn, description, published, approved, type, join_policy, discoverability, created)" . + " VALUES (" . $this->db->quote($cn) . ", " . $this->db->quote($cn) . ", 1, 1, 1, 3, 1, NOW())" + ); + $this->db->query(); + } + } } /** @@ -29,5 +41,13 @@ public function up() public function down() { $this->deletePluginEntry('user', 'd1'); + + if ($this->db->tableExists('#__xgroups')) + { + $this->db->setQuery( + "DELETE FROM `#__xgroups` WHERE cn IN ('d1_nation', 'd1_override')" + ); + $this->db->query(); + } } }