Skip to content

Commit 1289e20

Browse files
authored
Merge pull request #484 from OP-TED/feature/TED-1398
updated METS package publishing + tests
2 parents 4b5f1bc + 47ed19f commit 1289e20

8 files changed

Lines changed: 81 additions & 32 deletions

File tree

ted_sws/core/model/manifestation.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from ted_sws.core.model import PropertyBaseModel
1616
from ted_sws.core.model.validation_report_data import ReportNoticeData
17+
from ted_sws.notice_packager.model.metadata import METS_TYPE_CREATE
1718

1819

1920
class ManifestationMimeType(Enum):
@@ -195,6 +196,8 @@ class METSManifestation(Manifestation):
195196
"""
196197
197198
"""
199+
type: str = METS_TYPE_CREATE
200+
package_name: str = None
198201

199202

200203
class RDFValidationManifestation(ValidationManifestation):
@@ -301,5 +304,3 @@ def is_validated(self) -> bool:
301304
if len(self.shacl_validations) and len(self.sparql_validations):
302305
return True
303306
return False
304-
305-

ted_sws/notice_packager/services/notice_packager.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
FILE_METS_ACTION_FORMAT = "{work_identifier}_{action}.mets.xml"
3636
DEFAULT_RDF_FILE_FORMAT = "turtle"
3737

38+
3839
# The naming convention for an TEDRDF package:
3940
# {year}_{notice_metadata.ojs_type}_{notice_metadata.ojs_issue_number}_{notice_number}_{action}
4041
# ex.: "2021_S_4_003544_create.zip" , where:
@@ -53,8 +54,15 @@ def package_notice(notice: Notice, action: str = METS_TYPE_CREATE) -> Notice:
5354
notice_packager = NoticePackager(notice, action)
5455
notice_packager.add_template_files()
5556
notice_packager.add_rdf_content()
56-
mets_manifestation_content = notice_packager.pack()
57-
notice.set_mets_manifestation(mets_manifestation=METSManifestation(object_data=mets_manifestation_content))
57+
package_name = notice_packager.get_archive_name()
58+
mets_manifestation_content = notice_packager.pack(package_name=package_name)
59+
notice.set_mets_manifestation(
60+
mets_manifestation=METSManifestation(
61+
object_data=mets_manifestation_content,
62+
type=action,
63+
package_name=package_name
64+
)
65+
)
5866
return notice
5967

6068

@@ -134,9 +142,10 @@ def get_archive_name(self) -> str:
134142
)
135143
return archive_name
136144

137-
def pack(self) -> str:
145+
def pack(self, package_name: str = None) -> str:
146+
package_name = package_name or self.get_archive_name()
138147
archiver = ZipArchiver()
139-
archive_path = self.tmp_dir_path / self.get_archive_name()
148+
archive_path = self.tmp_dir_path / package_name
140149
package_path = archiver.process_archive(archive_path, self.files)
141150
raw_archive_content = package_path.read_bytes()
142151
archive_content = base64.b64encode(raw_archive_content)

ted_sws/notice_publisher/adapters/sftp_notice_publisher.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ class SFTPPublisher(SFTPPublisherABC):
1313
def __init__(self, hostname: str = None, username: str = None, password: str = None, port: int = None,
1414
private_key: str = None, private_key_passphrase: str = None):
1515
"""Constructor Method"""
16-
self.hostname = hostname if hostname else config.SFTP_PUBLISH_HOST
17-
self.username = username if username else config.SFTP_PUBLISH_USER
18-
self.password = password if password else config.SFTP_PUBLISH_PASSWORD
19-
self.port = port if port else config.SFTP_PUBLISH_PORT
16+
self.hostname = hostname or config.SFTP_PUBLISH_HOST
17+
self.username = username or config.SFTP_PUBLISH_USER
18+
self.password = password or config.SFTP_PUBLISH_PASSWORD
19+
self.port = port or config.SFTP_PUBLISH_PORT
2020
self.connection = None
2121
self.is_connected = False
2222
self.private_key = None
23-
self.private_key_passphrase = private_key_passphrase if private_key_passphrase else config.SFTP_PRIVATE_KEY_PASSPHRASE
24-
private_key = private_key if private_key else config.SFTP_PRIVATE_KEY
23+
self.private_key_passphrase = private_key_passphrase or config.SFTP_PRIVATE_KEY_PASSPHRASE
24+
private_key = private_key or config.SFTP_PRIVATE_KEY
2525
if private_key:
2626
self.private_key = paramiko.RSAKey.from_private_key(io.StringIO(private_key),
2727
password=self.private_key_passphrase)
@@ -77,4 +77,4 @@ def exists(self, remote_path: str) -> bool:
7777
self._sftp.stat(remote_path)
7878
except IOError:
7979
return False
80-
return True
80+
return True

