package de.learny.controller;
import io.swagger.annotations.Api;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import de.learny.controller.exception.InvalidPasswordException;
import de.learny.controller.exception.InvalidTokenException;
import de.learny.controller.exception.NotEnoughPermissionsException;
import de.learny.controller.exception.ResourceNotFoundException;
import de.learny.dataaccess.AccountRepository;
import de.learny.dataaccess.PasswordResetTokenRepository;
import de.learny.dataaccess.RoleRepository;
import de.learny.dataaccess.SubjectRepository;
import de.learny.dataaccess.TestScoreRepository;
import de.learny.domain.Account;
import de.learny.domain.Achievement;
import de.learny.domain.PasswordResetToken;
import de.learny.domain.Role;
import de.learny.domain.Subject;
import de.learny.domain.TestScore;
import de.learny.security.service.LoggedInAccountService;
import de.learny.security.service.PasswordGeneratorService;
import de.learny.service.LearnyMailSender;
import de.learny.service.UserFinder;
@Api(value = "Accounts", description = "Zugriff auf Accounts", produces = "application/json")
@RestController
@RequestMapping("/api/accounts")
public class AccountController {
@Autowired
PasswordGeneratorService passwordGenerator;
@Autowired
private LoggedInAccountService userToAccountService;
@Autowired
private AccountRepository accountRepository;
@Autowired
private SubjectRepository subjectRepo;
@Autowired
private RoleRepository roleRepo;
@Autowired
private UserFinder userFinder;
@Autowired
private TestScoreRepository testScoreRepo;
@Autowired
private PasswordResetTokenRepository pwTokenRepo;
@Autowired
private LearnyMailSender mailSender;
@RequestMapping(value = "", method = RequestMethod.GET)
Iterable<Account> getAllAccounts() {
return accountRepository.findAll();
}
@RequestMapping(value = "", method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE })
@ResponseStatus(HttpStatus.CREATED)
void create(@RequestBody Account account) {
if (account.getPassword() == null) {
throw new IllegalArgumentException("Passwort darf nicht leer sein.");
}
Account newAcc = new Account(account.getAccountName(),
passwordGenerator.hashPassword(account.getPassword()));
if (newAcc.getAccountName() == null) {
throw new IllegalArgumentException("Accountname darf nicht leer sein");
}
newAcc.setFirstname(account.getFirstname());
newAcc.setLastname(account.getLastname());
newAcc.setEmail(account.getEmail());
newAcc.addRole(roleRepo.findFirstByName("user"));
boolean accountNameAlreadyExists = accountRepository.findFirstByAccountName(newAcc
.getAccountName()) != null;
if (accountNameAlreadyExists) {
throw new IllegalArgumentException("Accountname schon vorhanden");
}
boolean emailAlreadyExists = accountRepository.findByEmail(account.getEmail()) != null;
if (emailAlreadyExists) {
throw new IllegalArgumentException("E-Mail schon vorhanden");
}
accountRepository.save(newAcc);
}
@RequestMapping(value = "/me", method = RequestMethod.GET)
Account getOwnAccounts() {
Account account = userToAccountService.getLoggedInAccount();
return account;
}
@RequestMapping(value = "/loggedin", method = RequestMethod.GET)
boolean checkLogin() {
return true;
}
@RequestMapping(value = "/{role}", method = RequestMethod.GET)
Iterable<Account> getAllAccountsToRole(@PathVariable("role") String role) {
Set<Role> roles = new HashSet<Role>();
roles.add(roleRepo.findFirstByName(role));
return accountRepository.findByRoles(roles);
}
@RequestMapping(value = "/find/{string}", method = RequestMethod.GET)
Set<Account> findAccountByString(@PathVariable("string") String string) {
return userFinder.findUserBy(string);
}
@RequestMapping(value = "/findwithrole/{string}&{role}", method = RequestMethod.GET)
Set<Account> findAccountWithRoleByString(@PathVariable("string") String string,
@PathVariable("role") String role) {
return userFinder.findUserBy(string, role);
}
@RequestMapping(value = "/{id}", method = RequestMethod.PUT, consumes = { MediaType.APPLICATION_JSON_VALUE })
Account update(@PathVariable("id") long id, @RequestBody Account postedAccount) {
Account loggedInAccount = userToAccountService.getLoggedInAccount();
if (!loggedInAccount.hasRole("admin") && loggedInAccount.getId() != id) {
throw new NotEnoughPermissionsException("Nicht genug Rechte, um das durchzuführen.");
}
Account oldAccount = accountRepository.findById(id);
if (oldAccount == null) {
throw new ResourceNotFoundException("Ein Account mit dieser id existiert nicht");
}
oldAccount.setFirstname(postedAccount.getFirstname());
oldAccount.setLastname(postedAccount.getLastname());
oldAccount.setAvatarUri(postedAccount.getAvatarUri());
oldAccount.setMyNote(postedAccount.getMyNote());
return accountRepository.save(oldAccount);
}
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
void delete(@PathVariable("id") long id) {
Account loggedInAccount = userToAccountService.getLoggedInAccount();
if (!loggedInAccount.hasRole("admin")) {
throw new NotEnoughPermissionsException("Nicht genug Rechte, um das auszuführen.");
}
accountRepository.delete(id);
}
@RequestMapping(value = "/me/enroled-subjects", method = RequestMethod.GET)
Iterable<Subject> getEnroledSubjects() {
Account loggedInAccount = userToAccountService.getLoggedInAccount();
return loggedInAccount.getJoinedSubjects();
}
@RequestMapping(value = "/me/enroled-subjects", method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE })
boolean registerToSubjects(@RequestBody Subject subject) {
Account loggedInAccount = userToAccountService.getLoggedInAccount();
Subject subjectToReg = subjectRepo.findById(subject.getId());
if (subjectToReg == null)
throw new ResourceNotFoundException("Ein Fach mit dieser id existiert nicht");
boolean var = loggedInAccount.addJoinedSubject(subjectToReg);
accountRepository.save(loggedInAccount);
return var;
}
@RequestMapping(value = "/me/enroled-subjects/{subjectId}", method = RequestMethod.DELETE)
boolean dischargeFromSubject(@PathVariable("subjectId") long subjectId) {
Account loggedInAccount = userToAccountService.getLoggedInAccount();
Subject subjectToRemove = subjectRepo.findById(subjectId);
if (subjectToRemove == null)
throw new ResourceNotFoundException("Ein Fach mit dieser id existiert nicht");
boolean var = loggedInAccount.removeJoinedSubject(subjectToRemove);
accountRepository.save(loggedInAccount);
return var;
}
@RequestMapping(value = "/me/administrated-subjects", method = RequestMethod.GET)
Iterable<Subject> getAdministratedSubjects() {
Account loggedInAccount = userToAccountService.getLoggedInAccount();
return loggedInAccount.getAdministratedSubjects();
}
@RequestMapping(value = "/me/achievements", method = RequestMethod.GET)
Iterable<Achievement> getOwnAchievments() {
Account loggedInAccount = userToAccountService.getLoggedInAccount();
return loggedInAccount.getAchievements();
}
@RequestMapping(value = "/me/password", method = RequestMethod.PUT)
public void changePassword(@RequestParam("oldPassword") String oldPassword, @RequestParam("newPassword") String newPassword) {
Account loggedInAccount = userToAccountService.getLoggedInAccount();
if(passwordGenerator.decodePassword(oldPassword, loggedInAccount.getPassword())){
loggedInAccount.setPassword(passwordGenerator.hashPassword(newPassword));
accountRepository.save(loggedInAccount);
}
else{
throw new InvalidPasswordException("Falsches Passwort");
}
}
@RequestMapping(value = "/password/requestToken", method = RequestMethod.POST)
public void requestPasswordToken(@RequestParam("mail") String mail) {
Account account = accountRepository.findByEmail(mail);
if(account == null) {
throw new ResourceNotFoundException("Es existiert kein Account mit dieser Mail-Adresse");
}
if(account.getPasswordResetToken() != null) {
pwTokenRepo.delete(account.getPasswordResetToken());
}
PasswordResetToken resetToken = new PasswordResetToken();
account.setPasswordResetToken(resetToken);
accountRepository.save(account);
String message = "http://learny.xent-online.de/#/resetPassword?token=" + resetToken.getToken();
mailSender.sendMail(mail, "Reset your password", message);
}
@RequestMapping(value = "/password/reset", method = RequestMethod.POST)
public void resetPassword(@RequestParam("password") String password, @RequestParam("token") String token) {
PasswordResetToken pwToken = pwTokenRepo.findByToken(token);
if(pwToken == null) {
throw new InvalidTokenException("Ungültiger Token");
}
if(!pwToken.getToken().equals(token)) {
throw new InvalidTokenException("Ungültiger Token");
}
if(new Date().getTime() > pwToken.getExpiryDate()) {
throw new InvalidTokenException("Abgelaufener oder ungültiger Token - bitte beantrage einen neuen Token");
};
Account account = accountRepository.findByPasswordResetToken(pwToken);
account.setPassword(passwordGenerator.hashPassword(password));
account.setPasswordResetToken(null);
pwTokenRepo.delete(pwToken);
accountRepository.save(account);
}
@RequestMapping(value = "/{id}/updateRole", method = RequestMethod.PUT, consumes = { MediaType.APPLICATION_JSON_VALUE })
Account updateRole(@PathVariable("id") long id, @RequestBody Set<Role> postedRoles) {
Account loggedInAccount = userToAccountService.getLoggedInAccount();
if (!loggedInAccount.hasRole("admin")) {
throw new NotEnoughPermissionsException("Nicht genug Rechte, um das auszuführen.");
}
Account updateAccount = accountRepository.findById(id);
if (updateAccount == null)
throw new ResourceNotFoundException("Ein Account mit dieser Id existiert nicht");
Set<Role> roles = new HashSet<Role>();
for(Role postedRole : postedRoles){
Role role = roleRepo.findFirstByName(postedRole.getName());
if (role == null)
throw new ResourceNotFoundException("Eine Role mit dem Namen " + postedRole.getName() + " existiert nicht");
roles.add(role);
}
updateAccount.setRoles(roles);
return accountRepository.save(updateAccount);
}
@RequestMapping(value = "/me/testResultsForSubject/{subjectId}", method = RequestMethod.GET)
Iterable<TestScore> showMyResultsForSubject(@PathVariable("subjectId") long subjectId){
Account loggedInAccount = userToAccountService.getLoggedInAccount();
Subject subject = subjectRepo.findById(subjectId);
if (subject == null)
throw new ResourceNotFoundException("Ein Fach mit dieser id existiert nicht");
return testScoreRepo.findByAccountAndTestSubject(loggedInAccount, subject);
}
@RequestMapping(value = "/me/statistics", method = RequestMethod.GET)
void getOwnStatistics() {
// TODO: Noch keine Funktionalität implementiert
// return null;
}
}