Skip to content

Commit

Permalink
Merge pull request #205 from agiledev-students-fall2023/AddDynamicBorder
Browse files Browse the repository at this point in the history
add front end and back end for dynamic historical borderline
  • Loading branch information
Ceiceiceii authored Jan 6, 2024
2 parents 1a2769e + 4b6b45d commit dfbe6ba
Show file tree
Hide file tree
Showing 25 changed files with 722 additions and 219 deletions.
172 changes: 130 additions & 42 deletions back-end/src/app.mjs
Original file line number Diff line number Diff line change
@@ -1,47 +1,133 @@
import express from "express";
import url from "url";
import path from "path";
import express from 'express';
import url from 'url';
import path from 'path';
import multer from "multer";
import cors from "cors";
import dotenv from "dotenv";
import "dotenv/config";
import morgan from "morgan";
import mongoose from "mongoose";
import { body } from "express-validator";
import passport from "passport";
// config
import JwtStrategy from "./config/JwtStrategy.mjs";
import cors from 'cors';
import dotenv from 'dotenv';
import "dotenv/config"
import morgan from 'morgan';
import session from 'express-session';
import mongoose from 'mongoose';
import { body, validationResult } from 'express-validator';
import jwt from 'jsonwebtoken';
import passport from 'passport'
import CustomJwtStrategy from './config/jwt-config.mjs';
// routes
import loginRouter from "./routes/loginRouter.mjs";
import registerRouter from "./routes/registerRouter.mjs";
import changeusernameRouter from "./routes/changeusernameRouter.mjs";
import forgetpasswordRouter from "./routes/forgetpasswordRouter.mjs";
import delaccountRouter from "./routes/delaccountRouter.mjs";
import resetpasswordRouter from "./routes/resetpasswordRouter.mjs";
import resetemailRouter from "./routes/resetemailRouter.mjs";
import searchArtsRouter from "./routes/searchArtsRouter.mjs";
import {
addFavListRouter,
favListRouter,
getArts,
} from "./routes/modifyFavListRouter.mjs";

export function getExpress() {
const app = express();

// config environmental variables
dotenv.config({ silent: true });

// use the morgan middleware to log all incoming http requests
app.use(morgan("dev"));

// use express's builtin body-parser middleware to parse any data included in a request
app.use(express.json()); // decode JSON-formatted incoming POST data
app.use(express.urlencoded({ extended: true })); // decode url-encoded incoming POST data

// serve static files
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
app.use("/static", express.static(path.join(__dirname, "public")));
import loginRouter from './routes/loginRouter.mjs';
import registerRouter from './routes/registerRouter.mjs';
import changeusernameRouter from './routes/changeusernameRouter.mjs';
import forgetpasswordRouter from './routes/forgetpasswordRouter.mjs';
import delaccountRouter from './routes/delaccountRouter.mjs';
import resetpasswordRouter from './routes/resetpasswordRouter.mjs';
import resetemailRouter from './routes/resetemailRouter.mjs';
import searchArtsRouter from './routes/searchArtsRouter.mjs';
import getBorderRouter from './routes/borderDataRouter.mjs';

import {addFavListRouter,favListRouter, getArts} from './routes/modifyFavListRouter.mjs'

const app = express();

// use the morgan middleware to log all incoming http requests
app.use(morgan("dev"));

// use express's builtin body-parser middleware to parse any data included in a request
app.use(express.json()); // decode JSON-formatted incoming POST data
app.use(express.urlencoded({ extended: true })); // decode url-encoded incoming POST data

// serve static files
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
app.use("/static", express.static(path.join(__dirname, 'dist')));
dotenv.config({ path: path.resolve(__dirname, '../.env') });

// cors
const corsOptions = {
credentials: true,
origin: process.env.CLIENT_URL.replace(/\/$/, ""),
// origin: 'http://10.19.137.49:5173/',
methods: ['GET', 'PUT', 'POST', 'DELETE', 'PATCH']
}
app.use(cors(corsOptions));



console.log(process.env.CLIENT_URL);
// Connect to MongoDB
mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => {
console.log('Connected to MongoDB...');
})
.catch(err => console.error('Could not connect to MongoDB...', err));



