diff --git a/web/templates/index.html b/web/templates/index.html index 7654bc737..9e2ca9d9e 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -644,21 +644,6 @@

View Waiting Rooms

Browse Waiting Rooms - - -
- -
-

View Contributions

-

- Explore contributions from our open source community. - See top contributors and recently merged pull requests. -

- - View Contributors - -
diff --git a/web/templates/web/contributor_detail.html b/web/templates/web/contributor_detail.html deleted file mode 100644 index a24a42997..000000000 --- a/web/templates/web/contributor_detail.html +++ /dev/null @@ -1,414 +0,0 @@ -{% extends "base.html" %} - -{% block content %} -
- - -

Contributor Details: {{ user.login }}

- -
- -
-
- {{ user.login }} -
-

{{ user.name|default:user.login }}

-

{{ user.bio|default:"No bio available" }}

- - GitHub Profile - - - - -
-
-
- -
-
-
-

Reactions

-

{{ user.reactions_received|default:"0" }}

-
-
-
-
-
-

Followers

-

{{ user.followers|default:"0" }}

-
-
👥
-
-
-
-

Mentorship

-

{{ user.mentorship_score|default:"0" }}

-
-
🤝
-
-
-
-

Collaboration

-

{{ user.collaboration_score|default:"0" }}

-
-
🔗
-
-
-
- -
-

Contribution Analytics

- -
- -
-

Pull Requests

-
- -
-
- -
-

Issues

-
- -
-
- -
-

Comments

-
- -
-
- -
-

Code Contributions

-
- -
-
-
-
- -
-

Recent Activity

-
-
    - -
  • -
    -
    -
    📅
    -
    -
    -
    -

    - First contribution on - {{ first_contribution_date|default:"N/A" }} -

    -
    -
    -
    -
  • - -
  • -
    -
    -
    -
    -
    -
    -

    - Completed - {{ user.issue_assignments|default:"0" }} - issue assignments -

    -
    -
    -
    -
  • - -
-
-
- -
- - - - - -{% endblock content %} diff --git a/web/templates/web/contributors_list.html b/web/templates/web/contributors_list.html deleted file mode 100644 index 8962da2f9..000000000 --- a/web/templates/web/contributors_list.html +++ /dev/null @@ -1,251 +0,0 @@ -{% extends "base.html" %} - -{% block title %} - GitHub Contributors - Alpha One Education -{% endblock title %} -{% block content %} -
- -
-
-

GitHub Contributors

-

- Celebrating the amazing people who contribute to our open source projects. -

-
- - - - - View on GitHub - -
- -
-

- Smart Contributor Ranking -

-

- Our contributor ranking system weighs multiple factors to provide a fair assessment of contribution value: -

-
-
-

- Merged PRs -

-

- Merged pull requests have the highest weight as they represent accepted contributions. -

-
-
-

- Balanced Contributions -

-

- We value contributors who maintain a healthy ratio of merged PRs to total PRs. -

-
-
-

- Quality Factors -

-

- Too many closed (non-merged) or open PRs may indicate quality issues or unfinished work. -

-
-
-
- -
-
-
{{ contributors|length }}
-
Contributors
-
-
-
- {% if contributors %} - {% with total=0 %} - {% for contributor in contributors %} - {% with total=total|add:contributor.merged_pr_count %}{% endwith %} - {% endfor %} - {{ total }} - {% endwith %} - {% else %} - 0 - {% endif %} -
-
Merged PRs
-
-
-
- {% if contributors %} - {% with total=0 %} - {% for contributor in contributors %} - {% with total=total|add:contributor.open_pr_count %}{% endwith %} - {% endfor %} - {{ total }} - {% endwith %} - {% else %} - 0 - {% endif %} -
-
Open PRs
-
-
-
- {% if contributors %} - {% with total=0 %} - {% for contributor in contributors %} - {% with total=total|add:contributor.closed_pr_count %}{% endwith %} - {% endfor %} - {{ total }} - {% endwith %} - {% else %} - 0 - {% endif %} -
-
Closed PRs
-
-
- -
-
-

