Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
be1ac98
Merge pull request #4 from RLBF-Group/feature
peterzepf Jul 15, 2023
5081084
Merge pull request #17 from RLBF-Group/dev
edwinlny Jul 17, 2023
20b75da
Merge pull request #20 from RLBF-Group/dev
edwinlny Jul 18, 2023
3625dd3
set up service worker auth with Google API
gschussler Jul 19, 2023
203185b
fixed leaked postgres URI lol
gschussler Jul 19, 2023
35bd493
added to gitignore
gschussler Jul 19, 2023
43c396f
cleaned up files to remove env
gschussler Jul 19, 2023
ae63267
repaired gitignore
gschussler Jul 19, 2023
9212de1
tues night
AlexandraAshcraft Jul 19, 2023
b765281
set up testing suite
gschussler Jul 19, 2023
1e88ddd
Merge pull request #1 from Heat-Seeking-Devil-Chicken17/alexandra/auth
gschussler Jul 19, 2023
483b110
stored pg uri in env
gschussler Jul 19, 2023
1e613a3
merge with dev
gschussler Jul 19, 2023
e23b48b
deleted env file
AlexandraAshcraft Jul 19, 2023
8ebb42e
Merge pull request #2 from Heat-Seeking-Devil-Chicken17/alexandra/auth
gschussler Jul 19, 2023
12f18c1
Merge branch 'dev' of https://github.com/Heat-Seeking-Devil-Chicken17…
gschussler Jul 19, 2023
dfc21e8
repaired package lock on test branch
gschussler Jul 19, 2023
6ae541e
lunch weds
AlexandraAshcraft Jul 19, 2023
2fae8d0
made progress testing endpoints
gschussler Jul 19, 2023
9c6eb3b
broken generate auth url
AlexandraAshcraft Jul 20, 2023
781a57e
able to create new sheet
annni11 Jul 20, 2023
0db4936
EOD wednesday
AlexandraAshcraft Jul 20, 2023
44bf9fa
Co-authored-by: tristanyukio <tristanyukio@users.noreply.github.com>
AlexandraAshcraft Jul 20, 2023
4c408ae
Merge pull request #3 from Heat-Seeking-Devil-Chicken17/alexandra/auth
gschussler Jul 20, 2023
b28949e
Annabelle and Tristan working still on update feature
annni11 Jul 20, 2023
c70c26e
update
tristanyukio Jul 20, 2023
398c073
not working still
AlexandraAshcraft Jul 20, 2023
d8e70a9
maybe have the get token working?
AlexandraAshcraft Jul 20, 2023
1df2516
Merge branch 'dev' into alexandra/auth
AlexandraAshcraft Jul 20, 2023
484e551
cleaned up route testing
gschussler Jul 20, 2023
ed3d935
added to .gitignore
gschussler Jul 20, 2023
007086b
Merge pull request #4 from Heat-Seeking-Devil-Chicken17/alexandra/auth
gschussler Jul 20, 2023
2f27baf
merged updates from dev to testing branch
gschussler Jul 20, 2023
fcd148b
updated version 1:06 pm before react
tristanyukio Jul 20, 2023
85a1f2e
updated before lunch
tristanyukio Jul 20, 2023
a334f9b
reverted a few steps to keep redirect working
gschussler Jul 20, 2023
b1c10d9
authController update
gschussler Jul 20, 2023
e9fa90c
able to get access and refresh tokens, need to finish auth for user
gschussler Jul 20, 2023
23aabc2
Merge pull request #5 from Heat-Seeking-Devil-Chicken17/grant/testing
AlexandraAshcraft Jul 20, 2023
cb0afb6
everything working except for quota
tristanyukio Jul 20, 2023
e8f03b2
trying to store tokens and redirect user to the right page
gschussler Jul 20, 2023
12c8a96
Merge branch 'dev' into grant/testing
gschussler Jul 20, 2023
e5f6d45
Merge pull request #7 from Heat-Seeking-Devil-Chicken17/grant/testing
AlexandraAshcraft Jul 20, 2023
1448b44
updated 6:39
tristanyukio Jul 20, 2023
6f6a1fc
Co-authored-by: annni11 <annni11@users.noreply.github.com>
tristanyukio Jul 20, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .env

This file was deleted.

4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ web_modules/
.env.test.local
.env.production.local
.env.local
.env

# parcel-bundler cache (https://parceljs.org/)
.cache
Expand Down Expand Up @@ -129,3 +130,6 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

# MacOS files
.DS_Store
43 changes: 43 additions & 0 deletions __tests__/routes.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// import routers/endpoints from files throughout the project to test them here
// supertest will be a required for http request testing
const request = require('supertest');
const app = require('../server/server');

// *** REFER TO `server.js` TO MAKE SURE Application Default Credentials (ADC) ARE AUTHENTICATED ***

