- add Figma API endpoints for summary, users, snapshots, comments, and admin sync - support date and user filters plus pagination for snapshots and comments - expand sync service and schema to store Figma user ids - refresh dashboard UI with summary cards, filters, pagination, and sync action - fold figma_user_id into base migration and remove extra migration
250 lines
6.6 KiB
PHP
250 lines
6.6 KiB
PHP
<?php
|
|
|
|
namespace App\Controllers\Api;
|
|
|
|
use App\Controllers\BaseController;
|
|
use App\Libraries\FigmaSyncService;
|
|
use CodeIgniter\API\ResponseTrait;
|
|
|
|
class FigmaApi extends BaseController
|
|
{
|
|
use ResponseTrait;
|
|
|
|
private function ensureLoggedIn()
|
|
{
|
|
if (!session()->get('userid')) {
|
|
return $this->respond([
|
|
'status' => 'error',
|
|
'message' => 'Unauthorized',
|
|
], 401);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function ensureAdmin()
|
|
{
|
|
$level = (int) session()->get('level');
|
|
if (!in_array($level, [0, 1, 2], true)) {
|
|
return $this->respond([
|
|
'status' => 'error',
|
|
'message' => 'Forbidden. Admin only.',
|
|
], 403);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function normalizeUsername(?string $username): ?string
|
|
{
|
|
$username = trim((string) $username);
|
|
return $username === '' ? null : mb_strtolower($username);
|
|
}
|
|
|
|
public function summary()
|
|
{
|
|
if ($response = $this->ensureLoggedIn()) {
|
|
return $response;
|
|
}
|
|
|
|
$db = \Config\Database::connect();
|
|
$file = $db->table('figma_files')->orderBy('id', 'DESC')->get()->getRowArray();
|
|
$versionsCount = $db->table('figma_file_versions')->countAllResults();
|
|
$commentsCount = $db->table('figma_comments')->countAllResults();
|
|
$latestVersion = $db->table('figma_file_versions')->orderBy('created_at_figma', 'DESC')->get()->getRowArray();
|
|
$latestComment = $db->table('figma_comments')->selectMax('created_at_figma', 'latest')->get()->getRowArray();
|
|
|
|
return $this->respond([
|
|
'status' => 'success',
|
|
'message' => 'Summary fetched',
|
|
'data' => [
|
|
'file' => $file,
|
|
'versions' => $versionsCount,
|
|
'comments' => $commentsCount,
|
|
'latest_version_at' => $latestVersion['created_at_figma'] ?? null,
|
|
'latest_version_label' => $latestVersion['label'] ?? $latestVersion['version'] ?? null,
|
|
'latest_version_description' => $latestVersion['description'] ?? null,
|
|
'latest_comment_at' => $latestComment['latest'] ?? null,
|
|
],
|
|
], 200);
|
|
}
|
|
|
|
public function users()
|
|
{
|
|
if ($response = $this->ensureLoggedIn()) {
|
|
return $response;
|
|
}
|
|
|
|
$db = \Config\Database::connect();
|
|
$versionUsers = $db->table('figma_file_versions')
|
|
->select('user_name')
|
|
->where('user_name IS NOT NULL', null, false)
|
|
->where('user_name !=', '')
|
|
->get()
|
|
->getResultArray();
|
|
|
|
$commentUsers = $db->table('figma_comments')
|
|
->select('user_name')
|
|
->where('user_name IS NOT NULL', null, false)
|
|
->where('user_name !=', '')
|
|
->get()
|
|
->getResultArray();
|
|
|
|
$users = [];
|
|
foreach (array_merge($versionUsers, $commentUsers) as $row) {
|
|
$name = trim((string) ($row['user_name'] ?? ''));
|
|
if ($name === '') {
|
|
continue;
|
|
}
|
|
|
|
$key = mb_strtolower($name);
|
|
if (!isset($users[$key])) {
|
|
$users[$key] = $name;
|
|
}
|
|
}
|
|
|
|
$rows = array_values($users);
|
|
sort($rows, SORT_NATURAL | SORT_FLAG_CASE);
|
|
|
|
return $this->respond([
|
|
'status' => 'success',
|
|
'message' => 'Users fetched',
|
|
'data' => $rows,
|
|
], 200);
|
|
}
|
|
|
|
private function getPaginationParams(): array
|
|
{
|
|
$page = (int) ($this->request->getGet('page') ?? 1);
|
|
if ($page <= 0) {
|
|
$page = 1;
|
|
}
|
|
|
|
$perPage = (int) ($this->request->getGet('per_page') ?? $this->request->getGet('limit') ?? 25);
|
|
if ($perPage <= 0 || $perPage > 100) {
|
|
$perPage = 25;
|
|
}
|
|
|
|
return [$page, $perPage];
|
|
}
|
|
|
|
public function snapshots()
|
|
{
|
|
if ($response = $this->ensureLoggedIn()) {
|
|
return $response;
|
|
}
|
|
|
|
$startDate = $this->request->getGet('start_date');
|
|
$endDate = $this->request->getGet('end_date');
|
|
$username = $this->normalizeUsername($this->request->getGet('username'));
|
|
[$page, $perPage] = $this->getPaginationParams();
|
|
$offset = ($page - 1) * $perPage;
|
|
|
|
$db = \Config\Database::connect();
|
|
$baseBuilder = $db->table('figma_file_versions v')
|
|
->join('figma_files f', 'f.id = v.file_id', 'inner');
|
|
|
|
if (!empty($startDate)) {
|
|
$baseBuilder->where('v.created_at_figma >=', $startDate . ' 00:00:00');
|
|
}
|
|
|
|
if (!empty($endDate)) {
|
|
$baseBuilder->where('v.created_at_figma <=', $endDate . ' 23:59:59');
|
|
}
|
|
|
|
if (!empty($username)) {
|
|
$baseBuilder->where('LOWER(TRIM(v.user_name)) = ' . $db->escape($username), null, false);
|
|
}
|
|
|
|
$total = (int) (clone $baseBuilder)->countAllResults();
|
|
$rows = $baseBuilder
|
|
->select('v.id, v.figma_version_id, v.version, v.label, v.description, v.name, v.editor_type, v.figma_user_id, v.user_name, v.last_modified_figma, v.created_at_figma, f.file_key, f.last_synced_at')
|
|
->orderBy('v.created_at_figma', 'DESC')
|
|
->limit($perPage, $offset)
|
|
->get()
|
|
->getResultArray();
|
|
|
|
return $this->respond([
|
|
'status' => 'success',
|
|
'message' => 'Snapshots fetched',
|
|
'data' => $rows,
|
|
'meta' => [
|
|
'total' => $total,
|
|
'page' => $page,
|
|
'per_page' => $perPage,
|
|
'total_pages' => $perPage > 0 ? (int) ceil($total / $perPage) : 0,
|
|
],
|
|
], 200);
|
|
}
|
|
|
|
public function comments()
|
|
{
|
|
if ($response = $this->ensureLoggedIn()) {
|
|
return $response;
|
|
}
|
|
|
|
$startDate = $this->request->getGet('start_date');
|
|
$endDate = $this->request->getGet('end_date');
|
|
$username = $this->normalizeUsername($this->request->getGet('username'));
|
|
[$page, $perPage] = $this->getPaginationParams();
|
|
$offset = ($page - 1) * $perPage;
|
|
|
|
$db = \Config\Database::connect();
|
|
$baseBuilder = $db->table('figma_comments c')
|
|
->join('figma_files f', 'f.id = c.file_id', 'inner');
|
|
|
|
if (!empty($startDate)) {
|
|
$baseBuilder->where('c.created_at_figma >=', $startDate . ' 00:00:00');
|
|
}
|
|
|
|
if (!empty($endDate)) {
|
|
$baseBuilder->where('c.created_at_figma <=', $endDate . ' 23:59:59');
|
|
}
|
|
|
|
if (!empty($username)) {
|
|
$baseBuilder->where('LOWER(TRIM(c.user_name)) = ' . $db->escape($username), null, false);
|
|
}
|
|
|
|
$total = (int) (clone $baseBuilder)->countAllResults();
|
|
$rows = $baseBuilder
|
|
->select('c.id, c.figma_comment_id, c.user_name, c.message, c.is_resolved, c.resolved_at, c.created_at_figma, c.client_meta_json, f.file_key')
|
|
->orderBy('c.created_at_figma', 'DESC')
|
|
->limit($perPage, $offset)
|
|
->get()
|
|
->getResultArray();
|
|
|
|
return $this->respond([
|
|
'status' => 'success',
|
|
'message' => 'Comments fetched',
|
|
'data' => $rows,
|
|
'meta' => [
|
|
'total' => $total,
|
|
'page' => $page,
|
|
'per_page' => $perPage,
|
|
'total_pages' => $perPage > 0 ? (int) ceil($total / $perPage) : 0,
|
|
],
|
|
], 200);
|
|
}
|
|
|
|
public function sync()
|
|
{
|
|
if ($response = $this->ensureLoggedIn()) {
|
|
return $response;
|
|
}
|
|
|
|
if ($response = $this->ensureAdmin()) {
|
|
return $response;
|
|
}
|
|
|
|
$service = new FigmaSyncService();
|
|
$result = $service->syncIncremental(1);
|
|
|
|
$statusCode = $result['success'] ? 200 : 500;
|
|
return $this->respond([
|
|
'status' => $result['success'] ? 'success' : 'error',
|
|
'message' => $result['message'],
|
|
'data' => $result['stats'] ?? [],
|
|
], $statusCode);
|
|
}
|
|
}
|