Skip to content

Commit 741b2ad

Browse files
CopilotCommanderStormCopilot
authored
Replace preview_edit links with GeoJSON fenced blocks in coordinate proposed edits (#2762)
* Initial plan * feat: replace preview_edit links with GeoJSON fenced blocks for coordinate edits Co-authored-by: CommanderStorm <26258709+CommanderStorm@users.noreply.github.com> * Update server/src/routes/feedback/proposed_edits/description.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix: update test_apply_set_as_blocks to match indented block output Co-authored-by: CommanderStorm <26258709+CommanderStorm@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: CommanderStorm <26258709+CommanderStorm@users.noreply.github.com> Co-authored-by: Frank Elsinga <frank@elsinga.de> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent b6a4283 commit 741b2ad

File tree

3 files changed

+124
-6
lines changed

3 files changed

+124
-6
lines changed

server/src/routes/feedback/proposed_edits/coordinate.rs

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,22 @@ impl AppliableEdit for Coordinate {
6868
// Replace original file with temp file
6969
std::fs::rename(&temp_file, &csv_file).unwrap();
7070

71-
format!(
72-
"https://nav.tum.de/api/preview_edit/{key}?to_lat={lat}&to_lon={lon}",
73-
lat = self.lat,
74-
lon = self.lon
75-
)
71+
let geojson = serde_json::json!({
72+
"type": "Feature",
73+
"geometry": {
74+
"type": "Point",
75+
// GeoJSON uses [longitude, latitude] ordering per RFC 7946
76+
"coordinates": [self.lon, self.lat]
77+
},
78+
"properties": {
79+
"kind": "coordinate-change",
80+
"id": key,
81+
"to_lat": self.lat,
82+
"to_lon": self.lon
83+
}
84+
});
85+
let pretty = serde_json::to_string_pretty(&geojson).unwrap_or_else(|_| geojson.to_string());
86+
format!("```geojson\n{pretty}\n```")
7687
}
7788
}
7889

@@ -233,4 +244,43 @@ mod tests {
233244
let expected = "id,lat,lon\n0,0,0\n";
234245
assert_eq!(fs::read_to_string(&csv_file).unwrap(), expected);
235246
}
247+
248+
#[test]
249+
fn test_apply_returns_geojson_block() {
250+
let coord = Coordinate {
251+
lat: 48.262,
252+
lon: 11.668,
253+
};
254+
let (dir, _csv_file) = setup();
255+
let result = coord.apply("mi", dir.path(), "branch");
256+
257+
// The result must start and end with the geojson fenced block markers.
258+
assert!(
259+
result.starts_with("```geojson\n"),
260+
"expected fenced geojson block, got: {result}"
261+
);
262+
assert!(
263+
result.ends_with("\n```"),
264+
"expected closing fence, got: {result}"
265+
);
266+
267+
// Strip the fences and parse as JSON.
268+
let json_str = result
269+
.strip_prefix("```geojson\n")
270+
.unwrap()
271+
.strip_suffix("\n```")
272+
.unwrap();
273+
let value: serde_json::Value = serde_json::from_str(json_str)
274+
.expect("apply() must return valid JSON inside the fenced block");
275+
276+
assert_eq!(value["type"], "Feature");
277+
assert_eq!(value["geometry"]["type"], "Point");
278+
// GeoJSON coordinate order is [longitude, latitude].
279+
assert_eq!(value["geometry"]["coordinates"][0], 11.668);
280+
assert_eq!(value["geometry"]["coordinates"][1], 48.262);
281+
assert_eq!(value["properties"]["kind"], "coordinate-change");
282+
assert_eq!(value["properties"]["id"], "mi");
283+
assert_eq!(value["properties"]["to_lat"], 48.262);
284+
assert_eq!(value["properties"]["to_lon"], 11.668);
285+
}
236286
}

server/src/routes/feedback/proposed_edits/description.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,36 @@ impl Description {
4040
}
4141
}
4242
}
43+
44+
pub fn apply_set_as_blocks<T: AppliableEdit>(
45+
&mut self,
46+
category_name: &'static str,
47+
set: HashMap<String, T>,
48+
base_dir: &Path,
49+
branch: &str,
50+
) {
51+
if !set.is_empty() {
52+
let edits = if set.len() == 1 { "edit" } else { "edits" };
53+
if self.title.is_empty() {
54+
self.title = format!("{amount} {category_name} {edits}", amount = set.len());
55+
} else {
56+
self.title += &format!(" and {amount} {category_name} {edits}", amount = set.len());
57+
}
58+
59+
self.body += &format!("\nThe following {category_name} edits were made:\n");
60+
61+
for (key, value) in set {
62+
let result = value.apply(&key, base_dir, branch);
63+
let indented_result = result
64+
.lines()
65+
.map(|line| format!(" {line}"))
66+
.collect::<Vec<_>>()
67+
.join("\n");
68+
self.body +=
69+
&format!("- [`{key}`](https://nav.tum.de/view/{key}):\n\n{indented_result}\n");
70+
}
71+
}
72+
}
4373
}
4474

4575
#[cfg(test)]
@@ -94,4 +124,37 @@ mod tests {
94124
"\nThe following category edits were made:\n| entry | edit |\n| --- | --- |\n| [`key`](https://nav.tum.de/view/key) | applied_value |\n"
95125
);
96126
}
127+
128+
#[test]
129+
fn test_apply_set_as_blocks_empty() {
130+
let mut description = Description::default();
131+
let set: HashMap<String, TestEdit> = HashMap::default();
132+
description.apply_set_as_blocks("coordinate", set, Path::new(""), "none");
133+
assert_eq!(description.title, "");
134+
assert_eq!(description.body, "");
135+
}
136+
137+
#[test]
138+
fn test_apply_set_as_blocks() {
139+
let mut description = Description::default();
140+
let set = HashMap::from([("key".to_string(), TestEdit)]);
141+
description.apply_set_as_blocks("coordinate", set, Path::new(""), "none");
142+
assert_eq!(description.title, "1 coordinate edit");
143+
// A blank line after the list-item colon and 4-space indentation ensure the fenced block
144+
// is rendered as content of the list item in GitHub-flavored Markdown.
145+
assert_eq!(
146+
description.body,
147+
"\nThe following coordinate edits were made:\n- [`key`](https://nav.tum.de/view/key):\n\n applied_value\n"
148+
);
149+
}
150+
151+
#[test]
152+
fn test_apply_set_as_blocks_does_not_use_table() {
153+
let mut description = Description::default();
154+
let set = HashMap::from([("key".to_string(), TestEdit)]);
155+
description.apply_set_as_blocks("coordinate", set, Path::new(""), "none");
156+
// Block output must not contain table syntax.
157+
assert!(!description.body.contains("| entry |"));
158+
assert!(!description.body.contains("| ---"));
159+
}
97160
}

server/src/routes/feedback/proposed_edits/tmp_repo.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,12 @@ impl TempRepo {
5454
description.add_context(&edits.additional_context);
5555

5656
let coordinate_edits = edits.edits_for(|edit| edit.coordinate);
57-
description.appply_set("coordinate", coordinate_edits, self.dir.path(), branch_name);
57+
description.apply_set_as_blocks(
58+
"coordinate",
59+
coordinate_edits,
60+
self.dir.path(),
61+
branch_name,
62+
);
5863
let image_edits = edits.edits_for(|edit| edit.image);
5964
description.appply_set("image", image_edits, self.dir.path(), branch_name);
6065

0 commit comments

Comments
 (0)