Skip to content

Commit 3cf346b

Browse files
authored
rewrite PI search functionality (#538)
1 parent 4400082 commit 3cf346b

File tree

8 files changed

+98
-131
lines changed

8 files changed

+98
-131
lines changed

resources/init.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
if (time() - ($_SESSION["LAST_ACTIVITY"] ?? 0) > CONFIG["site"]["session_cleanup_idle_seconds"]) {
3939
$_SESSION["csrf_tokens"] = [];
4040
$_SESSION["messages"] = [];
41+
if (array_key_exists("pi_group_gid_to_owner_gecos_and_mail", $_SESSION)) {
42+
unset($_SESSION["pi_group_gid_to_owner_gecos_and_mail"]);
43+
}
4144
session_write_close();
4245
session_start();
4346
}

resources/lib/UnityGroup.php

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -361,16 +361,6 @@ public static function GID2OwnerUID(string $gid): string
361361
return substr($gid, strlen(self::PI_PREFIX));
362362
}
363363

364-
/**
365-
* @throws \UnityWebPortal\lib\exceptions\EntryNotFoundException
366-
*/
367-
public static function ownerMail2GID(string $email): string
368-
{
369-
global $LDAP;
370-
$owner_uid = $LDAP->getUidFromEmail($email); // throws EntryNotFoundException
371-
return self::ownerUID2GID($owner_uid);
372-
}
373-
374364
public function getGroupMembersAttributes(array $attributes, array $default_values = []): array
375365
{
376366
return $this->LDAP->getUsersAttributes(

resources/lib/UnityLDAP.php

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -291,20 +291,6 @@ public function getOrgGroupEntry(string $gid): LDAPEntry
291291
return $this->getEntry(UnityLDAP::RDN . "=$gid," . CONFIG["ldap"]["orggroup_ou"]);
292292
}
293293

294-
/**
295-
* @throws \UnityWebPortal\lib\exceptions\EntryNotFoundException
296-
*/
297-
public function getUidFromEmail(string $email): string
298-
{
299-
$email = ldap_escape($email, flags: LDAP_ESCAPE_FILTER);
300-
$entries = $this->userOU->getChildrenArrayStrict(["uid"], true, "(mail=$email)");
301-
if (count($entries) == 0) {
302-
throw new exceptions\EntryNotFoundException($email);
303-
} else {
304-
return $entries[0]["uid"][0];
305-
}
306-
}
307-
308294
/**
309295
* returns an array with each UID as an array key
310296
* @throws \UnityWebPortal\lib\exceptions\EntryNotFoundException

test/functional/PIMemberRequestTest.php

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -64,22 +64,6 @@ public function testRequestMembershipBogus()
6464
}
6565
}
6666

67-
public function testRequestMembershipByOwnerMail()
68-
{
69-
global $USER, $SQL;
70-
$this->switchUser("EmptyPIGroupOwner");
71-
$pi_group = $USER->getPIGroup();
72-
$this->switchUser("Blank");
73-
try {
74-
$this->requestMembership($pi_group->getOwner()->getMail());
75-
$this->assertTrue($pi_group->requestExists($USER));
76-
} finally {
77-
if ($SQL->requestExists($USER->uid, $pi_group->gid)) {
78-
$SQL->removeRequest($USER->uid, $pi_group->gid);
79-
}
80-
}
81-
}
82-
8367
public function testRequestMembershipDuplicate()
8468
{
8569
global $USER, $SQL;

webroot/panel/ajax/pi_search.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
require_once __DIR__ . "/../../../resources/autoload.php"; // Load required libs
4+
use UnityWebPortal\lib\UnityHTTPD;
5+
6+
$search_query = strtolower(UnityHTTPD::getQueryParameter("search"));
7+
if ($search_query === "") {
8+
echo "[]";
9+
UnityHTTPD::die();
10+
}
11+
if (!array_key_exists("pi_group_gid_to_owner_gecos_and_mail", $_SESSION)) {
12+
UnityHTTPD::internalServerError(
13+
'$_SESSION["pi_group_gid_to_owner_gecos_and_mail"] does not exist!',
14+
"Session cache not found. Try reloading the page."
15+
);
16+
}
17+
$pi_group_gid_to_owner_gecos_and_mail = $_SESSION["pi_group_gid_to_owner_gecos_and_mail"];
18+
$output = [];
19+
foreach ($pi_group_gid_to_owner_gecos_and_mail as $gid => [$gecos, $mail]) {
20+
$gid = strtolower($gid);
21+
$gecos = strtolower($gecos);
22+
$mail = strtolower($mail);
23+
if (str_contains($gid, $search_query) || str_contains($gecos, $search_query) || str_contains($mail, $search_query)) {
24+
array_push($output, $gid);
25+
if (count($output) >= 10) {
26+
break;
27+
}
28+
}
29+
}
30+
echo jsonEncode($output);

webroot/panel/groups.php

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,10 @@
88

99
$getPIGroupFromPost = function () {
1010
global $LDAP, $SQL, $MAILER, $WEBHOOK;
11-
$gid_or_mail = UnityHTTPD::getPostData("pi");
12-
if (substr($gid_or_mail, 0, 3) !== "pi_" && str_contains($gid_or_mail, "@")) {
13-
try {
14-
$gid_or_mail = UnityGroup::ownerMail2GID($gid_or_mail);
15-
} catch (EntryNotFoundException) {
16-
// oh well, we tried
17-
}
18-
}
19-
$pi_group = new UnityGroup($gid_or_mail, $LDAP, $SQL, $MAILER, $WEBHOOK);
11+
$gid = UnityHTTPD::getPostData("pi");
12+
$pi_group = new UnityGroup($gid, $LDAP, $SQL, $MAILER, $WEBHOOK);
2013
if (!$pi_group->exists()) {
21-
UnityHTTPD::messageError("This PI Doesn't Exist", $gid_or_mail);
14+
UnityHTTPD::messageError("This PI Doesn't Exist", $gid);
2215
UnityHTTPD::redirect();
2316
}
2417
return $pi_group;

webroot/panel/modal/new_pi.php

Lines changed: 62 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,23 @@
22

33
require_once __DIR__ . "/../../../resources/autoload.php";
44
use UnityWebPortal\lib\UnityHTTPD;
5+
use UnityWebPortal\lib\UnityGroup;
56
$CSRFTokenHiddenFormInput = UnityHTTPD::getCSRFTokenHiddenFormInput();
7+
8+
// cache PI group info in $_SESSION for ajax pi_search.php
9+
// cache persists only until the user loads this page again
10+
$owner_uids = $LDAP->getAllPIGroupOwnerUIDs();
11+
$owner_attributes = $LDAP->getUsersAttributes(
12+
$owner_uids,
13+
["uid", "gecos", "mail"],
14+
default_values: ["gecos" => [""], "mail" => [""]]
15+
);
16+
$pi_group_gid_to_owner_gecos_and_mail = [];
17+
foreach ($owner_attributes as $attributes) {
18+
$gid = UnityGroup::ownerUID2GID($attributes["uid"][0]);
19+
$pi_group_gid_to_owner_gecos_and_mail[$gid] = [$attributes["gecos"][0], $attributes["mail"][0]];
20+
}
21+
$_SESSION["pi_group_gid_to_owner_gecos_and_mail"] = $pi_group_gid_to_owner_gecos_and_mail;
622
?>
723

824
<form
@@ -13,7 +29,13 @@
1329
<?php echo $CSRFTokenHiddenFormInput; ?>
1430
<input type="hidden" name="form_type" value="addPIform">
1531
<div style="position: relative;">
16-
<input type="text" id="pi_search" name="pi" placeholder="Search PI by NetID" required>
32+
<input
33+
type="text"
34+
id="pi_search"
35+
name="pi"
36+
placeholder="Search by GID, Name, or Email"
37+
required
38+
>
1739
<div class="searchWrapper" style="display: none;"></div>
1840
</div>
1941
<label>
@@ -23,40 +45,48 @@
2345
Terms of Service
2446
</a>.
2547
</label>
26-
<input type="submit" value="Send Request">
48+
<input type="submit" value="Send Request" disabled>
2749
</form>
2850

2951
<script>
30-
$("input[type=text][name=pi]").keyup(function() {
31-
var searchWrapper = $("div.searchWrapper");
32-
const url = '<?php echo getURL("panel/modal/pi_search.php") ?>';
33-
$.ajax({
34-
url: `${url}?search=` + $(this).val(),
35-
success: function(result) {
36-
searchWrapper.html(result);
37-
38-
if (result == "") {
39-
searchWrapper.hide();
40-
} else {
41-
searchWrapper.show();
52+
(function () {
53+
const input = $("input[name=pi]");
54+
const wrapper = $("div.searchWrapper");
55+
const submit = $("#newPIform > input[type=submit]");
56+
function updateSearch() {
57+
const query = input.val();
58+
$.ajax({
59+
url: '<?php echo getURL("panel/ajax/pi_search.php") ?>',
60+
data: {"search": query},
61+
success: function(data) {
62+
const results = JSON.parse(data);
63+
if (results.length === 0) {
64+
wrapper.html("<span>No Results</span>").show();
65+
submit.prop("disabled", true);
66+
} else if (results.includes(query)) {
67+
// search query exactly matches a PI group GID
68+
wrapper.html("").hide();
69+
submit.prop("disabled", false);
70+
} else {
71+
const html = results.map(gid => `<span>${gid}</span>`).join('');
72+
wrapper.html(html).show();
73+
submit.prop("disabled", true);
74+
}
75+
},
76+
error: function(result) {
77+
const error_msg_div = $("<div></div>");
78+
error_msg_div.html(result.responseText);
79+
submit.after(error_msg_div);
80+
wrapper.html("").hide();
81+
submit.prop("disabled", true);
4282
}
43-
},
44-
error: function (result) {
45-
searchWrapper.html(result.responseText);
46-
searchWrapper.show();
47-
},
83+
});
84+
};
85+
input.on("keyup", () => updateSearch());
86+
wrapper.on("click", "span", function() {
87+
input.val($(this).text());
88+
updateSearch();
4889
});
49-
});
50-
51-
$("div.searchWrapper").on("click", "span", function (event) {
52-
var textBox = $("input[type=text][name=pi]");
53-
textBox.val($(this).html());
54-
});
55-
56-
/**
57-
* Hides the searchresult box on click anywhere
58-
*/
59-
$(document).click(function() {
60-
$("div.searchWrapper").hide();
61-
});
90+
$(document).on("click", () => wrapper.hide());
91+
})();
6292
</script>

webroot/panel/modal/pi_search.php

Lines changed: 0 additions & 49 deletions
This file was deleted.

0 commit comments

Comments
 (0)