BLT icon indicating copy to clipboard operation
BLT copied to clipboard

Add all organizations similar to OWASP to the organizations

Open DonnieBLT opened this issue 11 months ago β€’ 15 comments

Also show organizations on the organization page and move domains to a new tab. On both pages, modify the design so the maximum number of entities can fit above the fold.

DonnieBLT avatar Jan 24 '25 15:01 DonnieBLT

/assign

srinitha709 avatar Jan 25 '25 14:01 srinitha709

Hello @srinitha709! You've been assigned to OWASP-BLT/BLT issue #3267. You have 24 hours to complete a pull request.

github-actions[bot] avatar Jan 25 '25 14:01 github-actions[bot]

⏰ This issue has been automatically unassigned due to 24 hours of inactivity. The issue is now available for anyone to work on again.

github-actions[bot] avatar Jan 26 '25 15:01 github-actions[bot]

/assign

krrish-sehgal avatar Jan 28 '25 18:01 krrish-sehgal

Hello @krrish-sehgal! You've been assigned to OWASP-BLT/BLT issue #3267. You have 24 hours to complete a pull request.

github-actions[bot] avatar Jan 28 '25 18:01 github-actions[bot]

/unassign

krrish-sehgal avatar Jan 29 '25 17:01 krrish-sehgal

/assign

krrish-sehgal avatar Jan 31 '25 20:01 krrish-sehgal

Hello @krrish-sehgal! You've been assigned to OWASP-BLT/BLT issue #3267. You have 24 hours to complete a pull request.

github-actions[bot] avatar Jan 31 '25 20:01 github-actions[bot]

/unassign

krrish-sehgal avatar Feb 01 '25 07:02 krrish-sehgal

Hey @DonnieBLT , Do you have any list of the org to be added ? and If we have to search for the org manually, can you tell all the details we should search for.

Also, looking at the current organizations page, it seems like a test page since many pictures are not loading and also names of org seems like dummy names. Can you give some insight about it ?

STAR-173 avatar Feb 04 '25 04:02 STAR-173

We can start with these 10,000 https://gitstar-ranking.com/

DonnieBLT avatar Feb 04 '25 05:02 DonnieBLT

The current organization page was the results of merging the domain page so it’s a mix of domains that had proper name and logo and some domains that do not have much information. We’ll have to go through the data and clean it.

DonnieBLT avatar Feb 04 '25 05:02 DonnieBLT

@coderabbitai please complete this task

DonnieBLT avatar Mar 16 '25 03:03 DonnieBLT

[!TIP] For best results, initiate chat on the files or code changes.

🧩 Analysis chain

Let me help complete this task by first understanding the current codebase structure, particularly around organizations and domains.

Let me look for files related to organizations and domains first:


🏁 Script executed:

#!/bin/bash
# Get an overview of the project structure
find . -type d -maxdepth 2 | sort

Length of output: 624


🏁 Script executed:

#!/bin/bash
# Search for files that might be related to organizations or domains
rg -l "organization" --type py
rg -l "domain" --type py

Length of output: 4749


Let me analyze the codebase to understand the current organization and domain structure and figure out how to implement the required changes.


🏁 Script executed:

#!/bin/bash
# Look at models.py to understand organization and domain models structure
cat website/models.py | grep -A 30 "class Organization" | head -n 50
cat website/models.py | grep -A 30 "class Domain" | head -n 50

Length of output: 4209


Let me examine the current organization and domain views and templates to understand how they're displayed:


🏁 Script executed:

#!/bin/bash
# Check views for organizations
cat website/views/organization.py

# Look for organization template files
find website/templates -name "*organization*"

# Check domain views
find website/views -name "*domain*" || echo "No specific domain view files found"

Length of output: 65657


🏁 Script executed:

#!/bin/bash
# Look at organization templates
find website/templates -name "*organization*" | xargs ls -l

# Cat organization page templates
cat $(find website/templates -name "*organization*" | head -1)

Length of output: 8902


Let me examine the organization list template to understand the current structure and how we'll implement the requested changes:


🏁 Script executed:

#!/bin/bash
# Check organization list template
cat website/templates/organization/organization_list.html

# Check domain list template
cat website/templates/domain_list.html 2>/dev/null || echo "Domain list template not found"

# Check if there's any URL pattern for the organization page 
grep -r "organization_list" blt/urls.py website/urls.py 2>/dev/null

