Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "compucie/database",
"description": "Library of database managers used by Newton's systems.",
"version": "6.0.1",
"version": "6.2.0",
"type": "library",
"license": "MIT",
"autoload": {
Expand Down
93 changes: 92 additions & 1 deletion src/Event/EventDatabaseManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

namespace Compucie\Database\Event;

use Exception;
use Compucie\Database\DatabaseManager;
use Compucie\Database\Event\Model\PinnedEvent;
use DateTime;
use InvalidArgumentException;
use mysqli_sql_exception;
use function Compucie\Database\safeDateTime;

class EventDatabaseManager extends DatabaseManager
{
Expand Down Expand Up @@ -46,12 +49,89 @@ public function getCurrentlyPinnedEventIds(): array
);
}

/**
* @return array<int>
* @throws mysqli_sql_exception
*/
public function getPinnedEventIds(): array
{
$rows = $this->executeReadAll(
"SELECT `event_id`
FROM `pins`"
);

return array_map(
static fn(array $row): int => (int)$row['event_id'],
$rows
);
}

/**
* @return array<PinnedEvent>
* @throws mysqli_sql_exception
*/
public function getPinnedEvents(): array
{
$rows = $this->executeReadAll(
"SELECT `pin_id`, `event_id`, `start_at`, `end_at`
FROM `pins`"
);

$pinnedEvents = [];

foreach ($rows as $row) {
$pinnedEvents[] = new PinnedEvent(
(int) $row['pin_id'],
(int) $row['event_id'],
safeDateTime((string)$row['start_at']),
safeDateTime((string)$row['end_at'])
);
}
return $pinnedEvents;
}

/**
* @param int $pinId
* @return PinnedEvent|null
* @throws Exception
* @throws mysqli_sql_exception
*/
public function getPinnedEvent(int $pinId): ?PinnedEvent
{
if ($pinId <= 0){
return null;
}

$row = $this->executeReadOne(
"SELECT `pin_id`, `event_id`, `start_at`, `end_at`
FROM `pins`
WHERE `pin_id` = ?",
[$pinId],
"i"
);

if ($row === null){
throw new Exception("Pinned event $pinId not found");
}

return new PinnedEvent(
$pinId,
(int) $row['event_id'],
safeDateTime((string)$row['start_at']),
safeDateTime((string)$row['end_at'])
);
}

/**
* Insert an event pin.
* @param int $eventId
* @param DateTime|null $startAt
* @param DateTime|null $endAt
* @return int
* @throws mysqli_sql_exception
* @throws InvalidArgumentException
*/
public function insertPin(int $eventId, DateTime $startAt = null, DateTime $endAt = null): int
public function insertPin(int $eventId, ?DateTime $startAt = null, ?DateTime $endAt = null): int
{
if ($endAt !== null && $endAt < ($startAt ?? new DateTime())) {
throw new InvalidArgumentException('endAt must be after startAt');
Expand All @@ -72,6 +152,7 @@ public function insertPin(int $eventId, DateTime $startAt = null, DateTime $endA

/**
* Update an event pin.
* @throws InvalidArgumentException
* @throws mysqli_sql_exception
*/
public function updatePin(int $eventId, ?DateTime $startAt = null, ?DateTime $endAt = null): bool
Expand All @@ -97,4 +178,14 @@ public function updatePin(int $eventId, ?DateTime $startAt = null, ?DateTime $en
'ss'
);
}

/**
* @param int $pinId
* @return bool
* @throws mysqli_sql_exception
*/
public function deletePin(int $pinId): bool
{
return $this->executeDelete('pins', 'pin_id', $pinId);
}
}
42 changes: 42 additions & 0 deletions src/Event/Model/PinnedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Compucie\Database\Event\Model;

use DateTime;

readonly class PinnedEvent
{
/**
* @param int $id
* @param int $eventId
* @param DateTime $startAt
* @param DateTime $endAt
*/
public function __construct(
private int $id,
private int $eventId,
private DateTime $startAt,
private DateTime $endAt
) {
}

public function getId(): int
{
return $this->id;
}

public function getEventId(): int
{
return $this->eventId;
}

public function getStartAt(): DateTime
{
return $this->startAt;
}

public function getEndAt(): DateTime
{
return $this->endAt;
}
}
33 changes: 33 additions & 0 deletions src/Member/Model/MemberAccess.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Compucie\Database\Member\Model;

readonly class MemberAccess
{
/**
* @param int $congressusMemberId
* @param string $reason
* @param bool $hasAccess
*/
public function __construct(
private int $congressusMemberId,
private string $reason,
private bool $hasAccess
) {
}

public function getCongressusMemberId(): int
{
return $this->congressusMemberId;
}

public function getReason(): string
{
return $this->reason;
}

public function getHasAccess(): bool
{
return $this->hasAccess;
}
}
164 changes: 164 additions & 0 deletions src/Member/RfidTableManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Compucie\Database\Member\Exceptions\ActivationTokenNotFoundException;
use Compucie\Database\Member\Exceptions\CardNotRegisteredException;
use Compucie\Database\Member\Model\MemberAccess;
use DateTime;
use Exception;
use mysqli;
Expand All @@ -30,6 +31,19 @@ protected function createRfidTable(): void
$statement->execute();
$statement->close();
}

