mahdahar 836618eaaf Add paginated git API and dashboard controls
- Add shared pagination params and meta output for commits and pull requests API endpoints.
- Switch dashboard lists to page-based loading with prev/next controls and total counters.
- Add safer HTML escaping and initial empty-state placeholders in gitea dashboard.
2026-04-23 08:33:18 +07:00

266 lines
7.1 KiB
PHP

<?php
namespace App\Controllers\Api;
use App\Controllers\BaseController;
use App\Libraries\GiteaSyncService;
use CodeIgniter\API\ResponseTrait;
class GitApi 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;
}
public function summary()
{
if ($response = $this->ensureLoggedIn()) {
return $response;
}
$db = \Config\Database::connect();
$usersCount = $db->table('git_users')->countAllResults();
$repositoriesCount = $db->table('git_repositories')->countAllResults();
$commitsCount = $db->table('git_commits')->countAllResults();
$pullRequestsCount = $db->table('git_pull_requests')->countAllResults();
$latestCommit = $db->table('git_commits')->selectMax('committed_at', 'latest')->get()->getRowArray();
$latestPullRequest = $db->table('git_pull_requests')->selectMax('updated_at_gitea', 'latest')->get()->getRowArray();
$latestRepoSync = $db->table('git_repositories')->selectMax('last_synced_at', 'latest')->get()->getRowArray();
return $this->respond([
'status' => 'success',
'message' => 'Summary fetched',
'data' => [
'users' => $usersCount,
'repositories' => $repositoriesCount,
'commits' => $commitsCount,
'pull_requests' => $pullRequestsCount,
'latest_commit_at' => $latestCommit['latest'] ?? null,
'latest_pull_request_at' => $latestPullRequest['latest'] ?? null,
'last_synced_at' => $latestRepoSync['latest'] ?? null,
],
], 200);
}
public function users()
{
if ($response = $this->ensureLoggedIn()) {
return $response;
}
$db = \Config\Database::connect();
$rows = $db->table('git_users')
->select('id, gitea_user_id, username, full_name, email, is_active, is_admin, last_synced_at')
->orderBy('username', 'ASC')
->get()
->getResultArray();
return $this->respond([
'status' => 'success',
'message' => 'Users fetched',
'data' => $rows,
], 200);
}
public function repositories()
{
if ($response = $this->ensureLoggedIn()) {
return $response;
}
$db = \Config\Database::connect();
$rows = $db->table('git_repositories r')
->select('r.id, r.gitea_repo_id, r.name, r.full_name, r.owner_username, r.default_branch, r.is_private, r.last_pushed_at, r.last_synced_at, u.username as owner_login')
->join('git_users u', 'u.id = r.owner_user_id', 'left')
->orderBy('r.full_name', 'ASC')
->get()
->getResultArray();
return $this->respond([
'status' => 'success',
'message' => 'Repositories 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 commits()
{
if ($response = $this->ensureLoggedIn()) {
return $response;
}
$repoId = $this->request->getGet('repo_id');
$userId = $this->request->getGet('user_id');
$startDate = $this->request->getGet('start_date');
$endDate = $this->request->getGet('end_date');
[$page, $perPage] = $this->getPaginationParams();
$offset = ($page - 1) * $perPage;
$db = \Config\Database::connect();
$baseBuilder = $db->table('git_commits c')
->join('git_repositories r', 'r.id = c.repository_id', 'inner')
->join('git_users u', 'u.id = c.author_user_id', 'left');
if (!empty($repoId)) {
$baseBuilder->where('c.repository_id', (int) $repoId);
}
if (!empty($userId)) {
$baseBuilder->where('c.author_user_id', (int) $userId);
}
if (!empty($startDate)) {
$baseBuilder->where('c.committed_at >=', $startDate . ' 00:00:00');
}
if (!empty($endDate)) {
$baseBuilder->where('c.committed_at <=', $endDate . ' 23:59:59');
}
$total = (int) (clone $baseBuilder)
->countAllResults();
$rows = $baseBuilder
->select('c.id, c.sha, c.short_sha, c.message, c.author_name, c.author_email, c.committed_at, c.html_url, r.id as repository_id, r.full_name as repository_full_name, u.id as user_id, u.username as user_username')
->orderBy('c.committed_at', 'DESC')
->limit($perPage, $offset)
->get()
->getResultArray();
return $this->respond([
'status' => 'success',
'message' => 'Commits fetched',
'data' => $rows,
'meta' => [
'total' => $total,
'page' => $page,
'per_page' => $perPage,
'total_pages' => $perPage > 0 ? (int) ceil($total / $perPage) : 0,
],
], 200);
}
public function pullRequests()
{
if ($response = $this->ensureLoggedIn()) {
return $response;
}
$repoId = $this->request->getGet('repo_id');
$userId = $this->request->getGet('user_id');
$state = $this->request->getGet('state');
$startDate = $this->request->getGet('start_date');
$endDate = $this->request->getGet('end_date');
[$page, $perPage] = $this->getPaginationParams();
$offset = ($page - 1) * $perPage;
$db = \Config\Database::connect();
$baseBuilder = $db->table('git_pull_requests p')
->join('git_repositories r', 'r.id = p.repository_id', 'inner')
->join('git_users u', 'u.id = p.author_user_id', 'left');
if (!empty($repoId)) {
$baseBuilder->where('p.repository_id', (int) $repoId);
}
if (!empty($userId)) {
$baseBuilder->where('p.author_user_id', (int) $userId);
}
if (!empty($state)) {
$baseBuilder->where('p.state', $state);
}
if (!empty($startDate)) {
$baseBuilder->where('p.updated_at_gitea >=', $startDate . ' 00:00:00');
}
if (!empty($endDate)) {
$baseBuilder->where('p.updated_at_gitea <=', $endDate . ' 23:59:59');
}
$total = (int) (clone $baseBuilder)
->countAllResults();
$rows = $baseBuilder
->select('p.id, p.number, p.title, p.state, p.is_draft, p.is_merged, p.created_at_gitea, p.updated_at_gitea, p.merged_at, p.closed_at, p.html_url, r.id as repository_id, r.full_name as repository_full_name, u.id as user_id, u.username as user_username')
->orderBy('p.updated_at_gitea', 'DESC')
->limit($perPage, $offset)
->get()
->getResultArray();
return $this->respond([
'status' => 'success',
'message' => 'Pull requests 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 GiteaSyncService();
$result = $service->syncAll();
$statusCode = $result['success'] ? 200 : 500;
return $this->respond([
'status' => $result['success'] ? 'success' : 'error',
'message' => $result['message'],
'data' => $result['stats'] ?? [],
], $statusCode);
}
}