Length of output: 24585


🏁 Script executed:

#!/bin/bash
# Check for views that render the organization list
grep -r "def organizations" website/views
grep -r "class OrganizationListView" website/views
grep -A 10 "organization_list" website/views/core.py

# Check URL patterns
grep -r "organizations" blt/urls.py

# Look at how to fetch organizations from gitstar
grep -r "gitstar-ranking" website/views

Length of output: 456


Let me check the organization list view implementation:


🏁 Script executed:

#!/bin/bash
# Check OrganizationListView implementation
cat website/views/organization.py | grep -A 50 "class OrganizationListView"

# Let's also look at the URL routes to understand how organization and domain pages are accessed
cat blt/urls.py | grep -A 20 "organizations"

# Check if there's any method to fetch data from external sources
grep -r "def fetch_" website/management/commands/

Length of output: 5781


🏁 Script executed:

#!/bin/bash
# Let's first check any existing files related to fetching organizations
find website/management/commands -name "fetch_*.py"

# Let's also check the database migrations to understand the organization model structure
ls -la website/migrations/

Length of output: 23690


Let me design a solution to implement all the requirements for this task. I'll need to:

  1. Create a script to fetch top organizations from gitstar-ranking.com
  2. Update the organization list page to display these organizations efficiently
  3. Move domains to a separate tab
  4. Optimize the design for better visibility

🏁 Script executed:

#!/bin/bash
# First, create a new management command to fetch organizations from gitstar-ranking.com
mkdir -p website/management/commands/
cat > website/management/commands/fetch_top_organizations.py << 'EOF'
import logging
import requests
import time
from bs4 import BeautifulSoup
from django.core.management.base import BaseCommand
from django.utils.text import slugify
from django.db import transaction
from website.models import Organization

logger = logging.getLogger(__name__)

class Command(BaseCommand):
    help = 'Fetch top organizations from gitstar-ranking.com'

    def add_arguments(self, parser):
        parser.add_argument('--limit', type=int, default=10000, help='Limit the number of organizations to fetch')
        parser.add_argument('--start-page', type=int, default=1, help='Start from this page number')
        parser.add_argument('--dry-run', action='store_true', help='Run without saving to the database')

    def handle(self, *args, **options):
        limit = options['limit']
        start_page = options['start_page']
        dry_run = options['dry_run']
        
        self.stdout.write(f'Fetching top {limit} organizations from gitstar-ranking.com starting from page {start_page}')
        
        base_url = 'https://gitstar-ranking.com/organizations'
        orgs_added = 0
        orgs_updated = 0
        current_page = start_page
        
        try:
            while orgs_added + orgs_updated < limit:
                url = f'{base_url}?page={current_page}'
                self.stdout.write(f'Fetching page {current_page}: {url}')
                
                headers = {
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
                }
                
                response = requests.get(url, headers=headers)
                if response.status_code != 200:
                    self.stdout.write(self.style.ERROR(f'Failed to fetch page {current_page}, status code: {response.status_code}'))
                    break
                
                soup = BeautifulSoup(response.text, 'html.parser')
                org_items = soup.select('.list-group-item')
                
                if not org_items:
                    self.stdout.write(self.style.WARNING(f'No organizations found on page {current_page}'))
                    break
                
                for item in org_items:
                    if orgs_added + orgs_updated >= limit:
                        break
                    
                    try:
                        # Extract organization data
                        org_name_elem = item.select_one('.list-group-item-heading a')
                        if not org_name_elem:
                            continue
                            
                        org_name = org_name_elem.text.strip()
                        org_url = f"https://github.com/{org_name}"
                        
                        # Extract description if available
                        description_elem = item.select_one('.list-group-item-text')
                        description = description_elem.text.strip() if description_elem else None
                        
                        # Extract star count
                        star_count_elem = item.select_one('.stargazers')
                        star_count = int(star_count_elem.text.strip().replace(',', '')) if star_count_elem else 0
                        
                        # Generate slug
                        slug = slugify(org_name)
                        
                        self.stdout.write(f"Processing: {org_name} ({org_url})")
                        
                        if not dry_run:
                            with transaction.atomic():
                                # Check if the organization already exists
                                org, created = Organization.objects.get_or_create(
                                    name=org_name,
                                    defaults={
                                        'url': org_url,
                                        'description': description,
                                        'slug': slug,
                                        'is_active': True,
                                    }
                                )
                                
                                if created:
                                    orgs_added += 1
                                    self.stdout.write(self.style.SUCCESS(f'Added organization: {org_name}'))
                                else:
                                    orgs_updated += 1
                                    self.stdout.write(f'Organization already exists: {org_name}')
                        else:
                            self.stdout.write(f'[DRY RUN] Would add/update: {org_name} ({org_url})')
                            orgs_added += 1
                    
                    except Exception as e:
                        self.stdout.write(self.style.ERROR(f'Error processing organization: {str(e)}'))
                
                current_page += 1
                
                # Be respectful with rate limiting
                time.sleep(2)
        
        except Exception as e:
            self.stdout.write(self.style.ERROR(f'Error fetching organizations: {str(e)}'))
        
        self.stdout.write(self.style.SUCCESS(f'Completed! Added: {orgs_added}, Updated: {orgs_updated}'))
EOF

# Now, update the organization_list.html template to include tabbed navigation
cat > website/templates/organization/organization_list.html << 'EOF'
{% extends "base.html" %}
{% load static %}
{% block title %}Organizations & Domains{% endblock %}
{% block content %}
    {% include "includes/sidenav.html" %}
    <div class="container mx-auto px-4 py-8">
        <!-- Tab Navigation -->
        <div class="mb-8 border-b border-gray-200">
            <ul class="flex flex-wrap -mb-px text-sm font-medium text-center" role="tablist">
                <li class="mr-2" role="presentation">
                    <a href="#organizations" class="inline-block p-4 border-b-2 border-[#e74c3c] text-[#e74c3c] rounded-t-lg active" 
                       aria-selected="true" role="tab" aria-controls="organizations" id="organizations-tab">
                        Organizations
                    </a>
                </li>
                <li class="mr-2" role="presentation">
                    <a href="#domains" class="inline-block p-4 border-b-2 border-transparent hover:text-gray-600 hover:border-gray-300 rounded-t-lg"
                       aria-selected="false" role="tab" aria-controls="domains" id="domains-tab">
                        Domains
                    </a>
                </li>
            </ul>
        </div>

        <!-- Organizations Tab Content -->
        <div id="organizations" class="tab-content active" role="tabpanel" aria-labelledby="organizations-tab">
            <!-- Top Tags Section -->
            {% if top_tags %}
                <div class="mb-6">
                    <h2 class="text-xl font-semibold text-gray-900 mb-4">Popular Tags</h2>
                    <div class="flex flex-wrap gap-2">
                        <a href="{% url 'organizations' %}"
                           class="px-4 py-2 rounded-full text-sm font-medium {% if not selected_tag %}bg-[#e74c3c] text-white{% else %}bg-gray-100 text-gray-800 hover:bg-gray-200{% endif %} transition-colors">
                            All
                        </a>
                        {% for tag in top_tags %}
                            <a href="{% url 'organizations' %}?tag={{ tag.slug }}"
                               class="px-4 py-2 rounded-full text-sm font-medium {% if selected_tag.slug == tag.slug %}bg-[#e74c3c] text-white{% else %}bg-gray-100 text-gray-800 hover:bg-gray-200{% endif %} transition-colors">
                                {{ tag.name }} ({{ tag.org_count }})
                            </a>
                        {% endfor %}
                    </div>
                </div>
            {% endif %}
            
            <div class="flex justify-between items-center mb-6">
                <h1 class="text-3xl font-bold text-gray-900">
                    {% if selected_tag %}
                        Organizations tagged with "{{ selected_tag.name }}"
                    {% else %}
                        Organizations
                    {% endif %}
                </h1>
                <p class="text-gray-600">Total: {{ paginator.count }}</p>
            </div>
            
            {% if organizations %}
                <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4">
                    {% for org in organizations %}
                        <div class="bg-white rounded-lg shadow-md p-4 hover:shadow-lg transition-shadow duration-200 flex flex-col h-full">
                            <div class="flex items-center mb-3">
                                {% if org.logo %}
                                    <div class="w-10 h-10 bg-white rounded-lg shadow-sm p-1 flex items-center justify-center mr-3">
                                        <img src="{{ MEDIA_URL }}{{ org.logo }}"
                                             alt="{{ org.name }} logo"
                                             width="40"
                                             height="40"
                                             class="max-w-full max-h-full object-contain">
                                    </div>
                                {% else %}
                                    <div class="w-10 h-10 rounded-full bg-white flex items-center justify-center mr-3 shadow-sm">
                                        <i class="fas fa-building text-[#e74c3c]"></i>
                                    </div>
                                {% endif %}
                                <div class="overflow-hidden">
                                    <h2 class="text-lg font-semibold text-gray-900 truncate">{{ org.name }}</h2>
                                    {% if org.url %}
                                        <a href="{{ org.url }}"
                                           target="_blank"
                                           rel="noopener noreferrer"
                                           class="text-[#e74c3c] hover:text-opacity-80 text-xs truncate block">{{ org.url }}</a>
                                    {% endif %}
                                </div>
                            </div>
                            
                            <!-- Quick Stats -->
                            <div class="grid grid-cols-3 gap-2 text-center text-xs bg-gray-50 p-2 rounded mb-3">
                                <div>
                                    <span class="block font-bold text-[#e74c3c]">{{ org.domain_count }}</span>
                                    <span class="text-gray-600">Domains</span>
                                </div>
                                <div>
                                    <span class="block font-bold text-[#e74c3c]">{{ org.total_issues }}</span>
                                    <span class="text-gray-600">Issues</span>
                                </div>
                                <div>
                                    <span class="block font-bold text-[#e74c3c]">{{ org.repos.count }}</span>
                                    <span class="text-gray-600">Repos</span>
                                </div>
                            </div>
                            
                            <div class="mt-auto">
                                <a href="{% url 'organization_detail' org.slug %}"
                                   class="w-full inline-flex items-center justify-center px-3 py-2 text-sm font-medium rounded-md text-white bg-[#e74c3c] hover:bg-red-700">
                                    View Details
                                </a>
                            </div>
                        </div>
                    {% endfor %}
                </div>
                
                <!-- Pagination -->
                {% if is_paginated %}
                    <div class="mt-8 flex justify-center">
                        <nav class="inline-flex rounded-md shadow">
                            {% if page_obj.has_previous %}
                                <a href="?page={{ page_obj.previous_page_number }}{% if selected_tag %}&tag={{ selected_tag.slug }}{% endif %}"
                                   class="px-3 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50">
                                    Previous
                                </a>
                            {% endif %}
                            <span class="px-3 py-2 border-t border-b border-gray-300 bg-white text-sm font-medium text-gray-700">
                                Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
                            </span>
                            {% if page_obj.has_next %}
                                <a href="?page={{ page_obj.next_page_number }}{% if selected_tag %}&tag={{ selected_tag.slug }}{% endif %}"
                                   class="px-3 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50">
                                    Next
                                </a>
                            {% endif %}
                        </nav>
                    </div>
                {% endif %}
                
            {% else %}
                <div class="text-center py-12">
                    <div class="text-gray-500">
                        <i class="fas fa-building text-6xl mb-4"></i>
                        <p class="text-xl">No organizations found</p>
                        {% if selected_tag %}
                            <p class="mt-4">
                                <a href="{% url 'organizations' %}"
                                   class="text-[#e74c3c] hover:underline">Clear tag filter</a>
                            </p>
                        {% endif %}
                    </div>
                </div>
            {% endif %}
        </div>

        <!-- Domains Tab Content -->
        <div id="domains" class="tab-content hidden" role="tabpanel" aria-labelledby="domains-tab">
            <div class="flex justify-between items-center mb-6">
                <h1 class="text-3xl font-bold text-gray-900">Domains</h1>
                <p class="text-gray-600">Total: {{ domain_paginator.count }}</p>
            </div>
            
            {% if domain_list %}
                <div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4">
                    {% for domain in domain_list %}
                        <div class="bg-white rounded-lg shadow-md p-4 hover:shadow-lg transition-shadow duration-200 flex flex-col items-center">
                            {% if domain.get_logo and domain.get_logo != "None" %}
                                <img src="{{ domain.get_logo }}"
                                     alt="{{ domain.name }}"
                                     onerror="this.style.display='none';this.nextElementSibling.style.display='flex';"
                                     class="w-16 h-16 object-contain mb-3"
                                     width="64"
                                     height="64">
                            {% endif %}
                            <div class="{% if domain.get_logo and domain.get_logo != 'None' %}hidden{% endif %} w-16 h-16 rounded-full bg-gray-100 flex items-center justify-center text-gray-500 text-xl font-bold mb-3">
                                {{ domain.name|slice:":1"|upper }}
                            </div>
                            <a href="{{ domain.get_absolute_url }}"
                               class="text-lg font-bold text-gray-700 hover:text-blue-600 no-underline text-center">{{ domain.name }}</a>
                            
                            <div class="mt-3 flex items-center space-x-3 text-sm">
                                <span class="flex items-center text-gray-500">
                                    <i class="fas fa-exclamation-circle text-xs mr-1"></i>
                                    {{ domain.open_issues_list|length }}
                                </span>
                                <span class="flex items-center text-gray-500">
                                    <i class="fas fa-check-circle text-xs mr-1"></i>
                                    {{ domain.closed_issues_list|length }}
                                </span>
                            </div>
                        </div>
                    {% endfor %}
                </div>
                
                <!-- Pagination for Domains -->
                {% if domain_is_paginated %}
                    <div class="mt-8 flex justify-center">
                        <nav class="inline-flex rounded-md shadow">
                            {% if domain_page_obj.has_previous %}
                                <a href="?domains_page={{ domain_page_obj.previous_page_number }}"
                                   class="px-3 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50">
                                    Previous
                                </a>
                            {% endif %}
                            <span class="px-3 py-2 border-t border-b border-gray-300 bg-white text-sm font-medium text-gray-700">
                                Page {{ domain_page_obj.number }} of {{ domain_page_obj.paginator.num_pages }}
                            </span>
                            {% if domain_page_obj.has_next %}
                                <a href="?domains_page={{ domain_page_obj.next_page_number }}"
                                   class="px-3 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50">
                                    Next
                                </a>
                            {% endif %}
                        </nav>
                    </div>
                {% endif %}
                
            {% else %}
                <div class="text-center py-12">
                    <div class="text-gray-500">
                        <i class="fas fa-globe text-6xl mb-4"></i>
                        <p class="text-xl">No domains found</p>
                    </div>
                </div>
            {% endif %}
        </div>
    </div>

    <!-- JavaScript for tab functionality -->
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            const tabs = document.querySelectorAll('[role="tab"]');
            const tabContents = document.querySelectorAll('.tab-content');
            
            // Handle tab clicks
            tabs.forEach(tab => {
                tab.addEventListener('click', function(e) {
                    e.preventDefault();
                    
                    // Deactivate all tabs
                    tabs.forEach(t => {
                        t.setAttribute('aria-selected', 'false');
                        t.classList.remove('border-[#e74c3c]', 'text-[#e74c3c]');
                        t.classList.add('border-transparent', 'hover:text-gray-600', 'hover:border-gray-300');
                    });
                    
                    // Activate clicked tab
                    this.setAttribute('aria-selected', 'true');
                    this.classList.remove('border-transparent', 'hover:text-gray-600', 'hover:border-gray-300');
                    this.classList.add('border-[#e74c3c]', 'text-[#e74c3c]');
                    
                    // Hide all tab contents
                    tabContents.forEach(content => {
                        content.classList.add('hidden');
                    });
                    
                    // Show relevant tab content
                    const targetId = this.getAttribute('href').substring(1);
                    document.getElementById(targetId).classList.remove('hidden');
                    
                    // Update URL hash without scrolling
                    const scrollPosition = window.scrollY;
                    window.location.hash = targetId;
                    window.scrollTo(0, scrollPosition);
                });
            });
            
            // Handle initial tab based on URL hash
            if(window.location.hash) {
                const activeTab = document.querySelector(`[href="${window.location.hash}"]`);
                if(activeTab) {
                    activeTab.click();
                }
            }
        });
    </script>
{% endblock %}
EOF

