Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ dependencies {
implementation(libs.instancioJunit)
implementation(libs.jsonunitAssertj)
implementation(libs.guava)
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.2")
// implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.2")

// MapStruct
implementation(libs.mapstruct)
Expand Down
1 change: 1 addition & 0 deletions src/main/java/io/hexlet/cv/config/JacksonConfig.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

package io.hexlet.cv.config;

import com.fasterxml.jackson.annotation.JsonInclude;
Expand Down
24 changes: 19 additions & 5 deletions src/main/java/io/hexlet/cv/config/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package io.hexlet.cv.config;

import io.hexlet.cv.service.CustomUserDetailsService;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
Expand All @@ -21,11 +26,6 @@
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
import org.springframework.security.web.SecurityFilterChain;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
Expand All @@ -41,9 +41,23 @@ SecurityFilterChain security(HttpSecurity http,
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**", "/*/admin/**", "/*/admin/").hasRole("ADMIN")
.requestMatchers("/account/purchase").authenticated()
.anyRequest().permitAll()
)
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// обработка ошибок безопасности
.exceptionHandling(ex -> ex
.authenticationEntryPoint((req, res, e) -> { // ADDED: 401 вместо 500
res.setContentType("application/json");
res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
res.getWriter().write("{\"errors\":{\"error\":\"Unauthorized\"}}");
})
.accessDeniedHandler((req, res, e) -> { // ADDED: 403 вместо 500
res.setContentType("application/json");
res.setStatus(HttpServletResponse.SC_FORBIDDEN);
res.getWriter().write("{\"errors\":{\"error\":\"Access Denied\"}}");
})
)
.oauth2ResourceServer(rs -> rs
.bearerTokenResolver(cookieTokenResolver)
.jwt(jwt -> jwt
Expand Down
5 changes: 2 additions & 3 deletions src/main/java/io/hexlet/cv/controller/MainPageController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import io.github.inertia4j.spring.Inertia;
import io.hexlet.cv.service.PageSectionService;
import java.util.Map;
import java.util.Set;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -11,9 +13,6 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.Map;
import java.util.Set;

@Controller
@AllArgsConstructor
@RequestMapping({"/", "/{locale}"})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import io.hexlet.cv.dto.pagesection.PageSectionUpdateDTO;
import io.hexlet.cv.service.PageSectionService;
import jakarta.validation.Valid;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -19,9 +21,6 @@
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

@RestController
@AllArgsConstructor
@RequestMapping("/api/pages/sections")
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/io/hexlet/cv/controller/UserPageController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import io.github.inertia4j.spring.Inertia;
import io.hexlet.cv.handler.exception.UserNotFoundException;
import io.hexlet.cv.service.FlashPropsService;
import io.hexlet.cv.service.UserPageSercive;
import io.hexlet.cv.service.UserPageService;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Locale;
import java.util.Map;
Expand All @@ -21,7 +21,7 @@ public class UserPageController {

private final Inertia inertia;
private final FlashPropsService flashPropsService;
private final UserPageSercive userPageService;
private final UserPageService userPageService;

private final MessageSource messageSource;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
package io.hexlet.cv.controller.account;



@Controller
@RequiredArgsConstructor
@RequestMapping("/account")
public class AccountWebinarsController {

private final Inertia inertia;
private final AccountWebinarService service;
private final UserUtils userUtils;

@PreAuthorize("isAuthenticated()")
@GetMapping("/webinars")
public Object index(@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
HttpServletRequest request) {

var userId = userUtils.currentUserId(); // id юзера который залогинился

Pageable pageable = PageRequest.of(page, size);
var props = service.indexWebinars(userId.get(), pageable);

var flash = RequestContextUtils.getInputFlashMap(request);
if (flash != null && !flash.isEmpty()) {
props.put("flash", flash);
}


return inertia.render("Account/Webinars/Index", props);
}
}
*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.hexlet.cv.controller.account;

import io.github.inertia4j.spring.Inertia;
import io.hexlet.cv.service.PurchaseAndSubscriptionService;
import io.hexlet.cv.util.UserUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.support.RequestContextUtils;

@Controller
@RequiredArgsConstructor
@RequestMapping("/account")
public class PurchaseAndSubscriptionController {

private final Inertia inertia;
private final PurchaseAndSubscriptionService service;
private final UserUtils userUtils;

@PreAuthorize("isAuthenticated()")
@GetMapping("/purchase")
public Object index(@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
HttpServletRequest request) {

var userId = userUtils.currentUserId(); // id юзера который залогинился

Pageable pageable = PageRequest.of(page, size);
var props = service.indexPurchSubs(userId.get(), pageable);

var flash = RequestContextUtils.getInputFlashMap(request);
if (flash != null && !flash.isEmpty()) {
props.put("flash", flash);
}

return inertia.render("Account/Purchase/Index", props);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

package io.hexlet.cv.controller;
package io.hexlet.cv.controller.admin;

import io.github.inertia4j.spring.Inertia;
import io.hexlet.cv.service.FlashPropsService;
Expand Down Expand Up @@ -36,12 +36,14 @@ public ResponseEntity<?> adminMarketingController(@PathVariable("locale") String
return inertia.render("Admin/Marketing/Index", props);
}

/*
@GetMapping("/webinars")
public ResponseEntity<?> adminWebinarsController(@PathVariable("locale") String locale,
HttpServletRequest request) {
var props = flashPropsService.buildProps(locale, request);
return inertia.render("Admin/Webinars/Index", props);
}
*/

@GetMapping("/knowledgebase")
public ResponseEntity<?> adminKnowledgebaseController(@PathVariable("locale") String locale,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package io.hexlet.cv.controller.admin;

import io.github.inertia4j.spring.Inertia;
import io.hexlet.cv.dto.admin.WebinarDTO;
import io.hexlet.cv.repository.WebinarRepository;
import io.hexlet.cv.service.AdminWebinarService;
import io.hexlet.cv.service.FlashPropsService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.support.RequestContextUtils;


@Controller
@AllArgsConstructor
@RequestMapping("/admin/webinars")
@PreAuthorize("hasRole('ADMIN')")
public class AdminWebinarsController {

private final Inertia inertia;
private final FlashPropsService flashPropsService;
private final WebinarRepository webinarRepository;
private final AdminWebinarService adminWebinarService;

@GetMapping("")
public Object adminWebinarsIndex(@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(name = "search", required = false) String searchStr,
HttpServletRequest request) {

Pageable pageable = PageRequest.of(page, size);
var props = adminWebinarService.indexSearchWebinar(pageable, searchStr);

var flash = RequestContextUtils.getInputFlashMap(request);

if (flash != null && !flash.isEmpty()) {
props.put("flash", flash);
}

return inertia.render("Admin/Webinars/Index", props);
}


@PostMapping("/create")
public Object createWebinar(@RequestBody WebinarDTO webinarDTO,
RedirectAttributes redirectAttributes) {



adminWebinarService.createWebinar(webinarDTO);

redirectAttributes.addFlashAttribute("success", "create.success");
return inertia.redirect("/Admin/Webinars/Index");
}

@PutMapping("/{id}/update")
public Object updateWebinar(@PathVariable Long id,
@RequestBody WebinarDTO webinarDTO,
RedirectAttributes redirectAttributes) {

adminWebinarService.updateWebinar(id, webinarDTO);

redirectAttributes.addFlashAttribute("success", "update.success");
return inertia.redirect("/Admin/Webinars/Index");
}

@DeleteMapping("/{id}/delete")
public Object deleteWebinar(@PathVariable Long id,
RedirectAttributes redirectAttributes) {

adminWebinarService.deleteWebinar(id);
redirectAttributes.addFlashAttribute("success", "delete.success");
return inertia.redirect("/Admin/Webinars/Index");
}
}
19 changes: 19 additions & 0 deletions src/main/java/io/hexlet/cv/converter/PurchSubsTypeConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.hexlet.cv.converter;

import io.hexlet.cv.model.enums.StatePurchSubsType;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;

@Converter(autoApply = true)
public class PurchSubsTypeConverter implements AttributeConverter<StatePurchSubsType, String> {

@Override
public String convertToDatabaseColumn(StatePurchSubsType stateType) {
return stateType == null ? null : stateType.name().toLowerCase();
}

@Override
public StatePurchSubsType convertToEntityAttribute(String dbValue) {
return dbValue == null ? null : StatePurchSubsType.valueOf(dbValue.toUpperCase());
}
}
23 changes: 23 additions & 0 deletions src/main/java/io/hexlet/cv/dto/account/PurchSubsDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.hexlet.cv.dto.account;

import io.hexlet.cv.model.enums.StatePurchSubsType;
import java.math.BigDecimal;
import java.time.LocalDate;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
public class PurchSubsDTO {

private Long id;
private Long userId;
private String orderNum;
private String itemName;
private LocalDate purchasedAt;
private BigDecimal amount;
private StatePurchSubsType state;
private String billUrl;
}
31 changes: 31 additions & 0 deletions src/main/java/io/hexlet/cv/dto/admin/WebinarDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.hexlet.cv.dto.admin;

import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.NotBlank;
import java.time.LocalDateTime;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;


@Getter
@Setter
@NoArgsConstructor
public class WebinarDTO {
private Long id;

@NotBlank
private String webinarName;

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm")
private LocalDateTime webinarDate;


private String webinarRegLink;


private String webinarRecordLink;

private boolean feature;
private boolean publicated;
}
Loading