@@ -19,11 +19,21 @@ def handle(self, *args, **kwargs) -> None:
19
19
"""Handle the command execution."""
20
20
self .stdout .write ("Syncing OWASP awards..." )
21
21
22
- data = yaml .safe_load (
23
- get_repository_file_content (
24
- "https://raw.githubusercontent.com/OWASP/owasp.github.io/main/_data/awards.yml"
22
+ url = "https://raw.githubusercontent.com/OWASP/owasp.github.io/main/_data/awards.yml"
23
+ raw = get_repository_file_content (url )
24
+ if not raw :
25
+ self .stderr .write (self .style .WARNING ("No awards data fetched; aborting." ))
26
+ return
27
+ try :
28
+ data = yaml .safe_load (raw ) or []
29
+ except yaml .YAMLError as e :
30
+ self .stderr .write (self .style .ERROR (f"Failed to parse awards YAML: { e } " ))
31
+ return
32
+ if not isinstance (data , list ):
33
+ self .stderr .write (
34
+ self .style .WARNING ("Unexpected awards YAML structure; expected a list." )
25
35
)
26
- )
36
+ return
27
37
28
38
awards_to_save = []
29
39
for item in data :
@@ -34,40 +44,59 @@ def handle(self, *args, **kwargs) -> None:
34
44
if award :
35
45
awards_to_save .append (award )
36
46
37
- Award .bulk_save (awards_to_save )
47
+ Award .bulk_save (awards_to_save , fields = ( "category" , "description" , "year" , "user" ) )
38
48
self .stdout .write (self .style .SUCCESS (f"Successfully synced { len (awards_to_save )} awards" ))
39
49
40
50
def _create_or_update_award (self , award_data , winner_data ):
41
51
"""Create or update award instance."""
42
- name = f"{ award_data ['title' ]} - { winner_data ['name' ]} ({ award_data ['year' ]} )"
52
+ # Safely extract values with defaults
53
+ title = award_data .get ("title" , "" )
54
+ year = award_data .get ("year" , 0 )
55
+ category = award_data .get ("category" , "" )
56
+
57
+ # Handle winner_data being string or dict
58
+ if isinstance (winner_data , str ):
59
+ winner_name = winner_data
60
+ winner_info = ""
61
+ else :
62
+ winner_name = winner_data .get ("name" , "" )
63
+ winner_info = winner_data .get ("info" , "" )
64
+
65
+ name = f"{ title } - { winner_name } ({ year } )"
43
66
44
67
try :
45
68
award = Award .objects .get (name = name )
46
69
except Award .DoesNotExist :
47
70
award = Award (name = name )
48
71
49
- award .category = award_data . get ( " category" , "" )
50
- award .description = winner_data . get ( "info" , "" )
51
- award .year = award_data . get ( " year" , 0 )
72
+ award .category = category
73
+ award .description = winner_info
74
+ award .year = year
52
75
53
- # Try to match user by name
54
- user = self ._match_user (winner_data ["name" ])
55
- if user :
56
- award .user = user
57
- else :
58
- logger .warning ("Could not match user for award winner: %s" , winner_data ["name" ])
76
+ # Only set user if not already reviewed
77
+ if not (award .user and award .is_reviewed ):
78
+ user = self ._match_user (winner_name )
79
+ if user :
80
+ award .user = user
81
+ else :
82
+ logger .warning ("Could not match user for award winner: %s" , winner_name )
59
83
60
84
return award
61
85
62
86
def _match_user (self , winner_name ):
63
87
"""Try to match award winner with existing user."""
64
- # Try exact name match first
65
- user = User .objects .filter (name__iexact = winner_name ).first ()
66
- if user :
67
- return user
88
+ winner_name = winner_name .strip ()
89
+
90
+ # Check if it looks like a GitHub handle
91
+ if winner_name .startswith ("@" ) or (" " not in winner_name and winner_name ):
92
+ # Strip leading @ and try login match first
93
+ login_name = winner_name .lstrip ("@" )
94
+ user = User .objects .filter (login__iexact = login_name ).first ()
95
+ if user :
96
+ return user
68
97
69
- # Try login match (GitHub username)
70
- user = User .objects .filter (login__iexact = winner_name ).first ()
98
+ # Try exact name match
99
+ user = User .objects .filter (name__iexact = winner_name ).first ()
71
100
if user :
72
101
return user
73
102
0 commit comments