#include "userdb.h" #include #include #include #include #include #include static mongoc_client_t* client = NULL; static mongoc_database_t* db = NULL; static mongoc_collection_t* collection = NULL; // Initialize MongoDB client int userdb_init(const char* host, int port) { const char* target = "mongodb://mongoadmin:secret@127.0.0.1:27017"; mongoc_uri_t* uri = mongoc_uri_new(target); bson_error_t error; // Initialize the C Driver mongoc_init(); // Create a new client and connect to the server mongoc_client_t *client = mongoc_client_new_from_uri(uri); if (!client) { fprintf(stderr, "Failed to create MongoDB client\n"); return -1; } db = mongoc_client_get_database(client, "userdb"); if (!db) { fprintf(stderr, "Failed to get database\n"); mongoc_client_destroy(client); return -1; } bson_t *ping = BCON_NEW("ping", BCON_INT32(1)); bson_t reply = BSON_INITIALIZER; bson_t* options; collection = mongoc_database_create_collection(db, "users", NULL, &error); if(!collection) { if(error.code == 43) { // if collection exists collection = mongoc_database_get_collection(db, "users"); if (!collection) { fprintf(stderr, "Failed to get collection\n"); mongoc_client_destroy(client); return -1; } } else { printf("bad thing has happed %d, %s\n", error.code, error.message); } } return 0; } // Create user //int userdb_create_user(const char* username, const char* email, const char* password_hash, const char** user_tags, int size_of_user_tags) { int userdb_create_user(UserCreate user) { bson_t* doc = NULL; bson_error_t error; int ret = 0; bson_t* array = bson_new(); if(!array) { printf("Failed to create BSON document\n"); ret = -2; goto cleanup; } for(int i = 0; i < user.size_of_user_tags; i++) { char id[32] = {0}; snprintf(id,32,"%d", i); bson_append_utf8(array, id, -1, user.user_tags[i], -1); } doc = bson_new(); if (!doc) { printf("Failed to create BSON document\n"); ret = -1; goto cleanup; } // This is the old way of doing things --V //doc = BCON_NEW( // "username", BCON_UTF8(username), // "email", BCON_UTF8(email), // "password_hash", BCON_UTF8(password_hash), // "session_id", BCON_UTF8(""), // "active", BCON_INT32(1) //); // bson_append_utf8(doc, "username", -1, user.username, -1); bson_append_utf8(doc, "email", -1, user.email, -1); bson_append_utf8(doc, "password_hash", -1, user.password_hash, -1); bson_append_utf8(doc, "session_id", -1, user.session_id, strlen(user.session_id)); bson_append_utf8(doc, "last_page", -1, "/", -1); bson_append_array(doc,"tags", -1, array); if (!mongoc_collection_insert_one(collection, doc, NULL, NULL, &error)) { fprintf(stderr, "Insert failed: %s\n", error.message); ret = -1; goto cleanup; } cleanup: if (doc) { bson_destroy(doc); } if(array) { bson_destroy(array); } return ret; } // Find user by username Userdb* userdb_find_user_by_username(const char* username) { Userdb* user = (Userdb*)malloc(sizeof(Userdb)); if (!user) { return NULL; } bson_t* query = BCON_NEW("username", BCON_UTF8(username)); bson_error_t error; mongoc_cursor_t* cursor = mongoc_collection_find_with_opts(collection, query, NULL, NULL); if (!cursor) { fprintf(stderr, "Find failed\n"); free(user); return NULL; } bson_iter_t iter; const bson_t* doc; if(mongoc_cursor_next(cursor, &doc)) { bson_iter_init(&iter, doc); strncpy(user->username, username, USERDB_USERNAME_MAX_SIZE); if(bson_iter_find(&iter, "email")) { const char* email = bson_iter_utf8(&iter, NULL); if(email && strlen(email) < USERDB_EMAIL_MAX_SIZE) { strcpy(user->email, email); } user->email[USERDB_EMAIL_MAX_SIZE - 1] = '\0'; } if(bson_iter_find(&iter, "password_hash")) { const char* password_hash = bson_iter_utf8(&iter, NULL); if(password_hash && strlen(password_hash) < USERDB_PASSWORD_HASH_MAX_SIZE) { strcpy(user->password_hash, password_hash); } user->password_hash[USERDB_PASSWORD_HASH_MAX_SIZE - 1] = '\0'; } if(bson_iter_find(&iter, "user_group")) { const char* user_group = bson_iter_utf8(&iter, NULL); if(user_group && strlen(user_group) < USERDB_USER_GROUP_MAX_SIZE) { strcpy(user->user_group, user_group); } user->user_group[USERDB_USER_GROUP_MAX_SIZE - 1] = '\0'; } if(bson_iter_find(&iter, "user_freads")) { const char* password_hash = bson_iter_utf8(&iter, NULL); if(password_hash && strlen(password_hash) < USERDB_PASSWORD_HASH_MAX_SIZE) { strcpy(user->password_hash, password_hash); } user->password_hash[USERDB_PASSWORD_HASH_MAX_SIZE - 1] = '\0'; } if(bson_iter_find(&iter, "user_freads")) { const char* password_hash = bson_iter_utf8(&iter, NULL); if(password_hash && strlen(password_hash) < USERDB_PASSWORD_HASH_MAX_SIZE) { strcpy(user->password_hash, password_hash); } user->password_hash[USERDB_PASSWORD_HASH_MAX_SIZE - 1] = '\0'; } if(bson_iter_find(&iter, "level")) { user->level = bson_iter_int32(&iter); } if(bson_iter_find(&iter, "current_xp")) { user->current_xp = bson_iter_int32(&iter); } if(bson_iter_find(&iter, "credits")) { user->credits = bson_iter_int32(&iter); } if(bson_iter_find(&iter, "runs")) { user->runs = bson_iter_int32(&iter); } if(bson_iter_find(&iter, "active")) { user->active = bson_iter_int32(&iter); } } bson_destroy(query); return user; } // Find user by username User* userdb_find_user_by_username(const char* username) { User* user = (User*)malloc(sizeof(User)); if (!user) { return NULL; } bson_t* query = BCON_NEW("username", BCON_UTF8(username)); bson_error_t error; mongoc_cursor_t* cursor = mongoc_collection_find_with_opts(collection, query, NULL, NULL); if (!cursor) { fprintf(stderr, "Find failed\n"); bson_destroy(query); free(user); return NULL; } bson_iter_t iter; const bson_t* doc; if(mongoc_cursor_next(cursor, &doc)) { if(bson_iter_init(&iter, doc)) { char* res = bson_as_canonical_extended_json(doc, NULL); printf("resolt :%s\n", res); bson_free(res); if(bson_iter_find(&iter, "email")) { const char* email = bson_iter_utf8(&iter, NULL); if(email && strlen(email) < USERDB_EMAIL_MAX_SIZE) { strcpy(user->email, email); } user->email[USERDB_EMAIL_MAX_SIZE - 1] = '\0'; } if(bson_iter_find(&iter, "password_hash")) { const char* password_hash = bson_iter_utf8(&iter, NULL); if(password_hash && strlen(password_hash) < USERDB_PASSWORD_HASH_MAX_SIZE) { strcpy(user->password_hash, password_hash); } user->password_hash[USERDB_PASSWORD_HASH_MAX_SIZE - 1] = '\0'; } if(bson_iter_find(&iter, "session_id")) { const char* username = bson_iter_utf8(&iter, NULL); if(username && strlen(username) < USERDB_USERNAME_MAX_SIZE) { strcpy(user->username, username); } user->username[USERDB_USERNAME_MAX_SIZE - 1] = '\0'; } } } bson_destroy(query); mongoc_cursor_destroy(cursor); return user; } // Update user status int userdb_update_user_status(const char* username, int active) { const bson_t* filter = BCON_NEW("username", BCON_UTF8(username)); const bson_t* update = BCON_NEW("$set", BCON_DOCUMENT(BCON_NEW("active", BCON_INT32(active)))); bson_error_t error; if (mongoc_collection_insert_one(collection, filter, update, NULL, &error) == 0) { fprintf(stderr, "Update failed: %s\n", error.message); return -1; } return 0; } // Delete user int userdb_delete_user(const char* username) { const bson_t* filter = BCON_NEW("username", BCON_UTF8(username)); bson_error_t error; if (mongoc_collection_delete_one(collection, filter,NULL, NULL, &error) == 0) { fprintf(stderr, "Delete failed: %s\n", error.message); return -1; } return 0; } // Cleanup void userdb_cleanup() { if (collection) { mongoc_collection_destroy(collection); } if (db) { mongoc_database_destroy(db); } if (client) { mongoc_client_destroy(client); } mongoc_cleanup(); }