From a1d16aabbf7ce25286059df87cdc30fe46fdb867 Mon Sep 17 00:00:00 2001 From: Tristan Partin Date: Sun, 9 Feb 2020 20:09:13 -0600 Subject: [PATCH] harvest-glib: continue organization --- harvest-glib/estimate/harvest-estimate.c | 10 +- harvest-glib/harvest.h | 5 +- harvest-glib/meson.build | 5 +- .../harvest-project-task-assignment.c} | 45 +-- ...nt.h => harvest-project-task-assignment.h} | 6 +- ...nt.c => harvest-project-user-assignment.c} | 47 +-- .../harvest-project-user-assignment.h} | 6 +- harvest-glib/project/meson.build | 3 +- harvest-glib/task/meson.build | 1 - harvest-glib/time-entry/harvest-time-entry.c | 54 ++-- .../requests/harvest-late-request.c | 4 + .../user/harvest-user-project-assignment.c | 300 ++++++++++++++++++ .../user/harvest-user-project-assignment.h | 15 + harvest-glib/user/meson.build | 1 + 14 files changed, 415 insertions(+), 87 deletions(-) rename harvest-glib/{task/harvest-task-assignment.c => project/harvest-project-task-assignment.c} (78%) rename harvest-glib/project/{harvest-user-assignment.h => harvest-project-task-assignment.h} (50%) rename harvest-glib/project/{harvest-user-assignment.c => harvest-project-user-assignment.c} (79%) rename harvest-glib/{task/harvest-task-assignment.h => project/harvest-project-user-assignment.h} (50%) create mode 100644 harvest-glib/user/harvest-user-project-assignment.c create mode 100644 harvest-glib/user/harvest-user-project-assignment.h diff --git a/harvest-glib/estimate/harvest-estimate.c b/harvest-glib/estimate/harvest-estimate.c index 7fd9275..304f22f 100644 --- a/harvest-glib/estimate/harvest-estimate.c +++ b/harvest-glib/estimate/harvest-estimate.c @@ -98,11 +98,11 @@ harvest_estimate_deserialize_property(JsonSerializable *serializable, const gcha return TRUE; } else if (g_strcmp0(prop_name, "line_items") == 0) { - JsonArray *arr = json_node_get_array(prop_node); - const guint length = json_array_get_length(arr); - GPtrArray *roles = g_ptr_array_sized_new(length); - json_array_foreach_element(arr, line_items_for_each, roles); - g_value_set_boxed(val, roles); + JsonArray *arr = json_node_get_array(prop_node); + const guint length = json_array_get_length(arr); + GPtrArray *line_items = g_ptr_array_sized_new(length); + json_array_foreach_element(arr, line_items_for_each, line_items); + g_value_set_boxed(val, line_items); return TRUE; } else if (g_strcmp0(prop_name, "creator") == 0) { diff --git a/harvest-glib/harvest.h b/harvest-glib/harvest.h index 926b7d9..6c6bb9b 100644 --- a/harvest-glib/harvest.h +++ b/harvest-glib/harvest.h @@ -25,12 +25,13 @@ #include "harvest-glib/invoice/harvest-invoice-item-category.h" #include "harvest-glib/invoice/harvest-invoice-line-item.h" #include "harvest-glib/invoice/harvest-invoice.h" +#include "harvest-glib/project/harvest-project-task-assignment.h" +#include "harvest-glib/project/harvest-project-user-assignment.h" #include "harvest-glib/project/harvest-project.h" -#include "harvest-glib/project/harvest-user-assignment.h" -#include "harvest-glib/task/harvest-task-assignment.h" #include "harvest-glib/task/harvest-task.h" #include "harvest-glib/time-entry/harvest-time-entry.h" #include "harvest-glib/time-entry/requests/harvest-late-request.h" +#include "harvest-glib/user/harvest-user-project-assignment.h" #include "harvest-glib/user/harvest-user.h" #include "harvest-glib/user/requests/harvest-users-me-request.h" diff --git a/harvest-glib/meson.build b/harvest-glib/meson.build index a08a458..881706c 100644 --- a/harvest-glib/meson.build +++ b/harvest-glib/meson.build @@ -31,12 +31,13 @@ harvest_glib_sources = [ 'invoice/harvest-invoice-item-category.c', 'invoice/harvest-invoice-line-item.c', 'invoice/harvest-invoice.c', + 'project/harvest-project-task-assignment.c', + 'project/harvest-project-user-assignment.c', 'project/harvest-project.c', - 'project/harvest-user-assignment.c', - 'task/harvest-task-assignment.c', 'task/harvest-task.c', 'time-entry/harvest-time-entry.c', 'time-entry/requests/harvest-late-request.c', + 'user/harvest-user-project-assignment.c', 'user/harvest-user.c', 'user/requests/harvest-users-me-request.c' ] diff --git a/harvest-glib/task/harvest-task-assignment.c b/harvest-glib/project/harvest-project-task-assignment.c similarity index 78% rename from harvest-glib/task/harvest-task-assignment.c rename to harvest-glib/project/harvest-project-task-assignment.c index aa48048..90d4ee2 100644 --- a/harvest-glib/task/harvest-task-assignment.c +++ b/harvest-glib/project/harvest-project-task-assignment.c @@ -7,11 +7,11 @@ #include #include +#include "harvest-glib/project/harvest-project-task-assignment.h" #include "harvest-glib/project/harvest-project.h" -#include "harvest-glib/task/harvest-task-assignment.h" #include "harvest-glib/task/harvest-task.h" -struct _HarvestTaskAssignment +struct _HarvestProjectTaskAssignment { GObject parent_instance; @@ -26,12 +26,14 @@ struct _HarvestTaskAssignment GDateTime *updated_at; }; -static void harvest_task_assignment_json_serializable_init(JsonSerializableIface *iface); +static void harvest_project_task_assignment_json_serializable_init(JsonSerializableIface *iface); -G_DEFINE_TYPE_WITH_CODE(HarvestTaskAssignment, harvest_task_assignment, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(JSON_TYPE_SERIALIZABLE, harvest_task_assignment_json_serializable_init)) +G_DEFINE_TYPE_WITH_CODE(HarvestProjectTaskAssignment, harvest_project_task_assignment, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE( + JSON_TYPE_SERIALIZABLE, harvest_project_task_assignment_json_serializable_init)) -enum HarvestTaskAssignmentProps +enum HarvestProjectTaskAssignmentProps { PROP_0, PROP_ID, @@ -49,7 +51,7 @@ enum HarvestTaskAssignmentProps static GParamSpec *obj_properties[N_PROPS]; static gboolean -harvest_task_assignment_json_deserialize_property(JsonSerializable *serializable, +harvest_project_task_assignment_json_deserialize_property(JsonSerializable *serializable, const gchar *prop_name, GValue *val, GParamSpec *pspec, JsonNode *prop_node) { if (g_strcmp0(prop_name, "created_at") == 0 || g_strcmp0(prop_name, "updated_at") == 0) { @@ -74,15 +76,15 @@ harvest_task_assignment_json_deserialize_property(JsonSerializable *serializable } static void -harvest_task_assignment_json_serializable_init(JsonSerializableIface *iface) +harvest_project_task_assignment_json_serializable_init(JsonSerializableIface *iface) { - iface->deserialize_property = harvest_task_assignment_json_deserialize_property; + iface->deserialize_property = harvest_project_task_assignment_json_deserialize_property; } static void -harvest_task_assignment_finalize(GObject *obj) +harvest_project_task_assignment_finalize(GObject *obj) { - HarvestTaskAssignment *self = HARVEST_TASK_ASSIGNMENT(obj); + HarvestProjectTaskAssignment *self = HARVEST_PROJECT_TASK_ASSIGNMENT(obj); if (self->project != NULL) g_object_unref(self->project); @@ -93,13 +95,14 @@ harvest_task_assignment_finalize(GObject *obj) if (self->updated_at != NULL) g_date_time_unref(self->updated_at); - G_OBJECT_CLASS(harvest_task_assignment_parent_class)->finalize(obj); + G_OBJECT_CLASS(harvest_project_task_assignment_parent_class)->finalize(obj); } static void -harvest_task_assignment_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *pspec) +harvest_project_task_assignment_get_property( + GObject *obj, guint prop_id, GValue *val, GParamSpec *pspec) { - HarvestTaskAssignment *self = HARVEST_TASK_ASSIGNMENT(obj); + HarvestProjectTaskAssignment *self = HARVEST_PROJECT_TASK_ASSIGNMENT(obj); switch (prop_id) { case PROP_ID: @@ -135,10 +138,10 @@ harvest_task_assignment_get_property(GObject *obj, guint prop_id, GValue *val, G } static void -harvest_task_assignment_set_property( +harvest_project_task_assignment_set_property( GObject *obj, guint prop_id, const GValue *val, GParamSpec *pspec) { - HarvestTaskAssignment *self = HARVEST_TASK_ASSIGNMENT(obj); + HarvestProjectTaskAssignment *self = HARVEST_PROJECT_TASK_ASSIGNMENT(obj); switch (prop_id) { case PROP_ID: @@ -182,13 +185,13 @@ harvest_task_assignment_set_property( } static void -harvest_task_assignment_class_init(HarvestTaskAssignmentClass *klass) +harvest_project_task_assignment_class_init(HarvestProjectTaskAssignmentClass *klass) { GObjectClass *obj_class = G_OBJECT_CLASS(klass); - obj_class->finalize = harvest_task_assignment_finalize; - obj_class->get_property = harvest_task_assignment_get_property; - obj_class->set_property = harvest_task_assignment_set_property; + obj_class->finalize = harvest_project_task_assignment_finalize; + obj_class->get_property = harvest_project_task_assignment_get_property; + obj_class->set_property = harvest_project_task_assignment_set_property; obj_properties[PROP_ID] = g_param_spec_int("id", _("ID"), _("Unique ID for the task assignment."), 0, INT_MAX, 0, @@ -223,5 +226,5 @@ harvest_task_assignment_class_init(HarvestTaskAssignmentClass *klass) } static void -harvest_task_assignment_init(G_GNUC_UNUSED HarvestTaskAssignment *self) +harvest_project_task_assignment_init(G_GNUC_UNUSED HarvestProjectTaskAssignment *self) {} diff --git a/harvest-glib/project/harvest-user-assignment.h b/harvest-glib/project/harvest-project-task-assignment.h similarity index 50% rename from harvest-glib/project/harvest-user-assignment.h rename to harvest-glib/project/harvest-project-task-assignment.h index 98dfd25..a89783e 100644 --- a/harvest-glib/project/harvest-user-assignment.h +++ b/harvest-glib/project/harvest-project-task-assignment.h @@ -8,8 +8,8 @@ G_BEGIN_DECLS -#define HARVEST_TYPE_USER_ASSIGNMENT (harvest_invoice_get_type()) -G_DECLARE_FINAL_TYPE( - HarvestUserAssignment, harvest_user_assignment, HARVEST, USER_ASSIGNMENT, GObject) +#define HARVEST_TYPE_PROJECT_TASK_ASSIGNMENT (harvest_project_task_assignment_get_type()) +G_DECLARE_FINAL_TYPE(HarvestProjectTaskAssignment, harvest_project_task_assignment, HARVEST, + PROJECT_TASK_ASSIGNMENT, GObject) G_END_DECLS diff --git a/harvest-glib/project/harvest-user-assignment.c b/harvest-glib/project/harvest-project-user-assignment.c similarity index 79% rename from harvest-glib/project/harvest-user-assignment.c rename to harvest-glib/project/harvest-project-user-assignment.c index fb06d5c..3eb184a 100644 --- a/harvest-glib/project/harvest-user-assignment.c +++ b/harvest-glib/project/harvest-project-user-assignment.c @@ -7,11 +7,11 @@ #include #include +#include "harvest-glib/project/harvest-project-user-assignment.h" #include "harvest-glib/project/harvest-project.h" -#include "harvest-glib/project/harvest-user-assignment.h" #include "harvest-glib/user/harvest-user.h" -struct _HarvestUserAssignment +struct _HarvestProjectUserAssignment { GObject parent_instance; @@ -27,12 +27,14 @@ struct _HarvestUserAssignment GDateTime *updated_at; }; -static void harvest_user_assignment_json_serializable_init(JsonSerializableIface *iface); +static void harvest_project_user_assignment_json_serializable_init(JsonSerializableIface *iface); -G_DEFINE_TYPE_WITH_CODE(HarvestUserAssignment, harvest_user_assignment, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(JSON_TYPE_SERIALIZABLE, harvest_user_assignment_json_serializable_init)) +G_DEFINE_TYPE_WITH_CODE(HarvestProjectUserAssignment, harvest_project_user_assignment, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE( + JSON_TYPE_SERIALIZABLE, harvest_project_user_assignment_json_serializable_init)) -enum HarvestUserAssignmentProps +enum HarvestProjectUserAssignmentProps { PROP_0, PROP_ID, @@ -51,8 +53,8 @@ enum HarvestUserAssignmentProps static GParamSpec *obj_properties[N_PROPS]; static gboolean -harvest_user_assignment_deserialize_property(JsonSerializable *serializable, const gchar *prop_name, - GValue *val, GParamSpec *pspec, JsonNode *prop_node) +harvest_project_user_assignment_deserialize_property(JsonSerializable *serializable, + const gchar *prop_name, GValue *val, GParamSpec *pspec, JsonNode *prop_node) { if (g_strcmp0(prop_name, "created_at") == 0 || g_strcmp0(prop_name, "updated_at") == 0) { const GDateTime *dt = g_date_time_new_from_iso8601(json_node_get_string(prop_node), NULL); @@ -76,15 +78,15 @@ harvest_user_assignment_deserialize_property(JsonSerializable *serializable, con } static void -harvest_user_assignment_json_serializable_init(JsonSerializableIface *iface) +harvest_project_user_assignment_json_serializable_init(JsonSerializableIface *iface) { - iface->deserialize_property = harvest_user_assignment_deserialize_property; + iface->deserialize_property = harvest_project_user_assignment_deserialize_property; } static void -harvest_user_assignment_finalize(GObject *obj) +harvest_project_user_assignment_finalize(GObject *obj) { - HarvestUserAssignment *self = HARVEST_USER_ASSIGNMENT(obj); + HarvestProjectUserAssignment *self = HARVEST_PROJECT_USER_ASSIGNMENT(obj); if (self->project != NULL) g_object_unref(self->project); @@ -95,13 +97,14 @@ harvest_user_assignment_finalize(GObject *obj) if (self->updated_at != NULL) g_date_time_unref(self->updated_at); - G_OBJECT_CLASS(harvest_user_assignment_parent_class)->finalize(obj); + G_OBJECT_CLASS(harvest_project_user_assignment_parent_class)->finalize(obj); } static void -harvest_user_assignment_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *pspec) +harvest_project_user_assignment_get_property( + GObject *obj, guint prop_id, GValue *val, GParamSpec *pspec) { - HarvestUserAssignment *self = HARVEST_USER_ASSIGNMENT(obj); + HarvestProjectUserAssignment *self = HARVEST_PROJECT_USER_ASSIGNMENT(obj); switch (prop_id) { case PROP_ID: @@ -140,10 +143,10 @@ harvest_user_assignment_get_property(GObject *obj, guint prop_id, GValue *val, G } static void -harvest_user_assignment_set_property( +harvest_project_user_assignment_set_property( GObject *obj, guint prop_id, const GValue *val, GParamSpec *pspec) { - HarvestUserAssignment *self = HARVEST_USER_ASSIGNMENT(obj); + HarvestProjectUserAssignment *self = HARVEST_PROJECT_USER_ASSIGNMENT(obj); switch (prop_id) { case PROP_ID: @@ -190,13 +193,13 @@ harvest_user_assignment_set_property( } static void -harvest_user_assignment_class_init(HarvestUserAssignmentClass *klass) +harvest_project_user_assignment_class_init(HarvestProjectUserAssignmentClass *klass) { GObjectClass *obj_class = G_OBJECT_CLASS(klass); - obj_class->finalize = harvest_user_assignment_finalize; - obj_class->get_property = harvest_user_assignment_get_property; - obj_class->set_property = harvest_user_assignment_set_property; + obj_class->finalize = harvest_project_user_assignment_finalize; + obj_class->get_property = harvest_project_user_assignment_get_property; + obj_class->set_property = harvest_project_user_assignment_set_property; obj_properties[PROP_ID] = g_param_spec_int("id", _("ID"), _("Unique ID for the user assignment."), 0, INT_MAX, 0, @@ -237,5 +240,5 @@ harvest_user_assignment_class_init(HarvestUserAssignmentClass *klass) } static void -harvest_user_assignment_init(G_GNUC_UNUSED HarvestUserAssignment *self) +harvest_project_user_assignment_init(G_GNUC_UNUSED HarvestProjectUserAssignment *self) {} diff --git a/harvest-glib/task/harvest-task-assignment.h b/harvest-glib/project/harvest-project-user-assignment.h similarity index 50% rename from harvest-glib/task/harvest-task-assignment.h rename to harvest-glib/project/harvest-project-user-assignment.h index a7eab04..6702f3f 100644 --- a/harvest-glib/task/harvest-task-assignment.h +++ b/harvest-glib/project/harvest-project-user-assignment.h @@ -8,8 +8,8 @@ G_BEGIN_DECLS -#define HARVEST_TYPE_TASK_ASSIGNMENT (harvest_task_assignment_get_type()) -G_DECLARE_FINAL_TYPE( - HarvestTaskAssignment, harvest_task_assignment, HARVEST, TASK_ASSIGNMENT, GObject) +#define HARVEST_TYPE_PROJECT_USER_ASSIGNMENT (harvest_project_user_assignment_get_type()) +G_DECLARE_FINAL_TYPE(HarvestProjectUserAssignment, harvest_project_user_assignment, HARVEST, + PROJECT_USER_ASSIGNMENT, GObject) G_END_DECLS diff --git a/harvest-glib/project/meson.build b/harvest-glib/project/meson.build index 73eba10..713500e 100644 --- a/harvest-glib/project/meson.build +++ b/harvest-glib/project/meson.build @@ -1,6 +1,7 @@ component_public_headers = [ + 'harvest-project-task-assignment.h', + 'harvest-project-user-assignment.h', 'harvest-project.h', - 'harvest-user-assignment.h', ] component_header_subdir = join_paths(harvest_glib_header_subdir, 'project') diff --git a/harvest-glib/task/meson.build b/harvest-glib/task/meson.build index bf74042..b01bb29 100644 --- a/harvest-glib/task/meson.build +++ b/harvest-glib/task/meson.build @@ -1,5 +1,4 @@ component_public_headers = [ - 'harvest-task-assignment.h', 'harvest-task.h', ] diff --git a/harvest-glib/time-entry/harvest-time-entry.c b/harvest-glib/time-entry/harvest-time-entry.c index 6a13449..6564b89 100644 --- a/harvest-glib/time-entry/harvest-time-entry.c +++ b/harvest-glib/time-entry/harvest-time-entry.c @@ -10,9 +10,9 @@ #include "harvest-glib/client/harvest-client.h" #include "harvest-glib/common/harvest-common.h" #include "harvest-glib/invoice/harvest-invoice.h" +#include "harvest-glib/project/harvest-project-task-assignment.h" +#include "harvest-glib/project/harvest-project-user-assignment.h" #include "harvest-glib/project/harvest-project.h" -#include "harvest-glib/project/harvest-user-assignment.h" -#include "harvest-glib/task/harvest-task-assignment.h" #include "harvest-glib/task/harvest-task.h" #include "harvest-glib/time-entry/harvest-time-entry.h" #include "harvest-glib/user/harvest-user.h" @@ -24,11 +24,11 @@ struct _HarvestTimeEntry int id; GDateTime *spent_date; HarvestUser *user; - HarvestUserAssignment *user_assignment; + HarvestProjectUserAssignment *user_assignment; HarvestClient *client; HarvestProject *project; HarvestTask *task; - HarvestTaskAssignment *task_assingment; + HarvestProjectTaskAssignment *task_assignment; HarvestInvoice *invoice; double hours; char *notes; @@ -111,7 +111,7 @@ harvest_time_entry_deserialize_property(JsonSerializable *serializable, const gc return TRUE; } else if (g_strcmp0(prop_name, "user_assignment") == 0) { - GObject *obj = json_gobject_deserialize(HARVEST_TYPE_USER_ASSIGNMENT, prop_node); + GObject *obj = json_gobject_deserialize(HARVEST_TYPE_PROJECT_USER_ASSIGNMENT, prop_node); g_value_set_object(val, obj); return TRUE; @@ -131,7 +131,7 @@ harvest_time_entry_deserialize_property(JsonSerializable *serializable, const gc return TRUE; } else if (g_strcmp0(prop_name, "task_assignment") == 0) { - GObject *obj = json_gobject_deserialize(HARVEST_TYPE_TASK_ASSIGNMENT, prop_node); + GObject *obj = json_gobject_deserialize(HARVEST_TYPE_PROJECT_TASK_ASSIGNMENT, prop_node); g_value_set_object(val, obj); return TRUE; @@ -169,8 +169,8 @@ harvest_time_entry_finalize(GObject *obj) g_object_unref(self->project); if (self->task != NULL) g_object_unref(self->task); - if (self->task_assingment != NULL) - g_object_unref(self->task_assingment); + if (self->task_assignment != NULL) + g_object_unref(self->task_assignment); if (self->invoice != NULL) g_object_unref(self->invoice); g_free(self->notes); @@ -217,7 +217,7 @@ harvest_time_entry_get_property(GObject *obj, guint prop_id, GValue *val, GParam g_value_set_object(val, self->task); break; case PROP_TASK_ASSIGNMEMT: - g_value_set_object(val, self->task_assingment); + g_value_set_object(val, self->task_assignment); break; case PROP_INVOICE: g_value_set_object(val, self->invoice); @@ -315,9 +315,9 @@ harvest_time_entry_set_property(GObject *obj, guint prop_id, const GValue *val, self->task = g_value_get_object(val); break; case PROP_TASK_ASSIGNMEMT: - if (self->task_assingment != NULL) - g_object_unref(self->task_assingment); - self->task_assingment = g_value_get_object(val); + if (self->task_assignment != NULL) + g_object_unref(self->task_assignment); + self->task_assignment = g_value_get_object(val); break; case PROP_INVOICE: if (self->invoice != NULL) @@ -403,31 +403,31 @@ harvest_time_entry_class_init(HarvestTimeEntryClass *klass) obj_properties[PROP_SPENT_DATE] = g_param_spec_boxed("spent_date", _("Spent Date"), _("Date of the time entry."), G_TYPE_DATE_TIME, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_USER] = g_param_spec_object("user", _("User"), - _("An object containing the id and name of the associated user."), HARVEST_TYPE_USER, + obj_properties[PROP_USER] = g_param_spec_object("user", _("User"), + _("An object containing the id and name of the associated user."), HARVEST_TYPE_USER, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_USER_ASSIGNMENT] = g_param_spec_object("user_assignment", + _("User Assignment"), _("A user assignment object of the associated user."), + HARVEST_TYPE_PROJECT_USER_ASSIGNMENT, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_USER_ASSIGNMENT] - = g_param_spec_object("user_assignment", _("User Assignment"), - _("A user assignment object of the associated user."), HARVEST_TYPE_USER_ASSIGNMENT, - G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_CLIENT] = g_param_spec_object("client", _("Client"), + obj_properties[PROP_CLIENT] = g_param_spec_object("client", _("Client"), _("An object containing the id and name of the associated client."), HARVEST_TYPE_CLIENT, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_PROJECT] = g_param_spec_object("project", _("Project"), + obj_properties[PROP_PROJECT] = g_param_spec_object("project", _("Project"), _("An object containing the id and name of the associated project."), HARVEST_TYPE_PROJECT, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_TASK] = g_param_spec_object("task", _("Task"), + obj_properties[PROP_TASK] = g_param_spec_object("task", _("Task"), _("An object containing the id and name of the associated task."), HARVEST_TYPE_TASK, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_TASK_ASSIGNMEMT] - = g_param_spec_object("task_assignment", _("Task Assignment"), - _("A task assignment object of the associated task."), HARVEST_TYPE_TASK_ASSIGNMENT, - G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_INVOICE] = g_param_spec_object("invoice", _("Invoice"), + obj_properties[PROP_TASK_ASSIGNMEMT] = g_param_spec_object("task_assignment", + _("Task Assignment"), _("A task assignment object of the associated task."), + HARVEST_TYPE_PROJECT_TASK_ASSIGNMENT, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_INVOICE] = g_param_spec_object("invoice", _("Invoice"), _("Once the time entry has been invoiced, this field will include the associated invoice’s " "id and number."), HARVEST_TYPE_INVOICE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_HOURS] = g_param_spec_double("hours", _("Hours"), + obj_properties[PROP_HOURS] = g_param_spec_double("hours", _("Hours"), _("Number of (decimal time) hours tracked in this time entry."), 0, DBL_MAX, 0, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_NOTES] diff --git a/harvest-glib/time-entry/requests/harvest-late-request.c b/harvest-glib/time-entry/requests/harvest-late-request.c index fb98f29..d0a16a5 100644 --- a/harvest-glib/time-entry/requests/harvest-late-request.c +++ b/harvest-glib/time-entry/requests/harvest-late-request.c @@ -109,9 +109,13 @@ harvest_late_request_set_property(GObject *obj, guint prop_id, const GValue *val switch (prop_id) { case PROP_USER_ID: + if (self->user_id != NULL) + g_variant_unref(self->user_id); self->user_id = g_value_dup_variant(val); break; case PROP_CLIENT_ID: + if (self->client_id != NULL) + g_variant_unref(self->client_id); self->client_id = g_value_dup_variant(val); break; case PROP_PROJECT_ID: diff --git a/harvest-glib/user/harvest-user-project-assignment.c b/harvest-glib/user/harvest-user-project-assignment.c new file mode 100644 index 0000000..2b5620e --- /dev/null +++ b/harvest-glib/user/harvest-user-project-assignment.c @@ -0,0 +1,300 @@ +#include "harvest-glib/config.h" + +#include +#include + +#include +#include +#include + +#include "harvest-glib/client/harvest-client.h" +#include "harvest-glib/project/harvest-project-task-assignment.h" +#include "harvest-glib/project/harvest-project.h" +#include "harvest-glib/user/harvest-user-project-assignment.h" +#include "harvest-glib/user/harvest-user.h" + +struct _HarvestUserProjectAssignment +{ + GObject parent_instance; + + int id; + gboolean is_active : 1; + gboolean is_project_manager : 1; + gboolean use_default_rates : 1; + double hourly_rate; + double budget; + GDateTime *created_at; + GDateTime *updated_at; + HarvestProject *project; + HarvestClient *client; + GPtrArray *task_assignments; // HarvestProjectTaskAssignment +}; + +static void harvest_user_project_assignment_json_serializable_init(JsonSerializableIface *iface); + +G_DEFINE_TYPE_WITH_CODE(HarvestUserProjectAssignment, harvest_user_project_assignment, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE( + JSON_TYPE_SERIALIZABLE, harvest_user_project_assignment_json_serializable_init)) + +enum HarvestUserProjectAssignmentProps +{ + PROP_0, + PROP_ID, + PROP_IS_ACTIVE, + PROP_IS_PROJECT_MANAGER, + PROP_USE_DEFAULT_RATES, + PROP_HOURLY_RATE, + PROP_BUDGET, + PROP_CREATED_AT, + PROP_UPDATED_AT, + PROP_PROJECT, + PROP_CLIENT, + PROP_TASK_ASSIGNMENTS, + N_PROPS, +}; + +static GParamSpec *obj_properties[N_PROPS]; + +static void +task_assignments_for_each( + G_GNUC_UNUSED JsonArray *array, G_GNUC_UNUSED guint index, JsonNode *node, gpointer user_data) +{ + g_ptr_array_add( + user_data, json_gobject_deserialize(HARVEST_TYPE_PROJECT_TASK_ASSIGNMENT, node)); +} + +static gboolean +harvest_user_project_assignment_deserialize_property(JsonSerializable *serializable, + const gchar *prop_name, GValue *val, GParamSpec *pspec, JsonNode *prop_node) +{ + if (g_strcmp0(prop_name, "created_at") == 0 || g_strcmp0(prop_name, "updated_at") == 0) { + const GDateTime *dt = g_date_time_new_from_iso8601(json_node_get_string(prop_node), NULL); + g_value_set_boxed(val, dt); + + return TRUE; + } else if (g_strcmp0(prop_name, "project") == 0) { + GObject *obj = json_gobject_deserialize(HARVEST_TYPE_PROJECT, prop_node); + g_value_set_object(val, obj); + + return TRUE; + } else if (g_strcmp0(prop_name, "client") == 0) { + GObject *obj = json_gobject_deserialize(HARVEST_TYPE_CLIENT, prop_node); + g_value_set_object(val, obj); + + return TRUE; + } else if (g_strcmp0(prop_name, "task_assignments") == 0) { + JsonArray *arr = json_node_get_array(prop_node); + const guint length = json_array_get_length(arr); + GPtrArray *task_assignments = g_ptr_array_sized_new(length); + json_array_foreach_element(arr, task_assignments_for_each, task_assignments); + g_value_set_boxed(val, task_assignments); + + return TRUE; + } + + return json_serializable_default_deserialize_property( + serializable, prop_name, val, pspec, prop_node); +} + +static void +harvest_user_project_assignment_json_serializable_init(JsonSerializableIface *iface) +{ + iface->deserialize_property = harvest_user_project_assignment_deserialize_property; +} + +static void +harvest_user_project_assignment_finalize(GObject *obj) +{ + HarvestUserProjectAssignment *self = HARVEST_USER_PROJECT_ASSIGNMENT(obj); + + if (self->created_at != NULL) + g_date_time_unref(self->created_at); + if (self->updated_at != NULL) + g_date_time_unref(self->updated_at); + if (self->project != NULL) + g_object_unref(self->project); + if (self->client != NULL) + g_object_unref(self->client); + if (self->task_assignments != NULL) { + /** + * Always remove the last one so that the array does not need to be resized. If we + * always remove the last one in conjunction with g_ptr_array_remove_index_fast, then + * the reverse order of the array should be preserved and we will be able to iterate + * linearly. + */ + for (int i = self->task_assignments->len - 1; i >= 0; i--) { + HarvestProjectTaskAssignment *task_assignment = HARVEST_PROJECT_TASK_ASSIGNMENT( + g_ptr_array_remove_index_fast(self->task_assignments, i)); + if (task_assignment != NULL) + g_object_unref(task_assignment); + } + g_ptr_array_unref(self->task_assignments); + } + + G_OBJECT_CLASS(harvest_user_project_assignment_parent_class)->finalize(obj); +} + +static void +harvest_user_project_assignment_get_property( + GObject *obj, guint prop_id, GValue *val, GParamSpec *pspec) +{ + HarvestUserProjectAssignment *self = HARVEST_USER_PROJECT_ASSIGNMENT(obj); + + switch (prop_id) { + case PROP_ID: + g_value_set_int(val, self->id); + break; + case PROP_IS_ACTIVE: + g_value_set_boolean(val, self->is_active); + break; + case PROP_IS_PROJECT_MANAGER: + g_value_set_boolean(val, self->is_project_manager); + break; + case PROP_USE_DEFAULT_RATES: + g_value_set_boolean(val, self->use_default_rates); + break; + case PROP_HOURLY_RATE: + g_value_set_double(val, self->hourly_rate); + break; + case PROP_BUDGET: + g_value_set_double(val, self->budget); + break; + case PROP_CREATED_AT: + g_value_set_boxed(val, self->created_at); + break; + case PROP_UPDATED_AT: + g_value_set_boxed(val, self->updated_at); + break; + case PROP_PROJECT: + g_value_set_object(val, self->project); + break; + case PROP_CLIENT: + g_value_set_object(val, self->client); + break; + case PROP_TASK_ASSIGNMENTS: + g_value_set_boxed(val, self->task_assignments); + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec); + } +} + +static void +harvest_user_project_assignment_set_property( + GObject *obj, guint prop_id, const GValue *val, GParamSpec *pspec) +{ + HarvestUserProjectAssignment *self = HARVEST_USER_PROJECT_ASSIGNMENT(obj); + + switch (prop_id) { + case PROP_ID: + self->id = g_value_get_int(val); + break; + case PROP_IS_ACTIVE: + self->is_active = g_value_get_boolean(val); + break; + case PROP_IS_PROJECT_MANAGER: + self->is_project_manager = g_value_get_boolean(val); + break; + case PROP_USE_DEFAULT_RATES: + self->use_default_rates = g_value_get_boolean(val); + break; + case PROP_HOURLY_RATE: + self->hourly_rate = g_value_get_double(val); + break; + case PROP_BUDGET: + self->budget = g_value_get_double(val); + break; + case PROP_CREATED_AT: + if (self->created_at != NULL) + g_date_time_unref(self->created_at); + self->created_at = g_value_dup_boxed(val); + break; + case PROP_UPDATED_AT: + if (self->updated_at != NULL) + g_date_time_unref(self->updated_at); + self->updated_at = g_value_dup_boxed(val); + break; + case PROP_PROJECT: + if (self->project != NULL) + g_object_unref(self->project); + self->project = g_value_dup_object(val); + break; + case PROP_CLIENT: + if (self->client != NULL) + g_object_unref(self->client); + self->client = g_value_dup_object(val); + break; + case PROP_TASK_ASSIGNMENTS: + if (self->task_assignments != NULL) { + /** + * Always remove the last one so that the array does not need to be resized. If we + * always remove the last one in conjunction with g_ptr_array_remove_index_fast, then + * the reverse order of the array should be preserved and we will be able to iterate + * linearly. + */ + for (int i = self->task_assignments->len - 1; i >= 0; i--) { + HarvestProjectTaskAssignment *task_assignment = HARVEST_PROJECT_TASK_ASSIGNMENT( + g_ptr_array_remove_index_fast(self->task_assignments, i)); + if (task_assignment != NULL) + g_object_unref(task_assignment); + } + g_ptr_array_unref(self->task_assignments); + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec); + } +} + +static void +harvest_user_project_assignment_class_init(HarvestUserProjectAssignmentClass *klass) +{ + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + + obj_class->finalize = harvest_user_project_assignment_finalize; + obj_class->get_property = harvest_user_project_assignment_get_property; + obj_class->set_property = harvest_user_project_assignment_set_property; + + obj_properties[PROP_ID] + = g_param_spec_int("id", _("ID"), _("Unique ID for the project assignment."), 0, INT_MAX, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_IS_ACTIVE] = g_param_spec_boolean("is_active", _("Is Active"), + _("Whether the project assignment is active or archived."), FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_IS_PROJECT_MANAGER] + = g_param_spec_boolean("is-project-manager", _("Is Project Manager"), + _("Determines if the user has project manager permissions for the project."), FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_USE_DEFAULT_RATES] = g_param_spec_boolean("use_default_rates", + _("Use Default Rates"), + _("Determines which billable rate(s) will be used on the project for this user when " + "bill_by is People. When true, the project will use the user’s default billable rates. " + "When false, the project will use the custom rate defined on this user assignment."), + FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_HOURLY_RATE] = g_param_spec_double("hourly-rate", _("Hourly Rate"), + _("Custom rate used when the project’s bill_by is People and use_default_rates is false."), + 0, DBL_MAX, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_BUDGET] = g_param_spec_double("budget", _("Budget"), + _("Budget used when the project’s budget_by is person."), 0, DBL_MAX, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_CREATED_AT] = g_param_spec_boxed("created-at", _("Created At"), + _("Date and time the project assignment was created."), G_TYPE_DATE_TIME, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_UPDATED_AT] = g_param_spec_boxed("updated-at", _("Updated At"), + _("Date and time the project assignment was last updated."), G_TYPE_DATE_TIME, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_PROJECT] = g_param_spec_object("project", _("Project"), + _("An object containing the assigned project id, name, and code."), HARVEST_TYPE_PROJECT, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_CLIENT] = g_param_spec_object("client", _("Client"), + _("An object containing the project’s client id and name."), HARVEST_TYPE_CLIENT, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_TASK_ASSIGNMENTS] = g_param_spec_boxed("task-assignments", + _("Task Assignments"), _("Array of task assignment objects associated with the project."), + G_TYPE_PTR_ARRAY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(obj_class, N_PROPS, obj_properties); +} + +static void +harvest_user_project_assignment_init(G_GNUC_UNUSED HarvestUserProjectAssignment *self) +{} diff --git a/harvest-glib/user/harvest-user-project-assignment.h b/harvest-glib/user/harvest-user-project-assignment.h new file mode 100644 index 0000000..c6aa79c --- /dev/null +++ b/harvest-glib/user/harvest-user-project-assignment.h @@ -0,0 +1,15 @@ +#pragma once + +#if !defined(__HARVEST_HEADER_INTERNAL__) && !defined(__HARVEST_COMPILATION__) +# error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +#define HARVEST_TYPE_USER_PROJECT_ASSIGNMENT (harvest_user_project_assignment_get_type()) +G_DECLARE_FINAL_TYPE(HarvestUserProjectAssignment, harvest_user_project_assignment, HARVEST, + USER_PROJECT_ASSIGNMENT, GObject) + +G_END_DECLS diff --git a/harvest-glib/user/meson.build b/harvest-glib/user/meson.build index c2fef44..74ec589 100644 --- a/harvest-glib/user/meson.build +++ b/harvest-glib/user/meson.build @@ -1,4 +1,5 @@ component_public_headers = [ + 'harvest-user-project-assignment.h', 'harvest-user.h', ] -- 2.45.2