$statement = $this->getClient()->prepare(
"CREATE TABLE IF NOT EXISTS `access` (
`congressus_member_id` INT NOT NULL,
`reason` VARCHAR(255) DEFAULT NULL,
`has_access` BOOLEAN NOT NULL DEFAULT FALSE,
PRIMARY KEY (`congressus_member_id`)
);"
);
if ($statement){
$statement->execute();
$statement->close();
}
}

/**
Expand Down Expand Up @@ -176,4 +190,154 @@ public function deleteMembersActivatedRegistrations(int $congressusMemberId): bo
['`is_email_confirmed` = TRUE']
);
}

/**
* @param int $congressusMemberId
* @param string $reason
* @param bool $hasAccess
* @return int
* @throws mysqli_sql_exception
*/
public function addMemberAccess(int $congressusMemberId, string $reason, bool $hasAccess = false): int
{
return $this->executeCreate(
"access",
["`congressus_member_id`", "`reason`", "`has_access`"],
[
$congressusMemberId,
$reason,
$hasAccess,
],
"isi"
);
}

/**
* @return array<MemberAccess>
* @throws mysqli_sql_exception
*/
public function getAllMemberAccesses(): array
{
$rows = $this->executeReadAll(
"SELECT `congressus_member_id`, `reason`, `has_access`
FROM `access`"
);

$memberAccesses = [];

foreach ($rows as $row) {
$memberAccesses[] = new MemberAccess(
(int) $row['congressus_member_id'],
$row['reason'],
(bool)$row['has_access']
);
}
return $memberAccesses;
}

/**
* @param int $congressusMemberId
* @return MemberAccess|null
* @throws Exception
* @throws mysqli_sql_exception
*/
public function getMemberAccesses(int $congressusMemberId): ?MemberAccess
{
if ($congressusMemberId <= 0){
return null;
}

$row = $this->executeReadOne(
"SELECT `congressus_member_id`, `reason`, `has_access`
FROM `access`
WHERE `congressus_member_id` = ?",
[$congressusMemberId],
"i"
);

if ($row === null){
throw new Exception("Member access for $congressusMemberId not found");
}

return new MemberAccess(
$congressusMemberId,
$row['reason'],
(bool)$row['has_access']
);
}

/**
* @param int $congressusMemberId
* @param string|null $reason
* @param bool|null $hasAccess
* @param bool $clearReason
* @return bool
* @throws mysqli_sql_exception
*/
public function updateMemberAccess(
int $congressusMemberId,
?string $reason = null,
?bool $hasAccess = null,
bool $clearReason = false
): bool {
$fields = [];
$params = [];
$types = '';

if ($clearReason) {
$fields[] = 'reason = NULL';
} elseif ($reason !== null) {
$fields[] = 'reason = ?';
$params[] = $reason;
$types .= 's';
}

if ($hasAccess !== null) {
$fields[] = 'has_access = ?';
$params[] = $hasAccess;
$types .= 'i';
}

return $this->executeUpdate('access', 'congressus_member_id', $congressusMemberId, $fields, $params, $types);
}

/**
* @param int $congressusMemberId
* @param string $reason
* @return bool
* @throws mysqli_sql_exception
* @throws Exception
*/
public function revokeMemberAccess(int $congressusMemberId, string $reason): bool
{
if ($reason === "") {
throw new Exception("Revoke member access reason cannot be empty");
}
return $this->updateMemberAccess($congressusMemberId, $reason, false);
}

/**
* @param int $congressusMemberId
* @param string $reason
* @return bool
* @throws mysqli_sql_exception
* @throws Exception
*/
public function approveMemberAccess(int $congressusMemberId, string $reason): bool
{
if ($reason === "") {
throw new Exception("Approve member access reason cannot be empty");
}
return $this->updateMemberAccess($congressusMemberId, $reason, true);
}

/**
* @param int $congressusMemberId
* @return bool
* @throws mysqli_sql_exception
*/
public function deleteMemberAccess(int $congressusMemberId): bool
{
return $this->executeDelete("access", "congressus_member_id", $congressusMemberId);
}
}
Loading