All Contributors

-

Sorted by contribution quality score

-
-
- {% for contributor in contributors %} -
-
-
- - - -
-

- {{ contributor.username }} -

-
- - - Score: {{ contributor.smart_score|floatformat:1 }} - - - - Ratio: {{ contributor.contribution_ratio|floatformat:2 }} - - - - Details - -
-
-
- - -
-
- {% empty %} -
- - - - -

No contributors found

-

We couldn't retrieve the contributor list at this time.

-

- - - - - Refresh - -

-
- {% endfor %} -
-
- -
-
-

Want to contribute?

-

- Join our community of contributors and help us build the future of education. No contribution is too small! -

- - - - - Browse Open Issues - -
-
-
-{% endblock content %} diff --git a/web/urls.py b/web/urls.py index 3fb4e298a..3d511d255 100644 --- a/web/urls.py +++ b/web/urls.py @@ -482,9 +482,6 @@ path("features/", features_page, name="features"), path("features/vote/", feature_vote, name="feature_vote"), path("features/vote-count/", feature_vote_count, name="feature_vote_count"), - # Contributors - path("contributors/", views.contributors_list_view, name="contributors_list_view"), - path("contributors//", views.contributor_detail_view, name="contributor_detail"), # Membership URLs path("membership/checkout//", views.membership_checkout, name="membership_checkout"), path( diff --git a/web/views.py b/web/views.py index 11b3d81a5..fb20e2fad 100644 --- a/web/views.py +++ b/web/views.py @@ -7619,153 +7619,6 @@ def get_user_contribution_metrics(username, token): return final_result -def contributor_detail_view(request, username): - """ - View to display detailed information about a specific GitHub contributor. - Only accessible to staff members. - """ - cache_key = f"github_contributor_{username}" - cached_data = cache.get(cache_key) - if cached_data: - return render(request, "web/contributor_detail.html", cached_data) - - token = os.environ.get("GITHUB_TOKEN") - headers = {"Authorization": f"token {token}"} if token else {} - - # Initialize variables to store contributor data - user_data = {} - prs_created = 0 - prs_merged = 0 - issues_created = 0 - pr_reviews = 0 - pr_comments = 0 - issue_comments = 0 - lines_added = 0 - lines_deleted = 0 - first_contribution_date = "N/A" - issue_assignments = 0 - - user_endpoint = f"{GITHUB_API_BASE}/users/{username}" - user_data = github_api_request(user_endpoint, headers=headers) - if not user_data: - logger.error("User profile data could not be retrieved.") - - # Pull requests created - prs_created_json = github_api_request( - f"{GITHUB_API_BASE}/search/issues", - params={"q": f"author:{username} type:pr repo:{GITHUB_REPO}"}, - headers=headers, - ) - prs_created = prs_created_json.get("total_count", 0) - - # Pull requests merged - prs_merged_json = github_api_request( - f"{GITHUB_API_BASE}/search/issues", - params={"q": f"author:{username} type:pr repo:{GITHUB_REPO} is:merged"}, - headers=headers, - ) - prs_merged = prs_merged_json.get("total_count", 0) - - # Issues created - issues_json = github_api_request( - f"{GITHUB_API_BASE}/search/issues", - params={"q": f"author:{username} type:issue repo:{GITHUB_REPO}"}, - headers=headers, - ) - issues_created = issues_json.get("total_count", 0) - - # Pull request reviews - reviews_json = github_api_request( - f"{GITHUB_API_BASE}/search/issues", - params={"q": f"reviewer:{username} type:pr repo:{GITHUB_REPO}"}, - headers=headers, - ) - pr_reviews = reviews_json.get("total_count", 0) - - # Pull requests with comments - pr_comments_json = github_api_request( - f"{GITHUB_API_BASE}/search/issues", - params={"q": f"commenter:{username} type:pr repo:{GITHUB_REPO}"}, - headers=headers, - ) - pr_comments = pr_comments_json.get("total_count", 0) - - # Issues with comments - issue_comments_json = github_api_request( - f"{GITHUB_API_BASE}/search/issues", - params={"q": f"commenter:{username} type:issue repo:{GITHUB_REPO}"}, - headers=headers, - ) - issue_comments = issue_comments_json.get("total_count", 0) - - # Oldest PR creation date - prs_oldest = github_api_request( - f"{GITHUB_API_BASE}/search/issues", - params={ - "q": f"author:{username} type:pr repo:{GITHUB_REPO}", - "sort": "created", - "order": "asc", - "per_page": 1, - }, - headers=headers, - ) - if prs_oldest.get("total_count", 0) > 0: - first_contribution_date = prs_oldest["items"][0].get("created_at", "N/A") - - # Issue assignments - issue_assignments_json = github_api_request( - f"{GITHUB_API_BASE}/search/issues", - params={"q": f"assignee:{username} type:issue repo:{GITHUB_REPO}"}, - headers=headers, - ) - issue_assignments = issue_assignments_json.get("total_count", 0) - metrics = get_user_contribution_metrics(username, token) - pr_data = metrics.get("data", {}).get("user", {}).get("pullRequests", {}).get("nodes", []) - for pr in pr_data: - lines_added += pr.get("additions", 0) - lines_deleted += pr.get("deletions", 0) - - # Update user_data with additional metrics - user_data.update( - { - "reactions_received": user_data.get("reactions_received", 0), - "mentorship_score": user_data.get("mentorship_score", 0), - "collaboration_score": user_data.get("collaboration_score", 0), - "issue_assignments": issue_assignments, - } - ) - - # Prepare context for the template - context = { - "user": user_data, - "prs_created": prs_created, - "prs_merged": prs_merged, - "pr_reviews": pr_reviews, - "issues_created": issues_created, - "issue_comments": issue_comments, - "pr_comments": pr_comments, - "lines_added": lines_added, - "lines_deleted": lines_deleted, - "first_contribution_date": first_contribution_date, - "chart_data": { - "prs_created": prs_created, - "prs_merged": prs_merged, - "pr_reviews": pr_reviews, - "issues_created": issues_created, - "issue_assignments": issue_assignments, - "pr_comments": pr_comments, - "issue_comments": issue_comments, - "lines_added": lines_added, - "lines_deleted": lines_deleted, - "first_contribution_date": (first_contribution_date if first_contribution_date != "N/A" else "N/A"), - }, - } - - # Cache for 1 hour - cache.set(cache_key, context, 3600) - return render(request, "web/contributor_detail.html", context) - - @login_required def all_study_groups(request): """Display all study groups across courses.""" @@ -8350,142 +8203,6 @@ def topic_detail(request, pk): return render(request, "web/forum/topic.html", context) -def contributors_list_view(request): - # Check if cached data is available - cached_context = cache.get("contributors_context") - if cached_context: - return render(request, "web/contributors_list.html", cached_context) - - # Initialize a dictionary to track contributor stats - contributor_stats = {} - - # Function to add a contributor to our stats dictionary - def add_contributor(username, avatar_url, profile_url): - if username not in contributor_stats: - contributor_stats[username] = { - "username": username, - "avatar_url": avatar_url, - "profile_url": profile_url, - "merged_pr_count": 0, - "closed_pr_count": 0, - "open_pr_count": 0, - "total_pr_count": 0, - "prs_url": f"https://github.com/AlphaOneLabs/education-website/pulls?q=is:pr+author:{username}", - } - - try: - # Fetch closed PRs first (includes both merged and non-merged closed PRs) - closed_prs = [] - for page in range(1, 11): # Limit to 10 pages to prevent hitting API rate limits - response = github_api_request( - f"{GITHUB_API_BASE}/repos/AlphaOneLabs/education-website/pulls", - params={"state": "closed", "per_page": 100, "page": page}, - ) - if not response or len(response) == 0: - break - - closed_prs.extend(response) - time.sleep(0.5) # Add delay to avoid hitting rate limits - - # Process closed PRs - for pr in closed_prs: - username = pr["user"]["login"] - - # Skip bots and specific users - if "[bot]" in username or "dependabot" in username or username == "A1L13N": - continue - - avatar_url = pr["user"]["avatar_url"] - profile_url = pr["user"]["html_url"] - - # Add to our tracking - add_contributor(username, avatar_url, profile_url) - - # Update the appropriate count based on whether it was merged - if pr["merged_at"]: - contributor_stats[username]["merged_pr_count"] += 1 - else: - contributor_stats[username]["closed_pr_count"] += 1 - - # Now fetch open PRs - open_prs = [] - for page in range(1, 6): # Limit to 5 pages for open PRs - response = github_api_request( - f"{GITHUB_API_BASE}/repos/AlphaOneLabs/education-website/pulls", - params={"state": "open", "per_page": 100, "page": page}, - ) - if not response or len(response) == 0: - break - - open_prs.extend(response) - time.sleep(0.5) # Add delay to avoid hitting rate limits - - # Process open PRs - for pr in open_prs: - username = pr["user"]["login"] - - # Skip bots and specific users - if "[bot]" in username or "dependabot" in username or username == "A1L13N": - continue - - avatar_url = pr["user"]["avatar_url"] - profile_url = pr["user"]["html_url"] - - # Add to our tracking - add_contributor(username, avatar_url, profile_url) - - # Update open PR count - contributor_stats[username]["open_pr_count"] += 1 - - # Calculate total PR count and filter out users with no merged PRs - contributors = [] - for username, stats in contributor_stats.items(): - # Skip contributors with no merged PRs - if stats["merged_pr_count"] == 0: - continue - - # Calculate total PR count - stats["total_pr_count"] = stats["merged_pr_count"] + stats["closed_pr_count"] + stats["open_pr_count"] - - # Calculate a smart score that prioritizes merged PRs but penalizes imbalances - # Formula: (merged_pr_count * 10) - penalties for imbalanced contributions - smart_score = stats["merged_pr_count"] * 10 - - # Penalize if closed PRs are more than half of merged PRs (could indicate issues with code quality) - if stats["closed_pr_count"] > (stats["merged_pr_count"] / 2): - smart_score -= (stats["closed_pr_count"] - (stats["merged_pr_count"] / 2)) * 2 - - # Penalize if open PRs are more than merged PRs (could indicate abandonment issues) - if stats["open_pr_count"] > stats["merged_pr_count"]: - smart_score -= stats["open_pr_count"] - stats["merged_pr_count"] - - # Calculate a contribution ratio: merged/(total) - higher is better - if stats["total_pr_count"] > 0: - stats["contribution_ratio"] = stats["merged_pr_count"] / stats["total_pr_count"] - else: - stats["contribution_ratio"] = 0 - - # Store the smart score - stats["smart_score"] = smart_score - - contributors.append(stats) - - # Sort by smart score (primary) and then by merged PR count (secondary) - contributors.sort(key=lambda x: (x["smart_score"], x["merged_pr_count"]), reverse=True) - - # Store the context in cache for 12 hours - context = {"contributors": contributors} - cache.set("contributors_context", context, 12 * 60 * 60) - - return render(request, "web/contributors_list.html", context) - - except Exception as e: - # Log the error - print(f"Error fetching contributors: {e}") - # Return an empty list in case of error - return render(request, "web/contributors_list.html", {"contributors": []}) - - @login_required def video_request_list(request): """View for listing video requests with optional category filtering."""