package de.w665.biblenotes.db; import com.rethinkdb.RethinkDB; import com.rethinkdb.gen.exc.ReqlOpFailedError; import com.rethinkdb.net.Connection; import de.w665.biblenotes.db.repo.UserRepository; import de.w665.biblenotes.model.User; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import java.util.Optional; @Slf4j @Service public class RethinkDBService { private final RethinkDBConfig config; private final RethinkDB r; private final Connection connection; private final UserRepository userRepository; @Value("${biblenotes.auto-reset-on-startup}") private boolean autoResetOnStartup; @Value("${biblenotes.management.user.username}") private String defaultUsername; @Value("${biblenotes.management.user.password}") private String defaultPassword; private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); @Autowired public RethinkDBService(RethinkDBConfig config, RethinkDBConnector connector, UserRepository userRepository) { this.config = config; // mapping to private vars for easier access this.r = connector.getR(); this.connection = connector.getConnection(); this.userRepository = userRepository; } @PostConstruct public void initialize() { // rethinkdb check if database exists try { r.dbCreate(config.getDatabase()).run(connection).stream(); log.debug("Database " + config.getDatabase() + " created"); } catch (ReqlOpFailedError e) { log.debug("Database " + config.getDatabase() + " already exists. Error: " + e.getClass().getSimpleName()); } // rethinkdb check if table users exists try { r.db(config.getDatabase()).tableCreate("users").run(connection).stream(); log.debug("Table 'users' created successfully."); } catch (ReqlOpFailedError e) { log.debug("Table 'users' already exists."); if(autoResetOnStartup) { log.debug("Clearing content..."); r.db(config.getDatabase()).table("users").delete().run(connection); log.debug("Table 'users' cleared successfully."); } } // rethinkdb check if table user_logins exists try { r.db(config.getDatabase()).tableCreate("user_logins").run(connection).stream(); log.debug("Table 'user_logins' created successfully."); } catch (ReqlOpFailedError e) { log.debug("Table 'user_logins' already exists."); if(autoResetOnStartup) { log.debug("Clearing content..."); r.db(config.getDatabase()).table("user_logins").delete().run(connection); log.debug("Table 'user_logins' cleared successfully."); } } finally { try { r.db(config.getDatabase()).table("user_logins").indexCreate("loginTime").run(connection); log.debug("Secondary index 'loginTime' on table 'user_logins' successfully created."); } catch (ReqlOpFailedError e) { log.debug("Secondary index 'loginTime' already exists."); } finally { r.db(config.getDatabase()).table("user_logins").indexWait("loginTime").run(connection); } } initializeAdminUser(); log.info("Database ready for operation!"); } private void initializeAdminUser() { Optional adminUser = userRepository.retrieveUserByUsername("admin"); if(adminUser.isEmpty()) { User user = new User(); user.setUsername(defaultUsername); user.setPassword(passwordEncoder.encode(defaultPassword)); user.setRole("ADMIN"); userRepository.insertUser(user); log.debug("Admin user created with default credentials. Username: admin, Password: admin"); } } @PreDestroy public void close() { if (connection != null) { connection.close(); } } }