Set or clear expiration date to protect public link in ShareFileFragment

This commit is contained in:
David A. Velasco 2015-11-12 16:38:58 +01:00
parent 729a9b7c77
commit ad7666370f
6 changed files with 314 additions and 51 deletions

View file

@ -211,7 +211,7 @@ public class FileOperationsHelper {
service.setAction(OperationsService.ACTION_CREATE_SHARE_VIA_LINK);
service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
service.putExtra(OperationsService.EXTRA_PASSWORD_SHARE, password);
service.putExtra(OperationsService.EXTRA_SHARE_PASSWORD, password);
service.putExtra(OperationsService.EXTRA_SEND_INTENT, sendIntent);
mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
@ -366,7 +366,7 @@ public class FileOperationsHelper {
updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
updateShareIntent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
updateShareIntent.putExtra(
OperationsService.EXTRA_PASSWORD_SHARE,
OperationsService.EXTRA_SHARE_PASSWORD,
(password == null) ? "" : password
);
@ -374,6 +374,28 @@ public class FileOperationsHelper {
}
/**
* Updates a public share on a file to set its expiration date.
* Starts a request to do it in {@link OperationsService}
*
* @param file File which public share will be constrained with an expiration date.
* @param year Year of the date expiration chosen. Negative value to remove current
* expiration date and leave the link unrestricted.
* @param monthOfYear Month of the date chosen [0, 11]
* @param dayOfMonth Day of the date chosen
*/
public void setExpirationDateToShareViaLink(OCFile file, int year, int monthOfYear, int dayOfMonth) {
Intent updateShareIntent = new Intent(mFileActivity, OperationsService.class);
updateShareIntent.setAction(OperationsService.ACTION_UPDATE_SHARE);
updateShareIntent.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
updateShareIntent.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_YEAR, year);
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_MONTH_OF_YEAR, monthOfYear);
updateShareIntent.putExtra(OperationsService.EXTRA_SHARE_EXPIRATION_DAY_OF_MONTH, dayOfMonth);
queueShareIntent(updateShareIntent);
}
/**
* @return 'True' if the server supports the Search Users API
*/

View file

