Progress with authentication tolen

This commit is contained in:
Riccardo
2021-01-05 13:58:26 +01:00
parent 4d021d6043
commit 436eb4410c
8 changed files with 138 additions and 34 deletions

View File

@@ -4,6 +4,7 @@ import Header from './Header';
import { Switch, Route } from 'react-router-dom'; import { Switch, Route } from 'react-router-dom';
// import ProductList from './ProductList'; // import ProductList from './ProductList';
import AppointmentList from './AppointmentList'; import AppointmentList from './AppointmentList';
import Login from './Login';
const App = () => { const App = () => {
return ( return (
@@ -14,6 +15,7 @@ const App = () => {
{/* <Route exact path="/" component={ProductList} /> */} {/* <Route exact path="/" component={ProductList} /> */}
<Route exact path="/" component={AppointmentList} /> <Route exact path="/" component={AppointmentList} />
<Route exact path="/create" component={CreateAppointment} /> <Route exact path="/create" component={CreateAppointment} />
<Route exact path="/login" component={Login} />
</Switch> </Switch>
</div> </div>
</div> </div>

View File

@@ -10,8 +10,10 @@ const CREATE_APPOINTMENT_MUTATION = gql`
mutation CreateAppointmentMutation( mutation CreateAppointmentMutation(
$title: String! $title: String!
$description: String! $description: String!
$timeStart: String!
$timeEnd: String!
) { ) {
createAppointment(title: $title, description: $description) { createAppointment(title: $title, description: $description, timeStart: $timeStart, timeEnd: $timeEnd) {
id id
title title
description description

View File

@@ -1,23 +1,30 @@
import React from 'react'; import React from 'react';
// import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
import { Link, withRouter } from 'react-router-dom'; import { Link, withRouter } from 'react-router-dom';
import { AUTH_TOKEN } from '../constants';
const Header = () => { const Header = () => {
// const history = useHistory(); const history = useHistory();
const authToken = localStorage.getItem(AUTH_TOKEN);
return ( return (
<div className="flex pa1 justify-between nowrap orange"> <div className="flex pa1 justify-between nowrap orange">
<div className="flex flex-fixed black"> <div className="flex flex-fixed black">
<div className="fw7 mr1">Store!</div> <div className="fw7 mr1">Store!</div>
<Link to="/" className="ml1 no-underline black"> <Link to="/" className="ml1 no-underline black">Top list</Link>
Top list
</Link>
<div className="ml1"> --- </div> <div className="ml1"> --- </div>
<Link <Link to="/create" className="ml1 no-underline black">Create new</Link>
to="/create" </div>
className="ml1 no-underline black" <div className="flex flex-fixed">
> {authToken ? (
Create new <div className="ml1 pointer black"
</Link> onClick={() => {
localStorage.removeItem(AUTH_TOKEN);
history.push(`/`);
}}
>Logout</div>
) : (
<Link to="/login" className="ml1 no-underline black">Login</Link>
)}
</div> </div>
</div> </div>
); );

View File

@@ -12,7 +12,7 @@ const SIGNUP_MUTATION = gql`
signup( signup(
email: $email email: $email
password: $password password: $password
name: $name username: $name
) { ) {
token token
} }

View File

@@ -1,8 +1,10 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import './styles/index.css'; import './styles/index.css';
import { AUTH_TOKEN } from './constants';
import App from './components/App'; import App from './components/App';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import { setContext } from '@apollo/client/link/context';
// import * as serviceWorker from './serviceWorker'; // import * as serviceWorker from './serviceWorker';
import { import {
@@ -16,8 +18,19 @@ const httpLink = createHttpLink({
uri: 'http://localhost:4000/graphql' uri: 'http://localhost:4000/graphql'
}); });
const authLink = setContext((_, { headers }) => {
const token = localStorage.getItem(AUTH_TOKEN);
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : ''
}
};
});
const client = new ApolloClient({ const client = new ApolloClient({
link: httpLink, link: authLink.concat(httpLink),
// link: httpLink,
cache: new InMemoryCache() cache: new InMemoryCache()
}); });

21
server/src/models/user.js Normal file
View File

@@ -0,0 +1,21 @@
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
const UserSchema = new Schema({
username: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
deleted: {
type: Boolean,
required: false
}
});
export default mongoose.model('user', UserSchema);

View File

@@ -1,7 +1,11 @@
// import Appointment from '../../client/src/components/Appointment.js'; // import Appointment from '../../client/src/components/Appointment.js';
import Product from './models/product.js'; import Product from './models/product.js';
import Appointment from './models/appointment.js'; import Appointment from './models/appointment.js';
import User from './models/user.js'
// import { createAppointment } from './resolvers/Mutation.js'; // import { createAppointment } from './resolvers/Mutation.js';
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import dotenv from 'dotenv';
export const resolvers = { export const resolvers = {
Query: { Query: {
@@ -11,8 +15,58 @@ export const resolvers = {
async allProducts() { async allProducts() {
return await Product.find(); return await Product.find();
}, },
async allUsers() {
return await User.find();
},
}, },
Mutation: { Mutation: {
async signup(root, {
input
}) {
console.log(input.password);
input.password = await bcrypt.hash(input.password, 10);
const user = await User.create(input);
const token = jwt.sign({ userId: user.id }, process.env.APP_SECRET);
return {
token,
user
};
},
async login(root, {
email, password
}) {
const user = await User.findOne({
email: email
});
if (!user) {
throw new Error('No such user found');
}
const pwd = await bcrypt.hash(password, 10);
console.log(pwd);
console.log(user.password);
const valid = await bcrypt.compare(
password,
user.password
);
if (!valid) {
throw new Error('Invalid password');
}
const token = jwt.sign({ userId: user.id }, APP_SECRET);
return {
token,
user
};
},
async createAppointment(root, { async createAppointment(root, {
input input
}) { }) {

View File

@@ -8,6 +8,7 @@ type Query {
): Feed! ): Feed!
allProducts: [Product] allProducts: [Product]
allAppointments: [Appointment] allAppointments: [Appointment]
allUsers: [User]
users: [User!]! users: [User!]!
} }
@@ -39,9 +40,7 @@ type Mutation {
_id: ID! _id: ID!
) : Product ) : Product
signup( signup(
email: String! input: UserInput
password: String!
name: String!
): AuthPayload ): AuthPayload
login( login(
email: String!, email: String!,
@@ -57,19 +56,26 @@ type Subscription {
newFollow: Follow newFollow: Follow
} }
#User Schemas
type User {
_id: ID!
username: String!
email: String!
password: String!
# appointments: [Appointment!]!
}
input UserInput{
username: String!
email: String!
password: String!
# appointments: [Appointment!]!
}
type AuthPayload { type AuthPayload {
token: String token: String
user: User user: User
} }
type User { # Appointment schemas
_id: ID!
name: String!
email: String!
appointments: [Appointment!]!
}
# Appointment model
type Appointment { type Appointment {
_id: ID! _id: ID!
title: String! title: String!
@@ -91,8 +97,13 @@ input AppointmentInput {
timeStart: Time! timeStart: Time!
timeEnd: Time! timeEnd: Time!
} }
input AppointmentOrderByInput {
description: Sort
url: Sort
createdAt: Sort
}
# Product model # Product schemas
type Product { type Product {
_id: ID! _id: ID!
title: String! title: String!
@@ -103,23 +114,17 @@ input ProductInput {
qty: Int qty: Int
} }
# Follow schemas
type Follow { type Follow {
_id: ID! _id: ID!
appointment: Appointment! appointment: Appointment!
user: User! user: User!
} }
# General-purpose schemas
input AppointmentOrderByInput {
description: Sort
url: Sort
createdAt: Sort
}
enum Sort { enum Sort {
asc asc
desc desc
} }
scalar DateTime scalar DateTime
scalar Time scalar Time