Browse Source

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

David A. Velasco 9 years ago
parent
commit
9b4d153e90

+ 2 - 0
src/com/owncloud/android/datamodel/FileDataStorageManager.java

@@ -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;

+ 13 - 6
src/com/owncloud/android/files/FileOperationsHelper.java

@@ -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

+ 3 - 2
src/com/owncloud/android/operations/CreateShareViaLinkOperation.java

@@ -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()) {

+ 1 - 1
src/com/owncloud/android/operations/RefreshFolderOperation.java

@@ -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");
         }
     }
 

+ 28 - 20
src/com/owncloud/android/ui/activity/FileActivity.java

@@ -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,

+ 18 - 12
src/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java

@@ -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);
+            }
         }
     }
 }

+ 72 - 18
src/com/owncloud/android/ui/fragment/ShareFileFragment.java

@@ -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();