Compare commits
2 Commits
1aba31e5ab
...
8162b23dd2
Author | SHA1 | Date | |
---|---|---|---|
8162b23dd2 | |||
7b13fb6f8b |
@ -1,7 +1,6 @@
|
||||
package com.example.nekontakte.core.api;
|
||||
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
@ -1,33 +1,50 @@
|
||||
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.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import com.example.nekontakte.posts.service.PostService;
|
||||
|
||||
import jakarta.websocket.server.PathParam;
|
||||
import com.example.nekontakte.users.api.UserDTO;
|
||||
import com.example.nekontakte.users.api.UserEditDTO;
|
||||
import com.example.nekontakte.users.service.UserService;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(HomeCotroller.URL)
|
||||
public class HomeCotroller {
|
||||
public static final String URL = "/";
|
||||
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 SUBS_VIEW = "subs";
|
||||
private static final String USER_PROFILE_VIEW = "user-profile";
|
||||
|
||||
private final PostService postsService;
|
||||
private final UserService userService;
|
||||
|
||||
public HomeCotroller(PostService postsService) {
|
||||
public HomeCotroller(PostService postsService, UserService userService) {
|
||||
this.postsService = postsService;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,8 @@ package com.example.nekontakte.posts.api;
|
||||
|
||||
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 jakarta.validation.constraints.NotNull;
|
||||
@ -14,6 +16,17 @@ public class PostDTO {
|
||||
@NotNull
|
||||
private Integer userId;
|
||||
|
||||
private UserDTO userDTO;
|
||||
|
||||
public UserDTO getUserDTO() {
|
||||
return userDTO;
|
||||
}
|
||||
|
||||
public void setUserDTO(UserDTO userDTO) {
|
||||
this.userDTO = userDTO;
|
||||
this.userId = userDTO.getId();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Date pubDate;
|
||||
|
||||
@ -61,4 +74,14 @@ public class PostDTO {
|
||||
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")
|
||||
public String getCreateView(Model model) {
|
||||
model.addAttribute(USER_ATTRIBUTE, new UserEditDTO());
|
||||
model.addAttribute("title", "Новый пользователь");
|
||||
return USER_EDIT_VIEW;
|
||||
}
|
||||
|
||||
@ -67,6 +68,8 @@ public class AdminUserController {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
model.addAttribute("title", "Редактировать пользователя");
|
||||
|
||||
UserEntity userEntity = userService.get(id);
|
||||
UserEditDTO userEditDTO = new UserEditDTO();
|
||||
userEditDTO.setId(userEntity.getId());
|
||||
@ -91,6 +94,8 @@ public class AdminUserController {
|
||||
Model model,
|
||||
RedirectAttributes redirectAttributes) {
|
||||
|
||||
model.addAttribute("title", "Редактировать пользователя");
|
||||
|
||||
UserEntity userEntity;
|
||||
|
||||
if (userEditDTO.getId() == null) {
|
||||
|
@ -1,7 +1,8 @@
|
||||
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 jakarta.validation.constraints.NotBlank;
|
||||
@ -36,6 +37,19 @@ public class UserDTO {
|
||||
|
||||
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)
|
||||
public Integer getId() {
|
||||
return id;
|
||||
|
@ -1,67 +1,61 @@
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.5em;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.25em;
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1em;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
td form {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-top: -.25em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-top: -0.25em;
|
||||
}
|
||||
|
||||
.button-fixed-width {
|
||||
width: 150px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.button-link {
|
||||
padding: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.invalid-feedback {
|
||||
display: block;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.w-10 {
|
||||
width: 10% !important;
|
||||
width: 10% !important;
|
||||
}
|
||||
|
||||
.my-navbar {
|
||||
background-color: #3c3c3c !important;
|
||||
background-color: #3c3c3c !important;
|
||||
}
|
||||
|
||||
.my-navbar .link a:hover {
|
||||
text-decoration: underline;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.my-navbar .logo {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
.my-footer {
|
||||
background-color: #2c2c2c;
|
||||
height: 32px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
background-color: #2c2c2c;
|
||||
height: 32px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.cart-image {
|
||||
width: 3.1rem;
|
||||
padding: 0.25rem;
|
||||
border-radius: 0.5rem;
|
||||
textarea {
|
||||
min-height: 1.5em;
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
height: auto;
|
||||
}
|
@ -1,63 +1,132 @@
|
||||
<!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>
|
||||
<title>[[${title}]]</title>
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<title>Редакторовать пользователя</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main layout:fragment="content">
|
||||
<form 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">
|
||||
<label for="username" class="form-label">Логин*</label>
|
||||
<input 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 class="mb-3">
|
||||
<label for="userRole" class="form-label">Роль в системе*</label>
|
||||
<select th:field="*{role}" id="userRole" class="form-control">
|
||||
<option
|
||||
th:each="userRoleOpt : ${T(com.example.nekontakte.users.model.UserRole).values()}"
|
||||
th:value="${userRoleOpt}"
|
||||
th:text="${userRoleOpt.displayName}">
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Пароль</label>
|
||||
<input 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 class="mb-3">
|
||||
<label for="passwordConfirm" class="form-label">Пароль (подтверждение)</label>
|
||||
<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 class="mb-3">
|
||||
<label for="name" class="form-label">Имя</label>
|
||||
<input type="text" th:field="*{name}" id="name" class="form-control">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="surname" class="form-label">Имя пользователя</label>
|
||||
<input type="text" th:field="*{surname}" id="surname" class="form-control">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="birthday" class="form-label">Дата рождения</label>
|
||||
<input type="date" th:field="*{birthday}" id="birthday" class="form-control">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="city" class="form-label">Место проживания</label>
|
||||
<input type="text" th:field="*{city}" id="city" class="form-control">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="status" class="form-label">Статус</label>
|
||||
<input type="text" th:field="*{status}" id="status" class="form-control">
|
||||
</div>
|
||||
<button class="btn btn-success me-3" type="submit">Применить</button>
|
||||
<a th:href="@{/admin/users(page=${page})}" class="btn btn-danger" >Отмена</a>
|
||||
</form>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<body>
|
||||
<main layout:fragment="content">
|
||||
<form
|
||||
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">
|
||||
<label for="username" class="form-label">Логин*</label>
|
||||
<input
|
||||
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 class="mb-3">
|
||||
<label for="userRole" class="form-label">Роль в системе*</label>
|
||||
<select th:field="*{role}" id="userRole" class="form-control">
|
||||
<option
|
||||
th:each="userRoleOpt : ${T(com.example.nekontakte.users.model.UserRole).values()}"
|
||||
th:value="${userRoleOpt}"
|
||||
th:text="${userRoleOpt.displayName}"
|
||||
></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Пароль</label>
|
||||
<input
|
||||
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 class="mb-3">
|
||||
<label for="passwordConfirm" class="form-label"
|
||||
>Пароль (подтверждение)</label
|
||||
>
|
||||
<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 class="mb-3">
|
||||
<label for="name" class="form-label">Имя</label>
|
||||
<input
|
||||
type="text"
|
||||
th:field="*{name}"
|
||||
id="name"
|
||||
class="form-control"
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="surname" class="form-label">Фамилия</label>
|
||||
<input
|
||||
type="text"
|
||||
th:field="*{surname}"
|
||||
id="surname"
|
||||
class="form-control"
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="birthday" class="form-label">Дата рождения</label>
|
||||
<input
|
||||
type="date"
|
||||
th:field="*{birthday}"
|
||||
id="birthday"
|
||||
class="form-control"
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="city" class="form-label">Место проживания</label>
|
||||
<input
|
||||
type="text"
|
||||
th:field="*{city}"
|
||||
id="city"
|
||||
class="form-control"
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="status" class="form-label">Статус</label>
|
||||
<input
|
||||
type="text"
|
||||
th:field="*{status}"
|
||||
id="status"
|
||||
class="form-control"
|
||||
/>
|
||||
</div>
|
||||
<button class="btn btn-success me-3" type="submit">Применить</button>
|
||||
<a th:href="@{/admin/users(page=${page})}" class="btn btn-danger"
|
||||
>Отмена</a
|
||||
>
|
||||
</form>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -12,7 +12,7 @@
|
||||
<th:block th:case="*">
|
||||
<h2>Пользователи</h2>
|
||||
<div>
|
||||
<a th:href="@{/admin/users/create}" class="btn btn-primary">Добавить пользователя</a>
|
||||
<a th:href="@{/admin/users/create}" class="btn btn-primary">Создать пользователя</a>
|
||||
</div>
|
||||
<table class="table">
|
||||
<caption></caption>
|
||||
|
@ -1,13 +1,50 @@
|
||||
<!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>
|
||||
<title>Ноаости</title>
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<title>Ноаости</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main layout:fragment="content">
|
||||
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
<body>
|
||||
<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>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,72 +1,126 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru" data-bs-theme="dark" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity6">
|
||||
<html
|
||||
lang="ru"
|
||||
data-bs-theme="dark"
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity6"
|
||||
>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/img/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">
|
||||
Неконтакте
|
||||
</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"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="/webjars/bootstrap-icons/1.11.3/font/bootstrap-icons.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="/css/style.css" />
|
||||
<meta
|
||||
http-equiv="Cache-Control"
|
||||
content="no-store, no-cache, must-revalidate"
|
||||
/>
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/img/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Неконтакте</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" />
|
||||
<link rel="stylesheet" href="/webjars/bootstrap-icons/1.11.3/font/bootstrap-icons.min.css" />
|
||||
<link rel="stylesheet" href="/css/style.css" />
|
||||
<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate">
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
<meta http-equiv="Expires" content="0">
|
||||
</head>
|
||||
|
||||
<body class="h-100 d-flex flex-column">
|
||||
<nav class="navbar navbar-expand-md my-navbar" data-bs-theme="dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img src="/img/favicon.svg" class="d-inline-block align-top me-4 logo" />
|
||||
Неконтакте
|
||||
</a>
|
||||
<th:block sec:authorize="isAuthenticated()" 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>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="main-navbar">
|
||||
<ul class="navbar-nav me-auto link" th:with="activeLink=${#objects.nullSafe(servletPath, '')}">
|
||||
<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 sec:authorize="hasRole('USER')">
|
||||
<a class="nav-link" href="/feed" th:classappend="${activeLink.startsWith('/feed') ? 'active' : ''}">
|
||||
Новости
|
||||
</a>
|
||||
<a class="nav-link" href="/subs" th:classappend="${activeLink.startsWith('/subs') ? 'active' : ''}">
|
||||
Подписки
|
||||
</a>
|
||||
<a class="nav-link"
|
||||
th:href="@{/me}"
|
||||
th:classappend="${activeLink.startsWith('/me') ? 'active' : ''}">
|
||||
Профиль
|
||||
</a>
|
||||
</th:block>
|
||||
</ul>
|
||||
<ul class="navbar-nav" th:if="${not #strings.isEmpty(userName)}">
|
||||
<form th:action="@{/logout}" method="post">
|
||||
<button type="submit" class="navbar-brand nav-link" onclick="return confirm('Вы уверены?')">
|
||||
Выход ([[${userName}]])
|
||||
</button>
|
||||
</form>
|
||||
</ul>
|
||||
</div>
|
||||
</th:block>
|
||||
</div>
|
||||
</nav>
|
||||
<main class="container w-50 p-2 d-flex flex-column flex-fill" 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())}]]
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<body class="h-100 d-flex flex-column">
|
||||
<nav class="navbar navbar-expand-md my-navbar" data-bs-theme="dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img
|
||||
src="/img/favicon.svg"
|
||||
class="d-inline-block align-top me-4 logo"
|
||||
/>
|
||||
Неконтакте
|
||||
</a>
|
||||
<th:block
|
||||
sec:authorize="isAuthenticated()"
|
||||
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>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="main-navbar">
|
||||
<ul
|
||||
class="navbar-nav me-auto link"
|
||||
th:with="activeLink=${#objects.nullSafe(servletPath, '')}"
|
||||
>
|
||||
<a
|
||||
class="nav-link"
|
||||
href="/feed"
|
||||
th:classappend="${activeLink.startsWith('/feed') ? 'active' : ''}"
|
||||
>
|
||||
Новости
|
||||
</a>
|
||||
<a
|
||||
class="nav-link"
|
||||
href="/subs"
|
||||
th:classappend="${activeLink.startsWith('/subs') ? 'active' : ''}"
|
||||
>
|
||||
Подписки
|
||||
</a>
|
||||
<a
|
||||
class="nav-link"
|
||||
th:href="@{/me}"
|
||||
th:classappend="${activeLink.startsWith('/me') ? 'active' : ''}"
|
||||
>
|
||||
Профиль
|
||||
</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>
|
||||
</ul>
|
||||
<ul class="navbar-nav" th:if="${not #strings.isEmpty(userName)}">
|
||||
<form th:action="@{/logout}" method="post">
|
||||
<button
|
||||
type="submit"
|
||||
class="navbar-brand nav-link"
|
||||
onclick="return confirm('Вы уверены?')"
|
||||
>
|
||||
Выход ([[${userName}]])
|
||||
</button>
|
||||
</form>
|
||||
</ul>
|
||||
</div>
|
||||
</th:block>
|
||||
</div>
|
||||
</nav>
|
||||
<main
|
||||
class="container w-50 p-2 d-flex flex-column flex-fill"
|
||||
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())}]]
|
||||
</footer>
|
||||
</body>
|
||||
</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