// Path: src/main/java/com/jeanchampemont/notedown/security/AuthenticationService.java
// @Service
// public class AuthenticationService {
//     private UserRepository userRepository;
// 
//     private AuthenticationManager authenticationManager;
// 
//     @Autowired
//     public AuthenticationService(UserRepository userRepository, AuthenticationManager authenticationManager) {
//         this.userRepository = userRepository;
//         this.authenticationManager = authenticationManager;
//     }
// 
//     public User getCurrentUser() {
//         String email = SecurityContextHolder.getContext().getAuthentication().getName();
//         return userRepository.findByEmailIgnoreCase(email);
//     }
// 
//     public boolean isAuthenticated() {
//         return (SecurityContextHolder.getContext().getAuthentication() != null);
//     }
// 
//     public void newAuthentication(String email, String password) {
//         Authentication request = new UsernamePasswordAuthenticationToken(email, password);
//         Authentication result = authenticationManager.authenticate(request);
//         SecurityContextHolder.getContext().setAuthentication(result);
//     }
// }
// 
// Path: src/main/java/com/jeanchampemont/notedown/user/persistence/User.java
// @Entity
// @Table(name = "user_account")
// public class User {
//     @Id
//     @GeneratedValue(strategy = GenerationType.TABLE)
//     private long id;
// 
//     @Column(name = "email", unique = true, length = 64)
//     private String email;
// 
//     @Column(name = "password", length = 60)
//     private String password;
// 
//     @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
//     private Set<Note> notes = new HashSet<>();
// 
//     @Column(name = "locale", length = 2)
//     private String locale;
// 
//     @Column(name = "display_name", length = 64)
//     private String displayName;
// 
//     public long getId() {
//         return id;
//     }
// 
//     public void setId(long id) {
//         this.id = id;
//     }
// 
//     public String getEmail() {
//         return email;
//     }
// 
//     public void setEmail(String email) {
//         this.email = email;
//     }
// 
//     public String getPassword() {
//         return password;
//     }
// 
//     public void setPassword(String password) {
//         this.password = password;
//     }
// 
//     public Set<Note> getNotes() {
//         return notes;
//     }
// 
//     public void setNotes(Set<Note> notes) {
//         this.notes = notes;
//     }
// 
//     public String getLocale() {
//         return locale;
//     }
// 
//     public void setLocale(String locale) {
//         this.locale = locale;
//     }
// 
//     public String getDisplayName() {
//         return displayName;
//     }
// 
//     public void setDisplayName(String displayName) {
//         this.displayName = displayName;
//     }
// }
// 
// Path: src/main/java/com/jeanchampemont/notedown/user/persistence/repository/UserRepository.java
// public interface UserRepository extends CrudRepository<User, Long> {
//     User findByEmailIgnoreCase(String email);
// }
// 
// Path: src/main/java/com/jeanchampemont/notedown/utils/exception/OperationNotAllowedException.java
// public class OperationNotAllowedException extends RuntimeException {
// 
// }


