1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 #include "common.h"
4 #include "utils.h"
5
6 #include "log.h"
7
8 #include "seafile-session.h"
9 #include "share-mgr.h"
10
11 #include "seaf-db.h"
12 #include "log.h"
13 #include "seafile-error.h"
14
15 SeafShareManager *
seaf_share_manager_new(SeafileSession * seaf)16 seaf_share_manager_new (SeafileSession *seaf)
17 {
18 SeafShareManager *mgr = g_new0 (SeafShareManager, 1);
19
20 mgr->seaf = seaf;
21
22 return mgr;
23 }
24
25 int
seaf_share_manager_start(SeafShareManager * mgr)26 seaf_share_manager_start (SeafShareManager *mgr)
27 {
28 if (!mgr->seaf->create_tables && seaf_db_type (mgr->seaf->db) != SEAF_DB_TYPE_PGSQL)
29 return 0;
30
31 SeafDB *db = mgr->seaf->db;
32 const char *sql;
33
34 int db_type = seaf_db_type (db);
35 if (db_type == SEAF_DB_TYPE_MYSQL) {
36 sql = "CREATE TABLE IF NOT EXISTS SharedRepo "
37 "(id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,"
38 "repo_id CHAR(37) , from_email VARCHAR(255), to_email VARCHAR(255), "
39 "permission CHAR(15), INDEX (repo_id), "
40 "INDEX(from_email), INDEX(to_email)) ENGINE=INNODB";
41
42 if (seaf_db_query (db, sql) < 0)
43 return -1;
44 } else if (db_type == SEAF_DB_TYPE_SQLITE) {
45 sql = "CREATE TABLE IF NOT EXISTS SharedRepo "
46 "(repo_id CHAR(37) , from_email VARCHAR(255), to_email VARCHAR(255), "
47 "permission CHAR(15))";
48 if (seaf_db_query (db, sql) < 0)
49 return -1;
50 sql = "CREATE INDEX IF NOT EXISTS RepoIdIndex on SharedRepo (repo_id)";
51 if (seaf_db_query (db, sql) < 0)
52 return -1;
53 sql = "CREATE INDEX IF NOT EXISTS FromEmailIndex on SharedRepo (from_email)";
54 if (seaf_db_query (db, sql) < 0)
55 return -1;
56 sql = "CREATE INDEX IF NOT EXISTS ToEmailIndex on SharedRepo (to_email)";
57 if (seaf_db_query (db, sql) < 0)
58 return -1;
59 }
60 /* else if (db_type == SEAF_DB_TYPE_PGSQL) { */
61 /* sql = "CREATE TABLE IF NOT EXISTS SharedRepo " */
62 /* "(repo_id CHAR(36) , from_email VARCHAR(255), to_email VARCHAR(255), " */
63 /* "permission VARCHAR(15))"; */
64 /* if (seaf_db_query (db, sql) < 0) */
65 /* return -1; */
66
67 /* if (!pgsql_index_exists (db, "sharedrepo_repoid_idx")) { */
68 /* sql = "CREATE INDEX sharedrepo_repoid_idx ON SharedRepo (repo_id)"; */
69 /* if (seaf_db_query (db, sql) < 0) */
70 /* return -1; */
71 /* } */
72 /* if (!pgsql_index_exists (db, "sharedrepo_from_email_idx")) { */
73 /* sql = "CREATE INDEX sharedrepo_from_email_idx ON SharedRepo (from_email)"; */
74 /* if (seaf_db_query (db, sql) < 0) */
75 /* return -1; */
76 /* } */
77 /* if (!pgsql_index_exists (db, "sharedrepo_to_email_idx")) { */
78 /* sql = "CREATE INDEX sharedrepo_to_email_idx ON SharedRepo (to_email)"; */
79 /* if (seaf_db_query (db, sql) < 0) */
80 /* return -1; */
81 /* } */
82 /* } */
83
84 return 0;
85 }
86
87 int
seaf_share_manager_add_share(SeafShareManager * mgr,const char * repo_id,const char * from_email,const char * to_email,const char * permission)88 seaf_share_manager_add_share (SeafShareManager *mgr, const char *repo_id,
89 const char *from_email, const char *to_email,
90 const char *permission)
91 {
92 gboolean db_err = FALSE;
93 int ret = 0;
94
95 char *from_email_l = g_ascii_strdown (from_email, -1);
96 char *to_email_l = g_ascii_strdown (to_email, -1);
97
98 if (seaf_db_statement_exists (mgr->seaf->db,
99 "SELECT repo_id from SharedRepo "
100 "WHERE repo_id=? AND "
101 "from_email=? AND to_email=?",
102 &db_err, 3, "string", repo_id,
103 "string", from_email_l, "string", to_email_l))
104 goto out;
105
106 if (seaf_db_statement_query (mgr->seaf->db,
107 "INSERT INTO SharedRepo (repo_id, from_email, "
108 "to_email, permission) VALUES (?, ?, ?, ?)",
109 4, "string", repo_id, "string", from_email_l,
110 "string", to_email_l, "string", permission) < 0) {
111 ret = -1;
112 goto out;
113 }
114
115 out:
116 g_free (from_email_l);
117 g_free (to_email_l);
118 return ret;
119 }
120
121 int
seaf_share_manager_set_subdir_perm_by_path(SeafShareManager * mgr,const char * repo_id,const char * from_email,const char * to_email,const char * permission,const char * path)122 seaf_share_manager_set_subdir_perm_by_path (SeafShareManager *mgr, const char *repo_id,
123 const char *from_email, const char *to_email,
124 const char *permission, const char *path)
125 {
126 char *sql;
127 int ret;
128
129 char *from_email_l = g_ascii_strdown (from_email, -1);
130 char *to_email_l = g_ascii_strdown (to_email, -1);
131 sql = "UPDATE SharedRepo SET permission=? WHERE repo_id IN "
132 "(SELECT repo_id FROM VirtualRepo WHERE origin_repo=? AND path=?) "
133 "AND from_email=? AND to_email=?";
134
135 ret = seaf_db_statement_query (mgr->seaf->db, sql,
136 5, "string", permission,
137 "string", repo_id,
138 "string", path,
139 "string", from_email_l,
140 "string", to_email_l);
141 g_free (from_email_l);
142 g_free (to_email_l);
143 return ret;
144 }
145
146 int
seaf_share_manager_set_permission(SeafShareManager * mgr,const char * repo_id,const char * from_email,const char * to_email,const char * permission)147 seaf_share_manager_set_permission (SeafShareManager *mgr, const char *repo_id,
148 const char *from_email, const char *to_email,
149 const char *permission)
150 {
151 char *sql;
152 int ret;
153
154 char *from_email_l = g_ascii_strdown (from_email, -1);
155 char *to_email_l = g_ascii_strdown (to_email, -1);
156 sql = "UPDATE SharedRepo SET permission=? WHERE "
157 "repo_id=? AND from_email=? AND to_email=?";
158
159 ret = seaf_db_statement_query (mgr->seaf->db, sql,
160 4, "string", permission, "string", repo_id,
161 "string", from_email_l, "string", to_email_l);
162
163 g_free (from_email_l);
164 g_free (to_email_l);
165 return ret;
166 }
167
168 static gboolean
collect_repos(SeafDBRow * row,void * data)169 collect_repos (SeafDBRow *row, void *data)
170 {
171 GList **p_repos = data;
172 const char *repo_id;
173 const char *vrepo_id;
174 const char *email;
175 const char *permission;
176 const char *commit_id;
177 gint64 size;
178 SeafileRepo *repo;
179
180 repo_id = seaf_db_row_get_column_text (row, 0);
181 vrepo_id = seaf_db_row_get_column_text (row, 1);
182 email = seaf_db_row_get_column_text (row, 2);
183 permission = seaf_db_row_get_column_text (row, 3);
184 commit_id = seaf_db_row_get_column_text (row, 4);
185 size = seaf_db_row_get_column_int64 (row, 5);
186 const char *repo_name = seaf_db_row_get_column_text (row, 8);
187 gint64 update_time = seaf_db_row_get_column_int64 (row, 9);
188 int version = seaf_db_row_get_column_int (row, 10);
189 gboolean is_encrypted = seaf_db_row_get_column_int (row, 11) ? TRUE : FALSE;
190 const char *last_modifier = seaf_db_row_get_column_text (row, 12);
191 int status = seaf_db_row_get_column_int (row, 13);
192 const char *origin_repo_name = seaf_db_row_get_column_text (row, 14);
193
194 char *email_l = g_ascii_strdown (email, -1);
195
196 repo = g_object_new (SEAFILE_TYPE_REPO,
197 "share_type", "personal",
198 "repo_id", repo_id,
199 "id", repo_id,
200 "head_cmmt_id", commit_id,
201 "user", email_l,
202 "permission", permission,
203 "is_virtual", (vrepo_id != NULL),
204 "size", size,
205 "status", status,
206 NULL);
207 g_free (email_l);
208
209 if (repo) {
210 if (vrepo_id) {
211 const char *origin_repo_id = seaf_db_row_get_column_text (row, 6);
212 const char *origin_path = seaf_db_row_get_column_text (row, 7);
213 g_object_set (repo, "store_id", origin_repo_id,
214 "origin_repo_id", origin_repo_id,
215 "origin_repo_name", origin_repo_name,
216 "origin_path", origin_path, NULL);
217 } else {
218 g_object_set (repo, "store_id", repo_id, NULL);
219 }
220 if (repo_name) {
221 g_object_set (repo, "name", repo_name,
222 "repo_name", repo_name,
223 "last_modify", update_time,
224 "last_modified", update_time,
225 "version", version,
226 "encrypted", is_encrypted,
227 "last_modifier", last_modifier, NULL);
228 }
229 *p_repos = g_list_prepend (*p_repos, repo);
230 }
231
232 return TRUE;
233 }
234
235 static void
seaf_fill_repo_commit_if_not_in_db(GList ** repos)236 seaf_fill_repo_commit_if_not_in_db (GList **repos)
237 {
238 char *repo_name = NULL;
239 char *last_modifier = NULL;
240 char *repo_id = NULL;
241 char *commit_id = NULL;
242 SeafileRepo *repo = NULL;
243 GList *p = NULL;
244
245 for (p = *repos; p;) {
246 repo = p->data;
247 g_object_get (repo, "name", &repo_name, NULL);
248 g_object_get (repo, "last_modifier", &last_modifier, NULL);
249 if (!repo_name || !last_modifier) {
250 g_object_get (repo, "repo_id", &repo_id,
251 "head_cmmt_id", &commit_id, NULL);
252 SeafCommit *commit = seaf_commit_manager_get_commit_compatible (seaf->commit_mgr,
253 repo_id, commit_id);
254 if (!commit) {
255 seaf_warning ("Commit %s:%s is missing\n", repo_id, commit_id);
256 GList *next = p->next;
257 g_object_unref (repo);
258 *repos = g_list_delete_link (*repos, p);
259 p = next;
260 if (repo_name)
261 g_free (repo_name);
262 if (last_modifier)
263 g_free (last_modifier);
264 continue;
265 } else {
266 g_object_set (repo, "name", commit->repo_name,
267 "repo_name", commit->repo_name,
268 "last_modify", commit->ctime,
269 "last_modified", commit->ctime,
270 "version", commit->version,
271 "encrypted", commit->encrypted,
272 "last_modifier", commit->creator_name,
273 NULL);
274
275 /* Set to database */
276 set_repo_commit_to_db (repo_id, commit->repo_name, commit->ctime, commit->version,
277 commit->encrypted, commit->creator_name);
278
279 seaf_commit_unref (commit);
280 }
281 g_free (repo_id);
282 g_free (commit_id);
283 }
284 if (repo_name)
285 g_free (repo_name);
286 if (last_modifier)
287 g_free (last_modifier);
288
289 p = p->next;
290 }
291 }
292
293 GList*
seaf_share_manager_list_share_repos(SeafShareManager * mgr,const char * email,const char * type,int start,int limit,gboolean * db_err)294 seaf_share_manager_list_share_repos (SeafShareManager *mgr, const char *email,
295 const char *type, int start, int limit,
296 gboolean *db_err)
297 {
298 GList *ret = NULL, *p;
299 char *sql;
300
301 if (start == -1 && limit == -1) {
302 if (g_strcmp0 (type, "from_email") == 0) {
303 sql = "SELECT sh.repo_id, v.repo_id, "
304 "to_email, permission, commit_id, s.size, "
305 "v.origin_repo, v.path, i.name, "
306 "i.update_time, i.version, i.is_encrypted, i.last_modifier, i.status, "
307 "(SELECT name from RepoInfo WHERE repo_id=v.origin_repo) FROM "
308 "SharedRepo sh LEFT JOIN VirtualRepo v ON "
309 "sh.repo_id=v.repo_id "
310 "LEFT JOIN RepoSize s ON sh.repo_id = s.repo_id "
311 "LEFT JOIN RepoInfo i ON sh.repo_id = i.repo_id, Branch b "
312 "WHERE from_email=? AND "
313 "sh.repo_id = b.repo_id AND "
314 "b.name = 'master' "
315 "ORDER BY i.update_time DESC, sh.repo_id";
316 } else if (g_strcmp0 (type, "to_email") == 0) {
317 sql = "SELECT sh.repo_id, v.repo_id, "
318 "from_email, permission, commit_id, s.size, "
319 "v.origin_repo, v.path, i.name, "
320 "i.update_time, i.version, i.is_encrypted, i.last_modifier, i.status, "
321 "(SELECT name from RepoInfo WHERE repo_id=v.origin_repo) FROM "
322 "SharedRepo sh LEFT JOIN VirtualRepo v ON "
323 "sh.repo_id=v.repo_id "
324 "LEFT JOIN RepoSize s ON sh.repo_id = s.repo_id "
325 "LEFT JOIN RepoInfo i ON sh.repo_id = i.repo_id, Branch b "
326 "WHERE to_email=? AND "
327 "sh.repo_id = b.repo_id AND "
328 "b.name = 'master' "
329 "ORDER BY i.update_time DESC, sh.repo_id";
330 } else {
331 /* should never reach here */
332 seaf_warning ("[share mgr] Wrong column type");
333 return NULL;
334 }
335
336 if (seaf_db_statement_foreach_row (mgr->seaf->db, sql,
337 collect_repos, &ret,
338 1, "string", email) < 0) {
339 seaf_warning ("[share mgr] DB error when get shared repo id and email "
340 "for %s.\n", email);
341 for (p = ret; p; p = p->next)
342 g_object_unref (p->data);
343 g_list_free (ret);
344 if (db_err)
345 *db_err = TRUE;
346 return NULL;
347 }
348 }
349 else {
350 if (g_strcmp0 (type, "from_email") == 0) {
351 sql = "SELECT sh.repo_id, v.repo_id, "
352 "to_email, permission, commit_id, s.size, "
353 "v.origin_repo, v.path, i.name, "
354 "i.update_time, i.version, i.is_encrypted, i.last_modifier, i.status, "
355 "(SELECT name from RepoInfo WHERE repo_id=v.origin_repo) FROM "
356 "SharedRepo sh LEFT JOIN VirtualRepo v ON "
357 "sh.repo_id=v.repo_id "
358 "LEFT JOIN RepoSize s ON sh.repo_id = s.repo_id "
359 "LEFT JOIN RepoInfo i ON sh.repo_id = i.repo_id, Branch b "
360 "WHERE from_email=? "
361 "AND sh.repo_id = b.repo_id "
362 "AND b.name = 'master' "
363 "ORDER BY i.update_time DESC, sh.repo_id "
364 "LIMIT ? OFFSET ?";
365 } else if (g_strcmp0 (type, "to_email") == 0) {
366 sql = "SELECT sh.repo_id, v.repo_id, "
367 "from_email, permission, commit_id, s.size, "
368 "v.origin_repo, v.path, i.name, "
369 "i.update_time, i.version, i.is_encrypted, i.last_modifier, i.status, "
370 "(SELECT name from RepoInfo WHERE repo_id=v.origin_repo) FROM "
371 "SharedRepo sh LEFT JOIN VirtualRepo v ON "
372 "sh.repo_id=v.repo_id "
373 "LEFT JOIN RepoSize s ON sh.repo_id = s.repo_id "
374 "LEFT JOIN RepoInfo i ON sh.repo_id = i.repo_id, Branch b "
375 "WHERE to_email=? "
376 "AND sh.repo_id = b.repo_id "
377 "AND b.name = 'master' "
378 "ORDER BY i.update_time DESC, sh.repo_id "
379 "LIMIT ? OFFSET ?";
380 } else {
381 /* should never reach here */
382 seaf_warning ("[share mgr] Wrong column type");
383 return NULL;
384 }
385
386 if (seaf_db_statement_foreach_row (mgr->seaf->db, sql,
387 collect_repos, &ret,
388 3, "string", email,
389 "int", limit, "int", start) < 0) {
390 seaf_warning ("[share mgr] DB error when get shared repo id and email "
391 "for %s.\n", email);
392 for (p = ret; p; p = p->next)
393 g_object_unref (p->data);
394 g_list_free (ret);
395 if (db_err)
396 *db_err = TRUE;
397 return NULL;
398 }
399 }
400
401 seaf_fill_repo_commit_if_not_in_db (&ret);
402
403 return g_list_reverse (ret);
404 }
405
406 static gboolean
collect_shared_to(SeafDBRow * row,void * data)407 collect_shared_to (SeafDBRow *row, void *data)
408 {
409 GList **plist = data;
410 const char *to_email;
411
412 to_email = seaf_db_row_get_column_text (row, 0);
413 *plist = g_list_prepend (*plist, g_ascii_strdown(to_email, -1));
414
415 return TRUE;
416 }
417
418 GList *
seaf_share_manager_list_shared_to(SeafShareManager * mgr,const char * owner,const char * repo_id)419 seaf_share_manager_list_shared_to (SeafShareManager *mgr,
420 const char *owner,
421 const char *repo_id)
422 {
423 char *sql;
424 GList *ret = NULL;
425
426 sql = "SELECT to_email FROM SharedRepo WHERE "
427 "from_email=? AND repo_id=?";
428 if (seaf_db_statement_foreach_row (mgr->seaf->db, sql,
429 collect_shared_to, &ret,
430 2, "string", owner, "string", repo_id) < 0) {
431 seaf_warning ("[share mgr] DB error when list shared to.\n");
432 string_list_free (ret);
433 return NULL;
434 }
435
436 return ret;
437 }
438
439 static gboolean
collect_repo_shared_to(SeafDBRow * row,void * data)440 collect_repo_shared_to (SeafDBRow *row, void *data)
441 {
442 GList **shared_to = data;
443 const char *to_email = seaf_db_row_get_column_text (row, 0);
444 char *email_down = g_ascii_strdown(to_email, -1);
445 const char *perm = seaf_db_row_get_column_text (row, 1);
446 const char *repo_id = seaf_db_row_get_column_text (row, 2);
447
448 SeafileSharedUser *uobj = g_object_new (SEAFILE_TYPE_SHARED_USER,
449 "repo_id", repo_id,
450 "user", email_down,
451 "perm", perm,
452 NULL);
453 *shared_to = g_list_prepend (*shared_to, uobj);
454 g_free (email_down);
455
456 return TRUE;
457 }
458
459 GList *
seaf_share_manager_list_repo_shared_to(SeafShareManager * mgr,const char * from_email,const char * repo_id,GError ** error)460 seaf_share_manager_list_repo_shared_to (SeafShareManager *mgr,
461 const char *from_email,
462 const char *repo_id,
463 GError **error)
464 {
465 GList *shared_to = NULL;
466 char *sql = "SELECT to_email, permission, repo_id FROM SharedRepo WHERE "
467 "from_email=? AND repo_id=?";
468
469 int ret = seaf_db_statement_foreach_row (mgr->seaf->db, sql,
470 collect_repo_shared_to, &shared_to,
471 2, "string", from_email, "string", repo_id);
472 if (ret < 0) {
473 seaf_warning ("Failed to list repo %s shared to from db.\n", repo_id);
474 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
475 "Failed to list repo shared to from db");
476 while (shared_to) {
477 g_object_unref (shared_to->data);
478 shared_to = g_list_delete_link (shared_to, shared_to);
479 }
480 return NULL;
481 }
482
483 return shared_to;
484 }
485
486 static gboolean
collect_repo_shared_group(SeafDBRow * row,void * data)487 collect_repo_shared_group (SeafDBRow *row, void *data)
488 {
489 GList **shared_group = data;
490 int group_id = seaf_db_row_get_column_int (row, 0);
491 const char *perm = seaf_db_row_get_column_text (row, 1);
492 const char *repo_id = seaf_db_row_get_column_text (row, 2);
493
494 SeafileSharedGroup *gobj = g_object_new (SEAFILE_TYPE_SHARED_GROUP,
495 "repo_id", repo_id,
496 "group_id", group_id,
497 "perm", perm,
498 NULL);
499 *shared_group = g_list_prepend (*shared_group, gobj);
500
501 return TRUE;
502 }
503
504 GList *
seaf_share_manager_list_repo_shared_group(SeafShareManager * mgr,const char * from_email,const char * repo_id,GError ** error)505 seaf_share_manager_list_repo_shared_group (SeafShareManager *mgr,
506 const char *from_email,
507 const char *repo_id,
508 GError **error)
509 {
510 GList *shared_group = NULL;
511 char *sql = "SELECT group_id, permission, repo_id FROM RepoGroup WHERE "
512 "user_name=? AND repo_id=?";
513
514 int ret = seaf_db_statement_foreach_row (mgr->seaf->db, sql,
515 collect_repo_shared_group, &shared_group,
516 2, "string", from_email, "string", repo_id);
517 if (ret < 0) {
518 seaf_warning ("Failed to list repo %s shared group from db.\n", repo_id);
519 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
520 "Failed to list repo shared group from db");
521 while (shared_group) {
522 g_object_unref (shared_group->data);
523 shared_group = g_list_delete_link (shared_group, shared_group);
524 }
525 return NULL;
526 }
527
528 return shared_group;
529 }
530
531 static gboolean
get_shared_dirs_to_user(SeafDBRow * row,void * data)532 get_shared_dirs_to_user (SeafDBRow *row, void *data)
533 {
534 GHashTable *dirs = data;
535
536 const char *path = seaf_db_row_get_column_text (row, 0);
537 const char *perm = seaf_db_row_get_column_text (row, 1);
538 g_hash_table_replace (dirs, g_strdup (path), g_strdup (perm));
539
540 return TRUE;
541 }
542
543 static gboolean
get_shared_dirs_to_group(SeafDBRow * row,void * data)544 get_shared_dirs_to_group (SeafDBRow *row, void *data)
545 {
546 GHashTable *dirs = data;
547
548 const char *path = seaf_db_row_get_column_text (row, 0);
549 const char *perm = seaf_db_row_get_column_text (row, 1);
550
551 char *prev_perm = g_hash_table_lookup (dirs, path);
552 if (g_strcmp0 (perm, prev_perm) != 0 &&
553 (prev_perm == NULL || g_strcmp0 (prev_perm, "r") == 0)) {
554 g_hash_table_replace (dirs, g_strdup (path), g_strdup (perm));
555 }
556
557 return TRUE;
558 }
559
560 // Conver group id list to comma separated str
561 // [1, 2, 3] -> 1,2,3
562 static GString *
convert_group_list_to_str(GList * groups)563 convert_group_list_to_str (GList *groups)
564 {
565 GList *iter = groups;
566 CcnetGroup *group;
567 int group_id;
568 GString *group_ids = g_string_new ("");
569
570 for (; iter; iter = iter->next) {
571 group = iter->data;
572 g_object_get (group, "id", &group_id, NULL);
573 g_string_append_printf (group_ids, "%d,", group_id);
574 }
575 group_ids = g_string_erase (group_ids, group_ids->len - 1, 1);
576
577 return group_ids;
578 }
579
580 GHashTable *
seaf_share_manager_get_shared_dirs_to_user(SeafShareManager * mgr,const char * orig_repo_id,const char * to_email)581 seaf_share_manager_get_shared_dirs_to_user (SeafShareManager *mgr,
582 const char *orig_repo_id,
583 const char *to_email)
584 {
585 GHashTable *dirs;
586 char *sql;
587
588 dirs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
589 sql = "SELECT v.path, s.permission FROM SharedRepo s, VirtualRepo v WHERE "
590 "s.repo_id = v.repo_id AND s.to_email = ? AND v.origin_repo = ?";
591
592 int ret = seaf_db_statement_foreach_row (mgr->seaf->db, sql, get_shared_dirs_to_user,
593 dirs, 2, "string", to_email,
594 "string", orig_repo_id);
595 if (ret < 0) {
596 seaf_warning ("Failed to get all shared folder perms "
597 "in parent repo %.8s for user %s.\n", orig_repo_id, to_email);
598 g_hash_table_destroy (dirs);
599 return NULL;
600 }
601
602 return dirs;
603 }
604
605 GHashTable *
seaf_share_manager_get_shared_dirs_to_group(SeafShareManager * mgr,const char * orig_repo_id,GList * groups)606 seaf_share_manager_get_shared_dirs_to_group (SeafShareManager *mgr,
607 const char *orig_repo_id,
608 GList *groups)
609 {
610 GHashTable *dirs;
611 GString *group_ids;
612 char *sql;
613
614 dirs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
615 group_ids = convert_group_list_to_str (groups);
616 sql = g_strdup_printf ("SELECT v.path, s.permission "
617 "FROM RepoGroup s, VirtualRepo v WHERE "
618 "s.repo_id = v.repo_id AND v.origin_repo = ? "
619 "AND s.group_id in (%s)", group_ids->str);
620
621 int ret = seaf_db_statement_foreach_row (mgr->seaf->db, sql, get_shared_dirs_to_group,
622 dirs, 1, "string", orig_repo_id);
623 g_free (sql);
624 g_string_free (group_ids, TRUE);
625
626 if (ret < 0) {
627 seaf_warning ("Failed to get all shared folder perm from parent repo %.8s "
628 "to all user groups.\n", orig_repo_id);
629 g_hash_table_destroy (dirs);
630 return NULL;
631 }
632
633 return dirs;
634 }
635
636 int
seaf_share_manager_remove_share(SeafShareManager * mgr,const char * repo_id,const char * from_email,const char * to_email)637 seaf_share_manager_remove_share (SeafShareManager *mgr, const char *repo_id,
638 const char *from_email, const char *to_email)
639 {
640 if (seaf_db_statement_query (mgr->seaf->db,
641 "DELETE FROM SharedRepo WHERE repo_id = ? AND from_email ="
642 " ? AND to_email = ?",
643 3, "string", repo_id, "string", from_email,
644 "string", to_email) < 0)
645 return -1;
646
647 return 0;
648 }
649
650 int
seaf_share_manager_unshare_subdir(SeafShareManager * mgr,const char * orig_repo_id,const char * path,const char * from_email,const char * to_email)651 seaf_share_manager_unshare_subdir (SeafShareManager* mgr,
652 const char *orig_repo_id,
653 const char *path,
654 const char *from_email,
655 const char *to_email)
656 {
657 if (seaf_db_statement_query (mgr->seaf->db,
658 "DELETE FROM SharedRepo WHERE "
659 "from_email = ? AND to_email = ? "
660 "AND repo_id IN "
661 "(SELECT repo_id FROM VirtualRepo WHERE "
662 "origin_repo = ? AND path = ?)",
663 4, "string", from_email,
664 "string", to_email,
665 "string", orig_repo_id,
666 "string", path) < 0)
667 return -1;
668
669 return 0;
670 }
671
672 int
seaf_share_manager_remove_repo(SeafShareManager * mgr,const char * repo_id)673 seaf_share_manager_remove_repo (SeafShareManager *mgr, const char *repo_id)
674 {
675 if (seaf_db_statement_query (mgr->seaf->db,
676 "DELETE FROM SharedRepo WHERE repo_id = ?",
677 1, "string", repo_id) < 0)
678 return -1;
679
680 return 0;
681 }
682
683 char *
seaf_share_manager_check_permission(SeafShareManager * mgr,const char * repo_id,const char * email)684 seaf_share_manager_check_permission (SeafShareManager *mgr,
685 const char *repo_id,
686 const char *email)
687 {
688 char *sql;
689
690 sql = "SELECT permission FROM SharedRepo WHERE repo_id=? AND to_email=?";
691 return seaf_db_statement_get_string (mgr->seaf->db, sql,
692 2, "string", repo_id, "string", email);
693 }
694
695 static gboolean
get_shared_sub_dirs(SeafDBRow * row,void * data)696 get_shared_sub_dirs (SeafDBRow *row, void *data)
697 {
698 GHashTable *sub_dirs = data;
699 int dummy;
700
701 const char *sub_dir = seaf_db_row_get_column_text (row, 0);
702 g_hash_table_replace (sub_dirs, g_strdup(sub_dir), &dummy);
703
704 return TRUE;
705 }
706
707 GHashTable *
seaf_share_manager_get_shared_sub_dirs(SeafShareManager * mgr,const char * repo_id,const char * path)708 seaf_share_manager_get_shared_sub_dirs (SeafShareManager *mgr,
709 const char *repo_id,
710 const char *path)
711 {
712 GHashTable *sub_dirs = g_hash_table_new_full (g_str_hash, g_str_equal,
713 g_free, NULL);
714 char *pattern;
715 if (strcmp (path, "/") == 0) {
716 pattern = g_strdup_printf("%s%%", path);
717 } else {
718 pattern = g_strdup_printf ("%s/%%", path);
719 }
720 int ret = seaf_db_statement_foreach_row (mgr->seaf->db,
721 "SELECT v.path FROM VirtualRepo v, SharedRepo s "
722 "WHERE v.repo_id = s.repo_id and "
723 "v.origin_repo = ? AND v.path LIKE ?",
724 get_shared_sub_dirs, sub_dirs,
725 2, "string", repo_id, "string", pattern);
726
727 if (ret < 0) {
728 g_free (pattern);
729 seaf_warning ("Failed to get shared sub dirs from db.\n");
730 g_hash_table_destroy (sub_dirs);
731 return NULL;
732 }
733
734 ret = seaf_db_statement_foreach_row (mgr->seaf->db,
735 "SELECT v.path FROM VirtualRepo v, RepoGroup r "
736 "WHERE v.repo_id = r.repo_id and "
737 "v.origin_repo = ? AND v.path LIKE ?",
738 get_shared_sub_dirs, sub_dirs,
739 2, "string", repo_id, "string", pattern);
740 g_free (pattern);
741
742 if (ret < 0) {
743 seaf_warning ("Failed to get shared sub dirs from db.\n");
744 g_hash_table_destroy (sub_dirs);
745 return NULL;
746 }
747
748 return sub_dirs;
749 }
750
751 int
seaf_share_manager_is_repo_shared(SeafShareManager * mgr,const char * repo_id)752 seaf_share_manager_is_repo_shared (SeafShareManager *mgr,
753 const char *repo_id)
754 {
755 gboolean ret;
756 gboolean db_err = FALSE;
757
758 ret = seaf_db_statement_exists (mgr->seaf->db,
759 "SELECT repo_id FROM SharedRepo WHERE "
760 "repo_id = ?", &db_err,
761 1, "string", repo_id);
762 if (db_err) {
763 seaf_warning ("DB error when check repo exist in SharedRepo.\n");
764 return -1;
765 }
766
767 if (!ret) {
768 ret = seaf_db_statement_exists (mgr->seaf->db,
769 "SELECT repo_id FROM RepoGroup WHERE "
770 "repo_id = ?", &db_err,
771 1, "string", repo_id);
772 if (db_err) {
773 seaf_warning ("DB error when check repo exist in RepoGroup.\n");
774 return -1;
775 }
776 }
777
778 return ret;
779 }
780
781 GObject *
seaf_get_shared_repo_by_path(SeafRepoManager * mgr,const char * repo_id,const char * path,const char * shared_to,int is_org,GError ** error)782 seaf_get_shared_repo_by_path (SeafRepoManager *mgr,
783 const char *repo_id,
784 const char *path,
785 const char *shared_to,
786 int is_org,
787 GError **error)
788 {
789 char *sql;
790 char *real_repo_id = NULL;
791 GList *repo = NULL;
792 GObject *ret = NULL;
793
794 /* If path is NULL, 'repo_id' represents for the repo we want,
795 * otherwise, 'repo_id' represents for the origin repo,
796 * find virtual repo by path first.
797 */
798 if (path != NULL) {
799 real_repo_id = seaf_repo_manager_get_virtual_repo_id (mgr, repo_id, path, NULL);
800 if (!real_repo_id) {
801 seaf_warning ("Failed to get virtual repo_id by path %s, origin_repo: %s\n", path, repo_id);
802 return NULL;
803 }
804 }
805 if (!real_repo_id)
806 real_repo_id = g_strdup (repo_id);
807
808 if (!is_org)
809 sql = "SELECT sh.repo_id, v.repo_id, "
810 "from_email, permission, commit_id, s.size, "
811 "v.origin_repo, v.path, i.name, "
812 "i.update_time, i.version, i.is_encrypted, i.last_modifier, i.status, "
813 "(SELECT name from RepoInfo WHERE repo_id=v.origin_repo) FROM "
814 "SharedRepo sh LEFT JOIN VirtualRepo v ON "
815 "sh.repo_id=v.repo_id "
816 "LEFT JOIN RepoSize s ON sh.repo_id = s.repo_id "
817 "LEFT JOIN RepoInfo i ON sh.repo_id = i.repo_id, Branch b "
818 "WHERE to_email=? AND "
819 "sh.repo_id = b.repo_id AND sh.repo_id=? AND "
820 "b.name = 'master' ";
821 else
822 sql = "SELECT sh.repo_id, v.repo_id, "
823 "from_email, permission, commit_id, s.size, "
824 "v.origin_repo, v.path, i.name, "
825 "i.update_time, i.version, i.is_encrypted, i.last_modifier, i.status, "
826 "(SELECT name from RepoInfo WHERE repo_id=v.origin_repo) FROM "
827 "OrgSharedRepo sh LEFT JOIN VirtualRepo v ON "
828 "sh.repo_id=v.repo_id "
829 "LEFT JOIN RepoSize s ON sh.repo_id = s.repo_id "
830 "LEFT JOIN RepoInfo i ON sh.repo_id = i.repo_id, Branch b "
831 "WHERE to_email=? AND "
832 "sh.repo_id = b.repo_id AND sh.repo_id=? AND "
833 "b.name = 'master' ";
834
835 /* The list 'repo' should have only one repo,
836 * use existing api collect_repos() to get it.
837 */
838 if (seaf_db_statement_foreach_row (mgr->seaf->db, sql,
839 collect_repos, &repo,
840 2, "string", shared_to, "string", real_repo_id) < 0) {
841 g_free (real_repo_id);
842 g_list_free (repo);
843 seaf_warning ("[share mgr] DB error when get shared repo "
844 "for %s, path:%s\n", shared_to, path);
845 return NULL;
846 }
847 g_free (real_repo_id);
848 if (repo) {
849 ret = (GObject *)(repo->data);
850 g_list_free (repo);
851 }
852
853 return ret;
854 }
855
856 int
seaf_share_manager_unshare_group_subdir(SeafShareManager * mgr,const char * repo_id,const char * path,const char * owner,int group_id)857 seaf_share_manager_unshare_group_subdir (SeafShareManager* mgr,
858 const char *repo_id,
859 const char *path,
860 const char *owner,
861 int group_id)
862 {
863 if (seaf_db_statement_query (mgr->seaf->db,
864 "DELETE FROM RepoGroup WHERE "
865 "user_name = ? AND group_id = ? "
866 "AND repo_id IN "
867 "(SELECT repo_id FROM VirtualRepo WHERE "
868 "origin_repo = ? AND path = ?)",
869 4, "string", owner,
870 "int", group_id,
871 "string", repo_id,
872 "string", path) < 0)
873 return -1;
874
875 return 0;
876 }
877
878 gboolean
seaf_share_manager_repo_has_been_shared(SeafShareManager * mgr,const char * repo_id,gboolean including_groups)879 seaf_share_manager_repo_has_been_shared (SeafShareManager* mgr,
880 const char *repo_id,
881 gboolean including_groups)
882 {
883 gboolean exists;
884 gboolean db_err = FALSE;
885 char *sql;
886
887 sql = "SELECT 1 FROM SharedRepo WHERE repo_id=?";
888 exists = seaf_db_statement_exists (mgr->seaf->db, sql, &db_err,
889 1, "string", repo_id);
890 if (db_err) {
891 seaf_warning ("DB error when check repo exist in SharedRepo and RepoGroup.\n");
892 return FALSE;
893 }
894
895 if (!exists && including_groups) {
896 sql = "SELECT 1 FROM RepoGroup WHERE repo_id=?";
897 exists = seaf_db_statement_exists (mgr->seaf->db, sql, &db_err,
898 1, "string", repo_id);
899 }
900
901 return exists;
902 }
903
904 gboolean
get_shared_users_cb(SeafDBRow * row,void * data)905 get_shared_users_cb (SeafDBRow *row, void *data)
906 {
907 GList **users = data;
908 const char *repo_id = seaf_db_row_get_column_text (row, 0);
909 const char *user = seaf_db_row_get_column_text (row, 1);
910 const char *perm = seaf_db_row_get_column_text (row, 2);
911 SeafileSharedUser *uobj = g_object_new (SEAFILE_TYPE_SHARED_USER,
912 "repo_id", repo_id,
913 "user", user,
914 "perm", perm,
915 NULL);
916 *users = g_list_append (*users, uobj);
917
918 return TRUE;
919 }
920
921 GList *
seaf_share_manager_org_get_shared_users_by_repo(SeafShareManager * mgr,int org_id,const char * repo_id)922 seaf_share_manager_org_get_shared_users_by_repo (SeafShareManager* mgr,
923 int org_id,
924 const char *repo_id)
925 {
926 GList *users = NULL;
927 char *sql = "SELECT repo_id, to_email, permission FROM OrgSharedRepo WHERE org_id=? AND "
928 "repo_id=?";
929
930 int ret = seaf_db_statement_foreach_row (mgr->seaf->db, sql,
931 get_shared_users_cb, &users,
932 2, "int", org_id, "string", repo_id);
933 if (ret < 0) {
934 seaf_warning("Failed to get users by repo_id[%s], org_id[%d]\n",
935 repo_id, org_id);
936 return NULL;
937 }
938
939 return users;
940 }
941
942
943 GList *
seaf_share_manager_get_shared_users_by_repo(SeafShareManager * mgr,const char * repo_id)944 seaf_share_manager_get_shared_users_by_repo(SeafShareManager* mgr,
945 const char *repo_id)
946 {
947 GList *users = NULL;
948 char *sql = "SELECT repo_id, to_email, permission FROM SharedRepo WHERE "
949 "repo_id=?";
950
951 int ret = seaf_db_statement_foreach_row (mgr->seaf->db, sql,
952 get_shared_users_cb, &users,
953 1, "string", repo_id);
954 if (ret < 0) {
955 seaf_warning("Failed to get users by repo_id[%s]\n", repo_id);
956 return NULL;
957 }
958
959 return users;
960 }
961