Updated handling of enforced password for public shares depending on server capabilities

This commit is contained in:
David A. Velasco 2015-11-20 16:31:17 +01:00
parent f5369ac4b2
commit 9b4d153e90
7 changed files with 137 additions and 59 deletions

View file

@ -1884,6 +1884,8 @@ public class FileDataStorageManager {
if (c.moveToFirst()) {
capability = createCapabilityInstance(c);
} else {
capability = new OCCapability(); // return default with all UNKNOWN
}
c.close();
return capability;

View file

@ -143,18 +143,22 @@ public class FileOperationsHelper {
/**
* Helper method to share a file via a public link. Starts a request to do it in {@link OperationsService}
*
* @param file The file to share.
* @param file The file to share.
* @param password Optional password to protect the public share.
*/
public void shareFileViaLink(OCFile file) {
public void shareFileViaLink(OCFile file, String password) {
if (isSharedSupported()) {
if (file != null) {
mFileActivity.showLoadingDialog(
mFileActivity.getApplicationContext().
getString(R.string.wait_a_moment)
getString(R.string.wait_a_moment)
);
Intent service = new Intent(mFileActivity, OperationsService.class);
service.setAction(OperationsService.ACTION_CREATE_SHARE_VIA_LINK);
service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
if (password != null && password.length() > 0) {
service.putExtra(OperationsService.EXTRA_SHARE_PASSWORD, password);
}
service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
@ -325,11 +329,14 @@ public class FileOperationsHelper {
/**
* Starts a dialog that requests a password to the user to protect a share link.
*
* @param file File which public share will be protected by the requested password
* @param file File which public share will be protected by the requested password
* @param createShare When 'true', the request for password will be followed by the creation of a new
* public link; when 'false', a public share is assumed to exist, and the password
* is bound to it.
*/
public void requestPasswordForShareViaLink(OCFile file) {
public void requestPasswordForShareViaLink(OCFile file, boolean createShare) {
SharePasswordDialogFragment dialog =
SharePasswordDialogFragment.newInstance(file);
SharePasswordDialogFragment.newInstance(file, createShare);
dialog.show(
mFileActivity.getSupportFragmentManager(),
SharePasswordDialogFragment.PASSWORD_FRAGMENT

View file

@ -89,7 +89,7 @@ public class CreateShareViaLinkOperation extends SyncOperation {
}
if (!result.isSuccess() || !shareByLink) {
operation = new CreateRemoteShareOperation(
CreateRemoteShareOperation createOp = new CreateRemoteShareOperation(
mPath,
ShareType.PUBLIC_LINK,
"",
@ -97,7 +97,8 @@ public class CreateShareViaLinkOperation extends SyncOperation {
mPassword,
OCShare.DEFAULT_PERMISSION
);
result = operation.execute(client);
createOp.setGetShareDetails(true);
result = createOp.execute(client);
}
if (result.isSuccess()) {

View file

@ -246,7 +246,7 @@ public class RefreshFolderOperation extends RemoteOperation {
GetCapabilitiesOperarion getCapabilities = new GetCapabilitiesOperarion();
RemoteOperationResult result = getCapabilities.execute(mStorageManager,mContext);
if (!result.isSuccess()){
Log_OC.d(TAG, "Update Capabilities unsuccessfully");
Log_OC.w(TAG, "Update Capabilities unsuccessfully");
}
}

View file

@ -67,6 +67,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OCCapability;
import com.owncloud.android.operations.CreateShareViaLinkOperation;
import com.owncloud.android.operations.CreateShareWithShareeOperation;
import com.owncloud.android.operations.GetSharesForFileOperation;
@ -94,8 +95,6 @@ public class FileActivity extends AppCompatActivity
public static final String EXTRA_FILE = "com.owncloud.android.ui.activity.FILE";
public static final String EXTRA_ACCOUNT = "com.owncloud.android.ui.activity.ACCOUNT";
public static final String EXTRA_WAITING_TO_PREVIEW =
"com.owncloud.android.ui.activity.WAITING_TO_PREVIEW";
public static final String EXTRA_FROM_NOTIFICATION =
"com.owncloud.android.ui.activity.FROM_NOTIFICATION";
@ -114,9 +113,13 @@ public class FileActivity extends AppCompatActivity
/** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located.*/
private Account mAccount;
/** Main {@link OCFile} handled by the activity.*/
/** Capabilites of the server where {@link #mAccount} lives */
private OCCapability mCapabilities;
/** Main {@link OCFile} handled by the activity.*/
private OCFile mFile;
/** Flag to signal that the activity will is finishing to enforce the creation of an ownCloud
* {@link Account} */
private boolean mRedirectingToSetupAccount = false;
@ -146,8 +149,6 @@ public class FileActivity extends AppCompatActivity
protected FileUploaderBinder mUploaderBinder = null;
private ServiceConnection mDownloadServiceConnection, mUploadServiceConnection = null;
private boolean mTryShareAgain = false;
// Navigation Drawer
protected DrawerLayout mDrawerLayout;
protected ActionBarDrawerToggle mDrawerToggle;
@ -162,6 +163,7 @@ public class FileActivity extends AppCompatActivity
protected NavigationDrawerListAdapter mNavigationDrawerAdapter = null;
// TODO re-enable when "Accounts" is available in Navigation Drawer
// protected boolean mShowAccounts = false;
@ -184,7 +186,6 @@ public class FileActivity extends AppCompatActivity
mFileOperationsHelper.setOpIdWaitingFor(
savedInstanceState.getLong(KEY_WAITING_FOR_OP_ID, Long.MAX_VALUE)
);
mTryShareAgain = savedInstanceState.getBoolean(KEY_TRY_SHARE_AGAIN);
if (getSupportActionBar() != null) {
getSupportActionBar().setTitle(savedInstanceState.getString(KEY_ACTION_BAR_TITLE));
}
@ -555,7 +556,6 @@ public class FileActivity extends AppCompatActivity
outState.putParcelable(FileActivity.EXTRA_FILE, mFile);
outState.putBoolean(FileActivity.EXTRA_FROM_NOTIFICATION, mFromNotification);
outState.putLong(KEY_WAITING_FOR_OP_ID, mFileOperationsHelper.getOpIdWaitingFor());
outState.putBoolean(KEY_TRY_SHARE_AGAIN, mTryShareAgain);
if(getSupportActionBar() != null && getSupportActionBar().getTitle() != null) {
// Null check in case the actionbar is used in ActionBar.NAVIGATION_MODE_LIST
// since it doesn't have a title then
@ -599,6 +599,18 @@ public class FileActivity extends AppCompatActivity
mAccount = account;
}
/**
* Getter for the capabilities of the server where the current OC account lives.
*
* @return Capabilities of the server where the current OC account lives. Null if the account is not
* set yet.
*/
public OCCapability getCapabilities() {
return mCapabilities;
}
/**
* @return Value of mFromNotification: True if the Activity is launched by a notification
*/
@ -613,14 +625,6 @@ public class FileActivity extends AppCompatActivity
return mRedirectingToSetupAccount;
}
public boolean isTryShareAgain(){
return mTryShareAgain;
}
public void setTryShareAgain(boolean tryShareAgain) {
mTryShareAgain = tryShareAgain;
}
public OperationsServiceBinder getOperationsServiceBinder() {
return mOperationsServiceBinder;
}
@ -677,6 +681,7 @@ public class FileActivity extends AppCompatActivity
protected void onAccountSet(boolean stateWasRecovered) {
if (getAccount() != null) {
mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver());
mCapabilities = mStorageManager.getCapability(mAccount.name);
} else {
Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!");
@ -731,7 +736,6 @@ public class FileActivity extends AppCompatActivity
Toast.LENGTH_LONG);
t.show();
}
mTryShareAgain = false;
} else if (operation == null ||
operation instanceof CreateShareWithShareeOperation ||
@ -783,7 +787,6 @@ public class FileActivity extends AppCompatActivity
private void onCreateShareViaLinkOperationFinish(CreateShareViaLinkOperation operation,
RemoteOperationResult result) {
if (result.isSuccess()) {
mTryShareAgain = false;
updateFileFromDB();
Intent sendIntent = operation.getSendIntentWithSubject(this);
@ -794,16 +797,21 @@ public class FileActivity extends AppCompatActivity
} else {
// Detect Failure (403) --> needs Password
if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
if (!isTryShareAgain()) {
String password = operation.getPassword();
if ((password == null || password.length() == 0) &&
!getCapabilities().getFilesSharingPublicEnabled().isFalse())
{
// Was tried without password, but not sure that it's optional. Try with password.
// Try with password before giving up.
// See also ShareFileFragment#OnShareViaLinkListener
SharePasswordDialogFragment dialog =
SharePasswordDialogFragment.newInstance(new OCFile(operation.getPath()));
SharePasswordDialogFragment.newInstance(new OCFile(operation.getPath()), true);
dialog.show(getSupportFragmentManager(), DIALOG_SHARE_PASSWORD);
} else {
Toast t = Toast.makeText(this,
ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
Toast.LENGTH_LONG);
t.show();
mTryShareAgain = false;
}
} else {
Toast t = Toast.makeText(this,

View file

@ -44,21 +44,26 @@ public class SharePasswordDialogFragment extends DialogFragment
implements DialogInterface.OnClickListener {
private static final String ARG_FILE = "FILE";
private static final String ARG_CREATE_SHARE = "CREATE_SHARE";
public static final String PASSWORD_FRAGMENT = "PASSWORD_FRAGMENT";
private OCFile mFile;
private boolean mCreateShare;
/**
* Public factory method to create new SharePasswordDialogFragment instances.
*
* @param file
* @return Dialog ready to show.
* @param file OCFile bound to the public share that which password will be set or updated
* @param createShare When 'true', the public share will be created; when 'false', will be assumed
* that the public share already exists, and its state will be directly updated.
* @return Dialog ready to show.
*/
public static SharePasswordDialogFragment newInstance(OCFile file) {
public static SharePasswordDialogFragment newInstance(OCFile file, boolean createShare) {
SharePasswordDialogFragment frag = new SharePasswordDialogFragment();
Bundle args = new Bundle();
args.putParcelable(ARG_FILE, file);
args.putBoolean(ARG_CREATE_SHARE, createShare);
frag.setArguments(args);
return frag;
}
@ -66,6 +71,7 @@ public class SharePasswordDialogFragment extends DialogFragment
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
mFile = getArguments().getParcelable(ARG_FILE);
mCreateShare = getArguments().getBoolean(ARG_CREATE_SHARE, false);
// Inflate the layout for the dialog
LayoutInflater inflater = getActivity().getLayoutInflater();
@ -91,9 +97,6 @@ public class SharePasswordDialogFragment extends DialogFragment
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == AlertDialog.BUTTON_POSITIVE) {
// Enable the flag "Share again"
((FileActivity) getActivity()).setTryShareAgain(true);
String password =
((TextView)(getDialog().findViewById(R.id.share_password)))
.getText().toString();
@ -106,13 +109,16 @@ public class SharePasswordDialogFragment extends DialogFragment
return;
}
// Share the file
((FileActivity) getActivity()).getFileOperationsHelper().
setPasswordToShareViaLink(mFile, password);
if (mCreateShare) {
// Share the file
((FileActivity) getActivity()).getFileOperationsHelper().
shareFileViaLink(mFile, password);
} else {
// Disable the flag "Share again"
((FileActivity) getActivity()).setTryShareAgain(false);
} else {
// updat existing link
((FileActivity) getActivity()).getFileOperationsHelper().
setPasswordToShareViaLink(mFile, password);
}
}
}
}

View file

@ -145,6 +145,7 @@ public class ShareFileFragment extends Fragment
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log_OC.d(TAG, "onCreate");
if (getArguments() != null) {
mFile = getArguments().getParcelable(ARG_FILE);
mAccount = getArguments().getParcelable(ARG_ACCOUNT);
@ -158,6 +159,8 @@ public class ShareFileFragment extends Fragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log_OC.d(TAG, "onCreateView");
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.share_file_layout, container, false);
@ -204,24 +207,12 @@ public class ShareFileFragment extends Fragment
// Switch to create public share
mOnShareViaLinkSwitchCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!isResumed()) {
// very important, setCheched(...) is called automatically during
// Fragment recreation on device rotations
return;
}
if (isChecked) {
((FileActivity) getActivity()).getFileOperationsHelper().
shareFileViaLink(mFile);
} else {
((FileActivity) getActivity()).getFileOperationsHelper().
unshareFileViaLink(mFile);
}
public void onCheckedChanged(CompoundButton switchView, boolean isChecked) {
}
};
Switch shareViaLinkSwitch = (Switch) view.findViewById(R.id.shareViaLinkSectionSwitch);
shareViaLinkSwitch.setOnCheckedChangeListener(mOnShareViaLinkSwitchCheckedChangeListener);
// Set listener for user actions on switch for sharing/unsharing via link
initShareViaLinkListener(view);
// Set listener for user actions on expiration date
initExpirationListener(view);
@ -232,6 +223,68 @@ public class ShareFileFragment extends Fragment
return view;
}
/**
* Binds listener for user actions to create or delete a public share
* to the views receiving the user events.
*
* @param shareView Root view in the fragment.
*/
private void initShareViaLinkListener(View shareView) {
mOnShareViaLinkSwitchCheckedChangeListener = new OnShareViaLinkListener();
Switch shareViaLinkSwitch = (Switch) shareView.findViewById(R.id.shareViaLinkSectionSwitch);
shareViaLinkSwitch.setOnCheckedChangeListener(mOnShareViaLinkSwitchCheckedChangeListener);
}
/**
* Listener for user actions that create or delete a public share.
*/
private class OnShareViaLinkListener
implements CompoundButton.OnCheckedChangeListener {
/**
* Called by R.id.shareViaLinkSectionSwitch to create or delete a public link.
*
* @param switchView {@link Switch} toggled by the user, R.id.shareViaLinkSectionSwitch
* @param isChecked New switch state.
*/
@Override
public void onCheckedChanged(CompoundButton switchView, boolean isChecked) {
if (!isResumed()) {
// very important, setCheched(...) is called automatically during
// Fragment recreation on device rotations
return;
}
if (isChecked) {
if (mCapabilities != null &&
mCapabilities.getFilesSharingPublicPasswordEnforced().isTrue()) {
// password enforced by server, request to the user before trying to create
((FileActivity) getActivity()).getFileOperationsHelper().
requestPasswordForShareViaLink(mFile, true);
} else {
// create without password if not enforced by server or we don't know if enforced;
((FileActivity) getActivity()).getFileOperationsHelper().
shareFileViaLink(mFile, null);
// FileActivtiy#onCreateShareViaLinkOperationFinish still handles the guess of enforcement
// for server in versions previous to OwnCloudVersion#MINIMUM_VERSION_CAPABILITIES_API
}
} else {
((FileActivity) getActivity()).getFileOperationsHelper().
unshareFileViaLink(mFile);
}
// undo the toggle to grant the view will be correct if any intermediate dialog is cancelled or
// the create/delete operation fails
switchView.setOnCheckedChangeListener(null);
switchView.toggle();
switchView.setOnCheckedChangeListener(mOnShareViaLinkSwitchCheckedChangeListener);
}
}
/**
* Binds listener for user actions that start any update on a expiration date
* for the public link to the views receiving the user events.
@ -357,7 +410,7 @@ public class ShareFileFragment extends Fragment
}
if (isChecked) {
((FileActivity) getActivity()).getFileOperationsHelper().
requestPasswordForShareViaLink(mFile);
requestPasswordForShareViaLink(mFile, false);
} else {
((FileActivity) getActivity()).getFileOperationsHelper().
setPasswordToShareViaLink(mFile, ""); // "" clears
@ -379,7 +432,7 @@ public class ShareFileFragment extends Fragment
public void onClick(View passwordView) {
if (mPublicShare != null && mPublicShare.isPasswordProtected()) {
((FileActivity) getActivity()).getFileOperationsHelper().
requestPasswordForShareViaLink(mFile);
requestPasswordForShareViaLink(mFile, false);
}
}
}
@ -388,6 +441,7 @@ public class ShareFileFragment extends Fragment
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log_OC.d(TAG, "onActivityCreated");
// Load known capabilities of the server from DB
refreshCapabilitiesFromDB();