Added NodeInitializer to replace specific individual initializers.

This commit is contained in:
Andrew Lalis 2023-10-22 20:15:43 -04:00
parent 19c7f35abc
commit c2dd6e8a4a
6 changed files with 86 additions and 33 deletions

View File

@ -0,0 +1,68 @@
package com.andrewlalis.onyx;
import com.andrewlalis.onyx.auth.model.User;
import com.andrewlalis.onyx.auth.model.UserRepository;
import com.andrewlalis.onyx.content.dao.ContentNodeRepository;
import com.andrewlalis.onyx.content.model.ContentContainerNode;
import com.andrewlalis.onyx.content.model.ContentNode;
import com.andrewlalis.onyx.content.model.access.ContentAccessLevel;
import com.andrewlalis.onyx.content.model.access.UserContentAccessRule;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
/**
* A component that runs on application startup, to take care of some
* first-time initialization, if needed:
* <ol>
* <li>Create a default admin user, if none exists.</li>
* <li>Create the root content node for the content tree.</li>
* </ol>
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class NodeInitializer implements CommandLineRunner {
private final ContentNodeRepository contentNodeRepository;
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
@Override
public void run(String... args) throws Exception {
User adminUser = createAdminUserIfNoUsers();
createRootNodeIfNotExists(adminUser);
}
private void createRootNodeIfNotExists(User adminUser) {
if (!contentNodeRepository.existsByName(ContentNode.ROOT_NODE_NAME)) {
ContentNode rootNode = new ContentContainerNode(ContentNode.ROOT_NODE_NAME, null);
rootNode.getAccessInfo().setPublicAccessLevel(ContentAccessLevel.NONE);
rootNode.getAccessInfo().setNetworkAccessLevel(ContentAccessLevel.NONE);
rootNode.getAccessInfo().setNodeAccessLevel(ContentAccessLevel.NONE);
if (adminUser != null) {
rootNode.getAccessInfo().getUserAccessRules().add(new UserContentAccessRule(
adminUser,
rootNode.getAccessInfo(),
ContentAccessLevel.EDIT
));
}
contentNodeRepository.saveAndFlush(rootNode);
log.info("Created content root container node.");
}
}
private User createAdminUserIfNoUsers() {
if (userRepository.count() == 0) {
User user = userRepository.saveAndFlush(new User(
"admin",
"Admin",
passwordEncoder.encode("onyx-admin")
));
log.info("Created user \"admin\" with password \"onyx-admin\"");
return user;
}
return null;
}
}

View File

@ -40,7 +40,7 @@ public class TokenService {
private static final String ISSUER = "Onyx API"; private static final String ISSUER = "Onyx API";
private PrivateKey signingKey; private PrivateKey signingKey;
private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(10); private final PasswordEncoder passwordEncoder;
private final RefreshTokenRepository refreshTokenRepository; private final RefreshTokenRepository refreshTokenRepository;
private final UserRepository userRepository; private final UserRepository userRepository;

View File

@ -0,0 +1,14 @@
package com.andrewlalis.onyx.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SecurityComponents {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(10);
}
}

View File

@ -1,30 +0,0 @@
package com.andrewlalis.onyx.content;
import com.andrewlalis.onyx.content.dao.ContentNodeRepository;
import com.andrewlalis.onyx.content.model.access.ContentAccessLevel;
import com.andrewlalis.onyx.content.model.ContentContainerNode;
import com.andrewlalis.onyx.content.model.ContentNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
@Slf4j
public class ContentTreeInitializer implements CommandLineRunner {
private final ContentNodeRepository contentNodeRepository;
@Override
public void run(String... args) throws Exception {
log.info("Check if content root container node exists.");
if (!contentNodeRepository.existsByName(ContentNode.ROOT_NODE_NAME)) {
ContentNode rootNode = new ContentContainerNode(ContentNode.ROOT_NODE_NAME, null);
rootNode.getAccessInfo().setPublicAccessLevel(ContentAccessLevel.NONE);
rootNode.getAccessInfo().setNetworkAccessLevel(ContentAccessLevel.NONE);
rootNode.getAccessInfo().setNodeAccessLevel(ContentAccessLevel.NONE);
contentNodeRepository.saveAndFlush(rootNode);
log.info("Created content root container node.");
}
}
}

View File

@ -5,6 +5,7 @@ import jakarta.persistence.*;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
/** /**
@ -40,5 +41,5 @@ public class ContentAccessRules {
* User-specific access rules that override other more generic rules, if present. * User-specific access rules that override other more generic rules, if present.
*/ */
@OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, cascade = CascadeType.ALL, mappedBy = "contentAccessRules") @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, cascade = CascadeType.ALL, mappedBy = "contentAccessRules")
private Set<UserContentAccessRule> userAccessRules; private Set<UserContentAccessRule> userAccessRules = new HashSet<>();
} }

View File

@ -2,4 +2,4 @@
spring.datasource.url=jdbc:h2:./onyx-db-dev spring.datasource.url=jdbc:h2:./onyx-db-dev
spring.datasource.driver-class-name=org.h2.Driver spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.hibernate.ddl-auto=create spring.jpa.hibernate.ddl-auto=update