Skip to content

Instantly share code, notes, and snippets.

@costlockerbot
Created July 29, 2019 07:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save costlockerbot/1d3ee907e33c18504c4bff500578858d to your computer and use it in GitHub Desktop.
Save costlockerbot/1d3ee907e33c18504c4bff500578858d to your computer and use it in GitHub Desktop.
Bulk add people to running and recurring projects
<?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