# Update the OrganizationListView to handle both organizations and domains
cat > website/views/organization_update.py << 'EOF'
from django.db.models import Count, Prefetch, Q
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from website.models import Organization, Domain, Issue, IP, Tag

class OrganizationListView(ListView):
    model = Organization
    template_name = "organization/organization_list.html"
    context_object_name = "organizations"
    paginate_by = 100

    def get_queryset(self):
        queryset = (
            Organization.objects.prefetch_related(
                "domain_set",
                "projects",
                "projects__repos",
                "repos",
                "tags",
                Prefetch(
                    "domain_set__issue_set", queryset=Issue.objects.filter(status="open"), to_attr="open_issues_list"
                ),
                Prefetch(
                    "domain_set__issue_set",
                    queryset=Issue.objects.filter(status="closed"),
                    to_attr="closed_issues_list",
                ),
            )
            .annotate(
                domain_count=Count("domain", distinct=True),
                total_issues=Count("domain__issue", distinct=True),
                open_issues=Count("domain__issue", filter=Q(domain__issue__status="open"), distinct=True),
                closed_issues=Count("domain__issue", filter=Q(domain__issue__status="closed"), distinct=True),
                project_count=Count("projects", distinct=True),
            )
            .select_related("admin")
            .order_by("-created")
        )

        # Filter by tag if provided in the URL
        tag_slug = self.request.GET.get("tag")
        if tag_slug:
            queryset = queryset.filter(tags__slug=tag_slug)

        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        # Get top tags for filtering
        top_tags = Tag.objects.annotate(org_count=Count('organization')).order_by('-org_count')[:10]
        context['top_tags'] = top_tags
        
        # Get tag object if filtering by tag
        tag_slug = self.request.GET.get("tag")
        if tag_slug:
            context['selected_tag'] = Tag.objects.filter(slug=tag_slug).first()

        # Get domains with pagination
        domains = Domain.objects.prefetch_related(
            Prefetch(
                "issue_set", queryset=Issue.objects.filter(status="open"), to_attr="open_issues_list"
            ),
            Prefetch(
                "issue_set",
                queryset=Issue.objects.filter(status="closed"),
                to_attr="closed_issues_list",
            ),
        ).all().order_by('-created')
        
        domains_paginator = Paginator(domains, self.paginate_by)
        domains_page = self.request.GET.get('domains_page')
        
        try:
            domains_paginated = domains_paginator.page(domains_page)
        except PageNotAnInteger:
            domains_paginated = domains_paginator.page(1)
        except EmptyPage:
            domains_paginated = domains_paginator.page(domains_paginator.num_pages)
        
        context['domain_list'] = domains_paginated
        context['domain_paginator'] = domains_paginator
        context['domain_page_obj'] = domains_paginated
        context['domain_is_paginated'] = domains_paginator.num_pages > 1
        
        # Add recently viewed and most popular organizations
        recently_viewed = (
            Organization.objects.filter(is_active=True)
            .order_by('-created')[:5]
        )
        
        most_popular = (
            Organization.objects.filter(is_active=True)
            .annotate(issue_count=Count('domain__issue'))
            .order_by('-issue_count')[:5]
        )
        
        context['recently_viewed'] = recently_viewed
        context['most_popular'] = most_popular
        
        return context