import com.jeanchampemont.notedown.security.AuthenticationService;
import com.jeanchampemont.notedown.user.persistence.User;
import com.jeanchampemont.notedown.user.persistence.repository.UserRepository;
import com.jeanchampemont.notedown.utils.exception.OperationNotAllowedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
    /**
     * Find a user for this email if it exists
     *
     * @param email
     * @return
     */
    @Transactional(readOnly = true)
    @Cacheable("user")
    public Optional<User> getUserByEmail(String email) {
        return Optional.ofNullable(repo.findByEmailIgnoreCase(email));
    }

    /**
     * Update user
     * This method does not update email or password.
     * Use changeEmail or changePassword instead.
     *
     * @param user
     * @return updated user
     */
    @Transactional
    @CacheEvict(value = "user", key = "#user.email")
    public User update(User user) {
        User originalUser = repo.findByEmailIgnoreCase(user.getEmail());
        User currentUser = authenticationService.getCurrentUser();
        if (hasWriteAccess(currentUser, originalUser)) {
            originalUser.setLocale(user.getLocale());
            originalUser.setDisplayName(user.getDisplayName());
            return repo.save(originalUser);
        }
// Path: src/main/java/com/jeanchampemont/notedown/security/AuthenticationService.java
// @Service
// public class AuthenticationService {
//     private UserRepository userRepository;
// 
//     private AuthenticationManager authenticationManager;
// 
//     @Autowired
//     public AuthenticationService(UserRepository userRepository, AuthenticationManager authenticationManager) {
//         this.userRepository = userRepository;
//         this.authenticationManager = authenticationManager;
//     }
// 
//     public User getCurrentUser() {
//         String email = SecurityContextHolder.getContext().getAuthentication().getName();
//         return userRepository.findByEmailIgnoreCase(email);
//     }
// 
//     public boolean isAuthenticated() {
//         return (SecurityContextHolder.getContext().getAuthentication() != null);
//     }
// 
//     public void newAuthentication(String email, String password) {
//         Authentication request = new UsernamePasswordAuthenticationToken(email, password);
//         Authentication result = authenticationManager.authenticate(request);
//         SecurityContextHolder.getContext().setAuthentication(result);
//     }
// }
// 
// Path: src/main/java/com/jeanchampemont/notedown/user/persistence/User.java
// @Entity
// @Table(name = "user_account")
// public class User {
//     @Id
//     @GeneratedValue(strategy = GenerationType.TABLE)
//     private long id;
// 
//     @Column(name = "email", unique = true, length = 64)
//     private String email;
// 
//     @Column(name = "password", length = 60)
//     private String password;
// 
//     @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
//     private Set<Note> notes = new HashSet<>();
// 
//     @Column(name = "locale", length = 2)
//     private String locale;
// 
//     @Column(name = "display_name", length = 64)
//     private String displayName;
// 
//     public long getId() {
//         return id;
//     }
// 
//     public void setId(long id) {
//         this.id = id;
//     }
// 
//     public String getEmail() {
//         return email;
//     }
// 
//     public void setEmail(String email) {
//         this.email = email;
//     }
// 
//     public String getPassword() {
//         return password;
//     }
// 
//     public void setPassword(String password) {
//         this.password = password;
//     }
// 
//     public Set<Note> getNotes() {
//         return notes;
//     }
// 
//     public void setNotes(Set<Note> notes) {
//         this.notes = notes;
//     }
// 
//     public String getLocale() {
//         return locale;
//     }
// 
//     public void setLocale(String locale) {
//         this.locale = locale;
//     }
// 
//     public String getDisplayName() {
//         return displayName;
//     }
// 
//     public void setDisplayName(String displayName) {
//         this.displayName = displayName;
//     }
// }
// 
// Path: src/main/java/com/jeanchampemont/notedown/user/persistence/repository/UserRepository.java
// public interface UserRepository extends CrudRepository<User, Long> {
//     User findByEmailIgnoreCase(String email);
// }
// 
// Path: src/main/java/com/jeanchampemont/notedown/utils/exception/OperationNotAllowedException.java
// public class OperationNotAllowedException extends RuntimeException {
// 
// }


// Path: src/main/java/com/jeanchampemont/notedown/user/UserService.java
import com.jeanchampemont.notedown.security.AuthenticationService;
import com.jeanchampemont.notedown.user.persistence.User;
import com.jeanchampemont.notedown.user.persistence.repository.UserRepository;
import com.jeanchampemont.notedown.utils.exception.OperationNotAllowedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;

    /**
     * Find a user for this email if it exists
     *
     * @param email
     * @return
     */
    @Transactional(readOnly = true)
    @Cacheable("user")
    public Optional<User> getUserByEmail(String email) {
        return Optional.ofNullable(repo.findByEmailIgnoreCase(email));
    }

    /**
     * Update user
     * This method does not update email or password.
     * Use changeEmail or changePassword instead.
     *
     * @param user
     * @return updated user
     */
    @Transactional
    @CacheEvict(value = "user", key = "#user.email")
    public User update(User user) {
        User originalUser = repo.findByEmailIgnoreCase(user.getEmail());
        User currentUser = authenticationService.getCurrentUser();
        if (hasWriteAccess(currentUser, originalUser)) {
            originalUser.setLocale(user.getLocale());
            originalUser.setDisplayName(user.getDisplayName());
            return repo.save(originalUser);
        }
        throw new OperationNotAllowedException();