mirror of
https://github.com/michaeldv/pit.git
synced 2025-12-08 15:43:25 +00:00
More work on projects and cascading deletes
This commit is contained in:
@@ -3,7 +3,12 @@
|
||||
#include <stdio.h>
|
||||
#include "pit.h"
|
||||
|
||||
void pit_note_delete(ulong id, PTask pt)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void pit_note(char *argv[])
|
||||
{
|
||||
puts("pit: note is not implemented yet");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,9 @@ void pit_db_load();
|
||||
void pit_db_save();
|
||||
void pit_db_initialize();
|
||||
void pit_action(ulong id, char *subject, char *message);
|
||||
void pit_task_delete(ulong id, PProject pp);
|
||||
void pit_note_delete(ulong id, PTask pt);
|
||||
|
||||
|
||||
/* Argument parsing helpers */
|
||||
int pit_arg_is_option(char **arg);
|
||||
@@ -65,6 +68,7 @@ time_t pit_arg_time(char **arg, char *required);
|
||||
/* Misc utilities */
|
||||
void die(char *msg, ...);
|
||||
void perish(char *prefix);
|
||||
char *str2str(char *str);
|
||||
char *mem2str(char *mem, int len);
|
||||
char *current_user();
|
||||
char *home_dir(char *username, int len);
|
||||
|
||||
244
src/project.c
244
src/project.c
@@ -3,20 +3,36 @@
|
||||
#include <stdio.h>
|
||||
#include "pit.h"
|
||||
|
||||
static int already_exist(char *name)
|
||||
{
|
||||
PProject pp;
|
||||
static void project_list(char *name, char *status);
|
||||
static void project_show(ulong id);
|
||||
static void project_create(char *name, char *status);
|
||||
static void project_update(ulong id, char *name, char *status);
|
||||
static void project_delete(ulong id);
|
||||
static bool project_already_exist(char *name);
|
||||
static void project_find_current(PProject *ppp, ulong *pid);
|
||||
static void project_log_create(PProject pp, char *name, char *status);
|
||||
static void project_log_update(PProject pp, char *name, char *status);
|
||||
static void project_log_delete(ulong id, char *name, ulong number_of_tasks);
|
||||
static void project_parse_options(char **arg, char **name, char **status);
|
||||
|
||||
pit_db_load();
|
||||
for_each_project(pp) {
|
||||
if (!strcmp(pp->name, name)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
** CREATING PROJECTS:
|
||||
** pit project -c name [-s status]
|
||||
**
|
||||
** EDITING PROJECTS:
|
||||
** pit project -e [number] [-n name] [-s status]
|
||||
**
|
||||
** DELETING PROJECTS:
|
||||
** pit project -d [number]
|
||||
**
|
||||
** VIEWING PROJECT:
|
||||
** pit project [[-q] number]
|
||||
**
|
||||
** LISTING PROJECTS:
|
||||
** pit project -q [number | [-n name] [-s status]]
|
||||
*/
|
||||
|
||||
static void list_projects()
|
||||
static void project_list(char *name, char *status)
|
||||
{
|
||||
PProject pp;
|
||||
PPager ppager;
|
||||
@@ -31,11 +47,11 @@ static void list_projects()
|
||||
}
|
||||
}
|
||||
|
||||
static void create_project(char *name, char *status)
|
||||
static void project_create(char *name, char *status)
|
||||
{
|
||||
pit_db_load();
|
||||
|
||||
if (already_exist(name)) {
|
||||
if (project_already_exist(name)) {
|
||||
die("project with the same name already exists");
|
||||
} else {
|
||||
Project p, *pp;
|
||||
@@ -55,12 +71,12 @@ static void create_project(char *name, char *status)
|
||||
}
|
||||
}
|
||||
|
||||
static int show_project(ulong number)
|
||||
static void project_show(ulong id)
|
||||
{
|
||||
PProject pp;
|
||||
|
||||
pit_db_load();
|
||||
pp = (PProject)pit_table_find(projects, number);
|
||||
pp = (PProject)pit_table_find(projects, id);
|
||||
if (pp) {
|
||||
printf("%lu: %s (%s, %lu task%s)\n",
|
||||
pp->id, pp->name, pp->status, pp->number_of_tasks, (pp->number_of_tasks != 1 ? "s" : ""));
|
||||
@@ -77,56 +93,192 @@ static int show_project(ulong number)
|
||||
} else {
|
||||
die("could not find the project");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int delete_project(unsigned long number)
|
||||
static void project_update(ulong id, char *name, char *status)
|
||||
{
|
||||
PProject pp;
|
||||
|
||||
printf("deleting project %lu\n", number);
|
||||
pit_db_load();
|
||||
pp = (PProject)pit_table_delete(projects, number);
|
||||
project_find_current(&pp, &id);
|
||||
|
||||
if (name) strncpy(pp->name, name, sizeof(pp->name) - 1);
|
||||
if (status) strncpy(pp->status, status, sizeof(pp->status) - 1);
|
||||
pit_table_mark(projects, pp->id);
|
||||
|
||||
project_log_update(pp, name, status);
|
||||
pit_db_save();
|
||||
}
|
||||
|
||||
static void project_delete(ulong id)
|
||||
{
|
||||
PProject pp;
|
||||
PTask pt;
|
||||
char *deleted_name;
|
||||
ulong deleted_number_of_tasks;
|
||||
|
||||
pit_db_load();
|
||||
project_find_current(&pp, &id);
|
||||
|
||||
/*
|
||||
** Delete project tasks.
|
||||
*/
|
||||
if (pp->number_of_tasks > 0) {
|
||||
for_each_task(pt) {
|
||||
if (pt->project_id == id) {
|
||||
pit_task_delete(pt->id, pp);
|
||||
--pt; /* Make the task pointer stay since it now points to the next task. */
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
** Ready to delete the project itself. But first preserve the
|
||||
** name and number of tasks since we need these bits for logging.
|
||||
*/
|
||||
deleted_name = str2str(pp->name);
|
||||
deleted_number_of_tasks = pp->number_of_tasks;
|
||||
pp = (PProject)pit_table_delete(projects, id);
|
||||
if (pp) {
|
||||
pit_table_mark(projects, 0);
|
||||
pit_table_mark(projects, 0); /* TODO: find better current project candidate. */
|
||||
project_log_delete(id, deleted_name, deleted_number_of_tasks);
|
||||
pit_db_save();
|
||||
} else {
|
||||
die("could not delete the project");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool project_already_exist(char *name)
|
||||
{
|
||||
PProject pp;
|
||||
|
||||
pit_db_load();
|
||||
for_each_project(pp) {
|
||||
if (!strcmp(pp->name, name)) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void project_find_current(PProject *ppp, ulong *pid)
|
||||
{
|
||||
if (*pid) {
|
||||
*ppp = (PProject)pit_table_find(projects, *pid);
|
||||
if (!*ppp) die("could not find project %lu", *pid);
|
||||
} else {
|
||||
*ppp = (PProject)pit_table_current(projects);
|
||||
if (!*ppp) die("could not find current project");
|
||||
else *pid = (*(PProject *)ppp)->id;
|
||||
}
|
||||
}
|
||||
|
||||
static void project_log_create(PProject pp, char *name, char *status)
|
||||
{
|
||||
char str[256];
|
||||
|
||||
sprintf(str, "created project %lu: %s (status: %s)", pp->id, name, status);
|
||||
puts(str);
|
||||
pit_action(pp->id, "project", str);
|
||||
}
|
||||
|
||||
static void project_log_update(PProject pp, char *name, char *status)
|
||||
{
|
||||
char str[256];
|
||||
bool empty = TRUE;
|
||||
|
||||
sprintf(str, "updated project %lu:", pp->id);
|
||||
if (name) {
|
||||
sprintf(str + strlen(str), " (name: %s", name);
|
||||
empty = FALSE;
|
||||
} else {
|
||||
sprintf(str + strlen(str), " %s (", pp->name);
|
||||
}
|
||||
if (status) {
|
||||
sprintf(str + strlen(str), "%sstatus: %s)", (empty ? "" : ", "), status);
|
||||
}
|
||||
puts(str);
|
||||
pit_action(pp->id, "project", str);
|
||||
}
|
||||
|
||||
static void project_log_delete(ulong id, char *name, ulong number_of_tasks)
|
||||
{
|
||||
char str[256];
|
||||
|
||||
sprintf(str, "deleted project %lu: %s", id, name);
|
||||
if (number_of_tasks > 0) {
|
||||
sprintf(str + strlen(str), " with %lu task%s", number_of_tasks, (number_of_tasks == 1 ? "" : "s"));
|
||||
}
|
||||
puts(str);
|
||||
pit_action(id, "project", str);
|
||||
}
|
||||
|
||||
static void project_parse_options(char **arg, char **name, char **status)
|
||||
{
|
||||
while(*++arg) {
|
||||
switch(pit_arg_option(arg)) {
|
||||
case 's':
|
||||
*status = pit_arg_string(++arg, "project status");
|
||||
break;
|
||||
case 'n':
|
||||
if (name) {
|
||||
*name = pit_arg_string(++arg, "project name");
|
||||
break;
|
||||
} /* else fall though */
|
||||
default:
|
||||
die("invalid project option: %s", *arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pit_project(char *argv[])
|
||||
{
|
||||
char **arg = &argv[1];
|
||||
unsigned long number;
|
||||
char *name = NULL, *status = NULL;
|
||||
ulong number = 0L;
|
||||
|
||||
if (!*arg) {
|
||||
list_projects();
|
||||
} else if (!strcmp(*arg, "-c")) {
|
||||
if (!*++arg) {
|
||||
die("missing project name");
|
||||
project_list(name, status); /* Show all projects. */
|
||||
} else { /* pit project [number] */
|
||||
number = pit_arg_number(arg, NULL);
|
||||
if (number) {
|
||||
project_show(number);
|
||||
} else {
|
||||
create_project(*arg, *(arg + 1));
|
||||
}
|
||||
} else if (!strcmp(*arg, "-d")) {
|
||||
if (!*++arg) {
|
||||
die("missing project number");
|
||||
} else {
|
||||
number = atoi(*arg);
|
||||
if (!number) {
|
||||
die("invalid project number");
|
||||
} else {
|
||||
delete_project(number);
|
||||
switch(pit_arg_option(arg)) {
|
||||
case 'c': /* pit project -c name [-s status] */
|
||||
name = pit_arg_string(++arg, "project name");
|
||||
project_parse_options(arg, NULL, &status);
|
||||
project_create(name, status);
|
||||
break;
|
||||
case 'e': /* pit project -e [number] [-n name] [-s status] */
|
||||
number = pit_arg_number(++arg, NULL);
|
||||
if (!number) --arg;
|
||||
project_parse_options(arg, &name, &status);
|
||||
if (!name && !status) {
|
||||
die("nothing to update");
|
||||
} else {
|
||||
project_update(number, name, status);
|
||||
}
|
||||
break;
|
||||
case 'd': /* pit project -d [number] */
|
||||
number = pit_arg_number(++arg, NULL);
|
||||
project_delete(number);
|
||||
break;
|
||||
case 'q': /* pit project -q [number | [-n name] [-s status]] */
|
||||
number = pit_arg_number(++arg, NULL);
|
||||
if (number) {
|
||||
project_show(number);
|
||||
} else {
|
||||
project_parse_options(--arg, &name, &status);
|
||||
if (!name && !status) {
|
||||
project_show(0); /* Show current project if any. */
|
||||
} else {
|
||||
project_list(name, status);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
die("invalid project option: %s", *arg);
|
||||
}
|
||||
}
|
||||
/* } else if (!strcmp(*arg, "-e")) { TODO: Edit */
|
||||
} else {
|
||||
number = atoi(*arg);
|
||||
if (!number) {
|
||||
die("invalid project parameters");
|
||||
} else {
|
||||
show_project(number);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ uchar *pit_table_find(PTable pt, ulong id) {
|
||||
** if the record was not found.
|
||||
*/
|
||||
uchar *pit_table_delete(PTable pt, ulong id) {
|
||||
// TODO: retrn NULL (or raise?) if table doesn't have id.
|
||||
// TODO: return NULL (or die?) if table doesn't have id.
|
||||
register uchar *pr = (uchar *)pit_table_find(pt, id);
|
||||
|
||||
if (pr) {
|
||||
|
||||
107
src/task.c
107
src/task.c
@@ -4,13 +4,13 @@
|
||||
#include "pit.h"
|
||||
|
||||
static void task_list(char *name, char *status, char *priority, time_t date, time_t time);
|
||||
static void task_show(ulong number);
|
||||
static void task_show(ulong id);
|
||||
static void task_create(char *name, char *status, char *priority, time_t date, time_t time);
|
||||
static void task_update(ulong number, char *name, char *status, char *priority, time_t date, time_t time);
|
||||
static void task_delete(ulong number);
|
||||
static void task_update(ulong id, char *name, char *status, char *priority, time_t date, time_t time);
|
||||
static void task_find_current(PTask *ppt, ulong *pid);
|
||||
static void task_log_create(PTask pt, char *name, char *status, char *priority, time_t date, time_t time);
|
||||
static void task_log_update(PTask pt, char *name, char *status, char *priority, time_t date, time_t time);
|
||||
static void task_log_delete(PTask pt);
|
||||
static void task_log_delete(ulong id, char *name, ulong number_of_notes);
|
||||
static void task_parse_options(char **arg, char **name, char **status, char **priority, time_t *date, time_t *time);
|
||||
|
||||
/*
|
||||
@@ -27,7 +27,7 @@ static void task_parse_options(char **arg, char **name, char **status, char **pr
|
||||
** pit task [[-q] number]
|
||||
**
|
||||
** LISTING TASKS:
|
||||
** pit task -q [-s status] [-p priority] [-d date] [-t time]
|
||||
** pit task -q [number | [-n name] [-s status] [-p priority] [-d date] [-t time]]
|
||||
*/
|
||||
|
||||
static void task_list(char *name, char *status, char *priority, time_t date, time_t time)
|
||||
@@ -50,9 +50,9 @@ static void task_list(char *name, char *status, char *priority, time_t date, tim
|
||||
}
|
||||
}
|
||||
|
||||
static void task_show(ulong number)
|
||||
static void task_show(ulong id)
|
||||
{
|
||||
printf("task_show(%lu)\n", number);
|
||||
printf("task_show(%lu)\n", id);
|
||||
}
|
||||
|
||||
static void task_create(char *name, char *status, char *priority, time_t date, time_t time)
|
||||
@@ -87,18 +87,13 @@ static void task_create(char *name, char *status, char *priority, time_t date, t
|
||||
}
|
||||
}
|
||||
|
||||
static void task_update(ulong number, char *name, char *status, char *priority, time_t date, time_t time)
|
||||
static void task_update(ulong id, char *name, char *status, char *priority, time_t date, time_t time)
|
||||
{
|
||||
PTask pt;
|
||||
|
||||
pit_db_load();
|
||||
if (number) {
|
||||
pt = (PTask)pit_table_find(tasks, number);
|
||||
if (!pt) die("could not find task %lu", number);
|
||||
} else {
|
||||
pt = (PTask)pit_table_current(tasks);
|
||||
if (!pt) die("could not find current task");
|
||||
}
|
||||
task_find_current(&pt, &id);
|
||||
|
||||
if (name) strncpy(pt->name, name, sizeof(pt->name) - 1);
|
||||
if (status) strncpy(pt->status, status, sizeof(pt->status) - 1);
|
||||
if (priority) strncpy(pt->priority, priority, sizeof(pt->priority) - 1);
|
||||
@@ -110,26 +105,68 @@ static void task_update(ulong number, char *name, char *status, char *priority,
|
||||
pit_db_save();
|
||||
}
|
||||
|
||||
static void task_delete(ulong number)
|
||||
/*
|
||||
** A task could be deleted as standalone entity or as part of cascading project
|
||||
** delete. In later case we're going to have 'pp' set and the database loaded.
|
||||
*/
|
||||
void pit_task_delete(ulong id, PProject pp)
|
||||
{
|
||||
PTask pt;
|
||||
PNote pn;
|
||||
bool standalone = (pp == NULL);
|
||||
|
||||
pit_db_load();
|
||||
pt = (PTask)pit_table_delete(tasks, number);
|
||||
if (pt) {
|
||||
pit_table_mark(tasks, 0);
|
||||
if (standalone) {
|
||||
pit_db_load();
|
||||
pp = (PProject)pit_table_find(projects, pt->project_id);
|
||||
}
|
||||
task_find_current(&pt, &id);
|
||||
|
||||
if (pp) {
|
||||
/*
|
||||
** First delete task notes if any.
|
||||
*/
|
||||
if (pt->number_of_notes > 0) {
|
||||
PNote pn;
|
||||
for_each_note(pn) {
|
||||
if (pn->task_id == pt->id) {
|
||||
pit_table_delete(notes, pn->id);
|
||||
if (pn->task_id == id) {
|
||||
pit_note_delete(pn->id, pt);
|
||||
--pn; /* Make the note pointer stay since it now points to the next note. */
|
||||
}
|
||||
}
|
||||
}
|
||||
task_log_delete(pt);
|
||||
pit_db_save();
|
||||
/*
|
||||
** Preserve task name and number_of_notes before deleting the task since
|
||||
** we need these for logging.
|
||||
*/
|
||||
char *deleted_name = str2str(pt->name);
|
||||
ulong deleted_number_of_notes = pt->number_of_notes;
|
||||
|
||||
pt = (PTask)pit_table_delete(tasks, id);
|
||||
if (pt) {
|
||||
pit_table_mark(tasks, 0); /* TODO: find better current task candidate. */
|
||||
task_log_delete(id, deleted_name, deleted_number_of_notes);
|
||||
if (standalone) {
|
||||
pp->number_of_tasks--;
|
||||
pit_db_save();
|
||||
}
|
||||
free(deleted_name);
|
||||
} else {
|
||||
free(deleted_name);
|
||||
die("could not delete task %lu", id);
|
||||
}
|
||||
} else {
|
||||
die("could not delete task %lu", number);
|
||||
die("could not find project for task %lu", id);
|
||||
}
|
||||
}
|
||||
|
||||
static void task_find_current(PTask *ppt, ulong *pid)
|
||||
{
|
||||
if (*pid) {
|
||||
*ppt = (PTask)pit_table_find(tasks, *pid);
|
||||
if (!*ppt) die("could not find task %lu", *pid);
|
||||
} else {
|
||||
*ppt = (PTask)pit_table_current(tasks);
|
||||
if (!*ppt) die("could not find current task");
|
||||
else *pid = (*(PTask *)ppt)->id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,16 +212,16 @@ static void task_log_update(PTask pt, char *name, char *status, char *priority,
|
||||
pit_action(pt->id, "task", str);
|
||||
}
|
||||
|
||||
static void task_log_delete(PTask pt)
|
||||
static void task_log_delete(ulong id, char *name, ulong number_of_notes)
|
||||
{
|
||||
char str[256];
|
||||
|
||||
sprintf(str, "deleted task %lu: %s", pt->id, pt->name);
|
||||
if (pt->number_of_notes > 0) {
|
||||
sprintf(str + strlen(str), " with %lu note%s", pt->number_of_notes, (pt->number_of_notes == 1 ? "" : "s"));
|
||||
sprintf(str, "deleted task %lu: %s", id, name);
|
||||
if (number_of_notes > 0) {
|
||||
sprintf(str + strlen(str), " with %lu note%s", number_of_notes, (number_of_notes == 1 ? "" : "s"));
|
||||
}
|
||||
puts(str);
|
||||
pit_action(pt->id, "task", str);
|
||||
pit_action(id, "task", str);
|
||||
}
|
||||
|
||||
static void task_parse_options(char **arg, char **name, char **status, char **priority, time_t *date, time_t *time)
|
||||
@@ -223,7 +260,7 @@ void pit_task(char *argv[])
|
||||
ulong number = 0L;
|
||||
|
||||
if (!*arg) {
|
||||
task_list(NULL, NULL, NULL, 0, 0); /* List all tasks (with default paramaters). */
|
||||
task_list(name, status, priority, date, time); /* List all tasks (i.e. use default paramaters). */
|
||||
} else { /* pit task [number] */
|
||||
number = pit_arg_number(arg, NULL);
|
||||
if (number) {
|
||||
@@ -235,7 +272,7 @@ void pit_task(char *argv[])
|
||||
task_parse_options(arg, NULL, &status, &priority, &date, &time);
|
||||
task_create(name, status, priority, date, time);
|
||||
break;
|
||||
case 'e': /* pit task -e [number] [-n name] [-s status] [-p priority] [-d date] [-t time]*/
|
||||
case 'e': /* pit task -e [number] [-n name] [-s status] [-p priority] [-d date] [-t time] */
|
||||
number = pit_arg_number(++arg, NULL);
|
||||
if (!number) --arg;
|
||||
task_parse_options(arg, &name, &status, &priority, &date, &time);
|
||||
@@ -247,7 +284,7 @@ void pit_task(char *argv[])
|
||||
break;
|
||||
case 'd': /* pit task -d [number] */
|
||||
number = pit_arg_number(++arg, NULL);
|
||||
task_delete(number);
|
||||
pit_task_delete(number, NULL); /* Delete the task, but keep its project. */
|
||||
break;
|
||||
case 'q': /* pit task -q [number | [-n name] [-s status] [-p priority] [-d date] [-t time]] */
|
||||
number = pit_arg_number(++arg, NULL);
|
||||
@@ -256,7 +293,7 @@ void pit_task(char *argv[])
|
||||
} else {
|
||||
task_parse_options(--arg, &name, &status, &priority, &date, &time);
|
||||
if (!name && !status && !priority && !date && !time) {
|
||||
task_show(0);
|
||||
task_show(0); /* Show current task if any. */
|
||||
} else {
|
||||
task_list(name, status, priority, date, time);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
#include <sys/types.h>
|
||||
#include "pit.h"
|
||||
|
||||
char *str2str(char *str) {
|
||||
return strcpy(malloc(strlen(str) + 1), str); /* Cheap strdup() */
|
||||
}
|
||||
|
||||
char *mem2str(char *mem, int len) {
|
||||
char *str = malloc(len + 1);
|
||||
memcpy(str, mem, len);
|
||||
|
||||
Reference in New Issue
Block a user