Created
July 29, 2019 07:41
-
-
Save costlockerbot/1d3ee907e33c18504c4bff500578858d to your computer and use it in GitHub Desktop.
Bulk add people to running and recurring projects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Usage: | |
// time CL_TOKEN="token from https://new.costlocker.com/api-token" php bulk-add.php | |
// 0) configuration | |
$config = [ | |
'costlocker' => [ | |
'url' => 'https://new.costlocker.com/api-public', | |
'token' => getenv('CL_TOKEN') ?: 'token from https://new.costlocker.com/api-token', | |
], | |
'newPeopleIds' => [1, 2, 3, 4, 5], | |
'newAssignments' => array_map( | |
function ($taskName) { | |
return [ | |
'item' => [ | |
'type' => 'task', | |
'person_id' => null, // will be replaced by id from newPeopleIds | |
], | |
'activity' => 'Optimalizace PPC', | |
'task' => $taskName, | |
'hours' => 0 | |
]; | |
}, | |
['Optimalizace PPC', 'Mail', 'Telefonát'] | |
), | |
]; | |
// 1) load projects | |
list($runningIds, $recurringIdsFromRunning) = findStandardRunningProjects($config); | |
$recurringIds = findActiveRecurringProjects($recurringIdsFromRunning, $config); | |
$projectIds = array_merge($runningIds, $recurringIds); | |
$existingProjectPeople = findProjectPeople($projectIds, $config); | |
// 2) add people to projects | |
$result = updateProjects($projectIds, $existingProjectPeople, $config); | |
// 3) log results | |
debugJson([ | |
'peopleCount' => count($config['newPeopleIds']), | |
'projectsCount' => [ | |
'total' => count($projectIds), | |
'running' => count($runningIds), | |
'recurring' => count($recurringIds), | |
'projectsWithAtLeastOnePerson' => count($existingProjectPeople), | |
], | |
'result' => $result, | |
]); | |
function findStandardRunningProjects(array $config) | |
{ | |
list($response) = httpRequest([ | |
'url' => "{$config['costlocker']['url']}/v1", | |
'json' => [ | |
'Simple_Projects' => [ | |
'state' => 'running', | |
'project_type' => 'standard', | |
], | |
], | |
'auth' => [ | |
'costlocker/bulk-add-people', | |
$config['costlocker']['token'], | |
], | |
]); | |
$running = []; | |
$recurring = []; | |
foreach ($response['Simple_Projects'] as $project) { | |
$running[] = $project['id']; | |
if ($project['recurring']['id']) { | |
$recurring[] = $project['recurring']['id']; | |
} | |
} | |
return [$running, $recurring]; | |
} | |
function findActiveRecurringProjects(array $recurringIds, array $config) | |
{ | |
list($response) = httpRequest([ | |
'url' => "{$config['costlocker']['url']}/v1", | |
'json' => [ | |
'Simple_Projects' => [ | |
'project' => $recurringIds, | |
'project_type' => 'recurring', | |
], | |
], | |
'auth' => [ | |
'costlocker/bulk-add-people', | |
$config['costlocker']['token'], | |
], | |
]); | |
$activeIds = []; | |
foreach ($response['Simple_Projects'] as $project) { | |
$recurring = $project['recurring']['settings']; | |
if (!$recurring['date_end'] || strtotime($recurring['date_end']) > time()) { | |
$activeIds[] = $project['id']; | |
} | |
} | |
return $activeIds; | |
} | |
function findProjectPeople(array $projectIds, array $config) | |
{ | |
list($response) = httpRequest([ | |
'url' => "{$config['costlocker']['url']}/v1", | |
'json' => [ | |
'Simple_Projects_Ce' => [ | |
'project' => $projectIds, | |
'person' => $config['newPeopleIds'], | |
], | |
], | |
'auth' => [ | |
'costlocker/bulk-add-people', | |
$config['costlocker']['token'], | |
], | |
]); | |
$projectPeople = []; | |
foreach ($response['Simple_Projects_Ce'] as $projectPerson) { | |
if (!array_key_exists($projectPerson['project_id'], $projectPeople)) { | |
$projectPeople[$projectPerson['project_id']] = []; | |
} | |
$projectPeople[$projectPerson['project_id']][] = $projectPerson['person_id']; | |
} | |
return $projectPeople; | |
} | |
function updateProjects(array $projectIds, array $existingProjectPeople, array $config) | |
{ | |
$projects = []; | |
foreach ($projectIds as $projectId) { | |
$items = []; | |
foreach ($config['newPeopleIds'] as $personId) { | |
if (in_array($personId, $existingProjectPeople[$projectId] ?? [])) { | |
continue; | |
} | |
foreach ($config['newAssignments'] as $item) { | |
$items[] = array_replace_recursive( | |
$item, | |
['item' => ['person_id' => $personId]] | |
); | |
} | |
} | |
if (!$items) { | |
continue; | |
} | |
$projects[] = ['id' => $projectId, 'items' => $items]; | |
} | |
if (!$projects) { | |
return 'People are already assigned in all projects!'; | |
} | |
$results = [ | |
'metaResponses' => [], | |
'duration' => 0, | |
]; | |
// avoid `413 Request Entity Too Large` | |
foreach (array_chunk($projects, 50) as $projectsChunk) { | |
list($response, $duration) = httpRequest([ | |
'url' => "{$config['costlocker']['url']}/v2/projects/", | |
'json' => [ | |
'data' => $projectsChunk, | |
], | |
'auth' => [ | |
'costlocker/bulk-add-people', | |
$config['costlocker']['token'], | |
], | |
]); | |
$results['metaResponses'][] = $response['meta'] ?? $response; | |
$results['duration'] += $duration; | |
} | |
return $results; | |
} | |
function httpRequest(array $rawRequest) | |
{ | |
$start = microtime(true); | |
$request = $rawRequest + ['json' => [], 'query' => []]; | |
$ch = curl_init(); | |
curl_setopt_array($ch, [ | |
CURLOPT_CUSTOMREQUEST => $request['json'] ? 'POST' : 'GET', | |
CURLOPT_URL => $request['url'] . '?' . http_build_query($request['query']), | |
CURLOPT_POSTFIELDS => json_encode($request['json'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), | |
CURLOPT_HTTPHEADER => ['Content-Type: application/json'], | |
CURLOPT_RETURNTRANSFER => true, | |
CURLOPT_HTTPAUTH => CURLAUTH_BASIC, | |
CURLOPT_USERPWD => implode(':', $request['auth']), | |
]); | |
$response = curl_exec($ch); | |
curl_close($ch); | |
$duration = microtime(true) - $start; | |
$json = json_decode($response, true); | |
return [$json ?: $response, $duration]; | |
} | |
function debugJson($data) | |
{ | |
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment