diff --git a/src/main/java/com/debatetimer/domain/organization/Organization.java b/src/main/java/com/debatetimer/domain/organization/Organization.java new file mode 100644 index 00000000..23b0b219 --- /dev/null +++ b/src/main/java/com/debatetimer/domain/organization/Organization.java @@ -0,0 +1,26 @@ +package com.debatetimer.domain.organization; + +import java.util.List; +import lombok.Getter; + +@Getter +public class Organization { + + private final Long id; + private final String name; + private final String affiliation; + private final String iconPath; + private final List templates; + + public Organization(Long id, + String name, + String affiliation, + String iconPath, + List templates) { + this.id = id; + this.name = name; + this.affiliation = affiliation; + this.iconPath = iconPath; + this.templates = templates; + } +} diff --git a/src/main/java/com/debatetimer/domain/organization/OrganizationTemplate.java b/src/main/java/com/debatetimer/domain/organization/OrganizationTemplate.java new file mode 100644 index 00000000..6c920f38 --- /dev/null +++ b/src/main/java/com/debatetimer/domain/organization/OrganizationTemplate.java @@ -0,0 +1,17 @@ +package com.debatetimer.domain.organization; + +import lombok.Getter; + +@Getter +public class OrganizationTemplate { + + private final Long id; + private final String name; + private final String data; + + public OrganizationTemplate(Long id, String name, String data) { + this.id = id; + this.name = name; + this.data = data; + } +} diff --git a/src/main/java/com/debatetimer/domainrepository/organization/OrganizationDomainRepository.java b/src/main/java/com/debatetimer/domainrepository/organization/OrganizationDomainRepository.java new file mode 100644 index 00000000..f13054e6 --- /dev/null +++ b/src/main/java/com/debatetimer/domainrepository/organization/OrganizationDomainRepository.java @@ -0,0 +1,39 @@ +package com.debatetimer.domainrepository.organization; + +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.mapping; +import static java.util.stream.Collectors.toList; + +import com.debatetimer.domain.organization.Organization; +import com.debatetimer.domain.organization.OrganizationTemplate; +import com.debatetimer.entity.organization.OrganizationTemplateEntity; +import com.debatetimer.repository.organization.OrganizationRepository; +import com.debatetimer.repository.organization.OrganizationTemplateRepository; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class OrganizationDomainRepository { + + private final OrganizationRepository organizationRepository; + private final OrganizationTemplateRepository organizationTemplateRepository; + + public List findAll() { + Map> idToTemplatesEntity = organizationTemplateRepository.findAll() + .stream() + .collect(groupingBy( + OrganizationTemplateEntity::getOrganizationId, + mapping(OrganizationTemplateEntity::toDomain, toList())) + ); + + return organizationRepository.findAll() + .stream() + .map(entity -> entity.toDomain( + idToTemplatesEntity.getOrDefault(entity.getId(), Collections.emptyList())) + ).toList(); + } +} diff --git a/src/main/java/com/debatetimer/entity/organization/OrganizationEntity.java b/src/main/java/com/debatetimer/entity/organization/OrganizationEntity.java new file mode 100644 index 00000000..326e289e --- /dev/null +++ b/src/main/java/com/debatetimer/entity/organization/OrganizationEntity.java @@ -0,0 +1,46 @@ +package com.debatetimer.entity.organization; + +import com.debatetimer.domain.organization.Organization; +import com.debatetimer.domain.organization.OrganizationTemplate; +import com.debatetimer.entity.BaseTimeEntity; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import java.util.List; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Table(name = "organization") +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class OrganizationEntity extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotBlank + private String name; + + @NotNull + private String affiliation; + + @NotBlank + private String iconPath; + + public OrganizationEntity(String name, String affiliation, String iconPath) { + this.name = name; + this.affiliation = affiliation; + this.iconPath = iconPath; + } + + public Organization toDomain(List templates) { + return new Organization(this.id, this.name, this.affiliation, this.iconPath, templates); + } +} diff --git a/src/main/java/com/debatetimer/entity/organization/OrganizationTemplateEntity.java b/src/main/java/com/debatetimer/entity/organization/OrganizationTemplateEntity.java new file mode 100644 index 00000000..96753279 --- /dev/null +++ b/src/main/java/com/debatetimer/entity/organization/OrganizationTemplateEntity.java @@ -0,0 +1,56 @@ +package com.debatetimer.entity.organization; + + +import com.debatetimer.domain.organization.OrganizationTemplate; +import com.debatetimer.entity.BaseTimeEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Table(name = "organization_template") +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class OrganizationTemplateEntity extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotNull + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "organization_id") + private OrganizationEntity organization; + + @NotBlank + private String name; + + @NotBlank + @Column(length = 8191) + private String data; + + public OrganizationTemplateEntity(OrganizationEntity organization, String name, String data) { + this.organization = organization; + this.name = name; + this.data = data; + } + + public OrganizationTemplate toDomain() { + return new OrganizationTemplate(this.id, this.name, this.data); + } + + public Long getOrganizationId() { + return this.organization.getId(); + } +} diff --git a/src/main/java/com/debatetimer/repository/organization/OrganizationRepository.java b/src/main/java/com/debatetimer/repository/organization/OrganizationRepository.java new file mode 100644 index 00000000..5c6ef65a --- /dev/null +++ b/src/main/java/com/debatetimer/repository/organization/OrganizationRepository.java @@ -0,0 +1,12 @@ +package com.debatetimer.repository.organization; + +import com.debatetimer.entity.organization.OrganizationEntity; +import java.util.List; +import org.springframework.data.repository.Repository; + +public interface OrganizationRepository extends Repository { + + List findAll(); + + OrganizationEntity save(OrganizationEntity organizationEntity); +} diff --git a/src/main/java/com/debatetimer/repository/organization/OrganizationTemplateRepository.java b/src/main/java/com/debatetimer/repository/organization/OrganizationTemplateRepository.java new file mode 100644 index 00000000..4c5b7472 --- /dev/null +++ b/src/main/java/com/debatetimer/repository/organization/OrganizationTemplateRepository.java @@ -0,0 +1,12 @@ +package com.debatetimer.repository.organization; + +import com.debatetimer.entity.organization.OrganizationTemplateEntity; +import java.util.List; +import org.springframework.data.repository.Repository; + +public interface OrganizationTemplateRepository extends Repository { + + List findAll(); + + OrganizationTemplateEntity save(OrganizationTemplateEntity entity); +} diff --git a/src/main/resources/db/migration/V15__create_organization_template.sql b/src/main/resources/db/migration/V15__create_organization_template.sql new file mode 100644 index 00000000..42ea295c --- /dev/null +++ b/src/main/resources/db/migration/V15__create_organization_template.sql @@ -0,0 +1,26 @@ +create table organization +( + id bigint auto_increment, + name varchar(255) not null, + affiliation varchar(255) not null, + icon_path varchar(255) not null, + created_at timestamp not null DEFAULT CURRENT_TIMESTAMP, + modified_at timestamp not null DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + primary key (id) +); + +create table organization_template +( + id bigint auto_increment, + name varchar(255) not null, + data varchar(8191) not null, + organization_id bigint not null, + created_at timestamp not null DEFAULT CURRENT_TIMESTAMP, + modified_at timestamp not null DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + primary key (id) +); + +alter table organization_template + add constraint organization_template_to_organization + foreign key (organization_id) + references organization (id); diff --git a/src/test/java/com/debatetimer/domainrepository/BaseDomainRepositoryTest.java b/src/test/java/com/debatetimer/domainrepository/BaseDomainRepositoryTest.java index 485a7f25..16b60f98 100644 --- a/src/test/java/com/debatetimer/domainrepository/BaseDomainRepositoryTest.java +++ b/src/test/java/com/debatetimer/domainrepository/BaseDomainRepositoryTest.java @@ -8,6 +8,8 @@ import com.debatetimer.fixture.entity.CustomizeTableEntityGenerator; import com.debatetimer.fixture.entity.CustomizeTimeBoxEntityGenerator; import com.debatetimer.fixture.entity.MemberGenerator; +import com.debatetimer.fixture.entity.OrganizationEntityGenerator; +import com.debatetimer.fixture.entity.OrganizationTemplateEntityGenerator; import com.debatetimer.fixture.entity.PollEntityGenerator; import com.debatetimer.fixture.entity.VoteEntityGenerator; import com.debatetimer.repository.customize.BellRepository; @@ -49,6 +51,12 @@ public abstract class BaseDomainRepositoryTest { @Autowired protected VoteEntityGenerator voteEntityGenerator; + @Autowired + protected OrganizationEntityGenerator organizationEntityGenerator; + + @Autowired + protected OrganizationTemplateEntityGenerator organizationTemplateEntityGenerator; + @Autowired protected PollRepository pollRepository; diff --git a/src/test/java/com/debatetimer/domainrepository/organization/OrganizationDomainRepositoryTest.java b/src/test/java/com/debatetimer/domainrepository/organization/OrganizationDomainRepositoryTest.java new file mode 100644 index 00000000..8e28eb07 --- /dev/null +++ b/src/test/java/com/debatetimer/domainrepository/organization/OrganizationDomainRepositoryTest.java @@ -0,0 +1,39 @@ +package com.debatetimer.domainrepository.organization; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import com.debatetimer.domain.organization.Organization; +import com.debatetimer.domainrepository.BaseDomainRepositoryTest; +import com.debatetimer.entity.organization.OrganizationEntity; +import java.util.List; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class OrganizationDomainRepositoryTest extends BaseDomainRepositoryTest { + + @Autowired + private OrganizationDomainRepository organizationDomainRepository; + + @Nested + class FindAll { + + @Test + void 모든_조직_템플릿을_가져온다() { + OrganizationEntity organization1 = organizationEntityGenerator.generate("한앎", "한양대"); + OrganizationEntity organization2 = organizationEntityGenerator.generate("한모름", "양한대"); + organizationTemplateEntityGenerator.generate(organization1, "템플릿1"); + organizationTemplateEntityGenerator.generate(organization1, "템플릿2"); + organizationTemplateEntityGenerator.generate(organization2, "릿플템1"); + + List organizations = organizationDomainRepository.findAll(); + + assertAll( + () -> assertThat(organizations).hasSize(2), + () -> assertThat(organizations.get(0).getTemplates()).hasSize(2), + () -> assertThat(organizations.get(1).getTemplates()).hasSize(1) + ); + } + } +} diff --git a/src/test/java/com/debatetimer/fixture/entity/OrganizationEntityGenerator.java b/src/test/java/com/debatetimer/fixture/entity/OrganizationEntityGenerator.java new file mode 100644 index 00000000..f193aeca --- /dev/null +++ b/src/test/java/com/debatetimer/fixture/entity/OrganizationEntityGenerator.java @@ -0,0 +1,22 @@ +package com.debatetimer.fixture.entity; + +import com.debatetimer.entity.organization.OrganizationEntity; +import com.debatetimer.repository.organization.OrganizationRepository; +import org.springframework.stereotype.Component; + +@Component +public class OrganizationEntityGenerator { + + private static final String DEFAULT_ICON_PATH = "/static/icons/default_icon.png"; + + private final OrganizationRepository organizationRepository; + + public OrganizationEntityGenerator(OrganizationRepository organizationRepository) { + this.organizationRepository = organizationRepository; + } + + public OrganizationEntity generate(String name, String affiliation) { + OrganizationEntity organization = new OrganizationEntity(name, affiliation, DEFAULT_ICON_PATH); + return organizationRepository.save(organization); + } +} diff --git a/src/test/java/com/debatetimer/fixture/entity/OrganizationTemplateEntityGenerator.java b/src/test/java/com/debatetimer/fixture/entity/OrganizationTemplateEntityGenerator.java new file mode 100644 index 00000000..45242cd7 --- /dev/null +++ b/src/test/java/com/debatetimer/fixture/entity/OrganizationTemplateEntityGenerator.java @@ -0,0 +1,24 @@ +package com.debatetimer.fixture.entity; + +import com.debatetimer.entity.organization.OrganizationEntity; +import com.debatetimer.entity.organization.OrganizationTemplateEntity; +import com.debatetimer.repository.organization.OrganizationTemplateRepository; +import org.springframework.stereotype.Component; + +@Component +public class OrganizationTemplateEntityGenerator { + + private static final String DEFAULT_TEMPLATE_CONTENT = "eJyrVspMUbIytjDXUcrMS8tXsqpWykvMTVWyUjJWKCtWMFZ427b1TXPj27YFrxcueN3T8HZWj8LbGVPfdM9V0lEqqSwAqXQODQ7x9%2FWMcgUKJaan5qUkAgWB7IKi%2FOKQ1MRcP4iBbzasedOyESienJ%2BHLP56wwygwUDx8sSivMy8dKfUnBwlq7TEnOJUHaW0zLzM4gwkoVqgtYlJOUCN0dVKxSWJeckgMwKC%2FIOBJhQXpKYmZ4RAnPVmXivQzUDRpPwKqJCff5Cvow%2FI5Zkgqw2NDICyYLPzSnNyIMIBqUUgx6EJBRekJmYDHQcTLgbxU4sg3FodJKc4%2B%2FsNFqf4uYaGBIEtQXPNhDdzFkCiFMVNIZ6%2BrvFOjsGuLnB3QazA6TBzkLMx3AX2DIkhtHXOm0WtCq83zHkzbQfdAwpr8qG7i2JrAbdLRw0%3D"; + + private final OrganizationTemplateRepository organizationTemplateRepository; + + public OrganizationTemplateEntityGenerator(OrganizationTemplateRepository organizationTemplateRepository) { + this.organizationTemplateRepository = organizationTemplateRepository; + } + + public OrganizationTemplateEntity generate(OrganizationEntity organization, String name) { + OrganizationTemplateEntity template = + new OrganizationTemplateEntity(organization, name, DEFAULT_TEMPLATE_CONTENT); + return organizationTemplateRepository.save(template); + } +}