@ -31,6 +31,8 @@ import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.lib.resources.shares.UpdateRemoteShareOperation;
import com.owncloud.android.operations.common.SyncOperation;
import java.util.Calendar;
/**
* Updates an existing public share for a given file
@ -40,21 +42,45 @@ public class UpdateShareViaLinkOperation extends SyncOperation {
private String mPath;
private String mPassword;
private Calendar mExpirationDate;
/**
* Constructor
*
* @param path Full path of the file/folder being shared. Mandatory argument
* @param password Password to protect a public link share.
*/
public UpdateShareViaLinkOperation(
String path,
String password
) {
public UpdateShareViaLinkOperation(String path) {
mPath = path;
mPassword = null;
mExpirationDate = null;
}
/**
* Set password to update in public link.
*
* @param password Password to set to the public link.
* Empty string clears the current password.
* Null results in no update applied to the password.
*/
public void setPassword(String password) {
mPassword = password;
}
/**
* Set expiration date to update in Share resource.
*
* @param expirationDate Expiration date to set to the public link.
* Start-of-epoch clears the current expiration date.
* Null results in no update applied to the expiration date.
*/
public void setExpirationDate(Calendar expirationDate) {
mExpirationDate = expirationDate;
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
@ -70,11 +96,12 @@ public class UpdateShareViaLinkOperation extends SyncOperation {
}
// Update remote share with password
RemoteOperation operation = new UpdateRemoteShareOperation(
UpdateRemoteShareOperation udpateOp = new UpdateRemoteShareOperation(
publicShare.getRemoteId()
);
((UpdateRemoteShareOperation)operation).setPassword(mPassword);
RemoteOperationResult result = operation.execute(client);
udpateOp.setPassword(mPassword);
udpateOp.setExpirationDate(mExpirationDate);
RemoteOperationResult result = udpateOp.execute(client);
/*
if (!result.isSuccess() || result.getData().size() <= 0) {
@ -92,8 +119,8 @@ public class UpdateShareViaLinkOperation extends SyncOperation {
if (result.isSuccess()) {
// Retrieve updated share / save directly with password? -> no; the password is not be saved
operation = new GetRemoteShareOperation(publicShare.getRemoteId());
result = operation.execute(client);
RemoteOperation getShareOp = new GetRemoteShareOperation(publicShare.getRemoteId());
result = getShareOp.execute(client);
if (result.isSuccess()) {
OCShare share = (OCShare) result.getData().get(0);
updateData(share);

View file

@ -68,6 +68,7 @@ import com.owncloud.android.operations.UpdateShareViaLinkOperation;
import com.owncloud.android.operations.common.SyncOperation;
import java.io.IOException;
import java.util.Calendar;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
@ -89,9 +90,12 @@ public class OperationsService extends Service {
public static final String EXTRA_RESULT = "RESULT";
public static final String EXTRA_NEW_PARENT_PATH = "NEW_PARENT_PATH";
public static final String EXTRA_FILE = "FILE";
public static final String EXTRA_PASSWORD_SHARE = "PASSWORD_SHARE";
public static final String EXTRA_SHARE_PASSWORD = "SHARE_PASSWORD";
public static final String EXTRA_SHARE_TYPE = "SHARE_TYPE";
public static final String EXTRA_SHARE_WITH = "SHARE_WITH";
public static final String EXTRA_SHARE_EXPIRATION_YEAR = "SHARE_EXPIRATION_YEAR";
public static final String EXTRA_SHARE_EXPIRATION_MONTH_OF_YEAR = "SHARE_EXPIRATION_MONTH_OF_YEAR";
public static final String EXTRA_SHARE_EXPIRATION_DAY_OF_MONTH = "SHARE_EXPIRATION_DAY_OF_MONTH";
public static final String EXTRA_COOKIE = "COOKIE";
@ -555,7 +559,7 @@ public class OperationsService extends Service {
String action = operationIntent.getAction();
if (action.equals(ACTION_CREATE_SHARE_VIA_LINK)) { // Create public share via link
String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
String password = operationIntent.getStringExtra(EXTRA_PASSWORD_SHARE);
String password = operationIntent.getStringExtra(EXTRA_SHARE_PASSWORD);
Intent sendIntent = operationIntent.getParcelableExtra(EXTRA_SEND_INTENT);
if (remotePath.length() > 0) {
operation = new CreateShareViaLinkOperation(
@ -567,22 +571,52 @@ public class OperationsService extends Service {
} else if (ACTION_UPDATE_SHARE.equals(action)) {
String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
String password = operationIntent.getStringExtra(EXTRA_PASSWORD_SHARE);
if (remotePath.length() > 0) {
operation = new UpdateShareViaLinkOperation(remotePath, password);
operation = new UpdateShareViaLinkOperation(remotePath);
String password = operationIntent.getStringExtra(EXTRA_SHARE_PASSWORD);
((UpdateShareViaLinkOperation)operation).setPassword(password);
int year = operationIntent.getIntExtra(EXTRA_SHARE_EXPIRATION_YEAR, 0);
if (year > 0) {
// expiration date is set
int monthOfYear = operationIntent.getIntExtra(
EXTRA_SHARE_EXPIRATION_MONTH_OF_YEAR, 0
);
int dayOfMonth = operationIntent.getIntExtra(
EXTRA_SHARE_EXPIRATION_DAY_OF_MONTH, 1
);
Calendar expirationDate = Calendar.getInstance();
expirationDate.set(Calendar.YEAR, year);
expirationDate.set(Calendar.MONTH, monthOfYear);
expirationDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
((UpdateShareViaLinkOperation)operation).setExpirationDate(
expirationDate
);
} else if (year < 0) {
// expiration date to be cleared
Calendar zeroDate = Calendar.getInstance();
zeroDate.clear();
((UpdateShareViaLinkOperation)operation).setExpirationDate(
zeroDate
);
} // else, no update on expiration date
}
} else if (action.equals(ACTION_CREATE_SHARE_WITH_SHAREE)) { // Create private share with user or group
String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
String shareeName = operationIntent.getStringExtra(EXTRA_SHARE_WITH);
ShareType shareType = (ShareType) operationIntent.getSerializableExtra(EXTRA_SHARE_TYPE);
if (remotePath.length() > 0) {
operation = new CreateShareWithShareeOperation(
remotePath,
shareeName,
shareType
);
}
} else if (action.equals(ACTION_CREATE_SHARE_WITH_SHAREE)) {
// Create private share with user or group
String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
String shareeName = operationIntent.getStringExtra(EXTRA_SHARE_WITH);
ShareType shareType = (ShareType) operationIntent.getSerializableExtra(EXTRA_SHARE_TYPE);
if (remotePath.length() > 0) {
operation = new CreateShareWithShareeOperation(
remotePath,
shareeName,
shareType
);
}
} else if (action.equals(ACTION_UNSHARE)) { // Unshare file
String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);

View file

@ -154,26 +154,28 @@ public class ShareActivity extends FileActivity
super.onRemoteOperationFinish(operation, result);
if (result.isSuccess()) {
Log_OC.d(TAG, "Refreshing lists on successful operation");
Log_OC.d(TAG, "Refreshing view on successful operation");
refreshSharesFromStorageManager();
}
}
/**
* Updates the view, reading data from {@link com.owncloud.android.datamodel.FileDataStorageManager}
*/
private void refreshSharesFromStorageManager() {
ShareFileFragment shareFileFragment = getShareFileFragment();
if (shareFileFragment != null) { // only if added to the view hierarchy!!
if (shareFileFragment.isAdded()) {
shareFileFragment.refreshUsersOrGroupsListFromDB();
shareFileFragment.refreshPublicShareFromDB();
}
if (shareFileFragment != null
&& shareFileFragment.isAdded()) { // only if added to the view hierarchy!!
shareFileFragment.refreshUsersOrGroupsListFromDB();
shareFileFragment.refreshPublicShareFromDB();
}
SearchShareesFragment searchShareesFragment = getSearchFragment();
if (searchShareesFragment != null) {
if (searchShareesFragment.isAdded()) { // only if added to the view hierarchy!!
searchShareesFragment.refreshUsersOrGroupsListFromDB();
}
if (searchShareesFragment != null &&
searchShareesFragment.isAdded()) { // only if added to the view hierarchy!!
searchShareesFragment.refreshUsersOrGroupsListFromDB();
}
}

View file

@ -0,0 +1,124 @@
/**
* 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/>.
*
*/
package com.owncloud.android.ui.dialog;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.text.format.DateUtils;
import android.widget.DatePicker;
import android.widget.Toast;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.ui.activity.FileActivity;
import java.util.Calendar;
import java.util.Date;
/**
* Dialog requesting a date after today.
*/
public class ExpirationDatePickerDialogFragment
extends DialogFragment
implements DatePickerDialog.OnDateSetListener {
/** Tag for FragmentsManager */
public static final String DATE_PICKER_DIALOG = "DATE_PICKER_DIALOG";
/** Constructor arguments */
private static final String ARG_FILE = "ARG_FILE";
/** File to bind an expiration date */
private OCFile mFile;
/**
* Factory method to create new instances
*
* @param file File to bind an expiration date
* @return New dialog instance
*/
public static ExpirationDatePickerDialogFragment newInstance(OCFile file) {
Bundle arguments = new Bundle();
arguments.putParcelable(ARG_FILE, file);
ExpirationDatePickerDialogFragment dialog = new ExpirationDatePickerDialogFragment();
dialog.setArguments(arguments);
return dialog;
}
/**
* {@inheritDoc}
*
* @return A new dialog to let the user choose an expiration date that will be bound to a share link.
*/
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Load arguments
mFile = getArguments().getParcelable(ARG_FILE);
// Get current day
final Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int day = c.get(Calendar.DAY_OF_MONTH);
// Create a new instance of DatePickerDialog, highlighting "tomorrow" as chosen day
DatePickerDialog dialog = new DatePickerDialog(getActivity(), this, year, month, day + 1);
// Prevent days in the past may be chosen
DatePicker picker = dialog.getDatePicker();
picker.setMinDate(System.currentTimeMillis() + DateUtils.DAY_IN_MILLIS - 1000);
// Enforce spinners view; ignored by MD-based theme in Android >=5, but calendar is REALLY buggy
// in Android < 5, so let's be sure it never appears (in tablets both spinners and calendar are
// shown by default)
picker.setCalendarViewShown(false);
return dialog;
}
/**
* Called when the user choses an expiration date.
*
* @param view View instance where the date was chosen
* @param year Year of the date chosen.
* @param monthOfYear Month of the date chosen [0, 11]
* @param dayOfMonth Day of the date chosen
*/
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
Calendar chosenDate = Calendar.getInstance();
chosenDate.set(Calendar.YEAR, year);
chosenDate.set(Calendar.MONTH, monthOfYear);
chosenDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
((FileActivity)getActivity()).getFileOperationsHelper().setExpirationDateToShareViaLink(
mFile,
year,
monthOfYear,
dayOfMonth
);
}
}

View file

@ -47,10 +47,13 @@ import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.ui.activity.FileActivity;
import com.owncloud.android.ui.adapter.ShareUserListAdapter;
import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment;
import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.MimetypeIconUtil;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
/**
* Fragment for Sharing a file with sharees (users or groups) or creating
@ -95,9 +98,16 @@ public class ShareFileFragment extends Fragment
/** Listener for changes on switch to share / unshare publicly */
private CompoundButton.OnCheckedChangeListener mOnShareViaLinkSwitchCheckedChangeListener;
/** Listener for changes on switch to set / clear password on public link */
/**
* Listener for changes on switch to set / clear password on public link
*/
private CompoundButton.OnCheckedChangeListener mOnPasswordSwitchCheckedChangeListener;
/**
* Listener for changes on switch to set / clear expiration date on public link
*/
private CompoundButton.OnCheckedChangeListener mOnExpirationDateSwitchCheckedChangeListener;
/**
* Public factory method to create new ShareFileFragment instances.
@ -203,8 +213,7 @@ public class ShareFileFragment extends Fragment
shareViaLinkSwitch.setOnCheckedChangeListener(mOnShareViaLinkSwitchCheckedChangeListener);
// Switch for expiration date
Switch shareViaLinkExpirationSwitch = (Switch) view.findViewById(R.id.shareViaLinkExpirationSwitch);
shareViaLinkExpirationSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
mOnExpirationDateSwitchCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (!isResumed()) {
@ -213,17 +222,26 @@ public class ShareFileFragment extends Fragment
return;
}
if (isChecked) {
// TODO real implementation: update share with expiration date
// show value of expiration date
getExpirationDateValue().setText(R.string.placeholder_timestamp);
ExpirationDatePickerDialogFragment dialog =
ExpirationDatePickerDialogFragment.newInstance(mFile);
dialog.show(
getActivity().getSupportFragmentManager(),
ExpirationDatePickerDialogFragment.DATE_PICKER_DIALOG
);
} else {
// TODO real implementation: update share without expiration date
// empty value
getExpirationDateValue().setText(R.string.empty);
((FileActivity) getActivity()).getFileOperationsHelper().
setExpirationDateToShareViaLink(mFile, -1, -1, -1);
}
// undo the toggle to grant the view will be correct if the dialog is cancelled
buttonView.setOnCheckedChangeListener(null);
buttonView.toggle();
buttonView.setOnCheckedChangeListener(mOnExpirationDateSwitchCheckedChangeListener);
}
});
};
Switch shareViaLinkExpirationSwitch = (Switch) view.findViewById(R.id.shareViaLinkExpirationSwitch);
shareViaLinkExpirationSwitch.setOnCheckedChangeListener(mOnExpirationDateSwitchCheckedChangeListener);
// Switch for password
mOnPasswordSwitchCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
@ -241,6 +259,11 @@ public class ShareFileFragment extends Fragment
((FileActivity) getActivity()).getFileOperationsHelper().
setPasswordToShareViaLink(mFile, ""); // "" clears
}
// undo the toggle to grant the view will be correct if the dialog is cancelled
buttonView.setOnCheckedChangeListener(null);
buttonView.toggle();
buttonView.setOnCheckedChangeListener(mOnPasswordSwitchCheckedChangeListener);
}
};
Switch shareViaLinkPasswordSwitch = (Switch) view.findViewById(R.id.shareViaLinkPasswordSwitch);
@ -278,7 +301,7 @@ public class ShareFileFragment extends Fragment
}
/**
* Get users and groups from the DB to fill in the "share with" list
* Get users and groups from the DB to fill in the "share with" list.
*
* Depends on the parent Activity provides a {@link com.owncloud.android.datamodel.FileDataStorageManager}
* instance ready to use. If not ready, does nothing.
@ -331,7 +354,7 @@ public class ShareFileFragment extends Fragment
/**
* Get public link from the DB to fill in the "Share link" section
* Get public link from the DB to fill in the "Share link" section in the UI.
*
* Depends on the parent Activity provides a {@link com.owncloud.android.datamodel.FileDataStorageManager}
* instance ready to use. If not ready, does nothing.
@ -345,7 +368,7 @@ public class ShareFileFragment extends Fragment
""
);
// Update list of users/groups
// Update public share section
updatePublicShareSection();
}
}
@ -370,6 +393,32 @@ public class ShareFileFragment extends Fragment
getPasswordSection().setVisibility(View.VISIBLE);
getGetLinkButton().setVisibility(View.VISIBLE);
/// update state of expiration date switch and message depending on expiration date
/// update state of expiration date switch and message depending on expiration date
Switch expirationDateSwitch = getExpirationDateSwitch();
// set null listener before setChecked() to prevent infinite loop of calls
expirationDateSwitch.setOnCheckedChangeListener(null);
long expirationDate = mPublicShare.getExpirationDate();
if (expirationDate > 0) {
if (!expirationDateSwitch.isChecked()) {
expirationDateSwitch.toggle();
}
String formattedDate =
SimpleDateFormat.getDateInstance().format(
new Date(expirationDate)
);
getExpirationDateValue().setText(formattedDate);
} else {
if (expirationDateSwitch.isChecked()) {
expirationDateSwitch.toggle();
}
getExpirationDateValue().setText(R.string.empty);
}
// recover listener
expirationDateSwitch.setOnCheckedChangeListener(
mOnExpirationDateSwitchCheckedChangeListener
);
/// update state of password switch and message depending on password protection
Switch passwordSwitch = getPasswordSwitch();
// set null listener before setChecked() to prevent infinite loop of calls
@ -407,6 +456,7 @@ public class ShareFileFragment extends Fragment
}
}
/// BEWARE: next methods will failed with NullPointerException if called before onCreateView() finishes
private Switch getShareViaLinkSwitch() {
@ -417,6 +467,10 @@ public class ShareFileFragment extends Fragment
return getView().findViewById(R.id.shareViaLinkExpirationSection);
}
private Switch getExpirationDateSwitch() {
return (Switch) getView().findViewById(R.id.shareViaLinkExpirationSwitch);
}
private TextView getExpirationDateValue() {
return (TextView) getView().findViewById(R.id.shareViaLinkExpirationValue);
}