diff --git a/src/main/java/biz/nynja/account/StartupScriptsListener.java b/src/main/java/biz/nynja/account/StartupScriptsListener.java index 08acd3a00f23296f1a2dea8daed47594d640f365..ac797ab029f730ba455206115828361f22ceda77 100644 --- a/src/main/java/biz/nynja/account/StartupScriptsListener.java +++ b/src/main/java/biz/nynja/account/StartupScriptsListener.java @@ -56,7 +56,12 @@ public class StartupScriptsListener { + ".pendingaccountbyauthenticationprovider AS SELECT * FROM pendingaccount " + "WHERE authenticationprovider IS NOT NULL " + "PRIMARY KEY (authenticationprovider, accountid);"; + String scriptAccountViewByQrCode = "CREATE MATERIALIZED VIEW IF NOT EXISTS " + keyspace + + ".accountbyqrcode AS SELECT * FROM account " + "WHERE qrcode IS NOT NULL " + + "PRIMARY KEY (qrcode, accountid);"; + return Arrays.asList(scriptAccountViewByProfileId, scriptAccountViewByAuthProvider, - scriptAccountViewByAccountName, scriptAccountViewByUsername, scriptPendingAccountViewByAuthenticationProvider); + scriptAccountViewByAccountName, scriptAccountViewByUsername, + scriptPendingAccountViewByAuthenticationProvider, scriptAccountViewByQrCode); } } \ No newline at end of file diff --git a/src/main/java/biz/nynja/account/components/Validator.java b/src/main/java/biz/nynja/account/components/Validator.java index a27e8a676f87c42379cac91bae15df03a2abb1b0..9f7adf6964c1b422463f62d25b6c13f839375e95 100644 --- a/src/main/java/biz/nynja/account/components/Validator.java +++ b/src/main/java/biz/nynja/account/components/Validator.java @@ -22,10 +22,9 @@ import org.slf4j.LoggerFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.stereotype.Component; -import biz.nynja.account.grpc.AddAuthenticationProviderRequest; -import biz.nynja.account.grpc.AddContactInfoRequest; import com.google.i18n.phonenumbers.NumberParseException; import com.google.i18n.phonenumbers.PhoneNumberUtil; +import com.google.i18n.phonenumbers.Phonenumber; import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; import biz.nynja.account.grpc.AuthProviderDetails; import biz.nynja.account.grpc.AuthenticationType; @@ -43,6 +42,12 @@ import biz.nynja.account.models.CountryInfo; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; +import biz.nynja.account.phone.PhoneNumberValidator; +import biz.nynja.account.validation.Validation; +import biz.nynja.account.validation.ValidationError; +import biz.nynja.account.grpc.AddAuthenticationProviderRequest; +import biz.nynja.account.grpc.AddContactInfoRequest; + /** * Component which contains all validation methods. */ @@ -59,101 +64,13 @@ public class Validator { private static final int MIN_LAST_NAME_LENGTH = 0; private static final int MAX_LAST_NAME_LENGTH = 32; - private HashMap countryInfoMap; - - @PostConstruct - public void loadPhonesBook() { - - CountryInfo countryInfo = null; - BufferedReader reader = null; - countryInfoMap = new HashMap<>(); - - logger.debug("Loading phones information from file."); - try { - Resource resource = new ClassPathResource("countries.txt"); - InputStream resourceInputStream = resource.getInputStream(); - logger.debug("Phones information loaded."); - reader = new BufferedReader(new InputStreamReader(resourceInputStream)); - String line; - while ((line = reader.readLine()) != null) { - String[] args = line.split(";"); - countryInfo = new CountryInfo(); - countryInfo.setCountryCode(args[1]); - countryInfo.setCountryPhoneCode(args[0]); - countryInfo.setCountryName(args[2]); - if (args.length > 3) { - countryInfo.setPhoneFormat(args[3]); - } - countryInfoMap.put(args[1], countryInfo); - } - } catch (IOException e) { - logger.error("Error during load phones information: {}", e.getMessage()); - } finally { - try { - reader.close(); - } catch (IOException e) { - logger.error("Close reader error: {}", e.getMessage()); - } - } - - } - - public boolean isPhoneNumberValid(String phoneNumber, String countryCode) { - - logger.debug("Checking phoneNumber: {} for country: {}", phoneNumber, countryCode); - CountryInfo countryInfo = countryInfoMap.get(countryCode); - if (countryInfo == null) { - logger.debug("Country: {} not found!", countryCode); - return false; - } - - char[] digits = countryInfo.getCountryPhoneCode().toCharArray(); - StringBuilder builder = new StringBuilder(); - for (char digit : digits) { - builder.append("[" + digit + "]"); - } - String codePattern = builder.toString(); - - String phoneLength = null; - if (countryInfo.getPhoneFormat() != null) { - phoneLength = "{" + countryInfo.getPhoneFormat().replaceAll("\\s", "").length() + "}"; - } else { - phoneLength = "+"; - } - - final String PHONE_PATTERN = "((?:\\+?([0][0])?" + codePattern + ")?||([0][0]" + codePattern + ")?)(\\d" - + phoneLength + ")$"; - logger.debug("Generated phone pattern for country: {}, {}", countryCode, PHONE_PATTERN); - - Pattern pattern = Pattern.compile(PHONE_PATTERN); - Matcher matcher = pattern.matcher(phoneNumber); - - boolean isValid = matcher.matches(); - logger.debug("PhoneNumber: {} for country: {} is valid: {}", phoneNumber, countryCode, isValid); - - return isValid; + private PhoneNumberValidator phoneValidator; + + public Validator(PhoneNumberValidator phoneValidator) { + this.phoneValidator = phoneValidator; + } - public String getNormalizedPhoneNumber(String authenticationProvider) { - String[] provider = authenticationProvider.split(":"); - String country = provider[0]; - String phoneNumber = provider[1]; - logger.info("libphone: New phone number normalization request received - phone number: {}, country code: {}", phoneNumber, - country); - - PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); - String normalizedPhoneNumber = ""; - try { - PhoneNumber pn = phoneUtil.parse(phoneNumber, country); - normalizedPhoneNumber = Integer.toString(pn.getCountryCode()) + - Long.toString(pn.getNationalNumber()); - logger.info("libphone: Normalized phone number: " + normalizedPhoneNumber); - } catch (NumberParseException e) { - logger.error("libphone: NumberParseException was thrown: {}", e.toString()); - logger.debug("libphone: NumberParseException was thrown: {}", e.getCause()); - } - return normalizedPhoneNumber; - } public boolean isUsernameValid(String username) { @@ -204,6 +121,13 @@ public class Validator { return isValid; } + public boolean isValidUsername(String username) { + if(username == null) { + return false; + } + return username.matches("[a-zA-Z0-9_]{1,32}"); + } + boolean isAccountNameValid(String accountName) { logger.debug("Checking Account Name: {}", accountName); @@ -231,7 +155,7 @@ public class Validator { if (provider == null || provider.length != 2) { return Cause.PHONE_NUMBER_INVALID; } - if (!isPhoneNumberValid(provider[1], provider[0])) { + if (!phoneValidator.isPhoneNumberValid(provider[1], provider[0])) { return Cause.PHONE_NUMBER_INVALID; } break; @@ -259,7 +183,7 @@ public class Validator { if (provider == null || provider.length != 2) { return Optional.of(new ImmutablePair<>(Cause.PHONE_NUMBER_INVALID, "Invalid phone number")); } - if (!isPhoneNumberValid(provider[1], provider[0])) { + if (!phoneValidator.isPhoneNumberValid(provider[1], provider[0])) { return Optional.of(new ImmutablePair<>(Cause.PHONE_NUMBER_INVALID, "Invalid phone number")); } break; diff --git a/src/main/java/biz/nynja/account/models/AccountByQrCode.java b/src/main/java/biz/nynja/account/models/AccountByQrCode.java new file mode 100644 index 0000000000000000000000000000000000000000..f80d84f263caaed54a51c501be434a515a3972a2 --- /dev/null +++ b/src/main/java/biz/nynja/account/models/AccountByQrCode.java @@ -0,0 +1,345 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ +package biz.nynja.account.models; + +import java.nio.ByteBuffer; +import java.util.Set; +import java.util.UUID; + +import biz.nynja.account.grpc.AccessStatus; +import biz.nynja.account.grpc.AccountDetails; +import biz.nynja.account.grpc.Role; +import biz.nynja.account.grpc.AccountDetails.Builder; + +public class AccountByQrCode { + + private UUID profileId; + private UUID accountId; + private String accountMark; + private String authenticationProvider; + private String authenticationProviderType; + private String firstName; + private String lastName; + private ByteBuffer avatar; + private String accountName; + private String username; + private Long creationTimestamp; + private Long lastUpdateTimestamp; + private Set contactsInfo; + private String qrCode; + private String accessStatus; + private Set roles; + + public UUID getProfileId() { + return profileId; + } + + public void setProfileId(UUID profileId) { + this.profileId = profileId; + } + + public UUID getAccountId() { + return accountId; + } + + public void setAccountId(UUID accountId) { + this.accountId = accountId; + } + + public String getAccountMark() { + return accountMark; + } + + public void setAccountMark(String accountMark) { + this.accountMark = accountMark; + } + + public String getAuthenticationProvider() { + return authenticationProvider; + } + + public void setAuthenticationProvider(String authenticationProvider) { + this.authenticationProvider = authenticationProvider; + } + + public String getAuthenticationProviderType() { + return authenticationProviderType; + } + + public void setAuthenticationProviderType(String authenticationProviderType) { + this.authenticationProviderType = authenticationProviderType; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public ByteBuffer getAvatar() { + return avatar; + } + + public void setAvatar(ByteBuffer avatar) { + this.avatar = avatar; + } + + public String getAccountName() { + return accountName; + } + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getAccessStatus() { + return accessStatus; + } + + public void setAccessStatus(String accesstStatus) { + this.accessStatus = accesstStatus; + } + + public Long getCreationTimestamp() { + return creationTimestamp; + } + + public void setCreationTimestamp(Long creationTimestamp) { + this.creationTimestamp = creationTimestamp; + } + + public Long getLastUpdateTimestamp() { + return lastUpdateTimestamp; + } + + public void setLastUpdateTimestamp(Long lastUpdateTimestamp) { + this.lastUpdateTimestamp = lastUpdateTimestamp; + } + + public Set getContactsInfo() { + return contactsInfo; + } + + public void setContactsInfo(Set contactsInfo) { + this.contactsInfo = contactsInfo; + } + + public String getQrCode() { + return qrCode; + } + + public void setQrCode(String qrCode) { + this.qrCode = qrCode; + } + + public Set getRoles() { + return roles; + } + + public void setRoles(Set roles) { + this.roles = roles; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((accountId == null) ? 0 : accountId.hashCode()); + result = prime * result + ((accountMark == null) ? 0 : accountMark.hashCode()); + result = prime * result + ((accountName == null) ? 0 : accountName.hashCode()); + result = prime * result + ((accessStatus == null) ? 0 : accessStatus.hashCode()); + result = prime * result + ((authenticationProvider == null) ? 0 : authenticationProvider.hashCode()); + result = prime * result + ((authenticationProviderType == null) ? 0 : authenticationProviderType.hashCode()); + result = prime * result + ((avatar == null) ? 0 : avatar.hashCode()); + result = prime * result + ((contactsInfo == null) ? 0 : contactsInfo.hashCode()); + result = prime * result + ((creationTimestamp == null) ? 0 : creationTimestamp.hashCode()); + result = prime * result + ((firstName == null) ? 0 : firstName.hashCode()); + result = prime * result + ((lastName == null) ? 0 : lastName.hashCode()); + result = prime * result + ((lastUpdateTimestamp == null) ? 0 : lastUpdateTimestamp.hashCode()); + result = prime * result + ((profileId == null) ? 0 : profileId.hashCode()); + result = prime * result + ((qrCode == null) ? 0 : qrCode.hashCode()); + result = prime * result + ((roles == null) ? 0 : roles.hashCode()); + result = prime * result + ((username == null) ? 0 : username.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AccountByQrCode other = (AccountByQrCode) obj; + if (accountId == null) { + if (other.accountId != null) + return false; + } else if (!accountId.equals(other.accountId)) + return false; + if (accountMark == null) { + if (other.accountMark != null) + return false; + } else if (!accountMark.equals(other.accountMark)) + return false; + if (accountName == null) { + if (other.accountName != null) + return false; + } else if (!accountName.equals(other.accountName)) + return false; + if (accessStatus == null) { + if (other.accessStatus != null) + return false; + } else if (!accessStatus.equals(other.accessStatus)) + return false; + if (authenticationProvider == null) { + if (other.authenticationProvider != null) + return false; + } else if (!authenticationProvider.equals(other.authenticationProvider)) + return false; + if (authenticationProviderType == null) { + if (other.authenticationProviderType != null) + return false; + } else if (!authenticationProviderType.equals(other.authenticationProviderType)) + return false; + if (avatar == null) { + if (other.avatar != null) + return false; + } else if (!avatar.equals(other.avatar)) + return false; + if (contactsInfo == null) { + if (other.contactsInfo != null) + return false; + } else if (!contactsInfo.equals(other.contactsInfo)) + return false; + if (creationTimestamp == null) { + if (other.creationTimestamp != null) + return false; + } else if (!creationTimestamp.equals(other.creationTimestamp)) + return false; + if (firstName == null) { + if (other.firstName != null) + return false; + } else if (!firstName.equals(other.firstName)) + return false; + if (lastName == null) { + if (other.lastName != null) + return false; + } else if (!lastName.equals(other.lastName)) + return false; + if (lastUpdateTimestamp == null) { + if (other.lastUpdateTimestamp != null) + return false; + } else if (!lastUpdateTimestamp.equals(other.lastUpdateTimestamp)) + return false; + if (profileId == null) { + if (other.profileId != null) + return false; + } else if (!profileId.equals(other.profileId)) + return false; + if (qrCode == null) { + if (other.qrCode != null) + return false; + } else if (!qrCode.equals(other.qrCode)) + return false; + if (roles == null) { + if (other.roles != null) + return false; + } else if (!roles.equals(other.roles)) + return false; + if (username == null) { + if (other.username != null) + return false; + } else if (!username.equals(other.username)) + return false; + return true; + } + + @Override + public String toString() { + return new StringBuilder("AccountByQrCode [accountId=").append(accountId).append(", profileId=") + .append(profileId).append(", accountMark=").append(accountMark).append(", authenticationProvider=") + .append(authenticationProvider).append(", authenticationProviderType=") + .append(authenticationProviderType).append(", firstName=").append(firstName).append(", lastName=") + .append(lastName).append(", avatar=").append(avatar).append(", accountName=").append(accountName) + .append(", username=").append(username).append(", accessStatus=").append(accessStatus) + .append(", creationTimestamp=").append(creationTimestamp).append(", lastUpdateTimestamp=") + .append(lastUpdateTimestamp).append(", qrCode=").append(qrCode).append(", contactsInfo=") + .append(contactsInfo).append(", roles=").append(roles).append("]").toString(); + } + + public AccountDetails toProto() { + + Builder builder = AccountDetails.newBuilder(); + + if (getAccountId() != null) { + builder.setAccountId(getAccountId().toString()); + } + if (getProfileId() != null) { + builder.setProfileId(getProfileId().toString()); + } + if (getAuthenticationProvider() != null) { + builder.setAuthenticationIdentifier(getAuthenticationProvider()); + } + if (getAuthenticationProviderType() != null) { + builder.setAuthenticationType(getAuthenticationProviderType()); + } + if (getAccountMark() != null) { + builder.setAccountMark(getAccountMark()); + } + if (getAccountName() != null) { + builder.setAccountName(getAccountName()); + } + if (getFirstName() != null) { + builder.setFirstName(getFirstName()); + } + if (getLastName() != null) { + builder.setLastName(getLastName()); + } + if (getUsername() != null) { + builder.setUsername(getUsername()); + } + if (getQrCode() != null) { + builder.setQrCode(getQrCode()); + } + if (getAvatar() != null) { + builder.setAvatar(com.google.protobuf.ByteString.copyFrom(avatar)); + } + if (getRoles() != null) { + for (String role : getRoles()) { + builder.addRoles(Role.valueOf(role)); + } + } + if (getAccessStatus() != null) { + builder.setAccessStatus(AccessStatus.valueOf(getAccessStatus())); + } + if (getContactsInfo() != null) { + for (ContactInfo c : contactsInfo) { + builder.addContactsInfo(c.toProto()); + } + } + + return builder.build(); + + } + +} diff --git a/src/main/java/biz/nynja/account/models/AccountByUsername.java b/src/main/java/biz/nynja/account/models/AccountByUsername.java index ebe01dcc9e7b90a38a8d7cc969612a712a9b4e13..ed40828a67ef508733e32e18410c77d9f4711d8a 100644 --- a/src/main/java/biz/nynja/account/models/AccountByUsername.java +++ b/src/main/java/biz/nynja/account/models/AccountByUsername.java @@ -8,6 +8,11 @@ import java.time.LocalDate; import java.util.Set; import java.util.UUID; +import biz.nynja.account.grpc.AccessStatus; +import biz.nynja.account.grpc.AccountDetails; +import biz.nynja.account.grpc.Role; +import biz.nynja.account.grpc.AccountDetails.Builder; + public class AccountByUsername { private UUID profileId; @@ -299,5 +304,60 @@ public class AccountByUsername { .append(", accessStatus=").append(accessStatus).append(", birthday=").append(birthday).append("]"); return builder.toString(); } - + + public AccountDetails toProto() { + + Builder builder = AccountDetails.newBuilder(); + + if (getAccountId() != null) { + builder.setAccountId(getAccountId().toString()); + } + if (getProfileId() != null) { + builder.setProfileId(getProfileId().toString()); + } + if (getAuthenticationProvider() != null) { + builder.setAuthenticationIdentifier(getAuthenticationProvider()); + } + if (getAuthenticationProviderType() != null) { + builder.setAuthenticationType(getAuthenticationProviderType()); + } + if (getAccountMark() != null) { + builder.setAccountMark(getAccountMark()); + } + if (getAccountName() != null) { + builder.setAccountName(getAccountName()); + } + if (getFirstName() != null) { + builder.setFirstName(getFirstName()); + } + if (getLastName() != null) { + builder.setLastName(getLastName()); + } + if (getUsername() != null) { + builder.setUsername(getUsername()); + } + if (getQrCode() != null) { + builder.setQrCode(getQrCode()); + } + if (getAvatar() != null) { + builder.setAvatar(com.google.protobuf.ByteString.copyFrom(avatar)); + } + if (getRoles() != null) { + for (String role : getRoles()) { + builder.addRoles(Role.valueOf(role)); + } + } + if (getAccessStatus() != null) { + builder.setAccessStatus(AccessStatus.valueOf(getAccessStatus())); + } + if (getContactsInfo() != null) { + for (ContactInfo c : contactsInfo) { + builder.addContactsInfo(c.toProto()); + } + } + + return builder.build(); + + } + } diff --git a/src/main/java/biz/nynja/account/phone/InvalidPhoneNumberException.java b/src/main/java/biz/nynja/account/phone/InvalidPhoneNumberException.java new file mode 100644 index 0000000000000000000000000000000000000000..51efe7344e0cadf63c62bf60b91aa8c615c40551 --- /dev/null +++ b/src/main/java/biz/nynja/account/phone/InvalidPhoneNumberException.java @@ -0,0 +1,8 @@ +package biz.nynja.account.phone; + +public class InvalidPhoneNumberException extends RuntimeException{ + + public InvalidPhoneNumberException(String msg) { + super(msg); + } +} diff --git a/src/main/java/biz/nynja/account/components/PhoneNumberNormalizer.java b/src/main/java/biz/nynja/account/phone/PhoneNumberNormalizer.java similarity index 96% rename from src/main/java/biz/nynja/account/components/PhoneNumberNormalizer.java rename to src/main/java/biz/nynja/account/phone/PhoneNumberNormalizer.java index 1ed7fc95598bba6466e6590beb80e3f0594b3c8c..e9b434f1703bf22c686f21508a91a5804661b42d 100644 --- a/src/main/java/biz/nynja/account/components/PhoneNumberNormalizer.java +++ b/src/main/java/biz/nynja/account/phone/PhoneNumberNormalizer.java @@ -1,11 +1,12 @@ /** * Copyright (C) 2018 Nynja Inc. All rights reserved. */ -package biz.nynja.account.components; +package biz.nynja.account.phone; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import biz.nynja.account.components.Validator; import biz.nynja.account.grpc.AddContactInfoRequest; import biz.nynja.account.grpc.ContactDetails; import biz.nynja.account.grpc.DeleteContactInfoRequest; @@ -15,7 +16,7 @@ import biz.nynja.account.grpc.EditContactInfoRequest; public class PhoneNumberNormalizer { @Autowired - private Validator validator; + private PhoneNumberValidator validator; public AddContactInfoRequest normalizePhoneNumber(AddContactInfoRequest request) { // Get the normalized phone number from libphone diff --git a/src/main/java/biz/nynja/account/phone/PhoneNumberValidator.java b/src/main/java/biz/nynja/account/phone/PhoneNumberValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..125928aee3544fa1156f573f2213989f5dd3c46a --- /dev/null +++ b/src/main/java/biz/nynja/account/phone/PhoneNumberValidator.java @@ -0,0 +1,208 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ + +package biz.nynja.account.phone; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.PostConstruct; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Component; + +import com.google.i18n.phonenumbers.NumberParseException; +import com.google.i18n.phonenumbers.PhoneNumberUtil; +import com.google.i18n.phonenumbers.Phonenumber; +import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; + +import biz.nynja.account.grpc.ErrorResponse.Cause; +import biz.nynja.account.models.CountryInfo; +import biz.nynja.account.validation.ValidationError; + +@Component +public class PhoneNumberValidator { + private static final Logger logger = LoggerFactory.getLogger(PhoneNumberValidator.class); + private HashMap countryInfoMap; + private HashMap countryMapByCountryCode; + + @PostConstruct + public void loadPhonesBook() { + + CountryInfo countryInfo = null; + BufferedReader reader = null; + countryInfoMap = new HashMap<>(); + countryMapByCountryCode = new HashMap<>(); + + logger.debug("Loading phones information from file."); + try { + Resource resource = new ClassPathResource("countries.txt"); + InputStream resourceInputStream = resource.getInputStream(); + logger.debug("Phones information loaded."); + reader = new BufferedReader(new InputStreamReader(resourceInputStream)); + String line; + while ((line = reader.readLine()) != null) { + String[] args = line.split(";"); + countryInfo = new CountryInfo(); + countryInfo.setCountryCode(args[1]); + countryInfo.setCountryPhoneCode(args[0]); + countryInfo.setCountryName(args[2]); + if (args.length > 3) { + countryInfo.setPhoneFormat(args[3]); + } + countryInfoMap.put(args[1], countryInfo); + countryMapByCountryCode.put(args[0], countryInfo); + } + } catch (IOException e) { + logger.error("Error during load phones information: {}", e.getMessage()); + } finally { + try { + reader.close(); + } catch (IOException e) { + logger.error("Close reader error: {}", e.getMessage()); + } + } + + } + + public boolean isPhoneNumberValid(String phoneNumber, String countryCode) { + + logger.debug("Checking phoneNumber: {} for country: {}", phoneNumber, countryCode); + CountryInfo countryInfo = countryInfoMap.get(countryCode); + if (countryInfo == null) { + logger.debug("Country: {} not found!", countryCode); + return false; + } + + char[] digits = countryInfo.getCountryPhoneCode().toCharArray(); + StringBuilder builder = new StringBuilder(); + for (char digit : digits) { + builder.append("[" + digit + "]"); + } + String codePattern = builder.toString(); + + String phoneLength = null; + if (countryInfo.getPhoneFormat() != null) { + phoneLength = "{" + countryInfo.getPhoneFormat().replaceAll("\\s", "").length() + "}"; + } else { + phoneLength = "+"; + } + + final String PHONE_PATTERN = "((?:\\+?([0][0])?" + codePattern + ")?||([0][0]" + codePattern + ")?)(\\d" + + phoneLength + ")$"; + logger.debug("Generated phone pattern for country: {}, {}", countryCode, PHONE_PATTERN); + + Pattern pattern = Pattern.compile(PHONE_PATTERN); + Matcher matcher = pattern.matcher(phoneNumber); + + boolean isValid = matcher.matches(); + logger.debug("PhoneNumber: {} for country: {} is valid: {}", phoneNumber, countryCode, isValid); + + return isValid; + } + + + + /** + * + * @param rawPhoneNumber + * it could be in format + i.e +359878123456 or 00 i.e + * 00359878123456 or : i.e :359878225840 + */ + public boolean isPhoneNumberValid(String rawPhoneNumber) { + String phoneNumber; + + String[] provider = rawPhoneNumber.split(":"); + if (provider.length == 1) { // no country selector + phoneNumber = provider[0]; + } else { + phoneNumber = provider[1]; + } + if (!phoneNumber.matches("^\\+?[\\d- ]+$")) { + return false; + } + phoneNumber = phoneNumber.replaceAll("^0*", "").replaceAll("[^\\d]", ""); + + String countrySelector; + try { + countrySelector = getCountrySelector(phoneNumber); + } catch (InvalidPhoneNumberException e) { + return false; + } + + if (!isPhoneNumberValid(phoneNumber, countrySelector)) { + return false; + } + + if ((provider.length == 2) && (!countrySelector.equals(provider[0]))) { + return false; + } + + return true; + } + + private String getCountryCode(String phoneNumber) { + + PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); + try { + Phonenumber.PhoneNumber numberProto = phoneUtil.parse("+" + phoneNumber, ""); + logger.debug("Country code found: {}", numberProto.getCountryCode()); + return Integer.toString(numberProto.getCountryCode()); + } catch (NumberParseException e) { + throw new InvalidPhoneNumberException("No country code found for phone number: " + phoneNumber); + } + } + + public String getNormalizedPhoneNumber(String rawPhoneNumber) throws InvalidPhoneNumberException { + String[] provider = rawPhoneNumber.split(":"); + if (provider == null || provider.length > 2) { + throw new InvalidPhoneNumberException("Phone number with wrong format: " + rawPhoneNumber); + } + String country; + String phoneNumber; + if(provider.length == 1) { + country = getCountrySelector(provider[0]); + phoneNumber = provider[0]; + } else { + country = provider[0]; + phoneNumber = provider[1]; + } + logger.info("libphone: New phone number normalization request received - phone number: {}, country code: {}", + phoneNumber, country); + + PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); + String normalizedPhoneNumber = ""; + try { + PhoneNumber pn = phoneUtil.parse(phoneNumber, country); + normalizedPhoneNumber = Integer.toString(pn.getCountryCode()) + Long.toString(pn.getNationalNumber()); + logger.info("libphone: Normalized phone number: " + normalizedPhoneNumber); + } catch (NumberParseException e) { + logger.error("libphone: NumberParseException was thrown: {}", e.toString()); + logger.debug("libphone: NumberParseException was thrown: {}", e.getCause()); + } + return normalizedPhoneNumber; + } + + private String getCountrySelector(String phoneNumber) throws InvalidPhoneNumberException{ + String countryCode; + countryCode = getCountryCode(phoneNumber); + + CountryInfo countryInfo = countryMapByCountryCode.get(countryCode); + if (countryInfo != null) { + return countryInfo.getCountryCode(); + } else { + logger.debug("Country selector not found in'countries.txt' for country code: {}", countryCode); + throw new InvalidPhoneNumberException("No country found for code: " + countryCode); + } + } + +} diff --git a/src/main/java/biz/nynja/account/repositories/AccountByQrCodeRepository.java b/src/main/java/biz/nynja/account/repositories/AccountByQrCodeRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..0d893fb77a39823a8e2c926241c75320e3d30a9c --- /dev/null +++ b/src/main/java/biz/nynja/account/repositories/AccountByQrCodeRepository.java @@ -0,0 +1,17 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ +package biz.nynja.account.repositories; + +import org.springframework.data.cassandra.repository.CassandraRepository; +import org.springframework.stereotype.Repository; + +import biz.nynja.account.models.AccountByQrCode; +import biz.nynja.account.models.AccountByUsername; + +@Repository +public interface AccountByQrCodeRepository extends CassandraRepository { + + AccountByQrCode findByQrCode(String qrCode); + +} diff --git a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java index 1909e98ac0e71c80b7eff8c9db2de5969a5568c8..9f6ea47620cb94131a29f348b97fe2aad380f59d 100644 --- a/src/main/java/biz/nynja/account/services/AccountServiceImpl.java +++ b/src/main/java/biz/nynja/account/services/AccountServiceImpl.java @@ -3,8 +3,6 @@ */ package biz.nynja.account.services; -import static biz.nynja.account.grpc.ErrorResponse.newBuilder; - import java.time.Instant; import java.util.Optional; import java.util.UUID; @@ -14,48 +12,28 @@ import org.lognet.springboot.grpc.GRpcService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import biz.nynja.account.components.PhoneNumberNormalizer; import biz.nynja.account.components.Validator; -import biz.nynja.account.grpc.AccountByAccountIdRequest; -import biz.nynja.account.grpc.AccountByAuthenticationProviderRequest; -import biz.nynja.account.grpc.AccountResponse; -import biz.nynja.account.grpc.AccountServiceGrpc; -import biz.nynja.account.grpc.AccountsByProfileIdRequest; -import biz.nynja.account.grpc.AccountsResponse; -import biz.nynja.account.grpc.AddAuthenticationProviderRequest; -import biz.nynja.account.grpc.AddContactInfoRequest; -import biz.nynja.account.grpc.AuthProviderDetails; -import biz.nynja.account.grpc.AuthenticationType; -import biz.nynja.account.grpc.CompletePendingAccountCreationRequest; -import biz.nynja.account.grpc.ContactType; -import biz.nynja.account.grpc.CreateAccountRequest; -import biz.nynja.account.grpc.CreatePendingAccountRequest; -import biz.nynja.account.grpc.CreatePendingAccountResponse; -import biz.nynja.account.grpc.DeleteAccountRequest; -import biz.nynja.account.grpc.DeleteAuthenticationProviderRequest; -import biz.nynja.account.grpc.DeleteContactInfoRequest; -import biz.nynja.account.grpc.DeleteProfileRequest; -import biz.nynja.account.grpc.EditContactInfoRequest; + +import biz.nynja.account.grpc.*; import biz.nynja.account.grpc.ErrorResponse.Cause; -import biz.nynja.account.grpc.ProfileResponse; -import biz.nynja.account.grpc.Role; -import biz.nynja.account.grpc.StatusResponse; -import biz.nynja.account.grpc.UpdateAccountRequest; -import biz.nynja.account.grpc.UpdateProfileRequest; import biz.nynja.account.models.Account; -import biz.nynja.account.models.AuthenticationProvider; -import biz.nynja.account.models.ContactInfo; -import biz.nynja.account.models.PendingAccount; -import biz.nynja.account.models.PendingAccountByAuthenticationProvider; -import biz.nynja.account.models.Profile; -import biz.nynja.account.models.ProfileByAuthenticationProvider; +import biz.nynja.account.phone.PhoneNumberNormalizer; +import biz.nynja.account.phone.PhoneNumberValidator; +import biz.nynja.account.models.*; +import biz.nynja.account.repositories.AccountByAuthenticationProviderRepository; +import biz.nynja.account.repositories.AccountByQrCodeRepository; +import biz.nynja.account.repositories.AccountByUsernameRepository; import biz.nynja.account.repositories.AccountRepositoryAdditional; import biz.nynja.account.repositories.PendingAccountRepository; import biz.nynja.account.repositories.ProfileByAuthenticationProviderRepository; import biz.nynja.account.repositories.ProfileRepository; import biz.nynja.account.services.decomposition.AccountsProvider; +import biz.nynja.account.validation.ValidationError; +import biz.nynja.account.validation.Validation; import io.grpc.stub.StreamObserver; +import java.nio.ByteBuffer; + /** * gRPC Account service implementation.
* The service extends the protobuf generated class and overrides the needed methods. It also saves/retrieves the @@ -71,19 +49,34 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas private final AccountRepositoryAdditional accountRepositoryAdditional; private final ProfileRepository profileRepository; private final ProfileByAuthenticationProviderRepository profileByAutheticationProviderRepository; + private final AccountByQrCodeRepository accountByQrCodeRepository; + private final AccountByAuthenticationProviderRepository accountByAuthenticationProviderRepository; + private final AccountByUsernameRepository accountByUsernameRepository; private final Validator validator; + private final PhoneNumberValidator phoneNumberValidator; private final AccountsProvider accountsProvider; private final PhoneNumberNormalizer phoneNumberNormalizer; public AccountServiceImpl(PendingAccountRepository pendingAccountRepository, - AccountRepositoryAdditional accountRepositoryAdditional, ProfileRepository profileRepository, - ProfileByAuthenticationProviderRepository profileByAutheticationProviderRepository, Validator validator, - AccountsProvider accountsProvider, PhoneNumberNormalizer phoneNumberNormalizer) { + AccountRepositoryAdditional accountRepositoryAdditional, + ProfileRepository profileRepository, + ProfileByAuthenticationProviderRepository profileByAutheticationProviderRepository, + AccountByQrCodeRepository accountByQrCodeRepository, + AccountByAuthenticationProviderRepository accountByAuthenticationProviderRepository, + AccountByUsernameRepository accountByUsernameRepository, + Validator validator, + PhoneNumberValidator phoneNumbervalidator, + AccountsProvider accountsProvider, + PhoneNumberNormalizer phoneNumberNormalizer) { this.pendingAccountRepository = pendingAccountRepository; this.accountRepositoryAdditional = accountRepositoryAdditional; this.profileRepository = profileRepository; this.profileByAutheticationProviderRepository = profileByAutheticationProviderRepository; + this.accountByQrCodeRepository = accountByQrCodeRepository; + this.accountByAuthenticationProviderRepository = accountByAuthenticationProviderRepository; + this.accountByUsernameRepository = accountByUsernameRepository; this.validator = validator; + this.phoneNumberValidator = phoneNumbervalidator; this.accountsProvider = accountsProvider; this.phoneNumberNormalizer = phoneNumberNormalizer; } @@ -108,17 +101,204 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas sendErrorMessageForAccountResponse(responseObserver, Cause.MISSING_AUTH_PROVIDER_IDENTIFIER); return; } - Optional account = accountsProvider.getAccountByAuthenticationProvider(request); + Optional account = accountsProvider.getAccountResponseByAuthenticationProvider( + request.getAuthenticationType(), request.getAuthenticationIdentifier()); if (!account.isPresent()) { sendErrorMessageForAccountResponse(responseObserver, Cause.ACCOUNT_NOT_FOUND); + return; } else { responseObserver.onNext(account.get()); responseObserver.onCompleted(); + return; + } + + } + + @Override + public void searchByEmail(GetByEmailRequest request, StreamObserver responseObserver) { + logger.info("Search account by e-mail: {}", request.getEmail()); + if ((request.getEmail() == null) || request.getEmail().isEmpty()) { + logAndBuildGrpcResponse(responseObserver, new ValidationError("Missing e-mail.", Cause.MISSING_EMAIL)); + return; + } + if (!validator.isEmailValid(request.getEmail())) { + logAndBuildGrpcResponse(responseObserver, new ValidationError("Invalid e-mail!. Value : " + request.getEmail(), Cause.EMAIL_INVALID)); + return; + } + + Optional account = accountsProvider.getAccountByAuthenticationProvider(AuthenticationType.EMAIL, + request.getEmail()); + + if (!account.isPresent()) { + logAndBuildGrpcResponse(responseObserver, new ValidationError("No matching accounts found for e-mail: " + request.getEmail(), + Cause.EMAIL_NOT_FOUND)); + return; + } else { + SearchResultDetails searchResultDetails = buildSearchResultDetails(account.get().getAccountId().toString(), + account.get().getAvatar(), account.get().getFirstName(), account.get().getLastName()); + + SearchResponse response = SearchResponse.newBuilder().setSearchResultDetails(searchResultDetails).build(); + logger.debug("Found result for account by e-mail {}: \"{}\"", request.getEmail(), response); + responseObserver.onNext(response); + responseObserver.onCompleted(); + return; + } + } + + @Override + public void searchByPhoneNumber(GetByPhoneNumberRequest request, StreamObserver responseObserver) { + + logger.info("Search account by phone: {}", request.getPhoneNumber()); + if ((request.getPhoneNumber() == null) || request.getPhoneNumber().isEmpty()) { + logAndBuildGrpcResponse(responseObserver, new ValidationError("Missing phone number.", Cause.MISSING_PHONENUMBER)); + return; + } + + if (!phoneNumberValidator.isPhoneNumberValid(request.getPhoneNumber())) { + logAndBuildGrpcResponse(responseObserver, new ValidationError("Invalid phone number.", Cause.INVALID_PHONENUMBER)); + return; + } + + Optional account = accountsProvider.getAccountByAuthenticationProvider(AuthenticationType.PHONE, + request.getPhoneNumber()); + + if (!account.isPresent()) { + logAndBuildGrpcResponse(responseObserver, new ValidationError( + "No matching accounts found for phone:" + request.getPhoneNumber(), Cause.PHONENUMBER_NOT_FOUND)); + return; + } else { + SearchResultDetails searchResultDetails = buildSearchResultDetails(account.get().getAccountId().toString(), + account.get().getAvatar(), account.get().getFirstName(), account.get().getLastName()); + + SearchResponse response = SearchResponse.newBuilder().setSearchResultDetails(searchResultDetails).build(); + logger.debug("Found result for account by phone {}: \"{}\"", request.getPhoneNumber(), response); + responseObserver.onNext(response); + responseObserver.onCompleted(); + return; + } + } + + @Override + public void getAccountByUsername(GetByUsernameRequest request, StreamObserver responseObserver) { + logger.info("Getting account by username: {}", request.getUsername()); + Validation validation = validateGetByUsernameRequest(request); + if(validation.hasErrors()) { + logger.debug(validation.getErrorMessage()); + responseObserver.onNext(AccountResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setMessage(validation.getErrorMessage()) + .setCause(validation.getCause().get())).build()); + responseObserver.onCompleted(); + return; + } + + Optional accountResonse = + accountsProvider.getAccountResponseByUsername(request.getUsername()); + + if (!accountResonse.isPresent()) { + sendErrorMessageForAccountResponse(responseObserver, Cause.ACCOUNT_NOT_FOUND); + return; + } else { + responseObserver.onNext(accountResonse.get()); + responseObserver.onCompleted(); + return; + } + } + + @Override + public void searchByUsername(GetByUsernameRequest request, StreamObserver responseObserver) { + logger.info("Searching account by username: {}", request.getUsername()); + Validation validation = validateGetByUsernameRequest(request); + if(validation.hasErrors()) { + logAndBuildGrpcResponse(responseObserver, validation); + return; + } + + AccountByUsername account = accountByUsernameRepository.findByUsername(request.getUsername()); + if (account == null) { + logAndBuildGrpcResponse(responseObserver, new ValidationError("No matching accounts found for username: "+ + request.getUsername(), Cause.USERNAME_NOT_FOUND)); + return; + } + + SearchResultDetails searchResultDetails = buildSearchResultDetails(account.getAccountId().toString(), + account.getAvatar(), account.getFirstName(), account.getLastName()); + + SearchResponse response = SearchResponse.newBuilder().setSearchResultDetails(searchResultDetails).build(); + logger.debug("Found result for account by username {}: \"{}\"", request.getUsername(), response); + responseObserver.onNext(response); + responseObserver.onCompleted(); + + return; + } + + private Validation validateGetByUsernameRequest(GetByUsernameRequest request) { + Validation validation = new Validation(); + + if ((request.getUsername() == null) || request.getUsername().isEmpty()) { + validation.addError(new ValidationError("Missing username.", Cause.MISSING_USERNAME)); } + if (!validator.isValidUsername(request.getUsername())) { + validation.addError( + new ValidationError("Invalid username. Value: " + request.getUsername(), Cause.USERNAME_INVALID)); + } + + return validation; + } + @Override + public void getAccountByQrCode(GetByQrCodeRequest request, StreamObserver responseObserver) { + logger.info("Search account by QR code: {}", request.getQrCode()); + if ((request.getQrCode() == null) || request.getQrCode().isEmpty()) { + logger.debug("Missing QR code."); + responseObserver.onNext(AccountResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setMessage("Missing QR code.") + .setCause(Cause.MISSING_QR_CODE)).build()); + responseObserver.onCompleted(); + return; + } + + Optional accountResonse = + accountsProvider.getAccountResponseByQrCode(request.getQrCode()); + + if (!accountResonse.isPresent()) { + sendErrorMessageForAccountResponse(responseObserver, Cause.ACCOUNT_NOT_FOUND); + return; + } else { + responseObserver.onNext(accountResonse.get()); + responseObserver.onCompleted(); + return; + } + } + @Override + public void searchByQrCode(GetByQrCodeRequest request, StreamObserver responseObserver) { + logger.info("Search account by QR code: {}", request.getQrCode()); + if ((request.getQrCode() == null) || request.getQrCode().isEmpty()) { + logAndBuildGrpcResponse(responseObserver, new ValidationError("Missing QR code.", Cause.MISSING_QR_CODE)); + return; + } + + AccountByQrCode account = accountByQrCodeRepository.findByQrCode(request.getQrCode()); + if (account == null) { + logAndBuildGrpcResponse(responseObserver, new ValidationError("No matching accounts found for QR code! Value: " + request.getQrCode(), + Cause.QR_CODE_NOT_FOUND)); + return; + } + + SearchResultDetails searchResultDetails = buildSearchResultDetails(account.getAccountId().toString(), + account.getAvatar(), account.getFirstName(), account.getLastName()); + + SearchResponse response = SearchResponse.newBuilder().setSearchResultDetails(searchResultDetails).build(); + logger.debug("Found result for account by QR code {}: \"{}\"", request.getQrCode(), response); + responseObserver.onNext(response); + responseObserver.onCompleted(); + + return; + } + + @Override public void getAllAccountsByProfileId(AccountsByProfileIdRequest request, StreamObserver responseObserver) { @@ -139,6 +319,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas } else { responseObserver.onNext(accounts.get()); responseObserver.onCompleted(); + return; } } @@ -162,9 +343,11 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas if (!account.isPresent()) { sendErrorMessageForAccountResponse(responseObserver, Cause.ACCOUNT_NOT_FOUND); + return; } else { responseObserver.onNext(account.get()); responseObserver.onCompleted(); + return; } } @@ -177,8 +360,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas Cause cause = validator.validateCreatePendingAccountRequest(request); if (cause != null) { - responseObserver - .onNext(CreatePendingAccountResponse.newBuilder().setError(newBuilder().setCause(cause)).build()); + responseObserver.onNext(CreatePendingAccountResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(cause)).build()); responseObserver.onCompleted(); return; } @@ -186,8 +369,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas if (request.getAuthenticationType() == AuthenticationType.PHONE) { // Get the normalized phone number from libphone CreatePendingAccountRequest newRequest = CreatePendingAccountRequest.newBuilder() - .setAuthenticationType(request.getAuthenticationType()) - .setAuthenticationProvider(validator.getNormalizedPhoneNumber(request.getAuthenticationProvider())) + .setAuthenticationType(request.getAuthenticationType()).setAuthenticationProvider( + phoneNumberValidator.getNormalizedPhoneNumber(request.getAuthenticationProvider())) .build(); request = newRequest; } @@ -219,7 +402,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas AuthenticationProvider.createAuthenticationProviderFromStrings(request.getAuthenticationType().name(), request.getAuthenticationProvider()))) { responseObserver.onNext(CreatePendingAccountResponse.newBuilder() - .setError(newBuilder().setCause(Cause.ACCOUNT_ALREADY_CREATED)).build()); + .setError(ErrorResponse.newBuilder().setCause(Cause.ACCOUNT_ALREADY_CREATED)).build()); responseObserver.onCompleted(); return; } @@ -252,15 +435,16 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas Cause cause = validator.validateCompletePendingAccountCreationRequest(request); if (cause != null) { - responseObserver.onNext(AccountResponse.newBuilder().setError(newBuilder().setCause(cause)).build()); + responseObserver + .onNext(AccountResponse.newBuilder().setError(ErrorResponse.newBuilder().setCause(cause)).build()); responseObserver.onCompleted(); return; } if (request.getUsername() != null && !request.getUsername().trim().isEmpty() && accountRepositoryAdditional .foundExistingNotOwnUsername(UUID.fromString(request.getAccountId()), request.getUsername())) { - responseObserver.onNext( - AccountResponse.newBuilder().setError(newBuilder().setCause(Cause.USERNAME_ALREADY_USED)).build()); + responseObserver.onNext(AccountResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.USERNAME_ALREADY_USED)).build()); responseObserver.onCompleted(); return; } @@ -272,8 +456,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas Account createdAccount = accountRepositoryAdditional.completePendingAccountCreation(request); if (createdAccount == null) { - responseObserver.onNext( - AccountResponse.newBuilder().setError(newBuilder().setCause(Cause.ERROR_CREATING_ACCOUNT)).build()); + responseObserver.onNext(AccountResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.ERROR_CREATING_ACCOUNT)).build()); responseObserver.onCompleted(); return; } else { @@ -294,15 +478,16 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas logger.debug("Updating profile...: {}", request); if ((request.getProfileId() == null) || (request.getProfileId().isEmpty())) { - responseObserver.onNext( - ProfileResponse.newBuilder().setError(newBuilder().setCause(Cause.MISSING_PROFILE_ID)).build()); + responseObserver.onNext(ProfileResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_PROFILE_ID)).build()); responseObserver.onCompleted(); return; } Cause cause = validator.validateUpdateProfileRequest(request); if (cause != null) { - responseObserver.onNext(ProfileResponse.newBuilder().setError(newBuilder().setCause(cause)).build()); + responseObserver.onNext(ProfileResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(cause)).build()); responseObserver.onCompleted(); return; } @@ -310,8 +495,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas Profile updatedProfile = accountRepositoryAdditional.updateProfile(request); if (updatedProfile == null) { - responseObserver.onNext( - ProfileResponse.newBuilder().setError(newBuilder().setCause(Cause.ERROR_UPDATING_PROFILE)).build()); + responseObserver.onNext(ProfileResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.ERROR_UPDATING_PROFILE)).build()); responseObserver.onCompleted(); return; } @@ -330,23 +515,23 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas logger.debug("Updating account...: {}", request); if ((request.getAccountId() == null) || (request.getAccountId().isEmpty())) { - responseObserver.onNext( - AccountResponse.newBuilder().setError(newBuilder().setCause(Cause.MISSING_ACCOUNT_ID)).build()); + responseObserver.onNext(AccountResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_ACCOUNT_ID)).build()); responseObserver.onCompleted(); return; } Cause validationCause = validator.validateUpdateAccountRequest(request); if (validationCause != null) { - responseObserver - .onNext(AccountResponse.newBuilder().setError(newBuilder().setCause(validationCause)).build()); + responseObserver.onNext(AccountResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(validationCause)).build()); responseObserver.onCompleted(); return; } if (request.getUsername() != null && !request.getUsername().trim().isEmpty() && accountRepositoryAdditional .foundExistingNotOwnUsername(UUID.fromString(request.getAccountId()), request.getUsername())) { - responseObserver.onNext( - AccountResponse.newBuilder().setError(newBuilder().setCause(Cause.USERNAME_ALREADY_USED)).build()); + responseObserver.onNext(AccountResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.USERNAME_ALREADY_USED)).build()); responseObserver.onCompleted(); return; } @@ -354,8 +539,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas Account updatedAccount = accountRepositoryAdditional.updateAccount(request); if (updatedAccount == null) { - responseObserver.onNext( - AccountResponse.newBuilder().setError(newBuilder().setCause(Cause.ERROR_UPDATING_ACCOUNT)).build()); + responseObserver.onNext(AccountResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.ERROR_UPDATING_ACCOUNT)).build()); responseObserver.onCompleted(); return; } @@ -373,8 +558,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas logger.debug("Deleting account...: {}", request); if ((request.getAccountId() == null) || (request.getAccountId().isEmpty())) { - responseObserver.onNext( - StatusResponse.newBuilder().setError(newBuilder().setCause(Cause.MISSING_ACCOUNT_ID)).build()); + responseObserver.onNext(StatusResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_ACCOUNT_ID)).build()); responseObserver.onCompleted(); return; } @@ -386,8 +571,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas return; } - responseObserver.onNext( - StatusResponse.newBuilder().setError(newBuilder().setCause(Cause.ERROR_DELETING_ACCOUNT)).build()); + responseObserver.onNext(StatusResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.ERROR_DELETING_ACCOUNT)).build()); responseObserver.onCompleted(); return; } @@ -396,8 +581,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas public void deleteProfile(DeleteProfileRequest request, StreamObserver responseObserver) { logger.debug("Deleting profile: {}", request); if ((request.getProfileId() == null) || (request.getProfileId().isEmpty())) { - responseObserver.onNext( - StatusResponse.newBuilder().setError(newBuilder().setCause(Cause.MISSING_PROFILE_ID)).build()); + responseObserver.onNext(StatusResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_PROFILE_ID)).build()); responseObserver.onCompleted(); return; } @@ -411,8 +596,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas } logger.info("Error deleting profile."); - responseObserver.onNext( - StatusResponse.newBuilder().setError(newBuilder().setCause(Cause.ERROR_DELETING_PROFILE)).build()); + responseObserver.onNext(StatusResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.ERROR_DELETING_PROFILE)).build()); responseObserver.onCompleted(); return; } @@ -422,28 +607,29 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas StreamObserver responseObserver) { logger.info("Adding authentication provider to profile requested."); logger.debug("Adding authentication provider to profile requested: {}", request); - if ((request.getProfileId() == null) || (request.getProfileId().isEmpty())) { - responseObserver.onNext( - StatusResponse.newBuilder().setError(newBuilder().setCause(Cause.MISSING_PROFILE_ID)).build()); + if ((request.getProfileId() == null) || (request.getProfileId().isEmpty())) { + responseObserver.onNext(StatusResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_PROFILE_ID)).build()); responseObserver.onCompleted(); return; } if (request.getAuthenticationProvider().getAuthenticationTypeValue() == 0) { responseObserver.onNext(StatusResponse.newBuilder() - .setError(newBuilder().setCause(Cause.MISSING_AUTH_PROVIDER_TYPE)).build()); + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_AUTH_PROVIDER_TYPE)).build()); responseObserver.onCompleted(); return; } if (request.getAuthenticationProvider().getAuthenticationProvider() == null || request.getAuthenticationProvider().getAuthenticationProvider().isEmpty()) { responseObserver.onNext(StatusResponse.newBuilder() - .setError(newBuilder().setCause(Cause.MISSING_AUTH_PROVIDER_IDENTIFIER)).build()); + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_AUTH_PROVIDER_IDENTIFIER)).build()); responseObserver.onCompleted(); return; } Cause cause = validator.validateAddAuthenticationProviderRequest(request); if (cause != null) { - responseObserver.onNext(StatusResponse.newBuilder().setError(newBuilder().setCause(cause)).build()); + responseObserver + .onNext(StatusResponse.newBuilder().setError(ErrorResponse.newBuilder().setCause(cause)).build()); responseObserver.onCompleted(); return; } @@ -452,7 +638,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas // Get the normalized phone number from libphone AuthProviderDetails newAuthProviderDetails = AuthProviderDetails.newBuilder() .setAuthenticationType(request.getAuthenticationProvider().getAuthenticationType()) - .setAuthenticationProvider(validator + .setAuthenticationProvider(phoneNumberValidator .getNormalizedPhoneNumber(request.getAuthenticationProvider().getAuthenticationProvider())) .build(); AddAuthenticationProviderRequest newRequest = AddAuthenticationProviderRequest.newBuilder() @@ -464,8 +650,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas Profile profile = profileRepository.findByProfileId(UUID.fromString(request.getProfileId())); if (profile == null) { logger.error("Profile id {} missing in DB.", request.getProfileId()); - responseObserver.onNext( - StatusResponse.newBuilder().setError(newBuilder().setCause(Cause.PROFILE_NOT_FOUND)).build()); + responseObserver.onNext(StatusResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.PROFILE_NOT_FOUND)).build()); responseObserver.onCompleted(); return; } @@ -479,7 +665,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas request.getAuthenticationProvider().getAuthenticationType().name(), request.getAuthenticationProvider().getAuthenticationProvider()); responseObserver.onNext(StatusResponse.newBuilder() - .setError(newBuilder().setCause(Cause.AUTH_PROVIDER_ALREADY_USED)).build()); + .setError(ErrorResponse.newBuilder().setCause(Cause.AUTH_PROVIDER_ALREADY_USED)).build()); responseObserver.onCompleted(); return; } @@ -496,8 +682,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas logger.error("Authentication provider {}:{} was not successfuly added for profile id {}.", request.getAuthenticationProvider().getAuthenticationType().name(), request.getAuthenticationProvider().getAuthenticationProvider(), request.getProfileId()); - responseObserver.onNext( - StatusResponse.newBuilder().setError(newBuilder().setCause(Cause.INTERNAL_SERVER_ERROR)).build()); + responseObserver.onNext(StatusResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.INTERNAL_SERVER_ERROR)).build()); responseObserver.onCompleted(); return; } @@ -568,28 +754,29 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas logger.info("Deleting Authentication Provider from profile: {}", request); if ((request.getProfileId() == null) || (request.getProfileId().isEmpty())) { - responseObserver.onNext( - StatusResponse.newBuilder().setError(newBuilder().setCause(Cause.MISSING_PROFILE_ID)).build()); + responseObserver.onNext(StatusResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_PROFILE_ID)).build()); responseObserver.onCompleted(); return; } if (request.getAuthenticationProvider().getAuthenticationTypeValue() == 0) { responseObserver.onNext(StatusResponse.newBuilder() - .setError(newBuilder().setCause(Cause.MISSING_AUTH_PROVIDER_TYPE)).build()); + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_AUTH_PROVIDER_TYPE)).build()); responseObserver.onCompleted(); return; } if (request.getAuthenticationProvider().getAuthenticationProvider() == null || request.getAuthenticationProvider().getAuthenticationProvider().isEmpty()) { responseObserver.onNext(StatusResponse.newBuilder() - .setError(newBuilder().setCause(Cause.MISSING_AUTH_PROVIDER_IDENTIFIER)).build()); + .setError(ErrorResponse.newBuilder().setCause(Cause.MISSING_AUTH_PROVIDER_IDENTIFIER)).build()); responseObserver.onCompleted(); return; } Cause cause = validator.validateDeleteAuthenticationProviderRequest(request); if (cause != null) { - responseObserver.onNext(StatusResponse.newBuilder().setError(newBuilder().setCause(cause)).build()); + responseObserver + .onNext(StatusResponse.newBuilder().setError(ErrorResponse.newBuilder().setCause(cause)).build()); responseObserver.onCompleted(); return; } @@ -598,8 +785,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas Profile profile = profileRepository.findByProfileId(UUID.fromString(request.getProfileId())); if (profile == null) { logger.error("Profile id {} missing in DB.", request.getProfileId()); - responseObserver.onNext( - StatusResponse.newBuilder().setError(newBuilder().setCause(Cause.PROFILE_NOT_FOUND)).build()); + responseObserver.onNext(StatusResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.PROFILE_NOT_FOUND)).build()); responseObserver.onCompleted(); return; } @@ -613,7 +800,7 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas "Error deleting authentication provider {} from profile with id {}. Check the number of authentication providers.", request.getAuthenticationProvider(), request.getProfileId()); responseObserver.onNext(StatusResponse.newBuilder() - .setError(newBuilder().setCause(Cause.ERROR_DELETING_AUTH_PROVIDER)).build()); + .setError(ErrorResponse.newBuilder().setCause(Cause.ERROR_DELETING_AUTH_PROVIDER)).build()); responseObserver.onCompleted(); return; } @@ -632,8 +819,8 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas logger.error("Authentication provider {}:{} was not successfuly deleted from profile id {}.", request.getAuthenticationProvider().getAuthenticationType().name(), request.getAuthenticationProvider().getAuthenticationProvider(), request.getProfileId()); - responseObserver.onNext( - StatusResponse.newBuilder().setError(newBuilder().setCause(Cause.INTERNAL_SERVER_ERROR)).build()); + responseObserver.onNext(StatusResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(Cause.INTERNAL_SERVER_ERROR)).build()); responseObserver.onCompleted(); return; } @@ -682,20 +869,47 @@ public class AccountServiceImpl extends AccountServiceGrpc.AccountServiceImplBas return; } + private static void logAndBuildGrpcResponse(StreamObserver responseObserver, Validation validation) { + logger.debug(validation.getErrorMessage()); + responseObserver + .onNext(SearchResponse.newBuilder().setError(ErrorResponse.newBuilder().setCause(validation.getCause().get())).build()); + responseObserver.onCompleted(); + } + + private static void logAndBuildGrpcResponse(StreamObserver responseObserver, ValidationError error) { + logger.debug(error.getMessage()); + responseObserver + .onNext(SearchResponse.newBuilder().setError(ErrorResponse.newBuilder().setCause(error.getCause())).build()); + responseObserver.onCompleted(); + } + + private SearchResultDetails buildSearchResultDetails(String id, ByteBuffer avatar, String firstName, String lastName) { + SearchResultDetails.Builder searchResultDetails = SearchResultDetails.newBuilder(); + + searchResultDetails.setFirstName(firstName).setLastName(lastName); + if (avatar != null) { + searchResultDetails.setAvatar(com.google.protobuf.ByteString.copyFrom(avatar)); + } + + return searchResultDetails.build(); + } + private void sendErrorMessageForAccountsResponse(StreamObserver responseObserver, Cause cause) { - responseObserver.onNext(AccountsResponse.newBuilder().setError(newBuilder().setCause(cause)).build()); + responseObserver.onNext(AccountsResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(cause)).build()); responseObserver.onCompleted(); } private void sendErrorMessageForAccountResponse(StreamObserver responseObserver, Cause cause) { - responseObserver.onNext(AccountResponse.newBuilder().setError(newBuilder().setCause(cause)).build()); + responseObserver.onNext(AccountResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(cause)).build()); responseObserver.onCompleted(); } public void prepareErrorStatusResponse(StreamObserver responseObserver, Cause error, String message) { - responseObserver - .onNext(StatusResponse.newBuilder().setError(newBuilder().setCause(error).setMessage(message)).build()); + responseObserver.onNext(StatusResponse.newBuilder() + .setError(ErrorResponse.newBuilder().setCause(error).setMessage(message)).build()); responseObserver.onCompleted(); } diff --git a/src/main/java/biz/nynja/account/services/decomposition/AccountsProvider.java b/src/main/java/biz/nynja/account/services/decomposition/AccountsProvider.java index 07dae8d4c2c9c32f9685af126cbb2409a30787d2..66c1c67a250ce39d1312022b3590b0e8b268eb2c 100644 --- a/src/main/java/biz/nynja/account/services/decomposition/AccountsProvider.java +++ b/src/main/java/biz/nynja/account/services/decomposition/AccountsProvider.java @@ -5,7 +5,12 @@ import biz.nynja.account.components.Validator; import biz.nynja.account.grpc.*; import biz.nynja.account.models.Account; import biz.nynja.account.models.AccountByProfileId; +import biz.nynja.account.models.AccountByQrCode; +import biz.nynja.account.models.AccountByUsername; +import biz.nynja.account.phone.PhoneNumberValidator; import biz.nynja.account.repositories.AccountByProfileIdRepository; +import biz.nynja.account.repositories.AccountByQrCodeRepository; +import biz.nynja.account.repositories.AccountByUsernameRepository; import biz.nynja.account.repositories.AccountRepository; import biz.nynja.account.services.AccountServiceImpl; import org.slf4j.Logger; @@ -24,34 +29,70 @@ public class AccountsProvider { private final AccountRepository accountRepository; private final AccountByProfileIdRepository accountByProfileIdRepository; - private final Validator validator; + private final AccountByUsernameRepository accountByUsernameRepository; + private final AccountByQrCodeRepository accountByQrCodeRepository; + private final PhoneNumberValidator validator; private final AccountServiceHelper accountServiceHelper; public AccountsProvider(AccountRepository accountRepository, AccountByProfileIdRepository accountByProfileIdRepository, - Validator validator, + AccountByUsernameRepository accountByUsernameRepository, + AccountByQrCodeRepository accountByQrCodeRepository, + PhoneNumberValidator validator, AccountServiceHelper accountServiceHelper) { this.accountRepository = accountRepository; this.accountByProfileIdRepository = accountByProfileIdRepository; this.validator = validator; this.accountServiceHelper = accountServiceHelper; + this.accountByUsernameRepository = accountByUsernameRepository; + this.accountByQrCodeRepository = accountByQrCodeRepository; } - public Optional getAccountByAuthenticationProvider(AccountByAuthenticationProviderRequest request) { + public Optional getAccountByAuthenticationProvider(AuthenticationType type, String authenticationIdentifier) { - if (request.getAuthenticationType() == AuthenticationType.PHONE) { - request = normalizedPhoneNumber(request); + if (type == AuthenticationType.PHONE) { + authenticationIdentifier = validator.getNormalizedPhoneNumber(authenticationIdentifier); } Account account = accountServiceHelper.getAccountByAuthenticationProviderHelper( - request.getAuthenticationIdentifier(), request.getAuthenticationType().toString()); + authenticationIdentifier, type.toString()); if (account == null) { logger.debug("No matching accounts found for authetntication provider {}: {}", - request.getAuthenticationType(), request.getAuthenticationIdentifier()); + type, authenticationIdentifier); return Optional.empty(); } - AccountResponse response = AccountResponse.newBuilder().setAccountDetails(account.toProto()).build(); + + return Optional.of(account); + } + + public Optional getAccountResponseByUsername(String username){ + AccountByUsername account = accountByUsernameRepository.findByUsername(username); + if(account == null) { + return Optional.empty(); + } + AccountResponse response = AccountResponse.newBuilder().setAccountDetails(account.toProto()).build(); + logger.debug("Found result for account by username {}:", username, response); + return Optional.of(response); + } + + public Optional getAccountResponseByQrCode(String qrCode){ + AccountByQrCode account = accountByQrCodeRepository.findByQrCode(qrCode); + if(account == null) { + return Optional.empty(); + } + AccountResponse response = AccountResponse.newBuilder().setAccountDetails(account.toProto()).build(); + logger.debug("Found result for account by username {}:", qrCode, response); + return Optional.of(response); + } + + public Optional getAccountResponseByAuthenticationProvider(AuthenticationType type, String authenticationIdentifier) { + Optional account = getAccountByAuthenticationProvider(type, authenticationIdentifier); + if(!account.isPresent()) { + return Optional.empty(); + } + + AccountResponse response = AccountResponse.newBuilder().setAccountDetails(account.get().toProto()).build(); logger.debug("Found result for account by authentication provider {}: {}: \"{}\"", - request.getAuthenticationType(), request.getAuthenticationIdentifier(), response); + type, authenticationIdentifier, response); return Optional.of(response); } @@ -71,7 +112,7 @@ public class AccountsProvider { public Optional getAccountByAccountId(AccountByAccountIdRequest request) { logger.info("Getting accounts by account id: {}", request.getAccountId()); Account account = accountRepository.findByAccountId(UUID.fromString(request.getAccountId())); - if (account == null) { + if (account == null || account.getAccountId() == null) { return Optional.empty(); } AccountResponse response = AccountResponse.newBuilder().setAccountDetails(account.toProto()).build(); diff --git a/src/main/java/biz/nynja/account/validation/Validation.java b/src/main/java/biz/nynja/account/validation/Validation.java new file mode 100644 index 0000000000000000000000000000000000000000..9ae0982ccd05c540755579adbc1039bcf38daed4 --- /dev/null +++ b/src/main/java/biz/nynja/account/validation/Validation.java @@ -0,0 +1,62 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ +package biz.nynja.account.validation; + +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; + +import biz.nynja.account.grpc.ErrorResponse.Cause; + +public class Validation { + List errors = new LinkedList<>(); + + public Validation() { + } + + public Validation(ValidationError e) { + errors.add(e); + } + + public void addError(ValidationError e) { + errors.add(e); + } + + public boolean hasErrors() { + return errors.size() > 0; + } + + public List getErrors() { + return errors; + } + + public String getErrorMessage() { + if (!hasErrors()) { + return ""; + } + StringBuilder builder = new StringBuilder(); + for (ValidationError error : errors) { + builder.append("Message: ").append(error.getMessage()).append(". "); + if (error.getCause() != null) { + builder.append("Cause: ").append(error.getCause()); + } + } + + return builder.toString(); + } + + public Optional getCause() { + if (!hasErrors()) { + return Optional.empty(); + } + + if (errors.size() == 1) { + return Optional.of(errors.get(0).getCause()); + } else { + return Optional.of(Cause.MULTIPLE_INVALID_PARAMETERS); + } + + } + +} diff --git a/src/main/java/biz/nynja/account/validation/ValidationError.java b/src/main/java/biz/nynja/account/validation/ValidationError.java new file mode 100644 index 0000000000000000000000000000000000000000..f9bcaae33f076ad62329386bd1ff4945d7c54e1b --- /dev/null +++ b/src/main/java/biz/nynja/account/validation/ValidationError.java @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ +package biz.nynja.account.validation; + +import biz.nynja.account.grpc.ErrorResponse.Cause; + +public class ValidationError { + private String message; + private Cause cause; + + public ValidationError(String message, Cause cause) { + this.setMessage(message); + this.setCause(cause); + } + + public ValidationError(String message) { + this.setMessage(message); + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Cause getCause() { + return cause; + } + + public void setCause(Cause cause) { + this.cause = cause; + } +} diff --git a/src/test/java/biz/nynja/account/components/AccountServiceHelperTests.java b/src/test/java/biz/nynja/account/components/AccountServiceHelperTests.java index ef4101673b036327f97fc26749052909697faf8b..96150641bf99eb6d5e8dd93a923faf80902c670d 100644 --- a/src/test/java/biz/nynja/account/components/AccountServiceHelperTests.java +++ b/src/test/java/biz/nynja/account/components/AccountServiceHelperTests.java @@ -32,6 +32,10 @@ import biz.nynja.account.utils.Util; "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration" }) @ActiveProfiles("dev") public class AccountServiceHelperTests { + + @MockBean + private PreparedStatementsCache preparedStatementsCache; + @MockBean private AccountByAuthenticationProviderRepository accountByAuthenticationProviderRepository; diff --git a/src/test/java/biz/nynja/account/components/LibphoneNormalizationParameterizedTest.java b/src/test/java/biz/nynja/account/components/LibphoneNormalizationParameterizedTest.java index 71e74d3f399b32c7ce7b42f8d4aed3e8f703fe17..79a0e6f5d629a79c5226f19f43d53acdc085544e 100644 --- a/src/test/java/biz/nynja/account/components/LibphoneNormalizationParameterizedTest.java +++ b/src/test/java/biz/nynja/account/components/LibphoneNormalizationParameterizedTest.java @@ -21,6 +21,7 @@ import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.rules.SpringClassRule; import org.springframework.test.context.junit4.rules.SpringMethodRule; +import biz.nynja.account.phone.PhoneNumberValidator; import biz.nynja.account.repositories.AccountRepository; import biz.nynja.account.services.AccountServiceImpl; @@ -34,7 +35,7 @@ import biz.nynja.account.services.AccountServiceImpl; @ContextConfiguration(classes = { Validator.class }) public class LibphoneNormalizationParameterizedTest { - private Validator validator = new Validator(); + private PhoneNumberValidator validator = new PhoneNumberValidator(); private String expectedPhoneNumber; private String inputPhoneNumber; diff --git a/src/test/java/biz/nynja/account/components/PhoneNumberValidatorTests.java b/src/test/java/biz/nynja/account/components/PhoneNumberValidatorTests.java new file mode 100644 index 0000000000000000000000000000000000000000..1536aaefe8747c25bef3114ec1615dabe09cf2aa --- /dev/null +++ b/src/test/java/biz/nynja/account/components/PhoneNumberValidatorTests.java @@ -0,0 +1,126 @@ +/** + * Copyright (C) 2018 Nynja Inc. All rights reserved. + */ + +package biz.nynja.account.components; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import biz.nynja.account.phone.PhoneNumberValidator; +import biz.nynja.account.repositories.AccountRepositoryAdditional; + +/** + * Components unit tests. + */ + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = { PhoneNumberValidator.class }) +public class PhoneNumberValidatorTests { + + @Autowired + @Qualifier("phoneNumberValidator") + private PhoneNumberValidator phoneNumberValidator; + + @MockBean + private AccountRepositoryAdditional accountRepositoryAdditional; + + @Test + public void validPhoneNumberTest() { + + String phoneNumber = "+359887434646"; + String countryCode = "BG"; + boolean isValid = phoneNumberValidator.isPhoneNumberValid(phoneNumber, countryCode); + assertTrue(String.format("Phone number: '%s' should be valid for country '%s'", phoneNumber, countryCode), + isValid == true); + + } + + @Test + public void invalidPhoneNumberTest() { + + String phoneNumber = "+357887434646"; + String countryCode = "BG"; + boolean isValid = phoneNumberValidator.isPhoneNumberValid(phoneNumber, countryCode); + assertFalse(String.format("Phone number: '%s' should be invalid for country '%s'", phoneNumber, countryCode), + isValid == true); + + } + + @Test + public void validNormalizedPhoneNumberTest1() { + + String expectedPhoneNumber = "359887345234"; + String inputPhoneNumber = "BG:+359887345234"; + String normalizedPhoneNumber = phoneNumberValidator.getNormalizedPhoneNumber(inputPhoneNumber); + assertEquals( + String.format("Phone number: '%s' should be normalized to '%s'", inputPhoneNumber, expectedPhoneNumber), + expectedPhoneNumber, normalizedPhoneNumber); + } + + @Test + public void validNormalizedPhoneNumberTest2() { + + String expectedPhoneNumber = "359887345234"; + String inputPhoneNumber = "BG:00359887345234"; + String normalizedPhoneNumber = phoneNumberValidator.getNormalizedPhoneNumber(inputPhoneNumber); + assertEquals( + String.format("Phone number: '%s' should be normalized to '%s'", inputPhoneNumber, expectedPhoneNumber), + expectedPhoneNumber, normalizedPhoneNumber); + } + + @Test + public void validNormalizedPhoneNumberTest3() { + + String expectedPhoneNumber = "359887345234"; + String inputPhoneNumber = "BG:359-887-345-234"; + String normalizedPhoneNumber = phoneNumberValidator.getNormalizedPhoneNumber(inputPhoneNumber); + assertEquals( + String.format("Phone number: '%s' should be normalized to '%s'", inputPhoneNumber, expectedPhoneNumber), + expectedPhoneNumber, normalizedPhoneNumber); + } + + @Test + public void validNormalizedPhoneNumberTest4() { + + String expectedPhoneNumber = "359887345234"; + String inputPhoneNumber = "BG:359 887 345 234"; + String normalizedPhoneNumber = phoneNumberValidator.getNormalizedPhoneNumber(inputPhoneNumber); + assertEquals( + String.format("Phone number: '%s' should be normalized to '%s'", inputPhoneNumber, expectedPhoneNumber), + expectedPhoneNumber, normalizedPhoneNumber); + } + + @Test + public void invalidNormalizedPhoneNumberTest1() { + + String expectedPhoneNumber = "359887345234"; + String inputPhoneNumber = "BG:359887345234567"; + String normalizedPhoneNumber = phoneNumberValidator.getNormalizedPhoneNumber(inputPhoneNumber); + assertNotEquals( + String.format("Phone number: '%s' should be normalized to '%s'", inputPhoneNumber, expectedPhoneNumber), + expectedPhoneNumber, normalizedPhoneNumber); + } + + @Test + public void invalidNormalizedPhoneNumberTest2() { + + String expectedPhoneNumber = "359887345234"; + String inputPhoneNumber = "BG:35988734523"; + String normalizedPhoneNumber = phoneNumberValidator.getNormalizedPhoneNumber(inputPhoneNumber); + assertNotEquals( + String.format("Phone number: '%s' should be normalized to '%s'", inputPhoneNumber, expectedPhoneNumber), + expectedPhoneNumber, normalizedPhoneNumber); + } +} diff --git a/src/test/java/biz/nynja/account/components/ValidatorTests.java b/src/test/java/biz/nynja/account/components/ValidatorTests.java index 008f3b100b31cecaa212fc5faad5bcea115d3920..932b69e2fcc9d18c9f77ee9abc1fd01c00fe7f1e 100644 --- a/src/test/java/biz/nynja/account/components/ValidatorTests.java +++ b/src/test/java/biz/nynja/account/components/ValidatorTests.java @@ -13,6 +13,7 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; @@ -22,6 +23,7 @@ import biz.nynja.account.grpc.AuthenticationType; import biz.nynja.account.grpc.CompletePendingAccountCreationRequest; import biz.nynja.account.grpc.CreatePendingAccountRequest; import biz.nynja.account.grpc.ErrorResponse.Cause; +import biz.nynja.account.phone.PhoneNumberValidator; import biz.nynja.account.repositories.AccountRepositoryAdditional; import biz.nynja.account.utils.Util; @@ -30,98 +32,15 @@ import biz.nynja.account.utils.Util; */ @RunWith(SpringRunner.class) -@ContextConfiguration(classes = { Validator.class }) +@ContextConfiguration(classes = { Validator.class, PhoneNumberValidator.class }) public class ValidatorTests { @Autowired + @Qualifier("validator") private Validator validator; @MockBean private AccountRepositoryAdditional accountRepositoryAdditional; - - @Test - public void validPhoneNumberTest() { - - String phoneNumber = "+359887434646"; - String countryCode = "BG"; - boolean isValid = validator.isPhoneNumberValid(phoneNumber, countryCode); - assertTrue(String.format("Phone number: '%s' should be valid for country '%s'", phoneNumber, countryCode), - isValid == true); - - } - - @Test - public void invalidPhoneNumberTest() { - - String phoneNumber = "+357887434646"; - String countryCode = "BG"; - boolean isValid = validator.isPhoneNumberValid(phoneNumber, countryCode); - assertFalse(String.format("Phone number: '%s' should be invalid for country '%s'", phoneNumber, countryCode), - isValid == true); - - } - - @Test - public void validNormalizedPhoneNumberTest1() { - - String expectedPhoneNumber = "359887345234"; - String inputPhoneNumber = "BG:+359887345234"; - String normalizedPhoneNumber = validator.getNormalizedPhoneNumber(inputPhoneNumber); - assertEquals(String.format("Phone number: '%s' should be normalized to '%s'", inputPhoneNumber, expectedPhoneNumber), - expectedPhoneNumber, normalizedPhoneNumber); - } - - @Test - public void validNormalizedPhoneNumberTest2() { - - String expectedPhoneNumber = "359887345234"; - String inputPhoneNumber = "BG:00359887345234"; - String normalizedPhoneNumber = validator.getNormalizedPhoneNumber(inputPhoneNumber); - assertEquals(String.format("Phone number: '%s' should be normalized to '%s'", inputPhoneNumber, expectedPhoneNumber), - expectedPhoneNumber, normalizedPhoneNumber); - } - - @Test - public void validNormalizedPhoneNumberTest3() { - - String expectedPhoneNumber = "359887345234"; - String inputPhoneNumber = "BG:359-887-345-234"; - String normalizedPhoneNumber = validator.getNormalizedPhoneNumber(inputPhoneNumber); - assertEquals(String.format("Phone number: '%s' should be normalized to '%s'", inputPhoneNumber, expectedPhoneNumber), - expectedPhoneNumber, normalizedPhoneNumber); - } - - @Test - public void validNormalizedPhoneNumberTest4() { - - String expectedPhoneNumber = "359887345234"; - String inputPhoneNumber = "BG:359 887 345 234"; - String normalizedPhoneNumber = validator.getNormalizedPhoneNumber(inputPhoneNumber); - assertEquals(String.format("Phone number: '%s' should be normalized to '%s'", inputPhoneNumber, expectedPhoneNumber), - expectedPhoneNumber, normalizedPhoneNumber); - } - - @Test - public void invalidNormalizedPhoneNumberTest1() { - - String expectedPhoneNumber = "359887345234"; - String inputPhoneNumber = "BG:359887345234567"; - String normalizedPhoneNumber = validator.getNormalizedPhoneNumber(inputPhoneNumber); - assertNotEquals(String.format("Phone number: '%s' should be normalized to '%s'", inputPhoneNumber, expectedPhoneNumber), - expectedPhoneNumber, normalizedPhoneNumber); - } - - @Test - public void invalidNormalizedPhoneNumberTest2() { - - String expectedPhoneNumber = "359887345234"; - String inputPhoneNumber = "BG:35988734523"; - String normalizedPhoneNumber = validator.getNormalizedPhoneNumber(inputPhoneNumber); - assertNotEquals(String.format("Phone number: '%s' should be normalized to '%s'", inputPhoneNumber, expectedPhoneNumber), - expectedPhoneNumber, normalizedPhoneNumber); - } - - @Test public void validUsernameTest() { diff --git a/src/test/java/biz/nynja/account/services/AccountServiceTests.java b/src/test/java/biz/nynja/account/services/AccountServiceTests.java index 1a3991b77ca7c1c4a037871b3617bdaf042d4ad2..7da87396bdf5a5034cf558dc56dc8e3b4eaf58f5 100644 --- a/src/test/java/biz/nynja/account/services/AccountServiceTests.java +++ b/src/test/java/biz/nynja/account/services/AccountServiceTests.java @@ -10,10 +10,12 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.verify; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import java.util.Optional; import java.util.UUID; import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,9 +34,11 @@ import biz.nynja.account.components.PreparedStatementsCache; import biz.nynja.account.configurations.CassandraTestsConfig; import biz.nynja.account.grpc.AccountByAccountIdRequest; import biz.nynja.account.grpc.AccountByAuthenticationProviderRequest; +import biz.nynja.account.grpc.AccountDetails; import biz.nynja.account.grpc.AccountResponse; import biz.nynja.account.grpc.AccountServiceGrpc; import biz.nynja.account.grpc.AccountsByProfileIdRequest; +import biz.nynja.account.grpc.AccountsList; import biz.nynja.account.grpc.AccountsResponse; import biz.nynja.account.grpc.AddAuthenticationProviderRequest; import biz.nynja.account.grpc.AddContactInfoRequest; @@ -54,12 +58,15 @@ import biz.nynja.account.grpc.EditContactInfoRequest; import biz.nynja.account.grpc.ErrorResponse.Cause; import biz.nynja.account.grpc.ProfileResponse; import biz.nynja.account.grpc.Role; +import biz.nynja.account.grpc.GetByUsernameRequest; import biz.nynja.account.grpc.StatusResponse; import biz.nynja.account.grpc.UpdateAccountRequest; import biz.nynja.account.grpc.UpdateProfileRequest; import biz.nynja.account.models.Account; import biz.nynja.account.models.AccountByAuthenticationProvider; import biz.nynja.account.models.AccountByProfileId; +import biz.nynja.account.models.AccountByQrCode; +import biz.nynja.account.models.AccountByUsername; import biz.nynja.account.models.AuthenticationProvider; import biz.nynja.account.models.ContactInfo; import biz.nynja.account.models.PendingAccount; @@ -68,13 +75,20 @@ import biz.nynja.account.models.Profile; import biz.nynja.account.models.ProfileByAuthenticationProvider; import biz.nynja.account.repositories.AccountByAuthenticationProviderRepository; import biz.nynja.account.repositories.AccountByProfileIdRepository; +import biz.nynja.account.repositories.AccountByQrCodeRepository; +import biz.nynja.account.repositories.AccountByUsernameRepository; import biz.nynja.account.repositories.AccountRepository; import biz.nynja.account.repositories.AccountRepositoryAdditional; import biz.nynja.account.repositories.PendingAccountRepository; import biz.nynja.account.repositories.ProfileByAuthenticationProviderRepository; import biz.nynja.account.repositories.ProfileRepository; +import biz.nynja.account.services.decomposition.AccountsProvider; import biz.nynja.account.utils.GrpcServerTestBase; import biz.nynja.account.utils.Util; +import biz.nynja.account.grpc.GetByQrCodeRequest; +import biz.nynja.account.grpc.GetByEmailRequest; +import biz.nynja.account.grpc.GetByPhoneNumberRequest; +import biz.nynja.account.grpc.SearchResponse; /** * AccountService unit tests. @@ -89,9 +103,6 @@ import biz.nynja.account.utils.Util; @ActiveProfiles("dev") public class AccountServiceTests extends GrpcServerTestBase { - @MockBean - private AccountByAuthenticationProviderRepository accountByAuthenticationProviderRepository; - @Autowired @Qualifier("accountByPhone") private AccountByAuthenticationProvider accountByPhone; @@ -152,6 +163,24 @@ public class AccountServiceTests extends GrpcServerTestBase { @Qualifier("profileByAuthenticationProvider") private ProfileByAuthenticationProvider profileByAuthenticationProvider; + @Autowired + @Qualifier("savedResponse") + private AccountByUsername savedResponse; + + @Autowired + @Qualifier("savedResponseProvider") + private AccountByAuthenticationProvider savedResponseProvider; + + @Autowired + @Qualifier("savedResponseQrCode") + private AccountByQrCode savedResponseQrCode; + + @MockBean + private AccountByAuthenticationProviderRepository accountByAuthenticationProviderRepository; + + @MockBean + private PreparedStatementsCache preparedStatementsCache; + @MockBean private AccountRepository accountRepository; @@ -170,11 +199,17 @@ public class AccountServiceTests extends GrpcServerTestBase { @MockBean private ProfileByAuthenticationProviderRepository profileByAutheticationProviderRepository; + @MockBean + private AccountByQrCodeRepository accountByQrCodeRepository; + @MockBean private AccountServiceHelper util; @MockBean - private PreparedStatementsCache preparedStatementsCache; + private AccountByUsernameRepository accountByUsernameRepository; + + @MockBean + private AccountsProvider accountsProvider; @Test public void testGetAccountByAccountId() throws ExecutionException, InterruptedException { @@ -182,8 +217,9 @@ public class AccountServiceTests extends GrpcServerTestBase { .setAccountId(Util.ACCOUNT_ID.toString()).build(); Account account = savedAccount; - - given(accountRepository.findByAccountId(UUID.fromString(request.getAccountId()))).willReturn(account); + AccountResponse response = AccountResponse.newBuilder().setAccountDetails(account.toProto()).build(); + Optional accountResponse = Optional.of(response); + given(accountsProvider.getAccountByAccountId(request)).willReturn(accountResponse); final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); @@ -236,9 +272,14 @@ public class AccountServiceTests extends GrpcServerTestBase { List accountByProfileId = new ArrayList<>(); accountByProfileId.add(savedAccountByProfileId); + + List responseList = accountByProfileId.stream().map(AccountByProfileId::toProto).collect(Collectors.toList()); - given(accountByProffileIdRepository.findAllByProfileId(UUID.fromString(request.getProfileId()))) - .willReturn(accountByProfileId); + AccountsResponse aResponse = AccountsResponse.newBuilder() + .setAccountsResponse(AccountsList.newBuilder().addAllAccountDetails(responseList)).build(); + Optional response = Optional.of(aResponse); + given(accountsProvider.getAllAccountsByProfileId(request)) + .willReturn(response); final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); @@ -289,12 +330,11 @@ public class AccountServiceTests extends GrpcServerTestBase { .setAuthenticationIdentifier(Util.PHONE_PROVIDER).setAuthenticationType(AuthenticationType.PHONE) .build(); - List accList = new ArrayList<>(); - accList.add(accountByPhone); - - given(accountByAuthenticationProviderRepository.findAllByAuthenticationProvider(Util.PHONE_PROVIDER)) - .willReturn(accList); - given(util.getAccountByAuthenticationProviderHelper(Util.PHONE_PROVIDER, "PHONE")).willReturn(phoneAccount); + AccountResponse response = AccountResponse.newBuilder().setAccountDetails(accountByPhone.toProto()).build(); + Optional accountResponse = Optional.of(response); + + given(accountsProvider.getAccountResponseByAuthenticationProvider(AuthenticationType.PHONE, + Util.PHONE_PROVIDER)).willReturn(accountResponse); final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); @@ -303,7 +343,7 @@ public class AccountServiceTests extends GrpcServerTestBase { assertTrue( String.format("Reply should contain authentication provider '%s'", request.getAuthenticationIdentifier()), - reply.getAccountDetails().getAuthenticationIdentifier().equals(Util.PHONE_PROVIDER)); + reply.getAccountDetails().getAuthenticationIdentifier().equals(Util.PHONE_NUMBER)); assertTrue(String.format("Reply should contain authentication type '%s'", AuthenticationType.PHONE.name()), reply.getAccountDetails().getAuthenticationType().equals(AuthenticationType.PHONE.name())); } @@ -745,8 +785,8 @@ public class AccountServiceTests extends GrpcServerTestBase { given(profileRepository.findByProfileId(Util.PROFILE_ID)).willReturn(profile2AuthProviders); - given(profileByAutheticationProviderRepository - .findByAuthenticationProviderAndAuthenticationProviderType(Util.PHONE_PROVIDER, "PHONE")) + given(profileByAutheticationProviderRepository.findByAuthenticationProviderAndAuthenticationProviderType( + Util.PHONE_NUMBER_STREIGHT, AuthenticationType.PHONE.name())) .willReturn(profileByAuthenticationProvider); final AccountServiceGrpc.AccountServiceBlockingStub accountServiceBlockingStub = AccountServiceGrpc @@ -1425,4 +1465,257 @@ public class AccountServiceTests extends GrpcServerTestBase { assertTrue(String.format("Reply should contain cause '%s'", Cause.INVALID_BIRTHDAY_DATE), reply.getError().getCause().equals(Cause.INVALID_BIRTHDAY_DATE)); } + + public void testSearchByUsername() throws ExecutionException, InterruptedException { + final GetByUsernameRequest request = GetByUsernameRequest.newBuilder() + .setUsername(Util.S_USERNAME).build(); + + AccountByUsername response = savedResponse; + + given(accountByUsernameRepository.findByUsername(request.getUsername())).willReturn(response); + + final AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByUsername(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain last name '%s'", Util.S_LAST_NAME.toString()), + reply.getSearchResultDetails().getLastName().equals(Util.S_LAST_NAME.toString())); + } + + @Test + public void testSearchByUsernameNotFound() throws ExecutionException, InterruptedException { + final GetByUsernameRequest request = GetByUsernameRequest.newBuilder() + .setUsername(Util.S_USERNAME).build(); + + AccountByUsername response = null; + + given(accountByUsernameRepository.findByUsername(request.getUsername())).willReturn(response); + + final AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByUsername(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.USERNAME_NOT_FOUND), + reply.getError().getCause().equals(Cause.USERNAME_NOT_FOUND)); + } + + @Test + public void testSearchByUsernameBadRequest() throws ExecutionException, InterruptedException { + final GetByUsernameRequest request = GetByUsernameRequest.newBuilder().build(); + + final AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByUsername(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.MULTIPLE_INVALID_PARAMETERS), + reply.getError().getCause().equals(Cause.MULTIPLE_INVALID_PARAMETERS)); + } + + @Test + public void testSearchByUsernameInvalid() { + final GetByUsernameRequest request = GetByUsernameRequest.newBuilder() + .setUsername(Util.S_INVALID_USERNAME).build(); + + final AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByUsername(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.USERNAME_INVALID), + reply.getError().getCause().equals(Cause.USERNAME_INVALID)); + } + + @Test + public void testSearchByPhoneNumber() throws ExecutionException, InterruptedException { + final GetByPhoneNumberRequest request = GetByPhoneNumberRequest.newBuilder() + .setPhoneNumber(Util.S_PHONE_NUMBER).build(); + + Optional response = Optional.of(savedAccount); + + given(accountsProvider.getAccountByAuthenticationProvider(AuthenticationType.PHONE, request.getPhoneNumber())).willReturn(response); + + final AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByPhoneNumber(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain last name '%s'", savedAccount.getFirstName()), + reply.getSearchResultDetails().getLastName().equals(savedAccount.getLastName())); + } + + @Test + public void testSearchByPhoneNumberNotFound() throws ExecutionException, InterruptedException { + final GetByPhoneNumberRequest request = GetByPhoneNumberRequest.newBuilder() + .setPhoneNumber(Util.S_PHONE_NUMBER).build(); + + List response = new LinkedList<>(); + + given(accountByAuthenticationProviderRepository.findAllByAuthenticationProvider(request.getPhoneNumber())).willReturn(response); + + final AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByPhoneNumber(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.PHONENUMBER_NOT_FOUND), + reply.getError().getCause().equals(Cause.PHONENUMBER_NOT_FOUND)); + } + + @Test + public void testSearchByPhoneNumberBadRequest() throws ExecutionException, InterruptedException { + final GetByPhoneNumberRequest request = GetByPhoneNumberRequest.newBuilder().build(); + + final AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByPhoneNumber(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.MISSING_PHONENUMBER), + reply.getError().getCause().equals(Cause.MISSING_PHONENUMBER)); + } + + @Test + public void testSearchByPhoneNumberInvalid() { + final GetByPhoneNumberRequest request = GetByPhoneNumberRequest.newBuilder() + .setPhoneNumber(Util.S_INVALID_PHONENUMBER).build(); + + final AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByPhoneNumber(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.INVALID_PHONENUMBER), + reply.getError().getCause().equals(Cause.INVALID_PHONENUMBER)); + } + + @Test + public void testSearchByEmail() throws ExecutionException, InterruptedException { + final GetByEmailRequest request = GetByEmailRequest.newBuilder() + .setEmail(Util.S_EMAIL).build(); + + Optional response = Optional.of(savedAccount); + + given(accountsProvider.getAccountByAuthenticationProvider(AuthenticationType.EMAIL, request.getEmail())).willReturn(response); + + final AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByEmail(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain last name '%s'", savedAccount.getFirstName()), + reply.getSearchResultDetails().getLastName().equals(savedAccount.getLastName())); + } + + @Test + public void testSearchByEmailNotFound() throws ExecutionException, InterruptedException { + final GetByEmailRequest request = GetByEmailRequest.newBuilder() + .setEmail(Util.S_EMAIL).build(); + + List response = new LinkedList<>(); + + given(accountByAuthenticationProviderRepository.findAllByAuthenticationProvider(request.getEmail())).willReturn(response); + + final AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByEmail(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.EMAIL_NOT_FOUND), + reply.getError().getCause().equals(Cause.EMAIL_NOT_FOUND)); + } + + @Test + public void testSearchByEmailBadRequest() throws ExecutionException, InterruptedException { + final GetByEmailRequest request = GetByEmailRequest.newBuilder().build(); + + final AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByEmail(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.MISSING_EMAIL), + reply.getError().getCause().equals(Cause.MISSING_EMAIL)); + } + + @Test + public void testSearchByEmailInvalid() { + final GetByEmailRequest request = GetByEmailRequest.newBuilder() + .setEmail(Util.S_INVALID_EMAIL).build(); + + final AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByEmail(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.EMAIL_INVALID), + reply.getError().getCause().equals(Cause.EMAIL_INVALID)); + } + + @Test + public void testSearchByQrCode() throws ExecutionException, InterruptedException { + final GetByQrCodeRequest request = GetByQrCodeRequest.newBuilder() + .setQrCode(Util.S_QR_CODE).build(); + + AccountByQrCode response = savedResponseQrCode; + + given(accountByQrCodeRepository.findByQrCode(request.getQrCode())).willReturn(response); + + final AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByQrCode(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain last name '%s'", Util.S_LAST_NAME.toString()), + reply.getSearchResultDetails().getLastName().equals(Util.S_LAST_NAME.toString())); + } + + @Test + public void testSearchByQrCodeNotFound() throws ExecutionException, InterruptedException { + final GetByQrCodeRequest request = GetByQrCodeRequest.newBuilder() + .setQrCode(Util.S_QR_CODE).build(); + + AccountByQrCode response = null; + + given(accountByQrCodeRepository.findByQrCode(request.getQrCode())).willReturn(response); + + final AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByQrCode(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.QR_CODE_NOT_FOUND), + reply.getError().getCause().equals(Cause.QR_CODE_NOT_FOUND)); + } + + @Test + public void testSearchByQrCodeBadRequest() throws ExecutionException, InterruptedException { + final GetByQrCodeRequest request = GetByQrCodeRequest.newBuilder().build(); + + final AccountServiceGrpc.AccountServiceBlockingStub searchServiceBlockingStub = AccountServiceGrpc + .newBlockingStub(Optional.ofNullable(channel).orElse(inProcChannel)); + + final SearchResponse reply = searchServiceBlockingStub.searchByQrCode(request); + + assertNotNull("Reply should not be null", reply); + assertTrue(String.format("Reply should contain cause '%s'", Cause.MISSING_QR_CODE), + reply.getError().getCause().equals(Cause.MISSING_QR_CODE)); + } + } diff --git a/src/test/java/biz/nynja/account/utils/Util.java b/src/test/java/biz/nynja/account/utils/Util.java index 08f4aa2ec4a1f191cce4db505d000b281295b826..11d213e1f912972c499dd77bcd81f2d58b997bbf 100644 --- a/src/test/java/biz/nynja/account/utils/Util.java +++ b/src/test/java/biz/nynja/account/utils/Util.java @@ -13,17 +13,20 @@ import java.util.UUID; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; + import biz.nynja.account.grpc.AccessStatus; import biz.nynja.account.grpc.Role; import biz.nynja.account.models.Account; import biz.nynja.account.models.AccountByAuthenticationProvider; import biz.nynja.account.models.AccountByProfileId; +import biz.nynja.account.models.AccountByQrCode; +import biz.nynja.account.models.AccountByUsername; import biz.nynja.account.models.AuthenticationProvider; import biz.nynja.account.models.ContactInfo; -import biz.nynja.account.models.PendingAccount; -import biz.nynja.account.models.PendingAccountByAuthenticationProvider; import biz.nynja.account.models.Profile; import biz.nynja.account.models.ProfileByAuthenticationProvider; +import biz.nynja.account.models.PendingAccount; +import biz.nynja.account.models.PendingAccountByAuthenticationProvider; /** * Unit tests variables, beans and help methods. @@ -59,6 +62,7 @@ public class Util { public static final LocalDate BIRTHDAY = LocalDate.of(1990, 9, 16); public static final String MIDDLE_NAME = "Kass"; public static final String PHONE_NUMBER = "+359887123456"; + public static final String PHONE_NUMBER_STREIGHT = "359887123456"; public static final String PHONE_PROVIDER = "BG:+359887123456"; public static final String PHONE_PROVIDER_EDITED = "BG:+359887111111"; public static final String INVALID_PHONE_PROVIDER = "BG:+3"; @@ -67,6 +71,18 @@ public class Util { public static final String FACBOOK_TYPE = "FACEBOOK"; public static final String GOOGLEPLUS_TYPE = "GOOGLEPLUS"; + public static final String S_USERNAME = "TomJohns"; + public static final String S_PHONE_NUMBER = "359878123456"; + public static final String S_EMAIL = "p_petrov@abv.bg"; + public static final String S_QR_CODE = "QRcoded"; + public static final String S_INVALID_USERNAME = "Tom-Johns"; + public static final String S_INVALID_PHONENUMBER = "GB:44887359883"; // one DTMF less + public static final String S_INVALID_EMAIL = "p_petrov.@abv.bg"; + public static final String S_AVATAR_STRING = "avatar-TomJohns"; + public static final String S_FIRST_NAME = "Tom"; + public static final String S_LAST_NAME = "Johns"; + + @Bean public ProfileByAuthenticationProvider profileByAuthenticationProvider() { ProfileByAuthenticationProvider profile = new ProfileByAuthenticationProvider(); @@ -262,4 +278,36 @@ public class Util { pendingAccount.setCreationTimestamp(EXISTING_PENDING_ACCOUNT_TIMESTAMP_UPDATED); return pendingAccount; } + + @Bean + public AccountByUsername savedResponse() { + AccountByUsername response = new AccountByUsername(); + response.setAccountId(Util.ACCOUNT_ID); + response.setAvatar(ByteBuffer.wrap(S_AVATAR_STRING.getBytes())); + response.setFirstName(Util.S_FIRST_NAME); + response.setLastName(Util.S_LAST_NAME); + return response; + } + + @Bean + public AccountByAuthenticationProvider savedResponseProvider() { + AccountByAuthenticationProvider response = new AccountByAuthenticationProvider(); + response.setAccountId(Util.ACCOUNT_ID); + response.setAvatar(ByteBuffer.wrap(S_AVATAR_STRING.getBytes())); + response.setFirstName(Util.S_FIRST_NAME); + response.setLastName(Util.S_LAST_NAME); + return response; + } + + @Bean + public AccountByQrCode savedResponseQrCode() { + AccountByQrCode response = new AccountByQrCode(); + response.setAccountId(Util.ACCOUNT_ID); + response.setAvatar(ByteBuffer.wrap(S_AVATAR_STRING.getBytes())); + response.setFirstName(Util.S_FIRST_NAME); + response.setLastName(Util.S_LAST_NAME); + response.setQrCode(Util.S_QR_CODE); + return response; + } + }