mirror of
https://github.com/michaeldv/pit.git
synced 2025-12-09 16:05:35 +00:00
273 lines
7.8 KiB
C
273 lines
7.8 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include "pit.h"
|
|
|
|
static void project_list(POptions po);
|
|
static void project_show(int id);
|
|
static void project_create(POptions po);
|
|
static void project_update(int id, POptions po);
|
|
static void project_delete(int id);
|
|
static bool project_already_exist(char *name);
|
|
static int project_find_current(int id, PProject *ppp);
|
|
static void project_log_create(PProject pp, POptions po);
|
|
static void project_log_update(PProject pp, POptions po);
|
|
static void project_log_delete(int id, char *name, int number_of_tasks);
|
|
static void project_parse_options(char **arg, POptions po);
|
|
|
|
/*
|
|
** 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 project_list(POptions po)
|
|
{
|
|
PPager ppager;
|
|
|
|
pit_db_load();
|
|
if (projects->number_of_records > 0) {
|
|
ppager = pit_pager_initialize(PAGER_PROJECT, projects->number_of_records);
|
|
for_each_project(pp) {
|
|
pit_pager_print(ppager, (char *)pp);
|
|
}
|
|
pit_pager_flush(ppager);
|
|
}
|
|
}
|
|
|
|
static void project_show(int id)
|
|
{
|
|
PProject pp;
|
|
|
|
pit_db_load();
|
|
id = project_find_current(id, &pp);
|
|
|
|
if (pp) {
|
|
printf("* %d: (%s) %s (status: %s, %d task%s)\n", pp->id, pp->username, pp->name, pp->status, pp->number_of_tasks, (pp->number_of_tasks != 1 ? "s" : ""));
|
|
printf("The project was created on %s, last updated on %s\n", format_timestamp(pp->created_at), format_timestamp(pp->updated_at));
|
|
pit_table_mark(projects, pp->id);
|
|
pit_db_save();
|
|
} else {
|
|
die("could not find the project");
|
|
}
|
|
}
|
|
|
|
static void project_create(POptions po)
|
|
{
|
|
pit_db_load();
|
|
|
|
if (project_already_exist(po->project.name)) {
|
|
die("project with the same name already exists");
|
|
} else {
|
|
Project p, *pp;
|
|
|
|
memset(&p, 0, sizeof(p));
|
|
|
|
if (!po->project.status) po->project.status = "active";
|
|
|
|
strncpy(p.name, po->project.name, sizeof(p.name) - 1);
|
|
strncpy(p.status, po->project.status, sizeof(p.status) - 1);
|
|
strncpy(p.username, current_user(), sizeof(p.username) - 1);
|
|
|
|
pp = (PProject)pit_table_insert(projects, (char *)&p);
|
|
pit_table_mark(projects, pp->id);
|
|
|
|
project_log_create(pp, po);
|
|
pit_db_save();
|
|
}
|
|
}
|
|
|
|
static void project_update(int id, POptions po)
|
|
{
|
|
PProject pp;
|
|
|
|
pit_db_load();
|
|
id = project_find_current(id, &pp);
|
|
|
|
if (po->project.name) strncpy(pp->name, po->project.name, sizeof(pp->name) - 1);
|
|
if (po->project.status) strncpy(pp->status, po->project.status, sizeof(pp->status) - 1);
|
|
pit_table_mark(projects, pp->id);
|
|
|
|
project_log_update(pp, po);
|
|
pit_db_save();
|
|
}
|
|
|
|
static void project_delete(int id)
|
|
{
|
|
PProject pp;
|
|
|
|
pit_db_load();
|
|
id = project_find_current(id, &pp);
|
|
/*
|
|
** 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.
|
|
*/
|
|
char *deleted_name = str2str(pp->name);
|
|
int deleted_number_of_tasks = pp->number_of_tasks;
|
|
|
|
pp = (PProject)pit_table_delete(projects, id);
|
|
if (pp) {
|
|
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");
|
|
}
|
|
}
|
|
|
|
static bool project_already_exist(char *name)
|
|
{
|
|
pit_db_load();
|
|
for_each_project(pp) {
|
|
if (!strcmp(pp->name, name)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static int project_find_current(int id, PProject *ppp)
|
|
{
|
|
if (id) {
|
|
*ppp = (PProject)pit_table_find(projects, id);
|
|
if (!*ppp) die("could not find project %d", id);
|
|
} else {
|
|
*ppp = (PProject)pit_table_current(projects);
|
|
if (!*ppp) die("could not find current project");
|
|
}
|
|
return *ppp ? (*(PProject *)ppp)->id : 0;
|
|
}
|
|
|
|
static void project_log_create(PProject pp, POptions po)
|
|
{
|
|
char str[256];
|
|
|
|
sprintf(str, "created project %d: %s (status: %s)", pp->id, po->project.name, po->project.status);
|
|
puts(str);
|
|
pit_action(pp->id, "project", str);
|
|
}
|
|
|
|
static void project_log_update(PProject pp, POptions po)
|
|
{
|
|
char str[256];
|
|
bool empty = TRUE;
|
|
|
|
sprintf(str, "updated project %d:", pp->id);
|
|
if (po->project.name) {
|
|
sprintf(str + strlen(str), " (name: %s", po->project.name);
|
|
empty = FALSE;
|
|
} else {
|
|
sprintf(str + strlen(str), " %s (", pp->name);
|
|
}
|
|
if (po->project.status) {
|
|
sprintf(str + strlen(str), "%sstatus: %s)", (empty ? "" : ", "), po->project.status);
|
|
}
|
|
strcat(str, ")");
|
|
puts(str);
|
|
pit_action(pp->id, "project", str);
|
|
}
|
|
|
|
static void project_log_delete(int id, char *name, int number_of_tasks)
|
|
{
|
|
char str[256];
|
|
|
|
sprintf(str, "deleted project %d: %s", id, name);
|
|
if (number_of_tasks > 0) {
|
|
sprintf(str + strlen(str), " with %d task%s", number_of_tasks, (number_of_tasks == 1 ? "" : "s"));
|
|
}
|
|
puts(str);
|
|
pit_action(id, "project", str);
|
|
}
|
|
|
|
static void project_parse_options(char **arg, POptions po)
|
|
{
|
|
while(*++arg) {
|
|
switch(pit_arg_option(arg)) {
|
|
case 'n':
|
|
po->project.name = pit_arg_string(++arg, "project name");
|
|
break;
|
|
case 's':
|
|
po->project.status = pit_arg_string(++arg, "project status");
|
|
break;
|
|
default:
|
|
die("invalid project option: %s", *arg);
|
|
}
|
|
}
|
|
}
|
|
|
|
void pit_project(char *argv[])
|
|
{
|
|
Options opt;
|
|
char **arg = &argv[1];
|
|
int number = 0;
|
|
|
|
memset(&opt, 0, sizeof(opt));
|
|
if (!*arg) {
|
|
project_list(&opt); /* Show all projects. */
|
|
} else { /* pit project [number] */
|
|
number = pit_arg_number(arg, NULL);
|
|
if (number) {
|
|
project_show(number);
|
|
} else {
|
|
switch(pit_arg_option(arg)) {
|
|
case 'c': /* pit project -c name [-s status] */
|
|
opt.project.name = pit_arg_string(++arg, "project name");
|
|
project_parse_options(arg, &opt);
|
|
project_create(&opt);
|
|
break;
|
|
case 'e': /* pit project -e [number] [-n name] [-s status] */
|
|
number = pit_arg_number(++arg, NULL);
|
|
if (!number) --arg;
|
|
project_parse_options(arg, &opt);
|
|
if (is_zero((char *)&opt.project, sizeof(opt.project))) {
|
|
die("nothing to update");
|
|
} else {
|
|
project_update(number, &opt);
|
|
}
|
|
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, &opt);
|
|
if (is_zero((char *)&opt.project, sizeof(opt.project))) {
|
|
project_show(0); /* Show current project if any. */
|
|
} else {
|
|
project_list(&opt);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
die("invalid project option: %s", *arg);
|
|
}
|
|
}
|
|
}
|
|
}
|