Skip to content

Commit 8c550e4

Browse files
EpicFnEpicFn
andauthored
[Fix/OPS-378] 대시보드 하위 entity 수정 (#117)
* fix : node, edge dto 수정 * fix : 테스트 케이스 수정 * fix : 테스트 수정 완료 * fix : 오타 수정 * fix : 오타 추가 수정; --------- Co-authored-by: EpicFn <[email protected]>
1 parent 5159ba4 commit 8c550e4

File tree

6 files changed

+265
-114
lines changed

6 files changed

+265
-114
lines changed

src/main/java/org/tuna/zoopzoop/backend/domain/dashboard/dto/BodyForReactFlow.java

Lines changed: 75 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,42 @@ public record BodyForReactFlow(
1919
public record NodeDto(
2020
@JsonProperty("id") String nodeKey,
2121
@JsonProperty("type") String nodeType,
22-
Map<String, String> data,
23-
@JsonProperty("position") PositionDto positionDto
22+
@JsonProperty("selected") Boolean selected,
23+
@JsonProperty("dragging") Boolean dragging,
24+
@JsonProperty("position") PositionDto positionDto,
25+
@JsonProperty("measured") MeasurementsDto measurements,
26+
@JsonProperty("data") DataDto data
2427
) {
2528
public record PositionDto(
2629
@JsonProperty("x") double x,
2730
@JsonProperty("y") double y
28-
) {}
31+
) {}
32+
33+
public record MeasurementsDto(
34+
@JsonProperty("width") double width,
35+
@JsonProperty("height") double height
36+
) {}
37+
38+
public record DataDto(
39+
@JsonProperty("content") String content,
40+
@JsonProperty("createdAt") String createAt, // YYYY-MM-DD format
41+
@JsonProperty("link") String sourceUrl,
42+
@JsonProperty("title") String title,
43+
@JsonProperty("user") WriterDto writer
44+
) {}
45+
46+
public record WriterDto(
47+
@JsonProperty("name") String name,
48+
@JsonProperty("profileUrl") String profileImageUrl
49+
) {}
50+
2951
}
3052

3153
public record EdgeDto(
3254
@JsonProperty("id") String edgeKey,
3355
@JsonProperty("source") String sourceNodeKey,
34-
@JsonProperty("target") String targetNodeKey,
35-
@JsonProperty("type") String edgeType,
36-
@JsonProperty("animated") boolean isAnimated,
37-
@JsonProperty("style") StyleDto styleDto
56+
@JsonProperty("target") String targetNodeKey
3857
) {
39-
public record StyleDto(
40-
String stroke,
41-
Double strokeWidth
42-
) {}
4358
}
4459

4560
// DTO -> Entity, BodyForReactFlow를 Graph 엔티티로 변환
@@ -51,10 +66,24 @@ public Graph toEntity() {
5166
Node node = new Node();
5267
node.setNodeKey(dto.nodeKey());
5368
node.setNodeType(NodeType.valueOf(dto.nodeType().toUpperCase()));
54-
node.setData(dto.data());
55-
node.setPositonX(dto.positionDto().x());
56-
node.setPositonY(dto.positionDto().y());
57-
node.setGraph(graph); // 연관관계 설정
69+
node.setSelected(dto.selected() != null ? dto.selected() : false);
70+
node.setDragging(dto.dragging() != null ? dto.dragging() : false);
71+
node.setPositionX(dto.positionDto().x());
72+
node.setPositionY(dto.positionDto().y());
73+
if (dto.measurements() != null) {
74+
node.setWidth(dto.measurements().width());
75+
node.setHeight(dto.measurements().height());
76+
}
77+
if (dto.data() != null) {
78+
node.setData(Map.of(
79+
"content", dto.data().content(),
80+
"createdAt", dto.data().createAt(),
81+
"sourceUrl", dto.data().sourceUrl(),
82+
"title", dto.data().title(),
83+
"writerName", dto.data().writer() != null ? dto.data().writer().name() : null,
84+
"writerProfileImageUrl", dto.data().writer() != null ? dto.data().writer().profileImageUrl() : null
85+
));
86+
}
5887
return node;
5988
})
6089
.toList();
@@ -65,12 +94,6 @@ public Graph toEntity() {
6594
edge.setEdgeKey(dto.edgeKey());
6695
edge.setSourceNodeKey(dto.sourceNodeKey());
6796
edge.setTargetNodeKey(dto.targetNodeKey());
68-
edge.setEdgeType(EdgeType.valueOf(dto.edgeType().toUpperCase()));
69-
edge.setAnimated(dto.isAnimated());
70-
if (dto.styleDto() != null) {
71-
edge.setStroke(dto.styleDto().stroke());
72-
edge.setStrokeWidth(dto.styleDto().strokeWidth());
73-
}
7497
edge.setGraph(graph); // 연관관계 설정
7598
return edge;
7699
})
@@ -88,19 +111,28 @@ public static BodyForReactFlow from(Graph graph) {
88111
.map(n -> new NodeDto(
89112
n.getNodeKey(),
90113
n.getNodeType().name().toUpperCase(),
91-
n.getData(),
92-
new NodeDto.PositionDto(n.getPositonX(), n.getPositonY())
114+
n.isSelected(),
115+
n.isDragging(),
116+
new NodeDto.PositionDto(n.getPositionX(), n.getPositionY()),
117+
new NodeDto.MeasurementsDto(n.getWidth(), n.getHeight()),
118+
new NodeDto.DataDto(
119+
n.getData().get("content"),
120+
n.getData().get("createdAt"),
121+
n.getData().get("sourceUrl"),
122+
n.getData().get("title"),
123+
new NodeDto.WriterDto(
124+
n.getData().get("writerName"),
125+
n.getData().get("writerProfileImageUrl")
126+
)
127+
)
93128
))
94129
.toList();
95130

96131
List<EdgeDto> edgeDtos = graph.getEdges().stream()
97132
.map(e -> new EdgeDto(
98133
e.getEdgeKey(),
99134
e.getSourceNodeKey(),
100-
e.getTargetNodeKey(),
101-
e.getEdgeType().name().toUpperCase(),
102-
e.isAnimated(),
103-
new EdgeDto.StyleDto(e.getStroke(), e.getStrokeWidth())
135+
e.getTargetNodeKey()
104136
))
105137
.toList();
106138

@@ -113,9 +145,22 @@ public List<Node> toNodeEntities(Graph graph) {
113145
Node node = new Node();
114146
node.setNodeKey(dto.nodeKey());
115147
node.setNodeType(NodeType.valueOf(dto.nodeType().toUpperCase()));
116-
node.setData(dto.data());
117-
node.setPositonX(dto.positionDto().x());
118-
node.setPositonY(dto.positionDto().y());
148+
node.setPositionX(dto.positionDto().x());
149+
node.setPositionY(dto.positionDto().y());
150+
if (dto.measurements() != null) {
151+
node.setWidth(dto.measurements().width());
152+
node.setHeight(dto.measurements().height());
153+
}
154+
if (dto.data() != null) {
155+
node.setData(Map.of(
156+
"content", dto.data().content(),
157+
"createdAt", dto.data().createAt(),
158+
"sourceUrl", dto.data().sourceUrl(),
159+
"title", dto.data().title(),
160+
"writerName", dto.data().writer() != null ? dto.data().writer().name() : null,
161+
"writerProfileImageUrl", dto.data().writer() != null ? dto.data().writer().profileImageUrl() : null
162+
));
163+
}
119164
node.setGraph(graph); // 연관관계 설정
120165
return node;
121166
})
@@ -129,12 +174,6 @@ public List<Edge> toEdgeEntities(Graph graph) {
129174
edge.setEdgeKey(dto.edgeKey());
130175
edge.setSourceNodeKey(dto.sourceNodeKey());
131176
edge.setTargetNodeKey(dto.targetNodeKey());
132-
edge.setEdgeType(EdgeType.valueOf(dto.edgeType().toUpperCase()));
133-
edge.setAnimated(dto.isAnimated());
134-
if (dto.styleDto() != null) {
135-
edge.setStroke(dto.styleDto().stroke());
136-
edge.setStrokeWidth(dto.styleDto().strokeWidth());
137-
}
138177
edge.setGraph(graph); // 연관관계 설정
139178
return edge;
140179
})

