Compare commits
2 Commits
1aba31e5ab
...
8162b23dd2
Author | SHA1 | Date | |
---|---|---|---|
8162b23dd2 | |||
7b13fb6f8b |
@ -1,7 +1,6 @@
|
|||||||
package com.example.nekontakte.core.api;
|
package com.example.nekontakte.core.api;
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
@ -1,33 +1,50 @@
|
|||||||
package com.example.nekontakte.core.api;
|
package com.example.nekontakte.core.api;
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.bind.Name;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import com.example.nekontakte.posts.api.PostDTO;
|
||||||
|
import com.example.nekontakte.posts.model.PostEntity;
|
||||||
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
import com.example.nekontakte.posts.service.PostService;
|
import com.example.nekontakte.posts.service.PostService;
|
||||||
|
import com.example.nekontakte.users.api.UserDTO;
|
||||||
import jakarta.websocket.server.PathParam;
|
import com.example.nekontakte.users.api.UserEditDTO;
|
||||||
|
import com.example.nekontakte.users.service.UserService;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping(HomeCotroller.URL)
|
@RequestMapping(HomeCotroller.URL)
|
||||||
public class HomeCotroller {
|
public class HomeCotroller {
|
||||||
public static final String URL = "/";
|
public static final String URL = "/";
|
||||||
private static final String PAGE_ATTRIBUTE = "page";
|
private static final String PAGE_ATTRIBUTE = "page";
|
||||||
|
private static final String POSTS_ATTRIBUTE = "posts";
|
||||||
private static final String FEED_VIEW = "feed";
|
private static final String FEED_VIEW = "feed";
|
||||||
private static final String SUBS_VIEW = "subs";
|
private static final String SUBS_VIEW = "subs";
|
||||||
private static final String USER_PROFILE_VIEW = "user-profile";
|
private static final String USER_PROFILE_VIEW = "user-profile";
|
||||||
|
|
||||||
private final PostService postsService;
|
private final PostService postsService;
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
public HomeCotroller(PostService postsService) {
|
public HomeCotroller(PostService postsService, UserService userService) {
|
||||||
this.postsService = postsService;
|
this.postsService = postsService;
|
||||||
|
this.userService = userService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/feed")
|
@GetMapping("/feed")
|
||||||
public String getFeed(Model model) {
|
public String getFeed(@RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page, Model model) {
|
||||||
|
List<PostEntity> posts = postsService.getAll();
|
||||||
|
List<PostDTO> postDTOs = new ArrayList<PostDTO>();
|
||||||
|
for (PostEntity postEntity : posts) {
|
||||||
|
PostDTO postDTO = PostDTO.createFromEntity(postEntity);
|
||||||
|
postDTOs.add(postDTO);
|
||||||
|
}
|
||||||
|
model.addAttribute(PAGE_ATTRIBUTE, page);
|
||||||
|
model.addAttribute(POSTS_ATTRIBUTE, postDTOs);
|
||||||
return FEED_VIEW;
|
return FEED_VIEW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@ package com.example.nekontakte.posts.api;
|
|||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import com.example.nekontakte.posts.model.PostEntity;
|
||||||
|
import com.example.nekontakte.users.api.UserDTO;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
@ -14,6 +16,17 @@ public class PostDTO {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private Integer userId;
|
private Integer userId;
|
||||||
|
|
||||||
|
private UserDTO userDTO;
|
||||||
|
|
||||||
|
public UserDTO getUserDTO() {
|
||||||
|
return userDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserDTO(UserDTO userDTO) {
|
||||||
|
this.userDTO = userDTO;
|
||||||
|
this.userId = userDTO.getId();
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private Date pubDate;
|
private Date pubDate;
|
||||||
|
|
||||||
@ -61,4 +74,14 @@ public class PostDTO {
|
|||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PostDTO createFromEntity(PostEntity entity) {
|
||||||
|
PostDTO post = new PostDTO();
|
||||||
|
post.setId(entity.getId());
|
||||||
|
post.setUserId(entity.getUser().getId());
|
||||||
|
post.setHtml(entity.getHtml());
|
||||||
|
post.setImage(entity.getImage());
|
||||||
|
post.setPubDate(entity.getPubDate());
|
||||||
|
post.setUserDTO(UserDTO.createFromEntity(entity.getUser()));
|
||||||
|
return post;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ public class AdminUserController {
|
|||||||
@GetMapping("/create")
|
@GetMapping("/create")
|
||||||
public String getCreateView(Model model) {
|
public String getCreateView(Model model) {
|
||||||
model.addAttribute(USER_ATTRIBUTE, new UserEditDTO());
|
model.addAttribute(USER_ATTRIBUTE, new UserEditDTO());
|
||||||
|
model.addAttribute("title", "Новый пользователь");
|
||||||
return USER_EDIT_VIEW;
|
return USER_EDIT_VIEW;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,6 +68,8 @@ public class AdminUserController {
|
|||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model.addAttribute("title", "Редактировать пользователя");
|
||||||
|
|
||||||
UserEntity userEntity = userService.get(id);
|
UserEntity userEntity = userService.get(id);
|
||||||
UserEditDTO userEditDTO = new UserEditDTO();
|
UserEditDTO userEditDTO = new UserEditDTO();
|
||||||
userEditDTO.setId(userEntity.getId());
|
userEditDTO.setId(userEntity.getId());
|
||||||
@ -91,6 +94,8 @@ public class AdminUserController {
|
|||||||
Model model,
|
Model model,
|
||||||
RedirectAttributes redirectAttributes) {
|
RedirectAttributes redirectAttributes) {
|
||||||
|
|
||||||
|
model.addAttribute("title", "Редактировать пользователя");
|
||||||
|
|
||||||
UserEntity userEntity;
|
UserEntity userEntity;
|
||||||
|
|
||||||
if (userEditDTO.getId() == null) {
|
if (userEditDTO.getId() == null) {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package com.example.nekontakte.users.api;
|
package com.example.nekontakte.users.api;
|
||||||
|
|
||||||
import java.sql.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import com.example.nekontakte.users.model.UserEntity;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
@ -36,6 +37,19 @@ public class UserDTO {
|
|||||||
|
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
|
public static UserDTO createFromEntity(UserEntity userEntity) {
|
||||||
|
UserDTO dto = new UserDTO();
|
||||||
|
dto.setUsername(userEntity.getUsername());
|
||||||
|
dto.setPassword(userEntity.getPassword());
|
||||||
|
dto.setName(userEntity.getName());
|
||||||
|
dto.setSurname(userEntity.getSurname());
|
||||||
|
dto.setCity(userEntity.getCity());
|
||||||
|
dto.setBirthday(userEntity.getBirthday());
|
||||||
|
dto.setAvatarImg(userEntity.getAvatarImg());
|
||||||
|
dto.setStatus(userEntity.getStatus());
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||||
public Integer getId() {
|
public Integer getId() {
|
||||||
return id;
|
return id;
|
||||||
|
@ -18,7 +18,7 @@ h3 {
|
|||||||
td form {
|
td form {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-top: -.25em;
|
margin-top: -0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-fixed-width {
|
.button-fixed-width {
|
||||||
@ -56,12 +56,6 @@ td form {
|
|||||||
color: rgba(255, 255, 255, 0.5);
|
color: rgba(255, 255, 255, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cart-image {
|
textarea {
|
||||||
width: 3.1rem;
|
min-height: 1.5em;
|
||||||
padding: 0.25rem;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cart-item {
|
|
||||||
height: auto;
|
|
||||||
}
|
}
|
@ -1,18 +1,41 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="ru" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{index}">
|
<html
|
||||||
|
lang="ru"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
layout:decorate="~{index}"
|
||||||
|
>
|
||||||
<head>
|
<head>
|
||||||
<title>Редакторовать пользователя</title>
|
<title>[[${title}]]</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<main layout:fragment="content">
|
<main layout:fragment="content">
|
||||||
<form action="#" th:action="@{/admin/users/edit(page=${page})}" th:object="${user}" method="post">
|
<form
|
||||||
<input type="hidden" th:field="*{id}" id="id" class="form-control" readonly>
|
action="#"
|
||||||
|
th:action="@{/admin/users/edit(page=${page})}"
|
||||||
|
th:object="${user}"
|
||||||
|
method="post"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
th:field="*{id}"
|
||||||
|
id="id"
|
||||||
|
class="form-control"
|
||||||
|
readonly
|
||||||
|
/>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="username" class="form-label">Логин*</label>
|
<label for="username" class="form-label">Логин*</label>
|
||||||
<input type="text" th:field="*{username}" id="username" class="form-control">
|
<input
|
||||||
<div th:if="${#fields.hasErrors('username')}" th:errors="*{username}" class="invalid-feedback"></div>
|
type="text"
|
||||||
|
th:field="*{username}"
|
||||||
|
id="username"
|
||||||
|
class="form-control"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
th:if="${#fields.hasErrors('username')}"
|
||||||
|
th:errors="*{username}"
|
||||||
|
class="invalid-feedback"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="userRole" class="form-label">Роль в системе*</label>
|
<label for="userRole" class="form-label">Роль в системе*</label>
|
||||||
@ -20,44 +43,90 @@
|
|||||||
<option
|
<option
|
||||||
th:each="userRoleOpt : ${T(com.example.nekontakte.users.model.UserRole).values()}"
|
th:each="userRoleOpt : ${T(com.example.nekontakte.users.model.UserRole).values()}"
|
||||||
th:value="${userRoleOpt}"
|
th:value="${userRoleOpt}"
|
||||||
th:text="${userRoleOpt.displayName}">
|
th:text="${userRoleOpt.displayName}"
|
||||||
</option>
|
></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="password" class="form-label">Пароль</label>
|
<label for="password" class="form-label">Пароль</label>
|
||||||
<input type="password" th:field="*{password}" id="password" class="form-control">
|
<input
|
||||||
<div th:if="${#fields.hasErrors('password')}" th:errors="*{password}" class="invalid-feedback"></div>
|
type="password"
|
||||||
|
th:field="*{password}"
|
||||||
|
id="password"
|
||||||
|
class="form-control"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
th:if="${#fields.hasErrors('password')}"
|
||||||
|
th:errors="*{password}"
|
||||||
|
class="invalid-feedback"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="passwordConfirm" class="form-label">Пароль (подтверждение)</label>
|
<label for="passwordConfirm" class="form-label"
|
||||||
<input type="password" th:field="*{passwordConfirm}" id="passwordConfirm" class="form-control">
|
>Пароль (подтверждение)</label
|
||||||
<div th:if="${#fields.hasErrors('passwordConfirm')}" th:errors="*{passwordConfirm}" class="invalid-feedback"></div>
|
>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
th:field="*{passwordConfirm}"
|
||||||
|
id="passwordConfirm"
|
||||||
|
class="form-control"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
th:if="${#fields.hasErrors('passwordConfirm')}"
|
||||||
|
th:errors="*{passwordConfirm}"
|
||||||
|
class="invalid-feedback"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="name" class="form-label">Имя</label>
|
<label for="name" class="form-label">Имя</label>
|
||||||
<input type="text" th:field="*{name}" id="name" class="form-control">
|
<input
|
||||||
|
type="text"
|
||||||
|
th:field="*{name}"
|
||||||
|
id="name"
|
||||||
|
class="form-control"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="surname" class="form-label">Имя пользователя</label>
|
<label for="surname" class="form-label">Фамилия</label>
|
||||||
<input type="text" th:field="*{surname}" id="surname" class="form-control">
|
<input
|
||||||
|
type="text"
|
||||||
|
th:field="*{surname}"
|
||||||
|
id="surname"
|
||||||
|
class="form-control"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="birthday" class="form-label">Дата рождения</label>
|
<label for="birthday" class="form-label">Дата рождения</label>
|
||||||
<input type="date" th:field="*{birthday}" id="birthday" class="form-control">
|
<input
|
||||||
|
type="date"
|
||||||
|
th:field="*{birthday}"
|
||||||
|
id="birthday"
|
||||||
|
class="form-control"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="city" class="form-label">Место проживания</label>
|
<label for="city" class="form-label">Место проживания</label>
|
||||||
<input type="text" th:field="*{city}" id="city" class="form-control">
|
<input
|
||||||
|
type="text"
|
||||||
|
th:field="*{city}"
|
||||||
|
id="city"
|
||||||
|
class="form-control"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="status" class="form-label">Статус</label>
|
<label for="status" class="form-label">Статус</label>
|
||||||
<input type="text" th:field="*{status}" id="status" class="form-control">
|
<input
|
||||||
|
type="text"
|
||||||
|
th:field="*{status}"
|
||||||
|
id="status"
|
||||||
|
class="form-control"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-success me-3" type="submit">Применить</button>
|
<button class="btn btn-success me-3" type="submit">Применить</button>
|
||||||
<a th:href="@{/admin/users(page=${page})}" class="btn btn-danger" >Отмена</a>
|
<a th:href="@{/admin/users(page=${page})}" class="btn btn-danger"
|
||||||
|
>Отмена</a
|
||||||
|
>
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -12,7 +12,7 @@
|
|||||||
<th:block th:case="*">
|
<th:block th:case="*">
|
||||||
<h2>Пользователи</h2>
|
<h2>Пользователи</h2>
|
||||||
<div>
|
<div>
|
||||||
<a th:href="@{/admin/users/create}" class="btn btn-primary">Добавить пользователя</a>
|
<a th:href="@{/admin/users/create}" class="btn btn-primary">Создать пользователя</a>
|
||||||
</div>
|
</div>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<caption></caption>
|
<caption></caption>
|
||||||
|
@ -1,13 +1,50 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="ru" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{index}">
|
<html
|
||||||
|
lang="ru"
|
||||||
|
xmlns:th="http://www.thymeleaf.org"
|
||||||
|
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity6"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
layout:decorate="~{index}"
|
||||||
|
>
|
||||||
<head>
|
<head>
|
||||||
<title>Ноаости</title>
|
<title>Ноаости</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<main layout:fragment="content">
|
<main layout:fragment="content">
|
||||||
|
<div class="container d-flex flex-column w-50 flex-fill">
|
||||||
|
<form
|
||||||
|
sec:authorize="isAuthenticated()"
|
||||||
|
method="post"
|
||||||
|
th:action="@{/posts/create/{username}(username=${#authentication.name})}"
|
||||||
|
class="d-flex flex-column mb-3 mt-2"
|
||||||
|
>
|
||||||
|
<textarea
|
||||||
|
name="postBody"
|
||||||
|
class="mb-3"
|
||||||
|
placeholder="Напишите что-нибудь..."
|
||||||
|
></textarea>
|
||||||
|
<button type="submit" class="btn btn-primary">Опубликовать</button>
|
||||||
|
</form>
|
||||||
|
<th:block th:switch="${posts.size()}">
|
||||||
|
<th:block th:case="0">
|
||||||
|
<div class="h-100 d-flex align-items-center justify-content-center">
|
||||||
|
Здесь пока нет постов
|
||||||
|
</div>
|
||||||
|
</th:block>
|
||||||
|
<th:block th:case="*">
|
||||||
|
<th:block th:each="post : ${posts}">
|
||||||
|
<div th:replace="~{ posts :: post (post=${post})}"></div>
|
||||||
|
</th:block>
|
||||||
|
</th:block>
|
||||||
|
<th:block
|
||||||
|
th:replace="~{ pagination :: pagination (
|
||||||
|
url=${'admin/users'},
|
||||||
|
totalPages=${totalPages},
|
||||||
|
currentPage=${currentPage}) }"
|
||||||
|
/>
|
||||||
|
</th:block>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,59 +1,110 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="ru" data-bs-theme="dark" xmlns:th="http://www.thymeleaf.org"
|
<html
|
||||||
|
lang="ru"
|
||||||
|
data-bs-theme="dark"
|
||||||
|
xmlns:th="http://www.thymeleaf.org"
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity6">
|
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity6"
|
||||||
|
>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/img/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/img/favicon.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Неконтакте</title>
|
<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">
|
||||||
<script type="text/javascript" src="/webjars/bootstrap/5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
Неконтакте
|
||||||
<link rel="stylesheet" href="/webjars/bootstrap/5.3.3/dist/css/bootstrap.min.css" />
|
</title>
|
||||||
<link rel="stylesheet" href="/webjars/bootstrap-icons/1.11.3/font/bootstrap-icons.min.css" />
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="/webjars/bootstrap/5.3.3/dist/js/bootstrap.bundle.min.js"
|
||||||
|
></script>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="/webjars/bootstrap/5.3.3/dist/css/bootstrap.min.css"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="/webjars/bootstrap-icons/1.11.3/font/bootstrap-icons.min.css"
|
||||||
|
/>
|
||||||
<link rel="stylesheet" href="/css/style.css" />
|
<link rel="stylesheet" href="/css/style.css" />
|
||||||
<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate">
|
<meta
|
||||||
<meta http-equiv="Pragma" content="no-cache">
|
http-equiv="Cache-Control"
|
||||||
<meta http-equiv="Expires" content="0">
|
content="no-store, no-cache, must-revalidate"
|
||||||
|
/>
|
||||||
|
<meta http-equiv="Pragma" content="no-cache" />
|
||||||
|
<meta http-equiv="Expires" content="0" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="h-100 d-flex flex-column">
|
<body class="h-100 d-flex flex-column">
|
||||||
<nav class="navbar navbar-expand-md my-navbar" data-bs-theme="dark">
|
<nav class="navbar navbar-expand-md my-navbar" data-bs-theme="dark">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||||
<img src="/img/favicon.svg" class="d-inline-block align-top me-4 logo" />
|
<img
|
||||||
|
src="/img/favicon.svg"
|
||||||
|
class="d-inline-block align-top me-4 logo"
|
||||||
|
/>
|
||||||
Неконтакте
|
Неконтакте
|
||||||
</a>
|
</a>
|
||||||
<th:block sec:authorize="isAuthenticated()" th:with="userName=${#authentication.name}">
|
<th:block
|
||||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#main-navbar"
|
sec:authorize="isAuthenticated()"
|
||||||
aria-controls="main-navbar" aria-expanded="false" aria-label="Toggle navigation">
|
th:with="userName=${#authentication.name}"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="navbar-toggler"
|
||||||
|
type="button"
|
||||||
|
data-bs-toggle="collapse"
|
||||||
|
data-bs-target="#main-navbar"
|
||||||
|
aria-controls="main-navbar"
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-label="Toggle navigation"
|
||||||
|
>
|
||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
</button>
|
</button>
|
||||||
<div class="collapse navbar-collapse" id="main-navbar">
|
<div class="collapse navbar-collapse" id="main-navbar">
|
||||||
<ul class="navbar-nav me-auto link" th:with="activeLink=${#objects.nullSafe(servletPath, '')}">
|
<ul
|
||||||
<th:block sec:authorize="hasRole('ADMIN')">
|
class="navbar-nav me-auto link"
|
||||||
<a class="nav-link" href="/admin/users" th:classappend="${activeLink.startsWith('/admin/users') ? 'active' : ''}">
|
th:with="activeLink=${#objects.nullSafe(servletPath, '')}"
|
||||||
Пользователи
|
>
|
||||||
</a>
|
<a
|
||||||
<a class="nav-link" href="/h2-console/" target="_blank">Консоль H2</a>
|
class="nav-link"
|
||||||
</th:block>
|
href="/feed"
|
||||||
<th:block sec:authorize="hasRole('USER')">
|
th:classappend="${activeLink.startsWith('/feed') ? 'active' : ''}"
|
||||||
<a class="nav-link" href="/feed" th:classappend="${activeLink.startsWith('/feed') ? 'active' : ''}">
|
>
|
||||||
Новости
|
Новости
|
||||||
</a>
|
</a>
|
||||||
<a class="nav-link" href="/subs" th:classappend="${activeLink.startsWith('/subs') ? 'active' : ''}">
|
<a
|
||||||
|
class="nav-link"
|
||||||
|
href="/subs"
|
||||||
|
th:classappend="${activeLink.startsWith('/subs') ? 'active' : ''}"
|
||||||
|
>
|
||||||
Подписки
|
Подписки
|
||||||
</a>
|
</a>
|
||||||
<a class="nav-link"
|
<a
|
||||||
|
class="nav-link"
|
||||||
th:href="@{/me}"
|
th:href="@{/me}"
|
||||||
th:classappend="${activeLink.startsWith('/me') ? 'active' : ''}">
|
th:classappend="${activeLink.startsWith('/me') ? 'active' : ''}"
|
||||||
|
>
|
||||||
Профиль
|
Профиль
|
||||||
</a>
|
</a>
|
||||||
|
<th:block sec:authorize="hasRole('ADMIN')">
|
||||||
|
<a
|
||||||
|
class="nav-link"
|
||||||
|
href="/admin/users"
|
||||||
|
th:classappend="${activeLink.startsWith('/admin/users') ? 'active' : ''}"
|
||||||
|
>
|
||||||
|
Пользователи
|
||||||
|
</a>
|
||||||
|
<a class="nav-link" href="/h2-console/" target="_blank"
|
||||||
|
>Консоль H2</a
|
||||||
|
>
|
||||||
</th:block>
|
</th:block>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="navbar-nav" th:if="${not #strings.isEmpty(userName)}">
|
<ul class="navbar-nav" th:if="${not #strings.isEmpty(userName)}">
|
||||||
<form th:action="@{/logout}" method="post">
|
<form th:action="@{/logout}" method="post">
|
||||||
<button type="submit" class="navbar-brand nav-link" onclick="return confirm('Вы уверены?')">
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="navbar-brand nav-link"
|
||||||
|
onclick="return confirm('Вы уверены?')"
|
||||||
|
>
|
||||||
Выход ([[${userName}]])
|
Выход ([[${userName}]])
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
@ -62,11 +113,14 @@
|
|||||||
</th:block>
|
</th:block>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<main class="container w-50 p-2 d-flex flex-column flex-fill" layout:fragment="content">
|
<main
|
||||||
</main>
|
class="container w-50 p-2 d-flex flex-column flex-fill"
|
||||||
<footer class="my-footer mt-auto d-flex flex-shrink-0 justify-content-center align-items-center">
|
layout:fragment="content"
|
||||||
|
></main>
|
||||||
|
<footer
|
||||||
|
class="my-footer mt-auto d-flex flex-shrink-0 justify-content-center align-items-center"
|
||||||
|
>
|
||||||
Потапов Н.С. ПИбд-21, [[${#dates.year(#dates.createNow())}]]
|
Потапов Н.С. ПИбд-21, [[${#dates.year(#dates.createNow())}]]
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
48
nekontakte/src/main/resources/templates/posts.html
Normal file
48
nekontakte/src/main/resources/templates/posts.html
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<body>
|
||||||
|
<div th:fragment="post (post)" class="post mb-2 mb-sm-4 w-100 d-flex flex-column border rounded-2" id="post-${post.id}">
|
||||||
|
<div class="post-header py-1 ps-1 pe-2 d-flex border-bottom justify-content-between align-items-center">
|
||||||
|
<Link to="@{/user/${post.user.username}}"
|
||||||
|
class="hoverable d-flex justify-content-start align-items-center rounded-pill px-1">
|
||||||
|
<div class="post-author-avatar-wrapper">
|
||||||
|
<img src="#" class="post-author-avatar avatar-small rounded-circle" />
|
||||||
|
</div>
|
||||||
|
<div class="post-meta mx-2 d-flex flex-column justify-content-center">
|
||||||
|
<div class="post-author-name">
|
||||||
|
[[${post.user.name}]] [[${post.user.surname}]]
|
||||||
|
</div>
|
||||||
|
<div class="post-publication-datetime">
|
||||||
|
[[${post.pubDate}]]
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
<div class='d-flex'>
|
||||||
|
<i class='fs-6 bi bi-pencil' title='Редактировать пост'></i>
|
||||||
|
<i class='fs-6 bi bi-trash' title='Удалить пост'></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="post-body">
|
||||||
|
<div th:if="${post.html != null}" class="post-body-text m-2">
|
||||||
|
[[${post.html}]]
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<img th:if="${post.image != null}" src="${post.image}" class="post-body-img img-fluid" />
|
||||||
|
</div>
|
||||||
|
<div class="post-footer py-1 px-2 border-top d-flex">
|
||||||
|
<div class="hoverable counter-block likes-block px-2 me-1 d-flex align-items-center rounded-4">
|
||||||
|
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g fill="none" fillRule="evenodd">
|
||||||
|
<path d="M0 0h24v24H0z"></path>
|
||||||
|
<path
|
||||||
|
d="M16 4a5.95 5.95 0 0 0-3.89 1.7l-.12.11-.12-.11A5.96 5.96 0 0 0 7.73 4 5.73 5.73 0 0 0 2 9.72c0 3.08 1.13 4.55 6.18 8.54l2.69 2.1c.66.52 1.6.52 2.26 0l2.36-1.84.94-.74c4.53-3.64 5.57-5.1 5.57-8.06A5.73 5.73 0 0 0 16.27 4zm.27 1.8a3.93 3.93 0 0 1 3.93 3.92v.3c-.08 2.15-1.07 3.33-5.51 6.84l-2.67 2.08a.04.04 0 0 1-.04 0L9.6 17.1l-.87-.7C4.6 13.1 3.8 11.98 3.8 9.73A3.93 3.93 0 0 1 7.73 5.8c1.34 0 2.51.62 3.57 1.92a.9.9 0 0 0 1.4-.01c1.04-1.3 2.2-1.91 3.57-1.91z"
|
||||||
|
fill="currentColor" fillRule="nonzero"></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<span class="count ms-1">734</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user