1 #include <jansson.h>
2 
3 #include <QScopedPointer>
4 #include <QtNetwork>
5 
6 #include "account.h"
7 
8 #include "api-error.h"
9 #include "commit-details.h"
10 #include "event.h"
11 #include "repo-service.h"
12 #include "rpc/rpc-client.h"
13 #include "seafile-applet.h"
14 #include "server-repo.h"
15 #include "starred-file.h"
16 #include "utils/api-utils.h"
17 #include "utils/json-utils.h"
18 #include "utils/utils.h"
19 #include "account-mgr.h"
20 
21 #include "requests.h"
22 
23 namespace
24 {
25 const char* kApiPingUrl = "api2/ping/";
26 const char* kApiLoginUrl = "api2/auth-token/";
27 const char* kListReposUrl = "api2/repos/";
28 const char* kCreateRepoUrl = "api2/repos/";
29 const char* kGetRepoUrl = "api2/repos/%1/";
30 const char* kCreateSubrepoUrl = "api2/repos/%1/dir/sub_repo/";
31 const char* kUnseenMessagesUrl = "api2/unseen_messages/";
32 const char* kDefaultRepoUrl = "api2/default-repo/";
33 const char* kStarredFilesUrl = "api2/starredfiles/";
34 const char* kStarredItemsUrl = "api/v2.1/starred-items/";
35 const char* kGetEventsUrl = "api2/events/";
36 const char* kCommitDetailsUrl = "api2/repo_history_changes/";
37 const char* kAvatarUrl = "api2/avatars/user/";
38 const char* kSetRepoPasswordUrl = "api2/repos/";
39 const char* kServerInfoUrl = "api2/server-info/";
40 const char* kLogoutDeviceUrl = "api2/logout-device/";
41 const char* kGetRepoTokensUrl = "api2/repo-tokens/";
42 const char* kGetLoginTokenUrl = "api2/client-login/";
43 const char* kFileSearchUrl = "api2/search/";
44 const char* kAccountInfoUrl = "api2/account/info/";
45 const char* kDirSharedItemsUrl = "api2/repos/%1/dir/shared_items/";
46 const char* kRepoSharedUrl = "api2/beshared-repos/%1/";
47 const char* kFetchGroupsAndContactsUrl = "api2/groupandcontacts/";
48 const char* kFetchGroupsUrl = "api2/groups/";
49 const char* kRemoteWipeReportUrl = "api2/device-wiped/";
50 const char* kSearchUsersUrl = "api2/search-user/";
51 const char* kGetThumbnailUrl = "api2/repos/%1/thumbnail/";
52 const char* kCreateFileUploadLink = "api/v2.1/upload-links/";
53 
54 const char* kGetFileActivitiesUrl = "api/v2.1/activities/";
55 } // namespace
56 
57 
PingServerRequest(const QUrl & serverAddr)58 PingServerRequest::PingServerRequest(const QUrl& serverAddr)
59 
60     : SeafileApiRequest(::urlJoin(serverAddr, kApiPingUrl),
61                         SeafileApiRequest::METHOD_GET)
62 {
63 }
64 
requestSuccess(QNetworkReply & reply)65 void PingServerRequest::requestSuccess(QNetworkReply& reply)
66 {
67     emit success();
68 }
69 
70 /**
71  * LoginRequest
72  */
LoginRequest(const QUrl & serverAddr,const QString & username,const QString & password,const QString & computer_name)73 LoginRequest::LoginRequest(const QUrl& serverAddr,
74                            const QString& username,
75                            const QString& password,
76                            const QString& computer_name)
77 
78     : SeafileApiRequest(::urlJoin(serverAddr, kApiLoginUrl),
79                         SeafileApiRequest::METHOD_POST)
80 {
81     setFormParam("username", username);
82     setFormParam("password", password);
83 
84     QHash<QString, QString> params = ::getSeafileLoginParams(computer_name);
85     foreach (const QString& key, params.keys()) {
86         setFormParam(key, params[key]);
87     }
88 }
89 
requestSuccess(QNetworkReply & reply)90 void LoginRequest::requestSuccess(QNetworkReply& reply)
91 {
92     json_error_t error;
93     json_t* root = parseJSON(reply, &error);
94     if (!root) {
95         qWarning("failed to parse json:%s\n", error.text);
96         emit failed(ApiError::fromJsonError());
97         return;
98     }
99 
100     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
101 
102     QString s2fa_token = reply.rawHeader("X-SEAFILE-S2FA");
103     const char* token =
104         json_string_value(json_object_get(json.data(), "token"));
105     if (token == NULL) {
106         qWarning("failed to parse json:%s\n", error.text);
107         emit failed(ApiError::fromJsonError());
108         return;
109     }
110 
111     emit success(token, s2fa_token);
112 }
113 
114 
115 /**
116  * ListReposRequest
117  */
ListReposRequest(const Account & account)118 ListReposRequest::ListReposRequest(const Account& account)
119     : SeafileApiRequest(account.getAbsoluteUrl(kListReposUrl),
120                         SeafileApiRequest::METHOD_GET,
121                         account.token)
122 {
123 }
124 
requestSuccess(QNetworkReply & reply)125 void ListReposRequest::requestSuccess(QNetworkReply& reply)
126 {
127     json_error_t error;
128     json_t* root = parseJSON(reply, &error);
129     if (!root) {
130         qWarning("ListReposRequest:failed to parse json:%s\n", error.text);
131         emit failed(ApiError::fromJsonError());
132         return;
133     }
134 
135     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
136 
137     std::vector<ServerRepo> repos =
138         ServerRepo::listFromJSON(json.data(), &error);
139     emit success(repos);
140 }
141 
142 
143 /**
144  * DownloadRepoRequest
145  */
DownloadRepoRequest(const Account & account,const QString & repo_id,bool read_only)146 DownloadRepoRequest::DownloadRepoRequest(const Account& account,
147                                          const QString& repo_id,
148                                          bool read_only)
149     : SeafileApiRequest(
150           account.getAbsoluteUrl("api2/repos/" + repo_id + "/download-info/"),
151           SeafileApiRequest::METHOD_GET,
152           account.token),
153       read_only_(read_only)
154 {
155 }
156 
fromDict(QMap<QString,QVariant> & dict,const QUrl & url_in,bool read_only)157 RepoDownloadInfo RepoDownloadInfo::fromDict(QMap<QString, QVariant>& dict,
158                                             const QUrl& url_in,
159                                             bool read_only)
160 {
161     RepoDownloadInfo info;
162     info.repo_version = dict["repo_version"].toInt();
163     info.email = dict["email"].toString();
164     info.token = dict["token"].toString();
165     info.repo_id = dict["repo_id"].toString();
166     info.repo_name = dict["repo_name"].toString();
167     info.encrypted = dict["encrypted"].toInt();
168     info.magic = dict["magic"].toString();
169     info.random_key = dict["random_key"].toString();
170     info.enc_version = dict.value("enc_version", 1).toInt();
171     info.readonly = read_only;
172 
173     QUrl url = url_in;
174     url.setPath("/");
175 
176     QString salt = dict.value("salt").toString();
177     QMap<QString, QVariant> map;
178     map.insert("is_readonly", read_only ? 1 : 0);
179     map.insert("server_url", url.toString());
180     map.insert("repo_salt", salt);
181 
182     info.more_info = ::mapToJson(map);
183 
184     return info;
185 }
186 
requestSuccess(QNetworkReply & reply)187 void DownloadRepoRequest::requestSuccess(QNetworkReply& reply)
188 {
189     json_error_t error;
190     json_t* root = parseJSON(reply, &error);
191     if (!root) {
192         qWarning("failed to parse json:%s\n", error.text);
193         emit failed(ApiError::fromJsonError());
194         return;
195     }
196 
197     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
198     QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
199 
200     RepoDownloadInfo info = RepoDownloadInfo::fromDict(dict, url(), read_only_);
201 
202     emit success(info);
203 }
204 
205 /**
206  * GetRepoRequest
207  */
GetRepoRequest(const Account & account,const QString & repoid)208 GetRepoRequest::GetRepoRequest(const Account& account, const QString& repoid)
209     : SeafileApiRequest(
210           account.getAbsoluteUrl(QString(kGetRepoUrl).arg(repoid)),
211           SeafileApiRequest::METHOD_GET,
212           account.token),
213       repoid_(repoid)
214 {
215 }
216 
requestSuccess(QNetworkReply & reply)217 void GetRepoRequest::requestSuccess(QNetworkReply& reply)
218 {
219     json_error_t error;
220     json_t* root = parseJSON(reply, &error);
221     if (!root) {
222         qWarning("failed to parse json:%s\n", error.text);
223         emit failed(ApiError::fromJsonError());
224         return;
225     }
226 
227     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
228     QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
229     ServerRepo repo = ServerRepo::fromJSON(root, &error);
230 
231     emit success(repo);
232 }
233 
234 /**
235  * CreateRepoRequest
236  */
CreateRepoRequest(const Account & account,const QString & name,const QString & desc,const QString & passwd)237 CreateRepoRequest::CreateRepoRequest(const Account& account,
238                                      const QString& name,
239                                      const QString& desc,
240                                      const QString& passwd)
241     : SeafileApiRequest(account.getAbsoluteUrl(kCreateRepoUrl),
242                         SeafileApiRequest::METHOD_POST,
243                         account.token)
244 {
245     setFormParam(QString("name"), name);
246     setFormParam(QString("desc"), desc);
247     if (!passwd.isNull()) {
248         qWarning("Encrypted repo");
249         setFormParam(QString("passwd"), passwd);
250     }
251 }
252 
CreateRepoRequest(const Account & account,const QString & name,const QString & desc,int enc_version,const QString & repo_id,const QString & magic,const QString & random_key)253 CreateRepoRequest::CreateRepoRequest(const Account& account,
254                                      const QString& name,
255                                      const QString& desc,
256                                      int enc_version,
257                                      const QString& repo_id,
258                                      const QString& magic,
259                                      const QString& random_key)
260     : SeafileApiRequest(account.getAbsoluteUrl(kCreateRepoUrl),
261                         SeafileApiRequest::METHOD_POST,
262                         account.token)
263 {
264     setFormParam("name", name);
265     setFormParam("desc", desc);
266     setFormParam("enc_version", QString::number(enc_version));
267     setFormParam("repo_id", repo_id);
268     setFormParam("magic", magic);
269     setFormParam("random_key", random_key);
270 }
271 
CreateRepoRequest(const Account & account,const QString & name,const QString & desc,int enc_version,const QString & repo_id,const QString & magic,const QString & random_key,const QString & salt)272 CreateRepoRequest::CreateRepoRequest(const Account& account,
273                                      const QString& name,
274                                      const QString& desc,
275                                      int enc_version,
276                                      const QString& repo_id,
277                                      const QString& magic,
278                                      const QString& random_key,
279                                      const QString& salt)
280     : SeafileApiRequest(account.getAbsoluteUrl(kCreateRepoUrl),
281                         SeafileApiRequest::METHOD_POST,
282                         account.token)
283 {
284     setFormParam("name", name);
285     setFormParam("desc", desc);
286     setFormParam("enc_version", QString::number(enc_version));
287     setFormParam("repo_id", repo_id);
288     setFormParam("magic", magic);
289     setFormParam("random_key", random_key);
290     setFormParam("salt", salt);
291 }
292 
requestSuccess(QNetworkReply & reply)293 void CreateRepoRequest::requestSuccess(QNetworkReply& reply)
294 {
295     json_error_t error;
296     json_t* root = parseJSON(reply, &error);
297     if (!root) {
298         qWarning("failed to parse json:%s\n", error.text);
299         emit failed(ApiError::fromJsonError());
300         return;
301     }
302 
303     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
304     QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
305     RepoDownloadInfo info = RepoDownloadInfo::fromDict(dict, url(), false);
306 
307     emit success(info);
308 }
309 
310 /**
311  * CreateSubrepoRequest
312  */
CreateSubrepoRequest(const Account & account,const QString & name,const QString & repoid,const QString & path,const QString & passwd)313 CreateSubrepoRequest::CreateSubrepoRequest(const Account& account,
314                                            const QString& name,
315                                            const QString& repoid,
316                                            const QString& path,
317                                            const QString& passwd)
318     : SeafileApiRequest(
319           account.getAbsoluteUrl(QString(kCreateSubrepoUrl).arg(repoid)),
320           SeafileApiRequest::METHOD_GET,
321           account.token)
322 {
323     setUrlParam(QString("p"), path);
324     setUrlParam(QString("name"), name);
325     if (!passwd.isNull()) {
326         setUrlParam(QString("password"), passwd);
327     }
328 }
329 
requestSuccess(QNetworkReply & reply)330 void CreateSubrepoRequest::requestSuccess(QNetworkReply& reply)
331 {
332     json_error_t error;
333     json_t* root = parseJSON(reply, &error);
334     if (!root) {
335         qWarning("failed to parse json:%s\n", error.text);
336         emit failed(ApiError::fromJsonError());
337         return;
338     }
339 
340     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
341     QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
342 
343     emit success(dict["sub_repo_id"].toString());
344 }
345 
346 /**
347  * GetUnseenSeahubNotificationsRequest
348  */
GetUnseenSeahubNotificationsRequest(const Account & account)349 GetUnseenSeahubNotificationsRequest::GetUnseenSeahubNotificationsRequest(
350     const Account& account)
351     : SeafileApiRequest(account.getAbsoluteUrl(kUnseenMessagesUrl),
352                         SeafileApiRequest::METHOD_GET,
353                         account.token)
354 {
355 }
356 
requestSuccess(QNetworkReply & reply)357 void GetUnseenSeahubNotificationsRequest::requestSuccess(QNetworkReply& reply)
358 {
359     json_error_t error;
360     json_t* root = parseJSON(reply, &error);
361     if (!root) {
362         qWarning(
363             "GetUnseenSeahubNotificationsRequest: failed to parse json:%s\n",
364             error.text);
365         emit failed(ApiError::fromJsonError());
366         return;
367     }
368 
369     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
370 
371     QMap<QString, QVariant> ret = mapFromJSON(root, &error);
372 
373     if (!ret.contains("count")) {
374         emit failed(ApiError::fromJsonError());
375         return;
376     }
377 
378     int count = ret.value("count").toInt();
379     emit success(count);
380 }
381 
GetDefaultRepoRequest(const Account & account)382 GetDefaultRepoRequest::GetDefaultRepoRequest(const Account& account)
383     : SeafileApiRequest(account.getAbsoluteUrl(kDefaultRepoUrl),
384                         SeafileApiRequest::METHOD_GET,
385                         account.token)
386 {
387 }
388 
requestSuccess(QNetworkReply & reply)389 void GetDefaultRepoRequest::requestSuccess(QNetworkReply& reply)
390 {
391     json_error_t error;
392     json_t* root = parseJSON(reply, &error);
393     if (!root) {
394         qWarning("CreateDefaultRepoRequest: failed to parse json:%s\n",
395                  error.text);
396         emit failed(ApiError::fromJsonError());
397         return;
398     }
399 
400     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
401 
402     QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
403 
404     if (!dict.contains("exists")) {
405         emit failed(ApiError::fromJsonError());
406         return;
407     }
408 
409     bool exists = dict.value("exists").toBool();
410     if (!exists) {
411         emit success(false, "");
412         return;
413     }
414 
415     if (!dict.contains("repo_id")) {
416         emit failed(ApiError::fromJsonError());
417         return;
418     }
419 
420     QString repo_id = dict.value("repo_id").toString();
421 
422     emit success(true, repo_id);
423 }
424 
425 
CreateDefaultRepoRequest(const Account & account)426 CreateDefaultRepoRequest::CreateDefaultRepoRequest(const Account& account)
427     : SeafileApiRequest(account.getAbsoluteUrl(kDefaultRepoUrl),
428                         SeafileApiRequest::METHOD_POST,
429                         account.token)
430 {
431 }
432 
requestSuccess(QNetworkReply & reply)433 void CreateDefaultRepoRequest::requestSuccess(QNetworkReply& reply)
434 {
435     json_error_t error;
436     json_t* root = parseJSON(reply, &error);
437     if (!root) {
438         qWarning("CreateDefaultRepoRequest: failed to parse json:%s\n",
439                  error.text);
440         emit failed(ApiError::fromJsonError());
441         return;
442     }
443 
444     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
445 
446     QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
447 
448     if (!dict.contains("repo_id")) {
449         emit failed(ApiError::fromJsonError());
450         return;
451     }
452 
453     emit success(dict.value("repo_id").toString());
454 }
455 
GetStarredFilesRequest(const Account & account)456 GetStarredFilesRequest::GetStarredFilesRequest(const Account& account)
457     : SeafileApiRequest(account.getAbsoluteUrl(kStarredFilesUrl),
458                         SeafileApiRequest::METHOD_GET,
459                         account.token)
460 {
461 }
462 
requestSuccess(QNetworkReply & reply)463 void GetStarredFilesRequest::requestSuccess(QNetworkReply& reply)
464 {
465     json_error_t error;
466     json_t* root = parseJSON(reply, &error);
467     if (!root) {
468         qWarning("GetStarredFilesRequest: failed to parse json:%s\n",
469                  error.text);
470         emit failed(ApiError::fromJsonError());
471         return;
472     }
473 
474     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
475 
476     std::vector<StarredItem> files =
477         StarredItem::listFromJSON(json.data(), &error);
478     emit success(files);
479 }
480 
GetStarredFilesRequestV2(const Account & account)481 GetStarredFilesRequestV2::GetStarredFilesRequestV2(const Account& account)
482         : SeafileApiRequest(account.getAbsoluteUrl(kStarredItemsUrl),
483                             SeafileApiRequest::METHOD_GET,
484                             account.token)
485 {
486 }
487 
requestSuccess(QNetworkReply & reply)488 void GetStarredFilesRequestV2::requestSuccess(QNetworkReply& reply)
489 {
490     json_error_t error;
491     json_t* root = parseJSON(reply, &error);
492     if (!root) {
493         qWarning("GetStarredItemsRequest: failed to parse json:%s\n",
494                  error.text);
495         emit failed(ApiError::fromJsonError());
496         return;
497     }
498 
499     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
500     json_t* array = json_object_get(json.data(), "starred_item_list");
501     std::vector<StarredItem> files =
502             StarredItem::listFromJSON(array, &error, true);
503     emit success(files);
504 }
505 
506 // Seafile get file activities api v2.1
507 // page default value is 1
508 // perpage defult value is 25
509 // avatar size defult value is 72, old api is 36
GetEventsRequestV2(const Account & account,int page,int perpage,int avatar_size)510 GetEventsRequestV2::GetEventsRequestV2(const Account& account, int page, int perpage, int avatar_size)
511     : SeafileApiRequest(account.getAbsoluteUrl(kGetFileActivitiesUrl),
512                         SeafileApiRequest::METHOD_GET,
513                         account.token)
514 {
515     setUrlParam("page", QString::number(page));
516     setUrlParam("avatar_size", QString::number(avatar_size));
517 }
518 
requestSuccess(QNetworkReply & reply)519 void GetEventsRequestV2::requestSuccess(QNetworkReply& reply)
520 {
521     json_error_t error;
522     json_t* root = parseJSON(reply, &error);
523     if (!root) {
524         qWarning("GetEventsRequestV2: failed to parse json:%s\n", error.text);
525         emit failed(ApiError::fromJsonError());
526         return;
527     }
528 
529     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
530 
531     json_t* array = json_object_get(json.data(), "events");
532     std::vector<SeafEvent> events = SeafEvent::listFromJSON(array, &error, true);
533 
534     emit success(events);
535 }
536 
GetEventsRequest(const Account & account,int start)537 GetEventsRequest::GetEventsRequest(const Account& account, int start)
538     : SeafileApiRequest(account.getAbsoluteUrl(kGetEventsUrl),
539                         SeafileApiRequest::METHOD_GET,
540                         account.token)
541 {
542     if (start > 0) {
543         setUrlParam("start", QString::number(start));
544     }
545 }
546 
requestSuccess(QNetworkReply & reply)547 void GetEventsRequest::requestSuccess(QNetworkReply& reply)
548 {
549     json_error_t error;
550     json_t* root = parseJSON(reply, &error);
551     if (!root) {
552         qWarning("GetEventsRequest: failed to parse json:%s\n", error.text);
553         emit failed(ApiError::fromJsonError());
554         return;
555     }
556 
557     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
558 
559     bool more = false;
560     int more_offset = -1;
561 
562     json_t* array = json_object_get(json.data(), "events");
563     std::vector<SeafEvent> events = SeafEvent::listFromJSON(array, &error);
564 
565     more = json_is_true(json_object_get(json.data(), "more"));
566     if (more) {
567         more_offset =
568             json_integer_value(json_object_get(json.data(), "more_offset"));
569     }
570 
571     emit success(events, more_offset);
572 }
573 
GetCommitDetailsRequest(const Account & account,const QString & repo_id,const QString & commit_id)574 GetCommitDetailsRequest::GetCommitDetailsRequest(const Account& account,
575                                                  const QString& repo_id,
576                                                  const QString& commit_id)
577     : SeafileApiRequest(
578           account.getAbsoluteUrl(kCommitDetailsUrl + repo_id + "/"),
579           SeafileApiRequest::METHOD_GET,
580           account.token)
581 {
582     setUrlParam("commit_id", commit_id);
583 }
584 
requestSuccess(QNetworkReply & reply)585 void GetCommitDetailsRequest::requestSuccess(QNetworkReply& reply)
586 {
587     json_error_t error;
588     json_t* root = parseJSON(reply, &error);
589     if (!root) {
590         qWarning("GetCommitDetailsRequest: failed to parse json:%s\n",
591                  error.text);
592         emit failed(ApiError::fromJsonError());
593         return;
594     }
595 
596     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
597 
598     CommitDetails details = CommitDetails::fromJSON(json.data(), &error);
599 
600     emit success(details);
601 }
602 
603 // /api2/user/foo@foo.com/resized/36
GetAvatarRequest(const Account & account,const QString & email,qint64 mtime,int size)604 GetAvatarRequest::GetAvatarRequest(const Account& account,
605                                    const QString& email,
606                                    qint64 mtime,
607                                    int size)
608     : SeafileApiRequest(
609           account.getAbsoluteUrl(kAvatarUrl + email + "/resized/" +
610                                  QString::number(size) + "/"),
611           SeafileApiRequest::METHOD_GET,
612           account.token),
613       fetch_img_req_(NULL),
614       mtime_(mtime)
615 {
616     account_ = account;
617     email_ = email;
618 }
619 
~GetAvatarRequest()620 GetAvatarRequest::~GetAvatarRequest()
621 {
622     if (fetch_img_req_) {
623         fetch_img_req_->deleteLater();
624         fetch_img_req_ = nullptr;
625     }
626 }
627 
requestSuccess(QNetworkReply & reply)628 void GetAvatarRequest::requestSuccess(QNetworkReply& reply)
629 {
630     json_error_t error;
631     json_t* root = parseJSON(reply, &error);
632     if (!root) {
633         qWarning("GetAvatarRequest: failed to parse json:%s\n", error.text);
634         emit failed(ApiError::fromJsonError());
635         return;
636     }
637 
638     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
639 
640     const char* avatar_url =
641         json_string_value(json_object_get(json.data(), "url"));
642 
643     // we don't need to fetch all images if we have latest one
644     json_t* mtime = json_object_get(json.data(), "mtime");
645     if (!mtime) {
646         qWarning("GetAvatarRequest: no 'mtime' value in response\n");
647     }
648     else {
649         qint64 new_mtime = json_integer_value(mtime);
650         // When mtime_ < 0 it means there is no local cache yet
651         if (mtime_ >= 0 && new_mtime == mtime_) {
652             emit success(QImage());
653             return;
654         }
655         mtime_ = new_mtime;
656     }
657 
658     if (!avatar_url) {
659         qWarning("GetAvatarRequest: no 'url' value in response\n");
660         emit failed(ApiError::fromJsonError());
661         return;
662     }
663 
664     QString url = QUrl::fromPercentEncoding(avatar_url);
665 
666     fetch_img_req_ = new FetchImageRequest(url);
667 
668     connect(fetch_img_req_, SIGNAL(failed(const ApiError&)), this,
669             SIGNAL(failed(const ApiError&)));
670     connect(fetch_img_req_, SIGNAL(success(const QImage&)), this,
671             SIGNAL(success(const QImage&)));
672     fetch_img_req_->send();
673 }
674 
FetchImageRequest(const QString & img_url)675 FetchImageRequest::FetchImageRequest(const QString& img_url)
676     : SeafileApiRequest(QUrl(img_url), SeafileApiRequest::METHOD_GET)
677 {
678 }
679 
requestSuccess(QNetworkReply & reply)680 void FetchImageRequest::requestSuccess(QNetworkReply& reply)
681 {
682     QImage img;
683     img.loadFromData(reply.readAll());
684 
685     if (img.isNull()) {
686         qWarning("FetchImageRequest: invalid image data\n");
687         emit failed(ApiError::fromHttpError(400));
688     }
689     else {
690         emit success(img);
691     }
692 }
693 
SetRepoPasswordRequest(const Account & account,const QString & repo_id,const QString & password)694 SetRepoPasswordRequest::SetRepoPasswordRequest(const Account& account,
695                                                const QString& repo_id,
696                                                const QString& password)
697     : SeafileApiRequest(
698           account.getAbsoluteUrl(kSetRepoPasswordUrl + repo_id + "/"),
699           SeafileApiRequest::METHOD_POST,
700           account.token)
701 {
702     setFormParam("password", password);
703 }
704 
requestSuccess(QNetworkReply & reply)705 void SetRepoPasswordRequest::requestSuccess(QNetworkReply& reply)
706 {
707     emit success();
708 }
709 
ServerInfoRequest(const Account & account)710 ServerInfoRequest::ServerInfoRequest(const Account& account)
711     : SeafileApiRequest(account.getAbsoluteUrl(kServerInfoUrl),
712                         SeafileApiRequest::METHOD_GET,
713                         account.token),
714       account_(account)
715 {
716 }
717 
requestSuccess(QNetworkReply & reply)718 void ServerInfoRequest::requestSuccess(QNetworkReply& reply)
719 {
720     json_error_t error;
721     json_t* root = parseJSON(reply, &error);
722     if (!root) {
723         qWarning("failed to parse json:%s\n", error.text);
724         emit failed(ApiError::fromJsonError());
725         return;
726     }
727     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
728 
729     QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
730 
731     ServerInfo ret;
732 
733     if (dict.contains("version")) {
734         ret.parseVersionFromString(dict["version"].toString());
735     }
736 
737     if (dict.contains("encrypted_library_version")) {
738         ret.parseEncryptedLibraryVersionFromString(dict["encrypted_library_version"].toString());
739     }
740 
741     if (dict.contains("features")) {
742         ret.parseFeatureFromStrings(dict["features"].toStringList());
743     }
744 
745     if (dict.contains("desktop-custom-logo")) {
746         ret.customLogo = dict["desktop-custom-logo"].toString();
747     }
748 
749     if (dict.contains("desktop-custom-brand")) {
750         ret.customBrand = dict["desktop-custom-brand"].toString();
751     }
752 
753     emit success(account_, ret);
754 }
755 
LogoutDeviceRequest(const Account & account)756 LogoutDeviceRequest::LogoutDeviceRequest(const Account& account)
757     : SeafileApiRequest(account.getAbsoluteUrl(kLogoutDeviceUrl),
758                         SeafileApiRequest::METHOD_POST,
759                         account.token),
760       account_(account)
761 {
762 }
763 
requestSuccess(QNetworkReply & reply)764 void LogoutDeviceRequest::requestSuccess(QNetworkReply& reply)
765 {
766     emit success();
767 }
768 
GetRepoTokensRequest(const Account & account,const QStringList & repo_ids,int max_retries,int batch_size)769 GetRepoTokensRequest::GetRepoTokensRequest(const Account& account,
770                                            const QStringList& repo_ids,
771                                            int max_retries,
772                                            int batch_size)
773     : SeafileApiRequest(account.getAbsoluteUrl(kGetRepoTokensUrl),
774                         SeafileApiRequest::METHOD_GET,
775                         account.token),
776       account_(account),
777       repo_ids_(repo_ids),
778       max_retries_(max_retries),
779       batch_offset_(0),
780       batch_size_(batch_size)
781 {
782 }
783 
send()784 void GetRepoTokensRequest::send()
785 {
786     doNextBatch();
787 }
788 
doNextBatch()789 void GetRepoTokensRequest::doNextBatch()
790 {
791     if (batch_offset_ >= repo_ids_.size()) {
792         emit success();
793         return;
794     }
795 
796     int count;
797     count = qMin(batch_size_, repo_ids_.size() - batch_offset_);
798     batch_req_.reset(new SingleBatchRepoTokensRequest(
799         account_, repo_ids_.mid(batch_offset_, count)));
800 
801     connect(batch_req_.data(),
802             SIGNAL(failed(const ApiError &)),
803             this,
804             SIGNAL(failed(const ApiError &)));
805     connect(batch_req_.data(), SIGNAL(success()), this, SLOT(batchSuccess()));
806     batch_req_->send();
807 
808     // printf("sending request for one batch: offset = %d, count = %d\n",
809     //        batch_offset_,
810     //        count);
811 }
812 
batchSuccess()813 void GetRepoTokensRequest::batchSuccess()
814 {
815     const QMap<QString, QString>& tokens = batch_req_->repoTokens();
816 
817     // printf ("one batch finished, offset = %d, count = %d\n", batch_offset_, tokens.size());
818 
819     repo_tokens_.unite(tokens);
820     batch_offset_ += batch_req_->repoIds().size();
821     doNextBatch();
822 }
823 
requestSuccess(QNetworkReply & reply)824 void GetRepoTokensRequest::requestSuccess(QNetworkReply& reply)
825 {
826     // Just a place holder. A `GetRepoTokensRequest` is a wrapper around a
827     // series of `SingleBatchRepoTokensRequest`, which really sends the api
828     // requests.
829 }
830 
SingleBatchRepoTokensRequest(const Account & account,const QStringList & repo_ids)831 SingleBatchRepoTokensRequest::SingleBatchRepoTokensRequest(const Account& account,
832                                            const QStringList& repo_ids)
833     : SeafileApiRequest(account.getAbsoluteUrl(kGetRepoTokensUrl),
834                         SeafileApiRequest::METHOD_GET,
835                         account.token),
836       repo_ids_(repo_ids)
837 {
838     setUrlParam("repos", repo_ids.join(","));
839 }
840 
requestSuccess(QNetworkReply & reply)841 void SingleBatchRepoTokensRequest::requestSuccess(QNetworkReply& reply)
842 {
843     json_error_t error;
844     json_t* root = parseJSON(reply, &error);
845     if (!root) {
846         qWarning("SingleBatchRepoTokensRequest: failed to parse json:%s\n", error.text);
847         emit failed(ApiError::fromJsonError());
848         return;
849     }
850 
851     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
852 
853     QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
854     foreach (const QString& repo_id, dict.keys()) {
855         repo_tokens_[repo_id] = dict[repo_id].toString();
856     }
857 
858     emit success();
859 }
860 
GetLoginTokenRequest(const Account & account,const QString & next_url)861 GetLoginTokenRequest::GetLoginTokenRequest(const Account& account,
862                                            const QString& next_url)
863     : SeafileApiRequest(account.getAbsoluteUrl(kGetLoginTokenUrl),
864                         SeafileApiRequest::METHOD_POST,
865                         account.token),
866       account_(account),
867       next_url_(next_url)
868 {
869 }
870 
requestSuccess(QNetworkReply & reply)871 void GetLoginTokenRequest::requestSuccess(QNetworkReply& reply)
872 {
873     json_error_t error;
874     json_t* root = parseJSON(reply, &error);
875     if (!root) {
876         qWarning("GetLoginTokenRequest: failed to parse json:%s\n", error.text);
877         emit failed(ApiError::fromJsonError());
878         return;
879     }
880 
881     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
882 
883     QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
884     if (!dict.contains("token")) {
885         emit failed(ApiError::fromJsonError());
886         return;
887     }
888     emit success(dict["token"].toString());
889 }
890 
FileSearchRequest(const Account & account,const QString & keyword,int page,int per_page,const QString & repo_id)891 FileSearchRequest::FileSearchRequest(const Account& account,
892                                      const QString& keyword,
893                                      int page,
894                                      int per_page,
895                                      const QString& repo_id)
896     : SeafileApiRequest(account.getAbsoluteUrl(kFileSearchUrl),
897                         SeafileApiRequest::METHOD_GET,
898                         account.token),
899       keyword_(keyword),
900       page_(page)
901 {
902     setUrlParam("q", keyword_);
903     if (page > 0) {
904         setUrlParam("page", QString::number(page));
905     }
906     // per_page = 2;
907     setUrlParam("per_page", QString::number(per_page));
908     if (!repo_id.isEmpty()) {
909         setUrlParam("search_repo", repo_id);
910     }
911 }
912 
requestSuccess(QNetworkReply & reply)913 void FileSearchRequest::requestSuccess(QNetworkReply& reply)
914 {
915     json_error_t error;
916     json_t* root = parseJSON(reply, &error);
917     if (!root) {
918         qWarning("FileSearchResult: failed to parse json:%s\n", error.text);
919         emit failed(ApiError::fromJsonError());
920         return;
921     }
922     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
923     QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
924     if (!dict.contains("results")) {
925         emit failed(ApiError::fromJsonError());
926         return;
927     }
928     QList<QVariant> results = dict["results"].toList();
929     std::vector<FileSearchResult> retval;
930     Q_FOREACH(const QVariant& result, results)
931     {
932         FileSearchResult tmp;
933         QMap<QString, QVariant> map = result.toMap();
934         if (map.empty())
935             continue;
936         tmp.repo_id = map["repo_id"].toString();
937         tmp.repo_name = RepoService::instance()->getRepo(tmp.repo_id).name;
938         tmp.name = map["name"].toString();
939         tmp.oid = map["oid"].toString();
940         tmp.last_modified = map["last_modified"].toLongLong();
941         tmp.fullpath = map["fullpath"].toString();
942         tmp.size = map["size"].toLongLong();
943         tmp.is_dir = map["is_dir"].toBool();
944         retval.push_back(tmp);
945     }
946     bool has_more = dict["has_more"].toBool();
947     bool is_loading_more = page_ > 1;
948 
949     emit success(retval, is_loading_more, has_more);
950 }
951 
FetchCustomLogoRequest(const QUrl & url)952 FetchCustomLogoRequest::FetchCustomLogoRequest(const QUrl& url)
953     : SeafileApiRequest(url, SeafileApiRequest::METHOD_GET)
954 {
955     setUseCache(true);
956 }
957 
requestSuccess(QNetworkReply & reply)958 void FetchCustomLogoRequest::requestSuccess(QNetworkReply& reply)
959 {
960     QPixmap logo;
961     logo.loadFromData(reply.readAll());
962 
963     if (logo.isNull()) {
964         qWarning("FetchCustomLogoRequest: invalid image data\n");
965         emit failed(ApiError::fromHttpError(400));
966     }
967     else {
968         emit success(url());
969     }
970 }
971 
FetchAccountInfoRequest(const Account & account)972 FetchAccountInfoRequest::FetchAccountInfoRequest(const Account& account)
973     : SeafileApiRequest(account.getAbsoluteUrl(kAccountInfoUrl),
974                         SeafileApiRequest::METHOD_GET,
975                         account.token)
976 {
977     account_ = account;
978 }
979 
requestSuccess(QNetworkReply & reply)980 void FetchAccountInfoRequest::requestSuccess(QNetworkReply& reply)
981 {
982     json_error_t error;
983     json_t* root = parseJSON(reply, &error);
984     if (!root) {
985         qWarning("FetchAccountInfoRequest: failed to parse json:%s\n",
986                  error.text);
987         emit failed(ApiError::fromJsonError());
988         return;
989     }
990 
991     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
992 
993     QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
994 
995     AccountInfo info;
996     info.email = dict["email"].toString();
997     info.name = dict["name"].toString();
998     info.totalStorage = dict["total"].toLongLong();
999     info.usedStorage = dict["usage"].toLongLong();
1000     if (info.name.isEmpty()) {
1001         info.name = dict["nickname"].toString();
1002     }
1003     emit success(info);
1004 }
1005 
PrivateShareRequest(const Account & account,const QString & repo_id,const QString & path,const SeafileUser & user,int group_id,SharePermission permission,ShareType share_type,ShareOperation op)1006 PrivateShareRequest::PrivateShareRequest(const Account& account,
1007                                          const QString& repo_id,
1008                                          const QString& path,
1009                                          const SeafileUser& user,
1010                                          int group_id,
1011                                          SharePermission permission,
1012                                          ShareType share_type,
1013                                          ShareOperation op)
1014     : SeafileApiRequest(
1015           account.getAbsoluteUrl(QString(kDirSharedItemsUrl).arg(repo_id)),
1016           op == UPDATE_SHARE ? METHOD_POST : (op == REMOVE_SHARE ? METHOD_DELETE
1017                                                                  : METHOD_PUT),
1018           account.token),
1019       group_id_(share_type == SHARE_TO_GROUP ? group_id : -1),
1020       user_(share_type == SHARE_TO_USER ? user: SeafileUser()),
1021       permission_(permission),
1022       share_type_(share_type),
1023       share_operation_(op)
1024 {
1025     setUrlParam("p", path);
1026     setFormParam("permission", permission == READ_ONLY ? "r" : "rw");
1027     bool is_add = op == ADD_SHARE;
1028     if (is_add) {
1029         setFormParam("share_type",
1030                      share_type == SHARE_TO_USER ? "user" : "group");
1031     }
1032     else {
1033         setUrlParam("share_type",
1034                     share_type == SHARE_TO_USER ? "user" : "group");
1035     }
1036 
1037     if (share_type == SHARE_TO_USER) {
1038         if (is_add) {
1039             setFormParam("username", user_.email);
1040         }
1041         else {
1042             setUrlParam("username", user_.email);
1043         }
1044     }
1045     else {
1046         if (is_add) {
1047             setFormParam("group_id", QString::number(group_id));
1048         }
1049         else {
1050             setUrlParam("group_id", QString::number(group_id));
1051         }
1052     }
1053 }
1054 
requestSuccess(QNetworkReply & reply)1055 void PrivateShareRequest::requestSuccess(QNetworkReply& reply)
1056 {
1057     json_error_t error;
1058     json_t* root = parseJSON(reply, &error);
1059     if (!root) {
1060         qWarning("PrivateShareRequest: failed to parse json:%s\n", error.text);
1061         emit failed(ApiError::fromJsonError());
1062         return;
1063     }
1064 
1065     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
1066 
1067     emit success();
1068 }
1069 
1070 
FetchGroupsAndContactsRequest(const Account & account)1071 FetchGroupsAndContactsRequest::FetchGroupsAndContactsRequest(
1072     const Account& account)
1073     : SeafileApiRequest(account.getAbsoluteUrl(kFetchGroupsAndContactsUrl),
1074                         SeafileApiRequest::METHOD_GET,
1075                         account.token)
1076 {
1077 }
1078 
requestSuccess(QNetworkReply & reply)1079 void FetchGroupsAndContactsRequest::requestSuccess(QNetworkReply& reply)
1080 {
1081     json_error_t error;
1082     json_t* root = parseJSON(reply, &error);
1083     if (!root) {
1084         qWarning("FetchGroupsAndContactsRequest: failed to parse json:%s\n",
1085                  error.text);
1086         emit failed(ApiError::fromJsonError());
1087         return;
1088     }
1089 
1090     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
1091 
1092     QList<SeafileGroup> groups;
1093     QList<SeafileUser> contacts;
1094 
1095     json_t* groups_array = json_object_get(json.data(), "groups");
1096     if (groups_array) {
1097         int i, n = json_array_size(groups_array);
1098         for (i = 0; i < n; i++) {
1099             json_t* group_object = json_array_get(groups_array, i);
1100             const char* name =
1101                 json_string_value(json_object_get(group_object, "name"));
1102             int group_id =
1103                 json_integer_value(json_object_get(group_object, "id"));
1104             if (name && group_id) {
1105                 SeafileGroup group;
1106                 group.id = group_id;
1107                 group.name = QString::fromUtf8(name);
1108                 const char* owner =
1109                     json_string_value(json_object_get(group_object, "creator"));
1110                 if (owner) {
1111                     group.owner = QString::fromUtf8(owner);
1112                 }
1113                 groups.push_back(group);
1114             }
1115         }
1116     }
1117 
1118     json_t* contacts_array = json_object_get(json.data(), "contacts");
1119     if (contacts_array) {
1120         int i, n = json_array_size(contacts_array);
1121 
1122         for (i = 0; i < n; i++) {
1123             json_t* contact_object = json_array_get(contacts_array, i);
1124             const char* email =
1125                 json_string_value(json_object_get(contact_object, "email"));
1126             if (email) {
1127                 SeafileUser contact;
1128                 contact.email = QString::fromUtf8(email);
1129                 contact.name = QString::fromUtf8(
1130                     json_string_value(json_object_get(contact_object, "name")));
1131                 contacts.push_back(contact);
1132             }
1133         }
1134     }
1135 
1136     emit success(groups, contacts);
1137 }
1138 
GetPrivateShareItemsRequest(const Account & account,const QString & repo_id,const QString & path)1139 GetPrivateShareItemsRequest::GetPrivateShareItemsRequest(const Account& account,
1140                                                          const QString& repo_id,
1141                                                          const QString& path)
1142     : SeafileApiRequest(
1143           account.getAbsoluteUrl(QString(kDirSharedItemsUrl).arg(repo_id)),
1144           SeafileApiRequest::METHOD_GET,
1145           account.token)
1146 {
1147     setUrlParam("p", path);
1148 }
1149 
requestSuccess(QNetworkReply & reply)1150 void GetPrivateShareItemsRequest::requestSuccess(QNetworkReply& reply)
1151 {
1152     json_error_t error;
1153     json_t* root = parseJSON(reply, &error);
1154     if (!root) {
1155         qWarning("GetPrivateShareItemsRequest: failed to parse json:%s\n",
1156                  error.text);
1157         emit failed(ApiError::fromJsonError());
1158         return;
1159     }
1160 
1161     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
1162 
1163     QList<GroupShareInfo> group_shares;
1164     QList<UserShareInfo> user_shares;
1165 
1166     int i, n = json_array_size(json.data());
1167     for (i = 0; i < n; i++) {
1168         json_t* share_info_object = json_array_get(json.data(), i);
1169         Json share_info(share_info_object);
1170         QString share_type = share_info.getString("share_type");
1171         QString permission = share_info.getString("permission");
1172         if (share_type == "group") {
1173             // group share
1174             Json group = share_info.getObject("group_info");
1175             GroupShareInfo group_share;
1176             group_share.group.id = group.getLong("id");
1177             group_share.group.name = group.getString("name");
1178             group_share.permission = ::permissionfromString(permission);
1179             group_shares.push_back(group_share);
1180         }
1181         else if (share_type == "user") {
1182             Json user = share_info.getObject("user_info");
1183             UserShareInfo user_share;
1184             user_share.user.email = user.getString("name");
1185             user_share.user.name = user.getString("nickname");
1186             user_share.permission = ::permissionfromString(permission);
1187             user_shares.push_back(user_share);
1188         }
1189     }
1190 
1191     emit success(group_shares, user_shares);
1192 }
1193 
RemoteWipeReportRequest(const Account & account)1194 RemoteWipeReportRequest::RemoteWipeReportRequest(const Account& account)
1195     : SeafileApiRequest(account.getAbsoluteUrl(kRemoteWipeReportUrl),
1196                         SeafileApiRequest::METHOD_POST)
1197 {
1198     setFormParam(QString("token"), account.token);
1199 }
1200 
requestSuccess(QNetworkReply & reply)1201 void RemoteWipeReportRequest::requestSuccess(QNetworkReply& reply)
1202 {
1203     emit success();
1204 }
1205 
SearchUsersRequest(const Account & account,const QString & pattern)1206 SearchUsersRequest::SearchUsersRequest(
1207     const Account& account, const QString& pattern)
1208     : SeafileApiRequest(account.getAbsoluteUrl(kSearchUsersUrl),
1209                         SeafileApiRequest::METHOD_GET,
1210                         account.token),
1211       pattern_(pattern)
1212 {
1213     setUrlParam("q", pattern);
1214 }
1215 
requestSuccess(QNetworkReply & reply)1216 void SearchUsersRequest::requestSuccess(QNetworkReply& reply)
1217 {
1218     json_error_t error;
1219     json_t* root = parseJSON(reply, &error);
1220     if (!root) {
1221         qWarning("SearchUsersRequest: failed to parse json:%s\n",
1222                  error.text);
1223         emit failed(ApiError::fromJsonError());
1224         return;
1225     }
1226 
1227     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
1228 
1229     QList<SeafileUser> users;
1230 
1231     json_t* users_array = json_object_get(json.data(), "users");
1232     if (users_array) {
1233         int i, n = json_array_size(users_array);
1234 
1235         for (i = 0; i < n; i++) {
1236             json_t* user_object = json_array_get(users_array, i);
1237             const char* email =
1238                 json_string_value(json_object_get(user_object, "email"));
1239             if (email) {
1240                 SeafileUser user;
1241                 user.email = QString::fromUtf8(email);
1242                 user.name = QString::fromUtf8(
1243                     json_string_value(json_object_get(user_object, "name")));
1244                 user.contact_email = QString::fromUtf8(
1245                     json_string_value(json_object_get(user_object, "contact_email")));
1246                 user.avatar_url = QString::fromUtf8(
1247                     json_string_value(json_object_get(user_object, "avatar_url")));
1248                 users.push_back(user);
1249             }
1250         }
1251     }
1252 
1253     emit success(users);
1254 }
1255 
1256 
FetchGroupsRequest(const Account & account)1257 FetchGroupsRequest::FetchGroupsRequest(
1258     const Account& account)
1259     : SeafileApiRequest(account.getAbsoluteUrl(kFetchGroupsUrl),
1260                         SeafileApiRequest::METHOD_GET,
1261                         account.token)
1262 {
1263     setUrlParam("with_msg", "false");
1264 }
1265 
requestSuccess(QNetworkReply & reply)1266 void FetchGroupsRequest::requestSuccess(QNetworkReply& reply)
1267 {
1268     json_error_t error;
1269     json_t* root = parseJSON(reply, &error);
1270     if (!root) {
1271         qWarning("FetchGroupsRequest: failed to parse json:%s\n",
1272                  error.text);
1273         emit failed(ApiError::fromJsonError());
1274         return;
1275     }
1276 
1277     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
1278 
1279     QList<SeafileGroup> groups;
1280 
1281     int i, n = json_array_size(json.data());
1282     for (i = 0; i < n; i++) {
1283         json_t* group_object = json_array_get(json.data(), i);
1284         const char* name =
1285             json_string_value(json_object_get(group_object, "name"));
1286         int group_id =
1287             json_integer_value(json_object_get(group_object, "id"));
1288         if (name && group_id) {
1289             SeafileGroup group;
1290             group.id = group_id;
1291             group.name = QString::fromUtf8(name);
1292             const char* owner =
1293                 json_string_value(json_object_get(group_object, "creator"));
1294             if (owner) {
1295                 group.owner = QString::fromUtf8(owner);
1296             }
1297             groups.push_back(group);
1298         }
1299     }
1300 
1301     emit success(groups);
1302 }
1303 
GetThumbnailRequest(const Account & account,const QString & repo_id,const QString & path,const QString & dirent_id,uint size)1304 GetThumbnailRequest::GetThumbnailRequest(const Account& account,
1305                                          const QString& repo_id,
1306                                          const QString& path,
1307 					 const QString& dirent_id,
1308                                          uint size)
1309     : SeafileApiRequest(
1310           account.getAbsoluteUrl(QString(kGetThumbnailUrl).arg(repo_id)),
1311           SeafileApiRequest::METHOD_GET,
1312           account.token),
1313       account_(account),
1314       repo_id_(repo_id),
1315       path_(path),
1316       dirent_id_(dirent_id),
1317       size_(size)
1318 {
1319     setUrlParam("p", path);
1320     setUrlParam("size", QString::number(size));
1321     setUseCache(true);
1322 }
1323 
requestSuccess(QNetworkReply & reply)1324 void GetThumbnailRequest::requestSuccess(QNetworkReply& reply)
1325 {
1326     QPixmap pixmap;
1327     pixmap.loadFromData(reply.readAll());
1328 
1329     if (pixmap.isNull()) {
1330         qWarning("GetThumbnailRequest: invalid image data\n");
1331         emit failed(ApiError::fromHttpError(400));
1332     }
1333     else {
1334         emit success(pixmap);
1335     }
1336 }
1337 
UnshareRepoRequest(const Account & account,const QString & repo_id,const QString & from_user)1338 UnshareRepoRequest::UnshareRepoRequest(const Account& account,
1339                                        const QString& repo_id,
1340                                        const QString& from_user)
1341     : SeafileApiRequest(
1342           account.getAbsoluteUrl(QString(kRepoSharedUrl).arg(repo_id)),
1343           SeafileApiRequest::METHOD_DELETE,
1344           account.token),
1345       repo_id_(repo_id)
1346 {
1347     setUrlParam("share_type", "personal");
1348     setUrlParam("from", from_user);
1349 }
1350 
requestSuccess(QNetworkReply & reply)1351 void UnshareRepoRequest::requestSuccess(QNetworkReply& reply)
1352 {
1353     emit success();
1354 }
1355 
CreateFileUploadLinkRequest(const Account & account,const QString & repo_id,const QString & path,const QString & password)1356 CreateFileUploadLinkRequest::CreateFileUploadLinkRequest(const Account& account,
1357                                                          const QString &repo_id,
1358                                                          const QString &path,
1359                                                          const QString &password)
1360     : SeafileApiRequest(
1361           account.getAbsoluteUrl(QString(kCreateFileUploadLink)),
1362           SeafileApiRequest::METHOD_POST, account.token),
1363       repo_id_(repo_id),
1364       path_(path),
1365       password_(password)
1366 {
1367     setFormParam(QString("repo_id"), repo_id);
1368     setFormParam(QString("path"), path);
1369     if (!password.isNull()) {
1370         setFormParam(QString("password"), password);
1371     }
1372 }
1373 
requestSuccess(QNetworkReply & reply)1374 void CreateFileUploadLinkRequest::requestSuccess(QNetworkReply& reply)
1375 {
1376     json_error_t error;
1377     json_t* root = parseJSON(reply, &error);
1378     if (!root) {
1379         qWarning("failed to parse json:%s\n", error.text);
1380         emit failed(ApiError::fromJsonError());
1381         return;
1382     }
1383 
1384     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
1385     QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
1386     UploadLinkInfo link_info;
1387     link_info.username = dict["username"].toString();
1388     link_info.repo_id = dict["repo_id"].toString();
1389     link_info.ctime = dict["ctime"].toString();
1390     link_info.token = dict["token"].toString();
1391     link_info.link = dict["link"].toString();
1392     link_info.path = dict["path"].toString();
1393 
1394     emit success(link_info);
1395 }
1396 
GetUploadFileLinkRequest(const QString & link)1397 GetUploadFileLinkRequest::GetUploadFileLinkRequest(const QString& link)
1398     : SeafileApiRequest(link, SeafileApiRequest::METHOD_GET)
1399 {
1400 }
1401 
requestSuccess(QNetworkReply & reply)1402 void GetUploadFileLinkRequest::requestSuccess(QNetworkReply& reply)
1403 {
1404     json_error_t error;
1405     json_t* root = parseJSON(reply, &error);
1406     if (!root) {
1407         qWarning("failed to parse json:%s\n", error.text);
1408         emit failed(ApiError::fromJsonError());
1409         return;
1410     }
1411 
1412     QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
1413     QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
1414     QString reply_content(dict["upload_link"].toString());
1415 
1416     do {
1417         if (reply_content.size() <= 2)
1418             break;
1419         QUrl new_url(reply_content);
1420         if (!new_url.isValid())
1421             break;
1422 
1423         emit success(reply_content);
1424         return;
1425     } while (0);
1426     emit failed(ApiError::fromHttpError(500));
1427 }
1428