Merge pull request #1492 from owncloud/federated_sharing

Create federated shares
This commit is contained in:
David A. Velasco 2016-03-16 14:03:36 +01:00
commit add4b81e9f
8 changed files with 147 additions and 85 deletions

@ -1 +1 @@
Subproject commit 1007a80534827479b0874ae942c8c7dbe87cac35
Subproject commit 996660b88c4e2b3cef08604963cf2c29491efa1b

View file

@ -388,6 +388,8 @@
<string name="search_users_and_groups_hint">Search users and groups</string>
<string name="share_group_clarification">%1$s (group)</string>
<string name="share_remote_clarification">%1$s (remote)</string>
<string name="share_known_remote_clarification">%1$s ( at %2$s )</string>
<string name="share_sharee_unavailable">Sorry, your server version does not allow share with users within clients.
\nPlease contact your administrator</string>

View file

@ -1525,6 +1525,7 @@ public class FileDataStorageManager {
getContentResolver().applyBatch(MainApp.getAuthority(), operations);
} else {
getContentProviderClient().applyBatch(operations);
}
@ -1625,10 +1626,12 @@ public class FileDataStorageManager {
String where = ProviderTableMeta.OCSHARES_PATH + "=?" + " AND "
+ ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?"+ "AND"
+ " (" + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? OR "
+ ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? ) ";
+ ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? OR "
+ ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? ) ";
String [] whereArgs = new String[]{ filePath, accountName ,
Integer.toString(ShareType.USER.getValue()),
Integer.toString(ShareType.GROUP.getValue()) };
Integer.toString(ShareType.GROUP.getValue()),
Integer.toString(ShareType.FEDERATED.getValue())};
Cursor c = null;
if (getContentResolver() != null) {

View file

@ -60,7 +60,8 @@ public class CreateShareWithShareeOperation extends SyncOperation {
* https://doc.owncloud.org/server/8.2/developer_manual/core/ocs-share-api.html .
*/
public CreateShareWithShareeOperation(String path, String shareeName, ShareType shareType, int permissions) {
if (!ShareType.USER.equals(shareType) && !ShareType.GROUP.equals(shareType)) {
if (!ShareType.USER.equals(shareType) && !ShareType.GROUP.equals(shareType)
&& !ShareType.FEDERATED.equals(shareType)) {
throw new IllegalArgumentException("Illegal share type " + shareType);
}
mPath = path;

View file

@ -75,10 +75,11 @@ public class UnshareOperation extends SyncOperation {
if (result.isSuccess()) {
Log_OC.d(TAG, "Share id = " + share.getRemoteId() + " deleted");
if (mShareType == ShareType.PUBLIC_LINK) {
if (ShareType.PUBLIC_LINK.equals(mShareType)) {
file.setShareViaLink(false);
file.setPublicLink("");
} else if (mShareType == ShareType.USER || mShareType == ShareType.GROUP){
} else if (ShareType.USER.equals(mShareType) || ShareType.GROUP.equals(mShareType)
|| ShareType.FEDERATED.equals(mShareType)){
// Check if it is the last share
ArrayList <OCShare> sharesWith = getStorageManager().
getSharesWithForAFile(mRemotePath,

View file

@ -1,21 +1,21 @@
/**
* ownCloud Android client application
*
* @author David A. Velasco
* Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ownCloud Android client application
*
* @author David A. Velasco
* @author Juan Carlos González Cabrero
* Copyright (C) 2015 ownCloud Inc.
* <p/>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
* <p/>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* <p/>
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@ -37,15 +37,18 @@ import android.widget.Toast;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AccountUtils;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.shares.GetRemoteShareesOperation;
import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.utils.ErrorMessageAdapter;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@ -58,9 +61,9 @@ public class UsersAndGroupsSearchProvider extends ContentProvider {
private static final String TAG = UsersAndGroupsSearchProvider.class.getSimpleName();
private static final String[] COLUMNS = {
BaseColumns._ID,
SearchManager.SUGGEST_COLUMN_TEXT_1,
SearchManager.SUGGEST_COLUMN_INTENT_DATA
BaseColumns._ID,
SearchManager.SUGGEST_COLUMN_TEXT_1,
SearchManager.SUGGEST_COLUMN_INTENT_DATA
};
private static final int SEARCH = 1;
@ -70,11 +73,29 @@ public class UsersAndGroupsSearchProvider extends ContentProvider {
public static final String AUTHORITY = UsersAndGroupsSearchProvider.class.getCanonicalName();
public static final String ACTION_SHARE_WITH = AUTHORITY + ".action.SHARE_WITH";
public static final String CONTENT = "content";
public static final String DATA_USER = AUTHORITY + ".data.user";
public static final String DATA_GROUP = AUTHORITY + ".data.group";
public static final String DATA_REMOTE = AUTHORITY + ".data.remote";
private UriMatcher mUriMatcher;
private static HashMap<String, ShareType> sShareTypes;
static {
sShareTypes = new HashMap<>();
sShareTypes.put(DATA_USER, ShareType.USER);
sShareTypes.put(DATA_GROUP, ShareType.GROUP);
sShareTypes.put(DATA_REMOTE, ShareType.FEDERATED);
}
public static ShareType getShareType(String authority) {
return sShareTypes.get(authority);
}
@Nullable
@Override
public String getType(Uri uri) {
@ -91,7 +112,7 @@ public class UsersAndGroupsSearchProvider extends ContentProvider {
/**
* TODO description
*
* <p/>
* Reference: http://developer.android.com/guide/topics/search/adding-custom-suggestions.html#CustomContentProvider
*
* @param uri Content {@link Uri}, formattted as
@ -101,7 +122,7 @@ public class UsersAndGroupsSearchProvider extends ContentProvider {
* @param selection Expected to be NULL.
* @param selectionArgs Expected to be NULL.
* @param sortOrder Expected to be NULL.
* @return Cursor with users and groups in the ownCloud server that match 'userQuery'.
* @return Cursor with users and groups in the ownCloud server that match 'userQuery'.
*/
@Nullable
@Override
@ -148,31 +169,52 @@ public class UsersAndGroupsSearchProvider extends ContentProvider {
if (names.size() > 0) {
response = new MatrixCursor(COLUMNS);
Iterator<JSONObject> namesIt = names.iterator();
int count = 0;
JSONObject item;
String displayName;
Uri dataUri;
Uri userBaseUri = new Uri.Builder().scheme("content").authority(DATA_USER).build();
Uri groupBaseUri = new Uri.Builder().scheme("content").authority(DATA_GROUP).build();
String displayName = null;
Uri dataUri = null;
int count = 0;
Uri userBaseUri = new Uri.Builder().scheme(CONTENT).authority(DATA_USER).build();
Uri groupBaseUri = new Uri.Builder().scheme(CONTENT).authority(DATA_GROUP).build();
Uri remoteBaseUri = new Uri.Builder().scheme(CONTENT).authority(DATA_REMOTE).build();
FileDataStorageManager manager = new FileDataStorageManager(account, getContext().getContentResolver());
boolean federatedShareAllowed = manager.getCapability(account.name).getFilesSharingFederationOutgoing()
.isTrue();
try {
while (namesIt.hasNext()) {
item = namesIt.next();
String userName = item.getString(GetRemoteShareesOperation.PROPERTY_LABEL);
JSONObject value = item.getJSONObject(GetRemoteShareesOperation.NODE_VALUE);
byte type = (byte) value.getInt(GetRemoteShareesOperation.PROPERTY_SHARE_TYPE);
int type = value.getInt(GetRemoteShareesOperation.PROPERTY_SHARE_TYPE);
String shareWith = value.getString(GetRemoteShareesOperation.PROPERTY_SHARE_WITH);
if (GetRemoteShareesOperation.GROUP_TYPE.equals(type)) {
if (ShareType.GROUP.getValue() == type) {
displayName = getContext().getString(R.string.share_group_clarification, userName);
dataUri = Uri.withAppendedPath(groupBaseUri, shareWith);
} else {
} else if (ShareType.FEDERATED.getValue() == type && federatedShareAllowed) {
if (userName.equals(shareWith)) {
displayName = getContext().getString(R.string.share_remote_clarification, userName);
} else {
String[] uriSplitted = shareWith.split("@");
displayName = getContext().getString(R.string.share_known_remote_clarification, userName,
uriSplitted[uriSplitted.length - 1]);
}
dataUri = Uri.withAppendedPath(remoteBaseUri, shareWith);
} else if (ShareType.USER.getValue() == type) {
displayName = userName;
dataUri = Uri.withAppendedPath(userBaseUri, shareWith);
}
response.newRow()
if (displayName != null && dataUri != null) {
response.newRow()
.add(count++) // BaseColumns._ID
.add(displayName) // SearchManager.SUGGEST_COLUMN_TEXT_1
.add(dataUri);
}
}
} catch (JSONException e) {
Log_OC.e(TAG, "Exception while parsing data of users/groups", e);
}
@ -203,7 +245,7 @@ public class UsersAndGroupsSearchProvider extends ContentProvider {
/**
* Show error message
*
* @param result Result with the failure information.
* @param result Result with the failure information.
*/
public void showErrorMessage(final RemoteOperationResult result) {
Handler handler = new Handler(Looper.getMainLooper());

View file

@ -1,22 +1,22 @@
/**
* ownCloud Android client application
*
* @author masensio
* @author David A. Velasco
* Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ownCloud Android client application
*
* @author masensio
* @author David A. Velasco
* @author Juan Carlos González Cabrero
* Copyright (C) 2015 ownCloud Inc.
* <p/>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
* <p/>
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* <p/>
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.owncloud.android.ui.activity;
@ -30,18 +30,17 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.operations.CreateShareViaLinkOperation;
import com.owncloud.android.operations.GetSharesForFileOperation;
import com.owncloud.android.operations.UnshareOperation;
import com.owncloud.android.operations.UpdateSharePermissionsOperation;
import com.owncloud.android.providers.UsersAndGroupsSearchProvider;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.ui.dialog.ShareLinkToDialog;
import com.owncloud.android.ui.fragment.EditShareFragment;
import com.owncloud.android.ui.fragment.SearchShareesFragment;
@ -63,7 +62,9 @@ public class ShareActivity extends FileActivity
private static final String TAG_SEARCH_FRAGMENT = "SEARCH_USER_AND_GROUPS_FRAGMENT";
private static final String TAG_EDIT_SHARE_FRAGMENT = "EDIT_SHARE_FRAGMENT";
/** Tag for dialog */
/**
* Tag for dialog
*/
private static final String FTAG_CHOOSER_DIALOG = "CHOOSER_DIALOG";
@Override
@ -108,7 +109,7 @@ public class ShareActivity extends FileActivity
String shareWith = dataString.substring(dataString.lastIndexOf('/') + 1);
doShareWith(
shareWith,
UsersAndGroupsSearchProvider.DATA_GROUP.equals(data.getAuthority())
data.getAuthority()
);
} else {
@ -116,25 +117,32 @@ public class ShareActivity extends FileActivity
}
}
private void doShareWith(String shareeName, boolean isGroup) {
private void doShareWith(String shareeName, String dataAuthority) {
ShareType shareType = UsersAndGroupsSearchProvider.getShareType(dataAuthority);
getFileOperationsHelper().shareFileWithSharee(
getFile(),
shareeName,
(isGroup ? ShareType.GROUP : ShareType.USER),
getAppropiatePermissions()
shareType,
getAppropiatePermissions(shareType)
);
}
private int getAppropiatePermissions() {
private int getAppropiatePermissions(ShareType shareType) {
// check if the Share is FERERATED
boolean isFederated = ShareType.FEDERATED.equals(shareType);
if (getFile().isSharedWithMe()) {
return OCShare.READ_PERMISSION_FLAG; // minimum permissions
} else if (getFile().isFolder()) {
return OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER;
return (isFederated) ? OCShare.FEDERATED_PERMISSIONS_FOR_FOLDER : OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER;
} else { // isFile
return OCShare.MAXIMUM_PERMISSIONS_FOR_FILE;
return (isFederated) ? OCShare.FEDERATED_PERMISSIONS_FOR_FILE : OCShare.MAXIMUM_PERMISSIONS_FOR_FILE;
}
}
@ -191,10 +199,10 @@ public class ShareActivity extends FileActivity
super.onRemoteOperationFinish(operation, result);
if (result.isSuccess() ||
(operation instanceof GetSharesForFileOperation &&
result.getCode() == RemoteOperationResult.ResultCode.SHARE_NOT_FOUND
)
) {
(operation instanceof GetSharesForFileOperation &&
result.getCode() == RemoteOperationResult.ResultCode.SHARE_NOT_FOUND
)
) {
Log_OC.d(TAG, "Refreshing view on successful operation or finished refresh");
refreshSharesFromStorageManager();
}
@ -245,7 +253,7 @@ public class ShareActivity extends FileActivity
EditShareFragment editShareFragment = getEditShareFragment();
if (editShareFragment != null &&
editShareFragment.isAdded()) {
editShareFragment.isAdded()) {
editShareFragment.refreshUiFromDB();
}
@ -254,7 +262,7 @@ public class ShareActivity extends FileActivity
/**
* Shortcut to get access to the {@link ShareFileFragment} instance, if any
*
* @return A {@link ShareFileFragment} instance, or null
* @return A {@link ShareFileFragment} instance, or null
*/
private ShareFileFragment getShareFileFragment() {
return (ShareFileFragment) getSupportFragmentManager().findFragmentByTag(TAG_SHARE_FRAGMENT);
@ -263,7 +271,7 @@ public class ShareActivity extends FileActivity
/**
* Shortcut to get access to the {@link SearchShareesFragment} instance, if any
*
* @return A {@link SearchShareesFragment} instance, or null
* @return A {@link SearchShareesFragment} instance, or null
*/
private SearchShareesFragment getSearchFragment() {
return (SearchShareesFragment) getSupportFragmentManager().findFragmentByTag(TAG_SEARCH_FRAGMENT);
@ -272,7 +280,7 @@ public class ShareActivity extends FileActivity
/**
* Shortcut to get access to the {@link EditShareFragment} instance, if any
*
* @return A {@link EditShareFragment} instance, or null
* @return A {@link EditShareFragment} instance, or null
*/
private EditShareFragment getEditShareFragment() {
return (EditShareFragment) getSupportFragmentManager().findFragmentByTag(TAG_EDIT_SHARE_FRAGMENT);

View file

@ -38,6 +38,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.lib.resources.shares.SharePermissionsBuilder;
import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.ui.activity.FileActivity;
public class EditShareFragment extends Fragment {
@ -131,7 +132,6 @@ public class EditShareFragment extends Fragment {
// Setup layout
refreshUiFromState(view);
setPermissionsListening(view, true);
return view;
}
@ -147,9 +147,13 @@ public class EditShareFragment extends Fragment {
setPermissionsListening(editShareView, false);
int sharePermissions = mShare.getPermissions();
boolean isFederated = ShareType.FEDERATED.equals(mShare.getShareType());
CompoundButton compound;
compound = (CompoundButton) editShareView.findViewById(R.id.canShareSwitch);
if(isFederated) {
compound.setVisibility(View.INVISIBLE);
}
compound.setChecked((sharePermissions & OCShare.SHARE_PERMISSION_FLAG) > 0);
compound = (CompoundButton) editShareView.findViewById(R.id.canEditSwitch);
@ -160,7 +164,7 @@ public class EditShareFragment extends Fragment {
boolean canEdit = (sharePermissions & anyUpdatePermission) > 0;
compound.setChecked(canEdit);
if (mFile.isFolder()) {
if (mFile.isFolder() && !isFederated) {
compound = (CompoundButton) editShareView.findViewById(R.id.canEditCreateCheckBox);
compound.setChecked((sharePermissions & OCShare.CREATE_PERMISSION_FLAG) > 0);
compound.setVisibility(canEdit ? View.VISIBLE : View.GONE);
@ -245,21 +249,20 @@ public class EditShareFragment extends Fragment {
case R.id.canEditSwitch:
Log_OC.v(TAG, "canEditCheckBox toggled to " + isChecked);
/// sync subordinate CheckBoxes
boolean isFederated = ShareType.FEDERATED.equals(mShare.getShareType());
if (mFile.isFolder()) {
if (isChecked) {
for (int i = 0; i < sSubordinateCheckBoxIds.length; i++) {
//noinspection ConstantConditions, prevented in the method beginning
subordinate = (CompoundButton) getView().findViewById(sSubordinateCheckBoxIds[i]);
subordinate.setVisibility(View.VISIBLE);
if (!isFederated) {
subordinate.setVisibility(View.VISIBLE);
}
if (!subordinate.isChecked() &&
!mFile.isSharedWithMe()) { // see (1)
toggleDisablingListener(subordinate);
}
}
if (!mFile.isSharedWithMe()) {
updatePermissionsToShare(); // see (1)
}
} else {
for (int i = 0; i < sSubordinateCheckBoxIds.length; i++) {
//noinspection ConstantConditions, prevented in the method beginning
@ -269,11 +272,13 @@ public class EditShareFragment extends Fragment {
toggleDisablingListener(subordinate);
}
}
updatePermissionsToShare(); // see (1)
}
} else {
}
if(!(mFile.isFolder() && isChecked && mFile.isSharedWithMe())) { // see (1)
updatePermissionsToShare();
}
// updatePermissionsToShare() // see (1)
// (1) These modifications result in an exceptional UI behaviour for the case
// where the switch 'can edit' is enabled for a *reshared folder*; if the same