diff --git a/server/stt/stt_planning_ml.py b/server/stt/stt_planning_ml.py index 6ab2bfd..949c005 100644 --- a/server/stt/stt_planning_ml.py +++ b/server/stt/stt_planning_ml.py @@ -28,11 +28,18 @@ class STTPlanningMLParser(PlanningMLParser): def parse(self, tree: Element, provider=None): items = super(STTPlanningMLParser, self).parse(tree, provider) items_to_ingest = [] + planning_service = get_resource_service("planning") for item in items: if planning_xml_contains_remove_signal(tree): unpost_or_spike_event_or_planning(item) # If the item contains the ``sttinstruct:remove`` signal, no need to ingest this one continue + + planning_item = planning_service.find_one(req=None, _id=item["_id"]) + self.check_coverage( + item, planning_item, tree + ) if planning_item else self.set_placeholder_coverage(item, tree) + self.set_extra_fields(item, tree) items_to_ingest.append(item) @@ -148,6 +155,45 @@ def set_urgency(self, content_meta, item): return item + def set_placeholder_coverage(self, item, tree): + """ + Set a Placeholder Coverage if no coverages are provided in the parsed item + """ + if not item.get("coverages"): + placeholder_coverage = [ + { + "coverage_id": f"placeholder_{item.get('guid')}", + "workflow_status": "draft", + "firstcreated": item.get("firstcreated"), + "planning": { + "slugline": "Placeholder Coverage", + "g2_content_type": "text", + "scheduled": item.get("planning_date"), + }, + "flags": {"placeholder": True}, + } + ] + item["coverages"] = placeholder_coverage + + super(STTPlanningMLParser, self).parse_news_coverage_status(tree, item) + + def check_coverage(self, item, planning_item, tree): + # if existing item is found in the db update coverage details of that item based on new item. + if not planning_item.get("coverages"): + # Existing: No Coverages | Ingest: No Coverages + self.set_placeholder_coverage(item, tree) + elif not item.get("coverages"): + # Existing: Coverages | Ingest: No Coverages + self.set_placeholder_coverage(item, tree) + else: + # Existing: Coverages | Ingest: Coverages + for existing_coverage in planning_item["coverages"]: + if existing_coverage.get("flags", {}).get("placeholder"): + # Existing: Placeholder Coverage | Ingest: Coverages + planning_item["coverages"].remove(existing_coverage) + # Update news_coverage_status for provided coverages + super(STTPlanningMLParser, self).parse_news_coverage_status(tree, item) + stt_planning_ml_parser = STTPlanningMLParser() register_feed_parser(STTPlanningMLParser.NAME, stt_planning_ml_parser) diff --git a/server/tests/fixtures/stt_planning_ml_placeholder-2.xml b/server/tests/fixtures/stt_planning_ml_placeholder-2.xml new file mode 100644 index 0000000..55a2ed9 --- /dev/null +++ b/server/tests/fixtures/stt_planning_ml_placeholder-2.xml @@ -0,0 +1,61 @@ + + + + + + + +2023-05-15T14:50:03+02:00 + + + +2023-05-15T14:50:03+02:00 +2023-05-15T14:50:03+02:00 +Karelian Lock 23 -taisteluharjoituksen mediapäivä +Maavoimien alueellinen taisteluharjoitus Karelian Lock 23 järjestetään Kouvolan, Luumäen ja Haminan alueilla 26.5–2.6.2023. Harjoituksessa kehitetään johtamisvalmiuksia ja yhteistoimintaa muiden puolustushaarojen kanssa. Harjoituksessa on mukana kansainvälisiä joukkoja Yhdysvaltojen maavoimista. +Harjoituksen kokonaisvahvuus on yhteensä noin 7000 henkilöä ja 720 ajoneuvoa. Harjoitukseen osallistuu palkatun henkilökunnan lisäksi varusmiehiä ja reserviläisiä. Kansainvälisten joukkojen vahvuus harjoituksessa on noin 450 henkilöä. +Mediatilaisuudessa on mahdollisuus tutustua harjoitukseen ja haastatella harjoitukseen osallistuvia joukkoja. + + + + +Kotimaa + + + + + + + + +application/vnd.iptc.g2.newsitem+xml + +2023-06-01T19:30:00+02:00 +Sudanissa taistelut jatkuvat + + + +Pääjuttu + + + + + + + + +2023-06-01T08:36:57+02:00 + + +2023-06-01T09:08:12+02:00 + + +2023-06-01T09:09:01+02:00 + + +2023-06-01T08:35:30+02:00 + + + + + \ No newline at end of file diff --git a/server/tests/fixtures/stt_planning_ml_placeholder.xml b/server/tests/fixtures/stt_planning_ml_placeholder.xml new file mode 100644 index 0000000..292f146 --- /dev/null +++ b/server/tests/fixtures/stt_planning_ml_placeholder.xml @@ -0,0 +1,28 @@ + + + + + + + +2023-05-15T14:50:03+02:00 + + + +2023-05-15T14:50:03+02:00 +2023-05-15T14:50:03+02:00 +Karelian Lock 23 -taisteluharjoituksen mediapäivä +Maavoimien alueellinen taisteluharjoitus Karelian Lock 23 järjestetään Kouvolan, Luumäen ja Haminan alueilla 26.5–2.6.2023. Harjoituksessa kehitetään johtamisvalmiuksia ja yhteistoimintaa muiden puolustushaarojen kanssa. Harjoituksessa on mukana kansainvälisiä joukkoja Yhdysvaltojen maavoimista. +Harjoituksen kokonaisvahvuus on yhteensä noin 7000 henkilöä ja 720 ajoneuvoa. Harjoitukseen osallistuu palkatun henkilökunnan lisäksi varusmiehiä ja reserviläisiä. Kansainvälisten joukkojen vahvuus harjoituksessa on noin 450 henkilöä. +Mediatilaisuudessa on mahdollisuus tutustua harjoitukseen ja haastatella harjoitukseen osallistuvia joukkoja. + + + + +Kotimaa + + + + + + diff --git a/server/tests/stt_planning_ml_test.py b/server/tests/stt_planning_ml_test.py index 676a762..47e651d 100644 --- a/server/tests/stt_planning_ml_test.py +++ b/server/tests/stt_planning_ml_test.py @@ -1,5 +1,10 @@ from tests import TestCase from stt.stt_planning_ml import STTPlanningMLParser +from datetime import datetime, timedelta +from dateutil.tz import tzoffset, tzutc +from superdesk.io.commands.update_ingest import ingest_item +from superdesk import get_resource_service +from bson import ObjectId class STTPlanningMLParserTest(TestCase): @@ -36,3 +41,129 @@ def test_stt_metadata(self): }, self.item["subject"], ) + + def test_placeholder_coverage(self): + # Case 1 : If Ingest Item does not contain any Coverage + + self.fixture = "stt_planning_ml_placeholder.xml" + self.parse_source_content() + self.assertEqual(self.item["guid"], "urn:newsml:stt.fi:20230529:620121") + self.assertEqual(self.item["state"], "ingested") + self.assertEqual(len(self.item["coverages"]), 1) + self.assertEqual( + self.item["versioncreated"], + datetime(2023, 5, 15, 14, 50, 3, tzinfo=tzoffset(None, 7200)), + ) + self.assertEqual( + self.item["firstcreated"], + datetime(2023, 5, 15, 14, 50, 3, tzinfo=tzoffset(None, 7200)), + ) + self.assertEqual( + self.item["name"], "Karelian Lock 23 -taisteluharjoituksen mediapäivä" + ) + self.assertEqual( + self.item["coverages"][0], + { + "coverage_id": "placeholder_urn:newsml:stt.fi:20230529:620121", + "workflow_status": "draft", + "firstcreated": datetime( + 2023, 5, 15, 14, 50, 3, tzinfo=tzoffset(None, 7200) + ), + "planning": { + "slugline": "Placeholder Coverage", + "g2_content_type": "text", + "scheduled": datetime(2023, 5, 28, 21, 0, tzinfo=tzutc()), + }, + "flags": {"placeholder": True}, + "news_coverage_status": { + "qcode": "ncostat:notint", + "name": "coverage not intended", + "label": "Not planned", + }, + }, + ) + + # Case 2 : If ingest item contain coverage. + + self.fixture = "stt_planning_ml_placeholder-2.xml" + self.parse_source_content() + print(self.item["coverages"]) + self.assertEqual(self.item["guid"], "urn:newsml:stt.fi:20230529:620121") + self.assertEqual(len(self.item["coverages"]), 1) + self.assertEqual( + self.item["coverages"][0], + { + "coverage_id": "ID_TEXT_120844691", + "workflow_status": "draft", + "firstcreated": datetime( + 2023, 5, 15, 14, 50, 3, tzinfo=tzoffset(None, 7200) + ), + "versioncreated": datetime( + 2023, 5, 15, 14, 50, 3, tzinfo=tzoffset(None, 7200) + ), + "planning": { + "slugline": "Sudanissa taistelut jatkuvat", + "g2_content_type": "text", + "scheduled": datetime( + 2023, 6, 1, 19, 30, tzinfo=tzoffset(None, 7200) + ), + "genre": [{"qcode": "sttgenre:1", "name": "Pääjuttu"}], + }, + "news_coverage_status": { + "qcode": "ncostat:notint", + "name": "coverage not intended", + "label": "Not planned", + }, + }, + ) + + def test_update_planning(self): + service = get_resource_service("planning") + self.fixture = "stt_planning_ml_placeholder.xml" + self.parse_source_content() + source = self.item + provider = { + "_id": ObjectId(), + "source": "sf", + "name": "STT-PlanningML Ingest", + } + + # Case 3 : Ingest Item with no coverage data + ingested, ids = ingest_item(source, provider=provider, feeding_service={}) + + self.assertTrue(ingested) + self.assertIn(source["guid"], ids) + dest = list(service.get_from_mongo(req=None, lookup={"guid": source["guid"]}))[ + 0 + ] + self.assertEqual(len(dest["coverages"]), 1) + coverage = dest["coverages"][0] + self.assertEqual( + coverage["coverage_id"], "placeholder_urn:newsml:stt.fi:20230529:620121" + ) + self.assertEqual( + coverage["news_coverage_status"], + { + "qcode": "ncostat:notint", + "name": "coverage not intended", + "label": "Not planned", + }, + ) + self.assertEqual( + coverage["flags"], {"placeholder": True, "no_content_linking": False} + ) + + # Case 4 : Remove Placeholder Coverage if item updates has coverage + self.fixture = "stt_planning_ml_placeholder-2.xml" + self.parse_source_content() + source = self.item + source["versioncreated"] += timedelta(hours=1) + ingested, ids = ingest_item(source, provider=provider, feeding_service={}) + dest = list(service.get_from_mongo(req=None, lookup={"guid": source["guid"]}))[ + 0 + ] + self.assertEqual(len(dest["coverages"]), 1) + self.assertNotIn( + "placeholder_urn:newsml:stt.fi:20230529:620121", + dest["coverages"][0]["coverage_id"], + )