package com.qprogramming.tasq.account;
import com.qprogramming.tasq.error.TasqAuthException;
import com.qprogramming.tasq.error.TasqException;
import com.qprogramming.tasq.manage.AppService;
import com.qprogramming.tasq.manage.Theme;
import com.qprogramming.tasq.manage.ThemeService;
import com.qprogramming.tasq.projects.ProjectService;
import com.qprogramming.tasq.support.ResultData;
import com.qprogramming.tasq.support.Utils;
import com.qprogramming.tasq.support.web.MessageHelper;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
@Controller
@Secured("ROLE_USER")
public class AccountController {
private static final Logger LOG = LoggerFactory.getLogger(AccountController.class);
private static final String AVATAR_DIR = "avatar";
private static final String PNG = ".png";
private AccountService accountSrv;
private ProjectService projSrv;
private SessionLocaleResolver localeResolver;
private MessageSource msg;
private SessionRegistry sessionRegistry;
private ThemeService themeSrv;
private AppService appSrv;
@Autowired
public AccountController(AccountService accountSrv, ProjectService projSrv, MessageSource msg,
SessionLocaleResolver localeResolver, SessionRegistry sessionRegistry, ThemeService themeSrv,
AppService appSrv) {
this.accountSrv = accountSrv;
this.projSrv = projSrv;
this.msg = msg;
this.localeResolver = localeResolver;
this.sessionRegistry = sessionRegistry;
this.themeSrv = themeSrv;
this.appSrv = appSrv;
}
@RequestMapping(value = "settings", method = RequestMethod.GET)
public String settings(Model model) {
model.addAttribute("themes", themeSrv.findAll());
return "user/settings";
}
@Transactional(rollbackFor = {TasqException.class})
@RequestMapping(value = "settings", method = RequestMethod.POST)
public String saveSettings(@RequestParam(value = "avatar", required = false) MultipartFile avatarFile,
@RequestParam(value = "email") String email,
@RequestParam(value = "firstname") String firstname,
@RequestParam(value = "surname") String surname,
@RequestParam(value = "watched", required = false) String watched,
@RequestParam(value = "system", required = false) String system,
@RequestParam(value = "comments", required = false) String comments,
@RequestParam(value = "language", required = false) String language,
@RequestParam(value = "theme", required = false) Long themeID,
@RequestParam(value = "password", required = false) String password,
RedirectAttributes ra,
HttpServletRequest request, HttpServletResponse response) {
Account account = Utils.getCurrentAccount();
if (avatarFile.getSize() != 0) {
File file = new File(getAvatar(account.getId()));
try {
FileUtils.writeByteArrayToFile(file, avatarFile.getBytes());
} catch (IOException e) {
LOG.error(e.getMessage());
}
}
//check if something vital was changed and password matches
if (!account.getName().equals(firstname) || !account.getSurname().equals(surname) || !account.getEmail().equals(email)) {
if (!accountSrv.verifyPassword(account, password)) {
MessageHelper.addErrorAttribute(ra, msg.getMessage("user.reset.badpassword", null, Utils.getCurrentLocale()));
return "redirect:/settings";
}
}
if (StringUtils.isNotBlank(firstname)) {
account.setName(firstname);
}
if (StringUtils.isNotBlank(surname)) {
account.setSurname(surname);
}
account.setLanguage(language);
localeResolver.setLocale(request, response, new Locale(language));
account.setSystemnotification(Boolean.parseBoolean(system));
account.setWatchnotification(Boolean.parseBoolean(watched));
account.setCommentnotification(Boolean.parseBoolean(comments));
Theme theme = themeSrv.findById(themeID);
account.setTheme(theme);
String message = "";
if (StringUtils.isNotEmpty(email) && !account.getEmail().equals(email)) {
account.setEmail(email);
account.setConfirmed(false);
if (!accountSrv.sendConfirmationLink(account)) {
throw new TasqException(msg.getMessage("error.email.sending", null, Utils.getCurrentLocale()));
}
}
accountSrv.update(account);
MessageHelper.addSuccessAttribute(ra,
msg.getMessage("panel.saved", null, Utils.getCurrentLocale()) + ". " + message);
return "redirect:/settings";
}
@RequestMapping(value = "/user/{username}", method = RequestMethod.GET)
public String getUser(@PathVariable(value = "username") String username, Model model, RedirectAttributes ra) {
Account account = accountSrv.findByUsername(username);
if (account == null) {
MessageHelper.addErrorAttribute(ra, msg.getMessage("error.noUser", null, Utils.getCurrentLocale()));
return "redirect:/users";
}
List<Object> principals = sessionRegistry.getAllPrincipals();
DisplayAccount dispAccount = accountWithSession(principals, account);
model.addAttribute("projects", projSrv.findAllByUser(account.getId()));
model.addAttribute("account", dispAccount);
return "user/details";
}
@RequestMapping(value = "/getAccounts", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<List<DisplayAccount>> listAccounts(@RequestParam String term, HttpServletResponse response) {
response.setContentType("application/json");
List<Account> accounts;
if (term == null) {
accounts = accountSrv.findAll();
} else {
accounts = accountSrv.findByNameSurnameContaining(term);
}
return ResponseEntity.ok(accounts.stream().map(DisplayAccount::new).collect(Collectors.toList()));
}
@RequestMapping(value = "/users", method = RequestMethod.GET)
public
@ResponseBody
Page<DisplayAccount> listUsers(@RequestParam(required = false) String term,
@PageableDefault(size = 25, page = 0, sort = "surname", direction = Direction.ASC) Pageable p) {
Page<Account> page;
if (term != null) {
page = accountSrv.findByNameSurnameContaining(term, p);
} else {
page = accountSrv.findAll(p);
}
List<DisplayAccount> list = new LinkedList<>();
List<Object> principals = sessionRegistry.getAllPrincipals();
for (Account account : page) {
DisplayAccount dispAccount = accountWithSession(principals, account);
list.add(dispAccount);
}
return new PageImpl<>(list, p, page.getTotalElements());
}
@RequestMapping(value = "/project/participants", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<Page<DisplayAccount>> listParticipants(@RequestParam(required = false) String term,
@RequestParam String projId,
@PageableDefault(size = 25, page = 0, sort = "surname", direction = Direction.ASC) Pageable p) {
List<Object> principals = sessionRegistry.getAllPrincipals();
List<Account> projectAccounts = projSrv.getProjectAccounts(projId, term);
List<DisplayAccount> participants = projectAccounts.stream().map(account -> accountWithSession(principals, account)).collect(Collectors.toList());
int totalParticipants = participants.size();
if (participants.size() > p.getPageSize()) {
participants = participants.subList(p.getOffset(), p.getOffset() + p.getPageSize());
}
return ResponseEntity.ok(new PageImpl<>(participants, p, totalParticipants));
}
private DisplayAccount accountWithSession(List<Object> principals, Account account) {
DisplayAccount dAccount = new DisplayAccount(account);
List<SessionInformation> sessions = sessionRegistry.getAllSessions(account, false);
if (!sessions.isEmpty() && principals.contains(account)) {
dAccount.setOnline(true);
}
return dAccount;
}
@RequestMapping(value = "/user/{username}/reset-avatar", method = RequestMethod.GET)
public String resetAvatar(@PathVariable(value = "username") String username, HttpServletRequest request,
RedirectAttributes ra) {
if (!Roles.isAdmin()) {
throw new TasqAuthException(msg);
}
Account account = accountSrv.findByUsername(username);
if (account == null) {
MessageHelper.addErrorAttribute(ra, msg.getMessage("error.noUser", null, Utils.getCurrentLocale()));
} else {
HttpSession session = request.getSession();
ServletContext sc = session.getServletContext();
File userAvatar = new File(getAvatar(account.getId()));
Utils.copyFile(sc, "/resources/img/avatar.png", userAvatar);
MessageHelper.addSuccessAttribute(ra, msg.getMessage("user.reset.success", null, Utils.getCurrentLocale()));
}
return "redirect:" + request.getHeader("Referer");
}
@RequestMapping(value = "/emailResend", method = RequestMethod.GET)
public String resendEmail(RedirectAttributes ra) {
Account account = Utils.getCurrentAccount();
if (!accountSrv.sendConfirmationLink(account)) {
throw new TasqException(msg.getMessage("error.email.sending", null, Utils.getCurrentLocale()));
}
MessageHelper.addSuccessAttribute(ra, msg.getMessage("panel.emails.resend.sent",
new Object[]{account.getEmail()}, Utils.getCurrentLocale()));
return "redirect:/settings";
}
@RequestMapping(value = "role", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<ResultData> setRole(@RequestParam(value = "id") Long id, @RequestParam(value = "role") Roles role) {
Account account = accountSrv.findById(id);
if (account != null) {
// check if not admin or user
List<Account> admins = accountSrv.findAdmins();
if (account.getRole().equals(Roles.ROLE_ADMIN) && admins.size() == 1) {
return ResponseEntity.ok(new ResultData(ResultData.Code.ERROR,
msg.getMessage("role.last.admin", null, Utils.getCurrentLocale())));
} else {
String rolemsg = msg.getMessage(role.getCode(), null, Utils.getCurrentLocale());
account.setRole(role);
accountSrv.update(account);
String resultMsg = msg.getMessage("role.change.succes", new Object[]{account.toString(), rolemsg},
Utils.getCurrentLocale());
return ResponseEntity.ok(new ResultData(ResultData.Code.OK, resultMsg));
}
}
return null;
}
/**
* Sends email with invite to indicated email
*
* @param email
* @param request
* @param ra
* @return
*/
@RequestMapping(value = "/inviteUsers", method = RequestMethod.GET)
public String sendInvite(@RequestParam(value = "email") String email, HttpServletRequest request,
RedirectAttributes ra) {
if (!accountSrv.sendInvite(email, themeSrv.getDefault())) {
throw new TasqException(msg.getMessage("error.email.sending", null, Utils.getCurrentLocale()));
}
MessageHelper.addSuccessAttribute(ra,
msg.getMessage("panel.invite.sent", new Object[]{email}, Utils.getCurrentLocale()));
return "redirect:" + request.getHeader("Referer");
}
@RequestMapping(value = "/sidebar")
@ResponseBody
public ResponseEntity saveSidebarSize(@RequestParam Boolean enable) {
Account account = Utils.getCurrentAccount();
if (account == null) {
LOG.error("Something went wrong while fetching current account");
return ResponseEntity.badRequest().body("Error while saving property");
}
account.setSmallSidebar(enable);
accountSrv.update(account);
return ResponseEntity.ok("");
}
private String getAvatarDir() {
return appSrv.getProperty(AppService.TASQROOTDIR) + File.separator + AVATAR_DIR + File.separator;
}
private String getAvatar(Long id) {
return getAvatarDir() + id + PNG;
}
}