From 7e37547d100491fb244d986208b818be0e12a4df Mon Sep 17 00:00:00 2001 From: Anton Lunev Date: Sun, 3 Jun 2018 01:23:21 +0300 Subject: [PATCH] fixed some errors in tx generation and processing --- web/app/WebModule.java | 9 ++- web/app/auth/AuthUserAccessor.java | 29 +++++++ web/app/auth/AuthUserConverter.java | 17 ---- web/app/auth/FmPlayAuthUserService.java | 9 +-- .../basic/AlwaysValidBasicAuthProvider.java | 58 ++++++++++++++ web/app/controllers/RestApiController.java | 12 ++- web/app/core/ParsingTransactionGenerator.java | 3 + web/app/model/MessagePattern.java | 17 +++- web/conf/play-authenticate/mine.conf | 77 ++++++++++--------- web/test/DataPopulator.java | 7 +- web/test/controllers/RestApiControllerIT.java | 2 +- .../core/message/RegexBankMatcherTest.java | 2 +- web/test/dao/MessagePatternDaoTest.java | 3 +- 13 files changed, 173 insertions(+), 72 deletions(-) create mode 100755 web/app/auth/AuthUserAccessor.java delete mode 100755 web/app/auth/AuthUserConverter.java create mode 100644 web/app/auth/basic/AlwaysValidBasicAuthProvider.java diff --git a/web/app/WebModule.java b/web/app/WebModule.java index df326ca..d6d689a 100755 --- a/web/app/WebModule.java +++ b/web/app/WebModule.java @@ -1,5 +1,6 @@ import auth.FmPlayAuthResolver; import auth.FmPlayAuthUserService; +import auth.basic.AlwaysValidBasicAuthProvider; import auth.deadbolt.FmPlayAuthCustomDeadboltHook; import auth.deadbolt.FmPlayAuthDeadboltHandler; import auth.deadbolt.FmPlayAuthHandlerCache; @@ -46,13 +47,15 @@ public void configure() { bind(UserDao.class).asEagerSingleton(); bind(Resolver.class).to(FmPlayAuthResolver.class); - bind(FmPlayAuthUserService.class).asEagerSingleton(); - bind(GoogleAuthProvider.class).asEagerSingleton(); - bind(DeadboltHandler.class).to(FmPlayAuthDeadboltHandler.class); + + bind(FmPlayAuthUserService.class).asEagerSingleton(); bind(FmPlayAuthHandlerCache.class).asEagerSingleton(); bind(FmPlayAuthCustomDeadboltHook.class).asEagerSingleton(); + bind(GoogleAuthProvider.class).asEagerSingleton(); + bind(AlwaysValidBasicAuthProvider.class).asEagerSingleton(); + bind(TransactionExecutor.class).to(LoggingTransactionExecutor.class); bind(AccountMatcher.class).to(RegexAccountMatcher.class); bind(TransactionGenerator.class).to(ParsingTransactionGenerator.class); diff --git a/web/app/auth/AuthUserAccessor.java b/web/app/auth/AuthUserAccessor.java new file mode 100755 index 0000000..2e8901f --- /dev/null +++ b/web/app/auth/AuthUserAccessor.java @@ -0,0 +1,29 @@ +package auth; + +import com.feth.play.module.pa.providers.oauth2.google.GoogleAuthUser; +import com.feth.play.module.pa.providers.password.UsernamePasswordAuthUser; +import com.feth.play.module.pa.user.AuthUser; + +/** + * Created by admin on 10/26/2016. + */ +public class AuthUserAccessor { + + public static String getEmailOf(AuthUser authUser) { + if ("google".equals(authUser.getProvider())) { + return ((GoogleAuthUser) authUser).getEmail(); + } else if ("basic".equals(authUser.getProvider())) { + return ((UsernamePasswordAuthUser) authUser).getEmail(); + } else { + return null; + } + } + + private static GoogleAuthUser toGoogleAuthUser(AuthUser authUser) { + if ("google".equals(authUser.getProvider())) { + return (GoogleAuthUser) authUser; + } else { + return null; + } + } +} diff --git a/web/app/auth/AuthUserConverter.java b/web/app/auth/AuthUserConverter.java deleted file mode 100755 index 554c5b8..0000000 --- a/web/app/auth/AuthUserConverter.java +++ /dev/null @@ -1,17 +0,0 @@ -package auth; - -import com.feth.play.module.pa.providers.oauth2.google.GoogleAuthUser; -import com.feth.play.module.pa.user.AuthUser; - -/** - * Created by admin on 10/26/2016. - */ -public class AuthUserConverter { - public static final GoogleAuthUser toGoogleAuthUser(AuthUser authUser) { - if ("google".equals(authUser.getProvider())) { - return (GoogleAuthUser) authUser; - } else { - return null; - } - } -} diff --git a/web/app/auth/FmPlayAuthUserService.java b/web/app/auth/FmPlayAuthUserService.java index adc64a7..b00bc22 100755 --- a/web/app/auth/FmPlayAuthUserService.java +++ b/web/app/auth/FmPlayAuthUserService.java @@ -24,16 +24,11 @@ public FmPlayAuthUserService(final PlayAuthenticate auth, UserDao userDao) { @Override public String save(final AuthUser authUser) { - GoogleAuthUser googleAuthUser = AuthUserConverter.toGoogleAuthUser(authUser); - if (googleAuthUser == null) { - return null; - } - - String authUserId = googleAuthUser.getId(); + String authUserId = authUser.getId(); User user = userDao.findByAuthId(authUserId); if (user == null) { - user = User.createEmptyUser(googleAuthUser.getId(), googleAuthUser.getEmail()); + user = User.createEmptyUser(authUser.getId(), AuthUserAccessor.getEmailOf(authUser)); userDao.save(user); } diff --git a/web/app/auth/basic/AlwaysValidBasicAuthProvider.java b/web/app/auth/basic/AlwaysValidBasicAuthProvider.java new file mode 100644 index 0000000..dc58563 --- /dev/null +++ b/web/app/auth/basic/AlwaysValidBasicAuthProvider.java @@ -0,0 +1,58 @@ +/* + * Copyright © 2014 Florian Hars, nMIT Solutions GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package auth.basic; + +import com.feth.play.module.pa.PlayAuthenticate; +import com.feth.play.module.pa.providers.password.DefaultUsernamePasswordAuthUser; +import com.feth.play.module.pa.providers.wwwauth.basic.BasicAuthProvider; +import com.feth.play.module.pa.user.AuthUser; +import play.inject.ApplicationLifecycle; +import play.mvc.Http.Context; +import play.twirl.api.Content; +import views.html.login; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * A really simple basic auth provider that accepts one hard coded user + */ +@Singleton +public class AlwaysValidBasicAuthProvider extends BasicAuthProvider { + + @Inject + public AlwaysValidBasicAuthProvider(final PlayAuthenticate auth, final ApplicationLifecycle lifecycle) { + super(auth, lifecycle); + } + + @Override + protected AuthUser authenticateUser(String username, String password) { + return new DefaultUsernamePasswordAuthUser(password, username); + } + + @Override + public String getKey() { + return "basic"; + } + + /** + * Diplay the normal login form if HTTP authentication fails + */ + @Override + protected Content unauthorized(Context context) { + return login.render(this.auth, null, ""); + } +} diff --git a/web/app/controllers/RestApiController.java b/web/app/controllers/RestApiController.java index 729864e..9178c01 100755 --- a/web/app/controllers/RestApiController.java +++ b/web/app/controllers/RestApiController.java @@ -6,6 +6,7 @@ import core.TransactionGenerator; import dao.SmsDao; import dao.TransactionDao; +import dao.UserDao; import model.Sms; import model.User; import play.libs.Json; @@ -29,24 +30,31 @@ public class RestApiController extends Controller { private TransactionGenerator transactionGenerator; private TransactionExecutor transactionExecutor; private UserService userService; + private UserDao userDao; @Inject public RestApiController(SmsDao smsDao, TransactionDao transactionDao, ParsingTransactionGenerator transactionGenerator, TransactionExecutor transactionExecutor, - UserService userService) { + UserService userService, UserDao userDao) { this.smsDao = smsDao; this.transactionDao = transactionDao; this.transactionGenerator = transactionGenerator; this.transactionExecutor = transactionExecutor; this.userService = userService; + this.userDao = userDao; } public CompletionStage processSms() { - User user = userService.getUser(session()); Sms sms = Json.fromJson(request().body().asJson(), Sms.class); + User user = userDao.findById(sms.getOwnerId()); + + if (user == null) { + return CompletableFuture.supplyAsync(() -> internalServerError("No user found with ID " + sms.getOwnerId())); + } + // push message to persistent queue and then async: // - saving to mongo (for history and traceability) // - generating of transactions based on sms data diff --git a/web/app/core/ParsingTransactionGenerator.java b/web/app/core/ParsingTransactionGenerator.java index 1850725..b8add89 100644 --- a/web/app/core/ParsingTransactionGenerator.java +++ b/web/app/core/ParsingTransactionGenerator.java @@ -1,5 +1,6 @@ package core; +import common.DateUtils; import core.message.ParserSelector; import core.message.RegexBankMatcher; import core.message.matcher.AccountMatcher; @@ -16,6 +17,7 @@ import play.Logger; import javax.inject.Inject; +import java.time.LocalDateTime; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -59,6 +61,7 @@ public List generate(Sms sms, User user) { builder.sourceAmount(result.getAmount()); builder.destAmount(result.getAmount()); builder.categoryId(categoryMatcher.getBestMatch(result.getPayeeString()).getId()); + builder.addedTime(DateUtils.now()); switch (result.getTransactionType()) { case EXPENSE: diff --git a/web/app/model/MessagePattern.java b/web/app/model/MessagePattern.java index d52855e..1ebf9be 100644 --- a/web/app/model/MessagePattern.java +++ b/web/app/model/MessagePattern.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.base.MoreObjects; import org.jongo.marshall.jackson.oid.MongoObjectId; import java.time.LocalDateTime; @@ -36,10 +37,7 @@ public MessagePattern(@JsonProperty("id") String _id, this.createdTs = createdTs; } - public MessagePattern(@JsonProperty("ownerId") String ownerId, - @JsonProperty("regex") String regex, - @JsonProperty("bankName") String bankName, - @JsonProperty("createdTs") LocalDateTime createdTs) { + public MessagePattern(String ownerId, String regex, String bankName, LocalDateTime createdTs) { this.ownerId = ownerId; this.regex = regex; this.bankName = bankName; @@ -65,4 +63,15 @@ public String getBankName() { public LocalDateTime getCreatedTs() { return createdTs; } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("_id", _id) + .add("ownerId", ownerId) + .add("regex", regex) + .add("bankName", bankName) + .add("createdTs", createdTs) + .toString(); + } } diff --git a/web/conf/play-authenticate/mine.conf b/web/conf/play-authenticate/mine.conf index 8f06161..0bd576d 100755 --- a/web/conf/play-authenticate/mine.conf +++ b/web/conf/play-authenticate/mine.conf @@ -6,39 +6,46 @@ play-authenticate { - # If set to true, account merging is enabled, if set to false its disabled and accounts will never prompted to be merged - # defaults to true - accountMergeEnabled=false - - # if this is set to true, accounts are automatically linked - # (e.g. if a user is logged in and uses a different authentication provider - # which has NOT yet been registered to another user, this newly used authentication - # provider gets added to the current local user - # Handle setting this to true with care - # If set to false, your resolver must not return null for askLink() - # defaults to false - accountAutoLink=true - - # Settings for the google-based authentication provider - # if you are not using it, you can remove this portion of the config file - # and remove the Google provider from conf/play.plugins - google { - redirectUri { - # Whether the redirect URI scheme should be HTTP or HTTPS (HTTP by default) - secure=false - - # You can use this setting to override the automatic detection - # of the host used for the redirect URI (helpful if your service is running behind a CDN for example) - # host=yourdomain.com - } - - # Google credentials - # These are mandatory for using OAuth and need to be provided by you, - # if you want to use Google as an authentication provider. - # Get them here: https://code.google.com/apis/console - # Remove leading '#' after entering - - clientId = ${GOOGLE_OAUTH_CLIENT_ID} - clientSecret = ${GOOGLE_OAUTH_SECRET} + # If set to true, account merging is enabled, if set to false its disabled and accounts will never prompted to be merged + # defaults to true + accountMergeEnabled = false + + # if this is set to true, accounts are automatically linked + # (e.g. if a user is logged in and uses a different authentication provider + # which has NOT yet been registered to another user, this newly used authentication + # provider gets added to the current local user + # Handle setting this to true with care + # If set to false, your resolver must not return null for askLink() + # defaults to false + accountAutoLink = true + + # Settings for the google-based authentication provider + # if you are not using it, you can remove this portion of the config file + # and remove the Google provider from conf/play.plugins + google { + redirectUri { + # Whether the redirect URI scheme should be HTTP or HTTPS (HTTP by default) + secure = false + + # You can use this setting to override the automatic detection + # of the host used for the redirect URI (helpful if your service is running behind a CDN for example) + # host=yourdomain.com } -} \ No newline at end of file + + # Google credentials + # These are mandatory for using OAuth and need to be provided by you, + # if you want to use Google as an authentication provider. + # Get them here: https://code.google.com/apis/console + # Remove leading '#' after entering + + clientId = ${GOOGLE_OAUTH_CLIENT_ID} + clientSecret = ${GOOGLE_OAUTH_SECRET} + } + + # Settings for the http basic auth provider + # if you are not using it (and you shouldn't), you can remove this portion + # of the config file + basic { + realm=Play_Authenticate + } +} diff --git a/web/test/DataPopulator.java b/web/test/DataPopulator.java index 7f56fef..925844f 100755 --- a/web/test/DataPopulator.java +++ b/web/test/DataPopulator.java @@ -58,7 +58,7 @@ public void setUp() { public void populatePatterns(String ownerId) { patternDao.save(new MessagePattern( ownerId, - "Покупка\\. Карта \\*(\\d{4}). (\\d+\\.\\d+) RUB. (.*). Доступно (\\d+\\.\\d+) RUB", + "(.*)\\. Карта \\*(\\d{4}). (\\d+\\.\\d+) (.*). OKEY. Доступно (\\d+\\.\\d+) RUB", "Tinkoff", DateUtils.now() )); @@ -70,6 +70,7 @@ public void populateUserWithSingleAccoutAndSomeTransactions() { TransactionCategory flatCat = TransactionCategory.createTransactionCategory("Flat", "commodities"); TransactionCategory transportCat = TransactionCategory.createTransactionCategory("Transaport", "tickets etc."); + transactionCategoryDao.save(TransactionCategory.UNDEFINED); transactionCategoryDao.save(foodCat); transactionCategoryDao.save(flatCat); transactionCategoryDao.save(transportCat); @@ -83,6 +84,10 @@ public void populateUserWithSingleAccoutAndSomeTransactions() { Account account = ObjectsFactory.createDummyAccountWithOwnerId(user.getId()); accountDao.save(account); + accountDao.save(Account.EXPENSE_ACCOUNT); + accountDao.save(Account.INCOME_ACCOUNT); + accountDao.save(Account.UNDEFINED_ACCOUNT); + user.addAccount(account); transactionDao.save(Transaction.createExpense( diff --git a/web/test/controllers/RestApiControllerIT.java b/web/test/controllers/RestApiControllerIT.java index f060c65..336abc6 100755 --- a/web/test/controllers/RestApiControllerIT.java +++ b/web/test/controllers/RestApiControllerIT.java @@ -49,7 +49,7 @@ public void sendSomeSmses() throws Exception { "", "android-1", "", - "Покупка Карта *2222. 42.42 RUB. OKEY DOSTAVKA. Доступно 1325.50 RUB", + "Покупка. Карта *2222. 3344.5 RUB. OKEY. Доступно 12345.92 RUB", ZonedDateTime.now(ZoneOffset.UTC).toLocalDateTime()); JsonNode jsonNode = Json.toJson(sms); diff --git a/web/test/core/message/RegexBankMatcherTest.java b/web/test/core/message/RegexBankMatcherTest.java index 339dbbd..720c5a1 100644 --- a/web/test/core/message/RegexBankMatcherTest.java +++ b/web/test/core/message/RegexBankMatcherTest.java @@ -25,7 +25,7 @@ public void canMatchBank() { RegexBankMatcher bankMatcher = new RegexBankMatcher(Lists.newArrayList( new MessagePattern( "user01", - "Покупка\\. Карта \\*(\\d{4}). (\\d+\\.\\d+) RUB. (.*). Доступно (\\d+\\.\\d+) RUB", + "(.*)\\. Карта \\*(\\d{4}). (\\d+\\.\\d+) (.*). OKEY. Доступно (\\d+\\.\\d+) RUB", "bank1", DateUtils.now() ), diff --git a/web/test/dao/MessagePatternDaoTest.java b/web/test/dao/MessagePatternDaoTest.java index d217f86..8f867ab 100644 --- a/web/test/dao/MessagePatternDaoTest.java +++ b/web/test/dao/MessagePatternDaoTest.java @@ -1,5 +1,6 @@ package dao; +import com.google.common.collect.Sets; import common.DateUtils; import model.Account; import model.MessagePattern; @@ -43,6 +44,6 @@ public void canFindByOwnerId() { patternDao.save(pattern); - assertThat(patternDao.findByOwnerId("01")).isEqualTo(pattern); + assertThat(patternDao.findByOwnerId("user01").stream().findFirst().get().getId()).isEqualTo(pattern.getId()); } } \ No newline at end of file