// Google API Authentication is essential to server-side operations in the application, but using Jest to mock that authentication here seemed to be unnecessary and inefficient. Google API docs will be of more help

xdescribe("server startup", () => {
let server;

beforeAll(() => {
server = app.listen(5555); //start server at PORT before tests
})

afterAll((done) => {
if(server) {
server.close(done) //close server after tests run
} else {
done();
}
});

it('should start and listen at proper port', async () => {
const res = await request(app).get('/');
expect(res.status).toBe(404);
expect(res.text).toBe('Not Found');
})

it('should catch all invalid routes and return a status 404', async () => {
const res = await request(app).get('/api/invalid-route');
expect(res.status).toBe(404);
})
})

describe('/api', () => {
describe('POST', () => {
it('responds with 200 status and application/json content type', async () => {
return request(app).post('/api').expect('Content-Type', /application\/json/).expect(200);
})
})
})
File renamed without changes.
1 change: 1 addition & 0 deletions build/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>RLBF GROUP</title><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=VT323&display=swap" rel="stylesheet"><script defer="defer" src="/bundle.js"></script></head><body><h1></h1><div id="root"></div></body></html>
10 changes: 9 additions & 1 deletion client/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import React from 'react'
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"
import Footer from './components/Footer.js'
import About from './components/About.js'
import Signin from './components/Signin.js'
import Callback from './components/Callback.js'
import ReadMe from './components/ReadMe.js'
import Output from './components/Output.js'
import Form from './components/Form.js'
import Home from './components/Home.js'
import Reverse from './components/Reverse.js'
import './styles/LandingPage.scss'


Expand All @@ -14,7 +18,11 @@ const App = () => {
<Router>
<div className="contentWrapper">
<Routes>
<Route path="/" exact element={<Form />}/>
<Route path="/home" exact element={<Home />}/>
<Route path="/form" element={<Signin />} />
<Route path="/callback" element={<Callback />} />

<Route path="/reverse" exact element={<Reverse />}/>
<Route path="/readme" exact element={<ReadMe />}/>
<Route path="/about" exact element={<About />}/>
<Route path="/output" exact element={<Output />}/>
Expand Down
88 changes: 88 additions & 0 deletions client/components/Callback.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React, { useEffect, useState } from 'react';
import { redirect, useParams } from 'react-router-dom';

//once a user has given permissions on the consent page, if the user's credentials were authenticated by Google, Google redirects the user to the redirect URL we provided ('/callback') along with an authorization code query parameter on the URL
//GET /oauthcallback?code={authorizationCode}

// using that auth code, we will now make a GET request to the server, which will make a GET request here to obtain the access token and refresh token(used as cookie) from Google's API

export default function Callback() {
const [fetched, setFetched] = useState(false);
//const navigate = useNavigate();

//get the redirect URL path (including the code query (authentication code) required to send to retrieve user specific tokens)
//href, the entire redirect URL appended with the authorization code
const href = window.location.href;

const index = href.indexOf('callback');
//append authorization code to the path for the GET request for user's access/refresh tokens
const path = '/api/authentication/' + href.slice(index);
// console.log('path: ', path);

//use authentication code in request query to get access/refresh tokens from Google
// const getTokens = async () => {
// try {
// const response = await fetch(path, {
// method: 'GET',
// headers: {
// 'Content-Type': 'Application/JSON',
// },
// });

// console.log('getTokens fetch response: ', response);
// const accessToken = await response.json();

// console.log('Access Token: ', accessToken);
// console.log(typeof accessToken);

// return redirect('/form');
// } catch (error) {
// console.log(
// 'Error when making fetch request to URL for access token and refresh token',
// error
// );
// }
// };

const handleCallback = async () => {
try {
const response = await fetch(path, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}

})
// const permission = await response.json();

// console.log('in callback component')
// if (permission.status === 200){
// console.log('login successful')
// return redirect('/form');
//}
} catch (error) {
console.log('Error, could not authenticate user with Google', error)
}

}




if (fetched === false) {
setFetched(true);
}

useEffect(() => {
handleCallback();
}, [fetched]);

return (
<div className="signinPage">
<div className="signin">
<h2>Confirming Google Account</h2>
<p>Please wait..</p>
</div>
</div>
);
}
17 changes: 17 additions & 0 deletions client/components/Email.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react'

const Email = ({formData, setFormData}) => {
return (
<div>
<input
placeholder='Please insert your email'
value={formData.email}
onChange={e => {
setFormData({ ...formData, email: e.target.value })
}}
></input>
</div>
)
}

export default Email
29 changes: 18 additions & 11 deletions client/components/Footer.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import React from 'react'
import { Link } from "react-router-dom";
import React from 'react';
import { Link } from 'react-router-dom';

