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"],
+ )