Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…andIndigenousMarketplace

merging diverged branches
  • Loading branch information
Harley Ewert committed Feb 29, 2024
2 parents 39f5bf5 + c1a4c23 commit d822f6c
Show file tree
Hide file tree
Showing 21 changed files with 218 additions and 108 deletions.
28 changes: 28 additions & 0 deletions backend/controllers/AdminController.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,33 @@ const createAdminMiddleware = async (req, res, next) => {
}
};

const authenticateAdmin = async (req, res, next) => {
try {
const {password} = req.body;
const {admin} = res.locals;

if (admin === undefined) {
return res.status(401).json({message: 'Unauthorized: Admin'});
}

const match = await bcrypt.compare(password, admin.password);

if (match) {
res.locals.data = {
'message': 'Login successful',
'status': 'success',
};
next();
} else {
res.status(401).json({message: 'Incorrect admin email or password.'});
}
} catch (err) {
console.log(err);
res.status(500).json({error: 'Internal Server Error'});

}
}

module.exports = {
getEventRequests,
getAllEventRequests,
Expand All @@ -181,4 +208,5 @@ module.exports = {
processEventRequest,
getAdminByEmail,
createAdminMiddleware,
authenticateAdmin,
};
9 changes: 7 additions & 2 deletions backend/controllers/AuthController.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ const signToken = async (req, res, next) => {
// Sign the token with JWT_SECRET
const token = await jwt.sign(res.locals.vendor, process.env.JWT_SECRET);
// Return the token in a cookie
res.cookie('auth', token, {httpOnly: true, secure: false});
res.cookie('auth', token, {secure: false});

console.log('Token:', token);

next();
};
Expand Down Expand Up @@ -58,11 +60,14 @@ const signAdminToken = async (req, res, next) => {
return res.status(401).json({message: 'Unauthorized: Admin'});
}

// Remove admin password from cookie
delete res.locals.admin['password'];

// Sign the token with JWT_SECRET
const token = await jwt.sign(res.locals.admin, process.env.JWT_SECRET);

// Return the token in a cookie
res.cookie('auth_pim', token, {httpOnly: true, secure: false});
res.cookie('auth_pim', token, {secure: false});

next();
};
Expand Down
17 changes: 16 additions & 1 deletion backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,22 @@ app.use(errorHandler({ dumbExceptions: true, showStack: true }));

// Allows cross origin requests
const cors = require('cors');
app.use(cors());

// Allowed origins
const allowedOrigins = ['http://localhost:3000', 'http://localhost:4000'];

// CORS options to dynamically match the allowed origins and allow credentials
const corsOptionsDelegate = function (req, callback) {
let corsOptions;
if (allowedOrigins.indexOf(req.header('Origin')) !== -1) {
corsOptions = { origin: true, credentials: true }; // Reflect (enable) the requested origin in the CORS response
} else {
corsOptions = { origin: false }; // Disable CORS for this request
}
callback(null, corsOptions); // Callback expects two parameters: error and options
};

app.use(cors(corsOptionsDelegate));

// Parses cookies attached to the client request object
const cookieParser = require('cookie-parser');
Expand Down
5 changes: 2 additions & 3 deletions backend/routes/AdminRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const {
processEventRequest,
getAdminByEmail,
createAdminMiddleware,
authenticateAdmin,
} = require('../controllers/AdminController');