const Footer = () => {
return (
<div className="footer">
<Link to="/" className="linkToReadMe">HOME</Link>
<Link to="/readme" className="linkToReadMe">READ ME</Link>
<Link to="/about" className="linkToReadMe">ABOUT US</Link>
</div>
)
}
return (
<div className="footer">
{/* //! ensure that this route is consistent with the user's logged in status */}
<Link to="/form" className="linkToReadMe">
HOME
</Link>
<Link to="/readme" className="linkToReadMe">
READ ME
</Link>
<Link to="/about" className="linkToReadMe">
ABOUT US
</Link>
</div>
);
};

export default Footer
export default Footer;
2 changes: 1 addition & 1 deletion client/components/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const Form = props => {
}

const handleClick = e => {
const url = '/api'
const url = '/api/sheets'
fetch(url, {
method: 'POST',
body: JSON.stringify({
Expand Down
14 changes: 14 additions & 0 deletions client/components/Home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react'
import { Link } from "react-router-dom";

const Home = () => {
return (
<div className="button-home">
<Link to="/form" className="linkToForm"><button>SheetsQL-ifier</button></Link>
<Link to="/reverse" className="linkToReverse"><button className='rev-button'>Reversifier</button></Link>
</div>
)
}


export default Home;
137 changes: 137 additions & 0 deletions client/components/Reverse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import React, { useState, useEffect } from 'react'
import GoogleSheetsUrl from './GoogleSheetsUrl';
import DataRange from './DataRange';
import SqlDatabaseUrl from './SqlDatabaseUrl';
import PrimaryKeyAndName from './PrimaryKeyAndName';
import TableName from './TableName';
import Email from './Email';
import Url from './Url';

const Form = props => {
const [page, setPage] = useState(0);
const [formData, setFormData] = useState({
sqlDatabaseUrl: "",
tableName: "",
email: "",
});
const FormTitles = ["Please Enter SQL Database URL", "Please Enter Table Name From SQL Database", "Please Enter Email Address", "Here Is Your Google Sheet:"];

const [googleSheetsErrorMessage, setGoogleSheetsErrorMessage] = useState();
const [successClassName, setSuccessClassName] = useState("submitSuccessHide");
const [submitDisabled, setSubmitDisabled] = useState(true);
const [updatedURL, setUpdatedURL] = useState('')

useEffect(()=> {
const {sqlDatabaseUrl, tableName, email} = formData;
if (sqlDatabaseUrl.startsWith('postgres://') && tableName && email){
setSubmitDisabled(false);
} else {
if (!submitDisabled) setSubmitDisabled(true);
}
}, [formData])

const personalPage = () => {
if(page === 0) {
return <SqlDatabaseUrl
formData={formData}
setFormData={setFormData}
/>
} else if(page === 1) {
return <TableName
formData={formData}
setFormData={setFormData}
/>
} else if(page === 2) {
return <Email
formData={formData}
setFormData={setFormData}
/>

} else if(page === 3) {
return <Url
// formData={formData}
// setFormData={setFormData}
updatedURL={updatedURL}
/>
}
}

const handleClick = e => {
const url = '/api/new'
console.log('entered post for backend')
fetch(url, {
method: 'POST',
body: JSON.stringify({
sqlDatabaseUrl: formData.sqlDatabaseUrl,
tableName: formData.tableName,
email: formData.email,
}),
headers: {
'Content-Type': 'application/json'
}
}
)
// .then(response => {
// console.log('entered response', response)
// // response.json()
// })
// .then(data => {
// console.log('data jsoned', data)
// setUpdatedURL(data)
}



return (
<div className="form">
<div className="form-container">
<div className={successClassName}>
<p></p>
</div>
<div className="formHeader">
<h3>{FormTitles[page]}</h3>
</div>
<div className="formBody">
{personalPage()}
</div>
<div className="formFooter">
<button
className="formButton"
disabled = {page === 0}
onClick={() => {
if (successClassName==='submitSuccess')
setSuccessClassName('submitSuccessHide');
setPage((currPage) => currPage -= 1)}
}
>Prev</button>
<button
className="formButtonNext"
disabled = {
// different cases for prev, next, and submit
(page === FormTitles.length -1 ) && (submitDisabled)
}
onClick={() => {

if(page === 2) {
{handleClick()}
setSuccessClassName("submitSuccess");
setPage((currPage) => currPage += 1)
} else {
setPage((currPage) => currPage += 1)
setSuccessClassName("submitSuccessHide");
}
}
}>{page === 2 ? 'Submit' : 'Next'}</button>
</div>
<div className="pageNumber">
<p>{page + 1}/4</p>
</div>
<div className="errorMessage">
<p>{googleSheetsErrorMessage}</p>
</div>
</div>
</div>
)
}

export default Form
Loading