diff --git a/common/rpc-service.c b/common/rpc-service.c index 431291e..bc9c311 100644 --- a/common/rpc-service.c +++ b/common/rpc-service.c @@ -5282,4 +5282,23 @@ seafile_org_get_shared_users_by_repo (int org_id, return seaf_share_manager_org_get_shared_users_by_repo (seaf->share_mgr, org_id, repo_id); } + +char * +seafile_convert_repo_path (const char *repo_id, + const char *path, + const char *user, + int is_org, + GError **error) +{ + if (!is_uuid_valid(repo_id) || !path || !user) { + g_set_error (error, 0, SEAF_ERR_BAD_ARGS, "Arguments error"); + return NULL; + } + + char *rpath = format_dir_path (path); + char *ret = seaf_repo_manager_convert_repo_path(seaf->repo_mgr, repo_id, rpath, user, is_org ? TRUE : FALSE, error); + g_free(rpath); + + return ret; +} #endif /* SEAFILE_SERVER */ diff --git a/include/seafile-rpc.h b/include/seafile-rpc.h index 3398aca..d7e0073 100644 --- a/include/seafile-rpc.h +++ b/include/seafile-rpc.h @@ -1102,4 +1102,11 @@ GList * seafile_org_get_shared_users_by_repo (int org_id, const char *repo_id, GError **error); + +char * +seafile_convert_repo_path (const char *repo_id, + const char *path, + const char *user, + int is_org, + GError **error); #endif diff --git a/lib/rpc_table.py b/lib/rpc_table.py index e85c022..f696d50 100644 --- a/lib/rpc_table.py +++ b/lib/rpc_table.py @@ -51,6 +51,7 @@ func_table = [ [ "string", ["string", "string", "int"] ], [ "string", ["string", "string", "int", "int"] ], [ "string", ["string", "string", "string"] ], + [ "string", ["string", "string", "string", "int"] ], [ "string", ["string", "string", "string", "string"] ], [ "string", ["string", "string", "string", "string", "int"] ], [ "string", ["string", "string", "string", "string", "string"] ], diff --git a/python/seafile/rpcclient.py b/python/seafile/rpcclient.py index 90a19f8..d7ad782 100644 --- a/python/seafile/rpcclient.py +++ b/python/seafile/rpcclient.py @@ -1037,3 +1037,7 @@ class SeafServerThreadedRpcClient(ccnet.RpcClientBase): @searpc_func("objlist", ["int", "string"]) def org_get_shared_users_by_repo (org_id, repo_id): pass + + @searpc_func("string", ["string", "string", "string", "int"]) + def convert_repo_path(repo_id, path, user, is_org): + pass diff --git a/python/seaserv/api.py b/python/seaserv/api.py index d3a95d0..15df68b 100644 --- a/python/seaserv/api.py +++ b/python/seaserv/api.py @@ -798,6 +798,9 @@ class SeafileAPI(object): def list_org_inner_pub_repos(self, org_id): return seafserv_threaded_rpc.list_org_inner_pub_repos(org_id) + def convert_repo_path(self, repo_id, path, user, is_org=False): + return seafserv_threaded_rpc.convert_repo_path(repo_id, path, user, 1 if is_org else 0) + seafile_api = SeafileAPI() class CcnetAPI(object): diff --git a/server/repo-mgr.c b/server/repo-mgr.c index f0b23a6..1ef68a0 100644 --- a/server/repo-mgr.c +++ b/server/repo-mgr.c @@ -4119,3 +4119,182 @@ out: return g_list_reverse (repos); } + +typedef struct RepoPath { + char *repo_id; + char *path; + int group_id; +} RepoPath; + + +gboolean +convert_repo_path_cb (SeafDBRow *row, void *data) +{ + GList **repo_paths = data; + + const char *repo_id = seaf_db_row_get_column_text (row, 0); + const char *path = seaf_db_row_get_column_text (row, 1); + int group_id = seaf_db_row_get_column_int (row, 2); + + RepoPath *rp = g_new0(RepoPath, 1); + rp->repo_id = g_strdup(repo_id); + rp->path = g_strdup(path); + rp->group_id = group_id; + *repo_paths = g_list_append (*repo_paths, rp); + + return TRUE; +} + +static void +free_repo_path (gpointer data) +{ + if (!data) + return; + + RepoPath *rp = data; + g_free (rp->repo_id); + g_free (rp->path); + g_free (rp); +} + +static char * +filter_path (GList *repo_paths, const char *path) +{ + GList *ptr = NULL; + int len; + const char *relative_path; + char *ret = NULL; + RepoPath *rp = NULL, res; + res.repo_id = NULL; + res.path = NULL; + res.group_id = 0; + + /* Find nearest item which contains @path, */ + for (ptr = repo_paths; ptr; ptr = ptr->next) { + rp = ptr->data; + len = strlen(rp->path); + if (strncmp(rp->path, path, len) == 0 && (path[len] == '/' || path[len] == '\0')) { + + if (g_strcmp0(rp->path, res.path) > 0) { + res.path = rp->path; + res.repo_id = rp->repo_id; + res.group_id = rp->group_id; + } + } + } + if (res.repo_id && res.path) { + relative_path = path + strlen(res.path); + if (relative_path[0] == '\0') + relative_path = "/"; + + json_t *json = json_object (); + json_object_set_string_member(json, "repo_id", res.repo_id); + json_object_set_string_member(json, "path", relative_path); + if (res.group_id > 0) + json_object_set_int_member(json, "group_id", res.group_id); + ret = json_dumps (json, 0); + json_decref (json); + } + + return ret; +} + +/* Convert origin repo and path to virtual repo and relative path */ +char * +seaf_repo_manager_convert_repo_path (SeafRepoManager *mgr, + const char *repo_id, + const char *path, + const char *user, + gboolean is_org, + GError **error) +{ + char *ret = NULL; + int rc; + int group_id; + GString *sql; + SearpcClient *rpc_client = NULL; + CcnetGroup *group; + GList *groups = NULL, *p1; + GList *repo_paths = NULL; + SeafVirtRepo *vinfo = NULL; + const char *r_repo_id = repo_id; + char *r_path = NULL; + + vinfo = seaf_repo_manager_get_virtual_repo_info (mgr, repo_id); + if (vinfo) { + r_repo_id = vinfo->origin_repo_id; + r_path = g_strconcat (vinfo->path, path, NULL); + } else { + r_path = g_strdup(path); + } + + sql = g_string_new (""); + g_string_printf (sql, "SELECT v.repo_id, path, 0 FROM VirtualRepo v, %s s WHERE " + "v.origin_repo=? AND v.repo_id=s.repo_id AND s.to_email=?", + is_org ? "OrgSharedRepo" : "SharedRepo"); + rc = seaf_db_statement_foreach_row (seaf->db, + sql->str, convert_repo_path_cb, + &repo_paths, 2, + "string", r_repo_id, "string", user); + if (rc < 0) { + seaf_warning("Failed to convert repo path [%s:%s] to virtual repo path, db_error.\n", + repo_id, path); + goto out; + } + ret = filter_path(repo_paths, r_path); + g_list_free_full(repo_paths, free_repo_path); + repo_paths = NULL; + if (ret) + goto out; + + rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool, + NULL, + "ccnet-threaded-rpcserver"); + if (!rpc_client) + goto out; + + /* Get the groups this user belongs to. */ + groups = ccnet_get_groups_by_user (rpc_client, user, 1); + if (!groups) { + goto out; + } + + g_string_printf (sql, "SELECT v.repo_id, path, r.group_id FROM VirtualRepo v, %s r WHERE " + "v.origin_repo=? AND v.repo_id=r.repo_id AND r.group_id IN(", + is_org ? "OrgGroupRepo" : "RepoGroup"); + for (p1 = groups; p1 != NULL; p1 = p1->next) { + group = p1->data; + g_object_get (group, "id", &group_id, NULL); + + g_string_append_printf (sql, "%d", group_id); + if (p1->next) + g_string_append_printf (sql, ","); + } + g_string_append_printf (sql, ")"); + + rc = seaf_db_statement_foreach_row (seaf->db, + sql->str, convert_repo_path_cb, + &repo_paths, 1, + "string", r_repo_id); + if (rc < 0) { + seaf_warning("Failed to convert repo path [%s:%s] to virtual repo path, db error.\n", + repo_id, path); + g_string_free (sql, TRUE); + goto out; + } + ret = filter_path(repo_paths, r_path); + g_list_free_full(repo_paths, free_repo_path); + +out: + g_free (r_path); + if (vinfo) + seaf_virtual_repo_info_free (vinfo); + g_string_free (sql, TRUE); + ccnet_rpc_client_free (rpc_client); + for (p1 = groups; p1 != NULL; p1 = p1->next) + g_object_unref ((GObject *)p1->data); + g_list_free (groups); + + return ret; +} + diff --git a/server/repo-mgr.h b/server/repo-mgr.h index bdf74c6..52f001e 100644 --- a/server/repo-mgr.h +++ b/server/repo-mgr.h @@ -861,4 +861,12 @@ post_files_and_gen_commit (GList *filenames, GList *id_list, GList *size_list, GError **error); + +char * +seaf_repo_manager_convert_repo_path (SeafRepoManager *mgr, + const char *repo_id, + const char *path, + const char *user, + gboolean is_org, + GError **error); #endif diff --git a/server/seaf-server.c b/server/seaf-server.c index b70fb52..d6cb3a3 100644 --- a/server/seaf-server.c +++ b/server/seaf-server.c @@ -378,6 +378,11 @@ static void start_rpc_service (CcnetClient *client, int cloud_mode) "get_trash_repo_owner", searpc_signature_string__string()); + searpc_server_register_function ("seafserv-threaded-rpcserver", + seafile_convert_repo_path, + "convert_repo_path", + searpc_signature_string__string_string_string_int()); + /* share repo to user */ searpc_server_register_function ("seafserv-threaded-rpcserver", seafile_add_share,