Skip to content

Commit

Permalink
Merge pull request #4453 from chimp1984/add-username-to-revolut
Browse files Browse the repository at this point in the history
Add support for user name for Revolut accounts
  • Loading branch information
sqrrm authored Sep 1, 2020
2 parents 7830dbf + 591011e commit 5b1d9cb
Show file tree
Hide file tree
Showing 11 changed files with 221 additions and 102 deletions.
1 change: 1 addition & 0 deletions core/src/main/java/bisq/core/app/BisqHeadlessApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ protected void setupHandlers() {
bisqSetup.setVoteResultExceptionHandler(voteResultException -> log.warn("voteResultException={}", voteResultException.toString()));
bisqSetup.setRejectedTxErrorMessageHandler(errorMessage -> log.warn("setRejectedTxErrorMessageHandler. errorMessage={}", errorMessage));
bisqSetup.setShowPopupIfInvalidBtcConfigHandler(() -> log.error("onShowPopupIfInvalidBtcConfigHandler"));
bisqSetup.setRevolutAccountsUpdateHandler(revolutAccountList -> log.info("setRevolutAccountsUpdateHandler: revolutAccountList={}", revolutAccountList));

//TODO move to bisqSetup
corruptedDatabaseFilesHandler.getCorruptedDatabaseFiles().ifPresent(files -> log.warn("getCorruptedDatabaseFiles. files={}", files));
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/java/bisq/core/app/BisqSetup.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import bisq.core.notifications.alerts.price.PriceAlert;
import bisq.core.offer.OpenOfferManager;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.RevolutAccount;
import bisq.core.payment.TradeLimits;
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.provider.fee.FeeService;
Expand Down Expand Up @@ -221,6 +222,9 @@ default void onRequestWalletPassword() {
@Setter
@Nullable
private Runnable showPopupIfInvalidBtcConfigHandler;
@Setter
@Nullable
private Consumer<List<RevolutAccount>> revolutAccountsUpdateHandler;

@Getter
final BooleanProperty newVersionAvailableProperty = new SimpleBooleanProperty(false);
Expand Down Expand Up @@ -824,6 +828,8 @@ private void initDomainServices() {
priceAlert.onAllServicesInitialized();
marketAlerts.onAllServicesInitialized();

user.onAllServicesInitialized(revolutAccountsUpdateHandler);

allBasicServicesInitialized = true;
}

Expand Down
12 changes: 8 additions & 4 deletions core/src/main/java/bisq/core/payment/RevolutAccount.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,15 @@ protected PaymentAccountPayload createPayload() {
return new RevolutAccountPayload(paymentMethod.getId(), id);
}

public void setAccountId(String accountId) {
((RevolutAccountPayload) paymentAccountPayload).setAccountId(accountId);
public void setUserName(String userName) {
((RevolutAccountPayload) paymentAccountPayload).setUserName(userName);
}

public String getAccountId() {
return ((RevolutAccountPayload) paymentAccountPayload).getAccountId();
public String getUserName() {
return ((RevolutAccountPayload) paymentAccountPayload).getUserName();
}

public boolean userNameNotSet() {
return ((RevolutAccountPayload) paymentAccountPayload).userNameNotSet();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,37 @@

import bisq.core.locale.Res;

import bisq.common.proto.ProtoUtil;

import com.google.protobuf.Message;

import java.nio.charset.StandardCharsets;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Nullable;

@EqualsAndHashCode(callSuper = true)
@ToString
@Setter
@Getter
@Slf4j
public final class RevolutAccountPayload extends PaymentAccountPayload {
// Not used anymore from outside. Only used as internal Id to not break existing account witness objects
private String accountId = "";

// Was added in 1.3.8
// To not break signed accounts we keep accountId as internal id used for signing.
// Old accounts get a popup to add the new required field userName but accountId is
// left unchanged. Newly created accounts fill accountId with the value of userName.
// In the UI we only use userName.
@Nullable
private String userName = null;

public RevolutAccountPayload(String paymentMethod, String id) {
super(paymentMethod, id);
}
Expand All @@ -52,6 +62,7 @@ public RevolutAccountPayload(String paymentMethod, String id) {
private RevolutAccountPayload(String paymentMethod,
String id,
String accountId,
@Nullable String userName,
long maxTradePeriod,
Map<String, String> excludeFromJsonDataMap) {
super(paymentMethod,
Expand All @@ -60,20 +71,24 @@ private RevolutAccountPayload(String paymentMethod,
excludeFromJsonDataMap);

this.accountId = accountId;
this.userName = userName;
}

@Override
public Message toProtoMessage() {
return getPaymentAccountPayloadBuilder()
.setRevolutAccountPayload(protobuf.RevolutAccountPayload.newBuilder()
.setAccountId(accountId))
.build();
protobuf.RevolutAccountPayload.Builder revolutBuilder = protobuf.RevolutAccountPayload.newBuilder()
.setAccountId(accountId);
Optional.ofNullable(userName).ifPresent(revolutBuilder::setUserName);
return getPaymentAccountPayloadBuilder().setRevolutAccountPayload(revolutBuilder).build();
}


public static RevolutAccountPayload fromProto(protobuf.PaymentAccountPayload proto) {
protobuf.RevolutAccountPayload revolutAccountPayload = proto.getRevolutAccountPayload();
return new RevolutAccountPayload(proto.getPaymentMethodId(),
proto.getId(),
proto.getRevolutAccountPayload().getAccountId(),
revolutAccountPayload.getAccountId(),
ProtoUtil.stringOrNullFromProto(revolutAccountPayload.getUserName()),
proto.getMaxTradePeriod(),
new HashMap<>(proto.getExcludeFromJsonDataMap()));
}
Expand All @@ -85,7 +100,7 @@ public static RevolutAccountPayload fromProto(protobuf.PaymentAccountPayload pro

@Override
public String getPaymentDetails() {
return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account") + " " + accountId;
return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account.userName") + " " + getUserName();
}

@Override
Expand All @@ -95,6 +110,24 @@ public String getPaymentDetailsForTradePopup() {

@Override
public byte[] getAgeWitnessInputData() {
// getAgeWitnessInputData is called at new account creation when accountId is empty string.
return super.getAgeWitnessInputData(accountId.getBytes(StandardCharsets.UTF_8));
}

public void setUserName(@Nullable String userName) {
this.userName = userName;
// We only set accountId to userName for new accounts. Existing accounts have accountId set with email
// or phone nr. and we keep that to not break account signing.
if (accountId.isEmpty()) {
accountId = userName;
}
}

public String getUserName() {
return userName != null ? userName : accountId;
}

public boolean userNameNotSet() {
return userName == null;
}
}
12 changes: 12 additions & 0 deletions core/src/main/java/bisq/core/user/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import bisq.core.notifications.alerts.market.MarketAlertFilter;
import bisq.core.notifications.alerts.price.PriceAlertFilter;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.RevolutAccount;
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;
import bisq.core.support.dispute.mediation.mediator.Mediator;
import bisq.core.support.dispute.refund.refundagent.RefundAgent;
Expand All @@ -50,6 +51,7 @@
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import lombok.AllArgsConstructor;
Expand Down Expand Up @@ -126,6 +128,16 @@ public void persist() {
// API
///////////////////////////////////////////////////////////////////////////////////////////

public void onAllServicesInitialized(@Nullable Consumer<List<RevolutAccount>> resultHandler) {
if (resultHandler != null) {
resultHandler.accept(paymentAccountsAsObservable.stream()
.filter(paymentAccount -> paymentAccount instanceof RevolutAccount)
.map(paymentAccount -> (RevolutAccount) paymentAccount)
.filter(RevolutAccount::userNameNotSet)
.collect(Collectors.toList()));
}
}

@Nullable
public Arbitrator getAcceptedArbitratorByAddress(NodeAddress nodeAddress) {
final List<Arbitrator> acceptedArbitrators = userPayload.getAcceptedArbitrators();
Expand Down
11 changes: 7 additions & 4 deletions core/src/main/resources/i18n/displayStrings.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3003,6 +3003,7 @@ seed.restore.error=An error occurred when restoring the wallets with seed words.
payment.account=Account
payment.account.no=Account no.
payment.account.name=Account name
payment.account.userName=User name
payment.account.owner=Account owner full name
payment.account.fullName=Full name (first, middle, last)
payment.account.state=State/Province/Region
Expand Down Expand Up @@ -3037,8 +3038,6 @@ payment.cashApp.cashTag=$Cashtag
payment.moneyBeam.accountId=Email or phone no.
payment.venmo.venmoUserName=Venmo username
payment.popmoney.accountId=Email or phone no.
payment.revolut.email=Email
payment.revolut.phoneNr=Registered phone no.
payment.promptPay.promptPayId=Citizen ID/Tax ID or phone no.
payment.supportedCurrencies=Supported currencies
payment.limitations=Limitations
Expand Down Expand Up @@ -3142,8 +3141,12 @@ payment.limits.info.withSigning=To limit chargeback risk, Bisq sets per-trade li
payment.cashDeposit.info=Please confirm your bank allows you to send cash deposits into other peoples' accounts. \
For example, Bank of America and Wells Fargo no longer allow such deposits.

payment.revolut.info=Please be sure that the phone number you used for your Revolut account is registered at Revolut \
otherwise the BTC buyer cannot send you the funds.
payment.revolut.info=Revolut requires the 'User name' as account ID not the phone number or email as it was the case in the past.
payment.account.revolut.addUserNameInfo={0}\n\
Your existing Revolut account ({1}) does not has set the ''User name''.\n\
Please enter your Revolut ''User name'' to update your account data.\n\
This will not affect your account age signing status.
payment.revolut.addUserNameInfo.headLine=Update Revolut account

payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Bisq requires that you understand the following:\n\
\n\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
import bisq.desktop.util.validation.RevolutValidator;

import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.Country;
import bisq.core.locale.CountryUtil;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.payment.PaymentAccount;
Expand All @@ -34,46 +32,28 @@
import bisq.core.util.coin.CoinFormatter;
import bisq.core.util.validation.InputValidator;

import com.jfoenix.controls.JFXComboBox;

import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;

import javafx.collections.FXCollections;

import javafx.util.StringConverter;

import static bisq.desktop.util.FormBuilder.addCompactTopLabelTextField;
import static bisq.desktop.util.FormBuilder.addCompactTopLabelTextFieldWithCopyIcon;
import static bisq.desktop.util.FormBuilder.addTopLabelFlowPane;
import static bisq.desktop.util.FormBuilder.addTopLabelTextField;
import static bisq.desktop.util.FormBuilder.addTopLabelWithVBox;

public class RevolutForm extends PaymentMethodForm {
private final RevolutAccount account;
private RevolutValidator validator;
private InputTextField accountIdInputTextField;
private Country selectedCountry;
private InputTextField userNameInputTextField;

public static int addFormForBuyer(GridPane gridPane, int gridRow,
PaymentAccountPayload paymentAccountPayload) {
String accountId = ((RevolutAccountPayload) paymentAccountPayload).getAccountId();
addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, getTitle(accountId), accountId);
String userName = ((RevolutAccountPayload) paymentAccountPayload).getUserName();
addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.get("payment.account.userName"), userName);

return gridRow;
}

private static String getTitle(String accountId) {
// From 0.9.4 on we only allow phone nr. as with emails we got too many disputes as users used an email which was
// not registered at Revolut. It seems that phone numbers need to be registered at least we have no reports from
// arbitrators with such cases. Thought email is still supported for backward compatibility.
// We might still get emails from users who have registered when email was supported
return accountId.contains("@") ? Res.get("payment.revolut.email") : Res.get("payment.revolut.phoneNr");
}

public RevolutForm(PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService,
RevolutValidator revolutValidator, InputValidator inputValidator, GridPane gridPane,
int gridRow, CoinFormatter formatter) {
Expand All @@ -86,63 +66,16 @@ public RevolutForm(PaymentAccount paymentAccount, AccountAgeWitnessService accou
public void addFormForAddAccount() {
gridRowFrom = gridRow + 1;

// country selection is added only to prevent anymore email id input and
// solely to validate the given phone number
ComboBox<Country> countryComboBox = addCountrySelection();
setCountryComboBoxAction(countryComboBox);
countryComboBox.setItems(FXCollections.observableArrayList(CountryUtil.getAllRevolutCountries()));

accountIdInputTextField = FormBuilder.addInputTextField(gridPane, ++gridRow, Res.get("payment.revolut.phoneNr"));
accountIdInputTextField.setValidator(validator);
accountIdInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
account.setAccountId(newValue.trim());
userNameInputTextField = FormBuilder.addInputTextField(gridPane, ++gridRow, Res.get("payment.account.userName"));
userNameInputTextField.setValidator(validator);
userNameInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
account.setUserName(newValue.trim());
updateFromInputs();
});

addCurrenciesGrid(true);
addLimitations(false);
addAccountNameTextFieldWithAutoFillToggleButton();

//set default country as selected
selectedCountry = CountryUtil.getDefaultCountry();
if (CountryUtil.getAllRevolutCountries().contains(selectedCountry)) {
countryComboBox.getSelectionModel().select(selectedCountry);
}
}

ComboBox<Country> addCountrySelection() {
HBox hBox = new HBox();

hBox.setSpacing(5);
ComboBox<Country> countryComboBox = new JFXComboBox<>();
hBox.getChildren().add(countryComboBox);

addTopLabelWithVBox(gridPane, ++gridRow, Res.get("payment.bank.country"), hBox, 0);

countryComboBox.setPromptText(Res.get("payment.select.bank.country"));
countryComboBox.setConverter(new StringConverter<>() {
@Override
public String toString(Country country) {
return country.name + " (" + country.code + ")";
}

@Override
public Country fromString(String s) {
return null;
}
});
return countryComboBox;
}

void setCountryComboBoxAction(ComboBox<Country> countryComboBox) {
countryComboBox.setOnAction(e -> {
selectedCountry = countryComboBox.getSelectionModel().getSelectedItem();
updateFromInputs();
accountIdInputTextField.resetValidation();
accountIdInputTextField.validate();
accountIdInputTextField.requestFocus();
countryComboBox.requestFocus();
});
}

private void addCurrenciesGrid(boolean isEditable) {
Expand All @@ -161,18 +94,18 @@ private void addCurrenciesGrid(boolean isEditable) {

@Override
protected void autoFillNameTextField() {
setAccountNameWithString(accountIdInputTextField.getText());
setAccountNameWithString(userNameInputTextField.getText());
}

@Override
public void addFormForDisplayAccount() {
gridRowFrom = gridRow;
addTopLabelTextField(gridPane, gridRow, Res.get("payment.account.name"),
addTopLabelTextField(gridPane, gridRow, Res.get("payment.account.userName"),
account.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE);
addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.paymentMethod"),
Res.get(account.getPaymentMethod().getId()));
String accountId = account.getAccountId();
TextField field = addCompactTopLabelTextField(gridPane, ++gridRow, getTitle(accountId), accountId).second;
String userName = account.getUserName();
TextField field = addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.userName"), userName).second;
field.setMouseTransparent(false);
addLimitations(true);
addCurrenciesGrid(false);
Expand All @@ -181,7 +114,7 @@ public void addFormForDisplayAccount() {
@Override
public void updateAllInputsValid() {
allInputsValid.set(isAccountNameValid()
&& validator.validate(account.getAccountId(), selectedCountry.code).isValid
&& validator.validate(account.getUserName()).isValid
&& account.getTradeCurrencies().size() > 0);
}
}
Loading

0 comments on commit 5b1d9cb

Please sign in to comment.