From 00d2fac01426c31c49b35e314a0830712b8e150a Mon Sep 17 00:00:00 2001 From: Rita Lopes Date: Thu, 23 May 2024 18:14:17 +0100 Subject: [PATCH 01/10] Create boilerplate for seeders to work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Luís Duarte --- .../backend/hooks/ApplicationStartupHook.kt | 23 +++++++++++++++++++ .../backend/model/seeders/AbstractSeeder.kt | 7 ++++++ .../backend/model/seeders/AccountSeeder.kt | 8 +++++++ .../model/seeders/ApplicationSeeder.kt | 19 +++++++++++++++ src/main/resources/application.properties | 3 +++ 5 files changed, 60 insertions(+) create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AbstractSeeder.kt create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt new file mode 100644 index 00000000..87e8eee3 --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt @@ -0,0 +1,23 @@ +package pt.up.fe.ni.website.backend.hooks + +import org.springframework.beans.factory.annotation.Value +import org.springframework.boot.ApplicationArguments +import org.springframework.boot.ApplicationRunner +import org.springframework.stereotype.Component +import pt.up.fe.ni.website.backend.config.Logging +import pt.up.fe.ni.website.backend.model.seeders.ApplicationSeeder + +@Component +class ApplicationStartupHook : ApplicationRunner, Logging{ + + @Value("\${app.debug}") + val debug: Boolean = false + + override fun run(args: ApplicationArguments?) { + logger.info("Running Startup hook...") + if(debug){ + logger.info("Running application seeder...") + ApplicationSeeder().seedDatabase() + } + } +} diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AbstractSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AbstractSeeder.kt new file mode 100644 index 00000000..aec90caa --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AbstractSeeder.kt @@ -0,0 +1,7 @@ +package pt.up.fe.ni.website.backend.model.seeders + +interface AbstractSeeder { + + fun createObjects() + +} diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt new file mode 100644 index 00000000..6d4add79 --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt @@ -0,0 +1,8 @@ +package pt.up.fe.ni.website.backend.model.seeders + +class AccountSeeder : AbstractSeeder { + + override fun createObjects() { + + } +} diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt new file mode 100644 index 00000000..4ef8e356 --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt @@ -0,0 +1,19 @@ +package pt.up.fe.ni.website.backend.model.seeders + +class ApplicationSeeder { + + //NOTE(luisd): these are run in order so you should take care of dependencies of said seeders + private val seeders : List = listOf( + AccountSeeder() + ) + + + fun seedDatabase(){ + //TODO(luisd): delete database + //TODO(luisd): apply schema + + seeders.forEach { + seeder -> seeder.createObjects() + } + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 449647da..8c02afc3 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,3 +1,6 @@ +# Application Settings +app.debug = true + # Datasource spring.datasource.url=jdbc:h2:file:~/website-be-h2-db spring.datasource.username=h2dev From bc1388ed15cad1b74dba617d93854be9b36cc4f2 Mon Sep 17 00:00:00 2001 From: Rita Lopes Date: Thu, 13 Jun 2024 18:35:48 +0100 Subject: [PATCH 02/10] Changed provider and finished account seeder --- build.gradle.kts | 1 + .../backend/hooks/ApplicationStartupHook.kt | 8 ++- .../backend/model/seeders/AbstractSeeder.kt | 10 +++- .../backend/model/seeders/AccountSeeder.kt | 60 ++++++++++++++++++- .../model/seeders/ApplicationSeeder.kt | 22 ++++--- 5 files changed, 83 insertions(+), 18 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 6ce75745..2deee7c6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -36,6 +36,7 @@ dependencies { implementation("ch.qos.logback:logback-core:1.4.8") implementation("org.slf4j:slf4j-api:2.0.7") implementation("com.cloudinary:cloudinary:1.0.14") + implementation("net.datafaker:datafaker:2.2.2") annotationProcessor("org.springframework.boot:spring-boot-configuration-processor") implementation("org.springframework.boot:spring-boot-starter-validation:3.1.1") developmentOnly("org.springframework.boot:spring-boot-devtools") diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt index 87e8eee3..4f8ec952 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt @@ -8,16 +8,18 @@ import pt.up.fe.ni.website.backend.config.Logging import pt.up.fe.ni.website.backend.model.seeders.ApplicationSeeder @Component -class ApplicationStartupHook : ApplicationRunner, Logging{ +class ApplicationStartupHook( + val applicationSeeder: ApplicationSeeder +) : ApplicationRunner, Logging { @Value("\${app.debug}") val debug: Boolean = false override fun run(args: ApplicationArguments?) { logger.info("Running Startup hook...") - if(debug){ + if (debug) { logger.info("Running application seeder...") - ApplicationSeeder().seedDatabase() + applicationSeeder.seedDatabase() } } } diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AbstractSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AbstractSeeder.kt index aec90caa..1747ff06 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AbstractSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AbstractSeeder.kt @@ -1,7 +1,13 @@ package pt.up.fe.ni.website.backend.model.seeders -interface AbstractSeeder { +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.repository.CrudRepository - fun createObjects() +@Suppress("SpringJavaInjectionPointsAutowiringInspection") +abstract class AbstractSeeder where T : CrudRepository { + @Autowired + protected lateinit var repository: T + + abstract fun createObjects() } diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt index 6d4add79..cc615f1a 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt @@ -1,8 +1,66 @@ package pt.up.fe.ni.website.backend.model.seeders -class AccountSeeder : AbstractSeeder { +import java.util.* +import net.datafaker.Faker +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.stereotype.Component +import pt.up.fe.ni.website.backend.config.Logging +import pt.up.fe.ni.website.backend.model.Account +import pt.up.fe.ni.website.backend.repository.AccountRepository + +@Component +class AccountSeeder( + private val encoder: PasswordEncoder +) : AbstractSeeder(), Logging { + val faker = Faker() override fun createObjects() { + logger.info("Running account logger...") + for (i in 1..10) { + val account = Account( + faker.name().firstName(), + faker.internet().emailAddress(), + encoder.encode(faker.random().hex(16)), + faker.lorem().sentence(), + Date.from(faker.date().birthday().toInstant()), + photo = faker.internet().image(), + github = null, + linkedin = null + ) + val accountWithSocials = Account( + faker.name().firstName(), + faker.internet().emailAddress(), + encoder.encode(faker.random().hex(16)), + faker.lorem().sentence(), + Date.from(faker.date().birthday().toInstant()), + photo = faker.internet().image(), + github = faker.internet().url(), + linkedin = faker.internet().url() + ) + val accountWithGithub = Account( + faker.name().firstName(), + faker.internet().emailAddress(), + encoder.encode(faker.random().hex(16)), + faker.lorem().sentence(), + Date.from(faker.date().birthday().toInstant()), + photo = faker.internet().image(), + github = faker.internet().url(), + linkedin = null + ) + val accountWithLinkedin = Account( + faker.name().firstName(), + faker.internet().emailAddress(), + encoder.encode(faker.random().hex(16)), + faker.lorem().sentence(), + Date.from(faker.date().birthday().toInstant()), + photo = faker.internet().image(), + github = null, + linkedin = faker.internet().url() + ) + repository.saveAll( + listOf(account, accountWithLinkedin, accountWithSocials, accountWithGithub, accountWithLinkedin) + ) + } } } diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt index 4ef8e356..dd5adecf 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt @@ -1,19 +1,17 @@ package pt.up.fe.ni.website.backend.model.seeders -class ApplicationSeeder { +import org.springframework.stereotype.Component - //NOTE(luisd): these are run in order so you should take care of dependencies of said seeders - private val seeders : List = listOf( - AccountSeeder() - ) +@Component +class ApplicationSeeder( + private val accountSeeder: AccountSeeder +) { + fun seedDatabase() { + // TODO(luisd): delete database + // TODO(luisd): apply schema - fun seedDatabase(){ - //TODO(luisd): delete database - //TODO(luisd): apply schema - - seeders.forEach { - seeder -> seeder.createObjects() - } + // NOTE(luisd): you must consider the dependencies between seeders + accountSeeder.createObjects() } } From f5add0cd4d5730edc59f2215eaa441abdc0d6fa7 Mon Sep 17 00:00:00 2001 From: Rita Lopes Date: Thu, 20 Jun 2024 18:17:53 +0100 Subject: [PATCH 03/10] More seeders. Run seeder only when debug and seeder arg --- build.gradle.kts | 7 ++ .../backend/hooks/ApplicationStartupHook.kt | 16 ++++- .../backend/model/seeders/AbstractSeeder.kt | 3 + .../backend/model/seeders/AccountSeeder.kt | 3 +- .../backend/model/seeders/EventSeeder.kt | 65 +++++++++++++++++++ .../backend/model/seeders/PostSeeder.kt | 35 ++++++++++ .../backend/model/seeders/ProjectSeeder.kt | 34 ++++++++++ .../backend/repository/AccountRepository.kt | 1 + 8 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PostSeeder.kt create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt diff --git a/build.gradle.kts b/build.gradle.kts index 2deee7c6..1e17149d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,7 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.springframework.boot.gradle.tasks.run.BootRun plugins { id("org.springframework.boot") version "3.1.1" @@ -135,6 +136,12 @@ tasks.register("generateDocs") { into(File("docs")) } +tasks.bootRun { + if(project.hasProperty("seed")){ + systemProperties(mapOf("seed" to "true")) + } +} + tasks.register("fixExamples") { dependsOn(tasks.named("openapi3")) doLast { diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt index 4f8ec952..dc3ced67 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt @@ -15,9 +15,23 @@ class ApplicationStartupHook( @Value("\${app.debug}") val debug: Boolean = false + + var seed: Boolean = false + + fun checkSeedArgument() { + try { + val seedProperty = System.getProperty("seed") + if (seedProperty == "true"){ + seed = true + } + } catch (_: NullPointerException ) { } + catch (_: IllegalArgumentException) {} + } + override fun run(args: ApplicationArguments?) { logger.info("Running Startup hook...") - if (debug) { + checkSeedArgument() + if (debug && seed) { logger.info("Running application seeder...") applicationSeeder.seedDatabase() } diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AbstractSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AbstractSeeder.kt index 1747ff06..a627e4f5 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AbstractSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AbstractSeeder.kt @@ -1,11 +1,14 @@ package pt.up.fe.ni.website.backend.model.seeders +import net.datafaker.Faker import org.springframework.beans.factory.annotation.Autowired import org.springframework.data.repository.CrudRepository @Suppress("SpringJavaInjectionPointsAutowiringInspection") abstract class AbstractSeeder where T : CrudRepository { + protected val faker = Faker() + @Autowired protected lateinit var repository: T diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt index cc615f1a..59db80a2 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt @@ -12,10 +12,9 @@ import pt.up.fe.ni.website.backend.repository.AccountRepository class AccountSeeder( private val encoder: PasswordEncoder ) : AbstractSeeder(), Logging { - val faker = Faker() override fun createObjects() { - logger.info("Running account logger...") + logger.info("Running account seeder...") for (i in 1..10) { val account = Account( faker.name().firstName(), diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt new file mode 100644 index 00000000..64d34bc2 --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt @@ -0,0 +1,65 @@ +package pt.up.fe.ni.website.backend.model.seeders + +import java.util.stream.StreamSupport +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component +import pt.up.fe.ni.website.backend.config.Logging +import pt.up.fe.ni.website.backend.model.Event +import pt.up.fe.ni.website.backend.repository.AccountRepository +import pt.up.fe.ni.website.backend.repository.EventRepository + +@Component +class EventSeeder( + @Autowired val accountRepository: AccountRepository +) : AbstractSeeder(), Logging { + + override fun createObjects() { + logger.info("Running event logger...") + val accounts = StreamSupport + .stream(accountRepository.findAll().spliterator(), false) + .limit(10).toList(); + /*for (i in 1..10) { + val event = Event( + faker.lorem().sentence(4), + faker.lorem().sentence(), + listOf(accounts[i]).toMutableList(), + null, + faker.internet().image() + ) + val accountWithSocials = Account( + faker.name().firstName(), + faker.internet().emailAddress(), + encoder.encode(faker.random().hex(16)), + faker.lorem().sentence(), + Date.from(faker.date().birthday().toInstant()), + photo = faker.internet().image(), + github = faker.internet().url(), + linkedin = faker.internet().url() + ) + val accountWithGithub = Account( + faker.name().firstName(), + faker.internet().emailAddress(), + encoder.encode(faker.random().hex(16)), + faker.lorem().sentence(), + Date.from(faker.date().birthday().toInstant()), + photo = faker.internet().image(), + github = faker.internet().url(), + linkedin = null + ) + val accountWithLinkedin = Account( + faker.name().firstName(), + faker.internet().emailAddress(), + encoder.encode(faker.random().hex(16)), + faker.lorem().sentence(), + Date.from(faker.date().birthday().toInstant()), + photo = faker.internet().image(), + github = null, + linkedin = faker.internet().url() + ) + + repository.saveAll( + listOf(account, accountWithLinkedin, accountWithSocials, accountWithGithub, accountWithLinkedin) + ) + }*/ + } +} diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PostSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PostSeeder.kt new file mode 100644 index 00000000..50ea6e7a --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PostSeeder.kt @@ -0,0 +1,35 @@ +package pt.up.fe.ni.website.backend.model.seeders + +import java.util.* +import org.springframework.stereotype.Component +import pt.up.fe.ni.website.backend.config.Logging +import pt.up.fe.ni.website.backend.model.Post +import pt.up.fe.ni.website.backend.model.constants.PostConstants +import pt.up.fe.ni.website.backend.repository.PostRepository + +@Component +class PostSeeder() : AbstractSeeder(), Logging { + + override fun createObjects() { + logger.info("Running post seeder...") + for (i in 1..10) { + val post = Post( + faker.lorem().characters(PostConstants.Title.minSize, PostConstants.Title.maxSize, true, true, true), + faker.lorem().characters(PostConstants.Body.minSize, 500, true, true, true), + faker.internet().url(), + Date.from(faker.date().birthday().toInstant()), + Date.from(faker.date().birthday().toInstant()), + slug = faker.lorem().characters(PostConstants.Slug.minSize, PostConstants.Slug.maxSize), + ) + + val postWithoutDate = Post( + faker.lorem().characters(PostConstants.Title.minSize, PostConstants.Title.maxSize, true, true, true), + faker.lorem().characters(PostConstants.Body.minSize, 500, true, true, true), + faker.internet().url(), + slug = faker.lorem().characters(PostConstants.Slug.minSize, PostConstants.Slug.maxSize, false, false, false), + ) + + repository.saveAll(listOf(post, postWithoutDate)) + } + } +} diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt new file mode 100644 index 00000000..659398e9 --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt @@ -0,0 +1,34 @@ +package pt.up.fe.ni.website.backend.model.seeders + +import org.springframework.stereotype.Component +import pt.up.fe.ni.website.backend.config.Logging +import pt.up.fe.ni.website.backend.model.Project +import pt.up.fe.ni.website.backend.model.constants.ProjectConstants +import pt.up.fe.ni.website.backend.repository.ProjectRepository + +@Component +class ProjectSeeder() : AbstractSeeder(), Logging { + + override fun createObjects() { + logger.info("Running project seeder...") + for (i in 1..10) { + val project = Project( + title = faker.lorem().word(), + description = faker.lorem().paragraph(), + teamMembers = , + associatedRoles = , + slug = faker.internet().slug(), + image = faker.internet().image(), + isArchived = faker.random().nextBoolean(), + technologies = List(faker.random().nextInt()) {faker.lorem().word()}, + slogan = faker.lorem().characters(ProjectConstants.Slogan.minSize, ProjectConstants.Slogan.maxSize, true, true, true), + targetAudience = faker.lorem().sentence(), + github = faker.internet().url(), + links = , + hallOfFame = , + timeline = , + ) + } + } +} + diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/repository/AccountRepository.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/repository/AccountRepository.kt index 3d009f12..96e59614 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/repository/AccountRepository.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/repository/AccountRepository.kt @@ -7,4 +7,5 @@ import pt.up.fe.ni.website.backend.model.Account @Repository interface AccountRepository : CrudRepository { fun findByEmail(email: String): Account? + } From e9be75d4da5259466d07b4e516644e0060e5db8d Mon Sep 17 00:00:00 2001 From: Rita Lopes Date: Thu, 20 Jun 2024 18:18:53 +0100 Subject: [PATCH 04/10] Linter --- build.gradle.kts | 3 +- .../backend/hooks/ApplicationStartupHook.kt | 6 ++-- .../backend/model/seeders/AccountSeeder.kt | 1 - .../backend/model/seeders/EventSeeder.kt | 2 +- .../backend/model/seeders/PostSeeder.kt | 10 ++++-- .../backend/model/seeders/ProjectSeeder.kt | 34 +++++++++---------- .../backend/repository/AccountRepository.kt | 1 - 7 files changed, 28 insertions(+), 29 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 1e17149d..50907e00 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,6 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import org.springframework.boot.gradle.tasks.run.BootRun plugins { id("org.springframework.boot") version "3.1.1" @@ -137,7 +136,7 @@ tasks.register("generateDocs") { } tasks.bootRun { - if(project.hasProperty("seed")){ + if (project.hasProperty("seed")) { systemProperties(mapOf("seed" to "true")) } } diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt index dc3ced67..946d98dd 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt @@ -15,17 +15,15 @@ class ApplicationStartupHook( @Value("\${app.debug}") val debug: Boolean = false - var seed: Boolean = false fun checkSeedArgument() { try { val seedProperty = System.getProperty("seed") - if (seedProperty == "true"){ + if (seedProperty == "true") { seed = true } - } catch (_: NullPointerException ) { } - catch (_: IllegalArgumentException) {} + } catch (_: NullPointerException) { } catch (_: IllegalArgumentException) {} } override fun run(args: ApplicationArguments?) { diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt index 59db80a2..a01961d2 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt @@ -1,7 +1,6 @@ package pt.up.fe.ni.website.backend.model.seeders import java.util.* -import net.datafaker.Faker import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.stereotype.Component import pt.up.fe.ni.website.backend.config.Logging diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt index 64d34bc2..0a79539b 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt @@ -17,7 +17,7 @@ class EventSeeder( logger.info("Running event logger...") val accounts = StreamSupport .stream(accountRepository.findAll().spliterator(), false) - .limit(10).toList(); + .limit(10).toList() /*for (i in 1..10) { val event = Event( faker.lorem().sentence(4), diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PostSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PostSeeder.kt index 50ea6e7a..5a26a1ac 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PostSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PostSeeder.kt @@ -19,14 +19,20 @@ class PostSeeder() : AbstractSeeder(), Logging { faker.internet().url(), Date.from(faker.date().birthday().toInstant()), Date.from(faker.date().birthday().toInstant()), - slug = faker.lorem().characters(PostConstants.Slug.minSize, PostConstants.Slug.maxSize), + slug = faker.lorem().characters(PostConstants.Slug.minSize, PostConstants.Slug.maxSize) ) val postWithoutDate = Post( faker.lorem().characters(PostConstants.Title.minSize, PostConstants.Title.maxSize, true, true, true), faker.lorem().characters(PostConstants.Body.minSize, 500, true, true, true), faker.internet().url(), - slug = faker.lorem().characters(PostConstants.Slug.minSize, PostConstants.Slug.maxSize, false, false, false), + slug = faker.lorem().characters( + PostConstants.Slug.minSize, + PostConstants.Slug.maxSize, + false, + false, + false + ) ) repository.saveAll(listOf(post, postWithoutDate)) diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt index 659398e9..b54c0e0e 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt @@ -3,7 +3,6 @@ package pt.up.fe.ni.website.backend.model.seeders import org.springframework.stereotype.Component import pt.up.fe.ni.website.backend.config.Logging import pt.up.fe.ni.website.backend.model.Project -import pt.up.fe.ni.website.backend.model.constants.ProjectConstants import pt.up.fe.ni.website.backend.repository.ProjectRepository @Component @@ -12,23 +11,22 @@ class ProjectSeeder() : AbstractSeeder(), Logg override fun createObjects() { logger.info("Running project seeder...") for (i in 1..10) { - val project = Project( - title = faker.lorem().word(), - description = faker.lorem().paragraph(), - teamMembers = , - associatedRoles = , - slug = faker.internet().slug(), - image = faker.internet().image(), - isArchived = faker.random().nextBoolean(), - technologies = List(faker.random().nextInt()) {faker.lorem().word()}, - slogan = faker.lorem().characters(ProjectConstants.Slogan.minSize, ProjectConstants.Slogan.maxSize, true, true, true), - targetAudience = faker.lorem().sentence(), - github = faker.internet().url(), - links = , - hallOfFame = , - timeline = , - ) +// val project = Project( +// title = faker.lorem().word(), +// description = faker.lorem().paragraph(), +// teamMembers = , +// associatedRoles = , +// slug = faker.internet().slug(), +// image = faker.internet().image(), +// isArchived = faker.random().nextBoolean(), +// technologies = List(faker.random().nextInt()) {faker.lorem().word()}, +// slogan = faker.lorem().characters(ProjectConstants.Slogan.minSize, ProjectConstants.Slogan.maxSize, true, true, true), +// targetAudience = faker.lorem().sentence(), +// github = faker.internet().url(), +// links = , +// hallOfFame = , +// timeline = , +// ) } } } - diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/repository/AccountRepository.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/repository/AccountRepository.kt index 96e59614..3d009f12 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/repository/AccountRepository.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/repository/AccountRepository.kt @@ -7,5 +7,4 @@ import pt.up.fe.ni.website.backend.model.Account @Repository interface AccountRepository : CrudRepository { fun findByEmail(email: String): Account? - } From 8282539cfc42f354596407982d0c0bc329a3fc38 Mon Sep 17 00:00:00 2001 From: Vidal322 Date: Fri, 18 Oct 2024 14:00:31 +0100 Subject: [PATCH 05/10] all seeders working. Need more volume --- .../backend/model/seeders/AccountSeeder.kt | 31 +++++- .../backend/model/seeders/ActivitySeeder.kt | 34 +++++++ .../model/seeders/ApplicationSeeder.kt | 4 +- .../model/seeders/CustomWebsiteSeeder.kt | 44 +++++++++ .../backend/model/seeders/EventSeeder.kt | 95 ++++++++++--------- .../backend/model/seeders/GenerationSeeder.kt | 31 ++++++ .../model/seeders/PerActivityRoleSeeder.kt | 17 ++++ .../backend/model/seeders/ProjectSeeder.kt | 78 +++++++++++---- .../backend/model/seeders/RoleSeeder.kt | 51 ++++++++++ .../model/seeders/TimeLineEventSeeder.kt | 41 ++++++++ .../repository/CustomWebsiteRepository.kt | 8 ++ .../repository/TimeLineEventRepository.kt | 8 ++ 12 files changed, 374 insertions(+), 68 deletions(-) create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/CustomWebsiteSeeder.kt create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/GenerationSeeder.kt create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PerActivityRoleSeeder.kt create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/RoleSeeder.kt create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/TimeLineEventSeeder.kt create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/repository/CustomWebsiteRepository.kt create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/repository/TimeLineEventRepository.kt diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt index a01961d2..5c6b5485 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt @@ -55,7 +55,36 @@ class AccountSeeder( github = null, linkedin = faker.internet().url() ) - + val accountWithoutBio = Account( + faker.name().firstName(), + faker.internet().emailAddress(), + encoder.encode(faker.random().hex(16)), + null, + Date.from(faker.date().birthday().toInstant()), + photo = faker.internet().image(), + github = faker.internet().url(), + linkedin = faker.internet().url() + ) + val accountWithoutPhoto = Account( + faker.name().firstName(), + faker.internet().emailAddress(), + encoder.encode(faker.random().hex(16)), + faker.lorem().sentence(), + Date.from(faker.date().birthday().toInstant()), + null, + github = faker.internet().url(), + linkedin = faker.internet().url() + ) + val accountWithoutBioAndPhoto = Account( + faker.name().firstName(), + faker.internet().emailAddress(), + encoder.encode(faker.random().hex(16)), + null, + Date.from(faker.date().birthday().toInstant()), + null, + github = faker.internet().url(), + linkedin = faker.internet().url() + ) repository.saveAll( listOf(account, accountWithLinkedin, accountWithSocials, accountWithGithub, accountWithLinkedin) ) diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt new file mode 100644 index 00000000..99db16fd --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt @@ -0,0 +1,34 @@ +package pt.up.fe.ni.website.backend.model.seeders + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component +import pt.up.fe.ni.website.backend.config.Logging +import pt.up.fe.ni.website.backend.model.Event +import pt.up.fe.ni.website.backend.repository.AccountRepository +import pt.up.fe.ni.website.backend.repository.ActivityRepository +import pt.up.fe.ni.website.backend.repository.PerActivityRoleRepository + +@Component +class ActivitySeeder( + @Autowired val eventSeeder: EventSeeder, + @Autowired val projectSeeder: ProjectSeeder, + @Autowired val accountRepository: AccountRepository, + @Autowired val perActivityRoleRepository: PerActivityRoleRepository +) : AbstractSeeder, Event, Long>(), Logging { + + val accounts = accountRepository.findAll().toList() // Fetch all accounts + val perActivityRoles = perActivityRoleRepository.findAll().toList() // Fetch all roles + + override fun createObjects() { + // Delegate seeding to the EventSeeder and ProjectSeeder + logger.info("Starting Activity seeding process") + + // Seed Events + eventSeeder.createObjects() + + // Seed Projects + projectSeeder.createObjects() + + logger.info("Finished seeding activities (events and projects)") + } +} diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt index dd5adecf..bce922a4 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt @@ -4,7 +4,8 @@ import org.springframework.stereotype.Component @Component class ApplicationSeeder( - private val accountSeeder: AccountSeeder + private val accountSeeder: AccountSeeder, + private val eventSeeder: EventSeeder ) { fun seedDatabase() { @@ -13,5 +14,6 @@ class ApplicationSeeder( // NOTE(luisd): you must consider the dependencies between seeders accountSeeder.createObjects() + eventSeeder.createObjects() } } diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/CustomWebsiteSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/CustomWebsiteSeeder.kt new file mode 100644 index 00000000..be341a91 --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/CustomWebsiteSeeder.kt @@ -0,0 +1,44 @@ +package pt.up.fe.ni.website.backend.model.seeders + +import org.springframework.stereotype.Component +import pt.up.fe.ni.website.backend.config.Logging +import pt.up.fe.ni.website.backend.model.CustomWebsite +import pt.up.fe.ni.website.backend.repository.CustomWebsiteRepository + +@Component +class CustomWebsiteSeeder() : AbstractSeeder(), Logging { + + override fun createObjects() { + if (repository.count() == 0L) { + logger.info("Seeding CustomWebsite data...") + + val customWebsites = listOf( + CustomWebsite( + url = "https://ai-project.com", + iconPath = "/images/icons/ai_project.png", + label = "AI Project Website" + ), + CustomWebsite( + url = "https://ai-project.com/docs", + iconPath = "/images/icons/docs.png", + label = "AI Project Documentation" + ), + CustomWebsite( + url = "https://blockchain-project.com", + iconPath = "/images/icons/blockchain_project.png", + label = "Blockchain Project Website" + ), + CustomWebsite( + url = "https://blockchain-project.com/whitepaper", + iconPath = "/images/icons/whitepaper.png", + label = "Blockchain Project Whitepaper" + ) + ) + + repository.saveAll(customWebsites) + logger.info("CustomWebsite data seeded successfully.") + } else { + logger.info("CustomWebsite data already exists, skipping seeding.") + } + } +} diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt index 0a79539b..3f0abf80 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt @@ -1,65 +1,66 @@ package pt.up.fe.ni.website.backend.model.seeders -import java.util.stream.StreamSupport +import java.util.Date import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component import pt.up.fe.ni.website.backend.config.Logging import pt.up.fe.ni.website.backend.model.Event +import pt.up.fe.ni.website.backend.model.embeddable.DateInterval import pt.up.fe.ni.website.backend.repository.AccountRepository import pt.up.fe.ni.website.backend.repository.EventRepository +import pt.up.fe.ni.website.backend.repository.PerActivityRoleRepository @Component class EventSeeder( - @Autowired val accountRepository: AccountRepository + @Autowired val accountRepository: AccountRepository, + @Autowired val perActivityRoleRepository: PerActivityRoleRepository ) : AbstractSeeder(), Logging { + val accounts = accountRepository.findAll().toList() + val perActivityRoles = perActivityRoleRepository.findAll().toList() + override fun createObjects() { - logger.info("Running event logger...") - val accounts = StreamSupport - .stream(accountRepository.findAll().spliterator(), false) - .limit(10).toList() - /*for (i in 1..10) { - val event = Event( - faker.lorem().sentence(4), - faker.lorem().sentence(), - listOf(accounts[i]).toMutableList(), - null, - faker.internet().image() - ) - val accountWithSocials = Account( - faker.name().firstName(), - faker.internet().emailAddress(), - encoder.encode(faker.random().hex(16)), - faker.lorem().sentence(), - Date.from(faker.date().birthday().toInstant()), - photo = faker.internet().image(), - github = faker.internet().url(), - linkedin = faker.internet().url() - ) - val accountWithGithub = Account( - faker.name().firstName(), - faker.internet().emailAddress(), - encoder.encode(faker.random().hex(16)), - faker.lorem().sentence(), - Date.from(faker.date().birthday().toInstant()), - photo = faker.internet().image(), - github = faker.internet().url(), - linkedin = null - ) - val accountWithLinkedin = Account( - faker.name().firstName(), - faker.internet().emailAddress(), - encoder.encode(faker.random().hex(16)), - faker.lorem().sentence(), - Date.from(faker.date().birthday().toInstant()), - photo = faker.internet().image(), - github = null, - linkedin = faker.internet().url() - ) + if (repository.count() == 0L) { + logger.info("Seeding Event data...") + + val events = listOf( + Event( + title = "Tech Conference 2024", + description = "A yearly tech conference bringing together industry experts and enthusiasts.", + teamMembers = accounts.subList(0, 3).toMutableList(), + associatedRoles = perActivityRoles.subList(0, 2).toMutableList(), + slug = "tech-conference-2024", + image = "conference_image.png", + registerUrl = "https://conference.com/register", + dateInterval = DateInterval( + startDate = Date.from(faker.date().birthday().toInstant()), + endDate = Date.from(faker.date().birthday().toInstant()) - repository.saveAll( - listOf(account, accountWithLinkedin, accountWithSocials, accountWithGithub, accountWithLinkedin) + ), + location = "Porto, Portugal", + category = "Conference" + ), + Event( + title = "Hackathon 2024", + description = "A 48-hour hackathon for students and professionals to collaborate and innovate.", + teamMembers = accounts.subList(3, 6).toMutableList(), // Assume next 3 accounts are team members + associatedRoles = perActivityRoles.subList(2, 4).toMutableList(), // Next 2 roles are related + slug = "hackathon-2024", + image = "hackathon_image.png", + registerUrl = "https://hackathon.com/register", + dateInterval = DateInterval( + startDate = Date.from(faker.date().birthday().toInstant()), + endDate = Date.from(faker.date().birthday().toInstant()) + ), + location = "Lisbon, Portugal", + category = "Hackathon" + ) ) - }*/ + + repository.saveAll(events) + logger.info("Event data seeded successfully.") + } else { + logger.info("Event data already exists, skipping seeding.") + } } } diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/GenerationSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/GenerationSeeder.kt new file mode 100644 index 00000000..466a23f8 --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/GenerationSeeder.kt @@ -0,0 +1,31 @@ +package pt.up.fe.ni.website.backend.model.seeders + +import org.springframework.stereotype.Component +import pt.up.fe.ni.website.backend.config.Logging +import pt.up.fe.ni.website.backend.model.Generation +import pt.up.fe.ni.website.backend.repository.GenerationRepository + +@Component +class GenerationSeeder() : AbstractSeeder(), Logging { + + override fun createObjects() { + logger.info("Running Generation seeder...") + + if (repository.count() > 0) { + logger.info("Skipping Generation seeding as generations already exist.") + return + } + + val generations = listOf( + Generation( + schoolYear = "2020/2021" + ), + Generation( + schoolYear = "2021/2022" + ) + ) + + repository.saveAll(generations) + logger.info("Seeded ${generations.size} generations into the system.") + } +} diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PerActivityRoleSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PerActivityRoleSeeder.kt new file mode 100644 index 00000000..19222c93 --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PerActivityRoleSeeder.kt @@ -0,0 +1,17 @@ +package pt.up.fe.ni.website.backend.model.seeders + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component +import pt.up.fe.ni.website.backend.config.Logging +import pt.up.fe.ni.website.backend.model.PerActivityRole +import pt.up.fe.ni.website.backend.repository.PerActivityRoleRepository +import pt.up.fe.ni.website.backend.repository.RoleRepository + +@Component +class PerActivityRoleSeeder( + @Autowired roleRepository: RoleRepository +) : AbstractSeeder(), Logging { + + override fun createObjects() { + } +} diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt index b54c0e0e..03b006cc 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt @@ -1,32 +1,72 @@ package pt.up.fe.ni.website.backend.model.seeders +import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component import pt.up.fe.ni.website.backend.config.Logging import pt.up.fe.ni.website.backend.model.Project +import pt.up.fe.ni.website.backend.repository.AccountRepository +import pt.up.fe.ni.website.backend.repository.CustomWebsiteRepository +import pt.up.fe.ni.website.backend.repository.PerActivityRoleRepository import pt.up.fe.ni.website.backend.repository.ProjectRepository +import pt.up.fe.ni.website.backend.repository.TimeLineEventRepository @Component -class ProjectSeeder() : AbstractSeeder(), Logging { +class ProjectSeeder( + @Autowired val accountRepository: AccountRepository, + @Autowired val perActivityRoleRepository: PerActivityRoleRepository, + @Autowired val customWebsiteRepository: CustomWebsiteRepository, + @Autowired val timelineEventRepository: TimeLineEventRepository +) : AbstractSeeder(), Logging { + + val accounts = accountRepository.findAll().toList() + val perActivityRoles = perActivityRoleRepository.findAll().toList() + + val customWebsites = customWebsiteRepository.findAll().toList() + val timelineEvents = timelineEventRepository.findAll().toList() override fun createObjects() { - logger.info("Running project seeder...") - for (i in 1..10) { -// val project = Project( -// title = faker.lorem().word(), -// description = faker.lorem().paragraph(), -// teamMembers = , -// associatedRoles = , -// slug = faker.internet().slug(), -// image = faker.internet().image(), -// isArchived = faker.random().nextBoolean(), -// technologies = List(faker.random().nextInt()) {faker.lorem().word()}, -// slogan = faker.lorem().characters(ProjectConstants.Slogan.minSize, ProjectConstants.Slogan.maxSize, true, true, true), -// targetAudience = faker.lorem().sentence(), -// github = faker.internet().url(), -// links = , -// hallOfFame = , -// timeline = , -// ) + if (repository.count() == 0L) { + logger.info("Seeding Project data...") + + val projects = listOf( + Project( + title = "AI Research Project", + description = "A project focused on developing AI models for real-time data analysis.", + teamMembers = accounts.subList(0, 3).toMutableList(), + associatedRoles = perActivityRoles.subList(0, 2).toMutableList(), + slug = "ai-research-project", + image = "ai_project_image.png", + isArchived = false, + technologies = listOf("Python", "TensorFlow", "Keras"), + slogan = "Transforming data with AI", + targetAudience = "Researchers, Data Scientists", + github = "https://github.com/research-ai", + links = customWebsites.subList(0, 2), + hallOfFame = accounts.subList(3, 4).toMutableList(), + timeline = timelineEvents.subList(0, 2) + ), + Project( + title = "Blockchain Development Project", + description = "Building a decentralized application using blockchain technology.", + teamMembers = accounts.subList(3, 6).toMutableList(), + associatedRoles = perActivityRoles.subList(2, 4).toMutableList(), + slug = "blockchain-dev-project", + image = "blockchain_project_image.png", + isArchived = false, + technologies = listOf("Solidity", "Ethereum", "Web3"), + slogan = "Decentralizing the future", + targetAudience = "Developers, Fintech Enthusiasts", + github = "https://github.com/blockchain-dev", + links = customWebsites.subList(2, 4), + hallOfFame = accounts.subList(6, 7).toMutableList(), + timeline = timelineEvents.subList(2, 4) + ) + ) + + repository.saveAll(projects) + logger.info("Project data seeded successfully.") + } else { + logger.info("Project data already exists, skipping seeding.") } } } diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/RoleSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/RoleSeeder.kt new file mode 100644 index 00000000..c616c7e0 --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/RoleSeeder.kt @@ -0,0 +1,51 @@ +package pt.up.fe.ni.website.backend.model.seeders + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component +import pt.up.fe.ni.website.backend.config.Logging +import pt.up.fe.ni.website.backend.model.Role +import pt.up.fe.ni.website.backend.model.permissions.Permission +import pt.up.fe.ni.website.backend.model.permissions.Permissions +import pt.up.fe.ni.website.backend.repository.AccountRepository +import pt.up.fe.ni.website.backend.repository.GenerationRepository +import pt.up.fe.ni.website.backend.repository.RoleRepository + +@Component +class RoleSeeder( + @Autowired private val roleRepository: RoleRepository, + @Autowired private val accountRepository: AccountRepository, + @Autowired private val generationRepository: GenerationRepository +) : AbstractSeeder(), Logging { + + override fun createObjects() { + logger.info("Running Role seeder...") + + if (roleRepository.count() > 0) { + logger.info("Skipping Role seeding as roles already exist.") + return + } + + val currentGeneration = generationRepository.findAllSchoolYearOrdered().firstOrNull() + + val roles = listOf( + Role( + name = "President", + isSection = true, + permissions = Permissions(listOf(Permission.EDIT_ACTIVITY)) + ), + Role( + name = "Vice President", + isSection = true, + permissions = Permissions(listOf(Permission.EDIT_ACTIVITY)) + ), + Role( + name = "Member", + isSection = false, + permissions = Permissions(listOf(Permission.VIEW_ACTIVITY)) + ) + ) + + roleRepository.saveAll(roles) + logger.info("Seeded ${roles.size} roles into the system.") + } +} diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/TimeLineEventSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/TimeLineEventSeeder.kt new file mode 100644 index 00000000..25fa0a98 --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/TimeLineEventSeeder.kt @@ -0,0 +1,41 @@ +package pt.up.fe.ni.website.backend.model.seeders + +import java.util.Date +import org.springframework.stereotype.Component +import pt.up.fe.ni.website.backend.config.Logging +import pt.up.fe.ni.website.backend.model.TimelineEvent +import pt.up.fe.ni.website.backend.repository.TimeLineEventRepository + +@Component +class TimeLineEventSeeder() : AbstractSeeder(), Logging { + + override fun createObjects() { + if (repository.count() == 0L) { + logger.info("Seeding TimelineEvent data...") + + val timelineEvents = listOf( + TimelineEvent( + date = Date(1672531200000), + description = "Project Conceptualization" + ), + TimelineEvent( + date = Date(1675123200000), + description = "First Prototype Developed" + ), + TimelineEvent( + date = Date(1677801600000), + description = "Initial User Testing" + ), + TimelineEvent( + date = Date(1680476400000), // Example: April 1, 2023 + description = "Launch of Beta Version" + ) + ) + + repository.saveAll(timelineEvents) + logger.info("TimelineEvent data seeded successfully.") + } else { + logger.info("TimelineEvent data already exists, skipping seeding.") + } + } +} diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/repository/CustomWebsiteRepository.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/repository/CustomWebsiteRepository.kt new file mode 100644 index 00000000..c35990ff --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/repository/CustomWebsiteRepository.kt @@ -0,0 +1,8 @@ +package pt.up.fe.ni.website.backend.repository + +import org.springframework.data.repository.CrudRepository +import org.springframework.stereotype.Repository +import pt.up.fe.ni.website.backend.model.CustomWebsite + +@Repository +interface CustomWebsiteRepository : CrudRepository diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/repository/TimeLineEventRepository.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/repository/TimeLineEventRepository.kt new file mode 100644 index 00000000..dd5b3c26 --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/repository/TimeLineEventRepository.kt @@ -0,0 +1,8 @@ +package pt.up.fe.ni.website.backend.repository + +import org.springframework.data.repository.CrudRepository +import org.springframework.stereotype.Repository +import pt.up.fe.ni.website.backend.model.TimelineEvent + +@Repository +interface TimeLineEventRepository : CrudRepository From aea42f0882232d5ea3347928778ed9c1bdb559a9 Mon Sep 17 00:00:00 2001 From: Pedro Vidal Date: Fri, 15 Nov 2024 23:11:33 +0000 Subject: [PATCH 06/10] Seeders working --- .../backend/hooks/ApplicationStartupHook.kt | 6 +- .../fe/ni/website/backend/model/Activity.kt | 3 +- .../up/fe/ni/website/backend/model/Project.kt | 5 +- .../backend/model/seeders/AccountSeeder.kt | 182 +++++++++++------- .../backend/model/seeders/ActivitySeeder.kt | 16 +- .../model/seeders/ApplicationSeeder.kt | 29 ++- .../model/seeders/CustomWebsiteSeeder.kt | 103 +++++++++- .../backend/model/seeders/EventSeeder.kt | 104 ++++++++-- .../backend/model/seeders/GenerationSeeder.kt | 20 +- .../model/seeders/PerActivityRoleSeeder.kt | 77 +++++++- .../backend/model/seeders/PostSeeder.kt | 46 +++-- .../backend/model/seeders/ProjectSeeder.kt | 96 +++++++-- .../backend/model/seeders/RoleSeeder.kt | 16 +- .../model/seeders/TimeLineEventSeeder.kt | 64 +++++- .../service/database/DatabaseService.kt | 93 +++++++++ src/main/resources/application.properties | 2 + 16 files changed, 695 insertions(+), 167 deletions(-) create mode 100644 src/main/kotlin/pt/up/fe/ni/website/backend/service/database/DatabaseService.kt diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt index 946d98dd..cface7db 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/hooks/ApplicationStartupHook.kt @@ -13,9 +13,9 @@ class ApplicationStartupHook( ) : ApplicationRunner, Logging { @Value("\${app.debug}") - val debug: Boolean = false + val debug: Boolean = true // false - var seed: Boolean = false + var seed: Boolean = true // false fun checkSeedArgument() { try { @@ -28,7 +28,7 @@ class ApplicationStartupHook( override fun run(args: ApplicationArguments?) { logger.info("Running Startup hook...") - checkSeedArgument() + // checkSeedArgument() if (debug && seed) { logger.info("Running application seeder...") applicationSeeder.seedDatabase() diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/Activity.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/Activity.kt index 3b2b81c0..657a9072 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/Activity.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/Activity.kt @@ -2,7 +2,6 @@ package pt.up.fe.ni.website.backend.model import com.fasterxml.jackson.annotation.JsonIgnore import com.fasterxml.jackson.annotation.JsonProperty -import jakarta.persistence.CascadeType import jakarta.persistence.Column import jakarta.persistence.Entity import jakarta.persistence.FetchType @@ -32,7 +31,7 @@ abstract class Activity( @OneToMany(fetch = FetchType.EAGER) open val teamMembers: MutableList, - @OneToMany(cascade = [CascadeType.ALL], mappedBy = "activity") + @OneToMany(/*cascade = [CascadeType.ALL],*/ mappedBy = "activity") @JsonIgnore // TODO: Decide if we want to return perRoles (or IDs) by default open val associatedRoles: MutableList<@Valid PerActivityRole> = mutableListOf(), diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/Project.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/Project.kt index 962b77bb..29f7beae 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/Project.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/Project.kt @@ -1,6 +1,5 @@ package pt.up.fe.ni.website.backend.model -import jakarta.persistence.CascadeType import jakarta.persistence.Entity import jakarta.persistence.FetchType import jakarta.persistence.JoinColumn @@ -36,14 +35,14 @@ class Project( var github: String? = null, @JoinColumn - @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER) + @OneToMany(/*cascade = [CascadeType.ALL],)*/ fetch = FetchType.EAGER) val links: List<@Valid CustomWebsite> = emptyList(), @JoinColumn @OneToMany(fetch = FetchType.EAGER) var hallOfFame: MutableList = mutableListOf(), - @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER) + @OneToMany(/*cascade = [CascadeType.ALL],*/fetch = FetchType.EAGER) @OrderBy("date") val timeline: List<@Valid TimelineEvent> = emptyList(), diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt index 5c6b5485..cf625a89 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt @@ -1,93 +1,145 @@ package pt.up.fe.ni.website.backend.model.seeders import java.util.* +import org.springframework.beans.factory.annotation.Autowired import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.stereotype.Component import pt.up.fe.ni.website.backend.config.Logging import pt.up.fe.ni.website.backend.model.Account import pt.up.fe.ni.website.backend.repository.AccountRepository +import pt.up.fe.ni.website.backend.repository.RoleRepository @Component class AccountSeeder( - private val encoder: PasswordEncoder + private val encoder: PasswordEncoder, + @Autowired private val roleRepository: RoleRepository ) : AbstractSeeder(), Logging { override fun createObjects() { logger.info("Running account seeder...") - for (i in 1..10) { - val account = Account( - faker.name().firstName(), - faker.internet().emailAddress(), - encoder.encode(faker.random().hex(16)), - faker.lorem().sentence(), - Date.from(faker.date().birthday().toInstant()), + + // Fetch all roles from the database + val roles = roleRepository.findAll().toList() + if (roles.isEmpty()) { + logger.warn("No roles found in the database. Accounts will be created without roles.") + } + + val accounts = listOf( + // Standard Account + Account( + name = "Alice Standard", + email = "alice.standard@example.com", + password = encoder.encode("password123"), + bio = "A standard user with all fields filled.", + birthDate = Date.from(faker.date().birthday(25, 35).toInstant()), + photo = faker.internet().image(), + github = faker.internet().url(), + linkedin = faker.internet().url(), + roles = roles.shuffled().take(2).toMutableList() + ), + // Account Without Photo + Account( + name = "Bob NoPhoto", + email = "bob.nophoto@example.com", + password = encoder.encode("securepass"), + bio = "An active user without a profile picture.", + birthDate = Date.from(faker.date().birthday(30, 40).toInstant()), + photo = null, + github = faker.internet().url(), + linkedin = faker.internet().url(), + roles = roles.shuffled().take(1).toMutableList() + ), + // Account Without Bio + Account( + name = "Charlie NoBio", + email = "charlie.nobio@example.com", + password = encoder.encode("anothersecurepass"), + bio = null, + birthDate = Date.from(faker.date().birthday(18, 28).toInstant()), photo = faker.internet().image(), github = null, - linkedin = null - ) - val accountWithSocials = Account( - faker.name().firstName(), - faker.internet().emailAddress(), - encoder.encode(faker.random().hex(16)), - faker.lorem().sentence(), - Date.from(faker.date().birthday().toInstant()), + linkedin = null, + roles = roles.shuffled().take(1).toMutableList() + ), + // Account Without Bio or Photo + Account( + name = "Dana Minimal", + email = "dana.minimal@example.com", + password = encoder.encode("minpass"), + bio = null, + birthDate = Date.from(faker.date().birthday(20, 30).toInstant()), + photo = null, + github = null, + linkedin = faker.internet().url(), + roles = roles.shuffled().take(1).toMutableList() + ), + // Account with Long Bio + Account( + name = "Eve LongBio", + email = "eve.longbio@example.com", + password = encoder.encode("verysecure"), + bio = faker.lorem().paragraph(5), + birthDate = Date.from(faker.date().birthday(35, 45).toInstant()), photo = faker.internet().image(), github = faker.internet().url(), - linkedin = faker.internet().url() - ) - val accountWithGithub = Account( - faker.name().firstName(), - faker.internet().emailAddress(), - encoder.encode(faker.random().hex(16)), - faker.lorem().sentence(), - Date.from(faker.date().birthday().toInstant()), + linkedin = faker.internet().url(), + roles = roles.shuffled().take(3).toMutableList() + ), + // Account with Single Role + Account( + name = "Grace SingleRole", + email = "grace.singlerole@example.com", + password = encoder.encode("singlepass"), + bio = "User with only one role.", + birthDate = Date.from(faker.date().birthday(22, 32).toInstant()), photo = faker.internet().image(), github = faker.internet().url(), - linkedin = null - ) - val accountWithLinkedin = Account( - faker.name().firstName(), - faker.internet().emailAddress(), - encoder.encode(faker.random().hex(16)), - faker.lorem().sentence(), - Date.from(faker.date().birthday().toInstant()), - photo = faker.internet().image(), + linkedin = faker.internet().url(), + roles = roles.shuffled().take(1).toMutableList() + ), + // Account with All Optional Fields Null + Account( + name = "Henry AllNull", + email = "henry.allnull@example.com", + password = encoder.encode("nullpass"), + bio = null, + birthDate = null, + photo = null, github = null, - linkedin = faker.internet().url() - ) - val accountWithoutBio = Account( - faker.name().firstName(), - faker.internet().emailAddress(), - encoder.encode(faker.random().hex(16)), - null, - Date.from(faker.date().birthday().toInstant()), + linkedin = null, + roles = mutableListOf() + ), + // Account with Edge Case Birth Date + Account( + name = "Ivy EdgeDate", + email = "ivy.edgedate@example.com", + password = encoder.encode("edgepass"), + bio = "Born on January 1st, 2000.", + birthDate = Date.from( + Calendar.getInstance().apply { + set(2000, Calendar.JANUARY, 1) + }.time.toInstant() + ), photo = faker.internet().image(), github = faker.internet().url(), - linkedin = faker.internet().url() - ) - val accountWithoutPhoto = Account( - faker.name().firstName(), - faker.internet().emailAddress(), - encoder.encode(faker.random().hex(16)), - faker.lorem().sentence(), - Date.from(faker.date().birthday().toInstant()), - null, - github = faker.internet().url(), - linkedin = faker.internet().url() - ) - val accountWithoutBioAndPhoto = Account( - faker.name().firstName(), - faker.internet().emailAddress(), - encoder.encode(faker.random().hex(16)), - null, - Date.from(faker.date().birthday().toInstant()), - null, + linkedin = faker.internet().url(), + roles = roles.shuffled().take(1).toMutableList() + ), + // Account with Special Characters in Name + Account( + name = "Zoë Löwe", + email = "zoe.lowe@example.com", + password = encoder.encode("specialpass"), + bio = "User with special characters in their name.", + birthDate = Date.from(faker.date().birthday(20, 40).toInstant()), + photo = faker.internet().image(), github = faker.internet().url(), - linkedin = faker.internet().url() - ) - repository.saveAll( - listOf(account, accountWithLinkedin, accountWithSocials, accountWithGithub, accountWithLinkedin) + linkedin = faker.internet().url(), + roles = roles.shuffled().take(2).toMutableList() ) - } + ) + + // Save all the accounts + repository.saveAll(accounts) } } diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt index 99db16fd..5a439a5b 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt @@ -4,30 +4,26 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component import pt.up.fe.ni.website.backend.config.Logging import pt.up.fe.ni.website.backend.model.Event -import pt.up.fe.ni.website.backend.repository.AccountRepository import pt.up.fe.ni.website.backend.repository.ActivityRepository -import pt.up.fe.ni.website.backend.repository.PerActivityRoleRepository @Component class ActivitySeeder( @Autowired val eventSeeder: EventSeeder, @Autowired val projectSeeder: ProjectSeeder, - @Autowired val accountRepository: AccountRepository, - @Autowired val perActivityRoleRepository: PerActivityRoleRepository + @Autowired val perActivityRoleSeeder: PerActivityRoleSeeder ) : AbstractSeeder, Event, Long>(), Logging { - val accounts = accountRepository.findAll().toList() // Fetch all accounts - val perActivityRoles = perActivityRoleRepository.findAll().toList() // Fetch all roles - override fun createObjects() { // Delegate seeding to the EventSeeder and ProjectSeeder - logger.info("Starting Activity seeding process") + logger.info("Running Activity Seeder") - // Seed Events - eventSeeder.createObjects() + // Seed Roles per Activity (needs to add projects and events later) + perActivityRoleSeeder.createObjects() // Seed Projects projectSeeder.createObjects() + // Seed Events + eventSeeder.createObjects() logger.info("Finished seeding activities (events and projects)") } diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt index bce922a4..17f1b8cf 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ApplicationSeeder.kt @@ -1,19 +1,36 @@ package pt.up.fe.ni.website.backend.model.seeders +import jakarta.persistence.EntityManager +import javax.sql.DataSource +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.ApplicationContext import org.springframework.stereotype.Component +import pt.up.fe.ni.website.backend.service.database.DatabaseService @Component class ApplicationSeeder( private val accountSeeder: AccountSeeder, - private val eventSeeder: EventSeeder + private val activitySeeder: ActivitySeeder, + private val postSeeder: PostSeeder, + private val generationSeeder: GenerationSeeder, + private val roleSeeder: RoleSeeder, + private val customWebsiteSeeder: CustomWebsiteSeeder, + @Autowired + private val appContext: ApplicationContext, + private val databaseService: DatabaseService ) { - fun seedDatabase() { - // TODO(luisd): delete database - // TODO(luisd): apply schema + val dataSource = appContext.getBean(DataSource::class.java) + databaseService.cleanDataSource(dataSource) + + val entityManager = appContext.getBean(EntityManager::class.java) + databaseService.cleanEntityManager(entityManager) - // NOTE(luisd): you must consider the dependencies between seeders + roleSeeder.createObjects() + customWebsiteSeeder.createObjects() accountSeeder.createObjects() - eventSeeder.createObjects() + activitySeeder.createObjects() + postSeeder.createObjects() + generationSeeder.createObjects() } } diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/CustomWebsiteSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/CustomWebsiteSeeder.kt index be341a91..10e2729d 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/CustomWebsiteSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/CustomWebsiteSeeder.kt @@ -10,31 +10,116 @@ class CustomWebsiteSeeder() : AbstractSeeder { + return perActivityRoles.shuffled().take(count).toMutableList() + } val events = listOf( Event( title = "Tech Conference 2024", description = "A yearly tech conference bringing together industry experts and enthusiasts.", teamMembers = accounts.subList(0, 3).toMutableList(), - associatedRoles = perActivityRoles.subList(0, 2).toMutableList(), + associatedRoles = getRandomRoles(2), slug = "tech-conference-2024", image = "conference_image.png", registerUrl = "https://conference.com/register", - dateInterval = DateInterval( - startDate = Date.from(faker.date().birthday().toInstant()), - endDate = Date.from(faker.date().birthday().toInstant()) - - ), + dateInterval = generateDateInterval(10, 3), location = "Porto, Portugal", category = "Conference" ), Event( title = "Hackathon 2024", description = "A 48-hour hackathon for students and professionals to collaborate and innovate.", - teamMembers = accounts.subList(3, 6).toMutableList(), // Assume next 3 accounts are team members - associatedRoles = perActivityRoles.subList(2, 4).toMutableList(), // Next 2 roles are related + teamMembers = accounts.subList(3, 6).toMutableList(), + associatedRoles = getRandomRoles(3), slug = "hackathon-2024", image = "hackathon_image.png", registerUrl = "https://hackathon.com/register", - dateInterval = DateInterval( - startDate = Date.from(faker.date().birthday().toInstant()), - endDate = Date.from(faker.date().birthday().toInstant()) - ), + dateInterval = generateDateInterval(20, 2), location = "Lisbon, Portugal", category = "Hackathon" + ), + Event( + title = "AI & Machine Learning Workshop", + description = "A hands-on workshop exploring AI and ML techniques.", + teamMembers = accounts.subList(1, 4).toMutableList(), + associatedRoles = getRandomRoles(1), + slug = "ai-ml-workshop", + image = "ai_workshop_image.png", + registerUrl = "https://aiworkshop.com/register", + dateInterval = generateDateInterval(30, 1), + location = "Braga, Portugal", + category = "Workshop" + ), + Event( + title = "Startup Pitch Night", + description = "An evening for startups to pitch their ideas to investors.", + teamMembers = accounts.subList(2, 5).toMutableList(), + associatedRoles = getRandomRoles(2), + slug = "startup-pitch-night", + image = "pitch_night_image.png", + registerUrl = "https://startupnight.com/register", + dateInterval = generateDateInterval(15, 1), + location = "Coimbra, Portugal", + category = "Networking" + ), + Event( + title = "Cybersecurity Summit", + description = "Discussing the latest trends and threats in cybersecurity.", + teamMembers = accounts.subList(0, 2).toMutableList(), + associatedRoles = getRandomRoles(3), + slug = "cybersecurity-summit", + image = "cybersecurity_image.png", + registerUrl = "https://cybersummit.com/register", + dateInterval = generateDateInterval(25, 2), + location = "Aveiro, Portugal", + category = "Conference" + ), + Event( + title = "Women in Tech Meetup", + description = "An inspiring meetup celebrating women in technology.", + teamMembers = accounts.subList(5, 7).toMutableList(), + associatedRoles = getRandomRoles(1), + slug = "women-in-tech-meetup", + image = "women_in_tech_image.png", + registerUrl = "https://womenintech.com/register", + dateInterval = generateDateInterval(5, 1), + location = "Porto, Portugal", + category = "Meetup" + ), + Event( + title = "Game Development Bootcamp", + description = "A weekend bootcamp for aspiring game developers.", + teamMembers = accounts.subList(4, 6).toMutableList(), + associatedRoles = getRandomRoles(2), + slug = "game-dev-bootcamp", + image = "game_dev_image.png", + registerUrl = "https://gamedevbootcamp.com/register", + dateInterval = generateDateInterval(40, 3), + location = "Lisbon, Portugal", + category = "Bootcamp" + ), + Event( + title = "Data Science Career Fair", + description = "Connecting data scientists with top companies.", + teamMembers = accounts.subList(2, 4).toMutableList(), + associatedRoles = getRandomRoles(3), + slug = "data-science-career-fair", + image = "career_fair_image.png", + registerUrl = "https://datasciencefair.com/register", + dateInterval = generateDateInterval(50, 1), + location = "Faro, Portugal", + category = "Career Fair" ) ) diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/GenerationSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/GenerationSeeder.kt index 466a23f8..6abe241d 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/GenerationSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/GenerationSeeder.kt @@ -1,6 +1,7 @@ package pt.up.fe.ni.website.backend.model.seeders import org.springframework.stereotype.Component +import org.springframework.transaction.annotation.Transactional import pt.up.fe.ni.website.backend.config.Logging import pt.up.fe.ni.website.backend.model.Generation import pt.up.fe.ni.website.backend.repository.GenerationRepository @@ -8,6 +9,7 @@ import pt.up.fe.ni.website.backend.repository.GenerationRepository @Component class GenerationSeeder() : AbstractSeeder(), Logging { + @Transactional override fun createObjects() { logger.info("Running Generation seeder...") @@ -16,16 +18,18 @@ class GenerationSeeder() : AbstractSeeder(), Logging { +class PerActivityRoleSeeder() : + AbstractSeeder(), Logging { override fun createObjects() { + if (repository.count() == 0L) { + logger.info("Running PerActivityRole seeder...") + + val perActivityRoles = listOf( + // Role: View and Edit Activity + // This role allows users to view and edit activities within the system. + PerActivityRole( + permissions = Permissions(setOf(Permission.VIEW_ACTIVITY, Permission.EDIT_ACTIVITY)) + ), + + // Role: Create and Delete Activity + // This role allows users to create new activities and delete existing ones. + PerActivityRole( + permissions = Permissions(setOf(Permission.CREATE_ACTIVITY, Permission.DELETE_ACTIVITY)) + ), + + // Role: Create and View Account + // This role allows users to create new accounts and view existing ones. + PerActivityRole( + permissions = Permissions(setOf(Permission.CREATE_ACCOUNT, Permission.VIEW_ACCOUNT)) + ), + + // Role: Edit and Delete Account + // This role allows users to edit existing accounts and delete them from the system. + PerActivityRole( + permissions = Permissions(setOf(Permission.EDIT_ACCOUNT, Permission.DELETE_ACCOUNT)) + ), + + // Role: Edit Settings and Superuser + // This role is for users with admin-level permissions, allowing them to edit settings and access superuser functionality. + PerActivityRole( + permissions = Permissions(setOf(Permission.EDIT_SETTINGS, Permission.SUPERUSER)) + ), + + // Role: Full Access (all permissions) + // This role gives the user complete access to all actions in the system, including managing accounts, activities, settings, and superuser permissions. + PerActivityRole( + permissions = Permissions( + setOf( + Permission.CREATE_ACCOUNT, Permission.VIEW_ACCOUNT, Permission.EDIT_ACCOUNT, + Permission.DELETE_ACCOUNT, Permission.CREATE_ACTIVITY, Permission.VIEW_ACTIVITY, + Permission.EDIT_ACTIVITY, Permission.DELETE_ACTIVITY, Permission.EDIT_SETTINGS, + Permission.SUPERUSER + ) + ) + ), + + // Role: Activity Management Only + // This role focuses only on activities, allowing users to create, view, and edit activities, without permissions for account or settings management. + PerActivityRole( + permissions = Permissions( + setOf(Permission.CREATE_ACTIVITY, Permission.VIEW_ACTIVITY, Permission.EDIT_ACTIVITY) + ) + ), + + // Role: Admin/Settings Access Only + // This role grants users administrative access to settings and superuser functionalities, but not permissions to manage accounts or activities. + PerActivityRole( + permissions = Permissions(setOf(Permission.EDIT_SETTINGS, Permission.SUPERUSER)) + ) + ) + + // Save all the roles to the repository + repository.saveAll(perActivityRoles) + logger.info("PerActivityRole data seeded successfully.") + } else { + logger.info("PerActivityRole data already exists, skipping seeding.") + } } } diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PostSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PostSeeder.kt index 5a26a1ac..b47c05e2 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PostSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/PostSeeder.kt @@ -8,34 +8,52 @@ import pt.up.fe.ni.website.backend.model.constants.PostConstants import pt.up.fe.ni.website.backend.repository.PostRepository @Component -class PostSeeder() : AbstractSeeder(), Logging { +class PostSeeder : AbstractSeeder(), Logging { override fun createObjects() { logger.info("Running post seeder...") + for (i in 1..10) { val post = Post( - faker.lorem().characters(PostConstants.Title.minSize, PostConstants.Title.maxSize, true, true, true), - faker.lorem().characters(PostConstants.Body.minSize, 500, true, true, true), - faker.internet().url(), - Date.from(faker.date().birthday().toInstant()), - Date.from(faker.date().birthday().toInstant()), - slug = faker.lorem().characters(PostConstants.Slug.minSize, PostConstants.Slug.maxSize) + title = faker.lorem().characters( + PostConstants.Title.minSize, + PostConstants.Title.maxSize, + false + ), + body = faker.lorem().characters( + PostConstants.Body.minSize, + false + ), + thumbnailPath = faker.internet().url(), + publishDate = Date(), + lastUpdatedAt = Date(), + slug = faker.lorem().characters( + PostConstants.Slug.minSize, + PostConstants.Slug.maxSize, + false + ) ) - val postWithoutDate = Post( - faker.lorem().characters(PostConstants.Title.minSize, PostConstants.Title.maxSize, true, true, true), - faker.lorem().characters(PostConstants.Body.minSize, 500, true, true, true), - faker.internet().url(), + val postWithoutPublishDate = Post( + title = faker.lorem().characters( + PostConstants.Title.minSize, + PostConstants.Title.maxSize, + false + ), + body = faker.lorem().characters( + PostConstants.Body.minSize, + false + ), + thumbnailPath = faker.internet().url(), + lastUpdatedAt = Date(), slug = faker.lorem().characters( PostConstants.Slug.minSize, PostConstants.Slug.maxSize, - false, - false, false ) ) - repository.saveAll(listOf(post, postWithoutDate)) + repository.saveAll(listOf(post, postWithoutPublishDate)) } } } diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt index 03b006cc..2356d46b 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt @@ -15,25 +15,30 @@ class ProjectSeeder( @Autowired val accountRepository: AccountRepository, @Autowired val perActivityRoleRepository: PerActivityRoleRepository, @Autowired val customWebsiteRepository: CustomWebsiteRepository, - @Autowired val timelineEventRepository: TimeLineEventRepository + @Autowired val timelineEventRepository: TimeLineEventRepository, + @Autowired val timelineEventSeeder: TimeLineEventSeeder ) : AbstractSeeder(), Logging { + // Preloading all accounts, timeline events, roles, and custom websites for reuse val accounts = accountRepository.findAll().toList() + val timelineEvents = timelineEventRepository.findAll().toList() val perActivityRoles = perActivityRoleRepository.findAll().toList() - val customWebsites = customWebsiteRepository.findAll().toList() - val timelineEvents = timelineEventRepository.findAll().toList() override fun createObjects() { if (repository.count() == 0L) { - logger.info("Seeding Project data...") + logger.info("Running Project seeder...") + + // Ensuring timeline events are created before projects + timelineEventSeeder.createObjects() val projects = listOf( + // AI Research Project Project( title = "AI Research Project", description = "A project focused on developing AI models for real-time data analysis.", teamMembers = accounts.subList(0, 3).toMutableList(), - associatedRoles = perActivityRoles.subList(0, 2).toMutableList(), + associatedRoles = perActivityRoles.subList(0, 1).toMutableList(), slug = "ai-research-project", image = "ai_project_image.png", isArchived = false, @@ -41,15 +46,16 @@ class ProjectSeeder( slogan = "Transforming data with AI", targetAudience = "Researchers, Data Scientists", github = "https://github.com/research-ai", - links = customWebsites.subList(0, 2), + links = mutableListOf(), hallOfFame = accounts.subList(3, 4).toMutableList(), - timeline = timelineEvents.subList(0, 2) + timeline = timelineEvents.subList(0, 1).toMutableList() // Unique timeline ), + // Blockchain Development Project Project( title = "Blockchain Development Project", description = "Building a decentralized application using blockchain technology.", teamMembers = accounts.subList(3, 6).toMutableList(), - associatedRoles = perActivityRoles.subList(2, 4).toMutableList(), + associatedRoles = perActivityRoles.subList(0, 1).toMutableList(), slug = "blockchain-dev-project", image = "blockchain_project_image.png", isArchived = false, @@ -57,13 +63,81 @@ class ProjectSeeder( slogan = "Decentralizing the future", targetAudience = "Developers, Fintech Enthusiasts", github = "https://github.com/blockchain-dev", - links = customWebsites.subList(2, 4), + links = customWebsites.subList(1, 3).toMutableList(), hallOfFame = accounts.subList(6, 7).toMutableList(), - timeline = timelineEvents.subList(2, 4) + timeline = timelineEvents.subList(1, 2).toMutableList() // Unique timeline + ), + // Augmented Reality Game Development + Project( + title = "Augmented Reality Game Development", + description = "Developing an immersive AR game for mobile devices.", + teamMembers = accounts.subList(0, 4).toMutableList(), + associatedRoles = perActivityRoles.subList(1, 2).toMutableList(), + slug = "ar-game-dev", + image = "ar_game_image.png", + isArchived = false, + technologies = listOf("Unity", "C#", "ARCore"), + slogan = "Gamify your reality", + targetAudience = "Gamers, Tech Enthusiasts", + github = "https://github.com/ar-game-dev", + links = customWebsites.subList(2, 4).toMutableList(), + hallOfFame = accounts.subList(4, 5).toMutableList(), + timeline = timelineEvents.subList(2, 3).toMutableList() // Unique timeline + ), + // Data Visualization Platform + Project( + title = "Data Visualization Platform", + description = "A platform to visualize large-scale data and generate insights.", + teamMembers = accounts.subList(1, 4).toMutableList(), + associatedRoles = perActivityRoles.subList(0, 1).toMutableList(), + slug = "data-visualization-platform", + image = "data_viz_image.png", + isArchived = true, // Archived project + technologies = listOf("D3.js", "JavaScript", "Python"), + slogan = "Turning data into stories", + targetAudience = "Data Scientists, Analysts, Enterprises", + github = "https://github.com/data-viz-platform", + links = customWebsites.subList(0, 1).toMutableList(), + hallOfFame = accounts.subList(2, 3).toMutableList(), + timeline = timelineEvents.subList(3, 4).toMutableList() // Unique timeline + ), + // E-commerce Website Development + Project( + title = "E-commerce Website Development", + description = "Building a robust e-commerce platform for online shopping.", + teamMembers = accounts.subList(2, 6).toMutableList(), + associatedRoles = perActivityRoles.subList(1, 2).toMutableList(), + slug = "ecommerce-web-dev", + image = "ecommerce_project_image.png", + isArchived = false, + technologies = listOf("React", "Node.js", "MongoDB"), + slogan = "Shop smart, shop online", + targetAudience = "Consumers, Online Shoppers", + github = "https://github.com/ecommerce-web-dev", + links = customWebsites.subList(3, 5).toMutableList(), + hallOfFame = accounts.subList(1, 2).toMutableList(), + timeline = timelineEvents.subList(4, 5).toMutableList() // Unique timeline + ), + // Virtual Reality Simulation System + Project( + title = "Virtual Reality Simulation System", + description = "Creating VR simulations for training and education.", + teamMembers = accounts.subList(0, 2).toMutableList(), + associatedRoles = perActivityRoles.subList(2, 3).toMutableList(), + slug = "vr-simulation-system", + image = "vr_simulation_image.png", + isArchived = false, + technologies = listOf("Unreal Engine", "C++", "Oculus"), + slogan = "Enter the virtual world", + targetAudience = "Educational Institutions, Training Centers", + github = "https://github.com/vr-simulation-system", + links = customWebsites.subList(1, 2).toMutableList(), + hallOfFame = accounts.subList(2, 3).toMutableList(), + timeline = timelineEvents.subList(5, 6).toMutableList() // Unique timeline ) ) - repository.saveAll(projects) + repository.saveAll(projects) // Save projects with unique timelines logger.info("Project data seeded successfully.") } else { logger.info("Project data already exists, skipping seeding.") diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/RoleSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/RoleSeeder.kt index c616c7e0..5dc3f8f8 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/RoleSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/RoleSeeder.kt @@ -1,32 +1,24 @@ package pt.up.fe.ni.website.backend.model.seeders -import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component import pt.up.fe.ni.website.backend.config.Logging import pt.up.fe.ni.website.backend.model.Role import pt.up.fe.ni.website.backend.model.permissions.Permission import pt.up.fe.ni.website.backend.model.permissions.Permissions -import pt.up.fe.ni.website.backend.repository.AccountRepository -import pt.up.fe.ni.website.backend.repository.GenerationRepository import pt.up.fe.ni.website.backend.repository.RoleRepository @Component -class RoleSeeder( - @Autowired private val roleRepository: RoleRepository, - @Autowired private val accountRepository: AccountRepository, - @Autowired private val generationRepository: GenerationRepository -) : AbstractSeeder(), Logging { +class RoleSeeder() : + AbstractSeeder(), Logging { override fun createObjects() { logger.info("Running Role seeder...") - if (roleRepository.count() > 0) { + if (repository.count() > 0) { logger.info("Skipping Role seeding as roles already exist.") return } - val currentGeneration = generationRepository.findAllSchoolYearOrdered().firstOrNull() - val roles = listOf( Role( name = "President", @@ -45,7 +37,7 @@ class RoleSeeder( ) ) - roleRepository.saveAll(roles) + repository.saveAll(roles) logger.info("Seeded ${roles.size} roles into the system.") } } diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/TimeLineEventSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/TimeLineEventSeeder.kt index 25fa0a98..2ef2732b 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/TimeLineEventSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/TimeLineEventSeeder.kt @@ -7,28 +7,80 @@ import pt.up.fe.ni.website.backend.model.TimelineEvent import pt.up.fe.ni.website.backend.repository.TimeLineEventRepository @Component -class TimeLineEventSeeder() : AbstractSeeder(), Logging { +class TimeLineEventSeeder() : + AbstractSeeder(), Logging { override fun createObjects() { if (repository.count() == 0L) { - logger.info("Seeding TimelineEvent data...") + logger.info("Running TimeLineEvent seeder...") val timelineEvents = listOf( + // Original events TimelineEvent( - date = Date(1672531200000), + date = Date(1672531200000), // January 1, 2023 description = "Project Conceptualization" ), TimelineEvent( - date = Date(1675123200000), + date = Date(1675123200000), // February 1, 2023 description = "First Prototype Developed" ), TimelineEvent( - date = Date(1677801600000), + date = Date(1677801600000), // March 1, 2023 description = "Initial User Testing" ), TimelineEvent( - date = Date(1680476400000), // Example: April 1, 2023 + date = Date(1680476400000), // April 1, 2023 description = "Launch of Beta Version" + ), + + // New Events (Added for more variety) + TimelineEvent( + date = Date(1683164800000), // May 1, 2023 + description = "Partnership Announcement with XYZ" + ), + TimelineEvent( + date = Date(1685756800000), // June 1, 2023 + description = "Completed Second Round of Funding" + ), + TimelineEvent( + date = Date(1688348800000), // July 1, 2023 + description = "User Feedback Collected" + ), + TimelineEvent( + date = Date(1691027200000), // August 1, 2023 + description = "Launch of Full Version" + ), + TimelineEvent( + date = Date(1693619200000), // September 1, 2023 + description = "Reached 100K Active Users" + ), + TimelineEvent( + date = Date(1696297600000), // October 1, 2023 + description = "Expanded to International Markets" + ), + TimelineEvent( + date = Date(1698889600000), // November 1, 2023 + description = "Introduced New Feature: Real-time Analytics" + ), + TimelineEvent( + date = Date(1701571200000), // December 1, 2023 + description = "Awarded Best Startup of the Year" + ), + TimelineEvent( + date = Date(1704249600000), // January 1, 2024 + description = "Company Valuation Exceeds $1B" + ), + TimelineEvent( + date = Date(1706841600000), // February 1, 2024 + description = "Secured New Partnership with ABC Corp" + ), + TimelineEvent( + date = Date(1709520000000), // March 1, 2024 + description = "Introduced Mobile App for iOS and Android" + ), + TimelineEvent( + date = Date(1712112000000), // April 1, 2024 + description = "Crossed 1M Downloads" ) ) diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/service/database/DatabaseService.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/service/database/DatabaseService.kt new file mode 100644 index 00000000..7d938943 --- /dev/null +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/service/database/DatabaseService.kt @@ -0,0 +1,93 @@ +package pt.up.fe.ni.website.backend.service.database + +import jakarta.persistence.EntityManager +import jakarta.transaction.Transactional +import java.sql.Connection +import java.sql.Statement +import javax.sql.DataSource +import org.hibernate.id.enhanced.PooledOptimizer +import org.hibernate.id.enhanced.SequenceStyleGenerator +import org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl +import org.springframework.stereotype.Service +import pt.up.fe.ni.website.backend.config.Logging + +@Service +class DatabaseService : Logging { + companion object { + private const val SCHEMA_NAME = "PUBLIC" + private const val DB_NAME = "H2" + } + + @Transactional(Transactional.TxType.REQUIRES_NEW) + fun cleanDataSource(dataSource: DataSource) { + logger.info("Cleaning Data Source...") + val connection = dataSource.connection + val statement = connection.createStatement() + if (connection.isH2Database()) { + disableConstraints(statement) + truncateTables(statement) + resetSequences(statement) + enableConstraints(statement) + } else { + logger.warn( + "Unexpected database type: ${connection.metaData.databaseProductName}" + + " (expected: $DB_NAME). Skipping cleanup." + ) + } + } + + fun cleanEntityManager(entityManager: EntityManager) { + logger.info("Cleaning Entity Manager...") + val metaModel = entityManager.metamodel as MappingMetamodelImpl + metaModel.forEachEntityDescriptor { entityDescriptor -> + if (!entityDescriptor.hasIdentifierProperty() || + entityDescriptor.identifierGenerator !is SequenceStyleGenerator + ) { + return@forEachEntityDescriptor + } + + val sequenceStyleGenerator = (entityDescriptor.identifierGenerator as SequenceStyleGenerator) + val optimizer = sequenceStyleGenerator.optimizer as? PooledOptimizer ?: return@forEachEntityDescriptor + + optimizer::class.java.getDeclaredField("noTenantState").apply { + isAccessible = true + set(optimizer, null) + } + } + } + + private fun enableConstraints(statement: Statement) = + statement.executeUpdate("SET REFERENTIAL_INTEGRITY TRUE") + + private fun disableConstraints(statement: Statement) = + statement.executeUpdate("SET REFERENTIAL_INTEGRITY FALSE") + + private fun truncateTables(statement: Statement) = + getSchemaTables(statement).forEach { statement.executeUpdate("TRUNCATE TABLE $it RESTART IDENTITY") } + + private fun resetSequences(statement: Statement) = + getSchemaSequences(statement).forEach { + statement.executeUpdate("ALTER SEQUENCE $it RESTART WITH 1") + } + + private fun getSchemaTables(statement: Statement): Set = + convertQueryToSet( + statement, + "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='$SCHEMA_NAME'" + ) + + private fun getSchemaSequences(statement: Statement): Set = + convertQueryToSet( + statement, + "SELECT SEQUENCE_NAME FROM INFORMATION_SCHEMA.SEQUENCES WHERE SEQUENCE_SCHEMA='$SCHEMA_NAME'" + ) + + private fun convertQueryToSet(statement: Statement, sql: String): Set = + statement.executeQuery(sql).use { rs -> + HashSet().apply { + while (rs.next()) add(rs.getString(1)) + } + } + + private fun Connection.isH2Database() = DB_NAME == this.metaData.databaseProductName +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8c02afc3..e4729650 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -9,6 +9,7 @@ spring.datasource.password= # Spring JPA spring.jpa.hibernate.ddl-auto=update spring.jpa.open-in-view=false +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect # H2 spring.h2.console.enabled=true @@ -41,3 +42,4 @@ upload.static-serve=http://localhost:3000/static # Cors Origin cors.allow-origin = http://localhost:3000 + From 5d48b9d789ed3a3ebeb7a288a80ec56ea5cc9e27 Mon Sep 17 00:00:00 2001 From: Pedro Vidal Date: Sat, 16 Nov 2024 00:17:02 +0000 Subject: [PATCH 07/10] Added datafaker to seeders where possible --- .../backend/model/seeders/AccountSeeder.kt | 77 +++++----- .../backend/model/seeders/ActivitySeeder.kt | 3 +- .../model/seeders/CustomWebsiteSeeder.kt | 108 +------------ .../backend/model/seeders/EventSeeder.kt | 123 ++++----------- .../backend/model/seeders/GenerationSeeder.kt | 3 +- .../backend/model/seeders/ProjectSeeder.kt | 144 +++++------------- .../model/seeders/TimeLineEventSeeder.kt | 85 ++--------- 7 files changed, 119 insertions(+), 424 deletions(-) diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt index cf625a89..f19f8670 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt @@ -25,12 +25,11 @@ class AccountSeeder( } val accounts = listOf( - // Standard Account Account( - name = "Alice Standard", - email = "alice.standard@example.com", + name = faker.name().fullName(), + email = faker.internet().emailAddress(), password = encoder.encode("password123"), - bio = "A standard user with all fields filled.", + bio = faker.lorem().paragraph(1), birthDate = Date.from(faker.date().birthday(25, 35).toInstant()), photo = faker.internet().image(), github = faker.internet().url(), @@ -39,10 +38,10 @@ class AccountSeeder( ), // Account Without Photo Account( - name = "Bob NoPhoto", - email = "bob.nophoto@example.com", + name = faker.name().fullName(), + email = faker.internet().emailAddress(), password = encoder.encode("securepass"), - bio = "An active user without a profile picture.", + bio = faker.lorem().sentence(), birthDate = Date.from(faker.date().birthday(30, 40).toInstant()), photo = null, github = faker.internet().url(), @@ -51,20 +50,20 @@ class AccountSeeder( ), // Account Without Bio Account( - name = "Charlie NoBio", - email = "charlie.nobio@example.com", + name = faker.name().fullName(), + email = faker.internet().emailAddress(), password = encoder.encode("anothersecurepass"), bio = null, birthDate = Date.from(faker.date().birthday(18, 28).toInstant()), photo = faker.internet().image(), - github = null, - linkedin = null, + github = faker.internet().url(), + linkedin = faker.internet().url(), roles = roles.shuffled().take(1).toMutableList() ), // Account Without Bio or Photo Account( - name = "Dana Minimal", - email = "dana.minimal@example.com", + name = faker.name().fullName(), + email = faker.internet().emailAddress(), password = encoder.encode("minpass"), bio = null, birthDate = Date.from(faker.date().birthday(20, 30).toInstant()), @@ -75,8 +74,8 @@ class AccountSeeder( ), // Account with Long Bio Account( - name = "Eve LongBio", - email = "eve.longbio@example.com", + name = faker.name().fullName(), + email = faker.internet().emailAddress(), password = encoder.encode("verysecure"), bio = faker.lorem().paragraph(5), birthDate = Date.from(faker.date().birthday(35, 45).toInstant()), @@ -87,8 +86,8 @@ class AccountSeeder( ), // Account with Single Role Account( - name = "Grace SingleRole", - email = "grace.singlerole@example.com", + name = faker.name().fullName(), + email = faker.internet().emailAddress(), password = encoder.encode("singlepass"), bio = "User with only one role.", birthDate = Date.from(faker.date().birthday(22, 32).toInstant()), @@ -99,8 +98,8 @@ class AccountSeeder( ), // Account with All Optional Fields Null Account( - name = "Henry AllNull", - email = "henry.allnull@example.com", + name = faker.name().fullName(), + email = faker.internet().emailAddress(), password = encoder.encode("nullpass"), bio = null, birthDate = null, @@ -108,29 +107,20 @@ class AccountSeeder( github = null, linkedin = null, roles = mutableListOf() - ), - // Account with Edge Case Birth Date - Account( - name = "Ivy EdgeDate", - email = "ivy.edgedate@example.com", - password = encoder.encode("edgepass"), - bio = "Born on January 1st, 2000.", - birthDate = Date.from( - Calendar.getInstance().apply { - set(2000, Calendar.JANUARY, 1) - }.time.toInstant() - ), - photo = faker.internet().image(), - github = faker.internet().url(), - linkedin = faker.internet().url(), - roles = roles.shuffled().take(1).toMutableList() - ), - // Account with Special Characters in Name + ) + ) + + val repeatedAccounts = mutableListOf() + for (i in 1..5) { + repeatedAccounts.addAll(accounts) + } + + val staticAccounts = listOf( // edge cases Account( - name = "Zoë Löwe", - email = "zoe.lowe@example.com", + name = "Zoë Löwe Dinis Canas", // Special characters in name + email = faker.internet().emailAddress(), password = encoder.encode("specialpass"), - bio = "User with special characters in their name.", + bio = faker.lorem().sentence(), birthDate = Date.from(faker.date().birthday(20, 40).toInstant()), photo = faker.internet().image(), github = faker.internet().url(), @@ -139,7 +129,10 @@ class AccountSeeder( ) ) - // Save all the accounts - repository.saveAll(accounts) + val allAccounts = repeatedAccounts + staticAccounts + + repository.saveAll(allAccounts) + + logger.info("Account data seeded successfully.") } } diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt index 5a439a5b..25261285 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt @@ -17,9 +17,8 @@ class ActivitySeeder( // Delegate seeding to the EventSeeder and ProjectSeeder logger.info("Running Activity Seeder") - // Seed Roles per Activity (needs to add projects and events later) + // Seed Roles per Activity (TODO: needs to add projects and events later) perActivityRoleSeeder.createObjects() - // Seed Projects projectSeeder.createObjects() // Seed Events diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/CustomWebsiteSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/CustomWebsiteSeeder.kt index 10e2729d..e8d22afb 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/CustomWebsiteSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/CustomWebsiteSeeder.kt @@ -10,116 +10,16 @@ class CustomWebsiteSeeder() : AbstractSeeder(), Logging { - // Preloading all accounts, timeline events, roles, and custom websites for reuse val accounts = accountRepository.findAll().toList() val timelineEvents = timelineEventRepository.findAll().toList() val perActivityRoles = perActivityRoleRepository.findAll().toList() @@ -31,113 +26,44 @@ class ProjectSeeder( // Ensuring timeline events are created before projects timelineEventSeeder.createObjects() + val shuffledTimelineEvents = timelineEvents.shuffled().toMutableList() + + val projects = (1..6).map { + val title = faker.company().bs() + val description = faker.lorem().sentence(10, 15) + val technologies = List(3) { faker.programmingLanguage().name() } + val slogan = faker.company().buzzword() + val targetAudience = faker.name().title() + + val slug = title.lowercase() + .replace(" ", "-") + .replace(Regex("[^a-z0-9-]"), "") + + // Ensure only one TimeLineEvent per project + val projectTimeline = shuffledTimelineEvents.take(1).toMutableList() + shuffledTimelineEvents.removeAt(0) + + val hallOfFameMembers = accounts.shuffled().take(2).toMutableList() - val projects = listOf( - // AI Research Project - Project( - title = "AI Research Project", - description = "A project focused on developing AI models for real-time data analysis.", - teamMembers = accounts.subList(0, 3).toMutableList(), - associatedRoles = perActivityRoles.subList(0, 1).toMutableList(), - slug = "ai-research-project", - image = "ai_project_image.png", - isArchived = false, - technologies = listOf("Python", "TensorFlow", "Keras"), - slogan = "Transforming data with AI", - targetAudience = "Researchers, Data Scientists", - github = "https://github.com/research-ai", - links = mutableListOf(), - hallOfFame = accounts.subList(3, 4).toMutableList(), - timeline = timelineEvents.subList(0, 1).toMutableList() // Unique timeline - ), - // Blockchain Development Project - Project( - title = "Blockchain Development Project", - description = "Building a decentralized application using blockchain technology.", - teamMembers = accounts.subList(3, 6).toMutableList(), - associatedRoles = perActivityRoles.subList(0, 1).toMutableList(), - slug = "blockchain-dev-project", - image = "blockchain_project_image.png", - isArchived = false, - technologies = listOf("Solidity", "Ethereum", "Web3"), - slogan = "Decentralizing the future", - targetAudience = "Developers, Fintech Enthusiasts", - github = "https://github.com/blockchain-dev", - links = customWebsites.subList(1, 3).toMutableList(), - hallOfFame = accounts.subList(6, 7).toMutableList(), - timeline = timelineEvents.subList(1, 2).toMutableList() // Unique timeline - ), - // Augmented Reality Game Development - Project( - title = "Augmented Reality Game Development", - description = "Developing an immersive AR game for mobile devices.", - teamMembers = accounts.subList(0, 4).toMutableList(), - associatedRoles = perActivityRoles.subList(1, 2).toMutableList(), - slug = "ar-game-dev", - image = "ar_game_image.png", - isArchived = false, - technologies = listOf("Unity", "C#", "ARCore"), - slogan = "Gamify your reality", - targetAudience = "Gamers, Tech Enthusiasts", - github = "https://github.com/ar-game-dev", - links = customWebsites.subList(2, 4).toMutableList(), - hallOfFame = accounts.subList(4, 5).toMutableList(), - timeline = timelineEvents.subList(2, 3).toMutableList() // Unique timeline - ), - // Data Visualization Platform - Project( - title = "Data Visualization Platform", - description = "A platform to visualize large-scale data and generate insights.", - teamMembers = accounts.subList(1, 4).toMutableList(), - associatedRoles = perActivityRoles.subList(0, 1).toMutableList(), - slug = "data-visualization-platform", - image = "data_viz_image.png", - isArchived = true, // Archived project - technologies = listOf("D3.js", "JavaScript", "Python"), - slogan = "Turning data into stories", - targetAudience = "Data Scientists, Analysts, Enterprises", - github = "https://github.com/data-viz-platform", - links = customWebsites.subList(0, 1).toMutableList(), - hallOfFame = accounts.subList(2, 3).toMutableList(), - timeline = timelineEvents.subList(3, 4).toMutableList() // Unique timeline - ), - // E-commerce Website Development - Project( - title = "E-commerce Website Development", - description = "Building a robust e-commerce platform for online shopping.", - teamMembers = accounts.subList(2, 6).toMutableList(), - associatedRoles = perActivityRoles.subList(1, 2).toMutableList(), - slug = "ecommerce-web-dev", - image = "ecommerce_project_image.png", - isArchived = false, - technologies = listOf("React", "Node.js", "MongoDB"), - slogan = "Shop smart, shop online", - targetAudience = "Consumers, Online Shoppers", - github = "https://github.com/ecommerce-web-dev", - links = customWebsites.subList(3, 5).toMutableList(), - hallOfFame = accounts.subList(1, 2).toMutableList(), - timeline = timelineEvents.subList(4, 5).toMutableList() // Unique timeline - ), - // Virtual Reality Simulation System Project( - title = "Virtual Reality Simulation System", - description = "Creating VR simulations for training and education.", - teamMembers = accounts.subList(0, 2).toMutableList(), - associatedRoles = perActivityRoles.subList(2, 3).toMutableList(), - slug = "vr-simulation-system", - image = "vr_simulation_image.png", - isArchived = false, - technologies = listOf("Unreal Engine", "C++", "Oculus"), - slogan = "Enter the virtual world", - targetAudience = "Educational Institutions, Training Centers", - github = "https://github.com/vr-simulation-system", - links = customWebsites.subList(1, 2).toMutableList(), - hallOfFame = accounts.subList(2, 3).toMutableList(), - timeline = timelineEvents.subList(5, 6).toMutableList() // Unique timeline + title = title, + description = description, + teamMembers = accounts.shuffled().take(3).toMutableList(), + associatedRoles = perActivityRoles.shuffled().take(1).toMutableList(), + slug = slug, + image = "${slug}_image.png", + isArchived = faker.random().nextBoolean(), + technologies = technologies, + slogan = slogan, + targetAudience = targetAudience, + github = "https://github.com/$slug", + links = customWebsites.shuffled().take(2).toMutableList(), + hallOfFame = hallOfFameMembers, + timeline = projectTimeline ) - ) + } - repository.saveAll(projects) // Save projects with unique timelines + repository.saveAll(projects) logger.info("Project data seeded successfully.") } else { logger.info("Project data already exists, skipping seeding.") diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/TimeLineEventSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/TimeLineEventSeeder.kt index 2ef2732b..2b7dd1dc 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/TimeLineEventSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/TimeLineEventSeeder.kt @@ -1,91 +1,36 @@ package pt.up.fe.ni.website.backend.model.seeders -import java.util.Date +import java.time.LocalDate +import java.time.Month +import java.util.* import org.springframework.stereotype.Component import pt.up.fe.ni.website.backend.config.Logging import pt.up.fe.ni.website.backend.model.TimelineEvent import pt.up.fe.ni.website.backend.repository.TimeLineEventRepository @Component -class TimeLineEventSeeder() : - AbstractSeeder(), Logging { +class TimeLineEventSeeder : AbstractSeeder(), Logging { override fun createObjects() { if (repository.count() == 0L) { logger.info("Running TimeLineEvent seeder...") - val timelineEvents = listOf( - // Original events - TimelineEvent( - date = Date(1672531200000), // January 1, 2023 - description = "Project Conceptualization" - ), - TimelineEvent( - date = Date(1675123200000), // February 1, 2023 - description = "First Prototype Developed" - ), - TimelineEvent( - date = Date(1677801600000), // March 1, 2023 - description = "Initial User Testing" - ), - TimelineEvent( - date = Date(1680476400000), // April 1, 2023 - description = "Launch of Beta Version" - ), + val timelineEvents = (1..15).map { + // Generate a random past date within the last 3 years + val randomYear = (2020..2023).random() + val randomMonth = Month.values().random() + val randomDay = (1..28).random() + + val randomPastDate = LocalDate.of(randomYear, randomMonth, randomDay) - // New Events (Added for more variety) - TimelineEvent( - date = Date(1683164800000), // May 1, 2023 - description = "Partnership Announcement with XYZ" - ), - TimelineEvent( - date = Date(1685756800000), // June 1, 2023 - description = "Completed Second Round of Funding" - ), - TimelineEvent( - date = Date(1688348800000), // July 1, 2023 - description = "User Feedback Collected" - ), - TimelineEvent( - date = Date(1691027200000), // August 1, 2023 - description = "Launch of Full Version" - ), - TimelineEvent( - date = Date(1693619200000), // September 1, 2023 - description = "Reached 100K Active Users" - ), - TimelineEvent( - date = Date(1696297600000), // October 1, 2023 - description = "Expanded to International Markets" - ), - TimelineEvent( - date = Date(1698889600000), // November 1, 2023 - description = "Introduced New Feature: Real-time Analytics" - ), - TimelineEvent( - date = Date(1701571200000), // December 1, 2023 - description = "Awarded Best Startup of the Year" - ), - TimelineEvent( - date = Date(1704249600000), // January 1, 2024 - description = "Company Valuation Exceeds $1B" - ), - TimelineEvent( - date = Date(1706841600000), // February 1, 2024 - description = "Secured New Partnership with ABC Corp" - ), - TimelineEvent( - date = Date(1709520000000), // March 1, 2024 - description = "Introduced Mobile App for iOS and Android" - ), TimelineEvent( - date = Date(1712112000000), // April 1, 2024 - description = "Crossed 1M Downloads" + date = Date.from(randomPastDate.atStartOfDay().toInstant(java.time.ZoneOffset.UTC)), + description = faker.lorem().sentence(5, 10) ) - ) + } repository.saveAll(timelineEvents) - logger.info("TimelineEvent data seeded successfully.") + logger.info("TimelineEvent data seeded successfully with ${timelineEvents.size} events.") } else { logger.info("TimelineEvent data already exists, skipping seeding.") } From 31192c8285ad4aa19218a7f0fb5714dab35c26da Mon Sep 17 00:00:00 2001 From: Pedro Vidal Date: Sat, 16 Nov 2024 00:25:13 +0000 Subject: [PATCH 08/10] removed wildcard import --- .../up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt index bdd43f50..95d40759 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt @@ -4,7 +4,11 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component import pt.up.fe.ni.website.backend.config.Logging import pt.up.fe.ni.website.backend.model.Project -import pt.up.fe.ni.website.backend.repository.* +import pt.up.fe.ni.website.backend.repository.AccountRepository +import pt.up.fe.ni.website.backend.repository.CustomWebsiteRepository +import pt.up.fe.ni.website.backend.repository.PerActivityRoleRepository +import pt.up.fe.ni.website.backend.repository.ProjectRepository +import pt.up.fe.ni.website.backend.repository.TimeLineEventRepository @Component class ProjectSeeder( From ae07560514921a3c0e743104ddb525a247a5849b Mon Sep 17 00:00:00 2001 From: Pedro Vidal Date: Sat, 16 Nov 2024 17:32:49 +0000 Subject: [PATCH 09/10] Fixed persistence problem with entity manager --- .../fe/ni/website/backend/model/Activity.kt | 3 +- .../up/fe/ni/website/backend/model/Project.kt | 5 +-- .../backend/model/seeders/AccountSeeder.kt | 19 ++++++++-- .../backend/model/seeders/ActivitySeeder.kt | 2 +- .../backend/model/seeders/EventSeeder.kt | 15 +++++--- .../backend/model/seeders/ProjectSeeder.kt | 36 ++++++++++++------- 6 files changed, 57 insertions(+), 23 deletions(-) diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/Activity.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/Activity.kt index 657a9072..3b2b81c0 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/Activity.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/Activity.kt @@ -2,6 +2,7 @@ package pt.up.fe.ni.website.backend.model import com.fasterxml.jackson.annotation.JsonIgnore import com.fasterxml.jackson.annotation.JsonProperty +import jakarta.persistence.CascadeType import jakarta.persistence.Column import jakarta.persistence.Entity import jakarta.persistence.FetchType @@ -31,7 +32,7 @@ abstract class Activity( @OneToMany(fetch = FetchType.EAGER) open val teamMembers: MutableList, - @OneToMany(/*cascade = [CascadeType.ALL],*/ mappedBy = "activity") + @OneToMany(cascade = [CascadeType.ALL], mappedBy = "activity") @JsonIgnore // TODO: Decide if we want to return perRoles (or IDs) by default open val associatedRoles: MutableList<@Valid PerActivityRole> = mutableListOf(), diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/Project.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/Project.kt index 29f7beae..962b77bb 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/Project.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/Project.kt @@ -1,5 +1,6 @@ package pt.up.fe.ni.website.backend.model +import jakarta.persistence.CascadeType import jakarta.persistence.Entity import jakarta.persistence.FetchType import jakarta.persistence.JoinColumn @@ -35,14 +36,14 @@ class Project( var github: String? = null, @JoinColumn - @OneToMany(/*cascade = [CascadeType.ALL],)*/ fetch = FetchType.EAGER) + @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER) val links: List<@Valid CustomWebsite> = emptyList(), @JoinColumn @OneToMany(fetch = FetchType.EAGER) var hallOfFame: MutableList = mutableListOf(), - @OneToMany(/*cascade = [CascadeType.ALL],*/fetch = FetchType.EAGER) + @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER) @OrderBy("date") val timeline: List<@Valid TimelineEvent> = emptyList(), diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt index f19f8670..08f9f329 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt @@ -1,5 +1,7 @@ package pt.up.fe.ni.website.backend.model.seeders +import jakarta.persistence.EntityManager +import jakarta.transaction.Transactional import java.util.* import org.springframework.beans.factory.annotation.Autowired import org.springframework.security.crypto.password.PasswordEncoder @@ -7,12 +9,15 @@ import org.springframework.stereotype.Component import pt.up.fe.ni.website.backend.config.Logging import pt.up.fe.ni.website.backend.model.Account import pt.up.fe.ni.website.backend.repository.AccountRepository +import pt.up.fe.ni.website.backend.repository.CustomWebsiteRepository import pt.up.fe.ni.website.backend.repository.RoleRepository -@Component +@Component @Transactional class AccountSeeder( private val encoder: PasswordEncoder, - @Autowired private val roleRepository: RoleRepository + @Autowired val roleRepository: RoleRepository, + @Autowired val customWebsiteRepository: CustomWebsiteRepository, + @Autowired val entityManager: EntityManager // Inject EntityManager ) : AbstractSeeder(), Logging { override fun createObjects() { @@ -24,6 +29,12 @@ class AccountSeeder( logger.warn("No roles found in the database. Accounts will be created without roles.") } + val websites = customWebsiteRepository.findAll().toList() + .map { entityManager.merge(it) }.toMutableList() + if (websites.isEmpty()) { + logger.warn("No Custom websites in database. Accounts will be created without websites") + } + val accounts = listOf( Account( name = faker.name().fullName(), @@ -33,6 +44,7 @@ class AccountSeeder( birthDate = Date.from(faker.date().birthday(25, 35).toInstant()), photo = faker.internet().image(), github = faker.internet().url(), + websites = websites.shuffled().take(1).toMutableList(), linkedin = faker.internet().url(), roles = roles.shuffled().take(2).toMutableList() ), @@ -58,6 +70,7 @@ class AccountSeeder( photo = faker.internet().image(), github = faker.internet().url(), linkedin = faker.internet().url(), + websites = websites.shuffled().take(3).toMutableList(), roles = roles.shuffled().take(1).toMutableList() ), // Account Without Bio or Photo @@ -70,6 +83,7 @@ class AccountSeeder( photo = null, github = null, linkedin = faker.internet().url(), + websites = websites.shuffled().take(5).toMutableList(), roles = roles.shuffled().take(1).toMutableList() ), // Account with Long Bio @@ -94,6 +108,7 @@ class AccountSeeder( photo = faker.internet().image(), github = faker.internet().url(), linkedin = faker.internet().url(), + websites = websites.shuffled().take(2).toMutableList(), roles = roles.shuffled().take(1).toMutableList() ), // Account with All Optional Fields Null diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt index 25261285..d9bbb4c3 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ActivitySeeder.kt @@ -17,7 +17,7 @@ class ActivitySeeder( // Delegate seeding to the EventSeeder and ProjectSeeder logger.info("Running Activity Seeder") - // Seed Roles per Activity (TODO: needs to add projects and events later) + // Seed Roles per Activity perActivityRoleSeeder.createObjects() // Seed Projects projectSeeder.createObjects() diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt index cfd9f4fb..9b8a1dbc 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/EventSeeder.kt @@ -1,5 +1,7 @@ package pt.up.fe.ni.website.backend.model.seeders +import jakarta.persistence.EntityManager +import jakarta.transaction.Transactional import java.util.* import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component @@ -11,19 +13,22 @@ import pt.up.fe.ni.website.backend.repository.AccountRepository import pt.up.fe.ni.website.backend.repository.EventRepository import pt.up.fe.ni.website.backend.repository.PerActivityRoleRepository -@Component +@Component @Transactional class EventSeeder( @Autowired val accountRepository: AccountRepository, - @Autowired val perActivityRoleRepository: PerActivityRoleRepository + @Autowired val perActivityRoleRepository: PerActivityRoleRepository, + @Autowired val entityManager: EntityManager ) : AbstractSeeder(), Logging { - val accounts = accountRepository.findAll().toList() - val perActivityRoles = perActivityRoleRepository.findAll().toList() - override fun createObjects() { if (repository.count() == 0L) { logger.info("Running Event seeder...") + val accounts = accountRepository.findAll().toList() + val perActivityRoles = perActivityRoleRepository.findAll().toList() + + perActivityRoles.map { entityManager.merge(it) }.toMutableList() + // Helper function to generate a valid DateInterval fun generateDateInterval(daysFromNow: Int, durationDays: Int): DateInterval { val startDate = Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * daysFromNow)) diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt index 95d40759..08290447 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/ProjectSeeder.kt @@ -1,36 +1,45 @@ package pt.up.fe.ni.website.backend.model.seeders +import jakarta.persistence.EntityManager +import jakarta.transaction.Transactional import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component import pt.up.fe.ni.website.backend.config.Logging import pt.up.fe.ni.website.backend.model.Project +import pt.up.fe.ni.website.backend.model.TimelineEvent import pt.up.fe.ni.website.backend.repository.AccountRepository import pt.up.fe.ni.website.backend.repository.CustomWebsiteRepository import pt.up.fe.ni.website.backend.repository.PerActivityRoleRepository import pt.up.fe.ni.website.backend.repository.ProjectRepository import pt.up.fe.ni.website.backend.repository.TimeLineEventRepository -@Component +@Component @Transactional class ProjectSeeder( @Autowired val accountRepository: AccountRepository, - @Autowired val perActivityRoleRepository: PerActivityRoleRepository, @Autowired val customWebsiteRepository: CustomWebsiteRepository, + @Autowired val perActivityRoleRepository: PerActivityRoleRepository, @Autowired val timelineEventRepository: TimeLineEventRepository, - @Autowired val timelineEventSeeder: TimeLineEventSeeder + @Autowired val timelineEventSeeder: TimeLineEventSeeder, + @Autowired val entityManager: EntityManager ) : AbstractSeeder(), Logging { - val accounts = accountRepository.findAll().toList() - val timelineEvents = timelineEventRepository.findAll().toList() - val perActivityRoles = perActivityRoleRepository.findAll().toList() - val customWebsites = customWebsiteRepository.findAll().toList() - override fun createObjects() { if (repository.count() == 0L) { logger.info("Running Project seeder...") // Ensuring timeline events are created before projects timelineEventSeeder.createObjects() - val shuffledTimelineEvents = timelineEvents.shuffled().toMutableList() + + val accounts = accountRepository.findAll().toList() + val timelineEvents = timelineEventRepository.findAll().toList() + val customWebsites = customWebsiteRepository.findAll().toList() + val perActivityRoles = perActivityRoleRepository.findAll().toList() + + val shuffledTimelineEvents = timelineEvents.shuffled() + .map { entityManager.merge(it) }.toMutableList() + + customWebsites.map { entityManager.merge(it) }.toMutableList() + perActivityRoles.map { entityManager.merge(it) }.toMutableList() val projects = (1..6).map { val title = faker.company().bs() @@ -44,8 +53,11 @@ class ProjectSeeder( .replace(Regex("[^a-z0-9-]"), "") // Ensure only one TimeLineEvent per project - val projectTimeline = shuffledTimelineEvents.take(1).toMutableList() - shuffledTimelineEvents.removeAt(0) + var projectTimeline = mutableListOf() + if (shuffledTimelineEvents.isNotEmpty()) { + projectTimeline = shuffledTimelineEvents.take(1).toMutableList() + shuffledTimelineEvents.removeAt(0) + } val hallOfFameMembers = accounts.shuffled().take(2).toMutableList() @@ -53,8 +65,8 @@ class ProjectSeeder( title = title, description = description, teamMembers = accounts.shuffled().take(3).toMutableList(), - associatedRoles = perActivityRoles.shuffled().take(1).toMutableList(), slug = slug, + associatedRoles = perActivityRoles.shuffled().take(2).toMutableList(), image = "${slug}_image.png", isArchived = faker.random().nextBoolean(), technologies = technologies, From 8489e238ae6c04fd0bc27f4933ac437d8a8eebc9 Mon Sep 17 00:00:00 2001 From: Pedro Vidal Date: Sat, 16 Nov 2024 17:38:39 +0000 Subject: [PATCH 10/10] all seeded accounts with the same password --- .../website/backend/model/seeders/AccountSeeder.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt index 08f9f329..eff37d3f 100644 --- a/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt +++ b/src/main/kotlin/pt/up/fe/ni/website/backend/model/seeders/AccountSeeder.kt @@ -52,7 +52,7 @@ class AccountSeeder( Account( name = faker.name().fullName(), email = faker.internet().emailAddress(), - password = encoder.encode("securepass"), + password = encoder.encode("password123"), bio = faker.lorem().sentence(), birthDate = Date.from(faker.date().birthday(30, 40).toInstant()), photo = null, @@ -64,7 +64,7 @@ class AccountSeeder( Account( name = faker.name().fullName(), email = faker.internet().emailAddress(), - password = encoder.encode("anothersecurepass"), + password = encoder.encode("password123"), bio = null, birthDate = Date.from(faker.date().birthday(18, 28).toInstant()), photo = faker.internet().image(), @@ -77,7 +77,7 @@ class AccountSeeder( Account( name = faker.name().fullName(), email = faker.internet().emailAddress(), - password = encoder.encode("minpass"), + password = encoder.encode("password123"), bio = null, birthDate = Date.from(faker.date().birthday(20, 30).toInstant()), photo = null, @@ -90,7 +90,7 @@ class AccountSeeder( Account( name = faker.name().fullName(), email = faker.internet().emailAddress(), - password = encoder.encode("verysecure"), + password = encoder.encode("password123"), bio = faker.lorem().paragraph(5), birthDate = Date.from(faker.date().birthday(35, 45).toInstant()), photo = faker.internet().image(), @@ -102,7 +102,7 @@ class AccountSeeder( Account( name = faker.name().fullName(), email = faker.internet().emailAddress(), - password = encoder.encode("singlepass"), + password = encoder.encode("password123"), bio = "User with only one role.", birthDate = Date.from(faker.date().birthday(22, 32).toInstant()), photo = faker.internet().image(), @@ -115,7 +115,7 @@ class AccountSeeder( Account( name = faker.name().fullName(), email = faker.internet().emailAddress(), - password = encoder.encode("nullpass"), + password = encoder.encode("password123"), bio = null, birthDate = null, photo = null,