diff --git a/lib/ccnetobj.vala b/lib/ccnetobj.vala index d929055..29a31e5 100644 --- a/lib/ccnetobj.vala +++ b/lib/ccnetobj.vala @@ -47,6 +47,8 @@ public class Group : Object { public string creator_name { get; set; } public int64 timestamp { get; set; } public string source { get; set; } + public int parent_group_id { get; set; } + } public class GroupUser : Object { diff --git a/lib/rpc_table.py b/lib/rpc_table.py index 5fde127..599e7d8 100644 --- a/lib/rpc_table.py +++ b/lib/rpc_table.py @@ -10,6 +10,7 @@ func_table = [ [ "int", ["int", "string"] ], [ "int", ["int", "string", "int"] ], [ "int", ["int", "string", "string"] ], + [ "int", ["int", "string", "string", "int"] ], [ "int", ["int", "string", "int", "int"] ], [ "int", ["string"] ], [ "int", ["string", "int"] ], @@ -18,6 +19,7 @@ func_table = [ [ "int", ["string", "int", "string", "int", "int"] ], [ "int", ["string", "string"] ], [ "int", ["string", "string", "string"] ], + [ "int", ["string", "string", "string", "int"] ], [ "int", ["string", "string", "int"] ], [ "int", ["string", "string", "int", "int"] ], [ "int", ["string", "string", "string", "string"] ], diff --git a/net/common/ccnet-db.c b/net/common/ccnet-db.c index e7dccd3..80ef07f 100644 --- a/net/common/ccnet-db.c +++ b/net/common/ccnet-db.c @@ -834,7 +834,7 @@ ccnet_db_rollback (CcnetDBTrans *trans) DBConnection *conn = trans->conn; GError *error = NULL; - if (!db_connection_commit (conn, &error)) { + if (!db_connection_rollback(conn, &error)) { ccnet_warning ("Rollback failed: %s.\n", error->message); g_clear_error (&error); return -1; diff --git a/net/common/rpc-service.c b/net/common/rpc-service.c index b1310d1..92f6473 100644 --- a/net/common/rpc-service.c +++ b/net/common/rpc-service.c @@ -211,11 +211,11 @@ ccnet_start_rpc(CcnetSession *session) searpc_server_register_function ("ccnet-threaded-rpcserver", ccnet_rpc_create_group, "create_group", - searpc_signature_int__string_string_string()); + searpc_signature_int__string_string_string_int()); searpc_server_register_function ("ccnet-threaded-rpcserver", ccnet_rpc_create_org_group, "create_org_group", - searpc_signature_int__int_string_string()); + searpc_signature_int__int_string_string_int()); searpc_server_register_function ("ccnet-threaded-rpcserver", ccnet_rpc_remove_group, "remove_group", @@ -247,11 +247,15 @@ ccnet_start_rpc(CcnetSession *session) searpc_server_register_function ("ccnet-threaded-rpcserver", ccnet_rpc_get_groups, "get_groups", - searpc_signature_objlist__string()); + searpc_signature_objlist__string_int()); searpc_server_register_function ("ccnet-threaded-rpcserver", ccnet_rpc_get_all_groups, "get_all_groups", searpc_signature_objlist__int_int_string()); + searpc_server_register_function ("ccnet-threaded-rpcserver", + ccnet_rpc_get_ancestor_groups, + "get_ancestor_groups", + searpc_signature_objlist__int()); searpc_server_register_function ("ccnet-threaded-rpcserver", ccnet_rpc_get_group, "get_group", @@ -280,6 +284,14 @@ ccnet_start_rpc(CcnetSession *session) ccnet_rpc_search_groups, "search_groups", searpc_signature_objlist__string_int_int()); + searpc_server_register_function ("ccnet-threaded-rpcserver", + ccnet_rpc_get_top_groups, + "get_top_groups", + searpc_signature_objlist__void()); + searpc_server_register_function ("ccnet-threaded-rpcserver", + ccnet_rpc_get_child_groups, + "get_child_groups", + searpc_signature_objlist__int()); searpc_server_register_function ("ccnet-threaded-rpcserver", ccnet_rpc_create_org, @@ -345,6 +357,10 @@ ccnet_start_rpc(CcnetSession *session) ccnet_rpc_get_org_groups_by_user, "get_org_groups_by_user", searpc_signature_objlist__string_int()); + searpc_server_register_function ("ccnet-threaded-rpcserver", + ccnet_rpc_get_org_top_groups, + "get_org_top_groups", + searpc_signature_objlist__int()); searpc_server_register_function ("ccnet-threaded-rpcserver", ccnet_rpc_org_user_exists, "org_user_exists", @@ -807,6 +823,30 @@ ccnet_rpc_search_groups (const char *group_patt, return groups; } +GList* +ccnet_rpc_get_top_groups (GError **error) +{ + CcnetGroupManager *group_mgr = + ((CcnetServerSession *)session)->group_mgr; + GList *groups = NULL; + + groups = ccnet_group_manager_get_top_groups (group_mgr, error); + + return groups; +} + +GList* +ccnet_rpc_get_child_groups (int group_id, GError **error) +{ + CcnetGroupManager *group_mgr = + ((CcnetServerSession *)session)->group_mgr; + GList *groups = NULL; + + groups = ccnet_group_manager_get_child_groups (group_mgr, group_id, error); + + return groups; +} + GList* ccnet_rpc_search_ldapusers (const char *keyword, int start, int limit, @@ -934,7 +974,7 @@ ccnet_rpc_verify_message (const char *message, int ccnet_rpc_create_group (const char *group_name, const char *user_name, - const char *type, GError **error) + const char *type, int parent_group_id, GError **error) { CcnetGroupManager *group_mgr = ((CcnetServerSession *)session)->group_mgr; @@ -946,14 +986,14 @@ ccnet_rpc_create_group (const char *group_name, const char *user_name, return -1; } - ret = ccnet_group_manager_create_group (group_mgr, group_name, user_name, error); + ret = ccnet_group_manager_create_group (group_mgr, group_name, user_name, parent_group_id, error); return ret; } int ccnet_rpc_create_org_group (int org_id, const char *group_name, - const char *user_name, GError **error) + const char *user_name, int parent_group_id, GError **error) { CcnetGroupManager *group_mgr = ((CcnetServerSession *)session)->group_mgr; @@ -965,7 +1005,7 @@ ccnet_rpc_create_org_group (int org_id, const char *group_name, } ret = ccnet_group_manager_create_org_group (group_mgr, org_id, - group_name, user_name, error); + group_name, user_name, parent_group_id, error); return ret; } @@ -983,7 +1023,7 @@ ccnet_rpc_remove_group (int group_id, GError **error) return -1; } - ret = ccnet_group_manager_remove_group (group_mgr, group_id, error); + ret = ccnet_group_manager_remove_group (group_mgr, group_id, FALSE, error); return ret; @@ -1105,7 +1145,7 @@ ccnet_rpc_quit_group (int group_id, const char *user_name, GError **error) } GList * -ccnet_rpc_get_groups (const char *username, GError **error) +ccnet_rpc_get_groups (const char *username, int return_ancestors, GError **error) { CcnetGroupManager *group_mgr = ((CcnetServerSession *)session)->group_mgr; @@ -1117,7 +1157,8 @@ ccnet_rpc_get_groups (const char *username, GError **error) return NULL; } - ret = ccnet_group_manager_get_groups_by_user (group_mgr, username, error); + ret = ccnet_group_manager_get_groups_by_user (group_mgr, username, + return_ancestors ? TRUE : FALSE, error); return ret; } @@ -1134,6 +1175,18 @@ ccnet_rpc_get_all_groups (int start, int limit, return ret; } +GList * +ccnet_rpc_get_ancestor_groups (int group_id, GError ** error) +{ + CcnetGroupManager *group_mgr = + ((CcnetServerSession *)session)->group_mgr; + GList *ret = NULL; + + ret = ccnet_group_manager_get_ancestor_groups (group_mgr, group_id); + + return ret; +} + GObject * ccnet_rpc_get_group (int group_id, GError **error) { @@ -1263,7 +1316,7 @@ ccnet_rpc_remove_org (int org_id, GError **error) group_ids = ccnet_org_manager_get_org_group_ids (org_mgr, org_id, 0, INT_MAX); ptr = group_ids; while (ptr) { - ccnet_group_manager_remove_group (group_mgr, (int)(long)ptr->data, error); + ccnet_group_manager_remove_group (group_mgr, (int)(long)ptr->data, TRUE, error); ptr = ptr->next; } g_list_free (group_ids); @@ -1477,7 +1530,6 @@ ccnet_rpc_get_org_groups (int org_id, int start, int limit, GError **error) return ret; } - GList * ccnet_rpc_get_org_groups_by_user (const char *user, int org_id, GError **error) { @@ -1488,12 +1540,26 @@ ccnet_rpc_get_org_groups_by_user (const char *user, int org_id, GError **error) g_set_error (error, CCNET_DOMAIN, CCNET_ERR_INTERNAL, "Bad arguments"); return NULL; } - ret = ccnet_org_manager_get_org_groups_by_user (org_mgr, user, org_id); return ret; } +GList * +ccnet_rpc_get_org_top_groups (int org_id, GError **error) +{ + CcnetOrgManager *org_mgr = ((CcnetServerSession *)session)->org_mgr; + GList *ret = NULL; + + if (org_id < 0) { + g_set_error (error, CCNET_DOMAIN, CCNET_ERR_INTERNAL, "Bad arguments"); + return NULL; + } + ret = ccnet_org_manager_get_org_top_groups (org_mgr, org_id, error); + + return ret; +} + int ccnet_rpc_org_user_exists (int org_id, const char *email, GError **error) { diff --git a/net/common/rpc-service.h b/net/common/rpc-service.h index 01ad6a6..9c2ba24 100644 --- a/net/common/rpc-service.h +++ b/net/common/rpc-service.h @@ -181,11 +181,11 @@ ccnet_rpc_verify_message (const char *message, int ccnet_rpc_create_group (const char *group_name, const char *user_name, - const char *type, GError **error); + const char *type, int parent_group_id, GError **error); int ccnet_rpc_create_org_group (int org_id, const char *group_name, - const char *user_name, GError **error); + const char *user_name, int parent_group_id, GError **error); int ccnet_rpc_remove_group (int group_id, GError **error); @@ -213,11 +213,20 @@ int ccnet_rpc_quit_group (int group_id, const char *user_name, GError **error); GList * -ccnet_rpc_get_groups (const char *username, GError **error); +ccnet_rpc_get_groups (const char *username, int return_ancestors, GError **error); GList * ccnet_rpc_get_all_groups (int start, int limit, const char *source, GError **error); +GList * +ccnet_rpc_get_ancestor_groups (int group_id, GError **error); + +GList * +ccnet_rpc_get_top_groups (GError **error); + +GList * +ccnet_rpc_get_child_groups (int group_id, GError **error); + GObject * ccnet_rpc_get_group (int group_id, GError **error); @@ -289,6 +298,9 @@ ccnet_rpc_get_org_groups (int org_id, int start, int limit, GError **error); GList * ccnet_rpc_get_org_groups_by_user (const char *user, int org_id, GError **error); +GList * +ccnet_rpc_get_org_top_groups (int org_id, GError **error); + int ccnet_rpc_org_user_exists (int org_id, const char *email, GError **error); diff --git a/net/server/group-mgr.c b/net/server/group-mgr.c index c8adb24..bbc3f10 100644 --- a/net/server/group-mgr.c +++ b/net/server/group-mgr.c @@ -11,6 +11,8 @@ #include "utils.h" #include "log.h" +extern CcnetSession *session; + struct _CcnetGroupManagerPriv { CcnetDB *db; const char *table_name; @@ -105,7 +107,7 @@ static int check_db_table (CcnetGroupManager *manager, CcnetDB *db) "CREATE TABLE IF NOT EXISTS `%s` (`group_id` INTEGER" " PRIMARY KEY AUTO_INCREMENT, `group_name` VARCHAR(255)," " `creator_name` VARCHAR(255), `timestamp` BIGINT," - " `type` VARCHAR(32))" + " `type` VARCHAR(32), `parent_group_id` INTEGER)" "ENGINE=INNODB", table_name); if (ccnet_db_query (db, group_sql->str) < 0) { g_string_free (group_sql, TRUE); @@ -123,12 +125,17 @@ static int check_db_table (CcnetGroupManager *manager, CcnetDB *db) " dn VARCHAR(255))ENGINE=INNODB"; if (ccnet_db_query (db, sql) < 0) return -1; + + sql = "CREATE TABLE IF NOT EXISTS GroupStructure (group_id INTEGER PRIMARY KEY, " + "path VARCHAR(1024))ENGINE=INNODB"; + if (ccnet_db_query (db, sql) < 0) + return -1; } else if (db_type == CCNET_DB_TYPE_SQLITE) { g_string_printf (group_sql, "CREATE TABLE IF NOT EXISTS `%s` (`group_id` INTEGER" " PRIMARY KEY AUTOINCREMENT, `group_name` VARCHAR(255)," " `creator_name` VARCHAR(255), `timestamp` BIGINT," - " `type` VARCHAR(32))", table_name); + " `type` VARCHAR(32), `parent_group_id` INTEGER)", table_name); if (ccnet_db_query (db, group_sql->str) < 0) { g_string_free (group_sql, TRUE); return -1; @@ -153,12 +160,17 @@ static int check_db_table (CcnetGroupManager *manager, CcnetDB *db) " dn VARCHAR(255))"; if (ccnet_db_query (db, sql) < 0) return -1; + + sql = "CREATE TABLE IF NOT EXISTS GroupStructure (group_id INTEGER PRIMARY KEY, " + "path VARCHAR(1024))"; + if (ccnet_db_query (db, sql) < 0) + return -1; } else if (db_type == CCNET_DB_TYPE_PGSQL) { g_string_printf (group_sql, "CREATE TABLE IF NOT EXISTS \"%s\" (group_id SERIAL" " PRIMARY KEY, group_name VARCHAR(255)," " creator_name VARCHAR(255), timestamp BIGINT," - " type VARCHAR(32))", table_name); + " type VARCHAR(32), parent_group_id INTEGER)", table_name); if (ccnet_db_query (db, group_sql->str) < 0) { g_string_free (group_sql, TRUE); return -1; @@ -180,16 +192,42 @@ static int check_db_table (CcnetGroupManager *manager, CcnetDB *db) " dn VARCHAR(255))"; if (ccnet_db_query (db, sql) < 0) return -1; + + sql = "CREATE TABLE IF NOT EXISTS GroupStructure (group_id INTEGER PRIMARY KEY, " + "path VARCHAR(1024))"; + if (ccnet_db_query (db, sql) < 0) + return -1; } g_string_free (group_sql, TRUE); return 0; } +static gboolean +get_group_id_cb (CcnetDBRow *row, void *data) +{ + int *id = data; + int group_id = ccnet_db_row_get_column_int(row, 0); + *id = group_id; + + return FALSE; +} + +static gboolean +get_group_path_cb (CcnetDBRow *row, void *data) +{ + char **path = (char **)data; + const char *group_path = ccnet_db_row_get_column_text (row, 0); + *path = g_strdup (group_path); + + return FALSE; +} + static int create_group_common (CcnetGroupManager *mgr, const char *group_name, const char *user_name, + int parent_group_id, GError **error) { CcnetDB *db = mgr->priv->db; @@ -197,24 +235,23 @@ create_group_common (CcnetGroupManager *mgr, GString *sql = g_string_new (""); const char *table_name = mgr->priv->table_name; int group_id = -1; + CcnetDBTrans *trans = ccnet_db_begin_transaction (db); char *user_name_l = g_ascii_strdown (user_name, -1); if (ccnet_db_type(db) == CCNET_DB_TYPE_PGSQL) g_string_printf (sql, "INSERT INTO \"%s\"(group_name, " - "creator_name, timestamp) VALUES(?, ?, ?)", table_name); + "creator_name, timestamp, parent_group_id) VALUES(?, ?, ?, ?)", table_name); else g_string_printf (sql, "INSERT INTO `%s`(group_name, " - "creator_name, timestamp) VALUES(?, ?, ?)", table_name); + "creator_name, timestamp, parent_group_id) VALUES(?, ?, ?, ?)", table_name); - if (ccnet_db_statement_query (db, sql->str, 3, - "string", group_name, "string", user_name_l, - "int64", now) < 0) { - g_set_error (error, CCNET_DOMAIN, 0, "Failed to create group"); - goto out; - } + if (ccnet_db_trans_query (trans, sql->str, 4, + "string", group_name, "string", user_name_l, + "int64", now, "int", parent_group_id) < 0) + goto error; if (ccnet_db_type(db) == CCNET_DB_TYPE_PGSQL) g_string_printf (sql, @@ -227,41 +264,61 @@ create_group_common (CcnetGroupManager *mgr, "group_name = ? AND creator_name = ? " "AND timestamp = ?", table_name); - group_id = ccnet_db_statement_get_int (db, sql->str, 3, - "string", group_name, "string", user_name_l, - "int64", now); - if (group_id < 0) { - g_set_error (error, CCNET_DOMAIN, 0, "Failed to create group"); - goto out; - } + ccnet_db_trans_foreach_selected_row (trans, sql->str, get_group_id_cb, + &group_id, 3, "string", group_name, + "string", user_name_l, "int64", now); + + if (group_id < 0) + goto error; g_string_printf (sql, "INSERT INTO GroupUser VALUES (?, ?, ?)"); - if (ccnet_db_statement_query (db, sql->str, 3, - "int", group_id, "string", user_name_l, - "int", 1) < 0) { - if (ccnet_db_type(db) == CCNET_DB_TYPE_PGSQL) - g_string_printf (sql, "DELETE FROM \"%s\" WHERE group_id=?", table_name); - else - g_string_printf (sql, "DELETE FROM `%s` WHERE group_id=?", table_name); - ccnet_db_statement_query (db, sql->str, 1, "int", group_id); - g_set_error (error, CCNET_DOMAIN, 0, "Failed to create group"); - group_id = -1; - goto out; + if (ccnet_db_trans_query (trans, sql->str, 3, + "int", group_id, "string", user_name_l, + "int", 1) < 0) + goto error; + + if (parent_group_id == -1) { + g_string_printf (sql, "INSERT INTO GroupStructure VALUES (?,'%d')", group_id); + if (ccnet_db_trans_query (trans, sql->str, 1, "int", group_id) < 0) + goto error; + } else if (parent_group_id > 0) { + g_string_printf (sql, "SELECT path FROM GroupStructure WHERE group_id=?"); + char *path = NULL; + ccnet_db_trans_foreach_selected_row (trans, sql->str, get_group_path_cb, + &path, 1, "int", parent_group_id); + if (!path) + goto error; + g_string_printf (sql, "INSERT INTO GroupStructure VALUES (?, '%s, %d')", path, group_id); + if (ccnet_db_trans_query (trans, sql->str, 1, "int", group_id) < 0) { + g_free (path); + goto error; + } + g_free (path); } -out: + ccnet_db_commit (trans); + ccnet_db_trans_close (trans); g_string_free (sql, TRUE); g_free (user_name_l); return group_id; + +error: + ccnet_db_rollback (trans); + ccnet_db_trans_close (trans); + g_set_error (error, CCNET_DOMAIN, 0, "Failed to create group"); + g_string_free (sql, TRUE); + g_free (user_name_l); + return -1; } int ccnet_group_manager_create_group (CcnetGroupManager *mgr, const char *group_name, const char *user_name, + int parent_group_id, GError **error) { - return create_group_common (mgr, group_name, user_name, error); + return create_group_common (mgr, group_name, user_name, parent_group_id, error); } /* static gboolean */ @@ -300,6 +357,7 @@ int ccnet_group_manager_create_org_group (CcnetGroupManager *mgr, int org_id, const char *group_name, const char *user_name, + int parent_group_id, GError **error) { CcnetOrgManager *org_mgr = ((CcnetServerSession *)(mgr->session))->org_mgr; @@ -310,7 +368,7 @@ int ccnet_group_manager_create_org_group (CcnetGroupManager *mgr, /* return -1; */ /* } */ - int group_id = create_group_common (mgr, group_name, user_name, error); + int group_id = create_group_common (mgr, group_name, user_name, parent_group_id, error); if (group_id < 0) { g_set_error (error, CCNET_DOMAIN, 0, "Failed to create org group."); return -1; @@ -336,15 +394,29 @@ check_group_staff (CcnetDB *db, int group_id, const char *user_name) int ccnet_group_manager_remove_group (CcnetGroupManager *mgr, int group_id, + gboolean remove_anyway, GError **error) { CcnetDB *db = mgr->priv->db; GString *sql = g_string_new (""); + gboolean exists; const char *table_name = mgr->priv->table_name; /* No permission check here, since both group staff and seahub staff * can remove group. */ + if (remove_anyway != TRUE) { + if (ccnet_db_type(db) == CCNET_DB_TYPE_PGSQL) + g_string_printf (sql, "SELECT 1 FROM \"%s\" WHERE parent_group_id=?", table_name); + else + g_string_printf (sql, "SELECT 1 FROM `%s` WHERE parent_group_id=?", table_name); + exists = ccnet_db_statement_exists (db, sql->str, 1, "int", group_id); + if (exists) { + ccnet_warning ("Failed to remove group [%d] whose child group must be removed first.\n", group_id); + g_string_free (sql, TRUE); + return -1; + } + } if (ccnet_db_type(db) == CCNET_DB_TYPE_PGSQL) g_string_printf (sql, "DELETE FROM \"%s\" WHERE group_id=?", table_name); @@ -355,6 +427,9 @@ int ccnet_group_manager_remove_group (CcnetGroupManager *mgr, g_string_printf (sql, "DELETE FROM GroupUser WHERE group_id=?"); ccnet_db_statement_query (db, sql->str, 1, "int", group_id); + g_string_printf (sql, "DELETE FROM GroupStructure WHERE group_id=?"); + ccnet_db_statement_query (db, sql->str, 1, "int", group_id); + g_string_free (sql, TRUE); return 0; @@ -547,6 +622,7 @@ get_user_groups_cb (CcnetDBRow *row, void *data) const char *group_name = ccnet_db_row_get_column_text (row, 1); const char *creator_name = ccnet_db_row_get_column_text (row, 2); gint64 ts = ccnet_db_row_get_column_int64 (row, 3); + int parent_group_id = ccnet_db_row_get_column_int (row, 4); group = g_object_new (CCNET_TYPE_GROUP, "id", group_id, @@ -554,9 +630,81 @@ get_user_groups_cb (CcnetDBRow *row, void *data) "creator_name", creator_name, "timestamp", ts, "source", "DB", + "parent_group_id", parent_group_id, NULL); - *plist = g_list_prepend (*plist, group); + *plist = g_list_append (*plist, group); + + return TRUE; +} + +GList * +ccnet_group_manager_get_ancestor_groups (CcnetGroupManager *mgr, int group_id) +{ + CcnetDB *db = mgr->priv->db; + GList *ret = NULL; + CcnetGroup *group = NULL; + GString *sql = g_string_new (""); + const char *table_name = mgr->priv->table_name; + + g_string_printf (sql, "SELECT path FROM GroupStructure WHERE group_id=?"); + + char *path = ccnet_db_statement_get_string (db, sql->str, 1, "int", group_id); + + if (path) { + if (ccnet_db_type(db) == CCNET_DB_TYPE_PGSQL) + g_string_printf (sql, "SELECT g.group_id, group_name, creator_name, timestamp, parent_group_id FROM " + "\"%s\" g WHERE g.group_id IN(%s) " + "ORDER BY g.group_id", + table_name, path); + else + g_string_printf (sql, "SELECT g.group_id, group_name, creator_name, timestamp, parent_group_id FROM " + "`%s` g WHERE g.group_id IN(%s) " + "ORDER BY g.group_id", + table_name, path); + + if (ccnet_db_statement_foreach_row (db, sql->str, get_user_groups_cb, &ret, 0) < 0) { + ccnet_warning ("Failed to get ancestor groups of group %d\n", group_id); + g_string_free (sql, TRUE); + g_free (path); + return NULL; + } + g_string_free (sql, TRUE); + g_free (path); + } else { // group is not in structure, return itself. + group = ccnet_group_manager_get_group (mgr, group_id, NULL); + if (group) { + ret = g_list_prepend (ret, group); + } + } + + return ret; +} + +static gint +group_comp_func (gconstpointer a, gconstpointer b) +{ + CcnetGroup *g1 = (CcnetGroup *)a; + CcnetGroup *g2 = (CcnetGroup *)b; + int id_1 = 0, id_2 = 0; + g_object_get (g1, "id", &id_1, NULL); + g_object_get (g2, "id", &id_2, NULL); + + if (id_1 == id_2) + return 0; + return id_1 > id_2 ? -1 : 1; +} + +gboolean +get_group_paths_cb (CcnetDBRow *row, void *data) +{ + GString *paths = data; + const char *path = ccnet_db_row_get_column_text (row, 0); + + if (g_strcmp0 (paths->str, "") == 0) + g_string_append_printf (paths, "%s", path); + else + g_string_append_printf (paths, ", %s", path); return TRUE; } @@ -564,34 +712,93 @@ get_user_groups_cb (CcnetDBRow *row, void *data) GList * ccnet_group_manager_get_groups_by_user (CcnetGroupManager *mgr, const char *user_name, + gboolean return_ancestors, GError **error) { CcnetDB *db = mgr->priv->db; - GList *groups = NULL; + GList *groups = NULL, *ret = NULL; + GList *ptr; GString *sql = g_string_new (""); const char *table_name = mgr->priv->table_name; + CcnetGroup *group; + int parent_group_id = 0, group_id = 0; if (ccnet_db_type(db) == CCNET_DB_TYPE_PGSQL) g_string_printf (sql, - "SELECT g.group_id, group_name, creator_name, timestamp FROM " - "\"%s\" g, GroupUser u WHERE g.group_id = u.group_id AND user_name=?", + "SELECT g.group_id, group_name, creator_name, timestamp, parent_group_id FROM " + "\"%s\" g, GroupUser u WHERE g.group_id = u.group_id AND user_name=? ORDER BY g.group_id DESC", table_name); else g_string_printf (sql, - "SELECT g.group_id, group_name, creator_name, timestamp FROM " - "`%s` g, GroupUser u WHERE g.group_id = u.group_id AND user_name=?", + "SELECT g.group_id, group_name, creator_name, timestamp, parent_group_id FROM " + "`%s` g, GroupUser u WHERE g.group_id = u.group_id AND user_name=? ORDER BY g.group_id DESC", table_name); if (ccnet_db_statement_foreach_row (db, sql->str, - get_user_groups_cb, &groups, + get_user_groups_cb, + &groups, 1, "string", user_name) < 0) { g_string_free (sql, TRUE); return NULL; } - g_string_free (sql, TRUE); - return g_list_reverse (groups); + if (!return_ancestors) { + g_string_free (sql, TRUE); + return groups; + } + + /* Get ancestor groups in descending order by group_id.*/ + GString *paths = g_string_new (""); + g_string_printf (sql, ""); + for (ptr = groups; ptr; ptr = ptr->next) { + group = ptr->data; + g_object_get (group, "parent_group_id", &parent_group_id, NULL); + g_object_get (group, "id", &group_id, NULL); + if (parent_group_id != 0) { + if (g_strcmp0(sql->str, "") == 0) + g_string_append_printf (sql, "SELECT path FROM GroupStructure WHERE group_id IN (%d", group_id); + else + g_string_append_printf (sql, ", %d", group_id); + } else { + g_object_ref (group); + ret = g_list_insert_sorted (ret, group, group_comp_func); + } + } + if (g_strcmp0(sql->str, "") != 0) { + g_string_append_printf (sql, ")"); + if (ccnet_db_statement_foreach_row (db, + sql->str, + get_group_paths_cb, + paths, 0) < 0) { + g_list_free_full (ret, g_object_unref); + goto out; + } + if (g_strcmp0(paths->str, "") == 0) { + ccnet_warning ("Failed to get groups path for user %s\n", user_name); + g_list_free_full (ret, g_object_unref); + goto out; + } + + g_string_printf (sql, "SELECT g.group_id, group_name, creator_name, timestamp, parent_group_id FROM " + "`%s` g WHERE g.group_id IN (%s) ORDER BY g.group_id DESC", + table_name, paths->str); + if (ccnet_db_statement_foreach_row (db, + sql->str, + get_user_groups_cb, + &ret, 0) < 0) { + g_list_free_full (ret, g_object_unref); + goto out; + } + } + ret = g_list_sort (ret, group_comp_func); + +out: + g_string_free (sql, TRUE); + g_list_free_full (groups, g_object_unref); + g_string_free (paths, TRUE); + + return ret; } static gboolean @@ -601,12 +808,14 @@ get_ccnetgroup_cb (CcnetDBRow *row, void *data) int group_id; const char *group_name; const char *creator; + int parent_group_id; gint64 ts; group_id = ccnet_db_row_get_column_int (row, 0); group_name = (const char *)ccnet_db_row_get_column_text (row, 1); creator = (const char *)ccnet_db_row_get_column_text (row, 2); ts = ccnet_db_row_get_column_int64 (row, 3); + parent_group_id = ccnet_db_row_get_column_int (row, 4); char *creator_l = g_ascii_strdown (creator, -1); *p_group = g_object_new (CCNET_TYPE_GROUP, @@ -615,12 +824,41 @@ get_ccnetgroup_cb (CcnetDBRow *row, void *data) "creator_name", creator_l, "timestamp", ts, "source", "DB", + "parent_group_id", parent_group_id, NULL); g_free (creator_l); return FALSE; } +GList * +ccnet_group_manager_get_child_groups (CcnetGroupManager *mgr, int group_id, + GError **error) +{ + CcnetDB *db = mgr->priv->db; + GString *sql = g_string_new (""); + GList *ret = NULL; + const char *table_name = mgr->priv->table_name; + + if (ccnet_db_type(db) == CCNET_DB_TYPE_PGSQL) + g_string_printf (sql, + "SELECT group_id, group_name, creator_name, timestamp, parent_group_id FROM " + "\"%s\" WHERE parent_group_id=?", table_name); + else + g_string_printf (sql, + "SELECT group_id, group_name, creator_name, timestamp, parent_group_id FROM " + "`%s` WHERE parent_group_id=?", table_name); + if (ccnet_db_statement_foreach_row (db, sql->str, + get_user_groups_cb, &ret, + 1, "int", group_id) < 0) { + g_string_free (sql, TRUE); + return NULL; + } + g_string_free (sql, TRUE); + + return ret; +} + CcnetGroup * ccnet_group_manager_get_group (CcnetGroupManager *mgr, int group_id, GError **error) @@ -632,11 +870,11 @@ ccnet_group_manager_get_group (CcnetGroupManager *mgr, int group_id, if (ccnet_db_type(db) == CCNET_DB_TYPE_PGSQL) g_string_printf (sql, - "SELECT group_id, group_name, creator_name, timestamp FROM " + "SELECT group_id, group_name, creator_name, timestamp, parent_group_id FROM " "\"%s\" WHERE group_id = ?", table_name); else g_string_printf (sql, - "SELECT group_id, group_name, creator_name, timestamp FROM " + "SELECT group_id, group_name, creator_name, timestamp, parent_group_id FROM " "`%s` WHERE group_id = ?", table_name); if (ccnet_db_statement_foreach_row (db, sql->str, get_ccnetgroup_cb, &ccnetgroup, @@ -732,11 +970,13 @@ get_all_ccnetgroups_cb (CcnetDBRow *row, void *data) const char *group_name; const char *creator; gint64 ts; + int parent_group_id; group_id = ccnet_db_row_get_column_int (row, 0); group_name = (const char *)ccnet_db_row_get_column_text (row, 1); creator = (const char *)ccnet_db_row_get_column_text (row, 2); ts = ccnet_db_row_get_column_int64 (row, 3); + parent_group_id = ccnet_db_row_get_column_int (row, 4); char *creator_l = g_ascii_strdown (creator, -1); CcnetGroup *group = g_object_new (CCNET_TYPE_GROUP, @@ -745,6 +985,7 @@ get_all_ccnetgroups_cb (CcnetDBRow *row, void *data) "creator_name", creator_l, "timestamp", ts, "source", "DB", + "parent_group_id", parent_group_id, NULL); g_free (creator_l); @@ -753,6 +994,33 @@ get_all_ccnetgroups_cb (CcnetDBRow *row, void *data) return TRUE; } +GList * +ccnet_group_manager_get_top_groups (CcnetGroupManager *mgr, + GError **error) +{ + CcnetDB *db = mgr->priv->db; + GList *ret = NULL; + GString *sql = g_string_new (""); + const char *table_name = mgr->priv->table_name; + int rc; + + if (ccnet_db_type(mgr->priv->db) == CCNET_DB_TYPE_PGSQL) + g_string_printf (sql, "SELECT group_id, group_name, " + "creator_name, timestamp, parent_group_id FROM \"%s\" " + "WHERE parent_group_id=-1 ORDER BY timestamp DESC", table_name); + else + g_string_printf (sql, "SELECT group_id, group_name, " + "creator_name, timestamp, parent_group_id FROM `%s` " + "WHERE parent_group_id=-1 ORDER BY timestamp DESC", table_name); + rc = ccnet_db_statement_foreach_row (db, sql->str, + get_all_ccnetgroups_cb, &ret, 0); + g_string_free (sql, TRUE); + if (rc < 0) + return NULL; + + return g_list_reverse (ret); +} + GList* ccnet_group_manager_get_all_groups (CcnetGroupManager *mgr, int start, int limit, GError **error) @@ -766,14 +1034,13 @@ ccnet_group_manager_get_all_groups (CcnetGroupManager *mgr, if (ccnet_db_type(mgr->priv->db) == CCNET_DB_TYPE_PGSQL) { if (start == -1 && limit == -1) { g_string_printf (sql, "SELECT group_id, group_name, " - "creator_name, timestamp FROM \"%s\" " + "creator_name, timestamp, parent_group_id FROM \"%s\" " "ORDER BY timestamp DESC", table_name); rc = ccnet_db_statement_foreach_row (db, sql->str, - get_all_ccnetgroups_cb, &ret, - 0); + get_all_ccnetgroups_cb, &ret, 0); } else { g_string_printf (sql, "SELECT group_id, group_name, " - "creator_name, timestamp FROM \"%s\" " + "creator_name, timestamp, parent_group_id FROM \"%s\" " "ORDER BY timestamp DESC LIMIT ? OFFSET ?", table_name); rc = ccnet_db_statement_foreach_row (db, sql->str, @@ -783,14 +1050,13 @@ ccnet_group_manager_get_all_groups (CcnetGroupManager *mgr, } else { if (start == -1 && limit == -1) { g_string_printf (sql, "SELECT `group_id`, `group_name`, " - "`creator_name`, `timestamp` FROM `%s` " + "`creator_name`, `timestamp`, `parent_group_id` FROM `%s` " "ORDER BY timestamp DESC", table_name); rc = ccnet_db_statement_foreach_row (db, sql->str, - get_all_ccnetgroups_cb, &ret, - 0); + get_all_ccnetgroups_cb, &ret, 0); } else { g_string_printf (sql, "SELECT `group_id`, `group_name`, " - "`creator_name`, `timestamp` FROM `%s` " + "`creator_name`, `timestamp`, `parent_group_id` FROM `%s` " "ORDER BY timestamp DESC LIMIT ? OFFSET ?", table_name); rc = ccnet_db_statement_foreach_row (db, sql->str, @@ -847,7 +1113,7 @@ ccnet_group_manager_search_groups (CcnetGroupManager *mgr, if (start == -1 && limit == -1) { g_string_printf (sql, "SELECT group_id, group_name, " - "creator_name, timestamp " + "creator_name, timestamp, parent_group_id " "FROM \"%s\" WHERE group_name LIKE ?", table_name); rc = ccnet_db_statement_foreach_row (db, sql->str, get_all_ccnetgroups_cb, &ret, @@ -855,7 +1121,7 @@ ccnet_group_manager_search_groups (CcnetGroupManager *mgr, } else { g_string_printf (sql, "SELECT group_id, group_name, " - "creator_name, timestamp " + "creator_name, timestamp, parent_group_id " "FROM \"%s\" WHERE group_name LIKE ? " "LIMIT ? OFFSET ?", table_name); rc = ccnet_db_statement_foreach_row (db, sql->str, @@ -867,7 +1133,7 @@ ccnet_group_manager_search_groups (CcnetGroupManager *mgr, if (start == -1 && limit == -1) { g_string_printf (sql, "SELECT group_id, group_name, " - "creator_name, timestamp " + "creator_name, timestamp, parent_group_id " "FROM `%s` WHERE group_name LIKE ?", table_name); rc = ccnet_db_statement_foreach_row (db, sql->str, get_all_ccnetgroups_cb, &ret, @@ -875,7 +1141,7 @@ ccnet_group_manager_search_groups (CcnetGroupManager *mgr, } else { g_string_printf (sql, "SELECT group_id, group_name, " - "creator_name, timestamp " + "creator_name, timestamp, parent_group_id " "FROM `%s` WHERE group_name LIKE ? " "LIMIT ? OFFSET ?", table_name); rc = ccnet_db_statement_foreach_row (db, sql->str, diff --git a/net/server/group-mgr.h b/net/server/group-mgr.h index 14bf51a..45c7997 100644 --- a/net/server/group-mgr.h +++ b/net/server/group-mgr.h @@ -27,16 +27,19 @@ void ccnet_group_manager_start (CcnetGroupManager *manager); int ccnet_group_manager_create_group (CcnetGroupManager *mgr, const char *group_name, const char *user_name, + int parent_group_id, GError **error); int ccnet_group_manager_create_org_group (CcnetGroupManager *mgr, int org_id, const char *group_name, const char *user_name, + int parent_group_id, GError **error); int ccnet_group_manager_remove_group (CcnetGroupManager *mgr, int group_id, + gboolean remove_anyway, GError **error); int ccnet_group_manager_add_member (CcnetGroupManager *mgr, @@ -74,6 +77,7 @@ int ccnet_group_manager_quit_group (CcnetGroupManager *mgr, GList * ccnet_group_manager_get_groups_by_user (CcnetGroupManager *mgr, const char *user_name, + gboolean return_ancestors, GError **error); CcnetGroup * @@ -111,5 +115,16 @@ GList* ccnet_group_manager_search_groups (CcnetGroupManager *mgr, const char *keyword, int start, int limit); + +GList * +ccnet_group_manager_get_top_groups (CcnetGroupManager *mgr, GError **error); + +GList * +ccnet_group_manager_get_child_groups (CcnetGroupManager *mgr, int group_id, + GError **error); + +GList * +ccnet_group_manager_get_ancestor_groups (CcnetGroupManager *mgr, int group_id); + #endif /* GROUP_MGR_H */ diff --git a/net/server/org-mgr.c b/net/server/org-mgr.c index d342465..5685d06 100644 --- a/net/server/org-mgr.c +++ b/net/server/org-mgr.c @@ -613,6 +613,7 @@ get_org_groups (CcnetDBRow *row, void *data) const char *group_name = ccnet_db_row_get_column_text (row, 1); const char *creator_name = ccnet_db_row_get_column_text (row, 2); gint64 ts = ccnet_db_row_get_column_int64 (row, 3); + int parent_group_id = ccnet_db_row_get_column_int (row, 4); group = g_object_new (CCNET_TYPE_GROUP, "id", group_id, @@ -620,6 +621,7 @@ get_org_groups (CcnetDBRow *row, void *data) "creator_name", creator_name, "timestamp", ts, "source", "DB", + "parent_group_id", parent_group_id, NULL); *plist = g_list_prepend (*plist, group); @@ -627,6 +629,27 @@ get_org_groups (CcnetDBRow *row, void *data) return TRUE; } +GList * +ccnet_org_manager_get_org_top_groups (CcnetOrgManager *mgr, int org_id, GError **error) +{ + CcnetDB *db = mgr->priv->db; + GList *ret = NULL; + char *sql; + int rc; + + sql = "SELECT g.group_id, group_name, creator_name, timestamp, parent_group_id FROM " + "`OrgGroup` o, `Group` g WHERE o.group_id = g.group_id AND " + "org_id=? AND parent_group_id=-1 ORDER BY timestamp DESC"; + + rc = ccnet_db_statement_foreach_row (db, sql, + get_org_groups, &ret, + 1, "int", org_id); + if (rc < 0) + return NULL; + + return g_list_reverse (ret); +} + GList * ccnet_org_manager_get_org_groups (CcnetOrgManager *mgr, int org_id, @@ -639,14 +662,14 @@ ccnet_org_manager_get_org_groups (CcnetOrgManager *mgr, int rc; if (limit == -1) { - sql = "SELECT g.group_id, group_name, creator_name, timestamp FROM " + sql = "SELECT g.group_id, group_name, creator_name, timestamp, parent_group_id FROM " "OrgGroup o, `Group` g WHERE o.group_id = g.group_id AND org_id = ?"; rc = ccnet_db_statement_foreach_row (db, sql, get_org_groups, &ret, 1, "int", org_id); } else { - sql = "SELECT g.group_id, group_name, creator_name, timestamp FROM " + sql = "SELECT g.group_id, group_name, creator_name, timestamp, parent_group_id FROM " "OrgGroup o, `Group` g WHERE o.group_id = g.group_id AND org_id = ? " "LIMIT ? OFFSET ?"; rc = ccnet_db_statement_foreach_row (db, diff --git a/net/server/org-mgr.h b/net/server/org-mgr.h index 15061eb..e9d9dc5 100644 --- a/net/server/org-mgr.h +++ b/net/server/org-mgr.h @@ -114,6 +114,9 @@ ccnet_org_manager_get_org_groups_by_user (CcnetOrgManager *mgr, const char *user, int org_id); +GList * +ccnet_org_manager_get_org_top_groups (CcnetOrgManager *mgr, int org_id, GError **error); + int ccnet_org_manager_org_user_exists (CcnetOrgManager *mgr, int org_id, diff --git a/python/ccnet/rpc.py b/python/ccnet/rpc.py index 777c451..8a7a33f 100644 --- a/python/ccnet/rpc.py +++ b/python/ccnet/rpc.py @@ -259,12 +259,12 @@ class CcnetThreadedRpcClient(RpcClientBase): def get_peers_by_email(self, email): pass - @searpc_func("int", ["string", "string", "string"]) - def create_group(self, group_name, user_name, gtype): + @searpc_func("int", ["string", "string", "string", "int"]) + def create_group(self, group_name, user_name, gtype, parent_group_id): pass - @searpc_func("int", ["int", "string", "string"]) - def create_org_group(self, org_id, group_name, user_name): + @searpc_func("int", ["int", "string", "string", "int"]) + def create_org_group(self, org_id, group_name, user_name, parent_group_id): pass @searpc_func("int", ["int"]) @@ -295,14 +295,26 @@ class CcnetThreadedRpcClient(RpcClientBase): def quit_group(self, group_id, user_name): pass - @searpc_func("objlist", ["string"]) - def get_groups(self, user_name): + @searpc_func("objlist", ["string", "int"]) + def get_groups(self, user_name, return_ancestors): pass @searpc_func("objlist", ["int", "int", "string"]) def get_all_groups(self, start, limit, source): pass + + @searpc_func("objlist", ["int"]) + def get_ancestor_groups(self, group_id): + pass + + @searpc_func("objlist", []) + def get_top_groups(self): + pass + @searpc_func("objlist", ["int"]) + def get_child_groups(self, group_id): + pass + @searpc_func("object", ["int"]) def get_group(self, group_id): pass @@ -395,6 +407,10 @@ class CcnetThreadedRpcClient(RpcClientBase): def get_org_groups_by_user (self, user, org_id): pass + @searpc_func("objlist", ["int"]) + def get_org_top_groups(self, org_id): + pass + @searpc_func("int", ["int", "string"]) def org_user_exists(self, org_id, email): pass