Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Floppy disk save emoji improvements #424

Merged
merged 2 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 125 additions & 64 deletions app/integrations/google_drive.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import base64
import logging
import datetime
import re

from dotenv import load_dotenv
from googleapiclient.discovery import build
Expand Down Expand Up @@ -312,6 +313,14 @@ def get_timeline_section(document_id):
text_run = elem.get("textRun")
if text_run:
text = text_run.get("content")
textStyle = text_run.get("textStyle", {})
if "link" in textStyle:
# Extract link URL
link = textStyle["link"].get("url")
# Format the text with the link as Markdown
formatted_text = f"[{text.strip()}]({link})"
# Replace the text with the formatted text
text = formatted_text
if START_HEADING in text:
record = True
found_start = True
Expand All @@ -326,6 +335,22 @@ def get_timeline_section(document_id):
return None if not (found_start and found_end) else timeline_content


def find_heading_indices(content, start_heading, end_heading):
"""Find the start and end indices of content between two headings."""
start_index, end_index = None, None
for element in content:
if "paragraph" in element:
text_runs = element["paragraph"].get("elements", [])
for text_run in text_runs:
text = text_run.get("textRun", {}).get("content", "")
if start_heading in text:
start_index = text_run.get("endIndex")
elif end_heading in text and start_index is not None:
end_index = text_run.get("startIndex")
return start_index, end_index
return start_index, end_index


# Replace the text between the headings
def replace_text_between_headings(doc_id, new_content, start_heading, end_heading):
# Setup the service
Expand All @@ -336,83 +361,119 @@ def replace_text_between_headings(doc_id, new_content, start_heading, end_headin
content = document.get("body").get("content")

# Find the start and end indices
start_index = None
end_index = None
for element in content:
if "paragraph" in element:
paragraph = element.get("paragraph")
text_runs = paragraph.get("elements")
for text_run in text_runs:
text = text_run.get("textRun").get("content")
if start_heading in text:
# Set start_index to the end of the start heading
start_index = text_run.get("endIndex")
if end_heading in text and start_index is not None:
# Set end_index to the start of the end heading
end_index = text_run.get("startIndex")
break
start_index, end_index = find_heading_indices(content, start_heading, end_heading)

if start_index is not None and end_index is not None:
# Format new content with new lines for proper insertion. We need to make sure that the formatted string contains only one
# leading and trailing newline character
# Split the string into three parts: leading newlines, core content, and trailing newlines
leading_newlines = len(new_content) - len(new_content.lstrip("\n"))
trailing_newlines = len(new_content) - len(new_content.rstrip("\n"))
core_content = new_content[
leading_newlines : len(new_content) - trailing_newlines
]

# Ensure only one newline at the start and one at the end, preserving internal newlines
formatted_content = "\n" + core_content + "\n"
content_length = len(formatted_content)

# Perform the replacement
# Delete the existing content from the document
requests = [
{
"deleteContentRange": {
"range": {"startIndex": start_index, "endIndex": end_index}
}
},
{
"insertText": {
"location": {"index": start_index},
"text": formatted_content,
}
},
]
# Format the inserted text - we want to make sure that the font size is what we want
requests.append(
{
"updateTextStyle": {
"range": {
"startIndex": start_index,
"endIndex": (
start_index + content_length
), # Adjust this index based on the length of the text
},
"textStyle": {
"fontSize": {"magnitude": 11, "unit": "PT"},
"bold": False,
},
"fields": "bold",
}
}
)
# Update paragraph style to be normal text
]

# split the formatted content by the emoji
line = new_content.split(" ➡ ")
pattern = r"\[([^\]]+)\]\(([^)]+)\)\s([^:]+):\s(.+)"
insert_index = start_index
inserted_content = ""

# Insert an empty line before the new content and after the placeholder text
text_to_insert = "\n"
text_len = len(text_to_insert)
requests.append(
{
"updateParagraphStyle": {
"range": {
"startIndex": start_index,
"endIndex": (
start_index + content_length
), # Adjust this index based on the length of the text
},
"paragraphStyle": {"namedStyleType": "NORMAL_TEXT"},
"fields": "namedStyleType",
"insertText": {
"location": {"index": insert_index},
"text": text_to_insert,
}
}
)
# udpate the insert index
insert_index += text_len

for item in line:
# split the item by the emoji and strip out any empty strings
original_entries = item.split("➡️ ")
entries = [entry for entry in original_entries if entry.strip()]

for entry in entries:
# Regular expression to match the entry pattern
pattern = r"\[(?P<date>.+?) ET\]\((?P<url>.+?)\) (?P<name>.+?): (?P<message>.+)$"

# Use re.DOTALL to make '.' match newline characters as well. This is needed for multi-line messages
match = re.match(pattern, entry, re.DOTALL)

if match:
# Extract components from the match object
date = match.group("date") + " ET"
url = match.group("url")
name = match.group("name")
message = match.group(
"message"
).strip() # Remove leading/trailing whitespace

# Construct the text to be inserted with the date as a link
text_to_insert = f" ➡️ {date} {name}: {message}\n"
text_len = len(text_to_insert)
inserted_content += text_to_insert

# Insert text request
requests.append(
{
"insertText": {
"location": {"index": insert_index},
"text": text_to_insert,
}
}
)
# Update link style for date_text
requests.append(
{
"updateTextStyle": {
"range": {
"startIndex": insert_index + 4,
"endIndex": insert_index + len(date) + 4,
},
"textStyle": {"link": {"url": url}},
"fields": "link",
}
}
)
# Update for next insertion
insert_index += text_len
else:
# if we don't match the above pattern, just insert the entry as is
text_to_insert = f" ➡️ {item}\n"
inserted_content += text_to_insert
text_len = len(text_to_insert)
# Insert text request for the entire block of formatted_content
requests.append(
{
"insertText": {
"location": {"index": insert_index},
"text": text_to_insert,
}
}
)

# Update insert_index as needed, assuming formatted_content is a single block of text
insert_index += text_len

# Make sure that we do normal formatting for the inserted content
requests.append(
{
"updateParagraphStyle": {
"range": {
"startIndex": start_index,
"endIndex": (start_index + len(inserted_content)),
},
"paragraphStyle": {"namedStyleType": "NORMAL_TEXT"},
"fields": "namedStyleType",
}
}
)
service.documents().batchUpdate(
documentId=doc_id, body={"requests": requests}
).execute()
Expand Down
62 changes: 22 additions & 40 deletions app/modules/incident/handle_slack_message_reactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,55 +4,37 @@


def rearrange_by_datetime_ascending(text):
# Split the text by lines
lines = text.split("\n")

# Temporary storage for multiline entries
entries = []
current_entry = []

# Iterate over each line
for line in lines:
# Check if the line starts with a datetime format including 'ET'
if re.match(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} ET", line):
if current_entry:
# Combine the lines in current_entry and add to entries
entries.append("\n".join(current_entry))
current_entry = [line]
else:
current_entry.append(line)
else:
# If not a datetime, it's a continuation of the previous message
current_entry.append(line)

# Add the last entry
if current_entry:
if current_entry.__len__() > 1:
# that means we have a multiline entry
joined_current_entry = "\n".join(current_entry)
entries.append(joined_current_entry)
else:
entries.append("\n".join(current_entry))
pattern = r"\s*➡️\s*\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ET\]\((https?://[\w./-]+)\)\s([\w\s]+):\s"

# Now extract date, time, and message from each entry
dated_entries = []
for entry in entries:
match = re.match(
r"(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} ET):?[\s,]*(.*)", entry, re.DOTALL
)
current_message = []
for line in lines:
match = re.match(pattern, line)
if match:
date_str, msg = match.groups()
# Parse the datetime string (ignoring 'ET' for parsing)
dt = datetime.strptime(date_str[:-3].strip(), "%Y-%m-%d %H:%M:%S")
dated_entries.append((dt, msg))
if (
current_message
): # If there's a current message, finalize it before starting a new one
entries.append(current_message)
current_message = []
date_str, url, name = match.groups()
dt = datetime.strptime(date_str.strip(), "%Y-%m-%d %H:%M:%S")
msg_start = line[match.end() :].strip(" ")
current_message = [dt, url, f"{name}:", msg_start]
elif current_message: # If it's a continuation of the current message
current_message[-1] += "\n" + f"{line.strip()}"

if current_message: # Don't forget to append the last message
entries.append(current_message)

# Sort the entries by datetime in ascending order
sorted_entries = sorted(dated_entries, key=lambda x: x[0], reverse=False)
sorted_entries = sorted(entries, key=lambda x: x[0])

# Reformat the entries back into strings, including 'ET'
sorted_text = "\n".join(
# Reformat the entries back into strings, including 'ET' and the full message
sorted_text = "\n\n".join(
[
f"{entry[0].strftime('%Y-%m-%d %H:%M:%S')} ET {entry[1]}"
f"➡️ [{entry[0].strftime('%Y-%m-%d %H:%M:%S')} ET]({entry[1]}) {entry[2]} {entry[3]}"
for entry in sorted_entries
]
)
Expand Down
31 changes: 27 additions & 4 deletions app/modules/incident/incident.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,9 +443,19 @@ def handle_reaction_added(client, ack, body, logger):
)
if document_id == "":
logger.error("No incident document found for this channel.")

for message in messages:
# get the message ts time
message_ts = message["ts"]

# convert the time which is now in epoch time to standard ET Time
message_date_time = convert_epoch_to_datetime_est(message["ts"])
message_date_time = convert_epoch_to_datetime_est(message_ts)

# get a link to the message
link = client.chat_getPermalink(
channel=channel_id, message_ts=message_ts
)["permalink"]

# get the user name from the message
user = client.users_profile_get(user=message["user"])
# get the full name of the user so that we include it into the timeline
Expand All @@ -462,7 +472,9 @@ def handle_reaction_added(client, ack, body, logger):
# if the message already exists in the timeline, then don't put it there again
if content and message_date_time not in content:
# append the new message to the content
content += f"{message_date_time} {user_full_name}: {message}"
content += (
f" ➡️ [{message_date_time}]({link}) {user_full_name}: {message}"
)

# if there is an image in the message, then add it to the timeline
if "files" in message:
Expand Down Expand Up @@ -500,8 +512,11 @@ def handle_reaction_removed(client, ack, body, logger):
# get the message we want to delete
message = messages[0]

# get the message ts time
message_ts = message["ts"]

# convert the epoch time to standard ET day/time
message_date_time = convert_epoch_to_datetime_est(message["ts"])
message_date_time = convert_epoch_to_datetime_est(message_ts)

# get the user of the person that send the message
user = client.users_profile_get(user=message["user"])
Expand All @@ -528,8 +543,16 @@ def handle_reaction_removed(client, ack, body, logger):
user_handle, message["text"]
)

# get a link to the message
link = client.chat_getPermalink(channel=channel_id, message_ts=message_ts)[
"permalink"
]

# Construct the message to remove
message_to_remove = f"\n{message_date_time} {user_full_name}: {message}\n"
message_to_remove = (
f" ➡️ [{message_date_time}]({link}) {user_full_name}: {message}\n"
)

# if there is a file in the message, then add it to the message to remove
if "files" in message:
image = message["files"][0]["url_private"]
Expand Down
Loading
Loading