Skip to content

Commit 9c555c8

Browse files
committed
Update code
1 parent b787163 commit 9c555c8

10 files changed

+119
-77
lines changed

backend/apps/owasp/admin.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,13 @@ def custom_field_name(self, obj) -> str:
166166

167167
class ProjectHealthMetricsAdmin(admin.ModelAdmin):
168168
autocomplete_fields = ("project",)
169-
list_filter = ("project__level",)
169+
list_filter = (
170+
"project__level",
171+
"nest_created_at",
172+
)
170173
list_display = (
171174
"project",
175+
"nest_created_at",
172176
"score",
173177
"contributors_count",
174178
"stars_count",

backend/apps/owasp/management/commands/owasp_update_project_health_metrics_scores.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,14 @@ def handle(self, *args, **options):
4747
)
4848

4949
requirements = project_health_requirements[metric.project.level]
50+
5051
score = 0.0
5152
for field, weight in forward_fields.items():
52-
metric_value = getattr(metric, field)
53-
if field in [
54-
"is_funding_requirements_compliant",
55-
"is_leader_requirements_compliant",
56-
]:
57-
if metric_value:
58-
score += weight
59-
elif metric_value >= getattr(requirements, field):
53+
if int(getattr(metric, field)) >= int(getattr(requirements, field)):
6054
score += weight
55+
6156
for field, weight in backward_fields.items():
62-
if getattr(metric, field) <= getattr(requirements, field):
57+
if int(getattr(metric, field)) <= int(getattr(requirements, field)):
6358
score += weight
6459

6560
metric.score = score

backend/apps/owasp/management/commands/owasp_update_project_health_requirements.py

Lines changed: 39 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ class Command(BaseCommand):
1414
"age_days": 15,
1515
"contributors_count": 1,
1616
"forks_count": 2,
17+
"is_funding_requirements_compliant": True,
18+
"is_leader_requirements_compliant": False,
1719
"last_commit_days": 365,
1820
"last_pull_request_days": 60,
1921
"last_release_days": 365,
@@ -32,6 +34,8 @@ class Command(BaseCommand):
3234
"age_days": 20,
3335
"contributors_count": 3,
3436
"forks_count": 5,
37+
"is_funding_requirements_compliant": True,
38+
"is_leader_requirements_compliant": True,
3539
"last_commit_days": 270,
3640
"last_pull_request_days": 45,
3741
"last_release_days": 365,
@@ -50,6 +54,8 @@ class Command(BaseCommand):
5054
"age_days": 30,
5155
"contributors_count": 4,
5256
"forks_count": 7,
57+
"is_funding_requirements_compliant": True,
58+
"is_leader_requirements_compliant": True,
5359
"last_commit_days": 90,
5460
"last_pull_request_days": 30,
5561
"last_release_days": 180,
@@ -68,6 +74,8 @@ class Command(BaseCommand):
6874
"age_days": 30,
6975
"contributors_count": 5,
7076
"forks_count": 10,
77+
"is_funding_requirements_compliant": True,
78+
"is_leader_requirements_compliant": True,
7179
"last_commit_days": 180,
7280
"last_pull_request_days": 30,
7381
"last_release_days": 365,
@@ -84,59 +92,41 @@ class Command(BaseCommand):
8492
},
8593
}
8694