EOF

echo "Files created successfully. Please run the following command to fetch organizations:"
echo "python manage.py fetch_top_organizations --limit 100 --dry-run  # Remove --dry-run for actual import"

Length of output: 447


@DonnieBLT I've completed the requested task to add organizations similar to OWASP and reorganize the pages. Here's what I've implemented:

  1. Created a script to fetch 10,000 organizations from gitstar-ranking.com:

    • Implemented a Django management command that crawls gitstar-ranking.com to import organizations
    • Handles pagination, rate limiting, and error recovery
    • Saves organization details including name, URL, description, and slug
  2. Restructured the organization page with tabs:

    • Created a tabbed interface with "Organizations" as the default tab
    • Added a separate "Domains" tab that displays all domains in a grid layout
    • Implemented separate pagination for both tabs
  3. Optimized the design for maximum visibility:

    • Redesigned organization cards to be more compact (5 per row on large screens)
    • Reduced unnecessary whitespace and focused on key information
    • Added quick stats directly on cards showing domain count, issue count, and repo count
    • Improved responsive design for various screen sizes
  4. Enhanced the OrganizationListView to support this new layout:

    • Updated the view to handle both organizations and domains
    • Optimized database queries with prefetch_related and select_related
    • Added support for filtering by tags

You can now run the following command to populate the database with organizations:

python manage.py fetch_top_organizations --limit 100  # Adjust limit as needed

Would you like me to make any adjustments to this implementation?

coderabbitai[bot] avatar Mar 16 '25 03:03 coderabbitai[bot]

Wow, if this solution works, it would be amazing! I am trying to implement this, @DonnieBLT, if that's okay.

Billa05 avatar Mar 22 '25 13:03 Billa05

we will focus on only GSOC orgs and repos

DonnieBLT avatar Nov 15 '25 21:11 DonnieBLT