diff --git a/src/main/java/io/hexlet/typoreporter/config/oauth2/CustomAuthenticationFilter.java b/src/main/java/io/hexlet/typoreporter/config/oauth2/CustomAuthenticationFilter.java index 012d1997..fc0e0794 100644 --- a/src/main/java/io/hexlet/typoreporter/config/oauth2/CustomAuthenticationFilter.java +++ b/src/main/java/io/hexlet/typoreporter/config/oauth2/CustomAuthenticationFilter.java @@ -8,6 +8,7 @@ import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; +import java.util.Arrays; @Component public class CustomAuthenticationFilter extends OncePerRequestFilter { diff --git a/src/main/java/io/hexlet/typoreporter/controller/AccountController.java b/src/main/java/io/hexlet/typoreporter/controller/AccountController.java index cc758d4d..12b2f301 100644 --- a/src/main/java/io/hexlet/typoreporter/controller/AccountController.java +++ b/src/main/java/io/hexlet/typoreporter/controller/AccountController.java @@ -35,7 +35,6 @@ public class AccountController { @GetMapping public String getAccountInfoPage(final Model model, final Authentication authentication) { - System.out.println("customAuth2-: " + authentication.toString()); final var accountInfo = accountService.getInfoAccount(authentication.getName()); final var workspaceInfos = accountService.getWorkspacesInfoListByEmail(accountInfo.email()); model.addAttribute("workspaceRoleInfoList", workspaceInfos); diff --git a/src/main/java/io/hexlet/typoreporter/domain/AccountSocialLink.java b/src/main/java/io/hexlet/typoreporter/domain/AccountSocialLink.java new file mode 100644 index 00000000..838dbcb1 --- /dev/null +++ b/src/main/java/io/hexlet/typoreporter/domain/AccountSocialLink.java @@ -0,0 +1,44 @@ +package io.hexlet.typoreporter.domain; + +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; +import io.hexlet.typoreporter.domain.account.Account; +import io.hexlet.typoreporter.domain.account.AuthProvider; +import io.hypersistence.utils.hibernate.type.basic.PostgreSQLEnumType; +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import lombok.experimental.Accessors; +import org.hibernate.annotations.Type; + +@Getter +@Setter +@ToString +@NoArgsConstructor +@Accessors(chain = true) +@Entity(name = "account_social_links") +@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") +public class AccountSocialLink implements Identifiable { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "social_links_to_accounts_id_seq") + @SequenceGenerator(name = "social_links_to_accounts_id_seq", allocationSize = 15) + private Long id; + + @ManyToOne + @JoinColumn(name = "account_id") + @NotNull + private Account account; + + @Column(name = "login") + @NotNull + private Integer login; + + @NotNull + @Enumerated(EnumType.STRING) + @Column(columnDefinition = "AUTH_PROVIDER") + @Type(PostgreSQLEnumType.class) + private AuthProvider authProvider; +} diff --git a/src/main/java/io/hexlet/typoreporter/domain/account/Account.java b/src/main/java/io/hexlet/typoreporter/domain/account/Account.java index 66b9ecc9..177535ff 100644 --- a/src/main/java/io/hexlet/typoreporter/domain/account/Account.java +++ b/src/main/java/io/hexlet/typoreporter/domain/account/Account.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.ObjectIdGenerators; import io.hexlet.typoreporter.domain.AbstractAuditingEntity; +import io.hexlet.typoreporter.domain.AccountSocialLink; import io.hexlet.typoreporter.domain.Identifiable; import io.hexlet.typoreporter.domain.account.constraint.AccountUsername; import io.hexlet.typoreporter.domain.typo.Typo; @@ -89,6 +90,10 @@ public class Account extends AbstractAuditingEntity implements Identifiable typos = new ArrayList<>(); + @OneToMany(mappedBy = "account", cascade = ALL, orphanRemoval = true) + @ToString.Exclude + private List accountSocialLinks = new ArrayList<>(); + public Account addTypo(final Typo typo) { typos.add(typo); typo.setAccount(this); @@ -112,6 +117,17 @@ public void removeWorkSpaceRole(WorkspaceRole workspaceRole) { workspaceRole.setAccount(null); } + public Account addAccountsSocialLinks(AccountSocialLink accountSocialLink) { + accountSocialLink.setAccount(this); + accountSocialLinks.add(accountSocialLink); + return this; + } + + public void removeAccountsSocialLinks(AccountSocialLink accountSocialLink) { + accountSocialLinks.remove(accountSocialLink); + accountSocialLink.setAccount(null); + } + @Override public boolean equals(Object o) { return this == o || id != null && o instanceof Account other && id.equals(other.id); diff --git a/src/main/java/io/hexlet/typoreporter/domain/account/OAuth2GithubUser.java b/src/main/java/io/hexlet/typoreporter/domain/account/OAuth2GithubUser.java index ba544e9f..9ab82d64 100644 --- a/src/main/java/io/hexlet/typoreporter/domain/account/OAuth2GithubUser.java +++ b/src/main/java/io/hexlet/typoreporter/domain/account/OAuth2GithubUser.java @@ -63,4 +63,8 @@ public String getPassword() { Integer password = oAuth2User.getAttribute("id"); return Objects.requireNonNull(password).toString(); } + + public Integer getId() { + return Objects.requireNonNull(oAuth2User.getAttribute("id")); + } } diff --git a/src/main/java/io/hexlet/typoreporter/handler/OAuth2LoginSuccessHandler.java b/src/main/java/io/hexlet/typoreporter/handler/OAuth2LoginSuccessHandler.java index e6d338d2..1e7f5afe 100644 --- a/src/main/java/io/hexlet/typoreporter/handler/OAuth2LoginSuccessHandler.java +++ b/src/main/java/io/hexlet/typoreporter/handler/OAuth2LoginSuccessHandler.java @@ -1,7 +1,9 @@ package io.hexlet.typoreporter.handler; +import io.hexlet.typoreporter.domain.account.AuthProvider; import io.hexlet.typoreporter.domain.account.OAuth2GithubUser; import io.hexlet.typoreporter.repository.AccountRepository; +import io.hexlet.typoreporter.repository.AccountSocialLinkRepository; import io.hexlet.typoreporter.service.AccountService; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -18,6 +20,8 @@ public class OAuth2LoginSuccessHandler extends SavedRequestAwareAuthenticationSu private AccountService accountService; @Autowired private AccountRepository accountRepository; + @Autowired + private AccountSocialLinkRepository accountSocialLinkRepository; @Override public void onAuthenticationSuccess(HttpServletRequest request, @@ -27,9 +31,11 @@ public void onAuthenticationSuccess(HttpServletRequest request, OAuth2AuthenticationToken authenticationToken = (OAuth2AuthenticationToken) authentication; if ("github".equals(authenticationToken.getAuthorizedClientRegistrationId())) { OAuth2GithubUser user = (OAuth2GithubUser) authentication.getPrincipal(); - var isUserExist = accountRepository.existsByEmail(user.getEmail()); - if (!isUserExist) { + var accountLink = accountSocialLinkRepository.findAccountSocialLinkByLoginAndAuthProvider(user.getId(), AuthProvider.GITHUB); + if (accountLink.isEmpty()) { accountService.createGithubUser(user); + } else { + accountService.updateGithubUser(accountLink.get().getAccount(), user); } } response.sendRedirect("/workspaces"); diff --git a/src/main/java/io/hexlet/typoreporter/repository/AccountRepository.java b/src/main/java/io/hexlet/typoreporter/repository/AccountRepository.java index 136937a1..03369d69 100644 --- a/src/main/java/io/hexlet/typoreporter/repository/AccountRepository.java +++ b/src/main/java/io/hexlet/typoreporter/repository/AccountRepository.java @@ -11,6 +11,8 @@ public interface AccountRepository extends JpaRepository { Optional findAccountByEmail(String email); + Optional findAccountByUsername(String username); + boolean existsByUsername(String username); boolean existsByEmail(String email); } diff --git a/src/main/java/io/hexlet/typoreporter/repository/AccountSocialLinkRepository.java b/src/main/java/io/hexlet/typoreporter/repository/AccountSocialLinkRepository.java new file mode 100644 index 00000000..a172d2ca --- /dev/null +++ b/src/main/java/io/hexlet/typoreporter/repository/AccountSocialLinkRepository.java @@ -0,0 +1,13 @@ +package io.hexlet.typoreporter.repository; + +import io.hexlet.typoreporter.domain.AccountSocialLink; +import io.hexlet.typoreporter.domain.account.AuthProvider; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface AccountSocialLinkRepository extends JpaRepository { + Optional findAccountSocialLinkByLoginAndAuthProvider(Integer login, AuthProvider authProvider); +} diff --git a/src/main/java/io/hexlet/typoreporter/service/AccountService.java b/src/main/java/io/hexlet/typoreporter/service/AccountService.java index b322f586..87da1002 100644 --- a/src/main/java/io/hexlet/typoreporter/service/AccountService.java +++ b/src/main/java/io/hexlet/typoreporter/service/AccountService.java @@ -1,5 +1,6 @@ package io.hexlet.typoreporter.service; +import io.hexlet.typoreporter.domain.AccountSocialLink; import io.hexlet.typoreporter.domain.account.Account; import io.hexlet.typoreporter.domain.account.AuthProvider; import io.hexlet.typoreporter.domain.account.OAuth2GithubUser; @@ -29,6 +30,8 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.NoSuchElementException; +import java.util.Optional; @Service @Transactional @@ -123,7 +126,6 @@ public Account updateProfile(final UpdateProfile updateProfile, final String ema Account updAccount = accountMapper.toAccount(updateProfile, sourceAccount); updAccount.setUsername(normalizedUserName); updAccount.setEmail(normalizedEmail); - System.out.println("12: " + updAccount); accountRepository.save(updAccount); return updAccount; } @@ -156,7 +158,35 @@ public void createGithubUser(OAuth2GithubUser user) { passwordEncoder.encode(user.getPassword()), user.getFirstName(), user.getLastName()); Account account = accountMapper.toAccount(signupAccount); account.setAuthProvider(AuthProvider.GITHUB); + AccountSocialLink link = new AccountSocialLink(); + link.setAccount(account); + link.setLogin(user.getId()); + link.setAuthProvider(AuthProvider.GITHUB); + account.addAccountsSocialLinks(link); accountRepository.save(account); + } + + @Transactional + public void updateGithubUser(Account sourceAccount, OAuth2GithubUser user) { + if (isAccountChanged(sourceAccount, user)) { + var accountByEmail = accountRepository.findAccountByEmail(user.getEmail()); + var accountByUsername = accountRepository.findAccountByEmail(user.getEmail()); + var isNewEmailCanBeUsed = accountByEmail.map(account -> account.equals(sourceAccount)).orElse(true); + var isNewUsernameCanBeUsed = accountByUsername.map(account -> account.equals(sourceAccount)).orElse(true); + if (isNewEmailCanBeUsed && isNewUsernameCanBeUsed) { + sourceAccount.setUsername(user.getLogin()); + sourceAccount.setEmail(user.getEmail()); + sourceAccount.setFirstName(user.getFirstName()); + sourceAccount.setLastName(user.getLastName()); + accountRepository.save(sourceAccount); + } + } + } + private boolean isAccountChanged(Account account, OAuth2GithubUser user) { + return !account.getEmail().equalsIgnoreCase(user.getEmail()) || + !account.getUsername().equalsIgnoreCase(user.getLogin()) || + !account.getFirstName().equalsIgnoreCase(user.getFirstName()) || + !account.getLastName().equalsIgnoreCase(user.getLastName()); } } diff --git a/src/main/resources/db/changelog/changesets/2024/10/2024-10-06-add-table-social-links-to-accounts.xml b/src/main/resources/db/changelog/changesets/2024/10/2024-10-06-add-table-social-links-to-accounts.xml new file mode 100644 index 00000000..7abd2d0f --- /dev/null +++ b/src/main/resources/db/changelog/changesets/2024/10/2024-10-06-add-table-social-links-to-accounts.xml @@ -0,0 +1,28 @@ + + + + + Таблица для хранения ID пользователя из социальной сети, т.к. пользователя можно идентифицировать только по нему + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/db/changelog/db.changelog-master.xml b/src/main/resources/db/changelog/db.changelog-master.xml index e68d18d9..0353309e 100644 --- a/src/main/resources/db/changelog/db.changelog-master.xml +++ b/src/main/resources/db/changelog/db.changelog-master.xml @@ -27,4 +27,6 @@ relativeToChangelogFile="true" /> +