Skip to content

Commit

Permalink
Add conversation.Transcript
Browse files Browse the repository at this point in the history
  • Loading branch information
gonzalo-bulnes committed Dec 28, 2022
1 parent 4ef79d8 commit d7028d3
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 0 deletions.
1 change: 1 addition & 0 deletions securedrop_client/conversation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .transcript import Transcript # noqa: F401
1 change: 1 addition & 0 deletions securedrop_client/conversation/transcript/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .transcript import Transcript # noqa: F401
2 changes: 2 additions & 0 deletions securedrop_client/conversation/transcript/items/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .factory import transcribe # noqa: F401
from .item import Item # noqa: F401
16 changes: 16 additions & 0 deletions securedrop_client/conversation/transcript/items/factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from typing import Optional

from securedrop_client import db as database

from .file import File
from .item import Item
from .message import Message


def transcribe(record: database.Base) -> Optional[Item]:
if isinstance(record, database.Message) or isinstance(record, database.Reply):
return Message(record)
if isinstance(record, database.File):
return File(record)
else:
return None
22 changes: 22 additions & 0 deletions securedrop_client/conversation/transcript/items/file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from gettext import gettext as _
from typing import Optional

from securedrop_client import db as database

from .item import Item


class File(Item):
def __init__(self, record: database.File):
super().__init__()

self.filename = record.filename
self.sender = record.source.journalist_designation

@property
def context(self) -> Optional[str]:
return _("{username} sent:\n").format(username=self.sender)

@property
def transcript(self) -> str:
return _("File: {filename}\n").format(filename=self.filename)
13 changes: 13 additions & 0 deletions securedrop_client/conversation/transcript/items/item.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from typing import Optional


class Item:
@property
def transcript(self) -> str:
"""A transcription of the conversation item."""
raise NotImplementedError # pragma: nocover

@property
def context(self) -> Optional[str]:
"""Some context about the conversation item."""
raise NotImplementedError # pragma: nocover
26 changes: 26 additions & 0 deletions securedrop_client/conversation/transcript/items/message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from gettext import gettext as _
from typing import Optional, Union

from securedrop_client import db as database

from .item import Item


class Message(Item):
def __init__(self, record: Union[database.Message, database.Reply]):
super().__init__()

self.content = record.content

if isinstance(record, database.Message):
self.sender = record.source.journalist_designation
else:
self.sender = record.journalist.username

@property
def context(self) -> Optional[str]:
return _("{username} wrote:\n").format(username=self.sender)

@property
def transcript(self) -> str:
return self.content + "\n"
44 changes: 44 additions & 0 deletions securedrop_client/conversation/transcript/transcript.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from typing import List, Optional

from securedrop_client import db as database

from .items import Item
from .items import transcribe as transcribe_item


def transcribe(record: database.Base) -> Optional[Item]:
return transcribe_item(record)


_ENTRY_SEPARATOR = "------\n"


class Transcript:
def __init__(self, conversation: database.Source) -> None:

self._items = [transcribe(record) for record in conversation.collection]

def __str__(self) -> str:
if len(self._items) <= 0:
return "No messages."

entries: List[str] = []

context: Optional[str] = None

for item in self._items:
if item is None:
continue

if context is not None and context == item.context:
entry = item.transcript
elif item.context is None:
entry = item.transcript # pragma: nocover
else:
entry = f"{item.context}{item.transcript}"

entries.append(entry)

context = item.context

return _ENTRY_SEPARATOR.join(entries)
9 changes: 9 additions & 0 deletions securedrop_client/locale/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ msgstr ""
msgid "Failed to delete source at server"
msgstr ""

msgid "{username} sent:\n"
msgstr ""

msgid "File: {filename}\n"
msgstr ""

msgid "{username} wrote:\n"
msgstr ""

msgid "Download All Files"
msgstr ""

Expand Down
127 changes: 127 additions & 0 deletions tests/test_conversation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import unittest
from datetime import datetime
from textwrap import dedent

from securedrop_client import conversation
from securedrop_client import db as database


class TestConversationTranscript(unittest.TestCase):
def setUp(self):

source = database.Source(
journalist_designation="happy-bird",
)
files = [
database.File(
filename="4-memo.pdf.gpg",
is_downloaded=True,
),
database.File(
filename="9-memo.zip.gpg",
is_downloaded=True,
),
]
messages = [
database.Message(
filename="1-message.gpg",
is_downloaded=True,
content="Hello! I think this is newsworthy: ...",
),
database.Message(
filename="6-message.gpg",
is_downloaded=True,
content="I can send you more if you're interested.",
),
database.Message(
filename="5-message.gpg",
is_downloaded=True,
content="Here is a document with details!",
),
database.Message(
filename="8-message.gpg",
is_downloaded=True,
content="Sure.",
),
]
interested_journalist = database.User(username="interested-journalist")
other_journalist = database.User(username="other-journalist")
replies = [
database.Reply(
journalist=interested_journalist,
filename="2-reply.gpg",
is_downloaded=True,
content=dedent(
"""\
Thank you for the tip!
Can you tell me more about... ?
"""
),
),
database.Reply(
journalist=interested_journalist,
filename="3-reply.gpg",
is_downloaded=True,
content=dedent(
"""\
Do you have proof of...?
"""
),
),
database.Reply(
journalist=other_journalist,
filename="7-reply.gpg",
is_downloaded=True,
content=dedent("Yes, the document you sent was useful, I'd love to see more."),
),
]
draft_reply = database.DraftReply(
content="Let me think...",
file_counter=2,
timestamp=datetime.now(),
)
source.files = files
source.messages = messages
source.replies = replies
source.draftreplies = [draft_reply]

self._source = source

def test_indicates_explicitly_absence_of_messages(self):
source = database.Source()
assert str(conversation.Transcript(source)) == "No messages."

def test_renders_all_messages(self):
assert str(conversation.Transcript(self._source)) == dedent(
"""\
happy-bird wrote:
Hello! I think this is newsworthy: ...
------
interested-journalist wrote:
Thank you for the tip!
Can you tell me more about... ?
------
Do you have proof of...?
------
happy-bird sent:
File: 4-memo.pdf.gpg
------
happy-bird wrote:
Here is a document with details!
------
I can send you more if you're interested.
------
other-journalist wrote:
Yes, the document you sent was useful, I'd love to see more.
------
happy-bird wrote:
Sure.
------
happy-bird sent:
File: 9-memo.zip.gpg
"""
)

0 comments on commit d7028d3

Please sign in to comment.