remake init data

json dump
This commit is contained in:
liosha84
2025-08-14 18:50:16 +03:00
parent 6c5e2d9de1
commit b5e99b0116
82 changed files with 2814 additions and 457 deletions
@@ -0,0 +1,48 @@
package com.jambotronGroup.jambotron.DTOs;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.jambotronGroup.jambotron.model.ERole;
import com.jambotronGroup.jambotron.model.Role;
public class RoleDto {
@JsonIgnore
private Long id;
private ERole name;
public RoleDto() {
}
public RoleDto(Long id, ERole name) {
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public ERole getName() {
return name;
}
public void setName(ERole name) {
this.name = name;
}
// Mapping helpers
public static RoleDto fromEntity(Role role) {
if (role == null) return null;
return new RoleDto(role.getId(), role.getName());
}
public Role toEntity() {
Role role = new Role();
role.setId(this.id);
role.setName(this.name);
return role;
}
}
@@ -0,0 +1,145 @@
package com.jambotronGroup.jambotron.DTOs;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.jambotronGroup.jambotron.model.Tutorial;
import java.sql.Timestamp;
public class TutorialDto {
@JsonIgnore
private Long id;
private String title;
private String description;
private Boolean published;
private boolean tobepublished;
private Long userID;
private java.sql.Timestamp created;
private java.sql.Timestamp modified;
private String titleimage;
private String body;
public TutorialDto() {
}
public TutorialDto(Long id, String title, String description, Boolean published, boolean tobepublished, Long userID, Timestamp created, Timestamp modified, String titleimage, String body) {
this.id = id;
this.title = title;
this.description = description;
this.published = published;
this.tobepublished = tobepublished;
this.userID = userID;
this.created = created;
this.modified = modified;
this.titleimage = titleimage;
this.body = body;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Boolean getPublished() {
return published;
}
public void setPublished(Boolean published) {
this.published = published;
}
public boolean isTobepublished() {
return tobepublished;
}
public void setTobepublished(boolean tobepublished) {
this.tobepublished = tobepublished;
}
public Long getUserID() {
return userID;
}
public void setUserID(Long userID) {
this.userID = userID;
}
public Timestamp getCreated() {
return created;
}
public void setCreated(Timestamp created) {
this.created = created;
}
public Timestamp getModified() {
return modified;
}
public void setModified(Timestamp modified) {
this.modified = modified;
}
public String getTitleimage() {
return titleimage;
}
public void setTitleimage(String titleimage) {
this.titleimage = titleimage;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
// Mapping helpers
public static TutorialDto fromEntity(Tutorial tutorial) {
if (tutorial == null) return null;
return new TutorialDto(
tutorial.getId(),
tutorial.getTitle(),
tutorial.getDescription(),
tutorial.isPublished(),
tutorial.isTobepublished(),
tutorial.getUser().getId(),
tutorial.getCreated(),
tutorial.getModified(),
tutorial.getTitleimage(),
tutorial.getBody()
);
}
public Tutorial toEntity() {
Tutorial tutorial = new Tutorial();
tutorial.setId(this.id);
tutorial.setTitle(this.title);
tutorial.setDescription(this.description);
if (this.published != null) {
tutorial.setPublished(this.published);
}
tutorial.setCreated(this.created);
tutorial.setModified(this.modified);
tutorial.setTobepublished(this.tobepublished);
tutorial.setTitleimage(this.titleimage);
tutorial.setBody(this.body);
return tutorial;
}
}
@@ -0,0 +1,102 @@
package com.jambotronGroup.jambotron.DTOs;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.jambotronGroup.jambotron.model.User;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
public class UserDto {
@JsonIgnore
private Long id;
private String username;
private String email;
private String password; // typically you don't expose password in DTOs
private Set<RoleDto> roles; // typically you don't expose password in DTOs
public UserDto() {
}
public UserDto(Long id, String username, String email, String password, Set<RoleDto> roles) {
this.id = id;
this.username = username;
this.email = email;
this.password = password;
this.roles = roles;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Set<RoleDto> getRoles() {
return roles;
}
public void setRoles(Set<RoleDto> roles) {
this.roles = roles;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
// Mapping helpers
public static UserDto fromEntity(User user) {
if (user == null) return null;
return new UserDto(
user.getId(),
user.getUsername(),
user.getEmail(),
user.getPassword(),
user.getRoles() == null ? null :
user.getRoles().stream()
.filter(Objects::nonNull)
.map(RoleDto::fromEntity)
.collect(Collectors.toSet())
);
}
public User toEntity() {
User user = new User();
user.setId(this.id);
user.setUsername(this.username);
user.setEmail(this.email);
user.setPassword(this.password); // Assuming password is already hashed
if (this.roles != null) {
user.setRoles(this.roles.stream()
.filter(Objects::nonNull)
.map(RoleDto::toEntity)
.collect(Collectors.toSet()));
}
return user;
}
}
@@ -2,9 +2,11 @@ package com.jambotronGroup.jambotron;
import com.jambotronGroup.jambotron.fileUpload.FilesStorageService;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -14,6 +16,9 @@ public class JambotronApplication implements CommandLineRunner {
@Resource
FilesStorageService storageService;
// @Autowired
// UserExportService userExportService;
private static final Logger logger = LoggerFactory.getLogger(JambotronApplication.class);
public static void main(String[] args) {
@@ -29,6 +34,14 @@ public class JambotronApplication implements CommandLineRunner {
public void run(String... arg) throws Exception {
// storageService.deleteAll();
storageService.init();
// try {
// userExportService.exportAllRolesToJson();
// userExportService.exportAllUsersToJson();
//
// } catch (Exception e) {
// logger.error("Error exporting users or roles to JSON", e);
// }
}
}
@@ -0,0 +1,347 @@
package com.jambotronGroup.jambotron.controllers;
import com.jambotronGroup.jambotron.jsonDump.JsonDumpService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.toList;
@RestController
@RequestMapping("/api/admin/json-dump")
@PreAuthorize("hasRole('ADMIN')")
public class JsonDumpController {
private static final Logger _logger = LoggerFactory.getLogger(JsonDumpController.class);
@Autowired
private JsonDumpService _jsonDumpService;
// ==================== EXPORT ENDPOINTS ====================
@PostMapping("/export/all")
public ResponseEntity<Map<String, Object>> exportAll() {
Map<String, Object> response = new HashMap<>();
try {
_jsonDumpService.exportAllRolesToJson();
_jsonDumpService.exportAllUsersToJson();
_jsonDumpService.exportAllTutorialsToJson();
response.put("success", true);
response.put("message", "All entities exported successfully");
response.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
_logger.info("Manual export of all entities completed successfully");
return ResponseEntity.ok(response);
} catch (Exception e) {
_logger.error("Failed to export all entities", e);
response.put("success", false);
response.put("message", "Export failed: " + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
}
@PostMapping("/export/users")
public ResponseEntity<Map<String, Object>> exportUsers() {
return performExport(() -> _jsonDumpService.exportAllUsersToJson(), "users");
}
@PostMapping("/export/tutorials")
public ResponseEntity<Map<String, Object>> exportTutorials() {
return performExport(() -> _jsonDumpService.exportAllTutorialsToJson(), "tutorials");
}
@PostMapping("/export/roles")
public ResponseEntity<Map<String, Object>> exportRoles() {
return performExport(() -> _jsonDumpService.exportAllRolesToJson(), "roles");
}
// ==================== IMPORT ENDPOINTS ====================
@PostMapping("/import/users")
public ResponseEntity<Map<String, Object>> importUsers() {
return performImport(() -> _jsonDumpService.importUsers(), "users");
}
@PostMapping("/import/tutorials")
public ResponseEntity<Map<String, Object>> importTutorials() {
return performImport(() -> _jsonDumpService.importTutorials(), "tutorials");
}
@PostMapping("/import/roles")
public ResponseEntity<Map<String, Object>> importRoles() {
return performImport(() -> _jsonDumpService.importRoles(), "roles");
}
@PostMapping("/import/users/file")
public ResponseEntity<Map<String, Object>> importUsersFromFile(@RequestParam("file") MultipartFile file) {
return importFromFile(file, (path) -> _jsonDumpService.importUsers(path), "users");
}
@PostMapping("/import/tutorials/file")
public ResponseEntity<Map<String, Object>> importTutorialsFromFile(@RequestParam("file") MultipartFile file) {
return importFromFile(file, (path) -> _jsonDumpService.importTutorials(path), "tutorials");
}
// ==================== ARCHIVE MANAGEMENT ====================
@PostMapping("/archives/archive-old-files")
public ResponseEntity<Map<String, Object>> archiveOldFiles() {
return performArchiveOldFiles(() -> _jsonDumpService.archiveOldFiles());
}
@GetMapping("/archives")
public ResponseEntity<Map<String, Object>> getArchivedFiles() {
Map<String, Object> response = new HashMap<>();
try {
List<String> archivedFiles = _jsonDumpService.getArchivedFiles();
response.put("success", true);
response.put("archives", archivedFiles);
response.put("count", archivedFiles.size());
return ResponseEntity.ok(response);
} catch (IOException e) {
_logger.error("Failed to list archived files", e);
response.put("success", false);
response.put("message", "Failed to list archives: " + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
}
@PostMapping("/archives/{fileName}/extract")
public ResponseEntity<Map<String, Object>> extractArchive(@PathVariable String fileName) {
Map<String, Object> response = new HashMap<>();
try {
_jsonDumpService.extractArchivedFile(fileName);
response.put("success", true);
response.put("message", "Archive extracted successfully");
response.put("fileName", fileName);
//response.put("targetDirectory", targetDir.toAbsolutePath().toString());
_logger.info("Archive {} extracted successfully", fileName);
return ResponseEntity.ok(response);
} catch (Exception e) {
_logger.error("Failed to extract archive: {}", fileName, e);
response.put("success", false);
response.put("message", "Failed to extract archive: " + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
}
@GetMapping("/archives/{fileName}/download")
public ResponseEntity<Resource> downloadArchive(@PathVariable String fileName) {
try {
Resource resource = _jsonDumpService.getArchivedFileResource(fileName);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(Files.size(resource.getFile().toPath()))
.body(resource);
} catch (IOException e) {
_logger.error("Failed to download archive: {}", fileName, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
// ==================== FILE MANAGEMENT ====================
@GetMapping("/files")
public ResponseEntity<Map<String, Object>> listFiles() {
Map<String, Object> response = new HashMap<>();
try {
List<Map<String, Object>> files = _jsonDumpService.getJsonDumpInfo();
response.put("success", true);
response.put("files", files);
response.put("count", files.size());
return ResponseEntity.ok(response);
} catch (IOException e) {
_logger.error("Failed to list files", e);
response.put("success", false);
response.put("message", "Failed to list files: " + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
}
@GetMapping("/files/{fileName}/download")
public ResponseEntity<Resource> downloadFile(@PathVariable String fileName) {
try {
Resource resource = _jsonDumpService.getJsonDumpResource(fileName);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
.contentType(MediaType.APPLICATION_JSON)
.contentLength(Files.size(resource.getFile().toPath()))
.body(resource);
} catch (IOException e) {
_logger.error("Failed to download file: {}", fileName, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
@DeleteMapping("/files/{fileName}")
public ResponseEntity<Map<String, Object>> deleteFile(@PathVariable String fileName) {
Map<String, Object> response = new HashMap<>();
try {
response = _jsonDumpService.deleteJsonDumpFile(fileName);
_logger.info("File {} deleted successfully", fileName);
return ResponseEntity.ok(response);
} catch (IOException e) {
_logger.error("Failed to delete file: {}", fileName, e);
response.put("success", false);
response.put("message", "Failed to delete file: " + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
}
// ==================== UTILITY METHODS ====================
private ResponseEntity<Map<String, Object>> performExport(ExportOperation operation, String entityType) {
Map<String, Object> response = new HashMap<>();
try {
operation.execute();
response.put("success", true);
response.put("message", entityType + " exported successfully");
response.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
_logger.info("Manual export of {} completed successfully", entityType);
return ResponseEntity.ok(response);
} catch (Exception e) {
_logger.error("Failed to export {}", entityType, e);
response.put("success", false);
response.put("message", "Export failed: " + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
}
private ResponseEntity<Map<String, Object>> performImport(ImportOperation operation, String entityType) {
Map<String, Object> response = new HashMap<>();
try {
operation.execute();
response.put("success", true);
response.put("message", entityType + " imported successfully");
response.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
_logger.info("Manual import of {} completed successfully", entityType);
return ResponseEntity.ok(response);
} catch (Exception e) {
_logger.error("Failed to import {}", entityType, e);
response.put("success", false);
response.put("message", "Import failed: " + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
}
private ResponseEntity<Map<String, Object>> importFromFile(MultipartFile file, FileImportOperation operation, String entityType) {
Map<String, Object> response = new HashMap<>();
try {
if (file.isEmpty() || !file.getOriginalFilename().endsWith(".json")) {
response.put("success", false);
response.put("message", "Please upload a valid JSON file");
return ResponseEntity.badRequest().body(response);
}
// Save uploaded file temporarily
Path tempFile = Files.createTempFile("import_", ".json");
file.transferTo(tempFile.toFile());
try {
operation.execute(tempFile);
response.put("success", true);
response.put("message", entityType + " imported successfully from uploaded file");
response.put("fileName", file.getOriginalFilename());
response.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
_logger.info("Manual import of {} from file {} completed successfully", entityType, file.getOriginalFilename());
return ResponseEntity.ok(response);
} finally {
// Clean up temp file
Files.deleteIfExists(tempFile);
}
} catch (Exception e) {
_logger.error("Failed to import {} from file", entityType, e);
response.put("success", false);
response.put("message", "Import failed: " + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
}
private ResponseEntity<Map<String, Object>> performArchiveOldFiles(ArchiveOperation operation) {
Map<String, Object> response = new HashMap<>();
try {
operation.execute();
response.put("success", true);
response.put("message", "Archive old files successfully");
response.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
_logger.info("Archive old files successfully");
return ResponseEntity.ok(response);
} catch (Exception e) {
_logger.error("Failed Archive old files.", e);
response.put("success", false);
response.put("message", "Failed Archive old files: " + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
}
@FunctionalInterface
private interface ArchiveOperation {
void execute() throws Exception;
}
// Functional interfaces for operations
@FunctionalInterface
private interface ExportOperation {
void execute() throws Exception;
}
@FunctionalInterface
private interface ImportOperation {
void execute() throws Exception;
}
@FunctionalInterface
private interface FileImportOperation {
void execute(Path filePath) throws Exception;
}
}
@@ -42,6 +42,7 @@ public class FilesStorageServiceImpl implements FilesStorageService {
private final Path root = Paths.get("/jambotron_data/uploads/user-images/");
private final Path rootPublic = Paths.get("/jambotron_data/uploads/public-images/");
// private final Path rootInitData = Pa
@Override
public void init() {
@@ -0,0 +1,21 @@
package com.jambotronGroup.jambotron.initData;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
@Configuration
//@ConditionalOnProperty(name = "app.init.data.enabled", havingValue = "true", matchIfMissing = true)
public class InitDataConfiguration {
@Autowired
private InitDataService _initDataService;
@PostConstruct
public void init() {
_initDataService.importData();
}
}
@@ -0,0 +1,148 @@
package com.jambotronGroup.jambotron.initData;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jambotronGroup.jambotron.DTOs.RoleDto;
import com.jambotronGroup.jambotron.DTOs.UserDto;
import com.jambotronGroup.jambotron.model.ERole;
import com.jambotronGroup.jambotron.model.Role;
import com.jambotronGroup.jambotron.model.User;
import com.jambotronGroup.jambotron.repository.RoleRepository;
import com.jambotronGroup.jambotron.repository.UserRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Service
@Primary
public class InitDataService {
private static final Logger _logger = LoggerFactory.getLogger(InitDataService.class);
private ObjectMapper _mapper;
@Autowired
private ResourceLoader _resources;
@Autowired
private RoleRepository _roleRepository;
@Autowired
private UserRepository _userRepository;
public InitDataService(){
_mapper = new ObjectMapper();
}
@Transactional
public void importRoles(Path jsonFile) throws Exception {
_logger.info("Importing roles from {}", jsonFile.toAbsolutePath());
List<RoleDto> items = readList(jsonFile, new TypeReference<List<RoleDto>>() {});
for (RoleDto dto : items) {
Role roleEntity = dto.toEntity();
// If a role with same name exists, reuse its ID to upsert
// _roleRepository.findByName(entity.getName())
// .ifPresent(existing -> entity.setId(existing.getId()));
if(!_roleRepository.existsByName(roleEntity.getName())) {
_roleRepository.save(roleEntity);
_logger.info("Saving new role: {}", roleEntity.getName());
} else {
_logger.info("Role {} already exists, SKIPPING import", roleEntity.getName());
}
}
_logger.info("Imported {} roles", items.stream()
.map(RoleDto::getName).toList()
.stream().map(ERole::toString).collect(Collectors.joining(", ")));
}
@Transactional
public void importUsers(Path jsonFile) throws Exception {
_logger.info("Importing users from {}", jsonFile.toAbsolutePath());
// Preload roles map by name for quick lookup
Map<ERole, Role> rolesByName = _roleRepository.findAll().stream()
.collect(Collectors.toMap(Role::getName, r -> r));
List<UserDto> items = readList(jsonFile, new TypeReference<List<UserDto>>() {});
for (UserDto dto : items) {
User user = new User();
if (dto.getId() != null) user.setId(dto.getId());
user.setUsername(dto.getUsername());
user.setEmail(dto.getEmail());
// Expecting already-hashed values; do not import plain text secrets
user.setPassword(dto.getPassword());
// Resolve roles by enum name
Set<Role> roles = new HashSet<>();
if (dto.getRoles() != null) {
for (RoleDto roleDto : dto.getRoles()) {
ERole erole = ERole.valueOf(roleDto.getName().name());
Role role = rolesByName.get(erole);
if (role == null) {
// Optionally create missing roles on the fly
role = new Role();
role.setName(erole);
role = _roleRepository.save(role);
rolesByName.put(erole, role);
}
roles.add(role);
}
}
user.setRoles(roles);
if(!_userRepository.existsByUsername(user.getUsername())) {
_userRepository.save(user);
_logger.info("Imported user: {} with roles: {}", user.getUsername(), user.getRoles().stream()
.map(Role::getName).collect(Collectors.toList()).stream().map(ERole::toString)
.collect(Collectors.joining(", ")));
} else {
_logger.warn("User with username {} already exists, SKIPPING import", user.getUsername());
_logger.info("Imported user: {} with roles: {}", user.getUsername(), user.getRoles().stream()
.map(Role::getName).collect(Collectors.toList()).stream().map(ERole::toString)
.collect(Collectors.joining(", ")));
}
}
}
protected <T> List<T> readList(Path file, TypeReference<List<T>> type) throws Exception {
String json = Files.readString(file);
return _mapper.readValue(json, type);
}
public void importData() {
try {
Resource resource = _resources.getResource("classpath:import/roles.json");
if (resource.exists()) {
importRoles(resource.getFile().toPath());
} else {
_logger.warn("Roles import file not found: {}", resource.getFilename());
}
resource = _resources.getResource("classpath:import/users.json");
if (resource.exists()) {
importUsers(resource.getFile().toPath());
} else {
_logger.warn("Users import file not found: {}", resource.getFilename());
}
} catch (Exception e) {
_logger.error("Error importing data", e);
throw new RuntimeException("Failed to import data", e);
}
}
}
@@ -0,0 +1,456 @@
package com.jambotronGroup.jambotron.jsonDump;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jambotronGroup.jambotron.DTOs.TutorialDto;
import com.jambotronGroup.jambotron.DTOs.UserDto;
import com.jambotronGroup.jambotron.controllers.AuthController;
import com.jambotronGroup.jambotron.initData.InitDataService;
import com.jambotronGroup.jambotron.model.ERole;
import com.jambotronGroup.jambotron.model.Role;
import com.jambotronGroup.jambotron.model.Tutorial;
import com.jambotronGroup.jambotron.model.User;
import com.jambotronGroup.jambotron.repository.RoleRepository;
import com.jambotronGroup.jambotron.repository.TutorialRepository;
import com.jambotronGroup.jambotron.repository.UserRepository;
import jakarta.persistence.EntityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@Service
public class JsonDumpService extends InitDataService {
private static final Logger _logger = LoggerFactory.getLogger(JsonDumpService.class);
private final Path _root = Paths.get("/jambotron_data/jsonDump/");
private final Path _archivePath = _root.resolve("archive");
private final Path _extractedPath = _root.resolve("extracted");
private final ObjectMapper _mapper;
@Autowired
private final UserRepository _userRepository;
@Autowired
private final RoleRepository _roleRepository;
@Autowired
private final TutorialRepository _tutorialRepository;
@Value("${app.json.dump.cleanup.enabled:true}")
private boolean _cleanupEnabled;
@Value("${app.json.dump.cleanup.retention.weeks:4}")
private int _retentionWeeks;
@Value("${app.json.dump.archive.enabled:true}")
private boolean _archiveEnabled;
public JsonDumpService(ObjectMapper mapper, UserRepository userRepository, RoleRepository roleRepository, TutorialRepository tutorialRepository) {
_mapper = mapper;
_userRepository = userRepository;
_roleRepository = roleRepository;
_tutorialRepository = tutorialRepository;
}
private static String getFileNameWithTimestamp(String prefix) {
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss"));
return String.format("%s_%s.json", prefix, timestamp);
}
private void exportToJson(List<?> entities, String entitiesName) throws Exception {
// Create filename with timestamp
String fileNameWithTimestamp = JsonDumpService.getFileNameWithTimestamp(entitiesName);
// Ensure export directory exists
Files.createDirectories(_root);
// Write entities to JSON file
Path filePath = _root.resolve(fileNameWithTimestamp);
_mapper.writerWithDefaultPrettyPrinter().writeValue(filePath.toFile(), entities);
_logger.info("Exported {} to {}", entitiesName, filePath.toAbsolutePath());
}
public void exportAllTutorialsToJson() throws Exception {
List<Tutorial> tutorials = _tutorialRepository.findAll();
List<TutorialDto> tutorialDtos = tutorials.stream().map(
TutorialDto::fromEntity
).toList();
exportToJson(tutorialDtos, "tutorials");
}
public void exportAllRolesToJson() throws Exception {
List<Role> roles = _roleRepository.findAll();
exportToJson(roles, "roles");
}
@Transactional
public void exportAllUsersToJson() throws Exception {
List<User> users = _userRepository.findAll();
List<UserDto> userDtos = users.stream().map(
user-> UserDto.fromEntity(user)
).toList();
exportToJson(userDtos, "users");
}
private Optional<Path> getLatestJsonFile(String prefix) throws IOException {
Optional<Path> latestFile = Files.list(_root)
.filter(p -> p.getFileName().toString().matches(prefix + "_.*\\.json"))
.max(Comparator.comparing(p -> p.toFile().lastModified()));
return latestFile.isPresent() ? latestFile : Optional.empty();
}
public void importRoles() throws Exception {
_logger.info("Importing roles from latest JSON file in {}", _root.toAbsolutePath());
Path jsonFile = getLatestJsonFile("roles").get();
if (!Files.exists(jsonFile)) {
throw new IllegalArgumentException("Roles JSON file not found: " + jsonFile.toAbsolutePath());
}
importRoles(jsonFile);
}
public void importUsers() throws Exception {
_logger.info("Importing users from latest JSON file in {}", _root.toAbsolutePath());
Path jsonFile = getLatestJsonFile("users").get();
if (!Files.exists(jsonFile)) {
throw new IllegalArgumentException("Users JSON file not found: " + jsonFile.toAbsolutePath());
}
importUsers(jsonFile);
}
public void importTutorials() throws Exception {
_logger.info("Importing tutorials from latest JSON file in {}", _root.toAbsolutePath());
Path jsonFile = getLatestJsonFile("tutorials").get();
if (!Files.exists(jsonFile)) {
throw new IllegalArgumentException("Tutorials JSON file not found: " + jsonFile.toAbsolutePath());
}
importTutorials(jsonFile);
}
@Transactional
public void importTutorials(Path jsonFile) throws Exception {
Map<Long, User> usersById = _userRepository.findAll().stream()
.collect(Collectors.toMap(User::getId, u -> u));
List<TutorialDto> items = super.readList(jsonFile, new TypeReference<List<TutorialDto>>() {});
for (TutorialDto dto : items) {
Tutorial t = new Tutorial();
t.setId(dto.getId());
t.setTitle(dto.getTitle());
t.setDescription(dto.getDescription());
t.setPublished(dto.getPublished());
t.setTobepublished(dto.isTobepublished());
t.setCreated(dto.getCreated());
t.setModified(dto.getModified());
t.setTitleimage(dto.getTitleimage());
t.setBody(dto.getBody());
if (!usersById.containsKey(dto.getUserID())) {
_logger.warn(String.format("Missing or unknown userId [%s] for tutorial: [%s]", dto.getUserID(), dto.getTitle()));
Optional<User> admin = _userRepository.findAll()
.stream().filter(
user -> user.getRoles()
.stream().anyMatch(
role -> role.getName().equals(ERole.ROLE_ADMIN)
)
).findFirst();
if (admin.isPresent()) {
_logger.info("Assigning tutorial [%s] to admin user [%s]".formatted(dto.getTitle(), admin.get().getUsername()));
t.setUser(admin.get());
} else {
throw new IllegalArgumentException("Missing user with ROLE_ADMIN to assign tutorial: " + dto.getTitle());
}
}
User user = usersById.get(dto.getUserID());
//user = _entityManager.merge(user); // Ensure user is managed by EntityManager
//user.setRoles(null); // because we don't want to load roles to user object
t.setUser(user);
if(_tutorialRepository.findByUserIdAndTitle(t.getUser().getId(), t.getTitle()).size()> 0) {
_logger.warn("Tutorial with title [{}] already exists for user [{}], SKIPPING import", t.getTitle(), t.getUser().getUsername());
continue;
}
_tutorialRepository.saveAndFlush(t);
//_tutorialRepository.save(t);
_logger.info("Imported tutorial: {} with user: {}", t.getTitle(), t.getUser().getUsername());
}
}
@Scheduled(cron = "${app.json.dump.schedule.cron:0 0 2 * * SUN}") // Configurable schedule, default: Sunday 2 AM
public void exportEntities() {
try {
_logger.info("--------------Starting weekly entity export...-------------------");
exportAllRolesToJson();
exportAllUsersToJson();
exportAllTutorialsToJson();
_logger.info("--------------Weekly entity export completed successfully.--------");
// Optional: Clean up old exports (configurable)
if (_cleanupEnabled) {
if( _archiveEnabled) {
archiveOldFiles(_retentionWeeks);
} else {
cleanupOldFiles();
}
}
} catch (Exception e) {
_logger.error("Failed to export entities", e);
}
}
public void cleanupOldFiles() throws IOException {
Path exportDir = _root;
if (!Files.exists(exportDir)) return;
LocalDateTime cutoffDate = LocalDateTime.now().minusWeeks(_retentionWeeks);
Files.list(exportDir)
.filter(path -> path.toString().endsWith(".json"))
.filter(path -> {
try {
FileTime lastModified = Files.getLastModifiedTime(path);
return lastModified.toInstant().isBefore(cutoffDate.atZone(ZoneId.systemDefault()).toInstant());
} catch (IOException e) {
return false;
}
})
.forEach(path -> {
try {
Files.delete(path);
_logger.info("Deleted old export file: {}", path);
} catch (IOException e) {
_logger.warn("Failed to delete old export file: {}", path, e);
}
});
}
public void archiveOldFiles() throws IOException {
this.archiveOldFiles(0);
}
private void archiveOldFiles(int retentionWeeks) throws IOException {
Path exportDir = _root;
Path archiveDir = _archivePath;
if (!Files.exists(exportDir)) return;
// Create archive directory if it doesn't exist
Files.createDirectories(archiveDir);
LocalDateTime cutoffDate = LocalDateTime.now().minusWeeks(retentionWeeks);
Files.list(exportDir)
.filter(path -> path.toString().endsWith(".json"))
//.filter(path -> path.getFileName().toString().startsWith("entities_"))
.filter(path -> {
try {
FileTime lastModified = Files.getLastModifiedTime(path);
return lastModified.toInstant().isBefore(cutoffDate.atZone(ZoneId.systemDefault()).toInstant());
} catch (IOException e) {
return false;
}
})
.forEach(path -> {
try {
// Create compressed archive
String fileName = path.getFileName().toString();
String zipFileName = fileName.replace(".json", ".zip");
Path zipPath = archiveDir.resolve(zipFileName);
compressFile(path, zipPath);
// Delete original after successful compression
Files.delete(path);
_logger.info("Archived and deleted old export file: {} -> {}", path, zipPath);
} catch (IOException e) {
_logger.error("Failed to archive export file: {}", path, e);
}
});
}
private void compressFile(Path sourceFile, Path zipFile) throws IOException {
try (FileOutputStream fos = new FileOutputStream(zipFile.toFile());
ZipOutputStream zos = new ZipOutputStream(fos);
FileInputStream fis = new FileInputStream(sourceFile.toFile())) {
ZipEntry zipEntry = new ZipEntry(sourceFile.getFileName().toString());
zos.putNextEntry(zipEntry);
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
zos.closeEntry();
}
}
public void extractArchivedFile(String zipFileName) throws IOException {
Path targetDir = _extractedPath;
extractArchivedFile(zipFileName, targetDir);
}
// Method to extract archived file when needed
public void extractArchivedFile(String zipFileName, Path targetDir) throws IOException {
Path zipPath = _archivePath.resolve(zipFileName);
if (!Files.exists(zipPath)) {
throw new FileNotFoundException("Archive file not found: " + zipFileName);
}
Files.createDirectories(targetDir);
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipPath.toFile()))) {
ZipEntry entry = zis.getNextEntry();
while (entry != null) {
Path filePath = targetDir.resolve(entry.getName());
try (FileOutputStream fos = new FileOutputStream(filePath.toFile())) {
byte[] buffer = new byte[1024];
int length;
while ((length = zis.read(buffer)) > 0) {
fos.write(buffer, 0, length);
}
}
entry = zis.getNextEntry();
}
}
_logger.info("Extracted archive {} to {}", zipFileName, targetDir.toAbsolutePath());
}
public Resource getArchivedFileResource(String zipFileName) throws IOException {
Path zipPath = _archivePath.resolve(zipFileName);
if (!Files.exists(zipPath)) {
throw new FileNotFoundException("Archive file not found: " + zipFileName);
}
return new org.springframework.core.io.FileSystemResource(zipPath.toFile());
}
public List<Map<String, Object>> getJsonDumpInfo() throws IOException {
List<Map<String, Object>> infoList = new ArrayList<>();
if (!Files.exists(_root)) {
Map<String, Object> info = new HashMap<>();
info.put("success", true);
info.put("files", List.of());
info.put("count", 0);
infoList.add(info);
return infoList;
}
// Get all JSON files in the root directory
Files.list(_root)
.filter(path -> path.toString().endsWith(".json"))
.forEach(path -> {
Map<String, Object> info = new HashMap<>();
info.put("fileName", path.getFileName().toString());
try {
info.put("lastModified", Files.getLastModifiedTime(path).toInstant().toString());
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
info.put("size", Files.size(path));
} catch (IOException e) {
throw new RuntimeException(e);
}
infoList.add(info);
});
return infoList;
}
public Resource getJsonDumpResource(String fileName) throws IOException {
Path filePath = _root.resolve(fileName);
if (!Files.exists(filePath)) {
throw new FileNotFoundException("JSON dump file not found: " + fileName);
}
return new org.springframework.core.io.FileSystemResource(filePath.toFile());
}
// Method to list archived files
public List<String> getArchivedFiles() throws IOException {
Path archiveDir = _archivePath;
if (!Files.exists(archiveDir)) {
return new ArrayList<>();
}
return Files.list(archiveDir)
.filter(path -> path.toString().endsWith(".zip"))
.map(path -> path.getFileName().toString())
.sorted()
.collect(Collectors.toList());
}
public Map<String, Object> deleteJsonDumpFile(String fileName) throws IOException {
Path filePath = _root.resolve(fileName);
Map<String, Object> response = new HashMap<>();
if (!Files.exists(filePath)) {
response.put("success", false);
response.put("message", "File not found: " + fileName);
return response;
}
Files.delete(filePath);
response.put("success", true);
response.put("message", "File deleted successfully: " + fileName);
return response;
}
}
@@ -0,0 +1,34 @@
package com.jambotronGroup.jambotron.jsonDump;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JsonDumpServiceConfiguration {
@Autowired
private JsonDumpService _jsonDumpService;
@PostConstruct
public void onInit(){
// This method will be called after the Spring context is initialized
// and will trigger the export of users and roles to JSON files.
// try{
// _jsonDumpService.exportAllRolesToJson();
// _jsonDumpService.exportAllUsersToJson();
// _jsonDumpService.exportAllTutorialsToJson();
// } catch (Exception e) {
// // Handle any exceptions that may occur during the export process
// e.printStackTrace();
// }
// try {
// _jsonDumpService.importRoles();
// _jsonDumpService.importUsers();
// _jsonDumpService.importTutorials();
// }catch (Exception e) {
// // Handle any exceptions that may occur during the import process
// e.printStackTrace();
// }
}
}
@@ -9,7 +9,7 @@ import jakarta.persistence.*;
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Long id;
@Enumerated(EnumType.STRING)
@Column(length = 20)
@@ -23,11 +23,11 @@ public class Role {
this.name = name;
}
public Integer getId() {
public Long getId() {
return id;
}
public void setId(Integer id) {
public void setId(Long id) {
this.id = id;
}
@@ -13,7 +13,7 @@ public class Tutorial {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private Long id;
@Column(name = "title")
private String title;
@@ -27,7 +27,7 @@ public class Tutorial {
@Column(name = "tobepublished")
private boolean tobepublished;
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@ManyToOne(fetch = FetchType.EAGER)//, cascade = CascadeType.PERSIST)
@JoinColumn(name = "userID", nullable = false)
private User user;
@@ -59,10 +59,14 @@ public class Tutorial {
this.body = body;
}
public long getId() {
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
@@ -115,6 +119,10 @@ public class Tutorial {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Tutorial [id=" + id + ", title=" + title + ", desc=" + description + ", published=" + published + "]";
@@ -20,7 +20,7 @@ public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
private Long id;
@Column(name = "username")
@NotBlank
@@ -11,4 +11,7 @@ import java.util.Optional;
@Repository
public interface RoleRepository extends JpaRepository<Role, Long> {
Optional<Role> findByName(ERole name);
boolean existsByName(ERole name);
}
@@ -1,5 +1,6 @@
package com.jambotronGroup.jambotron.security;
import com.jambotronGroup.jambotron.initData.InitDataService;
import com.jambotronGroup.jambotron.security.jwt.AuthEntryPointJwt;
import com.jambotronGroup.jambotron.security.jwt.AuthTokenFilter;
import com.jambotronGroup.jambotron.security.services.UserDetailsServiceImpl;
@@ -51,7 +52,6 @@ public class WebSecurityConfig implements WebMvcConfigurer {// extends WebSecuri
private AuthEntryPointJwt unauthorizedHandler;
@Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
@@ -121,8 +121,11 @@ public class WebSecurityConfig implements WebMvcConfigurer {// extends WebSecuri
// Access permitted for specific roles
.requestMatchers("/api/user/**").hasRole("USER")
.requestMatchers("/api/moderator/**").hasRole("MODERATOR")
.requestMatchers("/api/admin/**").hasRole("ADMIN")
//.requestMatchers("/api/admin/**").hasRole("ADMIN")
.requestMatchers("/api/admin/**").permitAll()
.requestMatchers("/api/admin/json-dump/**").permitAll()
.requestMatchers("/api/admin/json-dump/import/**").permitAll()
.anyRequest().authenticated()
);
@@ -16,6 +16,18 @@ spring.flyway.url=jdbc:postgresql://localhost:5433/jambotronDB
spring.flyway.user=admin
spring.flyway.password=postgrespw
#spring.datasource.url= jdbc:postgresql://localhost:5433/db_for_import
#spring.datasource.username= admin
#spring.datasource.password= postgrespw
#
#spring.flyway.enabled=false
##spring.flyway.baseline-on-migrate=true
##spring.flyway.validate-on-migrate=true
##
##spring.flyway.url=jdbc:postgresql://localhost:5433/db_for_import
##spring.flyway.user=admin
##spring.flyway.password=postgrespw
#============jpa=====================
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.PostgreSQLDialect
@@ -1,12 +0,0 @@
CREATE TABLE IF NOT EXISTS public.refreshtoken
(
id bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
user_id bigint NOT NULL,
token character varying COLLATE pg_catalog."default" NOT NULL,
expiry_date timestamp with time zone,
CONSTRAINT refreshtoken_pkey PRIMARY KEY (id),
CONSTRAINT "FK_refreshtoken_users" FOREIGN KEY (user_id)
REFERENCES public.users (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
);
+78 -6
View File
@@ -1,9 +1,81 @@
-- This script was generated by the ERD tool in pgAdmin 4.
-- Please log an issue at https://github.com/pgadmin-org/pgadmin4/issues/new/choose if you find any bugs, including reproduction steps.
BEGIN;
CREATE TABLE IF NOT EXISTS roles
CREATE TABLE IF NOT EXISTS public.refreshtoken
(
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name character varying(20)
id bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
user_id bigint NOT NULL,
token character varying COLLATE pg_catalog."default" NOT NULL,
expiry_date timestamp with time zone,
CONSTRAINT refreshtoken_pkey PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS public.roles
(
id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
name character varying(20) COLLATE pg_catalog."default",
CONSTRAINT roles_pkey PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS public.tutorials
(
id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
published boolean,
tobepublished boolean,
title character varying(255) COLLATE pg_catalog."default",
userid bigint,
created timestamp with time zone,
modified timestamp with time zone,
description character varying(255) COLLATE pg_catalog."default",
titleimage text COLLATE pg_catalog."default",
body text COLLATE pg_catalog."default",
CONSTRAINT tutorials_title_key UNIQUE (title)
);
CREATE TABLE IF NOT EXISTS public.user_roles
(
user_id bigint NOT NULL,
role_id integer NOT NULL,
CONSTRAINT user_roles_pkey PRIMARY KEY (user_id, role_id)
);
CREATE TABLE IF NOT EXISTS public.users
(
id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
email character varying(50) COLLATE pg_catalog."default",
password character varying(120) COLLATE pg_catalog."default",
username character varying(20) COLLATE pg_catalog."default",
CONSTRAINT users_pkey PRIMARY KEY (id),
CONSTRAINT uk6dotkott2kjsp8vw4d0m25fb7 UNIQUE (email),
CONSTRAINT ukr43af9ap4edm43mmtq01oddj6 UNIQUE (username)
);
ALTER TABLE IF EXISTS public.refreshtoken
ADD CONSTRAINT "FK_refreshtoken_users" FOREIGN KEY (user_id)
REFERENCES public.users (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION;
ALTER TABLE IF EXISTS public.tutorials
ADD CONSTRAINT "tutorial_user_FK" FOREIGN KEY (userid)
REFERENCES public.users (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION;
ALTER TABLE IF EXISTS public.user_roles
ADD CONSTRAINT fkh8ciramu9cc9q3qcqiv4ue8a6 FOREIGN KEY (role_id)
REFERENCES public.roles (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION;
ALTER TABLE IF EXISTS public.user_roles
ADD CONSTRAINT fkhfh9dx7w3ubf1co1vdev94g3f FOREIGN KEY (user_id)
REFERENCES public.users (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION;
END;
@@ -1,14 +0,0 @@
CREATE TABLE IF NOT EXISTS users
(
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
email character varying(50) COLLATE pg_catalog."default",
password character varying(120) COLLATE pg_catalog."default",
username character varying(20) COLLATE pg_catalog."default",
CONSTRAINT uk6dotkott2kjsp8vw4d0m25fb7 UNIQUE (email),
CONSTRAINT ukr43af9ap4edm43mmtq01oddj6 UNIQUE (username)
);
@@ -1,25 +0,0 @@
CREATE TABLE IF NOT EXISTS public.user_roles
(
user_id bigint NOT NULL,
role_id integer NOT NULL,
CONSTRAINT user_roles_pkey PRIMARY KEY (user_id, role_id),
CONSTRAINT fkh8ciramu9cc9q3qcqiv4ue8a6 FOREIGN KEY (role_id)
REFERENCES public.roles (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION,
CONSTRAINT fkhfh9dx7w3ubf1co1vdev94g3f FOREIGN KEY (user_id)
REFERENCES public.users (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
);
CREATE TABLE IF NOT EXISTS public.tutorials
(
id bigint NOT NULL,
description character varying(255) COLLATE pg_catalog."default",
published boolean,
title character varying(255) COLLATE pg_catalog."default",
CONSTRAINT tutorials_pkey PRIMARY KEY (id)
);
@@ -1,20 +0,0 @@
INSERT INTO roles (id, name) OVERRIDING SYSTEM VALUE VALUES (1, 'ROLE_USER');
INSERT INTO roles (id, name) OVERRIDING SYSTEM VALUE VALUES (2, 'ROLE_MODERATOR');
INSERT INTO roles (id, name) OVERRIDING SYSTEM VALUE VALUES (3, 'ROLE_ADMIN');
INSERT INTO users (id, email, password, username)
OVERRIDING SYSTEM VALUE
VALUES (1, 'liosha84@gmail.com', '$2a$10$qyoKXYSukha6XCjorTzoweF4Os1pwmwyzbaSsb3RCVB0LK6WLQKPC', 'Admin');
INSERT INTO users (id, email, password, username)
OVERRIDING SYSTEM VALUE
VALUES (2, 'Moderator@gmail.com', '$2a$10$zLo5th8Xbfq.MM7y/dCRQu3Ud7HHyAwm.7.yS08ytJtkHMKrbOJlu', 'Moderator');
INSERT INTO users (id, email, password, username)
OVERRIDING SYSTEM VALUE
VALUES (3, 'user@gmail.com', '$2a$10$2EcwYffteBF3GhVaf5qPB.I7XiHepDEauU5D4fx9fpBXMTZI/QnnC', 'User');
INSERT INTO user_roles (user_id, role_id) OVERRIDING SYSTEM VALUE VALUES (3, 1);
INSERT INTO user_roles (user_id, role_id) OVERRIDING SYSTEM VALUE VALUES (1, 3);
INSERT INTO user_roles (user_id, role_id) OVERRIDING SYSTEM VALUE VALUES (2, 2);
@@ -1,2 +0,0 @@
ALTER TABLE IF EXISTS public.tutorials
ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY;
@@ -1,6 +0,0 @@
-- Column: public.tutorials.
ALTER TABLE IF EXISTS public.tutorials DROP COLUMN IF EXISTS id;
ALTER TABLE IF EXISTS public.tutorials
ADD COLUMN id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 );
@@ -1,27 +0,0 @@
DROP TABLE IF EXISTS public.tutorials;
CREATE TABLE IF NOT EXISTS public.tutorials
(
description character varying(255) COLLATE pg_catalog."default",
published boolean,
title character varying(255) COLLATE pg_catalog."default",
id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
userid bigint,
CONSTRAINT "tutorial_user_FK" FOREIGN KEY (userid)
REFERENCES public.users (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
NOT VALID
)
TABLESPACE pg_default;
-- Index: fki_tutorial_user_FK
-- DROP INDEX IF EXISTS public."fki_tutorial_user_FK";
CREATE INDEX IF NOT EXISTS "fki_tutorial_user_FK"
ON public.tutorials USING btree
(userid ASC NULLS LAST)
TABLESPACE pg_default;
@@ -1,19 +0,0 @@
DROP TABLE tutorials;
CREATE TABLE tutorials
(
id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
published boolean,
tobepublished boolean,
title character varying(255) COLLATE pg_catalog."default",
userid bigint,
created timestamp with time zone,
modified timestamp with time zone,
description character varying(255) COLLATE pg_catalog."default",
CONSTRAINT tutorials_title_key UNIQUE (title),
CONSTRAINT "tutorial_user_FK" FOREIGN KEY (userid)
REFERENCES public.users (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
)
@@ -1,9 +0,0 @@
ALTER TABLE IF EXISTS public.tutorials DROP COLUMN IF EXISTS titleimage;
ALTER TABLE IF EXISTS public.tutorials
ADD COLUMN titleimage text COLLATE pg_catalog."default";
ALTER TABLE IF EXISTS public.tutorials DROP COLUMN IF EXISTS body;
ALTER TABLE IF EXISTS public.tutorials
ADD COLUMN body text COLLATE pg_catalog."default";
+10
View File
@@ -0,0 +1,10 @@
[ {
"id" : 1,
"name" : "ROLE_USER"
}, {
"id" : 2,
"name" : "ROLE_MODERATOR"
}, {
"id" : 3,
"name" : "ROLE_ADMIN"
} ]
+34
View File
@@ -0,0 +1,34 @@
[ {
"id" : 1,
"username" : "Admin",
"email" : "liosha84@gmail.com",
"password" : "$2a$10$qyoKXYSukha6XCjorTzoweF4Os1pwmwyzbaSsb3RCVB0LK6WLQKPC",
"roles" : [ {
"id" : 1,
"name" : "ROLE_USER"
}, {
"id" : 2,
"name" : "ROLE_MODERATOR"
}, {
"id" : 3,
"name" : "ROLE_ADMIN"
} ]
}, {
"id" : 2,
"username" : "Moderator",
"email" : "Moderator@gmail.com",
"password" : "$2a$10$zLo5th8Xbfq.MM7y/dCRQu3Ud7HHyAwm.7.yS08ytJtkHMKrbOJlu",
"roles" : [ {
"id" : 2,
"name" : "ROLE_MODERATOR"
} ]
}, {
"id" : 3,
"username" : "User",
"email" : "user@gmail.com",
"password" : "$2a$10$2EcwYffteBF3GhVaf5qPB.I7XiHepDEauU5D4fx9fpBXMTZI/QnnC",
"roles" : [ {
"id" : 1,
"name" : "ROLE_USER"
} ]
} ]