From 4645bdbd7f4251d91f8aa1bf30e4a9ec177cbcba Mon Sep 17 00:00:00 2001 From: Dishant1804 Date: Sat, 26 Apr 2025 22:05:30 +0530 Subject: [PATCH 1/3] events command refactored --- backend/apps/slack/commands/events.py | 10 +- backend/apps/slack/templates/events.jinja | 9 +- backend/apps/slack/utils.py | 4 +- .../tests/apps/slack/commands/events_test.py | 107 +++++++++++------- 4 files changed, 73 insertions(+), 57 deletions(-) diff --git a/backend/apps/slack/commands/events.py b/backend/apps/slack/commands/events.py index 233b6dfdf4..562bbc2227 100644 --- a/backend/apps/slack/commands/events.py +++ b/backend/apps/slack/commands/events.py @@ -14,23 +14,21 @@ def get_template_context(self, command): valid_events = [event for event in events_data if event.start_date] sorted_events = sorted(valid_events, key=lambda x: x.start_date) - categorized_events = {} + upcoming_events = {"event": []} for event in sorted_events: - category = event.category or "Other" - if category not in categorized_events: - categorized_events[category] = {"events": []} - categorized_events[category]["events"].append( + upcoming_events["event"].append( { "name": event.name, "url": event.url, "start_date": event.start_date, "end_date": event.end_date, + "location": event.suggested_location, "description": event.description, } ) return { **super().get_template_context(command), - "categorized_events": categorized_events, + "upcoming_events": upcoming_events, "website_url": OWASP_WEBSITE_URL, } diff --git a/backend/apps/slack/templates/events.jinja b/backend/apps/slack/templates/events.jinja index 19fa482e94..ce858ae9b2 100644 --- a/backend/apps/slack/templates/events.jinja +++ b/backend/apps/slack/templates/events.jinja @@ -1,10 +1,7 @@ *Upcoming OWASP Events:*{{ SECTION_BREAK }}{{ DIVIDER }}{{ SECTION_BREAK }} -{%- for category, category_data in categorized_events.items() %} -*Category: {{ category.replace('_', ' ').title() }}*{{ NL }}{{ SECTION_BREAK }} -{%- for event in category_data.events %} -*{{ loop.index }}. {% if event.url %}<{{ event.url }}|{{ event.name }}>{% else %}{{ event.name }}{% endif %}* -Start Date: {{ event.start_date }}{% if event.end_date %}{{ NL }}End Date: {{ event.end_date }}{% endif %}{% if event.description %}{{ NL }}_{{ event.description }}_{% endif %}{{ NL }}{{ NL }}{%- if not loop.last %}{{ SECTION_BREAK }}{% endif %} +{%- for event in upcoming_events.event %} +*{% if loop.index %}{{ loop.index }}. {% endif %}{% if event.url %}<{{ event.url }}|{{ event.name }}>{% else %}{{ event.name }}{% endif %}* +Start Date: {{ event.start_date }}{% if event.end_date %}{{ NL }}End Date: {{ event.end_date }}{% endif %}{% if event.location %}{{ NL }}Location: {{ event.location }}{% endif %}{% if event.description %}{{ NL }}_{{ event.description }}_{% endif %}{{ NL }}{{ NL }}{%- if not loop.last %}{{ SECTION_BREAK }}{% endif %} {%- endfor %} {{ SECTION_BREAK }}{{ DIVIDER }}{{ SECTION_BREAK }} -{%- endfor %} 🔍 For more information about upcoming events, please visit <{{ website_url }}/events/|OWASP Events>{{ NL }} diff --git a/backend/apps/slack/utils.py b/backend/apps/slack/utils.py index 7afc1f248b..1ed07d240d 100644 --- a/backend/apps/slack/utils.py +++ b/backend/apps/slack/utils.py @@ -117,7 +117,7 @@ def get_staff_data(timeout=30): logger.exception("Unable to parse OWASP staff data file", extra={"file_path": file_path}) -def get_events_data(): +def get_events_data(limit=9): """Get events data. Returns @@ -127,7 +127,7 @@ def get_events_data(): from apps.owasp.models.event import Event try: - return Event.objects.filter(start_date__gte=timezone.now()).order_by("start_date") + return Event.objects.filter(start_date__gte=timezone.now()).order_by("start_date")[:limit] except Exception as e: logger.exception("Failed to fetch events data via database", extra={"error": str(e)}) return None diff --git a/backend/tests/apps/slack/commands/events_test.py b/backend/tests/apps/slack/commands/events_test.py index 306f22eb08..e955ec7b09 100644 --- a/backend/tests/apps/slack/commands/events_test.py +++ b/backend/tests/apps/slack/commands/events_test.py @@ -7,33 +7,36 @@ class MockEvent: - def __init__(self, name, category, start_date, end_date, url, description): + def __init__(self, name, start_date, end_date, suggested_location, url, description): self.name = name - self.category = category self.start_date = start_date self.end_date = end_date + self.suggested_location = suggested_location self.url = url self.description = description -mock_events = [ - MockEvent( - name="OWASP Snow 2025", - category="AppSec Days", - start_date="2025-03-14", - end_date="March 14, 2025", - url="https://example.com/snow", - description="Regional conference", - ), - MockEvent( - name="OWASP Global AppSec EU 2025", - category="Global", - start_date="2025-05-26", - end_date="May 26-30, 2025", - url="https://example.com/eu", - description="Premier conference", - ), -] +mock_events = sorted( + [ + MockEvent( + name="OWASP Snow 2025", + start_date="2025-03-14", + end_date="March 14, 2025", + suggested_location="Denver, CO", + url="https://example.com/snow", + description="Regional conference", + ), + MockEvent( + name="OWASP Global AppSec EU 2025", + start_date="2025-05-26", + end_date="May 26-30, 2025", + suggested_location="Amsterdam, Netherlands", + url="https://example.com/eu", + description="Premier conference", + ), + ], + key=lambda x: x.start_date, +) class TestEventsHandler: @@ -82,27 +85,45 @@ def test_handler_responses( mock_slack_client.conversations_open.assert_called_once_with( users=mock_slack_command["user_id"] ) - blocks = mock_slack_client.chat_postMessage.call_args[1]["blocks"] - assert blocks[0]["text"]["text"] == expected_header - assert blocks[1]["type"] == "divider" + mock_slack_client.chat_postMessage.assert_called_once() + + sent_blocks = mock_slack_client.chat_postMessage.call_args[1]["blocks"] + assert sent_blocks[0]["type"] == "section" + assert sent_blocks[0]["text"]["text"] == expected_header + assert sent_blocks[1]["type"] == "divider" + if has_events_data: - current_block = 2 - assert "*Category: Appsec Days*" in blocks[current_block]["text"]["text"] - current_block += 1 - event_block = blocks[current_block]["text"]["text"] - assert "*1. *" in event_block - assert "Start Date: 2025-03-14" in event_block - assert "End Date: March 14, 2025" in event_block - assert "_Regional conference_" in event_block - current_block += 1 - assert blocks[current_block]["type"] == "divider" - current_block += 1 - assert "*Category: Global*" in blocks[current_block]["text"]["text"] - current_block += 1 - event_block = blocks[current_block]["text"]["text"] - assert "*1. *" in event_block - assert "Start Date: 2025-05-26" in event_block - assert "End Date: May 26-30, 2025" in event_block - assert "_Premier conference_" in event_block - footer_block = blocks[-1]["text"]["text"] - assert "🔍 For more information about upcoming events" in footer_block + event1 = mock_events[0] + event1_text_found = False + for block in sent_blocks: + if block.get("type") == "section" and "text" in block and "text" in block["text"]: + block_text = block["text"]["text"] + if ( + f"*1. <{event1.url}|{event1.name}>*" in block_text + and f"Start Date: {event1.start_date}" in block_text + and f"End Date: {event1.end_date}" in block_text + and f"Location: {event1.suggested_location}" in block_text + and f"_{event1.description}_" in block_text + ): + event1_text_found = True + break + assert event1_text_found, "Block containing Event 1 details not found or incorrect" + + event2 = mock_events[1] + event2_text_found = False + for block in sent_blocks: + if block.get("type") == "section" and "text" in block and "text" in block["text"]: + block_text = block["text"]["text"] + if ( + f"*2. <{event2.url}|{event2.name}>*" in block_text + and f"Start Date: {event2.start_date}" in block_text + and f"End Date: {event2.end_date}" in block_text + and f"Location: {event2.suggested_location}" in block_text + and f"_{event2.description}_" in block_text + ): + event2_text_found = True + break + assert event2_text_found, "Block containing Event 2 details not found or incorrect" + footer_block = sent_blocks[-1] + assert footer_block["type"] == "section" + assert "🔍 For more information about upcoming events" in footer_block["text"]["text"] From c2e880eb44f7eb4e13b9b43b63d9bf7012262f8b Mon Sep 17 00:00:00 2001 From: Dishant1804 Date: Sun, 27 Apr 2025 08:55:43 +0530 Subject: [PATCH 2/3] format changed --- backend/apps/slack/templates/events.jinja | 11 +++++++- .../tests/apps/slack/commands/events_test.py | 27 ++++++++++++------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/backend/apps/slack/templates/events.jinja b/backend/apps/slack/templates/events.jinja index ce858ae9b2..13382c4966 100644 --- a/backend/apps/slack/templates/events.jinja +++ b/backend/apps/slack/templates/events.jinja @@ -1,7 +1,16 @@ *Upcoming OWASP Events:*{{ SECTION_BREAK }}{{ DIVIDER }}{{ SECTION_BREAK }} {%- for event in upcoming_events.event %} *{% if loop.index %}{{ loop.index }}. {% endif %}{% if event.url %}<{{ event.url }}|{{ event.name }}>{% else %}{{ event.name }}{% endif %}* -Start Date: {{ event.start_date }}{% if event.end_date %}{{ NL }}End Date: {{ event.end_date }}{% endif %}{% if event.location %}{{ NL }}Location: {{ event.location }}{% endif %}{% if event.description %}{{ NL }}_{{ event.description }}_{% endif %}{{ NL }}{{ NL }}{%- if not loop.last %}{{ SECTION_BREAK }}{% endif %} +{{NL}}{%- if event.start_date and event.end_date -%} + {%- if event.start_date.strftime('%Y-%m-%d') == event.end_date.strftime('%Y-%m-%d') -%} + {{ event.start_date.strftime('%B %d, %Y') }} + {%- else -%} + {{ event.start_date.strftime('%B') }} {{ event.start_date.strftime('%d') }} - {{ event.end_date.strftime('%d') }}, {{ event.end_date.strftime('%Y') }} + {%- endif -%} +{%- elif event.start_date -%} + {{ event.start_date.strftime('%B %d, %Y') }} +{%- endif -%}; {{ event.location }} +{%- if event.description %}{{ NL }}_{{ event.description }}_{% endif %}{{ NL }}{{ NL }}{%- if not loop.last %}{{ SECTION_BREAK }}{% endif %} {%- endfor %} {{ SECTION_BREAK }}{{ DIVIDER }}{{ SECTION_BREAK }} 🔍 For more information about upcoming events, please visit <{{ website_url }}/events/|OWASP Events>{{ NL }} diff --git a/backend/tests/apps/slack/commands/events_test.py b/backend/tests/apps/slack/commands/events_test.py index e955ec7b09..4a972e39a4 100644 --- a/backend/tests/apps/slack/commands/events_test.py +++ b/backend/tests/apps/slack/commands/events_test.py @@ -1,3 +1,4 @@ +from datetime import datetime, timezone from unittest.mock import MagicMock, patch import pytest @@ -9,8 +10,16 @@ class MockEvent: def __init__(self, name, start_date, end_date, suggested_location, url, description): self.name = name - self.start_date = start_date - self.end_date = end_date + self.start_date = ( + datetime.strptime(start_date, "%Y-%m-%d").replace(tzinfo=timezone.utc).date() + if start_date + else None + ) + self.end_date = ( + datetime.strptime(end_date, "%Y-%m-%d").replace(tzinfo=timezone.utc).date() + if end_date + else None + ) self.suggested_location = suggested_location self.url = url self.description = description @@ -21,7 +30,7 @@ def __init__(self, name, start_date, end_date, suggested_location, url, descript MockEvent( name="OWASP Snow 2025", start_date="2025-03-14", - end_date="March 14, 2025", + end_date="2025-03-14", suggested_location="Denver, CO", url="https://example.com/snow", description="Regional conference", @@ -29,7 +38,7 @@ def __init__(self, name, start_date, end_date, suggested_location, url, descript MockEvent( name="OWASP Global AppSec EU 2025", start_date="2025-05-26", - end_date="May 26-30, 2025", + end_date="2025-05-30", suggested_location="Amsterdam, Netherlands", url="https://example.com/eu", description="Premier conference", @@ -100,9 +109,8 @@ def test_handler_responses( block_text = block["text"]["text"] if ( f"*1. <{event1.url}|{event1.name}>*" in block_text - and f"Start Date: {event1.start_date}" in block_text - and f"End Date: {event1.end_date}" in block_text - and f"Location: {event1.suggested_location}" in block_text + and "March 14, 2025" in block_text + and "Denver, CO" in block_text and f"_{event1.description}_" in block_text ): event1_text_found = True @@ -116,9 +124,8 @@ def test_handler_responses( block_text = block["text"]["text"] if ( f"*2. <{event2.url}|{event2.name}>*" in block_text - and f"Start Date: {event2.start_date}" in block_text - and f"End Date: {event2.end_date}" in block_text - and f"Location: {event2.suggested_location}" in block_text + and "May 26 - 30, 2025" in block_text + and "Amsterdam, Netherlands" in block_text and f"_{event2.description}_" in block_text ): event2_text_found = True From 80eec6afe26d030c57ee401aa5e65d26ef3e5254 Mon Sep 17 00:00:00 2001 From: Arkadii Yakovets Date: Sun, 27 Apr 2025 10:59:49 -0700 Subject: [PATCH 3/3] Update code --- backend/apps/slack/commands/events.py | 27 ++++++++----------- backend/apps/slack/templates/events.jinja | 18 ++++++------- backend/apps/slack/utils.py | 10 +++---- .../tests/apps/slack/commands/events_test.py | 9 ++++--- frontend/src/server/queries/homeQueries.ts | 2 +- 5 files changed, 31 insertions(+), 35 deletions(-) diff --git a/backend/apps/slack/commands/events.py b/backend/apps/slack/commands/events.py index 562bbc2227..96448827ff 100644 --- a/backend/apps/slack/commands/events.py +++ b/backend/apps/slack/commands/events.py @@ -10,22 +10,17 @@ class Events(CommandBase): def get_template_context(self, command): """Get the template context.""" - events_data = get_events_data() or [] - valid_events = [event for event in events_data if event.start_date] - sorted_events = sorted(valid_events, key=lambda x: x.start_date) - - upcoming_events = {"event": []} - for event in sorted_events: - upcoming_events["event"].append( - { - "name": event.name, - "url": event.url, - "start_date": event.start_date, - "end_date": event.end_date, - "location": event.suggested_location, - "description": event.description, - } - ) + upcoming_events = [ + { + "description": event.description, + "end_date": event.end_date, + "location": event.suggested_location, + "name": event.name, + "start_date": event.start_date, + "url": event.url, + } + for event in sorted(get_events_data(), key=lambda e: e.start_date) + ] return { **super().get_template_context(command), diff --git a/backend/apps/slack/templates/events.jinja b/backend/apps/slack/templates/events.jinja index 13382c4966..162d51c2ce 100644 --- a/backend/apps/slack/templates/events.jinja +++ b/backend/apps/slack/templates/events.jinja @@ -1,16 +1,16 @@ *Upcoming OWASP Events:*{{ SECTION_BREAK }}{{ DIVIDER }}{{ SECTION_BREAK }} -{%- for event in upcoming_events.event %} +{%- for event in upcoming_events %} *{% if loop.index %}{{ loop.index }}. {% endif %}{% if event.url %}<{{ event.url }}|{{ event.name }}>{% else %}{{ event.name }}{% endif %}* -{{NL}}{%- if event.start_date and event.end_date -%} - {%- if event.start_date.strftime('%Y-%m-%d') == event.end_date.strftime('%Y-%m-%d') -%} - {{ event.start_date.strftime('%B %d, %Y') }} +_{%- if event.start_date and event.end_date -%} + {%- if event.start_date == event.end_date -%} + {{ event.start_date.strftime('%b %-d, %Y') }} {%- else -%} - {{ event.start_date.strftime('%B') }} {{ event.start_date.strftime('%d') }} - {{ event.end_date.strftime('%d') }}, {{ event.end_date.strftime('%Y') }} + {{ event.start_date.strftime('%b') }} {{ event.start_date.strftime('%-d') }} — {{ event.end_date.strftime('%-d') }}, {{ event.end_date.strftime('%Y') }} {%- endif -%} -{%- elif event.start_date -%} - {{ event.start_date.strftime('%B %d, %Y') }} -{%- endif -%}; {{ event.location }} -{%- if event.description %}{{ NL }}_{{ event.description }}_{% endif %}{{ NL }}{{ NL }}{%- if not loop.last %}{{ SECTION_BREAK }}{% endif %} +{%- else -%} + {{ event.start_date.strftime('%b %-d, %Y') }} +{%- endif %} | {{ event.location }}_ +{%- if event.description %}{{ NL }}{{ event.description }}{% endif %}{{ NL }}{%- if not loop.last %}{{ SECTION_BREAK }}{% endif %} {%- endfor %} {{ SECTION_BREAK }}{{ DIVIDER }}{{ SECTION_BREAK }} 🔍 For more information about upcoming events, please visit <{{ website_url }}/events/|OWASP Events>{{ NL }} diff --git a/backend/apps/slack/utils.py b/backend/apps/slack/utils.py index 1ed07d240d..8ac35e1cf2 100644 --- a/backend/apps/slack/utils.py +++ b/backend/apps/slack/utils.py @@ -126,11 +126,11 @@ def get_events_data(limit=9): """ from apps.owasp.models.event import Event - try: - return Event.objects.filter(start_date__gte=timezone.now()).order_by("start_date")[:limit] - except Exception as e: - logger.exception("Failed to fetch events data via database", extra={"error": str(e)}) - return None + return Event.objects.filter( + start_date__gte=timezone.now(), + ).order_by( + "start_date", + )[:limit] def get_sponsors_data(limit=10): diff --git a/backend/tests/apps/slack/commands/events_test.py b/backend/tests/apps/slack/commands/events_test.py index 4a972e39a4..28817593a1 100644 --- a/backend/tests/apps/slack/commands/events_test.py +++ b/backend/tests/apps/slack/commands/events_test.py @@ -109,9 +109,9 @@ def test_handler_responses( block_text = block["text"]["text"] if ( f"*1. <{event1.url}|{event1.name}>*" in block_text - and "March 14, 2025" in block_text + and "Mar 14, 2025" in block_text and "Denver, CO" in block_text - and f"_{event1.description}_" in block_text + and event1.description in block_text ): event1_text_found = True break @@ -124,13 +124,14 @@ def test_handler_responses( block_text = block["text"]["text"] if ( f"*2. <{event2.url}|{event2.name}>*" in block_text - and "May 26 - 30, 2025" in block_text + and "May 26 — 30, 2025" in block_text and "Amsterdam, Netherlands" in block_text - and f"_{event2.description}_" in block_text + and event2.description in block_text ): event2_text_found = True break assert event2_text_found, "Block containing Event 2 details not found or incorrect" + footer_block = sent_blocks[-1] assert footer_block["type"] == "section" assert "🔍 For more information about upcoming events" in footer_block["text"]["text"] diff --git a/frontend/src/server/queries/homeQueries.ts b/frontend/src/server/queries/homeQueries.ts index 57fc2fd5e6..c96071823b 100644 --- a/frontend/src/server/queries/homeQueries.ts +++ b/frontend/src/server/queries/homeQueries.ts @@ -81,7 +81,7 @@ export const GET_MAIN_PAGE_DATA = gql` contributorsStats countriesStats } - upcomingEvents(limit: 6) { + upcomingEvents(limit: 9) { category endDate key