Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Anton Romanov 2019-06-08 14:37:07 +04:00
commit 098f70ede6
17 changed files with 383 additions and 47 deletions

View File

@ -13,8 +13,10 @@ import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import ru.ulstu.core.model.AuthFailureHandler;
import ru.ulstu.user.controller.UserController;
import ru.ulstu.user.model.UserRoleConstants;
import ru.ulstu.user.service.UserService;
@ -35,17 +37,20 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final AuthenticationSuccessHandler authenticationSuccessHandler;
private final LogoutSuccessHandler logoutSuccessHandler;
private final ApplicationProperties applicationProperties;
private final AuthenticationFailureHandler authenticationFailureHandler;
public SecurityConfiguration(UserService userService,
BCryptPasswordEncoder bCryptPasswordEncoder,
AuthenticationSuccessHandler authenticationSuccessHandler,
LogoutSuccessHandler logoutSuccessHandler,
ApplicationProperties applicationProperties) {
ApplicationProperties applicationProperties,
AuthFailureHandler authenticationFailureHandler) {
this.userService = userService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
this.authenticationSuccessHandler = authenticationSuccessHandler;
this.logoutSuccessHandler = logoutSuccessHandler;
this.applicationProperties = applicationProperties;
this.authenticationFailureHandler = authenticationFailureHandler;
}
@Override
@ -66,6 +71,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.antMatchers(UserController.ACTIVATE_URL).permitAll()
.antMatchers(Constants.PASSWORD_RESET_REQUEST_PAGE).permitAll()
.antMatchers(Constants.PASSWORD_RESET_PAGE).permitAll()
.antMatchers("/users/block").permitAll()
.antMatchers(UserController.URL + UserController.REGISTER_URL).permitAll()
.antMatchers(UserController.URL + UserController.ACTIVATE_URL).permitAll()
.antMatchers(UserController.URL + UserController.PASSWORD_RESET_REQUEST_URL).permitAll()
@ -76,6 +82,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.formLogin()
.loginPage("/login")
.successHandler(authenticationSuccessHandler)
.failureHandler(authenticationFailureHandler)
.permitAll()
.and()
.logout()

View File

@ -0,0 +1,21 @@
package ru.ulstu.core.model;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import ru.ulstu.user.error.UserBlockedException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class AuthFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException ex) throws IOException {
if (ex.getClass() == UserBlockedException.class) {
response.sendRedirect("/users/block");
}
}
}

View File

