diff --git a/frontend/css/axe_form_styles.css b/frontend/css/axe_form_styles.css index 1514f8aa..0e132d0b 100644 --- a/frontend/css/axe_form_styles.css +++ b/frontend/css/axe_form_styles.css @@ -21,4 +21,4 @@ .space-after-fields { padding-left: 1rem; max-width: 99%; -} \ No newline at end of file +} diff --git a/frontend/css/common_styles.css b/frontend/css/common_styles.css index 7c2035f7..26a712a6 100644 --- a/frontend/css/common_styles.css +++ b/frontend/css/common_styles.css @@ -224,4 +224,4 @@ vaadin-icon[icon="vaadin:sign-in"] { .fit-in-window > * { flex: 1 0 auto; -} \ No newline at end of file +} diff --git a/frontend/css/forgot_password_page.css b/frontend/css/forgot_password_page.css index eaad35b3..88ea3cab 100644 --- a/frontend/css/forgot_password_page.css +++ b/frontend/css/forgot_password_page.css @@ -1,3 +1,3 @@ .result-span { padding-left: 1rem; -} \ No newline at end of file +} diff --git a/frontend/css/profile_page.css b/frontend/css/profile_page.css index 3e43f2ea..cd782bbd 100644 --- a/frontend/css/profile_page.css +++ b/frontend/css/profile_page.css @@ -16,4 +16,9 @@ .fit-in-section { width: min-content; } -} \ No newline at end of file +} + +.telegram-details { + display: block; + max-width: 290px; +} diff --git a/frontend/css/registration_page.css b/frontend/css/registration_page.css index e695a23d..87200051 100644 --- a/frontend/css/registration_page.css +++ b/frontend/css/registration_page.css @@ -5,4 +5,4 @@ .info-button { border-radius: 100%; -} \ No newline at end of file +} diff --git a/src/main/java/pm/axe/core/IdentGenerator.java b/src/main/java/pm/axe/core/IdentGenerator.java index 67325197..63733fe4 100644 --- a/src/main/java/pm/axe/core/IdentGenerator.java +++ b/src/main/java/pm/axe/core/IdentGenerator.java @@ -65,7 +65,9 @@ public static String generateTokenIdent(final Token token) { private static String generateAccountConfirmationIdent(final Token token) { String prefix = token.getTokenType().getIdentPrefix(); - String randomPart = RandomStringUtils.randomAlphanumeric(Axe.C.FOUR); - return String.join("", prefix, randomPart); + String randomNumber = RandomStringUtils.randomNumeric(1); + String randomChar = RandomStringUtils.randomAlphanumeric(1); + String randomNum = RandomStringUtils.randomNumeric(1); + return String.join("", prefix, randomNumber, randomChar, randomNum); } } diff --git a/src/main/java/pm/axe/services/user/AccountService.java b/src/main/java/pm/axe/services/user/AccountService.java index 57cec640..b2fe4519 100644 --- a/src/main/java/pm/axe/services/user/AccountService.java +++ b/src/main/java/pm/axe/services/user/AccountService.java @@ -26,7 +26,6 @@ public class AccountService { private static final String TAG = "[" + AccountService.class.getSimpleName() + "]"; private static final String ERR_ACCOUNT_IS_EMPTY = "Account is null"; - private static final String ERR_NO_EMAIL_ACCOUNT = "User has no Email Account"; private final AccountDao accountDao; private final SymmetricCryptTool cryptTool; @@ -309,8 +308,6 @@ public OperationResult deleteAccount(final Account account) { * {@link OperationResult#malformedInput()}, when new email address not valid. * {@link OperationResult#generalFail()} with {@link #ERR_ENCRYPTION_FAILED} message, * when encryption failed. - * {@link OperationResult#generalFail()} with {@link #ERR_NO_EMAIL_ACCOUNT} message, - * when {@link User} has no {@link AccountType#EMAIL} {@link Account}. */ public OperationResult updateEmailAccount(final User user, final String email) { if (user == null) return OperationResult.malformedInput().withMessage("User cannot be NULL"); @@ -321,7 +318,9 @@ public OperationResult updateEmailAccount(final User user, final String email) { Optional emailAccount = getAccount(user, AccountType.EMAIL); + boolean userHasEmailAccount; if (emailAccount.isPresent()) { + userHasEmailAccount = true; String encryptedEmail; OperationResult encryptEmailResult = cryptTool.encrypt(email); if (encryptEmailResult.ok()) { @@ -334,13 +333,17 @@ public OperationResult updateEmailAccount(final User user, final String email) { emailAccount.get().setAccountName(encryptedEmail); emailAccount.get().setConfirmed(false); } else { - return OperationResult.generalFail().withMessage(ERR_NO_EMAIL_ACCOUNT); + userHasEmailAccount = false; } try { - accountDao.save(emailAccount.get()); - log.info("{} Updated email account for {} {}", TAG, User.class.getSimpleName(), user.getUsername()); - return OperationResult.success().addPayload(emailAccount.get()); + if (userHasEmailAccount) { + accountDao.save(emailAccount.get()); + log.info("{} Updated email account for {} {}", TAG, User.class.getSimpleName(), user.getUsername()); + return OperationResult.success().addPayload(emailAccount.get()); + } else { + return createEmailAccount(user, email); + } } catch (CannotCreateTransactionException e) { return OperationResult.databaseDown(); } catch (Exception e) { diff --git a/src/main/java/pm/axe/ui/elements/TelegramSpan.java b/src/main/java/pm/axe/ui/elements/TelegramSpan.java index 43c82fd0..850540f0 100644 --- a/src/main/java/pm/axe/ui/elements/TelegramSpan.java +++ b/src/main/java/pm/axe/ui/elements/TelegramSpan.java @@ -1,6 +1,7 @@ package pm.axe.ui.elements; import com.vaadin.flow.component.Composite; +import com.vaadin.flow.component.HasStyle; import com.vaadin.flow.component.html.Anchor; import com.vaadin.flow.component.html.Span; import com.vaadin.flow.component.icon.Icon; @@ -17,7 +18,7 @@ /** * {@link Span} with message "Send code to link your account with Telegram". */ -public final class TelegramSpan extends Composite { +public final class TelegramSpan extends Composite implements HasStyle { /** * Creates new {@link TelegramSpan}. diff --git a/src/main/java/pm/axe/ui/pages/user/profile/tabs/ProfileTab.java b/src/main/java/pm/axe/ui/pages/user/profile/tabs/ProfileTab.java index 7560e6d5..a0f96365 100644 --- a/src/main/java/pm/axe/ui/pages/user/profile/tabs/ProfileTab.java +++ b/src/main/java/pm/axe/ui/pages/user/profile/tabs/ProfileTab.java @@ -75,6 +75,9 @@ public void tabInit(final User user) { add(accountsSection); usernameRequirements.hide(); + if (StringUtils.isBlank(emailField.getValue())) { + emailField.focus(); + } } private Section createAccountSection() { @@ -83,7 +86,7 @@ private Section createAccountSection() { Details emailUsageDetails = createEmailUsageDetails(); HorizontalLayout telegramLayout = createTelegramLayout(); - Stream.of(usernameLayout, emailLayout, telegramLayout).forEach(VaadinUtils::setCentered); + Stream.of(usernameLayout, emailLayout).forEach(VaadinUtils::setCentered); Section section = new Section("Accounts"); section.setContent(usernameLayout, usernameRequirements, emailLayout, emailUsageDetails, telegramLayout); @@ -94,6 +97,7 @@ private Section createAccountSection() { private HorizontalLayout createUsernameLayout() { usernameField.setLabel("Username"); usernameField.setValue(user.getUsername()); + usernameField.setWidthFull(); usernameField.addValueChangeListener(this::onUsernameChanged); usernameField.setClearButtonVisible(true); usernameField.setReadOnly(true); @@ -117,22 +121,25 @@ private HorizontalLayout createEmailLayout() { emailField.setLabel("E-mail"); emailField.setClearButtonVisible(true); emailField.setReadOnly(true); + emailField.setWidthFull(); emailField.addValueChangeListener(this::onEmailChanged); Optional currentEmail = getCurrentEmail(); currentEmail.ifPresent(emailField::setValue); - currentEmail.ifPresent(e -> { - VaadinIcon confirmationStatusIcon = isCurrentEmailConfirmed() - ? VaadinIcon.CHECK : VaadinIcon.ELLIPSIS_CIRCLE; - emailField.setSuffixComponent(confirmationStatusIcon.create()); - }); + currentEmail.ifPresent(e -> setConfirmationStatus()); editEmailButton.setText("Edit"); editEmailButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY); saveEmailButton.setText("Save"); saveEmailButton.addThemeVariants(ButtonVariant.LUMO_SUCCESS, ButtonVariant.LUMO_PRIMARY); - emailLayout.add(emailField, editEmailButton); + if (currentEmail.isPresent()) { + emailLayout.add(emailField, editEmailButton); + } else { + emailField.setReadOnly(false); + emailLayout.add(emailField, saveEmailButton); + } + emailLayout.addClassName("fit-in-section"); VaadinUtils.fitLayoutInWindow(emailLayout); VaadinUtils.setSmallSpacing(emailLayout); @@ -168,6 +175,7 @@ private HorizontalLayout createTelegramLayout() { Optional tgToken = getTelegramToken(); if (tgToken.isPresent()) { Details telegramDetails = new Details("Link Telegram Account"); + telegramDetails.setClassName("telegram-details"); telegramDetails.setOpened(true); TelegramSpan telegramSpan = TelegramSpan.create(tgToken.get()); telegramDetails.setContent(telegramSpan); @@ -255,16 +263,17 @@ private void onEmailChanged(final AbstractField.ComponentValueChangeEvent currentEmail = getCurrentEmail(); - if (currentEmail.isEmpty()) return; - boolean isSameAsCurrent = currentEmail.get().equals(email); - if (isSameAsCurrent) { - return; + if (currentEmail.isPresent()) { + boolean isSameAsCurrent = currentEmail.get().equals(email); + if (isSameAsCurrent) { + return; + } } if (isValidEmail) { @@ -285,20 +294,25 @@ private void onEditEmail(final ClickEvent