support private share in cloud file browser

This commit is contained in:
Shuai Lin 2015-12-02 21:16:36 +08:00
parent 173a6fff17
commit a54c5a8fdf
16 changed files with 2017 additions and 186 deletions

View file

@ -34,6 +34,10 @@ AccessModifierOffset: -4
#
AlignTrailingComments: false
AllowShortFunctionsOnASingleLine: false
AllowShortBlocksOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
# Good:
#

View file

@ -213,6 +213,7 @@ SET(moc_headers
src/ui/init-vdrive-dialog.h
src/ui/uninstall-helper-dialog.h
src/ui/ssl-confirm-dialog.h
src/ui/private-share-dialog.h
src/ui/account-view.h
src/ui/seafile-tab-widget.h
src/ui/tab-view.h
@ -266,6 +267,7 @@ SET(ui_files
ui/init-vdrive-dialog.ui
ui/uninstall-helper-dialog.ui
ui/ssl-confirm-dialog.ui
ui/private-share-dialog.ui
ui/account-view.ui
ui/set-repo-password-dialog.ui
${platform_specific_ui_files}
@ -400,6 +402,7 @@ SET(seafile_client_sources
src/ui/search-tab.cpp
src/ui/search-tab-items.cpp
src/ui/ssl-confirm-dialog.cpp
src/ui/private-share-dialog.cpp
src/ui/proxy-style.cpp
src/ui/account-view.cpp
src/ui/seafile-tab-widget.cpp

4
qt-linux.css Normal file
View file

@ -0,0 +1,4 @@
PrivateShareDialog QFrame#mFrame {
border: 0;
}

16
qt.css
View file

@ -597,3 +597,19 @@ QProgressBar#mStorageUsage {
margin-right: 0;
font-size: 11px;
}
PrivateShareDialog {
min-width: 550px;
min-height: 200px;
}
SharedItemsTableView {
margin-top: 10px;
qproperty-focusPolicy: NoFocus;
}
SharedItemsTableView QHeaderView::section {
/* outline: 1px; */
font-size: 12px;
padding-top: 10px;
}

View file

@ -0,0 +1,58 @@
#ifndef SEAFILE_CLIENT_CONTACT_SHARE_INFO_H
#define SEAFILE_CLIENT_CONTACT_SHARE_INFO_H
#include <QMetaType>
#include <QString>
struct SeafileGroup {
int id;
QString name;
QString owner;
};
struct SeafileContact {
QString email;
QString nickname;
};
enum SharePermission {
READ_WRITE,
READ_ONLY,
};
enum ShareType {
SHARE_TO_USER,
SHARE_TO_GROUP,
};
inline SharePermission permissionfromString(const QString& s)
{
return s == "r" ? READ_ONLY : READ_WRITE;
}
inline ShareType shareTypeFromString(const QString& s)
{
return s == "group" ? SHARE_TO_GROUP : SHARE_TO_USER;
}
struct UserShareInfo {
SharePermission permission;
SeafileContact user;
};
struct GroupShareInfo {
SharePermission permission;
SeafileGroup group;
};
/**
* Register with QMetaType so we can wrap it with QVariant::fromValue
*/
Q_DECLARE_METATYPE(SeafileGroup)
Q_DECLARE_METATYPE(SeafileContact)
Q_DECLARE_METATYPE(UserShareInfo)
Q_DECLARE_METATYPE(GroupShareInfo)
#endif

View file

@ -1,53 +1,56 @@
#include <jansson.h>
#include <QtNetwork>
#include <QScopedPointer>
#include <QtNetwork>
#include "account.h"
#include "seafile-applet.h"
#include "api-error.h"
#include "commit-details.h"
#include "event.h"
#include "repo-service.h"
#include "rpc/rpc-client.h"
#include "utils/utils.h"
#include "utils/api-utils.h"
#include "api-error.h"
#include "seafile-applet.h"
#include "server-repo.h"
#include "starred-file.h"
#include "event.h"
#include "commit-details.h"
#include "utils/api-utils.h"
#include "utils/json-utils.h"
#include "utils/utils.h"
#include "requests.h"
namespace {
namespace
{
const char* kApiPingUrl = "api2/ping/";
const char* kApiLoginUrl = "api2/auth-token/";
const char* kListReposUrl = "api2/repos/";
const char* kCreateRepoUrl = "api2/repos/";
const char* kGetRepoUrl = "api2/repos/%1/";
const char* kCreateSubrepoUrl = "api2/repos/%1/dir/sub_repo/";
const char* kUnseenMessagesUrl = "api2/unseen_messages/";
const char* kDefaultRepoUrl = "api2/default-repo/";
const char* kStarredFilesUrl = "api2/starredfiles/";
const char* kGetEventsUrl = "api2/events/";
const char* kCommitDetailsUrl = "api2/repo_history_changes/";
const char* kAvatarUrl = "api2/avatars/user/";
const char* kSetRepoPasswordUrl = "api2/repos/";
const char* kServerInfoUrl = "api2/server-info/";
const char* kLogoutDeviceUrl = "api2/logout-device/";
const char* kGetRepoTokensUrl = "api2/repo-tokens/";
const char* kGetLoginTokenUrl = "api2/client-login/";
const char* kFileSearchUrl = "api2/search/";
const char* kAccountInfoUrl = "api2/account/info/";
const char* kDirSharedItemsUrl = "api2/repos/%1/dir/shared_items/";
const char* kFetchGroupsAndContactsUrl = "api2/groupandcontacts/";
const char *kApiPingUrl = "api2/ping/";
const char *kApiLoginUrl = "api2/auth-token/";
const char *kListReposUrl = "api2/repos/";
const char *kCreateRepoUrl = "api2/repos/";
const char *kGetRepoUrl = "api2/repos/%1/";
const char *kCreateSubrepoUrl ="api2/repos/%1/dir/sub_repo/";
const char *kUnseenMessagesUrl = "api2/unseen_messages/";
const char *kDefaultRepoUrl = "api2/default-repo/";
const char *kStarredFilesUrl = "api2/starredfiles/";
const char *kGetEventsUrl = "api2/events/";
const char *kCommitDetailsUrl = "api2/repo_history_changes/";
const char *kAvatarUrl = "api2/avatars/user/";
const char *kSetRepoPasswordUrl = "api2/repos/";
const char *kServerInfoUrl ="api2/server-info/";
const char *kLogoutDeviceUrl = "api2/logout-device/";
const char *kGetRepoTokensUrl = "api2/repo-tokens/";
const char *kGetLoginTokenUrl = "api2/client-login/";
const char *kFileSearchUrl = "api2/search/";
const char *kAccountInfoUrl = "api2/account/info/";
const char *kLatestVersionUrl = "http://seafile.com/api/client-versions/";
const char* kLatestVersionUrl = "http://seafile.com/api/client-versions/";
#if defined(Q_OS_WIN32)
const char *kOsName = "windows";
const char* kOsName = "windows";
#elif defined(Q_OS_LINUX)
const char *kOsName = "linux";
const char* kOsName = "linux";
#else
const char *kOsName = "mac";
const char* kOsName = "mac";
#endif
} // namespace
@ -55,8 +58,8 @@ const char *kOsName = "mac";
PingServerRequest::PingServerRequest(const QUrl& serverAddr)
: SeafileApiRequest (::urlJoin(serverAddr, kApiPingUrl),
SeafileApiRequest::METHOD_GET)
: SeafileApiRequest(::urlJoin(serverAddr, kApiPingUrl),
SeafileApiRequest::METHOD_GET)
{
}
@ -73,8 +76,8 @@ LoginRequest::LoginRequest(const QUrl& serverAddr,
const QString& password,
const QString& computer_name)
: SeafileApiRequest (::urlJoin(serverAddr, kApiLoginUrl),
SeafileApiRequest::METHOD_POST)
: SeafileApiRequest(::urlJoin(serverAddr, kApiLoginUrl),
SeafileApiRequest::METHOD_POST)
{
setFormParam("username", username);
setFormParam("password", password);
@ -88,7 +91,7 @@ LoginRequest::LoginRequest(const QUrl& serverAddr,
void LoginRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("failed to parse json:%s\n", error.text);
emit failed(ApiError::fromJsonError());
@ -97,7 +100,8 @@ void LoginRequest::requestSuccess(QNetworkReply& reply)
QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
const char *token = json_string_value(json_object_get(json.data(), "token"));
const char* token =
json_string_value(json_object_get(json.data(), "token"));
if (token == NULL) {
qWarning("failed to parse json:%s\n", error.text);
emit failed(ApiError::fromJsonError());
@ -112,15 +116,16 @@ void LoginRequest::requestSuccess(QNetworkReply& reply)
* ListReposRequest
*/
ListReposRequest::ListReposRequest(const Account& account)
: SeafileApiRequest (account.getAbsoluteUrl(kListReposUrl),
SeafileApiRequest::METHOD_GET, account.token)
: SeafileApiRequest(account.getAbsoluteUrl(kListReposUrl),
SeafileApiRequest::METHOD_GET,
account.token)
{
}
void ListReposRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("ListReposRequest:failed to parse json:%s\n", error.text);
emit failed(ApiError::fromJsonError());
@ -129,7 +134,8 @@ void ListReposRequest::requestSuccess(QNetworkReply& reply)
QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
std::vector<ServerRepo> repos = ServerRepo::listFromJSON(json.data(), &error);
std::vector<ServerRepo> repos =
ServerRepo::listFromJSON(json.data(), &error);
emit success(repos);
}
@ -137,9 +143,13 @@ void ListReposRequest::requestSuccess(QNetworkReply& reply)
/**
* DownloadRepoRequest
*/
DownloadRepoRequest::DownloadRepoRequest(const Account& account, const QString& repo_id, bool read_only)
: SeafileApiRequest(account.getAbsoluteUrl("api2/repos/" + repo_id + "/download-info/"),
SeafileApiRequest::METHOD_GET, account.token),
DownloadRepoRequest::DownloadRepoRequest(const Account& account,
const QString& repo_id,
bool read_only)
: SeafileApiRequest(
account.getAbsoluteUrl("api2/repos/" + repo_id + "/download-info/"),
SeafileApiRequest::METHOD_GET,
account.token),
read_only_(read_only)
{
}
@ -179,7 +189,7 @@ RepoDownloadInfo RepoDownloadInfo::fromDict(QMap<QString, QVariant>& dict,
void DownloadRepoRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("failed to parse json:%s\n", error.text);
emit failed(ApiError::fromJsonError());
@ -197,17 +207,19 @@ void DownloadRepoRequest::requestSuccess(QNetworkReply& reply)
/**
* GetRepoRequest
*/
GetRepoRequest::GetRepoRequest(const Account& account, const QString &repoid)
: SeafileApiRequest (account.getAbsoluteUrl(QString(kGetRepoUrl).arg(repoid)),
SeafileApiRequest::METHOD_GET, account.token)
, repoid_(repoid)
GetRepoRequest::GetRepoRequest(const Account& account, const QString& repoid)
: SeafileApiRequest(
account.getAbsoluteUrl(QString(kGetRepoUrl).arg(repoid)),
SeafileApiRequest::METHOD_GET,
account.token),
repoid_(repoid)
{
}
void GetRepoRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("failed to parse json:%s\n", error.text);
emit failed(ApiError::fromJsonError());
@ -224,9 +236,13 @@ void GetRepoRequest::requestSuccess(QNetworkReply& reply)
/**
* CreateRepoRequest
*/
CreateRepoRequest::CreateRepoRequest(const Account& account, const QString &name, const QString &desc, const QString &passwd)
: SeafileApiRequest (account.getAbsoluteUrl(kCreateRepoUrl),
SeafileApiRequest::METHOD_POST, account.token)
CreateRepoRequest::CreateRepoRequest(const Account& account,
const QString& name,
const QString& desc,
const QString& passwd)
: SeafileApiRequest(account.getAbsoluteUrl(kCreateRepoUrl),
SeafileApiRequest::METHOD_POST,
account.token)
{
setFormParam(QString("name"), name);
setFormParam(QString("desc"), desc);
@ -236,10 +252,16 @@ CreateRepoRequest::CreateRepoRequest(const Account& account, const QString &name
}
}
CreateRepoRequest::CreateRepoRequest(const Account& account, const QString &name, const QString &desc,
int enc_version, const QString &repo_id, const QString& magic, const QString& random_key)
: SeafileApiRequest (account.getAbsoluteUrl(kCreateRepoUrl),
SeafileApiRequest::METHOD_POST, account.token)
CreateRepoRequest::CreateRepoRequest(const Account& account,
const QString& name,
const QString& desc,
int enc_version,
const QString& repo_id,
const QString& magic,
const QString& random_key)
: SeafileApiRequest(account.getAbsoluteUrl(kCreateRepoUrl),
SeafileApiRequest::METHOD_POST,
account.token)
{
setFormParam("name", name);
setFormParam("desc", desc);
@ -252,7 +274,7 @@ CreateRepoRequest::CreateRepoRequest(const Account& account, const QString &name
void CreateRepoRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("failed to parse json:%s\n", error.text);
emit failed(ApiError::fromJsonError());
@ -269,9 +291,15 @@ void CreateRepoRequest::requestSuccess(QNetworkReply& reply)
/**
* CreateSubrepoRequest
*/
CreateSubrepoRequest::CreateSubrepoRequest(const Account& account, const QString &name, const QString &repoid , const QString &path, const QString &passwd)
: SeafileApiRequest (account.getAbsoluteUrl(QString(kCreateSubrepoUrl).arg(repoid)),
SeafileApiRequest::METHOD_GET, account.token)
CreateSubrepoRequest::CreateSubrepoRequest(const Account& account,
const QString& name,
const QString& repoid,
const QString& path,
const QString& passwd)
: SeafileApiRequest(
account.getAbsoluteUrl(QString(kCreateSubrepoUrl).arg(repoid)),
SeafileApiRequest::METHOD_GET,
account.token)
{
setUrlParam(QString("p"), path);
setUrlParam(QString("name"), name);
@ -283,7 +311,7 @@ CreateSubrepoRequest::CreateSubrepoRequest(const Account& account, const QString
void CreateSubrepoRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("failed to parse json:%s\n", error.text);
emit failed(ApiError::fromJsonError());
@ -299,18 +327,22 @@ void CreateSubrepoRequest::requestSuccess(QNetworkReply& reply)
/**
* GetUnseenSeahubNotificationsRequest
*/
GetUnseenSeahubNotificationsRequest::GetUnseenSeahubNotificationsRequest(const Account& account)
: SeafileApiRequest (account.getAbsoluteUrl(kUnseenMessagesUrl),
SeafileApiRequest::METHOD_GET, account.token)
GetUnseenSeahubNotificationsRequest::GetUnseenSeahubNotificationsRequest(
const Account& account)
: SeafileApiRequest(account.getAbsoluteUrl(kUnseenMessagesUrl),
SeafileApiRequest::METHOD_GET,
account.token)
{
}
void GetUnseenSeahubNotificationsRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("GetUnseenSeahubNotificationsRequest: failed to parse json:%s\n", error.text);
qWarning(
"GetUnseenSeahubNotificationsRequest: failed to parse json:%s\n",
error.text);
emit failed(ApiError::fromJsonError());
return;
}
@ -329,17 +361,19 @@ void GetUnseenSeahubNotificationsRequest::requestSuccess(QNetworkReply& reply)
}
GetDefaultRepoRequest::GetDefaultRepoRequest(const Account& account)
: SeafileApiRequest (account.getAbsoluteUrl(kDefaultRepoUrl),
SeafileApiRequest::METHOD_GET, account.token)
: SeafileApiRequest(account.getAbsoluteUrl(kDefaultRepoUrl),
SeafileApiRequest::METHOD_GET,
account.token)
{
}
void GetDefaultRepoRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("CreateDefaultRepoRequest: failed to parse json:%s\n", error.text);
qWarning("CreateDefaultRepoRequest: failed to parse json:%s\n",
error.text);
emit failed(ApiError::fromJsonError());
return;
}
@ -371,17 +405,19 @@ void GetDefaultRepoRequest::requestSuccess(QNetworkReply& reply)
CreateDefaultRepoRequest::CreateDefaultRepoRequest(const Account& account)
: SeafileApiRequest (account.getAbsoluteUrl(kDefaultRepoUrl),
SeafileApiRequest::METHOD_POST, account.token)
: SeafileApiRequest(account.getAbsoluteUrl(kDefaultRepoUrl),
SeafileApiRequest::METHOD_POST,
account.token)
{
}
void CreateDefaultRepoRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("CreateDefaultRepoRequest: failed to parse json:%s\n", error.text);
qWarning("CreateDefaultRepoRequest: failed to parse json:%s\n",
error.text);
emit failed(ApiError::fromJsonError());
return;
}
@ -409,9 +445,10 @@ GetLatestVersionRequest::GetLatestVersionRequest(const QString& client_id,
void GetLatestVersionRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("GetLatestVersionRequest: failed to parse json:%s\n", error.text);
qWarning("GetLatestVersionRequest: failed to parse json:%s\n",
error.text);
emit failed(ApiError::fromJsonError());
return;
}
@ -431,30 +468,34 @@ void GetLatestVersionRequest::requestSuccess(QNetworkReply& reply)
}
GetStarredFilesRequest::GetStarredFilesRequest(const Account& account)
: SeafileApiRequest (account.getAbsoluteUrl(kStarredFilesUrl),
SeafileApiRequest::METHOD_GET, account.token)
: SeafileApiRequest(account.getAbsoluteUrl(kStarredFilesUrl),
SeafileApiRequest::METHOD_GET,
account.token)
{
}
void GetStarredFilesRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("GetStarredFilesRequest: failed to parse json:%s\n", error.text);
qWarning("GetStarredFilesRequest: failed to parse json:%s\n",
error.text);
emit failed(ApiError::fromJsonError());
return;
}
QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
std::vector<StarredFile> files = StarredFile::listFromJSON(json.data(), &error);
std::vector<StarredFile> files =
StarredFile::listFromJSON(json.data(), &error);
emit success(files);
}
GetEventsRequest::GetEventsRequest(const Account& account, int start)
: SeafileApiRequest (account.getAbsoluteUrl(kGetEventsUrl),
SeafileApiRequest::METHOD_GET, account.token)
: SeafileApiRequest(account.getAbsoluteUrl(kGetEventsUrl),
SeafileApiRequest::METHOD_GET,
account.token)
{
if (start > 0) {
setUrlParam("start", QString::number(start));
@ -464,7 +505,7 @@ GetEventsRequest::GetEventsRequest(const Account& account, int start)
void GetEventsRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("GetEventsRequest: failed to parse json:%s\n", error.text);
emit failed(ApiError::fromJsonError());
@ -481,17 +522,20 @@ void GetEventsRequest::requestSuccess(QNetworkReply& reply)
more = json_is_true(json_object_get(json.data(), "more"));
if (more) {
more_offset = json_integer_value(json_object_get(json.data(), "more_offset"));
more_offset =
json_integer_value(json_object_get(json.data(), "more_offset"));
}
emit success(events, more_offset);
}
GetCommitDetailsRequest::GetCommitDetailsRequest(const Account& account,
const QString& repo_id,
const QString& commit_id)
: SeafileApiRequest (account.getAbsoluteUrl(kCommitDetailsUrl + repo_id + "/"),
SeafileApiRequest::METHOD_GET, account.token)
const QString& repo_id,
const QString& commit_id)
: SeafileApiRequest(
account.getAbsoluteUrl(kCommitDetailsUrl + repo_id + "/"),
SeafileApiRequest::METHOD_GET,
account.token)
{
setUrlParam("commit_id", commit_id);
}
@ -499,9 +543,10 @@ GetCommitDetailsRequest::GetCommitDetailsRequest(const Account& account,
void GetCommitDetailsRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("GetCommitDetailsRequest: failed to parse json:%s\n", error.text);
qWarning("GetCommitDetailsRequest: failed to parse json:%s\n",
error.text);
emit failed(ApiError::fromJsonError());
return;
}
@ -518,11 +563,11 @@ GetAvatarRequest::GetAvatarRequest(const Account& account,
const QString& email,
qint64 mtime,
int size)
: SeafileApiRequest (account.getAbsoluteUrl(
kAvatarUrl
+ email + "/resized/"
+ QString::number(size) + "/"),
SeafileApiRequest::METHOD_GET, account.token),
: SeafileApiRequest(
account.getAbsoluteUrl(kAvatarUrl + email + "/resized/" +
QString::number(size) + "/"),
SeafileApiRequest::METHOD_GET,
account.token),
fetch_img_req_(NULL),
mtime_(mtime)
{
@ -540,7 +585,7 @@ GetAvatarRequest::~GetAvatarRequest()
void GetAvatarRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("GetAvatarRequest: failed to parse json:%s\n", error.text);
emit failed(ApiError::fromJsonError());
@ -549,13 +594,15 @@ void GetAvatarRequest::requestSuccess(QNetworkReply& reply)
QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
const char *avatar_url = json_string_value(json_object_get(json.data(), "url"));
const char* avatar_url =
json_string_value(json_object_get(json.data(), "url"));
// we don't need to fetch all images if we have latest one
json_t *mtime = json_object_get(json.data(), "mtime");
json_t* mtime = json_object_get(json.data(), "mtime");
if (!mtime) {
qWarning("GetAvatarRequest: no 'mtime' value in response\n");
} else {
}
else {
qint64 new_mtime = json_integer_value(mtime);
if (new_mtime == mtime_) {
emit success(QImage());
@ -574,10 +621,10 @@ void GetAvatarRequest::requestSuccess(QNetworkReply& reply)
fetch_img_req_ = new FetchImageRequest(url);
connect(fetch_img_req_, SIGNAL(failed(const ApiError&)),
this, SIGNAL(failed(const ApiError&)));
connect(fetch_img_req_, SIGNAL(success(const QImage&)),
this, SIGNAL(success(const QImage&)));
connect(fetch_img_req_, SIGNAL(failed(const ApiError&)), this,
SIGNAL(failed(const ApiError&)));
connect(fetch_img_req_, SIGNAL(success(const QImage&)), this,
SIGNAL(success(const QImage&)));
fetch_img_req_->send();
}
@ -594,7 +641,8 @@ void FetchImageRequest::requestSuccess(QNetworkReply& reply)
if (img.isNull()) {
qWarning("FetchImageRequest: invalid image data\n");
emit failed(ApiError::fromHttpError(400));
} else {
}
else {
emit success(img);
}
}
@ -602,8 +650,10 @@ void FetchImageRequest::requestSuccess(QNetworkReply& reply)
SetRepoPasswordRequest::SetRepoPasswordRequest(const Account& account,
const QString& repo_id,
const QString& password)
: SeafileApiRequest (account.getAbsoluteUrl(kSetRepoPasswordUrl + repo_id + "/"),
SeafileApiRequest::METHOD_POST, account.token)
: SeafileApiRequest(
account.getAbsoluteUrl(kSetRepoPasswordUrl + repo_id + "/"),
SeafileApiRequest::METHOD_POST,
account.token)
{
setFormParam("password", password);
}
@ -614,16 +664,17 @@ void SetRepoPasswordRequest::requestSuccess(QNetworkReply& reply)
}
ServerInfoRequest::ServerInfoRequest(const Account& account)
: SeafileApiRequest (account.getAbsoluteUrl(kServerInfoUrl),
SeafileApiRequest::METHOD_GET, account.token),
account_(account)
: SeafileApiRequest(account.getAbsoluteUrl(kServerInfoUrl),
SeafileApiRequest::METHOD_GET,
account.token),
account_(account)
{
}
void ServerInfoRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("failed to parse json:%s\n", error.text);
emit failed(ApiError::fromJsonError());
@ -655,8 +706,9 @@ void ServerInfoRequest::requestSuccess(QNetworkReply& reply)
}
LogoutDeviceRequest::LogoutDeviceRequest(const Account& account)
: SeafileApiRequest (account.getAbsoluteUrl(kLogoutDeviceUrl),
SeafileApiRequest::METHOD_POST, account.token),
: SeafileApiRequest(account.getAbsoluteUrl(kLogoutDeviceUrl),
SeafileApiRequest::METHOD_POST,
account.token),
account_(account)
{
}
@ -668,8 +720,9 @@ void LogoutDeviceRequest::requestSuccess(QNetworkReply& reply)
GetRepoTokensRequest::GetRepoTokensRequest(const Account& account,
const QStringList& repo_ids)
: SeafileApiRequest (account.getAbsoluteUrl(kGetRepoTokensUrl),
SeafileApiRequest::METHOD_GET, account.token)
: SeafileApiRequest(account.getAbsoluteUrl(kGetRepoTokensUrl),
SeafileApiRequest::METHOD_GET,
account.token)
{
setUrlParam("repos", repo_ids.join(","));
}
@ -677,7 +730,7 @@ GetRepoTokensRequest::GetRepoTokensRequest(const Account& account,
void GetRepoTokensRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("GetRepoTokensRequest: failed to parse json:%s\n", error.text);
emit failed(ApiError::fromJsonError());
@ -687,16 +740,18 @@ void GetRepoTokensRequest::requestSuccess(QNetworkReply& reply)
QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
foreach (const QString &repo_id, dict.keys()) {
foreach (const QString& repo_id, dict.keys()) {
repo_tokens_[repo_id] = dict[repo_id].toString();
}
emit success();
}
GetLoginTokenRequest::GetLoginTokenRequest(const Account& account, const QString& next_url)
: SeafileApiRequest (account.getAbsoluteUrl(kGetLoginTokenUrl),
SeafileApiRequest::METHOD_POST, account.token),
GetLoginTokenRequest::GetLoginTokenRequest(const Account& account,
const QString& next_url)
: SeafileApiRequest(account.getAbsoluteUrl(kGetLoginTokenUrl),
SeafileApiRequest::METHOD_POST,
account.token),
account_(account),
next_url_(next_url)
{
@ -705,7 +760,7 @@ GetLoginTokenRequest::GetLoginTokenRequest(const Account& account, const QString
void GetLoginTokenRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("GetLoginTokenRequest: failed to parse json:%s\n", error.text);
emit failed(ApiError::fromJsonError());
@ -722,9 +777,12 @@ void GetLoginTokenRequest::requestSuccess(QNetworkReply& reply)
emit success(dict["token"].toString());
}
FileSearchRequest::FileSearchRequest(const Account& account, const QString &keyword, int per_page)
: SeafileApiRequest (account.getAbsoluteUrl(kFileSearchUrl),
SeafileApiRequest::METHOD_GET, account.token),
FileSearchRequest::FileSearchRequest(const Account& account,
const QString& keyword,
int per_page)
: SeafileApiRequest(account.getAbsoluteUrl(kFileSearchUrl),
SeafileApiRequest::METHOD_GET,
account.token),
keyword_(keyword)
{
setUrlParam("q", keyword_);
@ -733,7 +791,7 @@ FileSearchRequest::FileSearchRequest(const Account& account, const QString &keyw
void FileSearchRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("FileSearchResult: failed to parse jsn:%s\n", error.text);
emit failed(ApiError::fromJsonError());
@ -779,13 +837,16 @@ void FetchCustomLogoRequest::requestSuccess(QNetworkReply& reply)
if (logo.isNull()) {
qWarning("FetchCustomLogoRequest: invalid image data\n");
emit failed(ApiError::fromHttpError(400));
} else {
}
else {
emit success(url());
}
}
FetchAccountInfoRequest::FetchAccountInfoRequest(const Account& account)
: SeafileApiRequest (account.getAbsoluteUrl(kAccountInfoUrl), SeafileApiRequest::METHOD_GET, account.token)
: SeafileApiRequest(account.getAbsoluteUrl(kAccountInfoUrl),
SeafileApiRequest::METHOD_GET,
account.token)
{
account_ = account;
}
@ -793,9 +854,10 @@ FetchAccountInfoRequest::FetchAccountInfoRequest(const Account& account)
void FetchAccountInfoRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t *root = parseJSON(reply, &error);
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("FetchAccountInfoRequest: failed to parse json:%s\n", error.text);
qWarning("FetchAccountInfoRequest: failed to parse json:%s\n",
error.text);
emit failed(ApiError::fromJsonError());
return;
}
@ -811,3 +873,186 @@ void FetchAccountInfoRequest::requestSuccess(QNetworkReply& reply)
info.usedStorage = dict["usage"].toLongLong();
emit success(info);
}
PrivateShareRequest::PrivateShareRequest(const Account& account,
const QString& repo_id,
const QString& path,
const QString& username,
int group_id,
SharePermission permission,
ShareType share_type,
ShareOperation op)
: SeafileApiRequest(
account.getAbsoluteUrl(QString(kDirSharedItemsUrl).arg(repo_id)),
op == UPDATE_SHARE ? METHOD_POST : (op == REMOVE_SHARE ? METHOD_DELETE
: METHOD_PUT),
account.token),
group_id_(share_type == SHARE_TO_GROUP ? group_id : -1),
username_(share_type == SHARE_TO_USER ? username : QString()),
permission_(permission),
share_type_(share_type),
share_operation_(op)
{
setUrlParam("p", path);
setFormParam("permission", permission == READ_ONLY ? "r" : "rw");
bool is_add = op == ADD_SHARE;
if (is_add) {
setFormParam("share_type",
share_type == SHARE_TO_USER ? "user" : "group");
}
else {
setUrlParam("share_type",
share_type == SHARE_TO_USER ? "user" : "group");
}
if (share_type == SHARE_TO_USER) {
if (is_add) {
setFormParam("username", username);
}
else {
setUrlParam("username", username);
}
}
else {
if (is_add) {
setFormParam("group_id", QString::number(group_id));
}
else {
setUrlParam("group_id", QString::number(group_id));
}
}
}
void PrivateShareRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("PrivateShareRequest: failed to parse json:%s\n", error.text);
emit failed(ApiError::fromJsonError());
return;
}
QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
emit success();
}
FetchGroupsAndContactsRequest::FetchGroupsAndContactsRequest(
const Account& account)
: SeafileApiRequest(account.getAbsoluteUrl(kFetchGroupsAndContactsUrl),
SeafileApiRequest::METHOD_GET,
account.token)
{
}
void FetchGroupsAndContactsRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("FetchGroupsAndContactsRequest: failed to parse json:%s\n",
error.text);
emit failed(ApiError::fromJsonError());
return;
}
QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
QList<SeafileGroup> groups;
QList<SeafileContact> contacts;
json_t* groups_array = json_object_get(json.data(), "groups");
if (groups_array) {
int i, n = json_array_size(groups_array);
for (i = 0; i < n; i++) {
json_t* group_object = json_array_get(groups_array, i);
const char* name =
json_string_value(json_object_get(group_object, "name"));
int group_id =
json_integer_value(json_object_get(group_object, "id"));
if (name && group_id) {
SeafileGroup group;
group.id = group_id;
group.name = QString::fromUtf8(name);
groups.push_back(group);
}
}
}
json_t* contacts_array = json_object_get(json.data(), "contacts");
if (contacts_array) {
int i, n = json_array_size(contacts_array);
for (i = 0; i < n; i++) {
json_t* contact_object = json_array_get(contacts_array, i);
const char* email =
json_string_value(json_object_get(contact_object, "email"));
if (email) {
SeafileContact contact;
contact.email = QString::fromUtf8(email);
contact.nickname = QString::fromUtf8(
json_string_value(json_object_get(contact_object, "name")));
contacts.push_back(contact);
}
}
}
emit success(groups, contacts);
}
GetPrivateShareItemsRequest::GetPrivateShareItemsRequest(const Account& account,
const QString& repo_id,
const QString& path)
: SeafileApiRequest(
account.getAbsoluteUrl(QString(kDirSharedItemsUrl).arg(repo_id)),
SeafileApiRequest::METHOD_GET,
account.token)
{
setUrlParam("p", path);
}
void GetPrivateShareItemsRequest::requestSuccess(QNetworkReply& reply)
{
json_error_t error;
json_t* root = parseJSON(reply, &error);
if (!root) {
qWarning("GetPrivateShareItemsRequest: failed to parse json:%s\n",
error.text);
emit failed(ApiError::fromJsonError());
return;
}
QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
QList<GroupShareInfo> group_shares;
QList<UserShareInfo> user_shares;
int i, n = json_array_size(json.data());
for (i = 0; i < n; i++) {
json_t* share_info_object = json_array_get(json.data(), i);
Json share_info(share_info_object);
QString share_type = share_info.getString("share_type");
QString permission = share_info.getString("permission");
if (share_type == "group") {
// group share
Json group = share_info.getObject("group_info");
GroupShareInfo group_share;
group_share.group.id = group.getLong("id");
group_share.group.name = group.getString("name");
group_share.permission = ::permissionfromString(permission);
group_shares.push_back(group_share);
}
else if (share_type == "user") {
Json user = share_info.getObject("user_info");
UserShareInfo user_share;
user_share.user.email = user.getString("name");
user_share.user.nickname = user.getString("nickname");
user_share.permission = ::permissionfromString(permission);
user_shares.push_back(user_share);
}
}
emit success(group_shares, user_shares);
}