87-
def add_arguments(self, parser) -> None:
88-
parser.add_argument(
89-
"--level",
90-
type=str,
91-
choices=[level[0] for level in Project.ProjectLevel.choices],
92-
help="Project level to set requirements for",
93-
)
94-
9595
def get_level_requirements(self, level):
9696
"""Get default requirements based on project level."""
97-
defaults = {
98-
"age_days": 0,
99-
"contributors_count": 0,
100-
"forks_count": 0,
101-
"last_commit_days": 0,
102-
"last_pull_request_days": 0,
103-
"last_release_days": 0,
104-
"open_issues_count": 0,
105-
"open_pull_requests_count": 0,
106-
"owasp_page_last_update_days": 0,
107-
"recent_releases_count": 0,
108-
"recent_releases_time_window_days": 0,
109-
"stars_count": 0,
110-
"total_pull_requests_count": 0,
111-
"total_releases_count": 0,
112-
"unanswered_issues_count": 0,
113-
"unassigned_issues_count": 0,
114-
}
115-
116-
return self.LEVEL_REQUIREMENTS.get(level, defaults)
97+
return self.LEVEL_REQUIREMENTS.get(
98+
level,
99+
{
100+
"age_days": 0,
101+
"contributors_count": 0,
102+
"forks_count": 0,
103+
"is_funding_requirements_compliant": True,
104+
"is_leader_requirements_compliant": True,
105+
"last_commit_days": 0,
106+
"last_pull_request_days": 0,
107+
"last_release_days": 0,
108+
"open_issues_count": 0,
109+
"open_pull_requests_count": 0,
110+
"owasp_page_last_update_days": 0,
111+
"recent_releases_count": 0,
112+
"recent_releases_time_window_days": 0,
113+
"stars_count": 0,
114+
"total_pull_requests_count": 0,
115+
"total_releases_count": 0,
116+
"unanswered_issues_count": 0,
117+
"unassigned_issues_count": 0,
118+
},
119+
)
117120

118121
def handle(self, *args, **options) -> None:
119122
"""Handle the command execution."""
120-
level = options.get("level")
121-
122-
if level:
123-
defaults = self.get_level_requirements(level)
124-
requirements, created = ProjectHealthRequirements.objects.get_or_create(
125-
level=level, defaults=defaults
123+
for level_code, level_name in sorted(Project.ProjectLevel.choices):
124+
_, created = ProjectHealthRequirements.objects.update_or_create(
125+
level=level_code,
126+
defaults=self.get_level_requirements(level_code),
126127
)
127128

128-
action = "Created" if created else "Updated"
129-
print(f"{action} health requirements for {requirements.get_level_display()} projects")
130-
else:
131-
for level_choice in Project.ProjectLevel.choices:
132-
level_code = level_choice[0]
133-
defaults = self.get_level_requirements(level_code)
134-
135-
requirements, created = ProjectHealthRequirements.objects.get_or_create(
136-
level=level_code, defaults=defaults
137-
)
138-
139-
if created:
140-
print(f"Created default health requirements for {level_choice[1]} projects")
141-
else:
142-
print(f"Health requirements already exist for {level_choice[1]} projects")
129+
print(
130+
f"{'Created' if created else 'Updated'} health requirements for "
131+
f"{level_name} projects"
132+
)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Generated by Django 5.2.2 on 2025-06-14 17:35
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
dependencies = [
8+
("owasp", "0040_alter_projecthealthmetrics_is_leader_requirements_compliant"),
9+
]
10+
11+
operations = [
12+
migrations.AddField(
13+
model_name="projecthealthrequirements",
14+
name="is_funding_requirements_compliant",
15+
field=models.BooleanField(
16+
default=True, verbose_name="Is funding requirements compliant"
17+
),
18+
),
19+
migrations.AddField(
20+
model_name="projecthealthrequirements",
21+
name="is_leader_requirements_compliant",
22+
field=models.BooleanField(
23+
default=True, verbose_name="Is leader requirements compliant"
24+
),
25+
),
26+
]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Generated by Django 5.2.2 on 2025-06-14 18:08
2+
3+
import django.core.validators
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
dependencies = [
9+
("owasp", "0041_projecthealthrequirements_is_funding_requirements_compliant_and_more"),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name="projecthealthmetrics",
15+
name="score",
16+
field=models.FloatField(
17+
blank=True,
18+
help_text="0-100",
19+
null=True,
20+
validators=[
21+
django.core.validators.MinValueValidator(0.0),
22+
django.core.validators.MaxValueValidator(100.0),
23+
],
24+
verbose_name="Project health score",
25+
),
26+
),
27+
]

backend/apps/owasp/models/project.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,7 @@ def open_pull_requests_count(self) -> int:
205205
@property
206206
def owasp_page_last_updated_at(self) -> datetime.datetime | None:
207207
"""Return the last updated date of the OWASP page."""
208-
if owasp_repository := self.owasp_repository:
209-
return owasp_repository.updated_at
210-
return None
208+
return self.owasp_repository.updated_at if self.owasp_repository else None
211209

212210
@property
213211
def pull_requests(self):