src/main/java/org/tuna/zoopzoop/backend/domain/dashboard/entity/Edge.java

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,4 @@ public class Edge extends BaseEntity {
2222

2323
@Column
2424
private String targetNodeKey;
25-
26-
@Column
27-
@Enumerated(EnumType.STRING)
28-
private EdgeType edgeType;
29-
30-
@Column
31-
boolean isAnimated;
32-
33-
@Column
34-
private String stroke;
35-
36-
@Column
37-
private Double strokeWidth;
3825
}

src/main/java/org/tuna/zoopzoop/backend/domain/dashboard/entity/Node.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,27 @@ public class Node extends BaseEntity {
2424
@Enumerated(EnumType.STRING)
2525
private NodeType nodeType;
2626

27+
@Column
28+
private boolean selected;
29+
30+
@Column
31+
private boolean dragging;
32+
2733
@ElementCollection
2834
@CollectionTable(name = "node_data", joinColumns = @JoinColumn(name = "node_id"))
2935
@MapKeyColumn(name = "data_key")
3036
@Column(name = "data_value")
3137
private Map<String, String> data = new HashMap<>();
3238

3339
@Column
34-
private double positonX;
40+
private double positionX;
41+
42+
@Column
43+
private double positionY;
44+
45+
@Column
46+
private double width;
3547

3648
@Column
37-
private double positonY;
49+
private double height;
3850
}