// session to auto-save user data (like id) when they login
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized:true,
cookie: {httpOnly: true, secure: process.env.NODE_ENV==="production"}
}))
console.log('Session secret:', process.env.SESSION_SECRET);

// jwt strategy
passport.use(CustomJwtStrategy)

// initialize passport
app.use(passport.initialize())

// routes that does not need authentication
// app.post("/getpiece", getpieceRouter);
app.post("/register", registerRouter)
app.post("/login", loginRouter);

// Validation rules for routers
const usernameValidationRules = [
body('newUsername')
.trim() // Removes leading and trailing spaces
.isLength({ min: 3, max: 30 }) // Sets a length range for the username
.withMessage('Username must be between 3 and 30 characters long.')
.matches(/^[a-zA-Z0-9_]+$/) // Regular expression to allow letters, numbers, and underscores
.withMessage('Username must contain only letters, numbers, and underscores.')
];
const emailValidationRules = [
body('newEmail')
.trim() // Removes leading and trailing spaces
.isEmail() // Checks if the input is an email
.withMessage('Please enter a valid email address.')
.normalizeEmail() // Optionally, normalize the email address
];
const passwordValidationRules = [
// Validate new password
body('newPassword')
.isLength({ min: 8 }) // Set a minimum length for the new password
.withMessage('Password must be at least 8 characters long')
.matches(/\d/) // Ensure the password contains a number
.withMessage('Password must contain at least one number')
.matches(/[a-zA-Z]/) // Ensure the password contains a letter
.withMessage('Password must contain at least one letter')
// Optionally, include checks for special characters or uppercase letters
];

// routes that needs authentication
// Account routes
app.patch("/changeusername", usernameValidationRules, changeusernameRouter); //Finished
app.patch("/resetemail", emailValidationRules, resetemailRouter); //Finished
app.post("/forget", forgetpasswordRouter);
app.patch("/resetpassword", passwordValidationRules, resetpasswordRouter); //Finished
app.delete("/delaccount", delaccountRouter); //Finished

// Favorites list routes
app.post('/addFavorite', addFavListRouter);//finished
app.get('/getfavlist', favListRouter);
app.get('/getArts', getArts);//finished
app.get('/searchArts', searchArtsRouter);
// app.post('/favlist/remove',removeFavListRouter);


app.get('/getBorder', getBorderRouter);
// export the express app we created to make it available to other modules
export default app;



// serve static files
Expand Down Expand Up @@ -131,5 +217,7 @@ mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTop

// app.post('/favlist/remove',removeFavListRouter);


app.get('/getBorder', getBorderRouter);
// export the express app we created to make it available to other modules
// export default app;
3 changes: 0 additions & 3 deletions back-end/src/models/Artwork.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// Import statements
// import bcrypt from 'bcryptjs';

import mongoose from 'mongoose';

const { Schema, model } = mongoose;
Expand Down
35 changes: 35 additions & 0 deletions back-end/src/models/Border.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import mongoose from 'mongoose';
const { Schema, model } = mongoose;

const FeatureSchema = new Schema({
type: { type: String, required: true },
properties: {
NAME: String,
ABBREVN: String,
INFO_UR: String,
SUBJECTO: String,
BORDERPRECISION: Number,
PARTOF: String,
},
geometry: {
type: { type: String, required: true },
coordinates: [[[Number]]]
}
});

const BorderSchema = new Schema({
_id: Schema.Types.ObjectId,
type: { type: String, required: true },
name: { type: String, required: true },
crs: {
type: { type: String, required: true },
properties: {
name: { type: String, required: true }
}
},
features: [FeatureSchema]
});

const Border = model('Border', BorderSchema, 'borders');