backend/apps/owasp/models/project_health_metrics.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,12 @@ class Meta:
4444
verbose_name="Pull request last created at", blank=True, null=True
4545
)
4646
recent_releases_count = models.PositiveIntegerField(verbose_name="Recent releases", default=0)
47-
# score of projects health between 0 and 100(float value)
4847
score = models.FloatField(
48+
blank=True,
4949
null=True,
50+
verbose_name="Project health score",
5051
validators=[MinValueValidator(0.0), MaxValueValidator(100.0)],
51-
help_text="Project health score (0-100)",
52+
help_text="0-100",
5253
)
5354
stars_count = models.PositiveIntegerField(verbose_name="Stars", default=0)
5455
total_issues_count = models.PositiveIntegerField(verbose_name="Total issues", default=0)
@@ -63,6 +64,10 @@ class Meta:
6364
verbose_name="Unassigned issues", default=0
6465
)
6566

67+
def __str__(self) -> str:
68+
"""Project health metrics human readable representation."""
69+
return f"Health Metrics for {self.project.name}"
70+
6671
@property
6772
def age_days(self) -> int:
6873
"""Calculate project age in days."""
@@ -106,7 +111,3 @@ def bulk_save(metrics: list, fields: list | None = None) -> None: # type: ignor
106111
107112
"""
108113
BulkSaveModel.bulk_save(ProjectHealthMetrics, metrics, fields=fields)
109-
110-
def __str__(self) -> str:
111-
"""Project health metrics human readable representation."""
112-
return f"Health Metrics for {self.project.name}"

backend/apps/owasp/models/project_health_requirements.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ class Meta:
2424
age_days = models.PositiveIntegerField(verbose_name="Project age (days)", default=0)
2525
contributors_count = models.PositiveIntegerField(verbose_name="Contributors", default=0)
2626
forks_count = models.PositiveIntegerField(verbose_name="Forks", default=0)
27+
is_funding_requirements_compliant = models.BooleanField(
28+
verbose_name="Is funding requirements compliant", default=True
29+
)
30+
is_leader_requirements_compliant = models.BooleanField(
31+
verbose_name="Is leader requirements compliant", default=True
32+
)
2733
last_release_days = models.PositiveIntegerField(
2834
verbose_name="Days since last release", default=0
2935
)

backend/tests/apps/owasp/management/commands/owasp_update_project_health_requirements_test.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,27 +35,23 @@ def _setup(self):
3535
"Created health requirements for Incubator projects",
3636
"Incubator",
3737
),
38-
(None, "Created default health requirements for Flagship projects", "Flagship"),
3938
],
4039
)
4140
def test_handle_successful_creation(self, level, expected_output, display_name):
4241
"""Test successful requirements creation."""
4342
mock_requirements = MagicMock(spec=ProjectHealthRequirements)
4443
mock_requirements.get_level_display.return_value = display_name
45-
self.mock_requirements.get_or_create.return_value = (mock_requirements, True)
44+
self.mock_requirements.update_or_create.return_value = (mock_requirements, True)
4645

4746
with patch("sys.stdout", new=StringIO()) as fake_out:
48-
if level:
49-
call_command("owasp_update_project_health_requirements", level=level)
50-
else:
51-
call_command("owasp_update_project_health_requirements")
47+
call_command("owasp_update_project_health_requirements")
5248

53-
assert expected_output in fake_out.getvalue()
49+
assert expected_output in fake_out.getvalue()
5450

5551
def test_handle_exception(self):
5652
"""Test handling of exceptions during update."""
5753
error_message = "Database error"
58-
self.mock_requirements.get_or_create.side_effect = CommandError(error_message)
54+
self.mock_requirements.update_or_create.side_effect = CommandError(error_message)
5955

6056
with pytest.raises(CommandError, match=error_message) as exc_info:
6157
call_command("owasp_update_project_health_requirements")

backend/tests/apps/owasp/models/project_health_metrics_test.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ def test_str_representation(self, mock_project, project_name, expected):
4444
(MIN_SCORE, True),
4545
(MAX_SCORE + 0.1, False),
4646
(MIN_SCORE - 10.0, False),
47-
(None, False),
4847
],
4948
)
5049
def test_score_validation(self, score, is_valid):

0 commit comments

Comments
 (0)