building out asana client
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,4 +1,4 @@
|
||||
CFLAGS=--std=c18 -O2 -Wall -Wextra -pedantic
|
||||
CFLAGS=--std=c18 -Wall -Wextra -pedantic
|
||||
LDLIBS=-lncurses -lcurl
|
||||
|
||||
.phony: clean
|
||||
|
||||
194
asana/asana.c
194
asana/asana.c
@@ -0,0 +1,194 @@
|
||||
#include "asana.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../cJSON/cJSON.h"
|
||||
#include "fetch.h"
|
||||
|
||||
asana_err asana_parse(char *json, void *resource) {
|
||||
if (json == NULL) {
|
||||
return ASANA_ERR_PARSE;
|
||||
}
|
||||
|
||||
asana_err ret = ASANA_ERR_PARSE;
|
||||
|
||||
cJSON *parsed = cJSON_Parse(json);
|
||||
|
||||
if (parsed != NULL) {
|
||||
cJSON *data = cJSON_GetObjectItemCaseSensitive(parsed, "data");
|
||||
if (cJSON_IsObject(data)) {
|
||||
cJSON *resource_type = cJSON_GetObjectItemCaseSensitive(data, "resource_type");
|
||||
|
||||
if (cJSON_IsString(resource_type)) {
|
||||
char *typ = resource_type->valuestring;
|
||||
|
||||
fprintf(stderr, "Parsing a %s\n", typ);
|
||||
ret = ASANA_ERR_OK;
|
||||
|
||||
if (strcmp(typ, "user") == 0) {
|
||||
asana_extract_user(data, resource);
|
||||
} else if (strcmp(typ, "workspace") == 0) {
|
||||
asana_extract_resource(data, resource);
|
||||
} else if (strcmp(typ, "task") == 0) {
|
||||
asana_extract_task(data, resource);
|
||||
} else if (strcmp(typ, "project") == 0 || strcmp(typ, "user_task_list") == 0) {
|
||||
asana_extract_project(data, resource);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown resource type: %s\n", typ);
|
||||
ret = ASANA_ERR_UNKNOWN_TYPE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cJSON_Delete(parsed);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void asana_extract_user(cJSON *json, User *user) {
|
||||
user->type = USER;
|
||||
asana_extract_resource(json, (Resource *)user);
|
||||
|
||||
fprintf(stderr, "Parsing one user. Name: %s\n", user->name);
|
||||
|
||||
cJSON *workspaces = cJSON_GetObjectItemCaseSensitive(json, "workspaces");
|
||||
if (cJSON_IsArray(workspaces)) {
|
||||
fprintf(stderr, "We got workspaces\n");
|
||||
user->workspaces_len = cJSON_GetArraySize(workspaces);
|
||||
user->workspaces = calloc(sizeof(Workspace), user->workspaces_len);
|
||||
|
||||
cJSON *workspace = NULL;
|
||||
size_t i = 0;
|
||||
cJSON_ArrayForEach(workspace, workspaces) {
|
||||
fprintf(stderr, "Extracting workspace\n");
|
||||
asana_extract_resource(workspace, (Resource *)&(user->workspaces[i]));
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
user->workspaces_len = 0;
|
||||
user->workspaces = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void asana_extract_task(cJSON *json, Task *task) {
|
||||
task->type = TASK;
|
||||
asana_extract_resource(json, (Resource *)task);
|
||||
|
||||
cJSON *notes = cJSON_GetObjectItemCaseSensitive(json, "notes");
|
||||
if (cJSON_IsString(notes)) {
|
||||
task->notes = malloc(sizeof(char)*strlen(notes->valuestring));
|
||||
strcpy(task->notes, notes->valuestring);
|
||||
} else {
|
||||
task->notes = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void asana_extract_project(cJSON *json, Project *project) {
|
||||
project->type = PROJECT;
|
||||
asana_extract_resource(json, (Resource *)project);
|
||||
|
||||
cJSON *tasks = cJSON_GetObjectItemCaseSensitive(json, "tasks");
|
||||
if (cJSON_IsArray(tasks)) {
|
||||
project->tasks_len = cJSON_GetArraySize(tasks);
|
||||
project->tasks = calloc(sizeof(Task), project->tasks_len);
|
||||
|
||||
cJSON *task = NULL;
|
||||
size_t i=0;
|
||||
cJSON_ArrayForEach(task, tasks) {
|
||||
asana_extract_task(task, &(project->tasks[i]));
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
project->tasks_len = 0;
|
||||
project->tasks = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void asana_extract_resource(cJSON *json, Resource *resource) {
|
||||
cJSON *gid = cJSON_GetObjectItemCaseSensitive(json, "gid");
|
||||
if (cJSON_IsString(gid)) {
|
||||
resource->gid = malloc(sizeof(char)*strlen(gid->valuestring));
|
||||
strcpy(resource->gid, gid->valuestring);
|
||||
} else {
|
||||
resource->gid = NULL;
|
||||
}
|
||||
|
||||
cJSON *name = cJSON_GetObjectItemCaseSensitive(json, "name");
|
||||
if (cJSON_IsString(name)) {
|
||||
resource->name = malloc(sizeof(char)*strlen(name->valuestring));
|
||||
strcpy(resource->name, name->valuestring);
|
||||
} else {
|
||||
resource->name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
asana_err user_info(User *user) {
|
||||
asana_err ret = ASANA_ERR_FETCH;
|
||||
|
||||
Response *user_resp = asana_fetch("users/me");
|
||||
|
||||
if (user_resp == NULL) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (user_resp->status == 200) {
|
||||
ret = asana_parse(user_resp->body, user);
|
||||
} else {
|
||||
fprintf(stderr, "Error fetching user: %d", user_resp->status);
|
||||
}
|
||||
|
||||
asana_free_response(user_resp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
asana_err user_task_list_gid(char *workspace_gid, char *gid) {
|
||||
int ret = ASANA_ERR_FETCH;
|
||||
char path[ASANA_URL_MAX_LENGTH];
|
||||
snprintf(path, ASANA_URL_MAX_LENGTH, "users/me/user_task_list?workspace=%s&opt_fields=gid,resource_type", workspace_gid);
|
||||
Response *task_list_resp = asana_fetch(path);
|
||||
|
||||
if (task_list_resp == NULL) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (task_list_resp->status == 200) {
|
||||
Project task_list;
|
||||
ret = asana_parse(task_list_resp->body, &task_list);
|
||||
|
||||
if (ret == ASANA_ERR_OK) {
|
||||
strcpy(gid, task_list.gid);
|
||||
ret = ASANA_ERR_OK;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Error fetching user_task_list: %d\n", task_list_resp->status);
|
||||
}
|
||||
|
||||
asana_free_response(task_list_resp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
asana_err user_task_list(char *task_list_gid, Project *task_list) {
|
||||
asana_err ret = ASANA_ERR_FETCH;
|
||||
char path[ASANA_URL_MAX_LENGTH];
|
||||
snprintf(path, ASANA_URL_MAX_LENGTH, "user_task_lists/%s/tasks?limit=100&completed_since=now");
|
||||
|
||||
Response *task_list_resp = asana_fetch(path);
|
||||
|
||||
if (task_list_resp == NULL) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (task_list_resp->status == 200) {
|
||||
ret = asana_parse(task_list_resp->body, task_list);
|
||||
// TODO: need to parse top-level arrays
|
||||
} else {
|
||||
fprintf(stderr, "Error fetching user_Task_list: %d\n", task_list_resp->status);
|
||||
}
|
||||
|
||||
asana_free_response(task_list_resp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,71 @@
|
||||
#ifndef ASANA_ASANA_H_
|
||||
#define ASANA_ASANA_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../cJSON/cJSON.h"
|
||||
|
||||
enum ASANA_RESOURCE {
|
||||
WORKSPACE,
|
||||
USER,
|
||||
TASK,
|
||||
PROJECT,
|
||||
};
|
||||
|
||||
typedef struct Resource {
|
||||
enum ASANA_RESOURCE type;
|
||||
char *gid;
|
||||
char *name;
|
||||
} Resource;
|
||||
|
||||
typedef struct Workspace {
|
||||
enum ASANA_RESOURCE type;
|
||||
char *gid;
|
||||
char *name;
|
||||
} Workspace;
|
||||
|
||||
typedef struct User {
|
||||
enum ASANA_RESOURCE type;
|
||||
char *gid;
|
||||
char *name;
|
||||
size_t workspaces_len;
|
||||
Workspace *workspaces;
|
||||
} User;
|
||||
|
||||
typedef struct Task {
|
||||
enum ASANA_RESOURCE type;
|
||||
char *gid;
|
||||
char *name;
|
||||
char *notes;
|
||||
} Task;
|
||||
|
||||
typedef struct Project {
|
||||
enum ASANA_RESOURCE type;
|
||||
char *gid;
|
||||
char *name;
|
||||
size_t tasks_len;
|
||||
Task *tasks;
|
||||
} Project;
|
||||
|
||||
|
||||
typedef int asana_err;
|
||||
#define ASANA_ERR_OK 0
|
||||
#define ASANA_ERR_FETCH 1
|
||||
#define ASANA_ERR_PARSE 2
|
||||
#define ASANA_ERR_UNKNOWN_TYPE 3
|
||||
|
||||
/**
|
||||
* Parsing methods to take a cJSON object and populate the Asana resource struct
|
||||
*/
|
||||
void asana_extract_resource(cJSON *json, Resource *resource);
|
||||
void asana_extract_user(cJSON *json, User *user);
|
||||
void asana_extract_workspace(cJSON *json, Workspace *workspace);
|
||||
void asana_extract_task(cJSON *json, Task *task);
|
||||
void asana_extract_project(cJSON *json, Project *project);
|
||||
|
||||
asana_err user_info(User *user);
|
||||
|
||||
asana_err user_task_list_gid(char *workspace_gid, char *gid);
|
||||
asana_err user_task_list(char *task_list_gid, Project *task_list);
|
||||
|
||||
#endif // ASANA_ASANA_H_
|
||||
|
||||
@@ -49,6 +49,8 @@ size_t asana_write_callback(void *contents, size_t size, size_t nmemb,
|
||||
Response *asana_fetch(char *path) {
|
||||
char url[ASANA_URL_MAX_LENGTH];
|
||||
snprintf(url, ASANA_URL_MAX_LENGTH, "https://app.asana.com/api/1.0/%s", path);
|
||||
|
||||
fprintf(stderr, "fetching %s\n", url);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, asana_auth_header);
|
||||
@@ -62,6 +64,7 @@ Response *asana_fetch(char *path) {
|
||||
CURLcode result;
|
||||
result = curl_easy_perform(curl);
|
||||
if (result == CURLE_OK) {
|
||||
fprintf(stderr, "API Response:\n\n%s\n", response->body);
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &(response->status));
|
||||
} else {
|
||||
response->status = 500;
|
||||
|
||||
23
ncac.c
23
ncac.c
@@ -5,10 +5,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <term.h>
|
||||
|
||||
#include "asana/asana.h"
|
||||
#include "asana/fetch.h"
|
||||
#include "ui/base.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int main(/*int argc, char **argv*/) {
|
||||
setup();
|
||||
|
||||
int curs_x = 0;
|
||||
@@ -35,7 +36,7 @@ int main(int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void finish(int sig) {
|
||||
static void finish(/*int sig*/) {
|
||||
endwin();
|
||||
asana_cleanup();
|
||||
exit(0);
|
||||
@@ -75,11 +76,21 @@ static void setup() {
|
||||
}
|
||||
|
||||
void get_me(int *curs_x, int *curs_y) {
|
||||
Response *response = asana_fetch("users/me");
|
||||
User me;
|
||||
user_info(&me);
|
||||
|
||||
if (me.workspaces == NULL || me.workspaces_len == 0) {
|
||||
fprintf(stderr, "Unable to get workspaces.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char gid[64];
|
||||
gid[0] = '\0';
|
||||
|
||||
user_task_list_gid(me.workspaces[0].gid, gid);
|
||||
fprintf(stderr, "Got a task list? %s\n", gid);
|
||||
|
||||
*curs_x = 0;
|
||||
(*curs_y)++;
|
||||
draw_text(response->body, curs_x, curs_y);
|
||||
|
||||
asana_free_response(response);
|
||||
draw_text(gid, curs_x, curs_y);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user