added new API call attachmentDownload, fixed attachment URL to call attachmentDownload, refactoring Report.vue for <script setup>
302 lines
7.5 KiB
PHP
302 lines
7.5 KiB
PHP
<?php
|
|
|
|
namespace TPsoft\BugreportBackend;
|
|
|
|
require_once __DIR__ . '/Init.php';
|
|
|
|
use TPsoft\APIlite\APIlite;
|
|
use TPsoft\BugreportBackend\Models\Reports;
|
|
use TPsoft\BugreportBackend\Models\Attachments;
|
|
use TPsoft\BugreportBackend\Models\Options;
|
|
|
|
|
|
class API extends APIlite
|
|
{
|
|
/**
|
|
* Add new report
|
|
*
|
|
* @param string $title
|
|
* @param string $description
|
|
* @param int $status 0 = Uncategorized, 1 = Waiting, 2 = InProgress, 3 = Blocked, 4 = Archived
|
|
* @param string $group
|
|
* @param int $priority 0 = Low, 1 = Medium, 2 = High, 3 = Urgent
|
|
*
|
|
* @return int
|
|
*/
|
|
public function add(string $title, string $description, int $status = 0, ?string $group = null, int $priority = 0): int
|
|
{
|
|
$status = intval($status);
|
|
$priority = intval($priority);
|
|
$reports = new Reports();
|
|
$report_id = $reports->report(null, [
|
|
'report_title' => $title,
|
|
'report_description' => $description,
|
|
'report_status' => $status,
|
|
'report_group' => $group,
|
|
'report_priority' => $priority,
|
|
]);
|
|
return $report_id;
|
|
}
|
|
|
|
/**
|
|
* Update report
|
|
*
|
|
* @param int $report_id
|
|
* @param array $report_data
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function update(int $report_id, array $report_data): bool
|
|
{
|
|
$reports = new Reports();
|
|
$suc = $reports->report($report_id, $report_data);
|
|
return $suc !== false;
|
|
}
|
|
|
|
/**
|
|
* Delete report
|
|
*
|
|
* @param int $report_id
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function delete(int $report_id): bool
|
|
{
|
|
$reports = new Reports();
|
|
$suc = $reports->report($report_id, null);
|
|
return $suc !== false;
|
|
}
|
|
|
|
/**
|
|
* Get report
|
|
*
|
|
* @param int $report_id
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get(int $report_id): array
|
|
{
|
|
$reports = new Reports();
|
|
return $reports->report($report_id);
|
|
}
|
|
|
|
/**
|
|
* Get all reports
|
|
*
|
|
* @param array $status 0 = Uncategorized, 1 = Waiting, 2 = InProgress, 3 = Blocked, 4 = Archived
|
|
* @param int $page Pagination from 0
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getAll(?array $status = null, int $page = 0): array
|
|
{
|
|
$page = intval($page);
|
|
$reports = new Reports();
|
|
if ($status === null) $status = array(0, 1, 2, 3);
|
|
$ret = $reports->search('reports')
|
|
->where(['report_status' => $status])
|
|
->order(array('report_priority' => 'DESC', 'ordnum' => 'ASC'))
|
|
->limit($page * 10, 10)
|
|
->toArray();
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Get all reports grouped by status
|
|
*
|
|
* @param array $status 0 = Uncategorized, 1 = Waiting, 2 = InProgress, 3 = Blocked, 4 = Archived
|
|
* @param int $page Pagination from 0
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getAllGrouped(?array $status = null, int $page = 0): array
|
|
{
|
|
$page = intval($page);
|
|
$all = $this->getAll($status, $page);
|
|
$groups = [];
|
|
foreach ($all as $report) {
|
|
$groups[$report['report_status']][] = $report;
|
|
}
|
|
return $groups;
|
|
}
|
|
|
|
/**
|
|
* Get archived reports
|
|
*
|
|
* @param int $page Pagination from 0
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getArchived(int $page = 0): array
|
|
{
|
|
$page = intval($page);
|
|
$reports = new Reports();
|
|
$ret = $reports->search('reports')
|
|
->where(['report_status' => 4])
|
|
->order(array('created_dt' => 'DESC'))
|
|
->limit($page * 10, 10)
|
|
->toArray();
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Update report order number
|
|
*
|
|
* @param array $ordnums report_id => ordnum
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function updateOrdNum(array $ordnums): bool
|
|
{
|
|
$reports = new Reports();
|
|
$suc = true;
|
|
foreach ($ordnums as $report_id => $ordnum) {
|
|
$suc &= $reports->report($report_id, ['ordnum' => $ordnum]);
|
|
}
|
|
return $suc;
|
|
}
|
|
|
|
/**
|
|
* Update report status
|
|
*
|
|
* @param int $report_id
|
|
* @param int $status 0 = Uncategorized, 1 = Waiting, 2 = InProgress, 3 = Blocked, 4 = Archived
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function updateStatus(int $report_id, int $status): bool
|
|
{
|
|
$reports = new Reports();
|
|
$suc = $reports->report($report_id, ['report_status' => $status]);
|
|
return $suc !== false;
|
|
}
|
|
|
|
/**
|
|
* Add report attachment
|
|
*
|
|
* @param int $report_id
|
|
* @param string $attachment_type "comment" or "file"
|
|
* @param string $attachment_content
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function attachmentAdd(int $report_id, string $attachment_type, string $attachment_content): bool
|
|
{
|
|
if ($attachment_type == 'file') {
|
|
$data = json_decode($attachment_content, true);
|
|
if (!is_array($data)) return false;
|
|
$base64 = preg_replace('/^data:.*?;base64,/', '', $data['base64']);
|
|
$base64_data = base64_decode($base64);
|
|
$filename = 'report_' . $report_id . '_' . time() . '_' . $this->sanitizeFilename($data['filename']);
|
|
file_put_contents(UPLOAD_DIR_ATTACHMENTS . $filename, $base64_data);
|
|
$attachment_content = $filename;
|
|
}
|
|
$attachments = new Attachments();
|
|
$suc = $attachments->attachment(null, [
|
|
'report_id' => $report_id,
|
|
'attachment_type' => $attachment_type,
|
|
'attachment_content' => $attachment_content,
|
|
'created_dt' => date('Y-m-d H:i:s')
|
|
]);
|
|
return $suc !== false;
|
|
}
|
|
|
|
private function sanitizeFilename($filename, $allowedExtensions = [])
|
|
{
|
|
// Rozdelenie názvu a prípony
|
|
$pathInfo = pathinfo($filename);
|
|
$name = $pathInfo['filename'] ?? 'file';
|
|
$extension = strtolower($pathInfo['extension'] ?? '');
|
|
// Odstránenie nebezpečných znakov z názvu
|
|
$name = preg_replace('/[^a-zA-Z0-9_-]/', '_', $name);
|
|
$name = substr($name, 0, 100); // voliteľné obmedzenie dĺžky
|
|
// Validácia prípony, ak je zoznam povolený
|
|
if (
|
|
$allowedExtensions
|
|
&& count($allowedExtensions) > 0
|
|
&& !in_array($extension, $allowedExtensions)
|
|
) {
|
|
$extension = 'bin'; // fallback ak prípona nie je povolená
|
|
}
|
|
return $name . '.' . $extension;
|
|
}
|
|
|
|
/**
|
|
* Update report attachment
|
|
*
|
|
* @param int $attachment_id
|
|
* @param string $attachment_content
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function attachmentUpdate(int $attachment_id, string $attachment_content): bool
|
|
{
|
|
if (strlen(trim($attachment_content)) <= 0) return $this->attachmentDelete($attachment_id);
|
|
$attachments = new Attachments();
|
|
$suc = $attachments->attachment($attachment_id, [
|
|
'attachment_content' => $attachment_content,
|
|
'updated_dt' => date('Y-m-d H:i:s')
|
|
]);
|
|
return $suc !== false;
|
|
}
|
|
|
|
/**
|
|
* Get all report attachments
|
|
*
|
|
* @param int $report_id
|
|
*
|
|
* @return array
|
|
*/
|
|
public function attachmentGetAll(int $report_id): array
|
|
{
|
|
$attachments = new Attachments();
|
|
$all = $attachments->search('attachments')
|
|
->where(['report_id' => $report_id])
|
|
->order(array('created_dt' => 'ASC'))
|
|
->toArray();
|
|
if (is_array($all)) foreach ($all as $key => $row) {
|
|
if ($all[$key]['attachment_type'] == 'file') {
|
|
$all[$key]['attachment_content'] = '?action=attachmentDownload&filename=' . $all[$key]['attachment_content'];
|
|
}
|
|
}
|
|
return $all;
|
|
}
|
|
|
|
/**
|
|
* Delete report attachment
|
|
*
|
|
* @param int $attachment_id
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function attachmentDelete(int $attachment_id): bool {
|
|
$attachments = new Attachments();
|
|
$suc = $attachments->attachment($attachment_id, null);
|
|
return $suc !== false;
|
|
}
|
|
|
|
/**
|
|
* Download report attachment
|
|
*
|
|
* @param string $filename
|
|
*
|
|
* @return void
|
|
*/
|
|
public function attachmentDownload(string $filename): void {
|
|
$filename = $this->sanitizeFilename($filename);
|
|
$filename = UPLOAD_DIR_ATTACHMENTS . $filename;
|
|
if (file_exists($filename)) {
|
|
header('Content-Description: File Transfer');
|
|
header('Content-Type: application/octet-stream');
|
|
header('Content-Disposition: attachment; filename="' . basename($filename) . '"');
|
|
header('Expires: 0');
|
|
header('Cache-Control: must-revalidate');
|
|
header('Pragma: public');
|
|
header('Content-Length: ' . filesize($filename));
|
|
readfile($filename);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
}
|