View file

@ -1,12 +1,13 @@
#ifndef SEAFILE_CLIENT_API_REQUESTS_H
#define SEAFILE_CLIENT_API_REQUESTS_H
#include <vector>
#include <QMap>
#include <vector>
#include "api-request.h"
#include "server-repo.h"
#include "account.h"
#include "api-request.h"
#include "contact-share-info.h"
#include "server-repo.h"
#include "server-repo.h"
class QNetworkReply;
@ -19,7 +20,8 @@ class StarredFile;
class SeafEvent;
class CommitDetails;
class PingServerRequest : public SeafileApiRequest {
class PingServerRequest : public SeafileApiRequest
{
Q_OBJECT
public:
PingServerRequest(const QUrl& serverAddr);
@ -34,7 +36,8 @@ private:
Q_DISABLE_COPY(PingServerRequest)
};
class LoginRequest : public SeafileApiRequest {
class LoginRequest : public SeafileApiRequest
{
Q_OBJECT
public:
@ -54,7 +57,8 @@ private:
};
class ListReposRequest : public SeafileApiRequest {
class ListReposRequest : public SeafileApiRequest
{
Q_OBJECT
public:
@ -71,7 +75,8 @@ private:
};
class RepoDownloadInfo {
class RepoDownloadInfo
{
public:
int repo_version;
QString relay_id;
@ -93,7 +98,8 @@ public:
bool read_only);
};
class DownloadRepoRequest : public SeafileApiRequest {
class DownloadRepoRequest : public SeafileApiRequest
{
Q_OBJECT
public:
@ -113,12 +119,16 @@ private:
bool read_only_;
};
class GetRepoRequest : public SeafileApiRequest {
class GetRepoRequest : public SeafileApiRequest
{
Q_OBJECT
public:
explicit GetRepoRequest(const Account& account, const QString &repoid);
const QString &repoid() { return repoid_; }
explicit GetRepoRequest(const Account& account, const QString& repoid);
const QString& repoid()
{
return repoid_;
}
protected slots:
void requestSuccess(QNetworkReply& reply);
@ -131,13 +141,22 @@ private:
const QString repoid_;
};
class CreateRepoRequest : public SeafileApiRequest {
class CreateRepoRequest : public SeafileApiRequest
{
Q_OBJECT
public:
CreateRepoRequest(const Account& account, const QString &name, const QString &desc, const QString &passwd);
CreateRepoRequest(const Account& account, const QString &name, const QString &desc,
int enc_version, const QString &repo_id, const QString& magic, const QString& random_key);
CreateRepoRequest(const Account& account,
const QString& name,
const QString& desc,
const QString& passwd);
CreateRepoRequest(const Account& account,
const QString& name,
const QString& desc,
int enc_version,
const QString& repo_id,
const QString& magic,
const QString& random_key);
protected slots:
void requestSuccess(QNetworkReply& reply);
@ -147,14 +166,18 @@ signals:
private:
Q_DISABLE_COPY(CreateRepoRequest)
};
class CreateSubrepoRequest : public SeafileApiRequest {
class CreateSubrepoRequest : public SeafileApiRequest
{
Q_OBJECT
public:
explicit CreateSubrepoRequest(const Account& account, const QString &name, const QString &repoid , const QString &path, const QString &passwd);
explicit CreateSubrepoRequest(const Account& account,
const QString& name,
const QString& repoid,
const QString& path,
const QString& passwd);
protected slots:
void requestSuccess(QNetworkReply& reply);
@ -164,10 +187,10 @@ signals:
private:
Q_DISABLE_COPY(CreateSubrepoRequest)
};
class GetUnseenSeahubNotificationsRequest : public SeafileApiRequest {
class GetUnseenSeahubNotificationsRequest : public SeafileApiRequest
{
Q_OBJECT
public:
@ -181,10 +204,10 @@ signals:
private:
Q_DISABLE_COPY(GetUnseenSeahubNotificationsRequest)
};
class GetDefaultRepoRequest : public SeafileApiRequest {
class GetDefaultRepoRequest : public SeafileApiRequest
{
Q_OBJECT
public:
GetDefaultRepoRequest(const Account& account);
@ -199,7 +222,8 @@ private:
Q_DISABLE_COPY(GetDefaultRepoRequest);
};
class CreateDefaultRepoRequest : public SeafileApiRequest {
class CreateDefaultRepoRequest : public SeafileApiRequest
{
Q_OBJECT
public:
CreateDefaultRepoRequest(const Account& account);
@ -214,10 +238,12 @@ private:
Q_DISABLE_COPY(CreateDefaultRepoRequest);
};
class GetLatestVersionRequest : public SeafileApiRequest {
class GetLatestVersionRequest : public SeafileApiRequest
{
Q_OBJECT
public:
GetLatestVersionRequest(const QString& client_id, const QString& client_version);
GetLatestVersionRequest(const QString& client_id,
const QString& client_version);
signals:
void success(const QString& latest_version);
@ -229,7 +255,8 @@ private:
Q_DISABLE_COPY(GetLatestVersionRequest);
};
class GetStarredFilesRequest : public SeafileApiRequest {
class GetStarredFilesRequest : public SeafileApiRequest
{
Q_OBJECT
public:
GetStarredFilesRequest(const Account& account);
@ -244,10 +271,11 @@ private:
Q_DISABLE_COPY(GetStarredFilesRequest);
};
class GetEventsRequest : public SeafileApiRequest {
class GetEventsRequest : public SeafileApiRequest
{
Q_OBJECT
public:
GetEventsRequest(const Account& account, int start=0);
GetEventsRequest(const Account& account, int start = 0);
signals:
void success(const std::vector<SeafEvent>& events, int more_offset);
@ -259,7 +287,8 @@ private:
Q_DISABLE_COPY(GetEventsRequest);
};
class GetCommitDetailsRequest : public SeafileApiRequest {
class GetCommitDetailsRequest : public SeafileApiRequest
{
Q_OBJECT
public:
GetCommitDetailsRequest(const Account& account,
@ -276,7 +305,8 @@ private:
Q_DISABLE_COPY(GetCommitDetailsRequest);
};
class FetchImageRequest : public SeafileApiRequest {
class FetchImageRequest : public SeafileApiRequest
{
Q_OBJECT
public:
FetchImageRequest(const QString& img_url);
@ -291,7 +321,8 @@ private:
Q_DISABLE_COPY(FetchImageRequest);
};
class GetAvatarRequest : public SeafileApiRequest {
class GetAvatarRequest : public SeafileApiRequest
{
Q_OBJECT
public:
GetAvatarRequest(const Account& account,
@ -301,9 +332,18 @@ public:
~GetAvatarRequest();
const QString& email() const { return email_; }
const Account& account() const { return account_; }
qint64 mtime() const { return mtime_; }
const QString& email() const
{
return email_;
}
const Account& account() const
{
return account_;
}
qint64 mtime() const
{
return mtime_;
}
signals:
void success(const QImage& avatar);
@ -314,7 +354,7 @@ protected slots:
private:
Q_DISABLE_COPY(GetAvatarRequest);
FetchImageRequest *fetch_img_req_;
FetchImageRequest* fetch_img_req_;
QString email_;
@ -323,7 +363,8 @@ private:
qint64 mtime_;
};
class SetRepoPasswordRequest : public SeafileApiRequest {
class SetRepoPasswordRequest : public SeafileApiRequest
{
Q_OBJECT
public:
SetRepoPasswordRequest(const Account& account,
@ -340,13 +381,14 @@ private:
Q_DISABLE_COPY(SetRepoPasswordRequest);
};
class ServerInfoRequest : public SeafileApiRequest {
class ServerInfoRequest : public SeafileApiRequest
{
Q_OBJECT
public:
ServerInfoRequest(const Account& account);
signals:
void success(const Account &account, const ServerInfo &info);
void success(const Account& account, const ServerInfo& info);
protected slots:
void requestSuccess(QNetworkReply& reply);
@ -356,12 +398,16 @@ private:
const Account& account_;
};
class LogoutDeviceRequest : public SeafileApiRequest {
class LogoutDeviceRequest : public SeafileApiRequest
{
Q_OBJECT
public:
LogoutDeviceRequest(const Account& account);
const Account& account() { return account_; }
const Account& account()
{
return account_;
}
signals:
void success();
@ -375,13 +421,16 @@ private:
Account account_;
};
class GetRepoTokensRequest : public SeafileApiRequest {
class GetRepoTokensRequest : public SeafileApiRequest
{
Q_OBJECT
public:
GetRepoTokensRequest(const Account& account,
const QStringList& repo_ids);
GetRepoTokensRequest(const Account& account, const QStringList& repo_ids);
const QMap<QString, QString>& repoTokens() { return repo_tokens_; }
const QMap<QString, QString>& repoTokens()
{
return repo_tokens_;
}
signals:
void success();
@ -395,13 +444,20 @@ private:
QMap<QString, QString> repo_tokens_;
};
class GetLoginTokenRequest : public SeafileApiRequest {
class GetLoginTokenRequest : public SeafileApiRequest
{
Q_OBJECT
public:
GetLoginTokenRequest(const Account& account, const QString& next_url);
const Account& account() { return account_; }
const QString& nextUrl() { return next_url_; }
const Account& account()
{
return account_;
}
const QString& nextUrl()
{
return next_url_;
}
signals:
void success(const QString& token);
@ -428,11 +484,17 @@ struct FileSearchResult {
Q_DECLARE_METATYPE(FileSearchResult)
class FileSearchRequest : public SeafileApiRequest {
class FileSearchRequest : public SeafileApiRequest
{
Q_OBJECT
public:
FileSearchRequest(const Account& account, const QString &keyword, int per_page = 10);
const QString &keyword() const { return keyword_; }
FileSearchRequest(const Account& account,
const QString& keyword,
int per_page = 10);
const QString& keyword() const
{
return keyword_;
}
signals:
void success(const std::vector<FileSearchResult>& result);
@ -446,10 +508,11 @@ private:
const QString keyword_;
};
class FetchCustomLogoRequest : public SeafileApiRequest {
class FetchCustomLogoRequest : public SeafileApiRequest
{
Q_OBJECT
public:
FetchCustomLogoRequest(const QUrl &url);
FetchCustomLogoRequest(const QUrl& url);
signals:
void success(const QUrl& url);
@ -461,12 +524,16 @@ private:
Q_DISABLE_COPY(FetchCustomLogoRequest);
};
class FetchAccountInfoRequest : public SeafileApiRequest {
class FetchAccountInfoRequest : public SeafileApiRequest
{
Q_OBJECT
public:
FetchAccountInfoRequest(const Account& account);
const Account& account() const { return account_; }
const Account& account() const
{
return account_;
}
signals:
void success(const AccountInfo& info);
@ -480,4 +547,97 @@ private:
Account account_;
};
class PrivateShareRequest : public SeafileApiRequest
{
Q_OBJECT
public:
enum ShareOperation {
ADD_SHARE,
UPDATE_SHARE,
REMOVE_SHARE,
};
PrivateShareRequest(const Account& account,
const QString& repo_id,
const QString& path,
const QString& username,
int group_id,
SharePermission permission,
ShareType share_type,
ShareOperation op);
ShareOperation shareOperation() const
{
return share_operation_;
}
int groupId() const
{
return share_type_ == SHARE_TO_GROUP ? group_id_ : -1;
};
QString userName() const
{
return share_type_ == SHARE_TO_USER ? username_ : QString();
};
SharePermission permission() const
{
return permission_;
}
ShareType shareType() const
{
return share_type_;
}
signals:
void success();
protected slots:
void requestSuccess(QNetworkReply& reply);
private:
Q_DISABLE_COPY(PrivateShareRequest);
int group_id_;
QString username_;
SharePermission permission_;
ShareType share_type_;
ShareOperation share_operation_;
};
class GetPrivateShareItemsRequest : public SeafileApiRequest
{
Q_OBJECT
public:
GetPrivateShareItemsRequest(const Account& account,
const QString& repo_id,
const QString& path);
signals:
void success(const QList<GroupShareInfo>&, const QList<UserShareInfo>&);
protected slots:
void requestSuccess(QNetworkReply& reply);
private:
Q_DISABLE_COPY(GetPrivateShareItemsRequest);
};
class FetchGroupsAndContactsRequest : public SeafileApiRequest
{
Q_OBJECT
public:
FetchGroupsAndContactsRequest(const Account& account);
signals:
void success(const QList<SeafileGroup>&, const QList<SeafileContact>&);
protected slots:
void requestSuccess(QNetworkReply& reply);
private:
Q_DISABLE_COPY(FetchGroupsAndContactsRequest);
};
#endif // SEAFILE_CLIENT_API_REQUESTS_H

View file

@ -27,6 +27,7 @@
#include "repo-service.h"
#include "rpc/local-repo.h"
#include "rpc/rpc-client.h"
#include "ui/private-share-dialog.h"
#include "file-browser-manager.h"
#include "file-browser-dialog.h"
@ -152,6 +153,8 @@ FileBrowserDialog::FileBrowserDialog(const Account &account, const ServerRepo& r
this, SLOT(onGetDirentRemove(const QList<const SeafDirent*> &)));
connect(table_view_, SIGNAL(direntShare(const SeafDirent&)),
this, SLOT(onGetDirentShare(const SeafDirent&)));
connect(table_view_, SIGNAL(direntShareToUserOrGroup(const SeafDirent&, bool)),
this, SLOT(onGetDirentShareToUserOrGroup(const SeafDirent&, bool)));
connect(table_view_, SIGNAL(direntShareSeafile(const SeafDirent&)),
this, SLOT(onGetDirentShareSeafile(const SeafDirent&)));
connect(table_view_, SIGNAL(direntUpdate(const SeafDirent&)),
@ -1014,6 +1017,15 @@ void FileBrowserDialog::onGetDirentShare(const SeafDirent& dirent)
dirent.isFile());
}
void FileBrowserDialog::onGetDirentShareToUserOrGroup(const SeafDirent& dirent,
bool to_group)
{
PrivateShareDialog dialog(account_, repo_.id, repo_.name,
::pathJoin(current_path_, dirent.name), to_group,
this);
dialog.exec();
}
void FileBrowserDialog::onGetDirentShareSeafile(const SeafDirent& dirent)
{
QString repo_id = repo_.id;

View file

@ -88,6 +88,7 @@ private slots:
void onGetDirentRemove(const SeafDirent& dirent);
void onGetDirentRemove(const QList<const SeafDirent*> &dirents);
void onGetDirentShare(const SeafDirent& dirent);
void onGetDirentShareToUserOrGroup(const SeafDirent& dirent, bool to_group);
void onGetDirentShareSeafile(const SeafDirent& dirent);
void onGetDirentUpdate(const SeafDirent& dirent);
void onGetDirentsPaste();

View file

@ -317,6 +317,14 @@ void FileTableView::setupContextMenu()
this, SLOT(onShare()));
share_action_->setShortcut(Qt::ALT + Qt::Key_G);
share_to_user_action_ = new QAction(tr("Share to a User"), this);
connect(share_to_user_action_, SIGNAL(triggered()),
this, SLOT(onShareToUser()));
share_to_group_action_ = new QAction(tr("Share to a Group"), this);
connect(share_to_group_action_, SIGNAL(triggered()),
this, SLOT(onShareToGroup()));
share_seafile_action_ = new QAction(tr("G&enerate Seafile Internal Link"), this);
connect(share_seafile_action_, SIGNAL(triggered()),
this, SLOT(onShareSeafile()));
@ -366,6 +374,8 @@ void FileTableView::setupContextMenu()
context_menu_->addAction(saveas_action_);
context_menu_->addAction(share_action_);
context_menu_->addAction(share_seafile_action_);
context_menu_->addAction(share_to_user_action_);
context_menu_->addAction(share_to_group_action_);
context_menu_->addSeparator();
context_menu_->addAction(move_action_);
context_menu_->addAction(copy_action_);
@ -469,6 +479,8 @@ void FileTableView::contextMenuEvent(QContextMenuEvent *event)
rename_action_->setVisible(false);
share_action_->setVisible(false);
share_seafile_action_->setVisible(false);
share_to_user_action_->setVisible(false);
share_to_group_action_->setVisible(false);
update_action_->setVisible(false);
cancel_download_action_->setVisible(false);
sync_subdirectory_action_->setVisible(false);
@ -513,6 +525,8 @@ void FileTableView::contextMenuEvent(QContextMenuEvent *event)
download_action_->setText(tr("&Open"));
saveas_action_->setEnabled(false);
sync_subdirectory_action_->setVisible(true);
share_to_user_action_->setVisible(true);
share_to_group_action_->setVisible(true);
} else {
if (item_->locked_by_me) {
lock_action_->setText(tr("Un&lock"));
@ -528,6 +542,8 @@ void FileTableView::contextMenuEvent(QContextMenuEvent *event)
download_action_->setText(tr("D&ownload"));
saveas_action_->setEnabled(true);
sync_subdirectory_action_->setVisible(false);
share_to_user_action_->setVisible(false);
share_to_group_action_->setVisible(false);
if (TransferManager::instance()->getDownloadTask(parent_->repo_.id,
::pathJoin(parent_->current_path_, dirent->name))) {
@ -537,6 +553,11 @@ void FileTableView::contextMenuEvent(QContextMenuEvent *event)
}
}
if (!parent_->account_.isPro()) {
share_to_user_action_->setVisible(false);
share_to_group_action_->setVisible(false);
}
context_menu_->exec(position); // synchronously
//
@ -657,6 +678,28 @@ void FileTableView::onShare()
emit direntShare(*item_);
}
void FileTableView::onShareToUser()
{
onShareToUserOrGroup(false);
}
void FileTableView::onShareToGroup()
{
onShareToUserOrGroup(true);
}
void FileTableView::onShareToUserOrGroup(bool to_group)
{
if (item_ == NULL) {
const SeafDirent *selected_item = getSelectedItemFromSource();
if (selected_item && selected_item->isDir())
emit direntShareToUserOrGroup(*selected_item, to_group);
return;
}
emit direntShareToUserOrGroup(*item_, to_group);
}
void FileTableView::onShareSeafile()
{
if (item_ == NULL) {

View file

@ -40,6 +40,7 @@ signals:
void direntRemove(const QList<const SeafDirent*> &dirents);
void direntUpdate(const SeafDirent& dirent);
void direntShare(const SeafDirent& dirent);
void direntShareToUserOrGroup(const SeafDirent& dirent, bool to_group);
void direntShareSeafile(const SeafDirent& dirent);
void direntPaste();
@ -55,6 +56,8 @@ private slots:
void onRename();
void onRemove();
void onShare();
void onShareToUser();
void onShareToGroup();
void onShareSeafile();
void onUpdate();
void onCopy();
@ -80,6 +83,7 @@ private:
void dragMoveEvent(QDragMoveEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void resizeEvent(QResizeEvent *event);
void onShareToUserOrGroup(bool to_group);
Q_DISABLE_COPY(FileTableView)
@ -93,6 +97,8 @@ private:
QAction *rename_action_;
QAction *remove_action_;
QAction *share_action_;
QAction *share_to_user_action_;
QAction *share_to_group_action_;
QAction *share_seafile_action_;
QAction *update_action_;
QAction *copy_action_;

View file

@ -0,0 +1,922 @@
#include <QComboBox>
#include <QCompleter>
#include <QPainter>
#include <QResizeEvent>
#include <QStringList>
#include "api/api-error.h"
#include "api/requests.h"
#include "private-share-dialog.h"
#include "seafile-applet.h"
#include "utils/file-utils.h"
#include "utils/utils.h"
namespace
{
enum {
COLUMN_NAME = 0,
COLUMN_PERMISSION,
MAX_COLUMN,
};
const int kPermissionColumnWidth = 150;
const int kNameColumnWidth = 300;
const int kDefaultColumnHeight = 40;
const int kIndicatorIconWidth = 10;
const int kIndicatorIconHeight = 8;
const int kMarginLeft = 2;
const int kMarginTop = 2;
const int kPadding = 2;
const int kMarginBetweenPermissionAndIndicator = 10;
const QColor kSelectedItemBackgroundcColor("#F9E0C7");
const QColor kItemBackgroundColor("white");
const QColor kItemBottomBorderColor("#f3f3f3");
const QColor kItemColor("black");
} // namespace
PrivateShareDialog::PrivateShareDialog(const Account& account,
const QString& repo_id,
const QString& repo_name,
const QString& path,
bool to_group,
QWidget* parent)
: QDialog(parent),
account_(account),
repo_id_(repo_id),
repo_name_(repo_name),
path_(path),
to_group_(to_group),
request_in_progress_(false)
{
setupUi(this);
setWindowTitle(
tr("Share %1")
.arg(path.length() <= 1 ? repo_name : ::getBaseName(path)));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
mUsername->setPlaceholderText(to_group_ ? tr("Enter the group name")
: tr("Enter the email address"));
mOkBtn->setEnabled(false);
mPermission->setCurrentIndex(0);
createTable();
fetchContacsForCompletion();
connect(mOkBtn, SIGNAL(clicked()), this, SLOT(onOkBtnClicked()));
connect(mCancelBtn, SIGNAL(clicked()), this, SLOT(reject()));
connect(table_, SIGNAL(clicked(const QModelIndex&)), mStatusText,
SLOT(clear()));
connect(mUsername, SIGNAL(textEdited(const QString&)), mStatusText,
SLOT(clear()));
connect(mUsername, SIGNAL(textEdited(const QString&)), this,
SLOT(onNameInputEdited()));
connect(model_, SIGNAL(modelReset()), this, SLOT(selectFirstRow()));
adjustSize();
disableInputs();
}
void PrivateShareDialog::selectFirstRow()
{
// for (int i = 0; i < model_->rowCount(); i++) {
// table_->openPersistentEditor(model_->index(i, COLUMN_PERMISSION));
// }
// Select the first row of the table, so that the indicator would be
// painted, to tell the user the permission is editable.
if (!table_->currentIndex().isValid()) {
table_->setCurrentIndex(model_->index(0, 0));
}
}
void PrivateShareDialog::createTable()
{
table_ = new SharedItemsTableView(this);
// table_->setEditTriggers(QAbstractItemView::AllEditTriggers);
model_ = new SharedItemsTableModel(
to_group_ ? SHARE_TO_GROUP : SHARE_TO_USER, this);
table_->setModel(model_);
QVBoxLayout* vlayout = (QVBoxLayout*)mFrame->layout();
vlayout->insertWidget(1, table_);
table_->setItemDelegate(new SharedItemDelegate(this));
connect(model_, SIGNAL(updateShareItem(int, SharePermission)), this,
SLOT(onUpdateShareItem(int, SharePermission)));
connect(model_, SIGNAL(updateShareItem(const QString&, SharePermission)),
this, SLOT(onUpdateShareItem(const QString&, SharePermission)));
connect(model_, SIGNAL(removeShareItem(int, SharePermission)), this,
SLOT(onRemoveShareItem(int, SharePermission)));
connect(model_, SIGNAL(removeShareItem(const QString&, SharePermission)),
this, SLOT(onRemoveShareItem(const QString&, SharePermission)));
}
void PrivateShareDialog::onNameInputEdited()
{
mOkBtn->setEnabled(!mUsername->text().trimmed().isEmpty());
}
void PrivateShareDialog::fetchContacsForCompletion()
{
contacts_request_.reset(new FetchGroupsAndContactsRequest(account_));
contacts_request_->send();
connect(contacts_request_.data(),
SIGNAL(success(const QList<SeafileGroup>&,
const QList<SeafileContact>&)),
this, SLOT(onFetchContactsSuccess(const QList<SeafileGroup>&,
const QList<SeafileContact>&)));
connect(contacts_request_.data(), SIGNAL(failed(const ApiError&)), this,
SLOT(onFetchContactsFailed(const ApiError&)));
}
void PrivateShareDialog::onUpdateShareItem(int group_id,
SharePermission permission)
{
request_.reset(new PrivateShareRequest(account_, repo_id_, path_, QString(),
group_id, permission, SHARE_TO_GROUP,
PrivateShareRequest::UPDATE_SHARE));
connect(request_.data(), SIGNAL(success()), this,
SLOT(onUpdateShareSuccess()));
connect(request_.data(), SIGNAL(failed(const ApiError&)), this,
SLOT(onUpdateShareFailed(const ApiError&)));
// disableInputs();
request_in_progress_ = true;
request_->send();
}
void PrivateShareDialog::onUpdateShareItem(const QString& email,
SharePermission permission)
{
request_.reset(new PrivateShareRequest(account_, repo_id_, path_, email, 0,
permission, SHARE_TO_USER,
PrivateShareRequest::UPDATE_SHARE));
connect(request_.data(), SIGNAL(success()), this,
SLOT(onUpdateShareSuccess()));
connect(request_.data(), SIGNAL(failed(const ApiError&)), this,
SLOT(onUpdateShareFailed(const ApiError&)));
// disableInputs();
request_in_progress_ = true;
request_->send();
}
void PrivateShareDialog::onUpdateShareSuccess()
{
request_in_progress_ = false;
// seafApplet->messageBox(tr("Shared successfully"), this);
if (to_group_) {
GroupShareInfo info;
info.group.id = request_.data()->groupId();
info.group.name = group_id_map_[info.group.id];
info.permission = request_.data()->permission();
model_->addNewShareInfo(info);
}
else {
UserShareInfo info;
info.user.email = request_.data()->userName();
info.permission = request_.data()->permission();
model_->addNewShareInfo(info);
}
model_->shareOperationSuccess();
// enableInputs();
mStatusText->setText(tr("Updated successfully"));
}
void PrivateShareDialog::onUpdateShareFailed(const ApiError& error)
{
// enableInputs();
request_in_progress_ = false;
showWarning(tr("Share Operation Failed: %1").arg(error.toString()));
model_->shareOperationFailed(request_->shareOperation());
}
void PrivateShareDialog::onRemoveShareItem(int group_id,
SharePermission permission)
{
request_.reset(new PrivateShareRequest(account_, repo_id_, path_, QString(),
group_id, permission, SHARE_TO_GROUP,
PrivateShareRequest::REMOVE_SHARE));
connect(request_.data(), SIGNAL(success()), this,
SLOT(onRemoveShareSuccess()));
connect(request_.data(), SIGNAL(failed(const ApiError&)), this,
SLOT(onRemoveShareFailed(const ApiError&)));
// disableInputs();
request_in_progress_ = true;
request_->send();
}
void PrivateShareDialog::onRemoveShareSuccess()
{
// enableInputs();
request_in_progress_ = false;
model_->shareOperationSuccess();
mStatusText->setText(tr("Removed successfully"));
}
void PrivateShareDialog::onRemoveShareFailed(const ApiError& error)
{
request_in_progress_ = false;
showWarning(tr("Share Operation Failed: %1").arg(error.toString()));
model_->shareOperationFailed(request_->shareOperation());
// enableInputs();
}
void PrivateShareDialog::onRemoveShareItem(const QString& email,
SharePermission permission)
{
request_.reset(new PrivateShareRequest(account_, repo_id_, path_, email, 0,
permission, SHARE_TO_USER,
PrivateShareRequest::REMOVE_SHARE));
connect(request_.data(), SIGNAL(success()), this,
SLOT(onRemoveShareSuccess()));
connect(request_.data(), SIGNAL(failed(const ApiError&)), this,
SLOT(onRemoveShareFailed(const ApiError&)));
// disableInputs();
request_in_progress_ = true;
request_->send();
}
void PrivateShareDialog::onFetchContactsSuccess(
const QList<SeafileGroup>& groups, const QList<SeafileContact>& contacts)
{
QStringList candidates;
if (to_group_) {
foreach (const SeafileGroup& group, groups) {
candidates << group.name;
group_id_map_[group.id] = group.name;
}
}
else {
foreach (const SeafileContact& contact, contacts) {
candidates << contact.email;
}
}
if (!candidates.isEmpty()) {
completer_.reset(new QCompleter(candidates));
mUsername->setCompleter(completer_.data());
}
get_shared_items_request_.reset(
new GetPrivateShareItemsRequest(account_, repo_id_, path_));
connect(get_shared_items_request_.data(),
SIGNAL(success(const QList<GroupShareInfo>&,
const QList<UserShareInfo>&)),
this, SLOT(onGetSharedItemsSuccess(const QList<GroupShareInfo>&,
const QList<UserShareInfo>&)));
connect(get_shared_items_request_.data(), SIGNAL(failed(const ApiError&)),
this, SLOT(onGetSharedItemsFailed(const ApiError&)));
get_shared_items_request_->send();
}
void PrivateShareDialog::onGetSharedItemsSuccess(
const QList<GroupShareInfo>& group_shares,
const QList<UserShareInfo>& user_shares)
{
model_->setShareInfo(group_shares, user_shares);
selectFirstRow();
enableInputs();
}
void PrivateShareDialog::onGetSharedItemsFailed(const ApiError& error)
{
showWarning(tr("Failed to get share information of the folder"));
reject();
}
void PrivateShareDialog::onFetchContactsFailed(const ApiError& error)
{
showWarning(tr("Failed to get your groups and contacts information"));
reject();
}
SharePermission PrivateShareDialog::currentPermission()
{
return mPermission->currentIndex() == 0 ? READ_WRITE : READ_ONLY;
}
bool PrivateShareDialog::validateInputs()
{
QString name = mUsername->text().trimmed();
if (name.isEmpty()) {
showWarning(to_group_ ? tr("Please enter the username")
: tr("Please enter the group name"));
return false;
}
SharePermission permission = currentPermission();
if (to_group_) {
QList<int> ids = group_id_map_.keys(name);
if (ids.isEmpty()) {
showWarning(tr("No such group \"%1\"").arg(name));
return false;
}
int group_id = ids[0];
if (model_->shareExists(group_id)) {
GroupShareInfo info = model_->shareInfo(group_id);
if (info.permission == permission) {
showWarning(tr("Already shared to group %1").arg(name));
}
return false;
}
}
else {
if (model_->shareExists(name)) {
UserShareInfo info = model_->shareInfo(name);
if (info.permission == permission) {
showWarning(tr("Already shared to user %1").arg(name));
return false;
}
}
}
return true;
}
void PrivateShareDialog::onOkBtnClicked()
{
if (!validateInputs()) {
return;
}
if (request_in_progress_) {
showWarning(tr("The previous operation is still in progres"));
return;
}
// disableInputs();
QString username;
int group_id = 0;
QString name = mUsername->text().trimmed();
if (to_group_) {
group_id = group_id_map_.keys(name)[0];
}
else {
username = name;
}
request_.reset(new PrivateShareRequest(
account_, repo_id_, path_, username, group_id, currentPermission(),
to_group_ ? SHARE_TO_GROUP : SHARE_TO_USER,
PrivateShareRequest::ADD_SHARE));
connect(request_.data(), SIGNAL(success()), this, SLOT(onShareSuccess()));
connect(request_.data(), SIGNAL(failed(const ApiError&)), this,
SLOT(onShareFailed(const ApiError&)));
request_in_progress_ = true;
request_->send();
if (to_group_) {
GroupShareInfo info;
info.group.id = group_id;
info.group.name = name;
info.permission = currentPermission();
model_->addNewShareInfo(info);
}
else {
UserShareInfo info;
info.user.email = name;
info.permission = currentPermission();
model_->addNewShareInfo(info);
}
}
void PrivateShareDialog::disableInputs()
{
toggleInputs(false);
}
void PrivateShareDialog::enableInputs()
{
toggleInputs(true);
}
void PrivateShareDialog::toggleInputs(bool enabled)
{
mUsername->setEnabled(enabled);
mOkBtn->setEnabled(enabled);
mCancelBtn->setEnabled(enabled);
mPermission->setEnabled(enabled);
}
void PrivateShareDialog::onShareSuccess()
{
// seafApplet->messageBox(tr("Shared successfully"), this);
request_in_progress_ = false;
model_->shareOperationSuccess();
// enableInputs();
mStatusText->setText(tr("Shared successfully"));
}
void PrivateShareDialog::onShareFailed(const ApiError& error)
{
request_in_progress_ = false;
// enableInputs();
model_->shareOperationFailed(PrivateShareRequest::ADD_SHARE);
showWarning(tr("Share Operation Failed: %1").arg(error.toString()));
}
void PrivateShareDialog::showWarning(const QString& msg)
{
seafApplet->warningBox(msg, this);
}
SharedItemsHeadView::SharedItemsHeadView(QWidget* parent)
: QHeaderView(Qt::Horizontal, parent)
{
setDefaultAlignment(Qt::AlignLeft);
setStretchLastSection(false);
setCascadingSectionResizes(true);
setHighlightSections(false);
setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
setSectionResizeMode(QHeaderView::ResizeToContents);
#else
setResizeMode(QHeaderView::ResizeToContents);
#endif
}
QSize SharedItemsHeadView::sectionSizeFromContents(int index) const
{
QSize size = QHeaderView::sectionSizeFromContents(index);
SharedItemsTableView* table = (SharedItemsTableView*)parent();
SharedItemsTableModel* model =
(SharedItemsTableModel*)(table->sourceModel());
if (model) {
size.setWidth(index == COLUMN_NAME ? model->nameColumnWidth()
: kPermissionColumnWidth);
}
return size;
}
SharedItemsTableView::SharedItemsTableView(QWidget* parent)
: QTableView(parent), source_model_(0)
{
setHorizontalHeader(new SharedItemsHeadView(this));
verticalHeader()->hide();
setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QAbstractItemView::SingleSelection);
setMouseTracking(true);
setShowGrid(false);
setContentsMargins(0, 5, 0, 5);
// setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}
void SharedItemsTableView::setModel(QAbstractItemModel* model)
{
QTableView::setModel(model);
source_model_ = qobject_cast<SharedItemsTableModel*>(model);
}
void SharedItemsTableView::resizeEvent(QResizeEvent* event)
{
QTableView::resizeEvent(event);
if (source_model_)
source_model_->onResize(event->size());
}
SharedItemsTableModel::SharedItemsTableModel(ShareType share_type,
QObject* parent)
: QAbstractTableModel(parent),
share_type_(share_type),
name_column_width_(kNameColumnWidth)
{
}
int SharedItemsTableModel::columnCount(const QModelIndex& parent) const
{
return MAX_COLUMN;
}
int SharedItemsTableModel::rowCount(const QModelIndex& parent) const
{
return share_type_ == SHARE_TO_USER ? user_shares_.size()
: group_shares_.size();
}
QVariant SharedItemsTableModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid()) {
return QVariant();
}
if (role != Qt::DisplayRole && role != Qt::EditRole &&
role != Qt::SizeHintRole) {
return QVariant();
}
int column = index.column();
if (role == Qt::EditRole && column != COLUMN_PERMISSION) {
return QVariant();
}
if (role == Qt::SizeHintRole) {
QSize qsize(0, kDefaultColumnHeight);
if (column == COLUMN_NAME) {
qsize.setWidth(name_column_width_);
}
else {
qsize.setWidth(kPermissionColumnWidth);
}
return qsize;
}
if (isGroupShare()) {
if (index.row() >= group_shares_.size()) {
return QVariant();
}
const GroupShareInfo& info = group_shares_[index.row()];
if (column == COLUMN_NAME) {
return info.group.name;
}
else if (column == COLUMN_PERMISSION) {
if (role == Qt::DisplayRole) {
return info.permission == READ_WRITE ? tr("Read Write")
: tr("Read Only");
}
else {
return info.permission == READ_WRITE ? 0 : 1;
}
}
}
else {
if (index.row() >= user_shares_.size()) {
return QVariant();
}
const UserShareInfo& info = user_shares_[index.row()];
if (column == COLUMN_NAME) {
return info.user.email;
}
else if (column == COLUMN_PERMISSION) {
if (role == Qt::DisplayRole) {
return info.permission == READ_WRITE ? tr("Read Write")
: tr("Read Only");
}
else {
return info.permission == READ_WRITE ? 0 : 1;
}
}
}
return QVariant();
}
void SharedItemsTableModel::onResize(const QSize& size)
{
name_column_width_ = size.width() - kPermissionColumnWidth;
if (rowCount() == 0) {
emit dataChanged(index(0, COLUMN_NAME),
index(rowCount() - 1, COLUMN_NAME));
}
}
bool SharedItemsTableModel::isGroupShare() const
{
return share_type_ == SHARE_TO_GROUP;
}
QVariant SharedItemsTableModel::headerData(int section,
Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Vertical) {
return QVariant();
}
if (section == COLUMN_NAME) {
if (role == Qt::DisplayRole) {
return isGroupShare() ? tr("Group") : tr("User");
}
}
else if (section == COLUMN_PERMISSION) {
if (role == Qt::DisplayRole) {
return tr("Permission");
}
}
return QVariant();
}
void SharedItemsTableModel::setShareInfo(
const QList<GroupShareInfo>& group_shares,
const QList<UserShareInfo>& user_shares)
{
beginResetModel();
group_shares_ = group_shares;
user_shares_ = user_shares;
endResetModel();
}
void SharedItemsTableModel::addNewShareInfo(UserShareInfo newinfo)
{
previous_user_shares_ = user_shares_;
beginResetModel();
bool exists;
for (int i = 0; i < user_shares_.size(); i++) {
UserShareInfo& info = user_shares_[i];
if (info.user.email == newinfo.user.email) {
exists = true;
info.permission = newinfo.permission;
}
}
if (!exists) {
user_shares_.prepend(newinfo);
}
endResetModel();
}
void SharedItemsTableModel::addNewShareInfo(GroupShareInfo newinfo)
{
previous_group_shares_ = group_shares_;
beginResetModel();
bool exists;
for (int i = 0; i < group_shares_.size(); i++) {
GroupShareInfo& info = group_shares_[i];
if (info.group.id == newinfo.group.id) {
exists = true;
info.permission = newinfo.permission;
}
}
if (!exists) {
group_shares_.prepend(newinfo);
}
endResetModel();
}
bool SharedItemsTableModel::shareExists(int group_id)
{
foreach (const GroupShareInfo& info, group_shares_) {
if (info.group.id == group_id) {
return true;
}
}
return false;
}
bool SharedItemsTableModel::shareExists(const QString& email)
{
foreach (const UserShareInfo& info, user_shares_) {
if (info.user.email == email) {
return true;
}
}
return false;
}
GroupShareInfo SharedItemsTableModel::shareInfo(int group_id)
{
foreach (const GroupShareInfo& info, group_shares_) {
if (info.group.id == group_id) {
return info;
}
}
return GroupShareInfo();
}
UserShareInfo SharedItemsTableModel::shareInfo(const QString& email)
{
foreach (const UserShareInfo& info, user_shares_) {
if (info.user.email == email) {
return info;
}
}
return UserShareInfo();
}
Qt::ItemFlags SharedItemsTableModel::flags(const QModelIndex& index) const
{
if (!index.isValid())
return Qt::ItemIsEnabled;
if (index.column() == COLUMN_PERMISSION) {
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}
else {
return QAbstractItemModel::flags(index);
}
}
bool SharedItemsTableModel::removeRows(int row,
int count,
const QModelIndex& parent)
{
beginRemoveRows(parent, row, row);
if (isGroupShare()) {
group_shares_.removeAt(row);
}
else {
user_shares_.removeAt(row);
}
endRemoveRows();
return true;
}
bool SharedItemsTableModel::setData(const QModelIndex& index,
const QVariant& value,
int role)
{
PrivateShareDialog* dialog = (PrivateShareDialog*)parent();
if (dialog->requestInProgress()) {
dialog->showWarning(tr("The previous operation is still in progres"));
return false;
}
if (!index.isValid() || role != Qt::EditRole) {
return false;
}
int permission = value.toInt();
int row = index.row();
if (isGroupShare()) {
previous_group_shares_ = group_shares_;
GroupShareInfo& info = group_shares_[row];
if (permission == 3) {
emit removeShareItem(info.group.id, info.permission);
removed_group_share_ = info;
removeRows(row, 1);
}
else if (permission == info.permission) {
}
else {
emit updateShareItem(info.group.id, (SharePermission)permission);
info.permission =
info.permission == READ_ONLY ? READ_WRITE : READ_ONLY;
emit dataChanged(index, index);
}
}
else {
previous_user_shares_ = user_shares_;
UserShareInfo& info = user_shares_[row];
if (permission == 3) {
emit removeShareItem(info.user.email, info.permission);
removed_user_share_ = info;
removeRows(row, 1);
}
else if (permission == info.permission) {
}
else {
emit updateShareItem(info.user.email, (SharePermission)permission);
info.permission =
info.permission == READ_ONLY ? READ_WRITE : READ_ONLY;
emit dataChanged(index, index);
}
}
return true;
}
void SharedItemsTableModel::shareOperationSuccess()
{
}
void SharedItemsTableModel::shareOperationFailed(
PrivateShareRequest::ShareOperation op)
{
beginResetModel();
if (isGroupShare()) {
group_shares_ = previous_group_shares_;
}
else {
user_shares_ = previous_user_shares_;
}
endResetModel();
}
SharedItemDelegate::SharedItemDelegate(QObject* parent)
: QStyledItemDelegate(parent)
{
}
QWidget* SharedItemDelegate::createEditor(QWidget* parent,
const QStyleOptionViewItem& option,
const QModelIndex& index) const
{
QComboBox* combobox = new QComboBox(parent);
combobox->addItem(tr("Read Write"));
combobox->addItem(tr("Read Only"));
combobox->insertSeparator(2);
combobox->addItem(tr("Remove Share"));
return combobox;
}
void SharedItemDelegate::setEditorData(QWidget* editor,
const QModelIndex& index) const
{
int value = index.model()->data(index, Qt::EditRole).toInt();
QComboBox* combobox = static_cast<QComboBox*>(editor);
combobox->setCurrentIndex(value);
}
void SharedItemDelegate::setModelData(QWidget* editor,
QAbstractItemModel* model,
const QModelIndex& index) const
{
QComboBox* combobox = static_cast<QComboBox*>(editor);
model->setData(index, combobox->currentIndex(), Qt::EditRole);
}
void SharedItemDelegate::updateEditorGeometry(
QWidget* editor,
const QStyleOptionViewItem& option,
const QModelIndex& index) const
{
QComboBox* combobox = static_cast<QComboBox*>(editor);
combobox->setGeometry(option.rect);
// combobox->showPopup();
}
void SharedItemDelegate::paint(QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const
{
const SharedItemsTableModel* model =
static_cast<const SharedItemsTableModel*>(index.model());
QRect option_rect = option.rect;
bool selected = false;
// draw item's background
painter->save();
if (option.state & QStyle::State_Selected) {
painter->fillRect(option_rect, kSelectedItemBackgroundcColor);
selected = true;
}
else
painter->fillRect(option_rect, kItemBackgroundColor);
painter->restore();
// draw item's border for the first row only
static const QPen borderPen(kItemBottomBorderColor, 1);
// if (index.row() == 0) {
// painter->save();
// painter->setPen(borderPen);
// painter->drawLine(option_rect.topLeft(), option_rect.topRight());
// painter->restore();
// }
// draw item's border under the bottom
painter->save();
painter->setPen(borderPen);
painter->drawLine(option_rect.bottomLeft(), option_rect.bottomRight());
painter->restore();
QPoint text_pos(kMarginLeft + kPadding, kMarginTop + kPadding);
text_pos += option.rect.topLeft();
QSize size = model->data(index, Qt::SizeHintRole).value<QSize>();
QString text = model->data(index, Qt::DisplayRole).value<QString>();
QFont font = model->data(index, Qt::FontRole).value<QFont>();
QRect text_rect(text_pos, size);
painter->save();
painter->setPen(kItemColor);
painter->setFont(font);
painter->drawText(text_rect,
Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, text,
&text_rect);
painter->restore();
if (selected && index.column() == COLUMN_PERMISSION) {
int h = option.rect.height();
QPoint indicator_pos = option.rect.bottomRight() -
QPoint(40, h - (h - kIndicatorIconHeight) / 2);
indicator_pos.setX(text_rect.topRight().x() +
kMarginBetweenPermissionAndIndicator);
QRect indicator_rect(indicator_pos,
QSize(kIndicatorIconWidth, kIndicatorIconHeight));
QPainterPath path;
path.moveTo(indicator_rect.topLeft());
path.lineTo(indicator_rect.topRight());
path.lineTo(indicator_rect.bottomRight() -
QPoint((indicator_rect.width() / 2), 0));
path.lineTo(indicator_rect.topLeft());
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
painter->setRenderHint(QPainter::HighQualityAntialiasing);
painter->fillPath(path, QBrush(kItemColor));
painter->restore();
}
}

View file

@ -0,0 +1,220 @@
#ifndef SEAFILE_CLIENT_UI_PRIVATE_SHARE_DIALOG_H
#define SEAFILE_CLIENT_UI_PRIVATE_SHARE_DIALOG_H
#include <QUrl>
#include <QAbstractTableModel>
#include <QCompleter>
#include <QDialog>
#include <QHash>
#include <QScopedPointer>
#include <QStringList>
#include <QStyledItemDelegate>
#include <QTableView>
#include "ui_private-share-dialog.h"
#include "account.h"
#include "api/contact-share-info.h"
#include "api/requests.h"
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
// only available in qt 5.0+
#define Q_DECL_OVERRIDE
#endif
class QResizeEvent;
class SharedItemsTableView;
class SharedItemsTableModel;
class PrivateShareDialog : public QDialog, public Ui::PrivateShareDialog
{
Q_OBJECT
public:
PrivateShareDialog(const Account& account,
const QString& repo_id,
const QString& repo_name,
const QString& path,
bool to_group,
QWidget* parent);
bool requestInProgress() const
{
return request_in_progress_;
}
void showWarning(const QString& msg);
public slots:
void onUpdateShareItem(int group_id, SharePermission permission);
void onUpdateShareItem(const QString& email, SharePermission permission);
void onRemoveShareItem(int group_id, SharePermission permission);
void onRemoveShareItem(const QString& email, SharePermission permission);
private slots:
void selectFirstRow();
void onNameInputEdited();
void onShareSuccess();
void onShareFailed(const ApiError& error);
void onUpdateShareSuccess();
void onUpdateShareFailed(const ApiError& error);
void onRemoveShareSuccess();
void onRemoveShareFailed(const ApiError& error);
void onFetchContactsSuccess(const QList<SeafileGroup>& groups,
const QList<SeafileContact>& contacts);
void onFetchContactsFailed(const ApiError& error);
void onOkBtnClicked();
void onGetSharedItemsSuccess(const QList<GroupShareInfo>& group_shares,
const QList<UserShareInfo>& user_shares);
void onGetSharedItemsFailed(const ApiError& error);
private:
void createTable();
void fetchContacsForCompletion();
bool validateInputs();
void toggleInputs(bool enabled);
void enableInputs();
void disableInputs();
SharePermission currentPermission();
Account account_;
QString repo_id_;
QString repo_name_;
QString path_;
bool to_group_;
QHash<int, QString> group_id_map_;
SharedItemsTableView* table_;
SharedItemsTableModel* model_;
QScopedPointer<PrivateShareRequest> request_;
QScopedPointer<FetchGroupsAndContactsRequest> contacts_request_;
QScopedPointer<GetPrivateShareItemsRequest> get_shared_items_request_;
QScopedPointer<QCompleter> completer_;
bool request_in_progress_;
};
class SharedItemsHeadView : public QHeaderView
{
Q_OBJECT
public:
SharedItemsHeadView(QWidget* parent = 0);
QSize sectionSizeFromContents(int index) const Q_DECL_OVERRIDE;
};
class SharedItemsTableView : public QTableView
{
Q_OBJECT
public:
SharedItemsTableView(QWidget* parent = 0);
void resizeEvent(QResizeEvent* event) Q_DECL_OVERRIDE;
void setModel(QAbstractItemModel* model) Q_DECL_OVERRIDE;
SharedItemsTableModel* sourceModel()
{
return source_model_;
}
private:
SharedItemsTableModel* source_model_;
};
class SharedItemsTableModel : public QAbstractTableModel
{
Q_OBJECT
public:
SharedItemsTableModel(ShareType share_type, QObject* parent = 0);
void setShareInfo(const QList<GroupShareInfo>& group_shares,
const QList<UserShareInfo>& user_shares);
void addNewShareInfo(UserShareInfo info);
void addNewShareInfo(GroupShareInfo info);
bool shareExists(int group_id);
bool shareExists(const QString& email);
GroupShareInfo shareInfo(int group_id);
UserShareInfo shareInfo(const QString& email);
void shareOperationSuccess();
void shareOperationFailed(PrivateShareRequest::ShareOperation op);
int rowCount(const QModelIndex& parent = QModelIndex()) const
Q_DECL_OVERRIDE;
int columnCount(const QModelIndex& parent = QModelIndex()) const
Q_DECL_OVERRIDE;
QVariant data(const QModelIndex& index,
int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex& index) const Q_DECL_OVERRIDE;
bool setData(const QModelIndex& index,
const QVariant& value,
int role) Q_DECL_OVERRIDE;
bool removeRows(int row,
int count,
const QModelIndex& parent = QModelIndex()) Q_DECL_OVERRIDE;
QVariant headerData(int section,
Qt::Orientation orientation,
int role) const Q_DECL_OVERRIDE;
int nameColumnWidth() const
{
return name_column_width_;
}
signals:
void updateShareItem(int group_id, SharePermission permission);
void updateShareItem(const QString& email, SharePermission permission);
void removeShareItem(int group_id, SharePermission permission);
void removeShareItem(const QString& email, SharePermission permission);
public slots:
void onResize(const QSize& size);
private:
bool isGroupShare() const;
QList<UserShareInfo> user_shares_, previous_user_shares_;
QList<GroupShareInfo> group_shares_, previous_group_shares_;
ShareType share_type_;
int name_column_width_;
GroupShareInfo removed_group_share_;
UserShareInfo removed_user_share_;
};
class SharedItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
SharedItemDelegate(QObject* parent = 0);
QWidget* createEditor(QWidget* parent,
const QStyleOptionViewItem& option,
const QModelIndex& index) const Q_DECL_OVERRIDE;
void setEditorData(QWidget* editor,
const QModelIndex& index) const Q_DECL_OVERRIDE;
void setModelData(QWidget* editor,
QAbstractItemModel* model,
const QModelIndex& index) const Q_DECL_OVERRIDE;
void updateEditorGeometry(QWidget* editor,
const QStyleOptionViewItem& option,
const QModelIndex& index) const Q_DECL_OVERRIDE;
void paint(QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const Q_DECL_OVERRIDE;
};
#endif // SEAFILE_CLIENT_UI_PRIVATE_SHARE_DIALOG_H

View file

@ -8,18 +8,40 @@ Json::Json(const json_t *root)
QString Json::getString(const char *key) const
{
if (!json_) {
return QString();
}
return QString::fromUtf8(json_string_value(json_object_get(json_, key)));
}
qint64 Json::getLong(const char *key) const
{
if (!json_) {
return 0;
}
return json_integer_value(json_object_get(json_, key));
}
bool Json::getBool(const char *key) const
{
if (!json_) {
return false;
}
json_t *value = json_object_get(json_, key);
if (json_is_false(value))
return false;
return json_is_true(value) || json_integer_value(value);
}
Json Json::getObject(const char *key) const
{
if (!json_) {
return Json();
}
json_t *object = json_object_get(json_, key);
if (json_is_object(object))
return Json(object);
return Json();
}

View file

@ -6,11 +6,12 @@
// A convenient class to access jasson `json_t` struct
class Json {
public:
Json(const json_t *root);
Json(const json_t *root = 0);
QString getString(const char *name) const;
qint64 getLong(const char *name) const;
bool getBool(const char *name) const;
Json getObject(const char *name) const;
private:
const json_t *json_;

114
ui/private-share-dialog.ui Normal file
View file

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PrivateShareDialog</class>
<widget class="QDialog" name="PrivateShareDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>455</width>
<height>155</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QFrame" name="mFrame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Share To:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="mUsername"/>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="mOkBtn">
<property name="text">
<string>Share</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Permission:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="mPermission">
<item>
<property name="text">
<string>Read-Write</string>
</property>
</item>
<item>
<property name="text">
<string>Read-Only</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
</layout>
<zorder>mOkBtn</zorder>
<zorder>mOkBtn</zorder>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="mStatusText">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="mCancelBtn">
<property name="text">
<string>Done</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>