src/test/java/org/tuna/zoopzoop/backend/domain/dashboard/controller/DashboardControllerTest.java

Lines changed: 86 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
import org.springframework.test.web.servlet.ResultActions;
1414
import org.springframework.transaction.annotation.Transactional;
1515
import org.springframework.transaction.support.TransactionTemplate;
16+
import org.tuna.zoopzoop.backend.domain.dashboard.entity.Edge;
1617
import org.tuna.zoopzoop.backend.domain.dashboard.entity.Graph;
18+
import org.tuna.zoopzoop.backend.domain.dashboard.entity.Node;
1719
import org.tuna.zoopzoop.backend.domain.member.enums.Provider;
1820
import org.tuna.zoopzoop.backend.domain.member.repository.MemberRepository;
1921
import org.tuna.zoopzoop.backend.domain.member.service.MemberService;
@@ -30,6 +32,7 @@
3032
import java.nio.charset.StandardCharsets;
3133
import java.security.InvalidKeyException;
3234
import java.security.NoSuchAlgorithmException;
35+
import java.util.Map;
3336
import java.util.concurrent.TimeUnit;
3437

3538
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
@@ -183,9 +186,32 @@ void updateGraph_Success() throws Exception {
183186
transactionTemplate.execute(status -> {
184187
Space space = spaceService.findByName(authorizedSpaceName);
185188
Graph updatedGraph = space.getDashboard().getGraph();
189+
190+
// 1. 노드와 엣지의 전체 개수 검증
186191
assertThat(updatedGraph.getNodes()).hasSize(2);
187192
assertThat(updatedGraph.getEdges()).hasSize(1);
188-
assertThat(updatedGraph.getNodes().get(0).getData().get("title")).isEqualTo("노드1");
193+
194+
// 2. 특정 노드(id="1")의 상세 데이터 검증
195+
// DTO의 List 순서대로 엔티티가 생성되므로 get(0)으로 첫 번째 노드를 특정합니다.
196+
Node firstNode = updatedGraph.getNodes().get(0);
197+
assertThat(firstNode.getNodeKey()).isEqualTo("1");
198+
assertThat(firstNode.getPositionX()).isEqualTo(100.0);
199+
assertThat(firstNode.getPositionY()).isEqualTo(200.0);
200+
201+
// Node의 data Map 내부 값들을 상세히 검증
202+
Map<String, String> data = firstNode.getData();
203+
assertThat(data.get("title")).isEqualTo("노드 1");
204+
assertThat(data.get("content")).isEqualTo("첫 번째 노드에 대한 간단한 요약 내용입니다. 이 내용은 노드 내부에 표시됩니다.");
205+
assertThat(data.get("sourceUrl")).isEqualTo("https://example.com/source1");
206+
assertThat(data.get("writerName")).isEqualTo("김Tuna");
207+
assertThat(data.get("writerProfileImageUrl")).isEqualTo("https://example.com/profiles/tuna.jpg");
208+
209+
// 3. 엣지(id="e1-2")의 상세 데이터 검증
210+
Edge edge = updatedGraph.getEdges().get(0);
211+
assertThat(edge.getEdgeKey()).isEqualTo("e1-2");
212+
assertThat(edge.getSourceNodeKey()).isEqualTo("1");
213+
assertThat(edge.getTargetNodeKey()).isEqualTo("2");
214+
189215
return null; // execute 메서드는 반환값이 필요
190216
});
191217
});
@@ -235,32 +261,65 @@ void updateGraph_Fail_Forbidden() throws Exception {
235261

236262
private String createReactFlowJsonBody() {
237263
return """
238-
{
239-
"nodes": [
240-
{
241-
"id": "1",
242-
"type": "CUSTOM",
243-
"data": { "title": "노드1", "description": "설명1" },
244-
"position": { "x": 100, "y": 200 }
245-
},
246-
{
247-
"id": "2",
248-
"type": "CUSTOM",
249-
"data": { "title": "노드2" },
250-
"position": { "x": 300, "y": 400 }
251-
}
252-
],
253-
"edges": [
254-
{
255-
"id": "e1-2",
256-
"source": "1",
257-
"target": "2",
258-
"type": "SMOOTHSTEP",
259-
"animated": true,
260-
"style": { "stroke": "#999", "strokeWidth": 2.0 }
261-
}
262-
]
263-
}
264+
{
265+
"nodes": [
266+
{
267+
"id": "1",
268+
"type": "CUSTOM",
269+
"selected": false,
270+
"dragging": false,
271+
"position": {
272+
"x": 100,
273+
"y": 200
274+
},
275+
"measured": {
276+
"width": 250,
277+
"height": 150
278+
},
279+
"data": {
280+
"content": "첫 번째 노드에 대한 간단한 요약 내용입니다. 이 내용은 노드 내부에 표시됩니다.",
281+
"createdAt": "2025-10-02",
282+
"link": "https://example.com/source1",
283+
"title": "노드 1",
284+
"user": {
285+
"name": "김Tuna",
286+
"profileUrl": "https://example.com/profiles/tuna.jpg"
287+
}
288+
}
289+
},
290+
{
291+
"id": "2",
292+
"type": "CUSTOM",
293+
"selected": false,
294+
"dragging": false,
295+
"position": {
296+
"x": 500,
297+
"y": 300
298+
},
299+
"measured": {
300+
"width": 250,
301+
"height": 150
302+
},
303+
"data": {
304+
"content": "두 번째 노드에 대한 요약입니다. 원본 소스는 다른 곳을 가리킵니다.",
305+
"createdAt": "2025-10-01",
306+
"link": "https://example.com/source2",
307+
"title": "노드 2",
308+
"user": {
309+
"name": "박Zoop",
310+
"profileUrl": "https://example.com/profiles/zoop.jpg"
311+
}
312+
}
313+
}
314+
],
315+
"edges": [
316+
{
317+
"id": "e1-2",
318+
"source": "1",
319+
"target": "2"
320+
}
321+
]
322+
}
264323
""";
265324
}
266325

0 commit comments

Comments
 (0)