SpreadQuiz/class/GroupMgr.php
Epagris 139c3aa38d - Game to group assignments management added
- Printing of group and game IDs added
- some bugfixes
2024-10-07 20:47:27 +02:00

431 lines
13 KiB
PHP

<?php
require_once "vendor/autoload.php";
require_once "AutoStoring.php";
require_once "privilege_levels.php";
class Group extends AutoStoring
{
private int $_id; // Group's ID (assigned by SleekDB)
private string $name; // Group's name
private bool $unique; // Indicates if name is unique or not
private string $owner; // Group owner's nickname
private string $description; // Group description
private array $editors; // Nicknames of users able to manage the group
private array $members; // Nickname of group members
private array $games; // Game IDs assigned to this group
private GroupMgr $groupMgr; // Reference to GroupMgr object managing this group
// --------------
// store modifications to the database
public function storeMods() : void
{
$this->groupMgr->updateGroup($this);
}
// --------------
function __construct(GroupMgr &$groupMgr, string $name, string $description, string $owner, int $id = -1, bool $unique = true, array $editors = [], array $members = [], array $games = [])
{
parent::__construct();
$this->_id = $id;
$this->name = $name;
$this->unique = $unique;
$this->description = $description;
$this->owner = $owner;
$this->editors = $editors;
$this->members = $members;
$this->games = $games;
$this->groupMgr = &$groupMgr;
}
// Create Group from array
static function fromArray(GroupMgr &$groupMgr, array $a): Group
{
$id = $a["_id"] ?? -1;
return new Group($groupMgr, $a["groupname"], $a["description"], $a["owner"], $id, $a["unique"], $a["editors"], $a["users"], $a["games"]);
}
// Convert Group to array
function toArray(array $omit = []): array
{
$a = [
"_id" => $this->_id,
"groupname" => $this->name,
"unique" => $this->unique,
"description" => $this->description,
"owner" => $this->owner,
"editors" => $this->editors,
"users" => $this->members,
"games" => $this->games
];
foreach ($omit as $field) {
unset($a[$field]);
}
return $a;
}
// Get group's ID.
function getID(): int
{
return $this->_id;
}
// Get group's name.
function getName(): string
{
return $this->name;
}
// Set group's name.
function setName(string $name): void
{
$this->name = $name;
$this->storeMods();
}
// Tell if group is unique
function isUnique(): bool
{
return $this->unique;
}
// Get group's description.
function getDescription(): string
{
return $this->description;
}
// Set group's description.
function setDescription(string $description): void
{
$this->description = $description;
$this->storeMods();
}
// Get group's owner.
function getOwner(): string
{
return $this->owner;
}
// Set group's owner.
function setOwner(string $owner): void
{
$this->owner = $owner;
$this->storeMods();
}
// Get list of editors.
function getEditors(): array
{
return $this->editors;
}
// Set editors.
function setEditors(array $editors): void
{
$this->editors = $editors;
$this->storeMods();
}
// Get group members.
function getMembers(): array
{
return $this->members;
}
// Set group members.
function setMembers(array $members): void
{
$this->members = $members;
$this->storeMods();
}
// Get games.
function getGames(): array
{
return $this->games;
}
// Set games.
function setGames(array $games): void
{
$this->games = $games;
$this->storeMods();
}
// Include/exclude members.
function changeMembers(array $nicknames_add, array $nicknames_remove): void
{
foreach ($nicknames_add as $nickname) { // add members
alter_array_contents($this->members, $nickname, null);
}
foreach ($nicknames_remove as $nickname) { // remove members
alter_array_contents($this->members, null, $nickname); // delete from members
alter_array_contents($this->editors, null, $nickname); // delete from editors
}
$this->storeMods(); // store changes
}
// Add members
function addMembers(array $nicknames) : void {
$this->changeMembers($nicknames, []);
}
// Remove members
function removeMembers(array $nicknames) : void {
$this->changeMembers([], $nicknames);
}
// Include/exclude games.
function changeGames(array $gameids_add, array $gameids_remove): void
{
foreach ($gameids_add as $gameid) { // add games
alter_array_contents($this->games, $gameid, null);
}
foreach ($gameids_remove as $gameid) { // remove games
alter_array_contents($this->games, null, $gameid);
}
$this->storeMods(); // store changes
}
// Returns whether the user is an editor of this group.
function isUserEditor(string $nickname): bool
{
return in_array($nickname, $this->editors);
}
// Returns whether the user is an editor or the owner of the group.
function isUserContributor(string $nickname): bool
{
return $this->isUserEditor($nickname) || ($this->owner === $nickname);
}
// Returns if user is member of the group.
function isMember(string $nickname): bool
{
return in_array($nickname, $this->members);
}
// Return if game is assigned to this group.
function isGameAssigned(string $gameid): bool
{
return in_array($gameid, $this->games);
}
// Get groups unique name.
function getUniqueName(): string
{
return $this->name . ($this->unique ? "" : ("#" . $this->_id));
}
}
class GroupMgr
{
private \SleekDB\Store $db; // database
// -------------------------
public function manageTwins(int $current_group_id, string $groupname): bool
{
// make test on name uniqueness
$twins = $this->db->findBy([["groupname", "=", "$groupname"], "AND", ["_id", "!=", $current_group_id]]);
$unique = count($twins) == 0;
if (count($twins) === 1) { // if fails, then also indicate in the original group that its name is no longer unique
$twins[0]["unique"] = false;
$this->db->update($twins[0]); // UPDATE WITHOUT CONVERTING TO GROUP OBJECT!! BE CAREFUL!
}
return $unique;
}
// -------------------------
function __construct()
{
$this->db = new \SleekDB\Store(GROUPDB, DATADIR, ["timeout" => false]);
}
// Get group by ID.
function getGroup(string $groupid): Group|null
{
$group_data_array = $this->db->findById($groupid);
return count($group_data_array) != 0 ? Group::fromArray($this, $group_data_array) : null;
}
// Update group.
function updateGroup(Group $group): void
{
$a = $group->toArray();
$this->db->update($a);
}
// Add a new group.
function addGroup(string $groupname, string $owner, string $description = ""): bool
{
// test name uniqueness
$unique = $this->manageTwins(0, $groupname);
// initialize group data
$group_data = [
"groupname" => $groupname,
"unique" => $unique,
"owner" => $owner,
"description" => $description,
"editors" => [],
"users" => [],
"games" => []
];
$group = Group::fromArray($this, $group_data); // create group
$this->db->insert($group->toArray(["_id"])); // insert group
return true;
}
// Delete group.
function deleteGroup(string $groupid): void
{
//$group = $this->getGroup($groupid);
//if ($group != null) {
$this->db->deleteById($groupid);
//}
}
// Get all groups.
function getAllGroups(): array
{
return array_map(fn($a): Group => Group::fromArray($this, $a), $this->db->findAll());
}
// Search groups.
function searchGroups(string $needle, bool $infoOnly = true): array
{
if (strlen($needle) < 3) {
return [];
}
$parts = explode("#", $needle, 2);
$groupname = $parts[0];
$group_data_array = [];
if (count($parts) === 1) {
$group_data_array = $this->db->findBy(["groupname", "LIKE", "%$groupname%"]);
} else if (count($parts) > 1) {
$groupid = $parts[1];
$group_data_array = $this->db->findBy([["groupname", "LIKE", "%$groupname%"], "AND", ["_id", "LIKE", "%$groupid%"]]);
}
$results = [];
foreach ($group_data_array as $group_data) {
if ($infoOnly) {
$results[] = [
"groupname" => $group_data["groupname"],
"_id" => $group_data["_id"],
"unique" => $group_data["unique"]
];
} else {
$results[] = Group::fromArray($this, $group_data);
}
}
return $results;
}
// Get group IDs by the group compounds (name#ID).
function getGroupIdsByCompounds(array $compounds): array
{
$groupids = [];
foreach ($compounds as $compound) {
if (trim($compound) === "") { // skip empty entries
continue;
}
// fetch the group
$parts = explode("#", $compound);
$group_data = [];
if (count($parts) === 1) {
$fetch_cmd = ["groupname", "=", $parts[0]];
$group_data = $this->db->findBy($fetch_cmd);
if (count($group_data) == 1) { // too many hits
$group_data = $group_data[0];
} else {
$group_data = [];
}
} else {
$group_data = $this->db->findById($parts[1]);
}
if ($group_data !== []) {
$groupids[] = $group_data["_id"];
}
}
return $groupids;
}
// cache for converting group ID's to unique group names
private array $groupid_cache = [];
// Convert group IDs into unique group names IN PLACE!
function resolveGroupIds(array &$groupids): void
{
foreach ($groupids as &$groupid) {
if (!array_key_exists($groupid, $this->groupid_cache)) {
$group = $this->getGroup($groupid); // fetch group
$unique_name = $group->getUniqueName(); // get group's unique name
$this->groupid_cache[$groupid] = $unique_name; // store into the cache so that subsequent queries will be somewhat faster
}
$groupid = $this->groupid_cache[$groupid]; // replace with the unique name
}
}
// Check if a user has access to a game, i.e. there's at least a single group that contains both the user and the game.
function doesUserAccessGame(string $gameid, string $nickname): bool {
$intersection = $this->db->findOneBy([["games", "CONTAINS", (int)$gameid], "AND", ["users", "CONTAINS", $nickname]]);
return $intersection !== null;
}
// Get user's groups IDs.
function getUserGroupIDs(string $nickname) : array {
$qb = $this->db->createQueryBuilder();
$a = $qb->where(["users", "CONTAINS", $nickname])->select(["_id"])->getQuery()->fetch();
return array_map(fn($r) => $r["_id"], $a);
}
// Get game's group IDs.
function getGameGroupIDs(string $gameid) : array {
$qb = $this->db->createQueryBuilder();
$a = $qb->where(["games", "CONTAINS", (int)$gameid])->select(["_id"])->getQuery()->fetch();
return array_map(fn($r) => $r["_id"], $a);
}
// Get group by group compound (name#id).
function getGroupByUniqueName(string $uniqueName): Group|null {
$a = $this->db->findOneBy([ function($g) use ($uniqueName) : bool {
$group = Group::fromArray($this, $g);
return $group->getUniqueName() === $uniqueName;
}]);
if ($a !== null) {
return Group::fromArray($this, $a);
} else {
return null;
}
}
// Get the union of all members in the groups specified
function getJoinedMembersByUniqueNames(array $uniqueNames) : array {
$nicknames = [];
foreach ($uniqueNames as $uniqueName) {
$group = $this->getGroupByUniqueName($uniqueName);
if ($group !== null) {
$nicknames = array_merge($nicknames, $group->getMembers());
}
}
return $nicknames;
}
}