Skip to content

Commit

Permalink
Merge pull request #5 from bcgov/loginMechanism
Browse files Browse the repository at this point in the history
chore:Added login
  • Loading branch information
ayeshmcg authored Sep 18, 2024
2 parents 5d23c77 + 0c7f86a commit de134f0
Show file tree
Hide file tree
Showing 9 changed files with 253 additions and 34 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Generated by Django 5.1.1 on 2024-09-18 06:25

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("app", "0001_initial"),
]

operations = [
migrations.AddField(
model_name="githubuser",
name="access_token",
field=models.CharField(
blank=True,
db_comment="GitHub access token for OAuth authentication.",
max_length=255,
null=True,
),
),
migrations.AddField(
model_name="githubuser",
name="avatar_url",
field=models.URLField(blank=True, null=True),
),
]
14 changes: 14 additions & 0 deletions estimation/app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ class GithubUser(models.Model):
max_length=1000,
db_comment="The github handle for the user, without the '@github' part.",
)
access_token = models.CharField(
max_length=255,
blank=True,
null=True,
db_comment="GitHub access token for OAuth authentication."
)

avatar_url = models.URLField(blank=True, null=True)


def __str__(self):
return self.handle




class GithubIssue(models.Model):
Expand Down
53 changes: 25 additions & 28 deletions estimation/app/templates/base.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
{% load static %}
<head>
{% load static %}
<head>
<!-- <link rel="icon" href="{% static 'img/favicon.ico' %}"> -->
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="{% static 'styles/w3.css' %}" type="text/css" />
Expand All @@ -13,34 +13,31 @@
<link rel="stylesheet" href="{% static 'styles/BCSans.css' %}" type="text/css" />
<link rel="stylesheet" href="{% static 'styles/style.css' %}" type="text/css" />
<title>{% block title %} {{ title }} {% endblock title %}</title>
</head>
<body>
<!-- Top Navigation -->
<div class="w3-top">
<div class="w3-bar w3-row" style="height: 50px">
<img src={% static 'img/bc_logo.png' %} style="height: 48px" class="w3-left"/>
<div class="w3-left w3-margin-left"><h4 style="font-weight: bold">GitHub Async Estimation Tool</h4></div>
{% if user.handle %}
<a
{% comment %} href="{% url 'github:logout' %}" {% endcomment %}
class="w3-bar-item w3-border-right w3-button w3-right"
>Logout
</a>
<button class="w3-button">{{ user.handle }}@github</button>
</head>
<body>
<!-- Top Navigation -->
<div class="w3-top">
<div class="w3-bar w3-theme-light w3-border">
{% if user.is_authenticated %}
<a
href="{% url 'logout' %}"
class="w3-bar-item w3-border-right w3-button"
>Logout
</a>
<button class="w3-button">Welcome, {{ user.username }}!</button>
{% else %}
<a
href="{% url 'github_login' %}"
class="w3-bar-item w3-border-right w3-button"
>Login with GitHub</a>
{% endif %}
</div>
<div class="w3-bar w3-theme w3-border" style="height: 5px">
</div>
<div class="w3-main">
<!-- Body -->
<div class="w3-container w3-responsive w3-text-theme">
</div>
<div class="w3-main">
<!-- Body -->
<div class="w3-container w3-responsive w3-text-theme">
{% block content %} {% endblock content %}
</div>
</div>
<div class="w3-bottom">
<div class="w3-bar w3-row w3-theme w3-border w3-white" style="height: 55px">
<div class="w3-left">DDS Hackathon 2024</div>
</div>
</div>
</body>
</div>
</body>
</html>
5 changes: 5 additions & 0 deletions estimation/app/templates/dashboard.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<!-- dashboard.html -->
<div class="w3-bar-item">
<img src="{{ avatar_url }}" alt="Profile Picture" class="w3-circle" style="width: 50px; height: 50px; border-radius:50% ">
<label class="w3-button">Welcome, {{ github_handle }}!</label>
</div>
6 changes: 5 additions & 1 deletion estimation/app/urls.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
from django.urls import path
from . import views

urlpatterns = [path("", views.index, name="index")]
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'),
]
165 changes: 161 additions & 4 deletions estimation/app/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,165 @@
from django.http import HttpRequest
from django.shortcuts import render

# Create your views here.
import requests
from django.http import HttpRequest, JsonResponse
from django.shortcuts import render, redirect
from app.models import GithubUser
from estimation import settings
import re


def index(request: HttpRequest):
return render(request, "index.html", {})


def dashboard(request):
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
})


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'
)
return redirect(github_auth_url)


def github_callback(request):
code = request.GET.get('code')
if not code:
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'
payload = {
'client_id': settings.GITHUB_CLIENT_ID,
'client_secret': settings.GITHUB_CLIENT_SECRET,
'code': code,
'redirect_uri': settings.GITHUB_REDIRECT_URI,
}
headers = {'Accept': 'application/json'}

response = requests.post(token_url, data=payload, headers=headers)
response_data = response.json()

access_token = response_data.get('access_token')
if not access_token:
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_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')

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}
)

if not created:
# If the user already exists, update the access token
github_user.access_token = access_token
github_user.avatar_url = avatar_url
github_user.save()

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'
story_points = 5

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

return redirect('dashboard')


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:
# return {'error': 'Invalid project URL format'}
#
# project_id = project_match.group(1)

# Extract issue number from the URL
# issue_match = re.match(r'https://github.com/[^/]+/[^/]+/issues/(\d+)', issue_url)
# if not issue_match:
# return {'error': 'Invalid issue URL format'}
#
# issue_number = issue_match.group(1)

# Retrieve the project columns
columns_url = f'https://api.github.com/projects/1/columns'
headers = {
'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}'}

columns = columns_response.json()

# Find the card in a column
card_id = None
for column in columns:
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}'}

cards = cards_response.json()
for card in cards:
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'}

# Update the card with Story Points
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}'}

card_data = card_response.json()

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:
# updated_note = f"{card_data['note']}\n\nStory Points: {story_points}"
# update_data = {'note': updated_note}
# else:
# return {'error': 'This card is not a note card and cannot be updated'}
#
# update_response = requests.patch(card_url, json=update_data, headers=headers)
# if update_response.status_code == 200:
# return {'success': 'Story Points added successfully'}
# else:
# return {'error': f'Failed to add Story Points: {update_response.status_code}'}
10 changes: 10 additions & 0 deletions estimation/estimation/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@

import os
from pathlib import Path
from dotenv import load_dotenv

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

load_dotenv()


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
Expand Down Expand Up @@ -120,6 +123,13 @@

USE_TZ = True

#github details

GITHUB_CLIENT_ID = os.environ.get('GITHUB_CLIENT_ID', '')
GITHUB_CLIENT_SECRET = os.environ.get('GITHUB_CLIENT_SECRET', '')
GITHUB_REDIRECT_URI = os.environ.get('GITHUB_REDIRECT_URI', 'http://localhost:8000/app/github/callback/')



# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/
Expand Down
5 changes: 4 additions & 1 deletion estimation/estimation/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
from django.contrib import admin
from django.urls import include, path

from app import views

urlpatterns = [
path("app/", include("app.urls")),
path("admin/", admin.site.urls),
path("admin/", views.index),
# path("admin/", admin.site.urls),
]
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ requests==2.32.3
sqlparse==0.5.1
typing_extensions==4.12.2
urllib3==2.2.3
python-dotenv~=1.0.1

0 comments on commit de134f0

Please sign in to comment.