001package usecase.user;
002
003import com.sun.istack.NotNull;
004import media.MediaRepository;
005import media.ReadLimitExceededException;
006import model.entity.User;
007import model.repository.GenericRepository;
008import model.validation.*;
009import usecase.auth.*;
010import usecase.auth.Pbkdf2PasswordHash.HashedPassword;
011
012import javax.enterprise.context.ApplicationScoped;
013import javax.inject.Inject;
014import javax.transaction.Transactional;
015import javax.validation.Valid;
016import javax.validation.constraints.NotBlank;
017import java.io.IOException;
018import java.util.List;
019import java.util.stream.Collectors;
020
021/**
022 * Classe che fornisce i servizi relativi agli utenti.
023 */
024@ApplicationScoped
025@Transactional
026public class UserService {
027    private GenericRepository genericRepository;
028    private MediaRepository bcRepo;
029    private CurrentUser currentUser;
030    private Pbkdf2PasswordHash passwordHash;
031
032    protected UserService(){}
033
034    @Inject
035    protected UserService(GenericRepository genericRepository,
036                          MediaRepository mediaRepository, Pbkdf2PasswordHash passwordHash,
037                          CurrentUser currentUser){
038        this.genericRepository = genericRepository;
039        this.bcRepo = mediaRepository;
040        this.passwordHash = passwordHash;
041        this.currentUser = currentUser;
042    }
043
044    /**
045     * Converte User in UserProfile.
046     * @param user utente da convertire
047     * @return UserProfile con i dati di user
048     */
049    private UserProfile map(User user){
050        return UserProfile.builder()
051                .id(user.getId())
052                .email(user.getEmail())
053                .creationDate(user.getCreationDate())
054                .description(user.getDescription())
055                .picture(user.getPicture())
056                .username(user.getUsername())
057                .isAdmin(user.getAdmin()).build();
058    }
059
060    /**
061     * Inverte lo stato di admin di un utente dato un id
062     * @param id id di un utente esistente
063     */
064    @AdminsOnly
065    public void toggleAdmin(@UserExists int id){
066        User u = genericRepository.findById(User.class,id);
067        u.setAdmin(!u.getAdmin());
068    }
069
070    /**
071     * Ritorna un entita UserProfile dato un nome
072     * @param name di un utente esistente
073     * @return entita UserProfile
074     */
075    public UserProfile getUser(@NotBlank @UserExists String name){
076        User u = genericRepository.findByNaturalId(User.class,name);
077        return map(u);
078    }
079
080    /**
081     * Ritorna un entita UserProfile dato un id
082     * @param id di un utente esistente
083     * @return entita UserProfile
084     */
085    public UserProfile getUser(@UserExists int id){
086        User u = genericRepository.findById(User.class,id);
087        return map(u);
088    }
089
090    /**
091     * Ritorna un lo username di un utente dato un id
092     * @param id di un utente esistente
093     * @return nome dell'utente
094     */
095    public String getUsernameById(@UserExists int id){
096        return genericRepository.findById(User.class,id).getUsername();
097    }
098
099    /**
100     * Ritorna un lista di UserProfile relativa agli utenti registrati
101     * @return lista di entita UserIdentityDTO
102     */
103    public List<UserProfile> showUsers(){
104        List<User> users = genericRepository.findAll(User.class);
105        return users.stream().map(this::map).collect(Collectors.toList());
106    }
107
108    /**
109     * Elimina un utente dato un id
110     * @param id di un utente esistente
111     */
112    @AdminsOnly
113    public void delete(@UserExists int id){
114        genericRepository.remove(genericRepository.findById(User.class, id));
115    }
116
117    /**
118     * Modifica i dati di un utente dato un id
119     * @param edit nuovi dati dell'utente
120     * @param id di un utente esistente
121     */
122    @AuthenticationRequired
123    public void edit(@Valid UserEditPage edit,
124                     @UserExists int id){
125        if(currentUser.getId() != id && !currentUser.isAdmin())
126            throw new AuthorizationException();
127
128        User u = genericRepository.findById(User.class,id);
129
130        if(edit.getDescription() != null){
131            u.setDescription(edit.getDescription());
132        }
133        if(edit.getEmail() != null){
134            u.setEmail(edit.getEmail());
135        }
136        if(edit.getPassword() != null){
137            HashedPassword hashedPassword = passwordHash.generate(edit.getPassword());
138            u.setPassword(hashedPassword.getPassword());
139            u.setSalt(hashedPassword.getSalt());
140        }
141        if(edit.getPicture() != null){
142            try {
143                u.setPicture(bcRepo.insert(edit.getPicture()));
144            } catch(ReadLimitExceededException e){
145                throw new IllegalArgumentException("Il file non deve superare i 5MB");
146            } catch (IOException e) {
147                throw new RuntimeException(e); //todo: delet this
148            }
149        }
150    }
151
152    /**
153     * Crea un nuovo utente e ne restituisce l'id
154     * @param email stringa non vuota, unica e in formato email
155     * @param username stringa non vuota e unica
156     * @param password Stringa non vuota con minimo: 3 e massimo: 255 caratteri
157     * @return identificativo dell'utente creato
158     */
159    public int newUser(@NotNull @EmailFormat @UniqueEmail String email,
160                       @NotNull @UsernameFormat @UniqueUsername String username,
161                       @NotNull @PasswordFormat String password){
162        User user = new User();
163        user.setUsername(username);
164        user.setEmail(email);
165        HashedPassword hashedPassword = passwordHash.generate(password);
166        user.setPassword(hashedPassword.getPassword());
167        user.setSalt(hashedPassword.getSalt());
168        user.setAdmin(false);
169
170        user = genericRepository.insert(user);
171        return user.getId();
172    }
173}