diff --git a/estimation/app/templates/base.html b/estimation/app/templates/base.html index 3b41e40..776e571 100644 --- a/estimation/app/templates/base.html +++ b/estimation/app/templates/base.html @@ -1,43 +1,62 @@ -{% load static %} - + {% load static %} + - + - - + + {% block title %} {{ title }} {% endblock title %} - - - -
-
- {% if user.is_authenticated %} - Logout - - - {% else %} - Login with GitHub + + + +
+
+ +

GitHub Async Estimation Tool

+ {% if user.handle %} + Logout + + {{ user.handle }}@github {% endif %} +
+
+
+
+ +
+ {% block content %} + {% endblock content %} +
-
-
- -
- {% block content %} {% endblock content %} +
+
+
DDS Hackathon 2024
+
-
- + diff --git a/estimation/app/templates/dashboard.html b/estimation/app/templates/dashboard.html index bf13d25..fe50f17 100644 --- a/estimation/app/templates/dashboard.html +++ b/estimation/app/templates/dashboard.html @@ -1,5 +1,46 @@ - -
- Profile Picture - -
\ No newline at end of file +{% extends "base.html" %} + +{% load static %} + +{% block title %} GitHub Async Estimation Tool {% endblock %} + + +{% block content %} +
+
+
+ Profile Picture +

Issues awaiting votes for {{ user.handle }}@github:

+
+
+
+
+ +
+
+
+ {% for estimation_session in estimation_sessions %} +
+
+
+

+ Issue + {{estimation_session.issue.repo}}/#{{estimation_session.issue.issue_id}} +

+

this is a title

