-
-
Save GregPK/6447781 to your computer and use it in GitHub Desktop.
This utility class allows you to copy projects from one workspace in Asana to another. Shortcomings: * any tasks that have been set up as recurring will not preserve that setting (a limitation of the Asana API)
This file contains hidden or 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 | |
class CopyAsanaWorkspace | |
{ | |
public $apiKey; /// Get it from http://app.asana.com/-/account_api | |
public $indentationLevel = 0; | |
public $verbose = true; | |
private $projectFields = array('name','color','notes'); | |
public function __construct($apiKey) { | |
$this->apiKey = $apiKey; | |
} | |
function copyProjects($srcWorkspaceID,$targetWorkspaceID) { | |
$projectsResponse = $this->asanaRequest("workspaces/$srcWorkspaceID/projects",'GET',null,$this->projectFields); | |
$projects = $projectsResponse['data']; | |
$this->debug("Found ".count($projects)." projects in source workspace"); | |
foreach ($projects as $project) { | |
$this->levelDown(); | |
$newProj = $this->createProject($targetWorkspaceID,$project); | |
if ($newProj) { | |
$this->debug("Created new project with id=[{$newProj['id']}], starting to copy tasks..."); | |
$this->copyTasks($project['id'],$newProj['id']); | |
} | |
else { | |
$this->debug("Failed to create project"); | |
} | |
$this->levelUp(); | |
} | |
} | |
public function createProject($targetWorkspaceID, $data) { | |
$this->debug("Creating new project with name: {$data['name']}"); | |
unset($data['id']); | |
$data = array("data"=>$data); | |
$projectsResponse = $this->asanaRequest("workspaces/$targetWorkspaceID/projects",'POST',$data); | |
return $projectsResponse['data']; | |
} | |
public function asanaRequest($methodPath, $httpMethod = 'GET', $body = null, $fields = null) | |
{ | |
$url = "https://app.asana.com/api/1.0/$methodPath"; | |
if (is_array($fields)) { | |
$url .= "?opt_fields=".implode(',',$fields); | |
} | |
$ch = curl_init(); | |
curl_setopt($ch, CURLOPT_URL, $url); | |
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC ) ; | |
curl_setopt($ch, CURLOPT_USERPWD, $this->apiKey); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | |
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $httpMethod); | |
// SSL cert of Asana is selfmade | |
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0); | |
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0); | |
if ($body) | |
{ | |
if (!is_string($body)) | |
{ | |
$body = json_encode($body); | |
} | |
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json')); | |
curl_setopt($ch, CURLOPT_POSTFIELDS, $body); | |
} | |
$data = curl_exec($ch); | |
$error = curl_error($ch); | |
curl_close($ch); | |
$result = json_decode($data, true); | |
return $result; | |
} | |
function createTask($workspaceId, $projectId, $task) | |
{ | |
$this->levelDown(); | |
$this->debug("Creating new task"); | |
$data = array('data' => $task); | |
$result = $this->asanaRequest("workspaces/$workspaceId/tasks", 'POST', $data); | |
if ($result['data']) | |
{ | |
$newTask = $result['data']; | |
$newTaskId = $newTask['id']; | |
$data = array('data' => array('project' => $projectId)); | |
$result = $this->asanaRequest("tasks/$newTaskId/addProject", 'POST', $data); | |
$this->levelUp(); | |
return $newTask; | |
} | |
$this->levelUp(); | |
return $result; | |
} | |
function copySubtasks($taskId, $newTaskId, $failsafe) { | |
$this->levelDown(); | |
$this->debug("Copying subtasks from $taskId to $newTaskId"); | |
$failsafe++; | |
if ($failsafe > 10) { | |
$this->error("Copy aborting because of exceeding 10 levels of nesting"); | |
return FALSE; | |
} | |
// GET subtasks of task | |
$result = $this->asanaRequest("tasks/$taskId/subtasks"); | |
$subtasks = $result["data"]; | |
if ($subtasks){ // does subtask exist? | |
for ($i= count($subtasks) - 1; $i >= 0; $i--) { | |
$subtask = $subtasks[$i]; | |
$subtaskId = $subtask['id']; | |
// get data for subtask | |
$result = $this->asanaRequest("tasks/$subtaskId?opt_fields=name,due_on,assignee_status,notes,assignee"); | |
$newSubtask = $result['data']; | |
unset($newSubtask["id"]); | |
$newSubtask["assignee"] = $newSubtask["assignee"]["id"]; | |
// create Subtask | |
$data = array('data' => $newSubtask ); | |
$result = $this->asanaRequest("tasks/$newTaskId/subtasks", 'POST', $data); | |
// add History | |
$newSubId = $result["data"]["id"]; | |
$this->copyHistory($subtaskId, $newSubId); | |
// subtask of subtask? | |
$this->copySubtasks($subtaskId, $result["data"]["id"], $failsafe); | |
} | |
} | |
$this->levelUp(); | |
} | |
function copyHistory($taskId, $newTaskId) { | |
$this->levelDown(); | |
$this->debug("Copying task history"); | |
$result = $this->asanaRequest("tasks/$taskId/stories"); | |
$comments = array(); | |
foreach ($result['data'] as $story){ | |
$date = date('l M d, Y h:i A', strtotime($story['created_at'])); | |
$comment = " \n" . $story['created_by']['name'] . ' on ' . $date . ":\n" . $story['text']; | |
$comments[] = $comment; | |
} | |
$comment = implode("\n----------------------", $comments); | |
$data = array('data' => array('text' => $comment)); | |
$result = $this->asanaRequest("tasks/$newTaskId/stories", 'POST', $data); | |
$this->levelUp(); | |
} | |
function copyTags($taskId, $newTaskId, $newworkspaceId) { | |
$this->levelDown(); | |
$this->debug("Copying tags"); | |
// GET Tags | |
$result = $this->asanaRequest("tasks/$taskId/tags"); | |
if($result["data"]){ // are there any tags? | |
$tags = $result["data"]; | |
for ($i = count ($tags) - 1; $i >= 0; $i--) { | |
$tag = $tags[$i]; | |
$tagName = $tag["name"]; | |
// does tag exist? | |
$result = $this->asanaRequest("workspaces/$newworkspaceId/tags"); | |
$tagisset = false; | |
$existingtags = $result["data"]; | |
for($j = count($existingtags) - 1; $j >= 0; $j--) { | |
$existingtag = $existingtags[$j]; | |
if ($tagName == $existingtag["name"]) { | |
$tagisset = true; | |
$tagId = $existingtag["id"]; | |
break; | |
} | |
} | |
if (!$tagisset) { | |
$this->debug("tag does not exist in workspace"); | |
$data = array('data' => array('name' => $tagName)); | |
$result = $this->asanaRequest("workspaces/$newworkspaceId/tags", "POST", $data); | |
$tagId = $result["data"]["id"]; | |
} | |
$data = array("data" => array("tag" => $tagId)); | |
$result = $this->asanaRequest("tasks/$newTaskId/addTag", "POST", $data); | |
} | |
} | |
$this->levelUp(); | |
} | |
function createTag($tagName, $workspaceId, $newTaskId) { | |
$data = array('data' => array('name' => $tagName)); | |
$result = $this->asanaRequest("workspaces/$workspaceId/tags", "POST", $data); | |
$data = array("data" => array("tag" => $result["data"]["id"])); | |
$result = $this->asanaRequest("tasks/$newTaskId/addTag", "POST", $data); | |
} | |
function copyTasks($fromProjectId, $toProjectId) | |
{ | |
$this->levelDown(); | |
$result = $this->asanaRequest("projects/$toProjectId"); | |
if (!$result['data']) | |
{ | |
$this->error("Error Loading Project!"); | |
return; | |
} | |
$workspaceId = $result['data']['workspace']['id']; | |
// GET Project tasks | |
$result = $this->asanaRequest("projects/$fromProjectId/tasks?opt_fields=name,due_on,assignee_status,notes,assignee"); | |
$tasks = $result['data']; | |
// copy Tasks | |
for ($i = count($tasks) - 1; $i >= 0; $i--) | |
{ | |
$task = $tasks[$i]; | |
$newTask = $task; | |
unset($newTask['id']); | |
$newTask['assignee'] = $newTask['assignee']['id']; | |
foreach ($newTask as $key => $value) | |
{ | |
if (empty($value)) | |
{ | |
unset($newTask[$key]); | |
} | |
} | |
$this->debug("Copying task [{$task['name']}"); | |
$newTask = $this->createTask($workspaceId, $toProjectId, $newTask); | |
if ($newTask['id']) | |
{ | |
//copy history | |
$taskId = $task['id']; | |
$newTaskId = $newTask['id']; | |
$this->copyHistory($taskId, $newTaskId); | |
//copy tags | |
$this->copyTags($taskId, $newTaskId, $workspaceId); | |
//implement copying of subtasks | |
$failsafe = 0; | |
$this->copySubtasks($taskId, $newTaskId, $failsafe); | |
} | |
} | |
$this->levelUp(); | |
} | |
protected function levelUp() { | |
$this->indentationLevel--; | |
} | |
protected function levelDown() { | |
$this->indentationLevel++; | |
} | |
protected function debug($msg) { | |
if ($this->verbose) $this->msg($msg); | |
} | |
protected function error($msg) { | |
$this->msg($msg); | |
} | |
protected function msg($msg) { | |
echo str_repeat(" ",$this->indentationLevel). "$msg\n"; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How does one implement this exactly? I tried running it on a local server using WAMP. I'm guessing I need to upload it to a web server and run it there...right? #Learning