export default Border;
41 changes: 41 additions & 0 deletions back-end/src/routes/borderDataRouter.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import axios from "axios";

const axiosMongoDB = axios.create({
baseURL: process.env.MONGODB_DATA_API,
headers: {
'Content-Type': 'application/json',
'api-key': process.env.MONGODB_API_KEY
}
});

export const getBorderData = async (req, res) => {
try {
const name = req.query.name;
console.log(name);

// Make a request to the MongoDB Data API
const response = await axiosMongoDB.post('/action/find', {
collection: 'borderData',
database: 'bakerdb',
dataSource: 'bakerdb',
filter: {
name: name
}
});

if (response.data.documents) {
let data = response.data.documents[0];
console.log(data)

res.json(data);

} else {
res.status(404).send('Data not found');
}
} catch (error) {
console.error(error);
res.status(500).send('Server error');
}
};

export default getBorderData;
35 changes: 5 additions & 30 deletions back-end/src/routes/modifyFavListRouter.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const getArts = async (req, res) => {
const { timeRange, location } = req.query;
const startYear = parseInt(timeRange[0]);
const endYear = parseInt(timeRange[1]);
console.log(req.query);
// console.log(req.query);
const filter = {
Year: { $gte: startYear, $lte: endYear },
geoLocation: {
Expand All @@ -65,9 +65,9 @@ export const getArts = async (req, res) => {

try {
const response = await axiosMongoDB.post('/action/find', {
collection: 'arts', // Replace with your collection name
database: 'bakerdb', // Replace with your database name
dataSource: 'bakerdb', // Replace with your cluster name
collection: 'arts',
database: 'bakerdb',
dataSource: 'bakerdb',
filter: filter,
limit: 15
});
Expand Down Expand Up @@ -113,7 +113,7 @@ export const favListRouter = async (req, res) => {

// Fetch artworks from MongoDB Data API
const artworksResponse = await axiosMongoDB.post('/action/find', {
collection: 'arts', // Replace with your actual artwork collection name
collection: 'arts',
database: 'bakerdb',
dataSource: 'bakerdb',
filter: { '_id': { $in: objectIds } }
Expand All @@ -134,31 +134,6 @@ export const favListRouter = async (req, res) => {
}
};

// const user = await User.findOne({ uuid: userID });

// if (!user) {
// return res.status(404).send({ message: 'User not found' });
// }
// console.log(user.favorites);
// const favorites = await Artwork.find({
// '_id': { $in: user.favorites }
// });

// const favoritesWithFlag = favorites.map(artwork => {
// return {
// ...artwork._doc, // Spread the existing artwork properties
// isFavorited: true // Set isFavorited to true
// };
// });

// res.status(200).send(favoritesWithFlag);
// } catch (error) {
// console.error(error);
// res.status(500).send({ message: 'Internal server error' });
// }
// };



export const addFavListRouter = async (req, res) => {
// Check if the Authorization header is present
Expand Down
6 changes: 3 additions & 3 deletions back-end/src/routes/searchArtsRouter.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ const searchArtsRouter = async (req, res) => {
// console.log(artworks);
// return res.json(artworks);
const response = await axiosMongoDB.post('/action/find', {
collection: 'arts', // Replace with your actual artwork collection name
database: 'bakerdb', // Replace with your actual database name
dataSource: 'bakerdb', // Replace with your actual cluster name
collection: 'arts',
database: 'bakerdb',
dataSource: 'bakerdb',
filter: {
Year: { $gte: startYear, $lte: endYear },
$or: [
Expand Down
2 changes: 0 additions & 2 deletions back-end/src/routes/sendEmail.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ const sendRecoveryEmail = async (email, token) => {
},
});

// The URL to your password reset page in your frontend app
// Replace 'your-frontend-domain.com' with your actual domain and adjust the path as needed
const resetUrl = `http://localhost:3000/resetpassword?token=${token}`;

let mailOptions = {
Expand Down
Loading

0 comments on commit dfbe6ba

Please sign in to comment.