mirror of
https://github.com/nextcloud/android.git
synced 2024-11-27 17:46:37 +03:00
Updated handling of enforced password for public shares depending on server capabilities
This commit is contained in:
parent
f5369ac4b2
commit
9b4d153e90
7 changed files with 137 additions and 59 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue