diff --git a/DirectReport/browserview/app.py b/DirectReport/browserview/app.py index d025e906..0ce5a97c 100644 --- a/DirectReport/browserview/app.py +++ b/DirectReport/browserview/app.py @@ -1,9 +1,14 @@ #!/usr/bin/env python3 import sys +import os from pathlib import Path +import urllib +import requests -from flask import Flask, render_template, request, redirect, json, url_for +from flask import Flask, render_template, session, request, redirect, json, url_for +from flask import make_response +from datetime import datetime, timedelta from flask_login import LoginManager, login_required, current_user from DirectReport.browserview.services.github import GithubClient @@ -22,11 +27,147 @@ app.register_blueprint(auth) app.register_blueprint(reportsbp) app.secret_key = appsecrets.SECRET_KEY + +client_id = appsecrets.GITHUB_CLIENT_ID +client_secret = appsecrets.GITHUB_CLIENT_SECRET + login_manager.init_app(app) login_manager.login_view = "login" user_model = UserModel() +@app.route('/authorize/github') +def oauth2_authorize(): + github_url = "https://github.com/login/oauth/authorize?scope=user:email&client_id=" + client_id + "&client_secret=" + client_secret + "&redirect_uri=http%3A%2F%2F127.0.0.1%3A5000%2Fcallback%2Fgithub" + return redirect(github_url) + + +def get_commits_last_month(): + owner = 'chriswebb09' + repo = 'your_repository' + url = f'https://api.github.com/repos/{owner}/{repo}/pulls' + + # Replace 'your_token' with your personal access token + headers = {'Authorization': 'token your_token'} + + # Calculate the date one month ago + since_date = (datetime.utcnow() - timedelta(days=30)).strftime('%Y-%m-%dT%H:%M:%SZ') + params = {'state': 'all', 'sort': 'created', 'direction': 'desc', 'since': since_date} + response = requests.get(url, headers=headers, params=params) + + if response.status_code == 200: + pull_requests = response.json() + print(pull_requests) + else: + print(f"Error: {response.status_code}") + print(response.text) + +@app.route('/repo', methods=['GET', 'POST']) +def reponame(): + args_url = request.args.get('repo_url') + h_token = session['header_token'] + reponame = "https://api.github.com/repos/" + args_url + "/commits" + headers443 = { + 'Accept': 'application/vnd.github+json', + 'Authorization': 'Bearer ' + h_token, + 'X-GitHub-Api-Version': '2022-11-28' + } + response3 = requests.get( + url=reponame, + headers=headers443, + auth=(client_id, client_secret) + ) + json_Data3 = json.loads(response3.content) + + USERNAME = "chriswebb09" + REPO = "DirectReport" + + # Calculate the date one month ago + last_month = datetime.utcnow() - timedelta(days=30) + last_month_str = last_month.strftime("%Y-%m-%dT%H:%M:%SZ") + + # API endpoint to retrieve commits for a repository since the last month + api_url = f"https://api.github.com/repos/{USERNAME}/{REPO}/commits?since={last_month_str}" + + # Fetch commits using requests and your GitHub token + headers = {"Authorization": f"token {appsecrets.GITHUB_TOKEN}"} + response = requests.get(api_url, headers=headers) + + # Check if the request was successful (status code 200) + results_2 = [] + if response.status_code == 200: + commits = response.json() + + # Format and print the commits + for commit in commits: + author_name = commit["commit"]["author"]["name"] + commit_message = commit["commit"]["message"] + results_2.append(f"{author_name}: {commit_message}") + else: + print(f"Error: {response.status_code} - {response.text}") + results = [] + for commit in json_Data3: + commit_data_res = { + "message": commit["commit"]["message"], + "url": commit["commit"]["url"], + "commit_author_name": commit["commit"]["author"]["name"], + "commit_author_email": commit["commit"]["author"]["email"], + "commit_author_date": commit["commit"]["author"]["date"], + "committer_name": commit["commit"]["committer"]["name"], + "committer_email": commit["commit"]["committer"]["email"], + "committer_date": commit["commit"]["committer"]["date"], + "comment_count": commit["commit"]["comment_count"], + "verified": commit["commit"]["verification"]["verified"], + "verification_reason": commit["commit"]["verification"]["reason"], + "verification_signature": commit["commit"]["verification"]["signature"], + "type": "commit" + } + results.append(commit_data_res) + result_log = " ".join(results_2) + print(result_log) + return json_Data3, 200 + + + +@app.route('/callback/github', methods=['GET', 'POST']) +def ouath2_callback(): + data = {'client_id': client_id, 'client_secret': client_secret, 'code': request.args.get("code")} + response = requests.post('https://github.com/login/oauth/access_token', data=data) + res = response.text.split('&', 1) + token = res[0].split('=')[1] + HEADER_TOKEN = token + session['header_token'] = token + headers2 = { + 'Accept': 'application/vnd.github+json', + 'X-GitHub-Api-Version': '2022-11-28', + 'Content-Type': 'application/x-www-form-urlencoded', + } + HEADER_TOKEN = token + data2 = '{\n' + ' "access_token": "' + HEADER_TOKEN + '" \n}' + response2 = requests.post( + url="https://api.github.com/applications/" + client_id + "/token", + headers=headers2, + data=data2, + auth=(client_id, client_secret), + ) + json_Data = json.loads(response2.content) + repos = requests.get(json_Data["user"]['repos_url'] + "?sort=updated&direction=desc", data=data2, auth=(client_id, client_secret)) + json_Data2 = json.loads(repos.content) + results = [] + for repo in json_Data2: + owner = repo['owner'] + url_repo = "https://api.github.com/repos/" + owner['login'] + "/" + repo['name'] + + data_res = { + "name": repo['name'], + "description": repo['description'], + "url": repo['url'], + 'url_repo': url_repo, + "owner_url": owner['url'] + } + results.append(data_res) + return render_template('team/teamreport.html', title='Team', data=results) + @app.route("/") def home(): """ diff --git a/DirectReport/browserview/blueprints/auth/auth.py b/DirectReport/browserview/blueprints/auth/auth.py index fbef0c9e..31c89740 100644 --- a/DirectReport/browserview/blueprints/auth/auth.py +++ b/DirectReport/browserview/blueprints/auth/auth.py @@ -6,6 +6,7 @@ from DirectReport.models.user_model import UserModel from flask_login import login_user, login_required, logout_user, current_user from DirectReport.browserview import app +from DirectReport.datadependencies import appsecrets from DirectReport.models.Report.report_builder import ReportBuilder from DirectReport.browserview.services.github import GithubClient @@ -50,7 +51,9 @@ def login(): else: print("password no match") flash("Please check your login details and try again.") - return render_template('auth/login.html') + return render_template( + 'auth/login.html', client_id=appsecrets.GITHUB_CLIENT_ID, client_secret=appsecrets.GITHUB_CLIENT_SECRET + ) @auth.route("/account", methods=['GET', 'POST']) diff --git a/DirectReport/browserview/blueprints/reports/reportbp.py b/DirectReport/browserview/blueprints/reports/reportbp.py index eaa16c21..ff095ef7 100644 --- a/DirectReport/browserview/blueprints/reports/reportbp.py +++ b/DirectReport/browserview/blueprints/reports/reportbp.py @@ -6,8 +6,8 @@ from DirectReport.browserview.services.github import GithubClient from DirectReport.browserview.services.github import GoogleAIClient -from DirectReport.models.Report.report_builder import ReportBuilder -from DirectReport.models.Report.report_model import ReportModel +from DirectReport.models.report.report_builder import ReportBuilder +from DirectReport.models.report.report_model import ReportModel reportsbp = Blueprint('reportsbp', __name__) @@ -40,11 +40,11 @@ def report(): } data_json["shortlog"] = client.parse_git_shortlog(log_item) data_json["repos"] = repodata - ReportBuilder.new(data_json, prompt, current_user.id) + ReportBuilder.new(data_json, prompt, current_user.id, "DirectReport") return data_json, 201 -@reportsbp.route("/teamreport", methods=['GET', 'POST']) +@reportsbp.route("/reports/new", methods=['GET', 'POST']) @login_required def team_report(): if request.method == "POST": @@ -54,7 +54,7 @@ def team_report(): return render_template('team/teamreport.html', title='Team Report', data=[]) -@reportsbp.route("/getreport/", methods=['GET']) +@reportsbp.route("/reports/", methods=['GET']) @login_required def get_report(uid=None): reports = ReportBuilder.get_reports_for_user_id(current_user.id) @@ -63,14 +63,14 @@ def get_report(uid=None): return render_template('team/teamreport.html', title='Team Report', teamData=report["report"]) -@reportsbp.route("/getlist", methods=['GET']) +@reportsbp.route("/reports/list/new", methods=['GET']) @login_required def get_list(): reports = ReportBuilder.get_reports_for_user_id(current_user.id) return reports, 201 -@reportsbp.route("/list", methods=['GET', 'POST']) +@reportsbp.route("/reports", methods=['GET', 'POST']) @login_required def list_entries(): """ diff --git a/DirectReport/browserview/static/js/account/account.js b/DirectReport/browserview/static/js/account/account.js index 9d3ca3c8..f3b079b4 100644 --- a/DirectReport/browserview/static/js/account/account.js +++ b/DirectReport/browserview/static/js/account/account.js @@ -3,7 +3,6 @@ const { useState, useEffect } = React; const Account = () => { const [userData, setUserData] = useState({}); - const [actualData, setActualData] = useState({}); const [reportData, setReportData] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -18,10 +17,9 @@ const Account = () => { } return response.json(); }) - .then((actualData) => { - setUserData(actualData["user"]); - setReportData(actualData["reports"]); - setActualData(actualData); + .then((responseData) => { + setUserData(responseData["user"]); + setReportData(responseData["reports"]); setError(null); }) .catch((err) => { @@ -39,14 +37,14 @@ const Account = () => { ) } else { return ( -
-
+
+

User Account

-
+
{userData && AccountUserInfo(userData, reportData)}
diff --git a/DirectReport/browserview/static/js/auth/login.js b/DirectReport/browserview/static/js/auth/login.js index 0d67fb9d..da845e1a 100644 --- a/DirectReport/browserview/static/js/auth/login.js +++ b/DirectReport/browserview/static/js/auth/login.js @@ -18,7 +18,8 @@ const LoginForm = () => { placeholder="name@company.com" required=""/>
-
@@ -37,9 +39,16 @@ const LoginForm = () => { className="w-full text-white bg-indigo-700 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800"> Sign in +

Don’t have an account yet? - + Sign up

diff --git a/DirectReport/browserview/static/js/entryform.js b/DirectReport/browserview/static/js/entryform.js index 1a13fbed..cdcb7cd2 100644 --- a/DirectReport/browserview/static/js/entryform.js +++ b/DirectReport/browserview/static/js/entryform.js @@ -1,5 +1,6 @@ const { useState, useEffect } = React; +const { axios } = axios; class EntryForm extends React.Component { constructor(props) { super(props); diff --git a/DirectReport/browserview/static/js/index.js b/DirectReport/browserview/static/js/index.js index 2b9fd073..27db1292 100644 --- a/DirectReport/browserview/static/js/index.js +++ b/DirectReport/browserview/static/js/index.js @@ -1,6 +1,7 @@ 'use strict'; const elem = React.createElement; + class Home extends React.Component { render() { return elem( diff --git a/DirectReport/browserview/static/js/list/list.js b/DirectReport/browserview/static/js/list/list.js index ec5c4d50..dc90f681 100644 --- a/DirectReport/browserview/static/js/list/list.js +++ b/DirectReport/browserview/static/js/list/list.js @@ -7,7 +7,7 @@ const SavedReportListApp = () => { const [error, setError] = useState(null); useEffect(() => { - fetch(`/getlist`) + fetch(`/reports/list/new`) .then((response) => { if (!response.ok) { throw new Error( diff --git a/DirectReport/browserview/static/js/list/listcomponents.js b/DirectReport/browserview/static/js/list/listcomponents.js index 60159903..eff84277 100644 --- a/DirectReport/browserview/static/js/list/listcomponents.js +++ b/DirectReport/browserview/static/js/list/listcomponents.js @@ -11,7 +11,7 @@ class SavedReportList extends React.Component { {this.props.listdata.map(item =>
- +

{'User: ' + item.user_id}

{'Raw Input: ' + item.raw_input}

diff --git a/DirectReport/browserview/static/js/teamreport/teammember.js b/DirectReport/browserview/static/js/teamreport/teammember.js index 83929653..95d74388 100644 --- a/DirectReport/browserview/static/js/teamreport/teammember.js +++ b/DirectReport/browserview/static/js/teamreport/teammember.js @@ -1,5 +1,6 @@ const { useState, useEffect } = React; + const TeamMember = () => { const [userData, setUserData] = useState({}); diff --git a/DirectReport/browserview/static/js/teamreport/teamreport.js b/DirectReport/browserview/static/js/teamreport/teamreport.js index d9d6b068..aa221de1 100644 --- a/DirectReport/browserview/static/js/teamreport/teamreport.js +++ b/DirectReport/browserview/static/js/teamreport/teamreport.js @@ -1,15 +1,73 @@ -const { useState, useEffect } = React; +'use strict'; -const TeamReport = () => { +const { useState, useCallback, useEffect } = React; - const [teamData, setTeamData] = useState({}) - const [commentText, setCommentText] = useState("") - const [isOpened, setIsOpened] = useState(false) +class TeamReport extends React.Component { + constructor(props) { + super(props); + this.state = { + teamData: {}, + commits: [] + } + this.handleTeamDataChange = this.handleTeamDataChange.bind(this); + this.handleSubmit = this.handleSubmit.bind(this) + this.openRepoPopover = this.openRepoPopover.bind(this); + this.setCommits = this.setCommits.bind(this); + this.toggle = this.toggle.bind(this); + this.toggleHide = this.toggleHide.bind(this); + } + + toggle() { + this.setState({isOpened: !this.state.isOpened}); + } + + toggleHide() { + this.setState({isHidden: !this.state.isHidden}); + } + + handleTeamDataChange(team) { + this.setState({teamData: team}); + } + + setCommits(commitsData) { + this.setState({commits: commitsData}); + } - const handleSubmit = e => { - e.preventDefault() + update(repoURL) { + axios({ + method: 'post', + url: "/repo" + repoURL, + headers: {'content-type': 'application/json'} + }).then(result => { + + const results = result.data.map((commit) =>{ + console.log(commit) + return { + 'message': commit['commit']['message'], + 'name': commit['commit']['author']['name'], + 'authur_url': commit['author']['html_url'], + 'author_name': commit['author']['login'], + 'commit_author_email': commit['commit']['author']['email'], + 'commit_author_name': commit['commit']['author']['name'], + 'commit_author_date': commit['commit']['author']['date'], + 'committer': commit['commit']['committer']['name'], + 'committer_data': commit['commit']['committer']['date'], + 'committer_email': commit['commit']['committer']['email'], + 'comment_count': commit['commit']['comment_count'], + 'type': 'commit' + } + }) + console.log(results) + this.setCommits(results); + }).catch(error => { + console.log(error); + }) + } + + + handleSubmit(event) { var dataForm = { - "prompt": commentText + "prompt": this.state.commentText }; const formDataJsonString = JSON.stringify(dataForm); fetch("/report", { @@ -22,172 +80,124 @@ const TeamReport = () => { }).then(function(res) { return res.json(); }).then(function(data) { - setTeamData(data); - toggle(); + this.handleTeamDataChange(data); + this.toggle(); showGraphics(data, '#map-container'); showGraphics2(data, '#map-container2'); showGraphics3(data, '#map-container3'); }).then(function() { console.log('done'); }); - }; - - const handleClick = e => { - e.preventDefault() - var dataForm = { - "prompt": JSON.stringify(teamData) - }; - const formDataJsonString = JSON.stringify(dataForm); - fetch("/generate_email", { - method: "POST", - headers: { - "Content-Type": "application/json", - "Accept": "application/json" - }, - body: formDataJsonString - }).then(function(res) { - return res.json(); - }).then(function(data) { - setGeneratedEmail(data["email"]); - toggleHide(); - }); } - const closePopover = () => { - document.getElementById('popover-id-left-purple').classList.toggle("hidden"); - } - - const closeRepoPopover = () => { - document.getElementById('popover-repo-left-purple').classList.toggle("hidden"); - } - - - const openPopover = (e: ChangeEvent, teammember) => { - e.preventDefault(); - let element = e.target; - while("BUTTON" !== element.nodeName) { - element = element.parentNode; - } - Popper.createPopper(element, document.getElementById('popover-id-left-purple'), { - strategy: 'fixed' - }); - document.getElementById('popover-id-left-purple').classList.toggle("hidden"); - document.getElementById('popoverTitleContent').innerHTML = teammember.name - document.getElementById('popoverContent').innerHTML = teammember.accomplishments; - document.getElementById('popoverCommits').innerHTML = "Commits: " + teammember.commits; - } - - const openRepoPopover = (e: ChangeEvent) => { + openRepoPopover(repos, state) { const element = document.getElementById('h1content'); Popper.createPopper(element, document.getElementById('popover-repo-left-purple'), { - strategy: 'fixed' + strategy: 'fixed' }); document.getElementById('popover-repo-left-purple').classList.toggle("hidden"); - document.getElementById('popover-repo-TitleContent').innerHTML = "Repos" + "(" + teamData["repos"].length + ")"; - var list = '
'; - document.getElementById('popover-repo-Content').innerHTML = list; - } - - const repoPopoverUI = () => { - return ( -
-
-
- - -
-
-
- {/*
*/} - {/*
*/} -
-
- ) - } - - function toggle() { - setIsOpened(isOpened => !isOpened); - } - - function toggleHide() { - setIsHidden(isHidden => !isHidden); - } - - function toggle() { - setIsOpened(isOpened => !isOpened); - } + document.getElementById('popover-repo-TitleContent').innerHTML = "Repos" + "(" + repos.length + ")"; + const content = document.getElementById('popover-repo-Content'); + var list_element = document.createElement("ul") + repos.map((repo) => { + var li = document.createElement("li"); + var repoURL = repo["url_repo"].substring(28, repo['url'].length).replace("/", "?repo_url=") + li.innerHTML = '' + repo["name"] + '' + li.classList.add("py-3"); + li.classList.add("px-3"); + li.classList.add("border-b"); + li.classList.add("border-solid"); + li.classList.add("border-blueGray-100"); + li.onclick = () => { + this.update(repoURL); + document.getElementById('popover-repo-left-purple').classList.toggle("hidden"); + } + list_element.append(li) + }) + content.appendChild(list_element); + }; - const FormDiv = (handleSubmit, openRepoPopover, commentText) => { + render() { return ( -
-
-

Enter - Github Data -

-
-
- +
+

+ Generate Team Report From Metadata +

+ {repoPopoverUI()} +
+ - ) - } - - return ( -
-

- Generate Team Report From Metadata -

- {repoPopoverUI()} -
-
- {FormDiv(handleSubmit, openRepoPopover, commentText)} -
-
-
-

Summary

-
- {isOpened && ( -
- {ShowSummary(teamData["report"])} - {ShowHighlights(teamData["report"])} +
+
+

Team

+ {PopoverUI(closePopover)} +
+ {this.props.isOpened && ( +
+ {ShowTeamList(this.props.teamData["team"], openPopover)}
)}
-
-
-

Team

- {PopoverUI(closePopover)} -
- {isOpened && ( -
- {ShowTeamList(teamData["team"], openPopover)} -
- )} -
-
+ {this.props.isOpened && ( + + )}
- {isOpened && ( - - )} -
- ); + ) + } }; - -const domContainer = document.querySelector('#root'); -ReactDOM.render(, domContainer); diff --git a/DirectReport/browserview/static/js/teamreport/teamreportcomponents.js b/DirectReport/browserview/static/js/teamreport/teamreportcomponents.js index 9a0dd85f..68efe201 100644 --- a/DirectReport/browserview/static/js/teamreport/teamreportcomponents.js +++ b/DirectReport/browserview/static/js/teamreport/teamreportcomponents.js @@ -1,6 +1,5 @@ const { useState, useEffect } = React; - const ShowSummary = (report) => { return (

@@ -15,7 +14,7 @@ const ShowSummary = (report) => { const ShowHighlights = (report) => { return ( -

+