From aabd70d218fd0832dab2e1c6384eb31ffbb74c19 Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Sun, 16 Feb 2025 12:46:39 +0100 Subject: [PATCH] add first db tables and usersettings initialization --- application/Makefile | 2 + application/application.c | 47 ++++++++++++++++- application/application.h | 2 +- application/main.c | 2 + application/store.c | 104 +++++++++++++++++++++++++++++++++++++ application/store.h | 21 +++++++- application/store_sqlite.c | 88 +++++++++++++++++++++++++++++++ application/store_sqlite.h | 46 ++++++++++++++++ application/types.c | 52 +++++++++++++++++++ application/types.h | 85 ++++++++++++++++++++++++++++++ application/window.c | 2 +- dbutils/db.c | 12 +++++ dbutils/dbutils.c | 12 +++++ dbutils/dbutils/db.h | 1 + dbutils/dbutils/dbutils.h | 4 ++ dbutils/object.c | 4 +- 16 files changed, 478 insertions(+), 6 deletions(-) create mode 100644 application/store_sqlite.c create mode 100644 application/store_sqlite.h create mode 100644 application/types.c create mode 100644 application/types.h diff --git a/application/Makefile b/application/Makefile index 65c372a..24b3e93 100644 --- a/application/Makefile +++ b/application/Makefile @@ -34,7 +34,9 @@ CFLAGS += -I../ui/ -I../ucx -I.. SRC = main.c SRC += application.c SRC += window.c +SRC += types.c SRC += store.c +SRC += store_sqlite.c OBJ = $(SRC:%.c=../build/application/%.$(OBJ_EXT)) diff --git a/application/application.c b/application/application.c index bd6dd4f..42c7794 100644 --- a/application/application.c +++ b/application/application.c @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2024 Olaf Wintermann. All rights reserved. + * Copyright 2025 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -30,10 +30,53 @@ #include "window.h" #include "store.h" +#include +#include + +#include + void application_startup(UiEvent *event, void *data) { - if(init_note_store) { + if(init_note_store()) { + fprintf(stderr, "note store initialization failed\n"); return; } + // Get environment required by settings + char hostname[HOST_NAME_MAX]; + char *host = NULL; + if(gethostname(hostname, sizeof(hostname)) == 0) { + host = hostname; + } + char *user = getenv("USER"); + + // Get available user settings + // The first entry should be the default, however it must be checked if + // it is valid for this environment + CxMempool *mp = cxMempoolCreate(64, NULL); + CxList *usersettings = note_store_get_user_settings(mp->allocator, host, user, NULL); + int settings_valid = 0; + if(usersettings && cxListSize(usersettings) > 0) { + UserSettings *settings = cxListAt(usersettings, 0); + if(user_settings_is_valid(settings, host, user, NULL)) { + note_store_set_settings( + settings->host, + settings->user, + settings->profile_name, + settings->default_repository_id, + settings->default_collection_id); + settings_valid = 1; + } + } + + if(!settings_valid) { + // no valid settings (or no settings) + // TODO: Show a initialization dialog, where the user could + // select available settings or create new settings + fprintf(stderr, "TODO: settings prompt\n"); + exit(-1); + } + + cxMempoolFree(mp); + window_create(); } diff --git a/application/application.h b/application/application.h index 7046b8f..acae80e 100644 --- a/application/application.h +++ b/application/application.h @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2024 Olaf Wintermann. All rights reserved. + * Copyright 2025 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: diff --git a/application/main.c b/application/main.c index 5fb3c4c..b2b5f77 100644 --- a/application/main.c +++ b/application/main.c @@ -36,8 +36,10 @@ #include #include "application.h" +#include "types.h" int app_main(int argc, char **argv) { + register_types(); ui_init("note", argc, argv); ui_onstartup(application_startup, NULL); ui_main(); diff --git a/application/store.c b/application/store.c index 1682541..56d41df 100644 --- a/application/store.c +++ b/application/store.c @@ -34,11 +34,27 @@ #include #include +#include "types.h" +#include "store_sqlite.h" + #include "../dbutils/dbutils/db.h" #include "../dbutils/dbutils/sqlite.h" static DBUConnection *connection; +static char *settings_host; +static char *settings_user; +static char *settings_profile_name; +static int64_t settings_default_repository_id; +static int64_t settings_default_node_id; + +/* + * Creates a connection to the note database and initializes tables if necessary + * + * Returns: + * 0 on success + * 1 on error + */ int init_note_store() { char *sqlite_db_file = ui_configfile(NOTES_DB_FILE); @@ -59,5 +75,93 @@ int init_note_store() { return 1; } + if(init_db) { + if(store_sqlite_init_db(connection)) { + return 1; + } + } + return 0; } + +/* + * Gets a list of all available user settings, sorted by relevance. Usually + * the first item should be used as default settings, however the + * host/user/profile fields should be checked. + */ +CxList* note_store_get_user_settings(const CxAllocator *a, const char *host, const char *user, const char *profile) { + DBUQuery *query = connection->createQuery(connection, NULL); + dbuQuerySetSQL(query, "select * from user_settings;"); + if(host) { + dbuQuerySetParamString(query, 0, cx_str(host)); + } else { + dbuQuerySetParamNull(query, 0); + } + if(user) { + dbuQuerySetParamString(query, 1, cx_str(user)); + } else { + dbuQuerySetParamNull(query, 1); + } + if(profile) { + dbuQuerySetParamString(query, 2, cx_str(profile)); + } else { + dbuQuerySetParamNull(query, 2); + } + + DBUObjectBuilder *builder = dbuObjectBuilder(usersettings_class, query, a); + CxList *usersettings = dbuObjectBuilderGetList(builder); + dbuObjectBuilderDestroy(builder); + + return usersettings; +} + +void close_note_store() { + connection->free(connection); +} + + +/* + * Checks if the settings object complies to the specified host/user/profile. + * + * A settings field (like host) must be NULL or have the same specified value. + * + * Returns: + * 1: settings are valid + * 0: settings are not valid + */ +int user_settings_is_valid( + UserSettings *settings, + const char *host, + const char *user, + const char *profile) +{ + if(!settings) return 0; + if(settings->host && host && strcmp(settings->host, host)) { + return 0; + } + if(settings->user && host && strcmp(settings->user, user)) { + return 0; + } + if(settings->profile_name && profile && strcmp(settings->profile_name, profile)) { + return 0; + } + return 1; +} + +/* + * Sets global settings + */ +void note_store_set_settings( + const char *host, + const char *user, + const char *profile_name, + int64_t default_repository_id, + int64_t default_node_id) +{ + settings_host = host ? strdup(host) : NULL; + settings_user = user ? strdup(user) : NULL; + settings_profile_name = profile_name ? strdup(profile_name) : NULL; + settings_default_repository_id = default_repository_id; + settings_default_node_id = default_node_id; +} + diff --git a/application/store.h b/application/store.h index 2459c21..d603faa 100644 --- a/application/store.h +++ b/application/store.h @@ -30,15 +30,34 @@ #define STORE_H #include "application.h" +#include "types.h" +#include #ifdef __cplusplus extern "C" { #endif #define NOTES_DB_FILE "notes.db" - + int init_note_store(); +CxList* note_store_get_user_settings(const CxAllocator *a, const char *host, const char *user, const char *profile); + +void close_note_store(); + +int user_settings_is_valid( + UserSettings *settings, + const char *host, + const char *user, + const char *profile); + +void note_store_set_settings( + const char *host, + const char *user, + const char *profile_name, + int64_t default_repository_id, + int64_t default_node_id); + #ifdef __cplusplus } diff --git a/application/store_sqlite.c b/application/store_sqlite.c new file mode 100644 index 0000000..728c921 --- /dev/null +++ b/application/store_sqlite.c @@ -0,0 +1,88 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2025 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "store_sqlite.h" + +#include +#include "../dbutils/dbutils/sqlite.h" + + +#define SQL_CREATE_TABLE_NOTEDB "create table note_db( " \ + "version int, " \ + "created text);" +#define SQL_CREATE_TABLE_REPOSITORIES "create table repositories( " \ + "repository_id integer primary key, " \ + "name text not null unique, " \ + "url text, " \ + "encryption integer, " \ + "default_key text, " \ + "authmethod integer, " \ + "local_path text);" +#define SQL_CREATE_TABLE_COLLECTIONS "create table collections( " \ + "collection_id integer primary key, " \ + "parent_id integer, " \ + "repository_id integer, " \ + "name text not null, " \ + "display_name text, " \ + "type text, " \ + "created_by text, " \ + "created_at text, " \ + "foreign key (parent_id) references collections(collection_id), " \ + "foreign key (repository_id) references repositories(repository_id)" \ + ");" +#define SQL_CREATE_TABLE_USER_SETTINGS "create table user_settings( " \ + "host text, " \ + "user text, " \ + "profile_name text, " \ + "default_repository_id integer, " \ + "default_collection_id integer, " \ + "created_by text, " \ + "created_at text, " \ + "foreign key (default_repository_id) references repositories(repository_id), " \ + "foreign key (default_collection_id) references collections(collection_id), " \ + "unique (host, user, profile_name)" \ + ");" + +int store_sqlite_init_db(DBUConnection *connection) { + char *sql[] = { + SQL_CREATE_TABLE_NOTEDB, + SQL_CREATE_TABLE_REPOSITORIES, + SQL_CREATE_TABLE_COLLECTIONS, + SQL_CREATE_TABLE_USER_SETTINGS + }; + int nsql = sizeof(sql) / sizeof(char*); + + for(int i=0;icreateQuery(conn, NULL); + int err = 1; + if(!dbuQuerySetSQL(q, sql)) { + err = dbuQueryExec(q); + } + dbuQueryFree(q); + return err; +} + + + int dbuQuerySetSQL(DBUQuery *q, const char *sql) { return q->setSQL(q, sql); } diff --git a/dbutils/dbutils.c b/dbutils/dbutils.c index ab93ac9..68b013e 100644 --- a/dbutils/dbutils.c +++ b/dbutils/dbutils.c @@ -134,3 +134,15 @@ DBUClass* dbuRegisterClassWithPrimaryKeyCxMutStr( cxMapPut(context->classes, name, cls); return cls; } + +DBUClass* dbuRegisterClassWithoutPK( + DBUContext *context, + const char *name, + size_t obj_size) +{ + DBUClass *cls = dbuClassCreate(name); + cls->context = context; + cls->obj_size = obj_size; + cxMapPut(context->classes, name, cls); + return cls; +} diff --git a/dbutils/dbutils/db.h b/dbutils/dbutils/db.h index d871086..167204b 100644 --- a/dbutils/dbutils/db.h +++ b/dbutils/dbutils/db.h @@ -96,6 +96,7 @@ struct DBUResult { int rowIndex; }; +int dbuConnectionExec(DBUConnection *conn, const char *sql); int dbuQuerySetSQL(DBUQuery *q, const char *sql); int dbuQuerySetParamString(DBUQuery *q, int index, cxstring str); diff --git a/dbutils/dbutils/dbutils.h b/dbutils/dbutils/dbutils.h index cc24281..e11ac4c 100644 --- a/dbutils/dbutils/dbutils.h +++ b/dbutils/dbutils/dbutils.h @@ -265,6 +265,10 @@ DBUClass* dbuRegisterClassWithPrimaryKeyCxMutStr( size_t obj_size, const char *primary_key_column, off_t primary_key_offset); +DBUClass* dbuRegisterClassWithoutPK( + DBUContext *context, + const char *name, + size_t obj_size); void dbuClassSetPrimaryKeyInt32(DBUClass *cls, const char *column_name, off_t offset); void dbuClassSetPrimaryKeyUInt32(DBUClass *cls, const char *column_name, off_t offset); diff --git a/dbutils/object.c b/dbutils/object.c index deff5cd..0a54c30 100644 --- a/dbutils/object.c +++ b/dbutils/object.c @@ -449,7 +449,9 @@ int dbuObjectExecuteQuery(DBUObjectBuilder *builder, DBUQuery *query, DBUClass * DBUField *type_field = field.field; if(type_field && current_obj) { if(isnull) { - field.field->initDefaultValue(field.field, a, current_obj); + if(field.field->initDefaultValue) { + field.field->initDefaultValue(field.field, a, current_obj); + } } else { cxstring text = result->getText(result, i); //printf("getText(%d) = %s\n", i, text.ptr); -- 2.43.5