ted_sws/notice_publisher/services/notice_publisher.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,18 @@ def publish_notice(notice: Notice, publisher: SFTPPublisherABC = None,
1919
"""
2020
This function publishes the METS manifestation for a Notice in Cellar.
2121
"""
22-
publisher = publisher if publisher else SFTPPublisher()
23-
remote_folder_path = remote_folder_path if remote_folder_path else config.SFTP_PUBLISH_PATH
22+
publisher = publisher or SFTPPublisher()
23+
remote_folder_path = remote_folder_path or config.SFTP_PUBLISH_PATH
2424
mets_manifestation = notice.mets_manifestation
2525
if not mets_manifestation or not mets_manifestation.object_data:
2626
raise ValueError("Notice does not have a METS manifestation to be published.")
2727

28+
package_name = mets_manifestation.package_name
29+
if not package_name:
30+
raise ValueError("METS manifestation does not have a package name for publishing.")
31+
2832
package_content = base64.b64decode(bytes(mets_manifestation.object_data, encoding='utf-8'), validate=True)
29-
remote_notice_path = f"{remote_folder_path}/{notice.ted_id}{DEFAULT_NOTICE_PACKAGE_EXTENSION}"
33+
remote_notice_path = f"{remote_folder_path}/{package_name}"
3034
source_file = tempfile.NamedTemporaryFile()
3135
source_file.write(package_content)
3236
try:
@@ -62,15 +66,19 @@ def publish_notice_into_s3(notice: Notice, s3_publisher: S3Publisher = None,
6266
:param bucket_name:
6367
:return:
6468
"""
65-
s3_publisher = s3_publisher if s3_publisher else S3Publisher()
69+
s3_publisher = s3_publisher or S3Publisher()
6670
bucket_name = bucket_name or config.S3_PUBLISH_NOTICE_BUCKET
6771
mets_manifestation = notice.mets_manifestation
6872
if not mets_manifestation or not mets_manifestation.object_data:
6973
raise ValueError("Notice does not have a METS manifestation to be published.")
7074

75+
package_name = mets_manifestation.package_name
76+
if not package_name:
77+
raise ValueError("METS manifestation does not have a package name for publishing.")
78+
7179
package_content = base64.b64decode(bytes(mets_manifestation.object_data, encoding='utf-8'), validate=True)
7280
result: S3PublishResult = s3_publisher.publish(bucket_name=bucket_name,
73-
object_name=f"{notice.ted_id}{DEFAULT_NOTICE_PACKAGE_EXTENSION}",
81+
object_name=f"{package_name}",
7482
data=package_content)
7583
return result is not None
7684

@@ -86,7 +94,7 @@ def publish_notice_into_s3_by_id(notice_id: str, notice_repository: NoticeReposi
8694
:param bucket_name:
8795
:return:
8896
"""
89-
s3_publisher = s3_publisher if s3_publisher else S3Publisher()
97+
s3_publisher = s3_publisher or S3Publisher()
9098
bucket_name = bucket_name or config.S3_PUBLISH_NOTICE_BUCKET
9199
notice = notice_repository.get(reference=notice_id)
92100
result = publish_notice_into_s3(notice=notice, bucket_name=bucket_name, s3_publisher=s3_publisher)
@@ -102,7 +110,7 @@ def publish_notice_rdf_into_s3(notice: Notice, s3_publisher: S3Publisher = None,
102110
:param bucket_name:
103111
:return:
104112
"""
105-
s3_publisher = s3_publisher if s3_publisher else S3Publisher()
113+
s3_publisher = s3_publisher or S3Publisher()
106114
bucket_name = bucket_name or config.S3_PUBLISH_NOTICE_RDF_BUCKET
107115
rdf_manifestation: RDFManifestation = notice.distilled_rdf_manifestation
108116
result: bool = publish_notice_rdf_content_into_s3(
@@ -125,7 +133,7 @@ def publish_notice_rdf_into_s3_by_id(notice_id: str, notice_repository: NoticeRe
125133
:param bucket_name:
126134
:return:
127135
"""
128-
s3_publisher = s3_publisher if s3_publisher else S3Publisher()
136+
s3_publisher = s3_publisher or S3Publisher()
129137
bucket_name = bucket_name or config.S3_PUBLISH_NOTICE_RDF_BUCKET
130138
notice = notice_repository.get(reference=notice_id)
131139
return publish_notice_rdf_into_s3(notice=notice, bucket_name=bucket_name, s3_publisher=s3_publisher)
@@ -143,7 +151,7 @@ def publish_notice_rdf_content_into_s3(rdf_manifestation: RDFManifestation,
143151
:param bucket_name:
144152
:return:
145153
"""
146-
s3_publisher = s3_publisher if s3_publisher else S3Publisher()
154+
s3_publisher = s3_publisher or S3Publisher()
147155
if not rdf_manifestation or not rdf_manifestation.object_data:
148156
raise ValueError("Notice does not have a RDF manifestation to be published.")
149157

tests/e2e/notice_publisher/services/test_notice_publisher.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
def test_notice_publisher(notice_2016, fake_mongodb_client):
1717
notice = notice_2016
18+
package_name = "test_package.zip"
1819
notice_repository = NoticeRepository(mongodb_client=fake_mongodb_client)
1920
notice_repository.add(notice)
2021
notice_id = notice.ted_id
@@ -34,6 +35,16 @@ def test_notice_publisher(notice_2016, fake_mongodb_client):
3435
notice_repository.update(notice)
3536
sftp_publisher = SFTPPublisher()
3637

38+
with pytest.raises(ValueError):
39+
publish_notice_by_id(notice_id, notice_repository, publisher=sftp_publisher)
40+
41+
mets_manifestation = METSManifestation(
42+
object_data="62f0baf9a5458a3a67761392",
43+
package_name=package_name
44+
)
45+
notice.set_mets_manifestation(mets_manifestation)
46+
notice._status = NoticeStatus.ELIGIBLE_FOR_PUBLISHING
47+
notice_repository.update(notice)
3748
published = publish_notice_by_id(notice_id, notice_repository, publisher=sftp_publisher)
3849

3950
assert published
@@ -48,7 +59,7 @@ def test_notice_publisher(notice_2016, fake_mongodb_client):
4859
notice._mets_manifestation = None
4960
publish_notice(notice, publisher=sftp_publisher)
5061
sftp_publisher.connect()
51-
sftp_publisher.remove(f"{config.SFTP_PUBLISH_PATH}/{notice.ted_id}{DEFAULT_NOTICE_PACKAGE_EXTENSION}")
62+
sftp_publisher.remove(f"{config.SFTP_PUBLISH_PATH}/{package_name}")
5263
sftp_publisher.disconnect()
5364
assert not sftp_publisher.is_connected
5465

@@ -59,7 +70,7 @@ def test_s3_notice_publisher(notice_2016, fake_mongodb_client, notice_s3_bucket_
5970
notice_repository = NoticeRepository(mongodb_client=fake_mongodb_client)
6071
notice_repository.add(notice)
6172
notice_id = notice.ted_id
62-
object_name = f"{notice_id}{DEFAULT_NOTICE_PACKAGE_EXTENSION}"
73+
object_name = "test_package.zip"
6374

6475
rdf_manifestation = RDFManifestation(object_data="62f0baf9a5458a3a67761392")
6576
mets_manifestation = notice_mets_manifestation
@@ -76,6 +87,21 @@ def test_s3_notice_publisher(notice_2016, fake_mongodb_client, notice_s3_bucket_
7687

7788
notice_repository.update(notice)
7889

90+
with pytest.raises(ValueError):
91+
publish_notice_into_s3_by_id(
92+
notice_id=notice_id,
93+
notice_repository=notice_repository,
94+
bucket_name=notice_s3_bucket_name,
95+
s3_publisher=s3_publisher
96+
)
97+
98+
mets_manifestation = METSManifestation(
99+
object_data="62f0baf9a5458a3a67761392",
100+
package_name=object_name
101+
)
102+
notice.set_mets_manifestation(mets_manifestation)
103+
notice._status = NoticeStatus.ELIGIBLE_FOR_PUBLISHING
104+
notice_repository.update(notice)
79105
publish_result: bool = publish_notice_into_s3_by_id(
80106
notice_id=notice_id,
81107
notice_repository=notice_repository,

tests/features/notice_publisher/conftest.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ def mongodb_client():
2626

2727

2828
@pytest.fixture(scope="function")
29-
def publish_eligible_notice(publicly_available_notice) -> Notice:
29+
def publish_eligible_notice(publicly_available_notice, mets_package_published_name) -> Notice:
3030
notice = publicly_available_notice
3131
notice.update_status_to(NoticeStatus.ELIGIBLE_FOR_PUBLISHING)
3232
notice._mets_manifestation = METSManifestation(
33-
object_data=base64.b64encode("METS manifestation content".encode("utf-8")))
33+
object_data=base64.b64encode("METS manifestation content".encode("utf-8")),
34+
package_name=mets_package_published_name
35+
)
3436
return notice
3537

3638

@@ -54,9 +56,9 @@ def s3_bucket_name():
5456
return "tmp-test-bucket"
5557

5658
@pytest.fixture
57-
def mets_package_published_name(publish_eligible_notice):
58-
return f"{publish_eligible_notice.ted_id}.zip"
59+
def mets_package_published_name():
60+
return "test_package.zip"
5961

6062
@pytest.fixture
6163
def rdf_manifestation_published_name(publish_eligible_notice):
62-
return f"{publish_eligible_notice.ted_id}.ttl"
64+
return f"{publish_eligible_notice.ted_id}.ttl"

tests/features/notice_publisher/test_notice_publisher.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from ted_sws.core.model.notice import Notice, NoticeStatus
1111
from ted_sws.data_manager.adapters.repository_abc import NoticeRepositoryABC
1212
from ted_sws.notice_publisher.adapters.sftp_notice_publisher import SFTPPublisher
13-
from ted_sws.notice_publisher.adapters.sftp_publisher_abc import SFTPPublisherABC
1413
from ted_sws.notice_publisher.services.notice_publisher import publish_notice, publish_notice_by_id
1514

1615

tests/unit/notice_packager/test_notice_packager.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,17 @@
99

1010
from ted_sws.core.model.manifestation import RDFManifestation
1111
from ted_sws.core.model.notice import NoticeStatus
12-
from ted_sws.notice_packager.services.notice_packager import package_notice
12+
from ted_sws.notice_packager.model.metadata import METS_TYPE_CREATE
13+
from ted_sws.notice_packager.services.notice_packager import package_notice, NoticePackager
1314

1415

1516
def test_notice_packager_with_notice(notice_2018, rdf_content):
1617
rdf_manifestation = RDFManifestation(object_data=rdf_content)
1718
notice_2018._status = NoticeStatus.ELIGIBLE_FOR_PACKAGING
1819
notice_2018._rdf_manifestation = rdf_manifestation
1920
notice_2018._distilled_rdf_manifestation = rdf_manifestation
20-
packaged_notice = package_notice(notice_2018)
21+
packaged_notice = package_notice(notice_2018, action=METS_TYPE_CREATE)
22+
2123
assert packaged_notice.mets_manifestation
24+
assert packaged_notice.mets_manifestation.type == METS_TYPE_CREATE
25+
assert packaged_notice.mets_manifestation.package_name == "2018_S_22_045279_create.zip"

0 commit comments

Comments
 (0)