--- /dev/null
+--
+-- PostgreSQL database dump
+--
+
+SET client_encoding = 'UNICODE';
+SET check_function_bodies = false;
+
+SET SESSION AUTHORIZATION 'postgres';
+
+--
+-- TOC entry 4 (OID 2200)
+-- Name: public; Type: ACL; Schema: -; Owner: postgres
+--
+
+REVOKE ALL ON SCHEMA public FROM PUBLIC;
+REVOKE ALL ON SCHEMA public FROM postgres;
+GRANT ALL ON SCHEMA public TO PUBLIC;
+
+
+SET SESSION AUTHORIZATION 'postgres';
+
+SET search_path = public, pg_catalog;
+
+--
+-- TOC entry 5 (OID 39310)
+-- Name: valori; Type: TABLE; Schema: public; Owner: postgres
+--
+
+CREATE TABLE valori (
+ id_azioni bigint NOT NULL,
+ id_campi integer NOT NULL,
+ valore character varying DEFAULT ''::character varying
+) WITHOUT OIDS;
+
+
+--
+-- TOC entry 6 (OID 39315)
+-- Name: tabelle; Type: TABLE; Schema: public; Owner: postgres
+--
+
+CREATE TABLE tabelle (
+ id integer NOT NULL,
+ nome character(30) DEFAULT ''::bpchar,
+ status character(1) DEFAULT ''::bpchar,
+ id_datasources integer NOT NULL
+) WITHOUT OIDS;
+
+
+--
+-- TOC entry 7 (OID 39321)
+-- Name: campi; Type: TABLE; Schema: public; Owner: postgres
+--
+
+CREATE TABLE campi (
+ id integer NOT NULL,
+ id_tabelle integer NOT NULL,
+ nome character(30) DEFAULT ''::bpchar,
+ status character(1) DEFAULT ''::bpchar,
+ id_datasources integer NOT NULL
+) WITHOUT OIDS;
+
+
+--
+-- TOC entry 8 (OID 39344)
+-- Name: azioni; Type: TABLE; Schema: public; Owner: postgres
+--
+
+CREATE TABLE azioni (
+ id bigint NOT NULL,
+ tipo_azione integer,
+ dn character(200) DEFAULT ''::bpchar,
+ data timestamp without time zone,
+ id_tabelle integer,
+ id_datasources integer
+) WITHOUT OIDS;
+
+
+--
+-- TOC entry 9 (OID 39357)
+-- Name: datasources; Type: TABLE; Schema: public; Owner: postgres
+--
+
+CREATE TABLE datasources (
+ id integer NOT NULL,
+ nome character(30) DEFAULT ''::bpchar,
+ status character(1) DEFAULT ''::bpchar
+) WITHOUT OIDS;
+
+
+--
+-- TOC entry 13 (OID 39347)
+-- Name: azioni_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY azioni
+ ADD CONSTRAINT azioni_pkey PRIMARY KEY (id);
+
+
+--
+-- TOC entry 14 (OID 39360)
+-- Name: database_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY datasources
+ ADD CONSTRAINT database_pkey PRIMARY KEY (id);
+
+
+--
+-- TOC entry 11 (OID 39363)
+-- Name: tabelle_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY tabelle
+ ADD CONSTRAINT tabelle_pkey PRIMARY KEY (id_datasources, id);
+
+
+--
+-- TOC entry 12 (OID 39365)
+-- Name: campi_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY campi
+ ADD CONSTRAINT campi_pkey PRIMARY KEY (id_datasources, id_tabelle, id);
+
+
+--
+-- TOC entry 10 (OID 39367)
+-- Name: valori_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY valori
+ ADD CONSTRAINT valori_pkey PRIMARY KEY (id_azioni, id_campi);
+
+
+--
+-- TOC entry 3 (OID 2200)
+-- Name: SCHEMA public; Type: COMMENT; Schema: -; Owner: postgres
+--
+
+COMMENT ON SCHEMA public IS 'Standard public namespace';
+
+
--- /dev/null
+/*
+ * audit.c
+ *
+ * Copyright (C) 2005-2010 Andrea Zagli <azagli@libero.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "libaudit.h"
+
+struct Audit_
+{
+ GdaEx *gdaex;
+ GList *datasources;
+
+ GHashTable *campi_upd;
+};
+
+typedef struct
+{
+ gint id;
+ gchar *name;
+} Field;
+
+typedef struct
+{
+ gint id;
+ gchar *name;
+ GList *fields;
+} Table;
+
+typedef struct
+{
+ gint id;
+ gchar *cnc_string;
+ GdaEx *gdaex;
+ GList *tables;
+} Datasource;
+
+/* PRIVATE */
+static Audit
+*audit_init_ ()
+{
+ Audit *audit;
+
+ audit = (Audit *)g_malloc (sizeof (Audit));
+ audit->datasources = NULL;
+ audit->campi_upd = NULL;
+
+ return audit;
+}
+
+static gboolean
+load_fields (Audit *audit,
+ Table *table)
+{
+ GdaDataModel *dm;
+ gchar *sql;
+ gint rows, row;
+ Field *cam;
+
+ sql = g_strdup_printf ("SELECT id, name FROM fields "
+ "WHERE status <> 'D' AND id_tabelle = %d",
+ table->id);
+ dm = gdaex_query (audit->gdaex, sql);
+
+ if (dm == NULL)
+ {
+ g_warning ("Per la table \"%s\" non sono stati configurati i fields.",
+ table->name);
+ return FALSE;
+ }
+
+ rows = gda_data_model_get_n_rows (dm);
+ if (rows == 0)
+ {
+ g_warning ("Per la table \"%s\" non sono stati configurati i fields.",
+ table->name);
+ return FALSE;
+ }
+
+ for (row = 0; row < rows; row++)
+ {
+ cam = (Field *)g_malloc (sizeof (Field));
+
+ cam->id = gdaex_data_model_get_field_value_integer_at (dm, 0, "id");
+ cam->name = gdaex_data_model_get_field_value_stringify_at (dm, 1, "name");
+
+ table->fields = g_list_append (table->fields, (gpointer)cam);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+load_tables (Audit *audit,
+ Datasource *datasource)
+{
+ GdaDataModel *dm;
+ gchar *sql;
+ gint rows, row;
+ Table *tab;
+
+ sql = g_strdup_printf ("SELECT id, name FROM tables "
+ "WHERE status <> 'D' AND id_datasources = %d",
+ datasource->id);
+ dm = gdaex_query (audit->gdaex, sql);
+
+ if (dm == NULL)
+ {
+ g_warning ("Per il datasource \"%d\" non sono state configurate le tables.",
+ datasource->id);
+ return FALSE;
+ }
+
+ rows = gda_data_model_get_n_rows (dm);
+ if (rows == 0)
+ {
+ g_warning ("Per il datasource \"%d\" non sono state configurate le tables.",
+ datasource->id);
+ return FALSE;
+ }
+
+ for (row = 0; row < rows; row++)
+ {
+ tab = (Table *)g_malloc (sizeof (Table));
+
+ tab->id = gdaex_data_model_get_field_value_integer_at (dm, 0, "id");
+ tab->name = gdaex_data_model_get_field_value_stringify_at (dm, 1, "name");
+
+ datasource->tables = g_list_append (datasource->tables, (gpointer)tab);
+
+ /* per ogni table devo caricare i fields */
+ tab->fields = NULL;
+ load_fields (audit, tab);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+load_datasources (Audit *audit)
+{
+ GdaDataModel *dm;
+ gchar *sql;
+ gint rows, row;
+ Datasource *datas;
+
+ /* per ogni datasource nella table datasources devo aprire una connessione */
+ dm = gdaex_query (audit->gdaex, "SELECT id, cnc_string"
+ " FROM datasources"
+ " WHERE status <> 'D'");
+ if (dm == NULL)
+ {
+ g_warning ("Non ci sono datasource configurati.");
+ return FALSE;
+ }
+
+ rows = gda_data_model_get_n_rows (dm);
+ if (rows == 0)
+ {
+ g_warning ("Non ci sono datasource configurati.");
+ return FALSE;
+ }
+
+ for (row = 0; row < rows; row++)
+ {
+ datas = (Datasource *)g_malloc (sizeof (Datasource));
+
+ datas->id = gdaex_data_model_get_field_value_integer_at (dm, 0, "id");
+ datas->cnc_string = gdaex_data_model_get_field_value_stringify_at (dm, 1, "cnc_string");
+
+ datas->gdaex = gdaex_new_from_string (datas->cnc_string);
+
+ audit->datasources = g_list_append (audit->datasources, (gpointer)datas);
+
+ /* per ogni datasource devo caricare tables e fields */
+ datas->tables = NULL;
+ load_tables (audit, datas);
+ }
+
+ return TRUE;
+}
+
+static Field
+*get_campo_from_nome (Audit *audit,
+ Table *table,
+ const char *field)
+{
+ GList *c = g_list_first (table->fields);
+
+ while (c != NULL)
+ {
+ if (strcmp (((Field *)c->data)->name, field) == 0)
+ {
+ return (Field *)c->data;
+ }
+
+ c = g_list_next (c);
+ }
+
+ return NULL;
+}
+
+static Table
+*get_tabella_from_nome (Audit *audit,
+ Datasource *datasource,
+ const char *table)
+{
+ GList *t = g_list_first (datasource->tables);
+
+ while (t != NULL)
+ {
+ if (strcmp (((Table *)t->data)->name, table) == 0)
+ {
+ return (Table *)t->data;
+ }
+
+ t = g_list_next (t);
+ }
+
+ return NULL;
+}
+
+static Datasource
+*get_datasource_from_nome (Audit *audit,
+ const char *datasource)
+{
+ /*GList *f = g_list_first (audit->datasources);
+
+ while (f != NULL)
+ {
+ if (strcmp (((Datasource *)f->data)->name, datasource) == 0)
+ {
+ return (Datasource *)f->data;
+ }
+
+ f = g_list_next (f);
+ }*/
+
+ return NULL;
+}
+
+static gboolean
+insert_value (Audit *audit,
+ gint id_azione,
+ Table *table,
+ gchar *nome_campo,
+ gchar *value)
+{
+ gchar *sql;
+
+ Field *field = get_campo_from_nome (audit, table, nome_campo);
+ if (field == NULL)
+ {
+ g_warning ("Impossibile trovare il field \"%s\" nei fields caricati",
+ nome_campo);
+ }
+ else
+ {
+ sql = g_strdup_printf ("INSERT INTO valori "
+ "(id_azioni, id_campi, value) "
+ "VALUES (%d, %d, '%s')",
+ id_azione, field->id, value);
+ gdaex_execute (audit->gdaex, sql);
+ }
+
+ return TRUE;
+}
+
+/* PUBLIC */
+
+/**
+ * audit_init:
+ * @gda_connection: un #GdaConnection.
+ *
+ * Returns: l'oggetto #Audit appena creato.
+ */
+Audit
+*audit_init (GdaConnection *gda_connection)
+{
+ Audit *audit = audit_init_ ();
+
+ audit->gdaex = gdaex_new_from_connection (gda_connection);
+
+ if (audit->gdaex == NULL)
+ {
+ /* TO DO */
+ return NULL;
+ }
+
+ /* carico i datasource */
+ if (!load_datasources (audit))
+ {
+ /* TO DO */
+ return NULL;
+ }
+
+ return audit;
+}
+
+/**
+ * audit_init:
+ * @cnc_string: la stringa di connessione al datasource che contiene le tabelle per la libreria.
+ *
+ * Returns: l'oggetto #Audit appena creato.
+ */
+Audit
+*audit_init_from_string (const gchar *cnc_string)
+{
+ Audit *audit = audit_init_ ();
+
+ audit->gdaex = gdaex_new_from_string (cnc_string);
+
+ if (audit->gdaex == NULL)
+ {
+ /* TO DO */
+ return NULL;
+ }
+
+ /* carico i datasource */
+ if (!load_datasources (audit))
+ {
+ /* TO DO */
+ return NULL;
+ }
+
+ return audit;
+}
+
+/**
+ * audit_action:
+ * @audit: l'oggetto #Audit su cui effettuare l'azione.
+ * @action: il tipo di azione.
+ * @dn: lo username che effettua l'azione.
+ * @datasource:
+ * @tabella:
+ *
+ * Returns: #TRUE se l'azione viene effettuata con successo.
+ */
+gboolean
+audit_action (Audit *audit,
+ enum AuditActions action,
+ const gchar *dn,
+ const gchar *nome_datasource,
+ const gchar *nome_tabella,
+ ...)
+{
+ GdaDataModel *dm;
+ gchar *sql, *sql_where, *nome_campo, *value, *valore_new;
+ gint id = 0, cols, col;
+ time_t t;
+ struct tm *tm_ora;
+ va_list vargs;
+ Datasource *datasource;
+ Table *table;
+
+ /* trovo il nuovo id azione */
+ dm = gdaex_query (audit->gdaex, "SELECT COALESCE(MAX(id), 0) FROM actions");
+
+ if (dm != NULL && gda_data_model_get_n_rows (dm) == 1)
+ {
+ id = atol (gdaex_data_model_get_value_stringify_at (dm, 0, 0));
+ }
+ id++;
+
+ /* trovo il timestamp dell'operazione */
+ t = time(NULL);
+ tm_ora = localtime(&t);
+
+ /* trovo il datasource */
+ datasource = get_datasource_from_nome (audit, nome_datasource);
+ if (datasource == NULL)
+ {
+ g_warning ("Impossibile trovare il datasource \"%s\" nei datasource caricati",
+ nome_datasource);
+ return FALSE;
+ }
+
+ /* trovo la table */
+ table = get_tabella_from_nome (audit, datasource, nome_tabella);
+ if (table == NULL)
+ {
+ g_warning ("Impossibile trovare la table \"%s\" nelle tables caricate",
+ nome_tabella);
+ return FALSE;
+ }
+
+ /* salvo l'azione */
+ if (action != AUDIT_ACTION_BEFORE_UPDATE)
+ {
+ sql = g_strdup_printf ("INSERT INTO azioni "
+ "(id, tipo_azione, dn, data, id_tabelle, id_datasources) "
+ "VALUES (%d, %d, '%s', '%04d-%02d-%02d %02d:%02d:%02d', %d, %d)",
+ id, action + 1, dn,
+ tm_ora->tm_year + 1900, tm_ora->tm_mon + 1, tm_ora->tm_mday,
+ tm_ora->tm_hour, tm_ora->tm_min, tm_ora->tm_sec,
+ table->id, datasource->id);
+ gdaex_execute (audit->gdaex, sql);
+ }
+
+ /* fields */
+ va_start (vargs, nome_tabella);
+
+ switch (action)
+ {
+ case AUDIT_ACTION_INSERT:
+ /* salvo tutti i fields */
+ sql = g_strdup_printf ("SELECT * FROM %s ",
+ nome_tabella);
+
+ sql_where = g_strdup ("WHERE TRUE");
+ nome_campo = va_arg (vargs, gchar *);
+ while (nome_campo != NULL)
+ {
+ value = va_arg (vargs, gchar *);
+ if (value == NULL) break;
+
+ sql_where = g_strjoin (NULL, sql_where, " AND ", nome_campo, "='", value, "'", NULL);
+ nome_campo = va_arg (vargs, gchar *);
+ }
+ sql = g_strjoin (NULL, sql, sql_where, NULL);
+ dm = gdaex_query (datasource->gdaex, sql);
+
+ if (dm == NULL) return FALSE;
+
+ if (gda_data_model_get_n_rows (dm) == 0) return FALSE;
+
+ cols = gda_data_model_get_n_columns (dm);
+ for (col = 0; col < cols; col++)
+ {
+ /* trovo il field */
+ nome_campo = (gchar *)gda_data_model_get_column_title (dm, col);
+ insert_value (audit, id, table, nome_campo,
+ gdaex_data_model_get_value_stringify_at (dm, col, 0));
+ }
+ break;
+
+ case AUDIT_ACTION_BEFORE_UPDATE:
+ /* memorizzo tutta la table che sta per essere modificata */
+ sql = g_strdup_printf ("SELECT * FROM %s ",
+ nome_tabella);
+
+ sql_where = g_strdup ("WHERE TRUE");
+ nome_campo = va_arg (vargs, gchar *);
+ while (nome_campo != NULL)
+ {
+ value = va_arg (vargs, gchar *);
+ if (value == NULL) break;
+
+ sql_where = g_strjoin (NULL, sql_where, " AND ", nome_campo, "='", value, "'", NULL);
+ nome_campo = va_arg (vargs, gchar *);
+ }
+ sql = g_strjoin (NULL, sql, sql_where, NULL);
+ dm = gdaex_query (datasource->gdaex, sql);
+
+ if (dm == NULL) return FALSE;
+
+ if (gda_data_model_get_n_rows (dm) == 0 ||
+ gda_data_model_get_n_rows (dm) > 1) return FALSE;
+
+ audit->campi_upd = g_hash_table_new (g_str_hash, g_str_equal);
+ cols = gda_data_model_get_n_columns (dm);
+ for (col = 0; col < cols; col++)
+ {
+ g_hash_table_insert (audit->campi_upd,
+ (gpointer)gda_data_model_get_column_title (dm, col),
+ (gpointer)gdaex_data_model_get_value_stringify_at (dm, col, 0));
+ }
+ break;
+
+ case AUDIT_ACTION_AFTER_UPDATE:
+ /* salvo i fields modificati */
+ sql = g_strdup_printf ("SELECT * FROM %s ",
+ nome_tabella);
+
+ sql_where = g_strdup ("WHERE TRUE");
+ nome_campo = va_arg (vargs, gchar *);
+ while (nome_campo != NULL)
+ {
+ value = va_arg (vargs, gchar *);
+ if (value == NULL) break;
+
+ sql_where = g_strjoin (NULL, sql_where, " AND ", nome_campo, "='", value, "'", NULL);
+ nome_campo = va_arg (vargs, gchar *);
+ }
+ sql = g_strjoin (NULL, sql, sql_where, NULL);
+ dm = gdaex_query (datasource->gdaex, sql);
+
+ if (dm == NULL) return FALSE;
+
+ if (gda_data_model_get_n_rows (dm) == 0 ||
+ gda_data_model_get_n_rows (dm) > 1) return FALSE;
+
+ cols = gda_data_model_get_n_columns (dm);
+ for (col = 0; col < cols; col++)
+ {
+ nome_campo = (gchar *)gda_data_model_get_column_title (dm, col);
+
+ value = (gchar *)g_hash_table_lookup (audit->campi_upd, (gconstpointer)nome_campo);
+ valore_new = gdaex_data_model_get_value_stringify_at (dm, col, 0);
+ if (strcmp (value, valore_new) != 0)
+ {
+ /* field modificato */
+ insert_value (audit, id, table, nome_campo, valore_new);
+ }
+ }
+ break;
+
+ case AUDIT_ACTION_DELETE:
+ /* salvo solo i fields della chiave */
+ nome_campo = va_arg (vargs, gchar *);
+ while (nome_campo != NULL)
+ {
+ value = va_arg (vargs, gchar *);
+ if (value == NULL) break;
+
+ insert_value (audit, id, table, nome_campo, value);
+
+ nome_campo = va_arg (vargs, gchar *);
+ }
+ break;
+
+ default:
+ return FALSE;
+ };
+
+ va_end (vargs);
+
+ return TRUE;
+}
+
+/**
+ * audit_destroy:
+ *
+ */
+void
+audit_destroy (Audit *audit)
+{
+ gdaex_free (audit->gdaex);
+
+ g_free (audit);
+}
+
+/**
+ * audit_get_record_at:
+ * @audit:
+ * @datasoruce:
+ * @tabella:
+ * @tm_ora:
+ *
+ * Returns: il record con la chiave specificata al timestamp specificato.
+ */
+gboolean
+audit_get_record_at (Audit *audit,
+ const gchar *nome_datasource,
+ const gchar *nome_tabella,
+ struct tm *tm_ora,
+ ...)
+{
+ GdaDataModel *dm;
+ gchar *sql;
+ Datasource *datasource;
+
+ /* trovo il datasource */
+ datasource = get_datasource_from_nome (audit, nome_datasource);
+ if (datasource == NULL)
+ {
+ g_warning ("Impossibile trovare il datasource \"%s\" nei datasource caricati",
+ nome_datasource);
+ return FALSE;
+ }
+
+ sql = g_strdup_printf ("SELECT * FROM azioni "
+ "WHERE id_tabelle = %d AND id_datasources = %d "
+ "ORDER BY data)");
+
+ return TRUE;
+}