const sendSuccessResponse = require('../middleware/successResponse');
Expand All @@ -37,9 +38,7 @@ router.post('/violations/:vendorId', verify('admin'), createVendorViolation, sen

router.delete('/violations/:violationId', verify('admin'), deleteVendorViolation, sendSuccessResponse);

router.post('/login', getAdminByEmail, signAdminToken, (req, res) => {
res.status(200).json({status: 'success'});
});
router.post('/login', getAdminByEmail, authenticateAdmin, signAdminToken, sendSuccessResponse);

// UNFINISHED: Create an admin account
// Useful for creating an admin account for testing purposes. Password in database needs to be hashed for login to work properly.
Expand Down
4 changes: 1 addition & 3 deletions backend/routes/VendorRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ router.get('/', getVendors, sendSuccessResponse);
router.get('/:vendorId', getVendorById, sendSuccessResponse);

// Creates a new vendor
router.post('/', createVendor, (req, res) => {
res.status(200).json({status: 'success'});
});
router.post('/', createVendor, sendSuccessResponse);

// Create Vendor event request
router.post('/events/request', verify('vendor'), createEventRequest, sendSuccessResponse);
Expand Down
24 changes: 10 additions & 14 deletions frontend/src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,15 @@ import MockVendorService from './services/MockServices/MockVendorService.js';
import EventsService from './services/Events/EventsService.js';
import VendorsService from './services/Vendors/VendorsService.js';

import {handleLoginVendor} from './services/handleLogin.js';
import {handleRegister} from './services/handleRegister.js';

import HttpClient from './services/HttpClient.js';

// Import configuration variables
import config from './config.js';

// Import HttpClient
import HttpClient from './services/HttpClient.js';

let eventService;
let vendorService;
let httpClient;

if (config.environment == 'dev') {
MockVendorService.init();
Expand All @@ -49,15 +48,12 @@ if (config.environment == 'dev') {
// Load base url for the backend
const baseUrl = config.baseUrl;

// Create HttpClient
const httpClient = new HttpClient(baseUrl);
// Initialize HttpClient
httpClient = new HttpClient(baseUrl);

// Initilize Services
const eventsService = new EventsService(httpClient);
const vendorsService = new VendorsService(httpClient);

eventService = eventsService;
vendorService = vendorsService;
eventService = new EventsService(httpClient);
vendorService = new VendorsService(httpClient);
}

const router = createBrowserRouter([
Expand All @@ -71,12 +67,12 @@ const router = createBrowserRouter([
},
{
path: '/login',
element: <Login loginService={handleLoginVendor} />,
element: <Login vendorService={vendorService} />,

},
{
path: '/register',
element: <Register registerService={handleRegister} />,
element: <Register vendorService={vendorService} />,
},
{
path: '/reset_password',
Expand Down
9 changes: 0 additions & 9 deletions frontend/src/objects/Permission.js

This file was deleted.

33 changes: 6 additions & 27 deletions frontend/src/objects/User.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,20 @@
// import Permission from './Permission.js';
import Cookies from 'js-cookie';
import {jwtDecode} from 'jwt-decode';

/*
Storage mechanism for the currently logged-in user.
*/
export default class User {
constructor(id, name, email, isadmin, phone_number=null, website=null) {
constructor(id, name, email, isadmin, phoneNumber=null, website=null) {
this.id = id;
this.name = name;
this.email = email;
this.isadmin = isadmin;
this.phone_number = phone_number;
this.phoneNumber = phoneNumber;
this.website = website;
}

// isAdmin() {
// return this.permission === Permission.Admin;
// }

// isVendor() {
// return this.permission === Permission.Vendor;
// }

static createFromCookie() {
if (Cookies.get('auth_pim') != undefined) {
const cookie = Cookies.get('auth_pim');
const decode = jwtDecode(cookie);

return User(decode.admin_id, decode.name, decode.email, true, null, null);
} else if ( Cookies.get('auth') != undefined ) {
const cookie = Cookies.get('auth');
const decode = jwtDecode(cookie);

return User(decode.vendor_id, decode.name, decode.email, false, decode.phone_number, decode.website);
} else {
return undefined;
}
static newUserFromCookie(cookie, isadmin) {
const decode = jwtDecode(cookie);
if (isadmin) return new User(decode.admin_id, decode.name, decode.email, isadmin, null, null);
return new User(decode.vendor_id, decode.name, decode.email, isadmin, decode.phone_number, decode.website);
}
}
21 changes: 11 additions & 10 deletions frontend/src/routes/login.jsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@

import React, {useState} from 'react';
import logo from './../assets/PIM_logo_black.png';
import {Link, useNavigate} from 'react-router-dom';
import {useContext} from 'react';
import {Context} from '../services/context';
import PropTypes from 'prop-types';
import User from '../objects/User';

export default function Login({loginService}) {
export default function Login({vendorService}) {
const [email, setEmail] = useState('');
const [pass, setPass] = useState('');
const navigate = useNavigate();
const {setMessage, setBad, setUser} = useContext(Context);

async function handleLogin() {
const data = {email: email, password: pass};
const loginResponse = await loginService(data);

console.log(loginResponse);
const loginResponse = await vendorService.authenticateVendor(data);

if (loginResponse != undefined) {
if (loginResponse.status == 200) {
setUser(User.createFromCookie());
setUser(vendorService.httpClient.user);
setBad(false);
setMessage('Logged in succesfully');
navigate('/events');
console.log('Logged in!');
console.log('Logged in as user: ', vendorService.httpClient.user);
} else if (loginResponse.status == 401) {
setBad(true);
setMessage('Bad Request. Check username and password.');
Expand Down Expand Up @@ -53,7 +49,7 @@ export default function Login({loginService}) {
<div className="m-2">
<input
className="p-1 rounded-lg w-3/4 drop-shadow-md"
placeholder="Username"
placeholder="Email"
onChange={(e) => setEmail(e.target.value)}>
</input>
</div>
Expand Down Expand Up @@ -87,5 +83,10 @@ export default function Login({loginService}) {
}

Login.propTypes = {
loginService: PropTypes.func.isRequired,
vendorService: PropTypes.shape( {
authenticateVendor: PropTypes.func.isRequired,
httpClient: PropTypes.shape( {
user: PropTypes.object,
}).isRequired,
}).isRequired,
};
15 changes: 10 additions & 5 deletions frontend/src/routes/register.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import {Context} from '../services/context';
import Alert from '../components/alert.jsx';
import {useContext} from 'react';
import PropTypes from 'prop-types';
import Vendor from '../objects/Vendor.js';


export default function Register({registerService}) {
export default function Register({vendorService}) {
const [name, setName] = useState('');
const [pass, setPass] = useState('');
const [pass2, setPass2] = useState('');
Expand All @@ -19,9 +20,11 @@ export default function Register({registerService}) {
const navigate = useNavigate();

async function handleRegister() {
const data = {name: name, email: email, password: pass, website: website, phoneNumber: phone};
const vendor = new Vendor(name, email, website, phone);

if (await registerService(data)) {
const response = await vendorService.createVendor(vendor, pass);
console.log(response);
if (response) {
setBad(false);
setMessage('Registered succesfully');
console.log('Registered!');
Expand Down Expand Up @@ -60,7 +63,7 @@ export default function Register({registerService}) {
</div>

<div className="m-2">
<input className="p-1 rounded-lg w-3/4" placeholder="Reenter password" type="password" onChange={(e) => setPass2(e.target.value)}></input>
<input className="p-1 rounded-lg w-3/4" placeholder="Re-enter password" type="password" onChange={(e) => setPass2(e.target.value)}></input>
</div>

{pass !== pass2 && <Alert content="Passwords match" bad ={true}/>}
Expand All @@ -79,5 +82,7 @@ export default function Register({registerService}) {
}

Register.propTypes = {
registerService: PropTypes.func.isRequired,
vendorService: PropTypes.shape({
createVendor: PropTypes.func.isRequired,
}).isRequired,
};
24 changes: 24 additions & 0 deletions frontend/src/services/Admins/AdminsRepository.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export default class AdminsRepository {
constructor(httpClient) {
this.httpClient = httpClient;
}
async authenticateAdmin(adminData) {
try {
const response = await this.httpClient.axiosInstance.post('admins/login', adminData);
// this.httpClient.processCookie(response.headers['set-cookie'][0]);
return response;
} catch (error) {
console.error('Error logging in admin:');
}
}

async createAdmin(adminData) {
try {
const response = await this.httpClient.axiosInstance.post('/admins', adminData);
return response.data;
} catch (error) {
console.error('Error creating admin:');
throw error;
}
}
}
17 changes: 17 additions & 0 deletions frontend/src/services/Admins/AdminsService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import AdminsRepository from './AdminsRepository.js';

export default class AdminsService {
constructor(httpClient) {
this.httpClient = httpClient;
this.adminsRepository = new AdminsRepository(httpClient);
}

async authenticateAdmin(adminData) {
const response = await this.adminsRepository.authenticateAdmin(adminData);
return response;
}

async createAdmin(adminData) {
return await this.adminsRepository.createAdmin(adminData);
}
}
1 change: 1 addition & 0 deletions frontend/src/services/Events/EventsService.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Event from '../../objects/Event.js';

export default class EventsService {
constructor(httpClient) {
this.httpClient = httpClient;
this.eventsRepository = new EventsRepository(httpClient);
}

Expand Down
Loading

0 comments on commit d822f6c

Please sign in to comment.