From f1001d25829f5a0328f2302bb3e0578038d39494 Mon Sep 17 00:00:00 2001 From: Pascal Meunier Date: Mon, 27 Apr 2026 16:44:44 -0400 Subject: [PATCH 1/3] created plugin to add users to a location_us group if they login from a US IP address --- .../language/en-GB/en-GB.plg_user_us.sys.ini | 2 + .../Migration20260421000001PlgUserUs.php | 33 +++++++ core/plugins/user/us/us.php | 91 +++++++++++++++++++ core/plugins/user/us/us.xml | 16 ++++ 4 files changed, 142 insertions(+) create mode 100644 core/plugins/user/us/language/en-GB/en-GB.plg_user_us.sys.ini create mode 100644 core/plugins/user/us/migrations/Migration20260421000001PlgUserUs.php create mode 100644 core/plugins/user/us/us.php create mode 100644 core/plugins/user/us/us.xml diff --git a/core/plugins/user/us/language/en-GB/en-GB.plg_user_us.sys.ini b/core/plugins/user/us/language/en-GB/en-GB.plg_user_us.sys.ini new file mode 100644 index 00000000000..a9caf13907c --- /dev/null +++ b/core/plugins/user/us/language/en-GB/en-GB.plg_user_us.sys.ini @@ -0,0 +1,2 @@ +PLG_USER_US="User - US" +PLG_USER_US_XML_DESCRIPTION="Adds users to the location_us group on login when their IP resolves to a US address via the ipcountry table." diff --git a/core/plugins/user/us/migrations/Migration20260421000001PlgUserUs.php b/core/plugins/user/us/migrations/Migration20260421000001PlgUserUs.php new file mode 100644 index 00000000000..4e53bc71b27 --- /dev/null +++ b/core/plugins/user/us/migrations/Migration20260421000001PlgUserUs.php @@ -0,0 +1,33 @@ +addPluginEntry('user', 'us'); + } + + /** + * Down + **/ + public function down() + { + $this->deletePluginEntry('user', 'us'); + } +} diff --git a/core/plugins/user/us/us.php b/core/plugins/user/us/us.php new file mode 100644 index 00000000000..2b36e48132a --- /dev/null +++ b/core/plugins/user/us/us.php @@ -0,0 +1,91 @@ +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('plgUserUs: geo database unavailable, skipping group update for [' . User::get('username') . '].'); + return; + } + + $gdb->setQuery( + "SELECT countrySHORT FROM ipcountry" . + " WHERE ipfrom <= INET_ATON(" . $gdb->quote($ip) . ")" . + " AND ipto >= INET_ATON(" . $gdb->quote($ip) . ")" + ); + $country = $gdb->loadResult(); + + if ($country == 'US') + { + Log::debug($ip . ' is a US address, adding [' . User::get('username') . '] to group [location_us].'); + + $group = \Hubzero\User\Group::getInstance('location_us'); + + if (is_object($group)) + { + $group->add('members', array(User::get('id'))); + $group->update(); + } + else + { + Log::debug('group [location_us] does not exist, member addition failed.'); + } + } + else + { + Log::debug($ip . ' is not a US address, leaving [' . User::get('username') . '] membership to group [location_us] 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('location_us'); + + if (is_object($group)) + { + $group->remove('members', array($user['id'])); + $group->update(); + } + } +} diff --git a/core/plugins/user/us/us.xml b/core/plugins/user/us/us.xml new file mode 100644 index 00000000000..c56cb2486fe --- /dev/null +++ b/core/plugins/user/us/us.xml @@ -0,0 +1,16 @@ + + + plg_user_us + 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_US_XML_DESCRIPTION + + us.php + + + language/en-GB/en-GB.plg_user_us.sys.ini + + From 7a99dcf38d2ffbce02f2e40e50a6296755247e6d Mon Sep 17 00:00:00 2001 From: Pascal Meunier Date: Tue, 5 May 2026 10:31:28 -0400 Subject: [PATCH 2/3] remove people from location_us group if they login from elsewhere or if they are in the d1_nation group. The purdue group will supersede the location_us group through unix ACLs that will allow access to people in the purdue group for things that are restricted to people in the US --- core/plugins/user/us/us.php | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/core/plugins/user/us/us.php b/core/plugins/user/us/us.php index 2b36e48132a..c18f9840c63 100644 --- a/core/plugins/user/us/us.php +++ b/core/plugins/user/us/us.php @@ -29,6 +29,23 @@ public function onUserLogin($user, $options = array()) { $ip = $_SERVER['REMOTE_ADDR']; + $d1 = \Hubzero\User\Group::getInstance('d1_nation'); + + if (is_object($d1) && in_array(User::get('id'), $d1->get('members'))) + { + Log::debug('[' . User::get('username') . '] is a member of [d1_nation], removing from group [location_us].'); + + $group = \Hubzero\User\Group::getInstance('location_us'); + + if (is_object($group)) + { + $group->remove('members', array(User::get('id'))); + $group->update(); + } + + return; + } + $gdb = \Hubzero\Geocode\Geocode::getGeoDBO(); if (!$gdb) @@ -62,7 +79,15 @@ public function onUserLogin($user, $options = array()) } else { - Log::debug($ip . ' is not a US address, leaving [' . User::get('username') . '] membership to group [location_us] unchanged.'); + Log::debug($ip . ' is not a US address, removing [' . User::get('username') . '] from group [location_us].'); + + $group = \Hubzero\User\Group::getInstance('location_us'); + + if (is_object($group)) + { + $group->remove('members', array(User::get('id'))); + $group->update(); + } } } From 296b739b1286237463458b366d20755b7d29168d Mon Sep 17 00:00:00 2001 From: Pascal Meunier Date: Tue, 5 May 2026 11:19:43 -0400 Subject: [PATCH 3/3] up() now registers the plugin and inserts the location_us group into #__xgroups with discoverability=1 (hidden) and join_policy=3 (closed), using INSERT IGNORE so a re-run is safe. down() deletes the group before removing the plugin entry. Both operations are guarded by a tableExists check. --- .../Migration20260421000001PlgUserUs.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/core/plugins/user/us/migrations/Migration20260421000001PlgUserUs.php b/core/plugins/user/us/migrations/Migration20260421000001PlgUserUs.php index 4e53bc71b27..546cedf2a8d 100644 --- a/core/plugins/user/us/migrations/Migration20260421000001PlgUserUs.php +++ b/core/plugins/user/us/migrations/Migration20260421000001PlgUserUs.php @@ -21,6 +21,15 @@ class Migration20260421000001PlgUserUs extends Base public function up() { $this->addPluginEntry('user', 'us'); + + if ($this->db->tableExists('#__xgroups')) + { + $this->db->setQuery( + "INSERT IGNORE INTO `#__xgroups` (`cn`, `published`, `approved`, `type`, `join_policy`, `discoverability`) + VALUES ('location_us', 1, 1, 1, 3, 1)" + ); + $this->db->query(); + } } /** @@ -28,6 +37,12 @@ public function up() **/ public function down() { + if ($this->db->tableExists('#__xgroups')) + { + $this->db->setQuery("DELETE FROM `#__xgroups` WHERE `cn` = 'location_us'"); + $this->db->query(); + } + $this->deletePluginEntry('user', 'us'); } }