@ -50,7 +50,7 @@ public class GrantController {
@GetMapping("/grant")
public void getGrant(ModelMap modelMap, @RequestParam(value = "id") Integer id) {
if (id != null && id > 0) {
GrantDto grantDto = grantService.findOneDto(id);
GrantDto grantDto = grantService.getExistGrantById(id);
attachPaper(grantDto);
modelMap.put("grantDto", grantDto);
} else {

View File

@ -1,5 +1,6 @@
package ru.ulstu.grant.service;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@ -17,7 +18,6 @@ import ru.ulstu.paper.model.Paper;
import ru.ulstu.paper.model.PaperDto;
import ru.ulstu.paper.service.PaperService;
import ru.ulstu.ping.service.PingService;
import ru.ulstu.project.model.Project;
import ru.ulstu.project.model.ProjectDto;
import ru.ulstu.project.service.ProjectService;
import ru.ulstu.timeline.service.EventService;
@ -77,6 +77,11 @@ public class GrantService extends BaseService {
this.pingService = pingService;
}
public GrantDto getExistGrantById(Integer id) {
GrantDto grantDto = new GrantDto(findById(id));
return grantDto;
}
public List<Grant> findAll() {
return grantRepository.findAll();
}
@ -85,17 +90,13 @@ public class GrantService extends BaseService {
return convert(findAll(), GrantDto::new);
}
public GrantDto findOneDto(Integer id) {
return new GrantDto(grantRepository.findOne(id));
}
@Transactional
public Integer create(GrantDto grantDto) throws IOException {
public Grant create(GrantDto grantDto) throws IOException {
Grant newGrant = copyFromDto(new Grant(), grantDto);
newGrant = grantRepository.save(newGrant);
eventService.createFromObject(newGrant, Collections.emptyList(), false, "гранта");
grantNotificationService.sendCreateNotification(newGrant);
return newGrant.getId();
return newGrant;
}
private Grant copyFromDto(Grant grant, GrantDto grantDto) throws IOException {
@ -106,9 +107,11 @@ public class GrantService extends BaseService {
grant.setProject(projectService.findById(grantDto.getProject().getId()));
}
grant.setDeadlines(deadlineService.saveOrCreate(grantDto.getDeadlines()));
grant.setFiles(fileService.saveOrCreate(grantDto.getFiles().stream()
.filter(f -> !f.isDeleted())
.collect(toList())));
if (!grant.getFiles().isEmpty()) {
grant.setFiles(fileService.saveOrCreate(grantDto.getFiles().stream()
.filter(f -> !f.isDeleted())
.collect(toList())));
}
grant.getAuthors().clear();
if (grantDto.getAuthorIds() != null && !grantDto.getAuthorIds().isEmpty()) {
grantDto.getAuthorIds().forEach(authorIds -> grant.getAuthors().add(userService.findById(authorIds)));
@ -123,6 +126,7 @@ public class GrantService extends BaseService {
return grant;
}
public void createProject(GrantDto grantDto) throws IOException {
grantDto.setProject(
new ProjectDto(projectService.save(new ProjectDto(grantDto.getTitle()))));
@ -130,7 +134,7 @@ public class GrantService extends BaseService {
@Transactional
public Integer update(GrantDto grantDto) throws IOException {
Grant grant = grantRepository.findOne(grantDto.getId());
Grant grant = findById(grantDto.getId());
Set<User> oldAuthors = new HashSet<>(grant.getAuthors());
User oldLeader = grant.getLeader();
for (FileDataDto file : grantDto.getFiles().stream()
@ -159,34 +163,19 @@ public class GrantService extends BaseService {
}
@Transactional
public void delete(Integer grantId) throws IOException {
Grant grant = grantRepository.findOne(grantId);
grantRepository.delete(grant);
public boolean delete(Integer grantId) throws IOException {
Grant grant = findById(grantId);
if (grant != null) {
grantRepository.delete(grant);
return true;
}
return false;
}
public List<Grant.GrantStatus> getGrantStatuses() {
return Arrays.asList(Grant.GrantStatus.values());
}
@Transactional
public Grant create(String title, Project projectId, Date deadlineDate, User user, Paper paper) {
Grant grant = new Grant();
grant.setTitle(title);
grant.setComment("Комментарий к гранту 1");
grant.setProject(projectId);
grant.setStatus(APPLICATION);
grant.getDeadlines().add(new Deadline(deadlineDate, "первый дедлайн"));
grant.getAuthors().add(user);
grant.setLeader(user);
grant.getPapers().add(paper);
grant = grantRepository.save(grant);
eventService.createFromObject(grant, Collections.emptyList(), false, "гранта");
grantNotificationService.sendCreateNotification(grant);
return grant;
}
public boolean save(GrantDto grantDto, Errors errors) throws IOException {
grantDto.setName(grantDto.getTitle());
filterEmptyDeadlines(grantDto);
@ -274,20 +263,22 @@ public class GrantService extends BaseService {
return paperService.findAllNotCompleted();
}
public void attachPaper(GrantDto grantDto) {
public List<PaperDto> attachPaper(GrantDto grantDto) {
if (!grantDto.getPaperIds().isEmpty()) {
grantDto.getPapers().clear();
grantDto.setPapers(getGrantPapers(grantDto.getPaperIds()));
} else {
grantDto.getPapers().clear();
}
return grantDto.getPapers();
}
public void removeDeadline(GrantDto grantDto, Integer deadlineId) {
public GrantDto removeDeadline(GrantDto grantDto, Integer deadlineId) {
if (grantDto.getDeadlines().get(deadlineId).getId() != null) {
grantDto.getRemovedDeadlineIds().add(grantDto.getDeadlines().get(deadlineId).getId());
}
grantDto.getDeadlines().remove((int) deadlineId);
return grantDto;
}
private List<User> getCompletedPapersAuthors(Paper.PaperType type) {
@ -313,10 +304,11 @@ public class GrantService extends BaseService {
.collect(toList());
}
public void filterEmptyDeadlines(GrantDto grantDto) {
public List<Deadline> filterEmptyDeadlines(GrantDto grantDto) {
grantDto.setDeadlines(grantDto.getDeadlines().stream()
.filter(dto -> dto.getDate() != null || !org.springframework.util.StringUtils.isEmpty(dto.getDescription()))
.filter(dto -> dto.getDate() != null || !StringUtils.isEmpty(dto.getDescription()))
.collect(Collectors.toList()));
return grantDto.getDeadlines();
}
@Transactional
@ -346,8 +338,4 @@ public class GrantService extends BaseService {
public void ping(int grantId) throws IOException {
pingService.addPing(findById(grantId));
}
public Grant findGrantById(Integer grantId) {
return grantRepository.findOne(grantId);
}
}

View File

@ -175,4 +175,9 @@ public class UserController extends OdinController<UserListDto, UserDto> {
@RequestParam(value = "activity", required = false) String activity) {
return new Response<>(userService.getActivitiesPings(userId, activity));
}
@PostMapping("/block")
public void blockUser(@RequestParam("userId") Integer userId) {
userService.blockUser(userId);
}
}

View File

@ -74,4 +74,8 @@ public class UserMvcController extends OdinController<UserListDto, UserDto> {
@GetMapping("/pings")
public void getPings() {
}
@GetMapping("/block")
public void getBlock() {
}
}

View File

@ -0,0 +1,9 @@
package ru.ulstu.user.error;
import org.springframework.security.core.AuthenticationException;
public class UserBlockedException extends AuthenticationException {
public UserBlockedException(String message) {
super(message);
}
}

View File

@ -12,6 +12,7 @@ import javax.persistence.Enumerated;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@ -91,6 +92,10 @@ public class User extends BaseEntity {
@Temporal(TemporalType.TIMESTAMP)
private Date birthDate;
@ManyToOne()
@JoinColumn(name = "blocker_id")
private User blocker;
public enum UserDegree {
CANDIDATE("Кандидат технических наук"),
DOCTOR("Доктор технических наук");
@ -229,6 +234,14 @@ public class User extends BaseEntity {
this.degree = degree;
}
public User getBlocker() {
return blocker;
}
public void setBlocker(User blocker) {
this.blocker = blocker;
}
public String getUserAbbreviate() {
return String.format(USER_ABBREVIATE_TEMPLATE,
lastName == null ? "" : lastName,

View File

@ -21,12 +21,10 @@ import ru.ulstu.core.jpa.OffsetablePageRequest;
import ru.ulstu.core.model.BaseEntity;
import ru.ulstu.core.model.UserActivity;
import ru.ulstu.core.model.response.PageableItems;
import ru.ulstu.grant.service.GrantService;
import ru.ulstu.paper.service.PaperService;
import ru.ulstu.ping.model.Ping;
import ru.ulstu.ping.service.PingService;
import ru.ulstu.project.service.ProjectService;
import ru.ulstu.user.error.UserActivationError;
import ru.ulstu.user.error.UserBlockedException;
import ru.ulstu.user.error.UserEmailExistsException;
import ru.ulstu.user.error.UserIdExistsException;
import ru.ulstu.user.error.UserIsUndeadException;
@ -323,6 +321,9 @@ public class UserService implements UserDetailsService {
if (!user.getActivated()) {
throw new UserNotActivatedException();
}
if (user.getBlocker() != null) {
throw new UserBlockedException(String.format("Вы заблокированы пользователем %s", user.getBlocker().getUserAbbreviate()));
}
return new org.springframework.security.core.userdetails.User(user.getLogin(),
user.getPassword(),
Optional.ofNullable(user.getRoles()).orElse(Collections.emptySet()).stream()
@ -424,4 +425,10 @@ public class UserService implements UserDetailsService {
}
return activitiesPings;
}
public void blockUser(int userId) {
User userToBlock = findById(userId);
userToBlock.setBlocker(getCurrentUser());
userRepository.save(userToBlock);
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet author="arefyev" id="20190528_000000-3">
<addColumn tableName="users">
<column name="blocker_id" type="integer"/>
</addColumn>
<addForeignKeyConstraint baseTableName="users" baseColumnNames="blocker_id" constraintName="fk_blocker"
referencedTableName="users" referencedColumnNames="id"/>
</changeSet>
</databaseChangeLog>

View File

@ -53,4 +53,5 @@
<include file="db/changelog-20190529_000001-schema.xml"/>
<include file="db/changelog-20190601_000001-schema.xml"/>
<include file="db/changelog-20190605_000000-schema.xml"/>
<include file="db/changelog-20190607_000002-schema.xml"/>
</databaseChangeLog>

View File

@ -120,6 +120,20 @@ function resetPassword() {
})
}
function blockUser() {
userId = $('#userId').val();
$.ajax({
url:"/api/1.0/users/block?userId=" + userId,
contentType: "application/json; charset=utf-8",
method: "POST",
success: function() {
showFeedbackMessage("Пользователь заблокирован", MessageTypesEnum.SUCCESS)
},
error: function(errorData) {
showFeedbackMessage(errorData.responseJSON.error.message, MessageTypesEnum.WARNING)
}
})
}
function isEmailValid(email) {
re = /\S+@\S+\.\S+/;

View File

@ -109,6 +109,7 @@
<script src="/js/core.js"></script>
<script src="/js/config.js"></script>
<script src="/js/odin.js"></script>
<script src="/js/users.js"></script>
<script th:inline="javascript">
/*<![CDATA[*/

View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorator="default">
<head>
</head>
<body>
<div class="container" layout:fragment="content">
<section id="services">
<div class="container">
<div class="row">
<div class="col-lg-12 text-center">
<h2 class="section-heading text-uppercase">Ваш аккаунт заблокирован</h2>
<a href="/"><h3>Вернуться на страницу авторизации</h3></a>
</div>
</div>
</div>
</section>
</div>
</body>
</html>

View File

@ -7,6 +7,7 @@
<div th:fragment="userDashboard (user)" class="col-12 col-sm-12 col-md-12 col-lg-4 col-xl-3 dashboard-card">
<div class="row">
<div class="col col-10">
<input type="hidden" id="userId" th:value="${user.user.id}"/>
<b><p th:text="${user.user.lastName} + ' ' + ${user.user.firstName} + ' ' + ${user.user.patronymic}"></p>
</b>
<i><p th:if="${user.conference != null}" th:text="'Сейчас на конференции ' + ${user.conference.title}"></p>
@ -15,6 +16,7 @@
th:text="'Сейчас на паре ' + ${user.lesson.nameOfLesson} + ' в аудитории ' + ${user.lesson.room}"></p>
</i>
<p th:if="${user.isOnline()}">Онлайн</p>
<button onclick="blockUser()">Заблокировать</button>
</div>
</div>
</div>

View File

@ -14,7 +14,7 @@ public class GrantPage extends PageObject {
}
public String getId() {
return driver.findElement(By.id("id")).getAttribute("value");
return driver.findElement(By.id("grantId")).getAttribute("value");
}
public void setTitle(String name) {

View File

@ -0,0 +1,231 @@
package ru.ulstu.grant.service;
import org.apache.commons.lang3.StringUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.deadline.service.DeadlineService;
import ru.ulstu.grant.model.Grant;
import ru.ulstu.grant.model.GrantDto;
import ru.ulstu.grant.repository.GrantRepository;
import ru.ulstu.paper.model.Paper;
import ru.ulstu.paper.model.PaperDto;
import ru.ulstu.paper.service.PaperService;
import ru.ulstu.timeline.service.EventService;
import ru.ulstu.user.model.User;
import ru.ulstu.user.service.UserService;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class GrantServiceTest {
@Mock
GrantRepository grantRepository;
@Mock
DeadlineService deadlineService;
@Mock
PaperService paperService;
@Mock
UserService userService;
@Mock
EventService eventService;
@Mock
GrantNotificationService grantNotificationService;
@InjectMocks
GrantService grantService;
private final static Integer ID = 1;
private final static Integer INDEX = 0;
private final static String TITLE = "Title";
private final static String COMMENT = "Comment";
private final static boolean TRUE = true;
private final static Integer YEAR = 2019;
private final static Integer MAX_DISPLAY_SIZE = 50;
private List<Grant> grants;
private List<GrantDto> grantDtos;
private List<Deadline> deadlines;
private List<Paper> papers;
private PaperDto paperDto;
private List<PaperDto> paperDtos;
private Set<User> authors;
private GrantDto grantDto;
private Deadline deadline;
private User leader;
private User author;
private Grant grantWithId;
private Paper paperWithId;
@Before
public void setUp() throws Exception {
grants = new ArrayList<>();
grantDtos = new ArrayList<>();
paperDtos = new ArrayList<>();
grantWithId = new Grant();
deadlines = new ArrayList<>();
deadline = new Deadline(new Date(), COMMENT);
deadline.setId(ID);
deadlines.add(deadline);
leader = Mockito.mock(User.class);
papers = new ArrayList<>();
paperWithId = new Paper();
paperWithId.setId(ID);
paperWithId.setTitle(TITLE);
papers.add(paperWithId);
paperDto = new PaperDto(paperWithId);
paperDtos.add(paperDto);
authors = new HashSet<>();
author = leader;
authors.add(author);
grantWithId.setId(ID);
grantWithId.setTitle(TITLE);
grantWithId.setComment(COMMENT);
grantWithId.setDeadlines(deadlines);
grantWithId.setLeader(leader);
grantWithId.setPapers(papers);
grantWithId.setAuthors(authors);
grants.add(grantWithId);
grantDto = new GrantDto(grantWithId);
grantDtos.add(grantDto);
}
@Test
public void getExistGrantById() {
when(grantRepository.findOne(ID)).thenReturn(grantWithId);
GrantDto newGrantDto = new GrantDto(grantWithId);
GrantDto result = grantService.getExistGrantById(ID);
assertEquals(newGrantDto.getId(), result.getId());
}
@Test
public void findAll() {
when(grantRepository.findAll()).thenReturn(grants);
assertEquals(Collections.singletonList(grantWithId), grantService.findAll());
}
@Test
public void create() throws IOException {
when(deadlineService.saveOrCreate(new ArrayList<>())).thenReturn(deadlines);
when(userService.getUserByLogin("admin")).thenReturn(leader);
when(grantRepository.save(new Grant())).thenReturn(grantWithId);
Grant newGrant = new Grant();
newGrant.setId(ID);
newGrant.setTitle(TITLE);
newGrant.setComment(COMMENT);
newGrant.setDeadlines(deadlines);
newGrant.setLeader(leader);
assertEquals(newGrant, grantService.create(grantDto));
}
@Test
public void getGrantStatuses() {
assertEquals(Arrays.asList(Grant.GrantStatus.values()), grantService.getGrantStatuses());
}
@Test
public void getGrantPapers() {
when(paperService.findAllSelect(Collections.singletonList(ID))).thenReturn(paperDtos);
assertEquals(paperDtos, grantService.getGrantPapers(Collections.singletonList(ID)));
}
@Test
public void getAllUncompletedPapers() {
when(paperService.findAllNotCompleted()).thenReturn(paperDtos);
paperDtos.stream()
.forEach(paperDto -> {
paperDto.setTitle(StringUtils.abbreviate(paperDto.getTitle(), MAX_DISPLAY_SIZE));
});
assertEquals(paperDtos, grantService.getAllUncompletedPapers());
}
@Test
public void delete() throws IOException {
when(grantRepository.findOne(ID)).thenReturn(grantWithId);
assertTrue(grantService.delete(grantWithId.getId()));
}
@Test
public void removeDeadline() {
GrantDto newGrantDto = new GrantDto();
newGrantDto.getRemovedDeadlineIds().add(ID);
grantDto.getDeadlines().add(deadline);
GrantDto result = grantService.removeDeadline(grantDto, INDEX);
assertEquals(newGrantDto.getRemovedDeadlineIds(), result.getRemovedDeadlineIds());
}
@Test
public void findById() {
when(grantRepository.findOne(ID)).thenReturn(grantWithId);
Grant findGrant = grantService.findById(ID);
assertEquals(grantWithId.getId(), findGrant.getId());
}
@Test
public void attachPaper() {
when(grantRepository.findOne(ID)).thenReturn(grantWithId);
when(paperService.findAllSelect(Collections.singletonList(ID))).thenReturn(paperDtos);
GrantDto newGrantDto = new GrantDto(grantWithId);
if (!newGrantDto.getPaperIds().isEmpty()) {
newGrantDto.getPapers().clear();
newGrantDto.setPapers(paperDtos);
} else {
newGrantDto.getPapers().clear();
}
assertEquals(newGrantDto.getPapers(), grantService.attachPaper(grantDto));
}
@Test
public void filterEmptyDeadlines() {
when(grantRepository.findOne(ID)).thenReturn(grantWithId);
GrantDto newGrantDto = new GrantDto(grantWithId);
newGrantDto.setDeadlines(newGrantDto.getDeadlines().stream()
.filter(dto -> dto.getDate() != null || !StringUtils.isEmpty(dto.getDescription()))
.collect(Collectors.toList()));
assertEquals(newGrantDto.getDeadlines(), grantService.filterEmptyDeadlines(grantDto));
}
}