+
+
+
+ {% endfor %} +
+
+{% endblock %} diff --git a/estimation/app/templates/index.html b/estimation/app/templates/index.html index e24fc8f..27f34af 100644 --- a/estimation/app/templates/index.html +++ b/estimation/app/templates/index.html @@ -7,10 +7,10 @@ {% block content %} {% endblock %} diff --git a/estimation/app/urls.py b/estimation/app/urls.py index 4c61ce9..d5cc9cb 100644 --- a/estimation/app/urls.py +++ b/estimation/app/urls.py @@ -1,8 +1,10 @@ from django.urls import path from . import views -urlpatterns = [path("", views.index, name="index"), - path('github/login/', views.github_login, name='github_login'), - path('github/callback/', views.github_callback, name='github_callback'), - path('dashboard/', views.dashboard, name='dashboard'), - ] + +urlpatterns = [ + path("", views.index, name="index"), + path("github/login/", views.github_login, name="github_login"), + path("github/callback/", views.github_callback, name="github_callback"), + path("dashboard/", views.dashboard, name="dashboard"), +] diff --git a/estimation/app/view_models/__init__.py b/estimation/app/view_models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/estimation/app/view_models/base_view_model.py b/estimation/app/view_models/base_view_model.py new file mode 100644 index 0000000..5fb015d --- /dev/null +++ b/estimation/app/view_models/base_view_model.py @@ -0,0 +1,7 @@ +from typing import TypedDict + +from ..models import GithubUser + + +class BaseViewModel(TypedDict): + user: GithubUser diff --git a/estimation/app/view_models/dashboard_view_model.py b/estimation/app/view_models/dashboard_view_model.py new file mode 100644 index 0000000..13a7c14 --- /dev/null +++ b/estimation/app/view_models/dashboard_view_model.py @@ -0,0 +1,8 @@ +from typing import List + +from ..models import EstimationSession +from ..view_models.base_view_model import BaseViewModel + + +class DashboardViewModel(BaseViewModel): + estimation_sessions: List[EstimationSession] diff --git a/estimation/app/view_models/index_view_model.py b/estimation/app/view_models/index_view_model.py new file mode 100644 index 0000000..7193c07 --- /dev/null +++ b/estimation/app/view_models/index_view_model.py @@ -0,0 +1,5 @@ +from typing import TypedDict + + +class IndexViewModel(TypedDict): + pass diff --git a/estimation/app/views.py b/estimation/app/views.py index e94b127..212b574 100644 --- a/estimation/app/views.py +++ b/estimation/app/views.py @@ -1,76 +1,97 @@ import requests -from django.http import HttpRequest, JsonResponse +from django.http import HttpRequest from django.shortcuts import render, redirect -from app.models import GithubUser +from app.models import EstimationSession, GithubIssue, GithubUser from estimation import settings -import re + + +from .view_models.dashboard_view_model import DashboardViewModel +from .view_models.index_view_model import IndexViewModel def index(request: HttpRequest): - return render(request, "index.html", {}) + return render(request, "index.html", IndexViewModel()) def dashboard(request): - avatar_url = request.session.get('avatar_url') - github_handle = request.session.get('github_handle') + avatar_url = request.session.get("avatar_url") + github_handle = request.session.get("github_handle") # Clear session variables if necessary - request.session.pop('avatar_url', None) - request.session.pop('github_handle', None) - - return render(request, 'dashboard.html', { - 'avatar_url': avatar_url, - 'github_handle': github_handle - }) + request.session.pop("avatar_url", None) + request.session.pop("github_handle", None) + + sample_estimation_sessions = [ + EstimationSession( + issue=GithubIssue(org="bcgov", repo="cas-estimation-tool", issue_id=1), + is_open=True, + ), + EstimationSession( + issue=GithubIssue(org="bcgov", repo="cas-estimation-tool", issue_id=155), + is_open=True, + ), + EstimationSession( + issue=GithubIssue(org="bcgov", repo="cas-estimation-tool", issue_id=65554), + is_open=False, + ), + ] + + return render( + request, + "dashboard.html", + DashboardViewModel( + estimation_sessions=sample_estimation_sessions, + user=GithubUser(handle=github_handle, avatar_url=avatar_url), + ), + ) def github_login(request): # GitHub OAuth authorization URL github_auth_url = ( - 'https://github.com/login/oauth/authorize?' - f'client_id={settings.GITHUB_CLIENT_ID}&' - f'redirect_uri={settings.GITHUB_REDIRECT_URI}&' - 'scope=repo' + "https://github.com/login/oauth/authorize?" + f"client_id={settings.GITHUB_CLIENT_ID}&" + f"redirect_uri={settings.GITHUB_REDIRECT_URI}&" + "scope=repo" ) return redirect(github_auth_url) def github_callback(request): - code = request.GET.get('code') + code = request.GET.get("code") if not code: - return redirect('index') # Redirect to the main page if no code is present + return redirect("index") # Redirect to the main page if no code is present # Exchange the authorization code for an access token - token_url = 'https://github.com/login/oauth/access_token' + token_url = "https://github.com/login/oauth/access_token" payload = { - 'client_id': settings.GITHUB_CLIENT_ID, - 'client_secret': settings.GITHUB_CLIENT_SECRET, - 'code': code, - 'redirect_uri': settings.GITHUB_REDIRECT_URI, + "client_id": settings.GITHUB_CLIENT_ID, + "client_secret": settings.GITHUB_CLIENT_SECRET, + "code": code, + "redirect_uri": settings.GITHUB_REDIRECT_URI, } - headers = {'Accept': 'application/json'} + headers = {"Accept": "application/json"} response = requests.post(token_url, data=payload, headers=headers) response_data = response.json() - access_token = response_data.get('access_token') + access_token = response_data.get("access_token") if not access_token: - return redirect('index') # Handle the case where token is not retrieved + return redirect("index") # Handle the case where token is not retrieved # Get user information from GitHub - user_info_url = 'https://api.github.com/user' - headers = {'Authorization': f'token {access_token}'} + user_info_url = "https://api.github.com/user" + headers = {"Authorization": f"token {access_token}"} user_info_response = requests.get(user_info_url, headers=headers) user_info = user_info_response.json() - github_handle = user_info.get('login') - avatar_url = user_info.get('avatar_url') + github_handle = user_info.get("login") + avatar_url = user_info.get("avatar_url") if github_handle: # Check if the user already exists in the database github_user, created = GithubUser.objects.get_or_create( - handle=github_handle, - defaults={'access_token': access_token} + handle=github_handle, defaults={"access_token": access_token} ) if not created: @@ -82,19 +103,23 @@ def github_callback(request): print(user_info) # Optional: You can log user info for debugging # Example values for demonstration purposes - project_url = 'https://github.com/users/ayeshmcg/projects/1' - issue_url = 'https://github.com/ayeshmcg/testRepo/issues/1' + project_url = "https://github.com/users/ayeshmcg/projects/1" + issue_url = "https://github.com/ayeshmcg/testRepo/issues/1" story_points = 5 - result = update_story_points_for_issue_card(project_url, issue_url, story_points, access_token) + result = update_story_points_for_issue_card( + project_url, issue_url, story_points, access_token + ) print(result) # Log the result for debugging - request.session['avatar_url'] = avatar_url - request.session['github_handle'] = github_handle + request.session["avatar_url"] = avatar_url + request.session["github_handle"] = github_handle - return redirect('dashboard') + return redirect("dashboard") -def update_story_points_for_issue_card(project_url, issue_url, story_points, access_token): +def update_story_points_for_issue_card( + project_url, issue_url, story_points, access_token +): # Extract project ID from the URL # project_match = re.match(r'https://github.com/orgs/[^/]+/projects/(\d+)', project_url) # if not project_match: @@ -110,14 +135,16 @@ def update_story_points_for_issue_card(project_url, issue_url, story_points, acc # issue_number = issue_match.group(1) # Retrieve the project columns - columns_url = f'https://api.github.com/projects/1/columns' + columns_url = f"https://api.github.com/projects/1/columns" headers = { - 'Authorization': f'token {access_token}', - 'Accept': 'application/vnd.github+json' + "Authorization": f"token {access_token}", + "Accept": "application/vnd.github+json", } columns_response = requests.get(columns_url, headers=headers) if columns_response.status_code != 200: - return {'error': f'Unable to retrieve columns: {columns_response.status_code}, {columns_response.text}'} + return { + "error": f"Unable to retrieve columns: {columns_response.status_code}, {columns_response.text}" + } columns = columns_response.json() @@ -127,29 +154,33 @@ def update_story_points_for_issue_card(project_url, issue_url, story_points, acc cards_url = f'https://api.github.com/projects/columns/{column["id"]}/cards' cards_response = requests.get(cards_url, headers=headers) if cards_response.status_code != 200: - return {'error': f'Unable to retrieve cards: {cards_response.status_code}, {cards_response.text}'} + return { + "error": f"Unable to retrieve cards: {cards_response.status_code}, {cards_response.text}" + } cards = cards_response.json() for card in cards: - if card.get('content_url') == issue_url: - card_id = card['id'] + if card.get("content_url") == issue_url: + card_id = card["id"] break if card_id: break if not card_id: - return {'error': 'No card found for the specified issue URL'} + return {"error": "No card found for the specified issue URL"} # Update the card with Story Points - card_url = f'https://api.github.com/projects/columns/cards/{card_id}' + card_url = f"https://api.github.com/projects/columns/cards/{card_id}" card_response = requests.get(card_url, headers=headers) if card_response.status_code != 200: - return {'error': f'Unable to retrieve card details: {card_response.status_code}, {card_response.text}'} + return { + "error": f"Unable to retrieve card details: {card_response.status_code}, {card_response.text}" + } card_data = card_response.json() - print('card_data', card_data) - print('story_points', story_points) + print("card_data", card_data) + print("story_points", story_points) # If the card is a note card, append the story points # if 'note' in card_data: diff --git a/estimation/estimation/urls.py b/estimation/estimation/urls.py index 321e2a3..d00c527 100644 --- a/estimation/estimation/urls.py +++ b/estimation/estimation/urls.py @@ -18,10 +18,7 @@ from django.contrib import admin from django.urls import include, path -from app import views - urlpatterns = [ - path("app/", include("app.urls")), - path("admin/", views.index), - # path("admin/", admin.site.urls), + path("", include("app.urls")), + path("admin/", admin.site.urls), ]