Skip to content

Commit b929565

Browse files
committed
done
1 parent afdd07b commit b929565

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import logging
2+
3+
import requests
4+
from django.core.files.base import ContentFile
5+
from django.core.files.storage import default_storage
6+
from django.core.management.base import BaseCommand
7+
from django.utils.text import slugify
8+
9+
from website.models import Organization, Tag
10+
11+
# ANSI escape codes for colors
12+
COLOR_RED = "\033[91m"
13+
COLOR_GREEN = "\033[92m"
14+
COLOR_YELLOW = "\033[93m"
15+
COLOR_BLUE = "\033[94m"
16+
COLOR_RESET = "\033[0m"
17+
18+
logger = logging.getLogger(__name__)
19+
20+
GSoC_API_URL = "https://summerofcode.withgoogle.com/api/program/2025/organizations/"
21+
22+
23+
class Command(BaseCommand):
24+
help = "Fetches organizations from Google Summer of Code and stores them in the database."
25+
26+
def handle(self, *args, **kwargs):
27+
logger.info(f"{COLOR_BLUE}Fetching organizations from GSoC 2025 API...{COLOR_RESET}")
28+
29+
try:
30+
response = requests.get(GSoC_API_URL, headers={"User-Agent": "GSOC-Fetcher/1.0"})
31+
response.raise_for_status()
32+
organizations = response.json()
33+
except requests.RequestException as e:
34+
logger.error(f"{COLOR_RED}Error fetching data from GSoC API: {str(e)}{COLOR_RESET}")
35+
return
36+
37+
for org_data in organizations:
38+
self.process_organization(org_data)
39+
40+
logger.info(f"{COLOR_GREEN}Finished fetching organizations!{COLOR_RESET}")
41+
42+
def process_organization(self, org_data):
43+
data = org_data
44+
slug = slugify(data["slug"])
45+
46+
try:
47+
org, created = Organization.objects.update_or_create(
48+
slug=slug,
49+
defaults={
50+
"name": data["name"],
51+
"description": data.get("description", "")[:500],
52+
"url": data.get("website_url"),
53+
"tagline": data.get("tagline", ""),
54+
"license": data.get("license", ""),
55+
"categories": data.get("categories", []),
56+
"contributor_guidance_url": data.get("contributor_guidance_url", ""),
57+
"tech_tags": data.get("tech_tags", []),
58+
"topic_tags": data.get("topic_tags", []),
59+
"source_code": data.get("website_url"),
60+
"is_active": True,
61+
},
62+
)
63+
64+
# Handle Logo
65+
if data.get("logo_url"):
66+
self.download_logo(data["logo_url"], org, slug)
67+
68+
# Handle Tags (tech_tags + topic_tags)
69+
self.assign_tags(org, data.get("tech_tags", []) + data.get("topic_tags", []))
70+
71+
# Handle Contact Links
72+
self.assign_contacts(org, data.get("contact_links", []))
73+
74+
org.save()
75+
status = "Added" if created else "Updated"
76+
logger.info(f"{COLOR_GREEN}{status}: {data['name']}{COLOR_RESET}")
77+
78+
except Exception as e:
79+
logger.error(f"{COLOR_RED}Failed to save {data['name']}: {str(e)}{COLOR_RESET}")
80+
81+
def download_logo(self, logo_url, org, slug):
82+
"""Downloads and saves the organization’s logo."""
83+
try:
84+
response = requests.get(logo_url)
85+
response.raise_for_status()
86+
87+
logo_path = f"{slug}.png"
88+
if default_storage.exists(logo_path):
89+
default_storage.delete(logo_path)
90+
91+
org.logo.save(logo_path, ContentFile(response.content))
92+
logger.info(f"{COLOR_BLUE}Downloaded logo for {org.name}{COLOR_RESET}")
93+
94+
except requests.RequestException as e:
95+
logger.warning(f"{COLOR_YELLOW}Failed to download logo for {org.name}: {str(e)}{COLOR_RESET}")
96+
97+
def assign_tags(self, org, tags):
98+
"""Assigns tags to an organization."""
99+
for tag_name in tags:
100+
tag_slug = slugify(tag_name)
101+
tag, _ = Tag.objects.get_or_create(slug=tag_slug, defaults={"name": tag_name})
102+
org.tags.add(tag)
103+
104+
def assign_contacts(self, org, contacts):
105+
for contact in contacts:
106+
if contact["name"].lower() == "email":
107+
org.email = contact["value"]
108+
elif contact["name"].lower() == "chat":
109+
org.twitter = contact["value"] # Adjust this if needed
110+
111+
org.save()

website/models.py

+9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from django.contrib.auth.models import User
1515
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
1616
from django.contrib.contenttypes.models import ContentType
17+
from django.contrib.postgres.fields import ArrayField
1718
from django.core.cache import cache
1819
from django.core.exceptions import ValidationError
1920
from django.core.files.base import ContentFile
@@ -135,6 +136,14 @@ class Organization(models.Model):
135136
trademark_count = models.IntegerField(default=0)
136137
trademark_check_date = models.DateTimeField(null=True, blank=True)
137138
team_points = models.IntegerField(default=0)
139+
tagline = models.CharField(max_length=255, blank=True, null=True)
140+
license = models.CharField(max_length=100, blank=True, null=True)
141+
categories = ArrayField(models.CharField(max_length=100), blank=True, default=list)
142+
contributor_guidance_url = models.URLField(blank=True, null=True)
143+
tech_tags = ArrayField(models.CharField(max_length=100), blank=True, default=list)
144+
topic_tags = ArrayField(models.CharField(max_length=100), blank=True, default=list)
145+
source_code = models.URLField(blank=True, null=True)
146+
ideas_link = models.URLField(blank=True, null=True)
138147
type = models.CharField(
139148
max_length=15,
140149
choices=[(tag.value, tag.name) for tag in OrganisationType],

0 commit comments

Comments
 (0)