344 lines
13 KiB
PHP
344 lines
13 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Helper\Cache\UserJiraCacheHelper;
|
|
use App\Models\User;
|
|
use GuzzleHttp\Client;
|
|
use GuzzleHttp\Promise\Utils;
|
|
|
|
class JiraService
|
|
{
|
|
protected $client;
|
|
protected $baseUrl;
|
|
protected $authHeader;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->baseUrl = env('JIRA_BASE_URL');
|
|
$this->authHeader = 'Basic ' . base64_encode(env('JIRA_USERNAME') . ':' . env('JIRA_API_TOKEN'));
|
|
$this->client = new Client([
|
|
'base_uri' => $this->baseUrl,
|
|
'headers' => [
|
|
'Authorization' => $this->authHeader,
|
|
'Accept' => 'application/json',
|
|
'Content-Type' => 'application/json'
|
|
],
|
|
'timeout' => 60, // Tăng thời gian timeout lên 60 giây
|
|
'connect_timeout' => 30 // Tăng thời gian chờ kết nối lên 30 giây
|
|
]);
|
|
}
|
|
|
|
public function getAllProjects()
|
|
{
|
|
$response = $this->client->get('/rest/api/3/project');
|
|
return json_decode($response->getBody()->getContents(), true);
|
|
}
|
|
|
|
public function getIssuesAsync($projectKey, $startAt = 0, $maxResults = 50)
|
|
{
|
|
$body = [
|
|
'expand' => ['names', 'schema', 'operations'],
|
|
'fields' => ['summary', 'status', 'description', 'timeoriginalestimate', 'timespent', 'worklog', 'assignee'],
|
|
'jql' => "project = '{$projectKey}' ORDER BY created DESC",
|
|
'maxResults' => $maxResults,
|
|
'startAt' => $startAt
|
|
];
|
|
|
|
return $this->client->postAsync($this->baseUrl . '/rest/api/3/search', [
|
|
'body' => json_encode($body),
|
|
'headers' => [
|
|
'Authorization' => $this->authHeader,
|
|
'Accept' => 'application/json',
|
|
'Content-Type' => 'application/json'
|
|
]
|
|
]);
|
|
}
|
|
public function getIssues($projectKey, $startAt = 0)
|
|
{
|
|
$body = [
|
|
'expand' => ['names', 'schema', 'operations'],
|
|
'fields' => ['summary', 'status', 'description', 'timeoriginalestimate', 'timespent', 'worklog', 'assignee'],
|
|
'jql' => "project = '{$projectKey}' ORDER BY created DESC",
|
|
'maxResults' => 100,
|
|
'startAt' => $startAt
|
|
];
|
|
|
|
$response = $this->client->post('/rest/api/3/search', [
|
|
'body' => json_encode($body)
|
|
]);
|
|
|
|
return json_decode($response->getBody()->getContents(), true);
|
|
}
|
|
|
|
public function getIssuesByUser($accountId, $startAt = 0)
|
|
{
|
|
$body = [
|
|
'expand' => ['names', 'schema', 'operations'],
|
|
'fields' => ['summary', 'status', 'timeoriginalestimate', 'timespent', 'assignee', 'project'],
|
|
'jql' => sprintf(
|
|
"assignee = '%s' AND status IN ('backlog', 'to do', 'in progress')",
|
|
$accountId
|
|
),
|
|
'maxResults' => 50,
|
|
'startAt' => $startAt
|
|
];
|
|
|
|
$response = $this->client->post('/rest/api/3/search', [
|
|
'body' => json_encode($body)
|
|
]);
|
|
|
|
$issues = json_decode($response->getBody()->getContents(), true);
|
|
|
|
foreach ($issues['issues'] as &$issue) {
|
|
$issueKey = $issue['key'];
|
|
$issueResponse = $this->client->get("/rest/api/3/issue/{$issueKey}?expand=changelog");
|
|
$issueDetails = json_decode($issueResponse->getBody()->getContents(), true);
|
|
$issue['changelog'] = $issueDetails['changelog'];
|
|
}
|
|
|
|
return $issues;
|
|
}
|
|
|
|
public function getAllUsers()
|
|
{
|
|
$response = $this->client->get('/rest/api/3/users/search', [
|
|
'headers' => [
|
|
'Authorization' => $this->authHeader,
|
|
'Accept' => 'application/json'
|
|
]
|
|
]);
|
|
|
|
return json_decode($response->getBody()->getContents(), true);
|
|
}
|
|
|
|
public function getUserByEmail($email)
|
|
{
|
|
|
|
$response = $this->client->get("/rest/api/3/user/search?query={$email}", [
|
|
'headers' => [
|
|
'Authorization' => $this->authHeader,
|
|
'Accept' => 'application/json'
|
|
]
|
|
]);
|
|
|
|
if ($response->getStatusCode() == 200) {
|
|
return json_decode($response->getBody(), true);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function getUsersByEmails($all_users)
|
|
{
|
|
$users = [];
|
|
|
|
foreach ($all_users as $user) {
|
|
$user_info = $this->getUserByEmail($user->email);
|
|
|
|
if (isset($user_info[0]['self'])) {
|
|
$user_info[0]['emailAddress'] = $user->email;
|
|
$users[] = $user_info;
|
|
}
|
|
}
|
|
|
|
return $users;
|
|
}
|
|
|
|
public function getUserWorkLogs($accountId, $startDate, $endDate)
|
|
{
|
|
$body = [
|
|
'jql' => "worklogAuthor = '{$accountId}'AND worklogDate >= '{$startDate}' AND worklogDate <= '{$endDate}'",
|
|
'fields' => ['summary', 'status', 'timeoriginalestimate', 'timespent', 'project'],
|
|
'maxResults' => 100
|
|
];
|
|
|
|
$response = $this->client->post('/rest/api/3/search', [
|
|
'body' => json_encode($body),
|
|
'headers' => [
|
|
'Authorization' => $this->authHeader,
|
|
'Accept' => 'application/json',
|
|
'Content-Type' => 'application/json'
|
|
]
|
|
]);
|
|
|
|
$data_response = json_decode($response->getBody()->getContents(), true);
|
|
|
|
if ($data_response['total'] == 0) {
|
|
return $data_response;
|
|
}
|
|
|
|
$promises = [];
|
|
foreach ($data_response['issues'] as $index => $issue) {
|
|
$issueId = $issue['id'];
|
|
|
|
// Get the initial worklog data to determine total number of worklogs
|
|
$promises[$index] = $this->client->getAsync("/rest/api/3/issue/{$issueId}/worklog", [
|
|
'query' => [
|
|
'startAt' => 0,
|
|
'maxResults' => 1
|
|
]
|
|
])->then(function ($checkApiResponse) use ($issueId, $index) {
|
|
$checkApi = json_decode($checkApiResponse->getBody()->getContents(), true);
|
|
$maxResults = 100;
|
|
$totalWorklogs = $checkApi['total'];
|
|
return $this->client->getAsync("/rest/api/3/issue/{$issueId}/worklog", [
|
|
'query' => [
|
|
'startAt' => $totalWorklogs - $maxResults,
|
|
'maxResults' => $totalWorklogs
|
|
]
|
|
])->then(function ($worklogResponse) use ($index) {
|
|
return [
|
|
'index' => $index,
|
|
'worklogs' => json_decode($worklogResponse->getBody()->getContents(), true)
|
|
];
|
|
});
|
|
});
|
|
}
|
|
|
|
// Wait for all promises to complete
|
|
$results = Utils::settle($promises)->wait();
|
|
|
|
// Attach worklogs to issues
|
|
foreach ($results as $result) {
|
|
if ($result['state'] === 'fulfilled') {
|
|
$data_response['issues'][$result['value']['index']]["fields"]['worklog'] = $result['value']['worklogs'];
|
|
}
|
|
}
|
|
|
|
return $data_response;
|
|
}
|
|
|
|
public function getAllUserWorkLogs($startDate, $endDate)
|
|
{
|
|
$users = $this->getAllUsers();
|
|
$workLogs = [];
|
|
|
|
foreach ($users as $user) {
|
|
$userWorkLogs = $this->getUserWorkLogs($user['accountId'], $startDate, $endDate);
|
|
$assignTask = [];
|
|
if (count($userWorkLogs['issues']) > 0) {
|
|
$assignTask = $this->getIssuesByUser($user['accountId']);
|
|
$workLogs[] = ['username' => $user['displayName'], 'information' => $userWorkLogs, 'tasksAssign' => $assignTask, 'user' => $user];
|
|
}
|
|
}
|
|
|
|
return $workLogs;
|
|
}
|
|
|
|
public function getAllUserDoing()
|
|
{
|
|
$users = UserJiraCacheHelper::getCacheSetting();
|
|
$groupedIssues = [];
|
|
$users_data = [];
|
|
$user_warning = [];
|
|
$ignore_projects = ['PJ_tracking'];
|
|
foreach ($users as $user) {
|
|
$user = (array) $user[0];
|
|
$users_data[$user['displayName']]['user'] = $user;
|
|
$users_data[$user['displayName']]['total_spent'] = 0;
|
|
$users_data[$user['displayName']]['total_est'] = 0;
|
|
$body = [
|
|
'expand' => ['names', 'schema', 'changelog'],
|
|
'fields' => ['summary', 'status', 'timeoriginalestimate', 'timespent', 'assignee', 'project', 'updated'],
|
|
'jql' => sprintf(
|
|
"assignee = '%s' AND status IN ('to do', 'todo', 'in progress') ORDER BY updated DESC",
|
|
$user['accountId']
|
|
),
|
|
'maxResults' => 50,
|
|
'startAt' => 0
|
|
];
|
|
|
|
$response = $this->client->post('/rest/api/3/search', [
|
|
'body' => json_encode($body)
|
|
]);
|
|
|
|
$issues = json_decode($response->getBody()->getContents(), true);
|
|
|
|
// Lọc các issue không thuộc các project bị ignore
|
|
$filtered_issues = array_filter($issues['issues'], function ($issue) use ($ignore_projects) {
|
|
return !in_array($issue['fields']['project']['name'], $ignore_projects);
|
|
});
|
|
|
|
$issues['issues'] = $filtered_issues;
|
|
|
|
if (count($issues['issues']) == 0) {
|
|
$user_warning[] = $user;
|
|
}
|
|
|
|
foreach ($issues['issues'] as $issue) {
|
|
$projectName = $issue['fields']['project']['name'];
|
|
if (!in_array($projectName, $ignore_projects)) {
|
|
$username = $issue['fields']['assignee']['displayName'];
|
|
$issue['fields']['assignee']['emailAddress'] = $user['emailAddress'];
|
|
if (!isset($groupedIssues[$projectName])) {
|
|
$groupedIssues[$projectName] = [];
|
|
$groupedIssues[$projectName]['project'] = $issue['fields']['project'];
|
|
}
|
|
|
|
if (!isset($groupedIssues[$projectName]['users'][$username])) {
|
|
$groupedIssues[$projectName]['users'][$username] = [];
|
|
$groupedIssues[$projectName]['users'][$username]['user'] = $issue['fields']['assignee'];
|
|
$groupedIssues[$projectName]['users'][$username]['p_total_spent'] = 0;
|
|
$groupedIssues[$projectName]['users'][$username]['p_total_est'] = 0;
|
|
}
|
|
|
|
$groupedIssues[$projectName]['users'][$username]['issues'][] = $issue;
|
|
$groupedIssues[$projectName]['users'][$username]['p_total_spent'] = $groupedIssues[$projectName]['users'][$username]['p_total_spent'] + $issue['fields']['timespent'];
|
|
$groupedIssues[$projectName]['users'][$username]['p_total_est'] = $groupedIssues[$projectName]['users'][$username]['p_total_est'] + ($issue['fields']['timeoriginalestimate'] ?? 0);
|
|
|
|
$users_data[$user['displayName']]['total_spent'] = $users_data[$user['displayName']]['total_spent'] + $issue['fields']['timespent'];
|
|
$users_data[$user['displayName']]['total_est'] = $users_data[$user['displayName']]['total_est'] + ($issue['fields']['timeoriginalestimate'] ?? 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return ['projects' => $groupedIssues, 'users' => $users_data, 'warningList' => $user_warning];
|
|
}
|
|
|
|
public function getDetailIssueByKey($issueKey)
|
|
{
|
|
$issueResponse = $this->client->get("/rest/api/3/issue/{$issueKey}?expand=changelog");
|
|
$issueDetail = json_decode($issueResponse->getBody()->getContents(), true);
|
|
return $issueDetail;
|
|
}
|
|
public function getDetailsProjectsById($id)
|
|
{
|
|
$response = $this->client->get('/rest/api/3/project/' . $id);
|
|
return json_decode($response->getBody()->getContents(), true);
|
|
}
|
|
public function getAllBoardByIdProjects($id)
|
|
{
|
|
$response = $this->client->get('/rest/agile/1.0/board?projectKeyOrId=' . $id);
|
|
return json_decode($response->getBody()->getContents(), true);
|
|
}
|
|
public function getAllSprintByIdBoard($id)
|
|
{
|
|
$response = $this->client->get('/rest/agile/1.0/board/' . $id . '/sprint');
|
|
return json_decode($response->getBody()->getContents(), true);
|
|
}
|
|
public function getAllIssueByIdSprint($id)
|
|
{
|
|
$response = $this->client->get('/rest/agile/1.0/sprint/' . $id . '/issue');
|
|
return json_decode($response->getBody()->getContents(), true);
|
|
}
|
|
|
|
public function getWeeklyReport()
|
|
{
|
|
$body = [
|
|
'fields' => ['summary', 'status', 'timeoriginalestimate', 'timespent', 'assignee', 'project', 'worklog'],
|
|
'jql' => 'worklogDate >= startOfWeek() AND worklogDate < startOfWeek(1) order by created DESC',
|
|
'maxResults' => 1000
|
|
];
|
|
|
|
$response = $this->client->post('/rest/api/3/search', [
|
|
'body' => json_encode($body)
|
|
]);
|
|
return json_decode($response->getBody()->getContents(), true);
|
|
}
|
|
}
|