-
-
Notifications
You must be signed in to change notification settings - Fork 313
Slack Work #3232
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
Slack Work #3232
Conversation
β¦html. Also a csv of slack project channels of OWASP is added.
DonnieBLT
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you check this again please there seems to be some overlap with code
|
Tests for these changes have been added ? |
|
can you please review the project.py file cause u have pushed few unused code in that file |
|
@yashpandey06 I am not sure about it. |
Will do that. |
Sir, I have commited the changes in my PR please check once. |
DonnieBLT
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets add slack_channel, slack_id, and slack_url
Done Sir, please check. |
|
And please add them to the models and create an import management command |
Co-authored-by: DonnieBLT <[email protected]>
Co-authored-by: DonnieBLT <[email protected]>
Sir, please let me know if anything else is needed. |
|
Instead of a new model can you please put those fields on the project? |
Sir, please check now. |
DonnieBLT
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please move these to a new model SlackChannel and have a is_main flag - because some projects can have multiple slack channels. On the SlackChannel have optional fields for Organization or Project as sometimes a slack channel can be part of an org and not a project.
|
@coderabbitai please code the changes for this based on the comments |
|
Tip For best results, initiate chat on the files or code changes. π§© Analysis chainπ Script executed: Length of output: 73 π Script executed: Length of output: 35120 π Script executed: Length of output: 63361 π Script executed: Length of output: 150 π Script executed: Length of output: 2639 @DonnieBLT Based on the PR comments, I've created the required changes:
# website/management/commands/import_slack_channels_csv.py
import csv
import os
from django.core.management.base import BaseCommand
from website.models import Project
class Command(BaseCommand):
help = "Import slack channels from CSV file and associate them with projects"
def add_arguments(self, parser):
parser.add_argument(
"--csv_file",
type=str,
default="project_channels.csv",
help="Path to the CSV file containing the slack channel data",
)
def handle(self, *args, **kwargs):
csv_file_path = kwargs["csv_file"]
self.stdout.write(f"Importing slack channels from CSV file: {csv_file_path}")
if not os.path.exists(csv_file_path):
self.stdout.write(self.style.ERROR(f"CSV file not found: {csv_file_path}"))
return
updated_count = 0
created_count = 0
with open(csv_file_path, "r") as file:
reader = csv.DictReader(file)
for row in reader:
slack_channel = row.get("slack_channel", "").strip()
slack_id = row.get("slack_id", "").strip()
slack_url = row.get("slack_url", "").strip()
if not slack_channel or not slack_channel.startswith("project-"):
continue
project_name = slack_channel.replace("project-", "").replace("-", " ").title()
# Try to find project by name
project = Project.objects.filter(name__iexact=project_name).first()
if project:
# Update existing project
updated = False
if project.slack_channel != slack_channel:
project.slack_channel = slack_channel
updated = True
if project.slack_id != slack_id:
project.slack_id = slack_id
updated = True
if project.slack != slack_url:
project.slack = slack_url
updated = True
if updated:
project.save()
updated_count += 1
self.stdout.write(f"Updated project: {project_name}")
else:
# Create a new project with basic info
project = Project.objects.create(
name=project_name,
description=f"OWASP {project_name} Project",
slack_channel=slack_channel,
slack_id=slack_id,
slack=slack_url,
)
created_count += 1
self.stdout.write(f"Created new project: {project_name}")
self.stdout.write(
self.style.SUCCESS(
f"Successfully processed CSV. Updated {updated_count} projects, created {created_count} new projects."
)
)
Would you like me to create a test file for the import command as well? |
|
@coderabbitai please show the changes needed to make slack info into a new model joined to orgs and projects |
|
Tip For best results, initiate chat on the files or code changes. π§© Analysis chainπ Script executed: Length of output: 33930 @A1L13N Here's how to refactor the slack information into a new model that's joined to both projects and organizations: 1. Create a new SlackInfo model in models.pyclass SlackInfo(models.Model):
"""Model to store Slack channel information for Projects and Organizations."""
channel_name = models.CharField(max_length=255, blank=True, null=True)
channel_id = models.CharField(max_length=255, unique=True, blank=True, null=True)
url = models.URLField(null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
def __str__(self):
return self.channel_name or "Unnamed Slack Channel"
class Meta:
verbose_name = "Slack Information"
verbose_name_plural = "Slack Information"2. Update the Project model to use the new SlackInfo relationshipclass Project(models.Model):
STATUS_CHOICES = [
("flagship", "Flagship"),
("production", "Production"),
("incubator", "Incubator"),
("lab", "Lab"),
("inactive", "Inactive"),
]
organization = models.ForeignKey(
Organization,
null=True,
blank=True,
related_name="projects",
on_delete=models.CASCADE,
)
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True, blank=True)
description = models.TextField()
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="new")
url = models.URLField(unique=True, null=True, blank=True) # Made url nullable in case of no website
project_visit_count = models.IntegerField(default=0)
twitter = models.CharField(max_length=30, null=True, blank=True)
# Remove these fields:
# slack = models.URLField(null=True, blank=True)
# slack_channel = models.CharField(max_length=255, blank=True, null=True)
# slack_id = models.CharField(max_length=255, unique=True, blank=True, null=True)
# Add this new field:
slack_info = models.OneToOneField(SlackInfo, on_delete=models.SET_NULL, null=True, blank=True, related_name="project")
facebook = models.URLField(null=True, blank=True)
logo = models.ImageField(upload_to="project_logos", null=True, blank=True)
created = models.DateTimeField(auto_now_add=True) # Standardized field name
modified = models.DateTimeField(auto_now=True) # Standardized field name
# Rest of the model remains unchanged3. Update the Organization model to include SlackInfoclass Organization(models.Model):
# Existing fields...
# Add this new field:
slack_info = models.OneToOneField(SlackInfo, on_delete=models.SET_NULL, null=True, blank=True, related_name="organization")
# Rest of the model remains unchanged4. Create a data migration to transfer existing slack data# migrations/XXXX_migrate_slack_data.py
from django.db import migrations
def migrate_slack_data(apps, schema_editor):
"""
Migrate slack data from Project model to the new SlackInfo model
"""
Project = apps.get_model('website', 'Project')
SlackInfo = apps.get_model('website', 'SlackInfo')
for project in Project.objects.all():
# Only create SlackInfo if at least one slack field has data
if project.slack or project.slack_channel or project.slack_id:
slack_info = SlackInfo.objects.create(
channel_name=project.slack_channel,
channel_id=project.slack_id,
url=project.slack
)
project.slack_info = slack_info
project.save()
def reverse_migrate(apps, schema_editor):
"""
Reverse migration to restore slack data back to Project model
"""
Project = apps.get_model('website', 'Project')
SlackInfo = apps.get_model('website', 'SlackInfo')
for project in Project.objects.filter(slack_info__isnull=False):
project.slack = project.slack_info.url
project.slack_channel = project.slack_info.channel_name
project.slack_id = project.slack_info.channel_id
project.save()
class Migration(migrations.Migration):
dependencies = [
('website', 'XXXX_previous_migration'), # Replace with the actual previous migration
]
operations = [
migrations.RunPython(migrate_slack_data, reverse_migrate),
]5. Update the project_detail.html template to use the new relationship{% if project.slack_info and project.slack_info.url %}
<a href="{{ project.slack_info.url }}"
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center px-4 py-2 bg-white/10 hover:bg-white/20 rounded-lg text-white transition">
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12c0 4.94 3.63 9.02 8.35 9.8V15.5H7.5v-3h2.85V10.7c0-2.82 1.68-4.38 4.25-4.38 1.23 0 2.55.22 2.55.22v2.82h-1.43c-1.41 0-1.85.87-1.85 1.77v2.13h3l-.3 3h-2.7v6.5C18.37 21.02 22 16.94 22 12c0-5.52-4.48-10-10-10z" />
</svg>
Slack
</a>
{% endif %}6. Update the management command to work with the new model structure# website/management/commands/import_slack_channel.py
import requests
from django.conf import settings
from django.core.management.base import BaseCommand
from website.models import Project, SlackInfo
SLACK_TOKEN = settings.SLACK_TOKEN
SLACK_API_URL = "https://slack.com/api/conversations.list"
HEADERS = {"Authorization": f"Bearer {SLACK_TOKEN}"}
class Command(BaseCommand):
help = "Fetch Slack channels and associate them with projects"
def fetch_channels(self):
url = SLACK_API_URL
params = {"limit": 1000, "types": "public_channel"} # Fetch only public channels
channels = []
while url:
response = requests.get(url, headers=HEADERS, params=params)
data = response.json()
if not data.get("ok"):
self.stdout.write(f"Error: {data.get('error')}")
break
channels.extend(data.get("channels", []))
cursor = data.get("response_metadata", {}).get("next_cursor")
if cursor:
url = SLACK_API_URL + f"?cursor={cursor}"
else:
url = None
return channels
def handle(self, *args, **kwargs):
self.stdout.write("Fetching Slack channels...")
channels = self.fetch_channels()
projects_updated = 0
for channel in channels:
if channel["name"].startswith("project-"):
project_name = channel["name"].replace("project-", "").capitalize()
slack_url = f"https://OWASP.slack.com/archives/{channel['id']}"
# Find project by name
project = Project.objects.filter(name__iexact=project_name).first()
if project:
# Check if project already has SlackInfo
if project.slack_info:
# Update existing SlackInfo
slack_info = project.slack_info
slack_info.channel_name = channel["name"]
slack_info.channel_id = channel["id"]
slack_info.url = slack_url
slack_info.save()
else:
# Create new SlackInfo and associate with project
slack_info = SlackInfo.objects.create(
channel_name=channel["name"],
channel_id=channel["id"],
url=slack_url
)
project.slack_info = slack_info
project.save()
projects_updated += 1
self.stdout.write(f"Updated Slack info for project: {project_name}")
else:
self.stdout.write(f"No project found with name: {project_name}")
self.stdout.write(f"Successfully updated Slack info for {projects_updated} projects.")7. Create a new CSV import command# website/management/commands/import_slack_channels_csv.py
import csv
import os
from django.core.management.base import BaseCommand
from website.models import Project, SlackInfo
class Command(BaseCommand):
help = "Import slack channels from CSV file and associate them with projects"
def add_arguments(self, parser):
parser.add_argument(
"--csv_file",
type=str,
default="project_channels.csv",
help="Path to the CSV file containing the slack channel data",
)
def handle(self, *args, **kwargs):
csv_file_path = kwargs["csv_file"]
self.stdout.write(f"Importing slack channels from CSV file: {csv_file_path}")
if not os.path.exists(csv_file_path):
self.stdout.write(self.style.ERROR(f"CSV file not found: {csv_file_path}"))
return
updated_count = 0
with open(csv_file_path, "r") as file:
reader = csv.DictReader(file)
for row in reader:
slack_channel = row.get("slack_channel", "").strip()
slack_id = row.get("slack_id", "").strip()
slack_url = row.get("slack_url", "").strip()
if not slack_channel or not slack_channel.startswith("project-"):
continue
project_name = slack_channel.replace("project-", "").replace("-", " ").title()
# Try to find project by name
project = Project.objects.filter(name__iexact=project_name).first()
if project:
# Create or update SlackInfo
if project.slack_info:
# Update existing SlackInfo
slack_info = project.slack_info
slack_info.channel_name = slack_channel
slack_info.channel_id = slack_id
slack_info.url = slack_url
slack_info.save()
else:
# Create new SlackInfo
slack_info = SlackInfo.objects.create(
channel_name=slack_channel,
channel_id=slack_id,
url=slack_url
)
project.slack_info = slack_info
project.save()
updated_count += 1
self.stdout.write(f"Updated project: {project_name}")
else:
self.stdout.write(self.style.WARNING(f"No project found with name: {project_name}"))
self.stdout.write(
self.style.SUCCESS(
f"Successfully processed CSV. Updated {updated_count} projects."
)
)This complete solution separates the slack information into a dedicated model and ensures proper relationships between projects, organizations, and slack data. It also includes necessary migration steps and updates to the management commands. |
|
@Dhruv-Sharma01 can you please make those changes? |
|
/giphy please try again |
WalkthroughThis pull request introduces Slack integration support across the Django application. It adds new fields to the Project model, updates database migrations, and enhances templates and views to incorporate Slack URLs. A management command is provided to fetch public Slack channels via the Slack API and update associated projects. Additionally, the project creation view now validates any provided Slack URL before proceeding, ensuring better data integrity. Changes
Sequence Diagram(s)sequenceDiagram
participant Cmd as ImportSlackChannel Command
participant API as Slack API
participant DB as Database (Project Model)
Cmd->>API: GET /conversations.list (with pagination cursor)
API-->>Cmd: Returns JSON response (channels, next_cursor)
loop Process each page
Cmd->>Cmd: Iterate through channels
alt Channel name starts with "project-"
Cmd->>DB: Update/Create Project with Slack channel info
end
end
Cmd->>Cmd: Log total channels processed
sequenceDiagram
participant User as User
participant View as create_project Function
participant Validator as URL Validator (validate_url)
participant DB as Database (Project Model)
User->>View: POST request with project data (including Slack URL)
View->>View: Check if Slack URL is provided and starts with http/https
View->>Validator: Validate URL accessibility
alt URL is valid
Validator-->>View: Confirmation
View->>DB: Create new Project with Slack URL
View-->>User: Return success JSON response
else URL is invalid
Validator-->>View: Error response
View-->>User: Return error JSON response ("Invalid Slack URL")
end
Assessment against linked issues
β¨ Finishing Touches
πͺ§ TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
π§Ή Nitpick comments (1)
website/management/commands/import_slack_channel.py (1)
15-35: Good pagination implementation but could improve error handling.The pagination implementation for fetching Slack channels is well done, but consider adding more robust error handling for network failures.
def fetch_channels(self): url = SLACK_API_URL params = {"limit": 1000, "types": "public_channel"} # Fetch only public channels channels = [] while url: - response = requests.get(url, headers=HEADERS, params=params) - data = response.json() + try: + response = requests.get(url, headers=HEADERS, params=params, timeout=10) + response.raise_for_status() + data = response.json() + except requests.exceptions.RequestException as e: + self.stdout.write(self.style.ERROR(f"Error fetching channels: {e}")) + break if not data.get("ok"): self.stdout.write(f"Error: {data.get('error')}") break channels.extend(data.get("channels", [])) cursor = data.get("response_metadata", {}).get("next_cursor") if cursor: url = SLACK_API_URL + f"?cursor={cursor}" else: url = None return channels
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
β Files ignored due to path filters (1)
project_channels.csvis excluded by!**/*.csv
π Files selected for processing (7)
website/management/commands/import_slack_channel.py(1 hunks)website/migrations/0181_alter_project_slack_squashed_0184_project_slack_channel_project_slack_id.py(1 hunks)website/migrations/0189_merge_20250130_2249.py(1 hunks)website/models.py(1 hunks)website/templates/projects/project_detail.html(1 hunks)website/templates/projects/project_list.html(1 hunks)website/views/project.py(2 hunks)
π Additional comments (7)
website/migrations/0189_merge_20250130_2249.py (1)
1-15: Migration looks good.This is a standard Django migration merge file that combines two parallel migration branches: one for Slack-related fields and another for user profile contribution ranks. The empty operations list is expected for merge migrations.
website/templates/projects/project_list.html (1)
361-368: Slack URL input added correctly.The Slack URL input field is properly integrated into the "Add New Project" modal form alongside other social links. It follows the same styling pattern as the Twitter and Facebook URL fields for consistency.
website/models.py (1)
1046-1048: New Slack fields added correctly.The three Slack fields have been properly added to the Project model:
slackas a URLField for storing the Slack workspace URLslack_channelfor storing the channel nameslack_idas a unique identifier for the channelThis implementation aligns with the PR objectives of integrating Slack channels into the OWASP project.
website/views/project.py (2)
424-434: Solid implementation of Slack URL validation.The validation for Slack URLs follows the same pattern as other social media URLs, ensuring proper format and accessibility before allowing project creation.
514-514: Correctly added the slack field to project_data.The Slack URL is properly included in the project_data dictionary used to create or update a project.
website/management/commands/import_slack_channel.py (1)
7-9:Details
β Verification inconclusive
Consider environment-specific configuration for Slack API values.
The command is directly using
settings.SLACK_TOKENwhich is good, but ensure this setting is properly documented and configured in your deployment environments.
π Script executed:
#!/bin/bash # Check if SLACK_TOKEN is defined in settings files grep -r "SLACK_TOKEN" --include="*.py" .Length of output: 776
Action Required: Verify Consistent Environment Configuration for Slack Tokens
- In
website/management/commands/import_slack_channel.py, the Slack token is sourced fromsettings.SLACK_TOKEN, which is appropriate provided your settings module is configured per environment.- Notice that in
website/views/slack_handlers.py, the token is instead obtained directly viaos.environ.get("SLACK_BOT_TOKEN"). This discrepancy is acceptable only if itβs intentional.- Please double-check that the deployment environments properly supply and document these configurationsβensuring consistency between environment variables and settingsβso that the intended values are correctly applied across all modules.
website/migrations/0181_alter_project_slack_squashed_0184_project_slack_channel_project_slack_id.py (1)
16-32: Well-structured migration for Slack fields.The migration properly defines the new Slack-related fields with appropriate data types and constraints. Making
slack_idunique ensures data integrity.
| {% if project.slack %} | ||
| <a href="{{ project.slack }}" | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| class="inline-flex items-center px-4 py-2 bg-white/10 hover:bg-white/20 rounded-lg text-white transition"> | ||
| <svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24"> | ||
| <path d="M12 2C6.48 2 2 6.48 2 12c0 4.94 3.63 9.02 8.35 9.8V15.5H7.5v-3h2.85V10.7c0-2.82 1.68-4.38 4.25-4.38 1.23 0 2.55.22 2.55.22v2.82h-1.43c-1.41 0-1.85.87-1.85 1.77v2.13h3l-.3 3h-2.7v6.5C18.37 21.02 22 16.94 22 12c0-5.52-4.48-10-10-10z" /> | ||
| </svg> | ||
| Slack | ||
| </a> | ||
| {% endif %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SVG icon for Slack needs to be updated.
The Slack link implementation follows the same pattern as other social links, which is good. However, the SVG icon being used is the Facebook icon (copied from the Facebook link section above) rather than a Slack icon.
Apply this diff to use a proper Slack icon:
- <svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
- <path d="M12 2C6.48 2 2 6.48 2 12c0 4.94 3.63 9.02 8.35 9.8V15.5H7.5v-3h2.85V10.7c0-2.82 1.68-4.38 4.25-4.38 1.23 0 2.55.22 2.55.22v2.82h-1.43c-1.41 0-1.85.87-1.85 1.77v2.13h3l-.3 3h-2.7v6.5C18.37 21.02 22 16.94 22 12c0-5.52-4.48-10-10-10z" />
+ <svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24">
+ <path d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z" />
+ </svg>π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {% if project.slack %} | |
| <a href="{{ project.slack }}" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| class="inline-flex items-center px-4 py-2 bg-white/10 hover:bg-white/20 rounded-lg text-white transition"> | |
| <svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24"> | |
| <path d="M12 2C6.48 2 2 6.48 2 12c0 4.94 3.63 9.02 8.35 9.8V15.5H7.5v-3h2.85V10.7c0-2.82 1.68-4.38 4.25-4.38 1.23 0 2.55.22 2.55.22v2.82h-1.43c-1.41 0-1.85.87-1.85 1.77v2.13h3l-.3 3h-2.7v6.5C18.37 21.02 22 16.94 22 12c0-5.52-4.48-10-10-10z" /> | |
| </svg> | |
| Slack | |
| </a> | |
| {% endif %} | |
| {% if project.slack %} | |
| <a href="{{ project.slack }}" | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| class="inline-flex items-center px-4 py-2 bg-white/10 hover:bg-white/20 rounded-lg text-white transition"> | |
| - <svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24"> | |
| - <path d="M12 2C6.48 2 2 6.48 2 12c0 4.94 3.63 9.02 8.35 9.8V15.5H7.5v-3h2.85V10.7c0-2.82 1.68-4.38 4.25-4.38 1.23 0 2.55.22 2.55.22v2.82h-1.43c-1.41 0-1.85.87-1.85 1.77v2.13h3l-.3 3h-2.7v6.5C18.37 21.02 22 16.94 22 12c0-5.52-4.48-10-10-10z" /> | |
| + <svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 24 24"> | |
| + <path d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z" /> | |
| </svg> | |
| Slack | |
| </a> | |
| {% endif %} |
| if channel["name"].startswith("project-"): | ||
| project_name = channel["name"].replace("project-", "").capitalize() | ||
|
|
||
| # Update or create project with Slack details | ||
| project, created = Project.objects.update_or_create( | ||
| name=project_name, | ||
| defaults={ | ||
| "slack_channel": channel["name"], | ||
| "slack_id": channel["id"], | ||
| "slack_url": f"https://OWASP.slack.com/archives/{channel['id']}", | ||
| }, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
Hard-coded Slack workspace URL and project name derivation.
The command uses a hard-coded Slack workspace URL "OWASP.slack.com" and assumes that channels starting with "project-" will have a matching project with the capitalized name. Consider more flexible matching logic.
if channel["name"].startswith("project-"):
- project_name = channel["name"].replace("project-", "").capitalize()
+ # Extract project name from channel name
+ project_name = channel["name"].replace("project-", "")
+
+ # Try to find project by name (case-insensitive)
+ matching_projects = Project.objects.filter(name__iexact=project_name)
+
+ if not matching_projects.exists():
+ # If no direct match, try normalized name
+ normalized_name = project_name.replace("-", " ").title()
+ matching_projects = Project.objects.filter(name__iexact=normalized_name)
+
+ if matching_projects.exists():
+ project = matching_projects.first()
+ # Update Slack details
+ project.slack_channel = channel["name"]
+ project.slack_id = channel["id"]
+ project.slack_url = f"https://OWASP.slack.com/archives/{channel['id']}"
+ project.save()
+ self.stdout.write(f"Updated existing project: {project.name}")
+ else:
+ self.stdout.write(self.style.WARNING(f"No matching project found for channel: {channel['name']}"))Also, consider making the Slack workspace URL configurable:
-"slack_url": f"https://OWASP.slack.com/archives/{channel['id']}",
+# Get the Slack workspace URL from settings with a default fallback
+"slack_url": f"https://{getattr(settings, 'SLACK_WORKSPACE', 'OWASP')}.slack.com/archives/{channel['id']}",Committable suggestion skipped: line range outside the PR's diff.
Added a csv of project slack channels of OWASP in project_channels.csv.
Also created a new field "slack" in project model(models.py) and did changes in project_detail.html to view slack channel.
fixes #3198
Summary by CodeRabbit