Skip to content

Commit

Permalink
Merge pull request #34 from SENG-499-Company-3/user_api_data_flow
Browse files Browse the repository at this point in the history
Backend #30: setup basic router/controller/model  data flow
  • Loading branch information
KjartanE authored May 30, 2023
2 parents 884ebbd + a50b9a9 commit 9e3257d
Show file tree
Hide file tree
Showing 13 changed files with 393 additions and 181 deletions.
20 changes: 15 additions & 5 deletions .env
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@

# ------------------------------------------------------------------------------
# Express Server
# ------------------------------------------------------------------------------
PORT=3001
MONGO_INITDB_ROOT_USERNAME=admin
MONGO_INITDB_ROOT_PASSWORD=admin
MONGO_INITDB_DATABASE=schedule_backend
MONGO_HOST=10.9.0.3
MONGO_PORT=27017

# ------------------------------------------------------------------------------
# Mongo Database
# ------------------------------------------------------------------------------
DB_HOST=10.9.0.3
DB_ADMIN=admin
DB_ADMIN_PASS=admin
DB_USER_API=
DB_USER_API_PASS=
DB_PORT=27017
DB_DATABASE=schedule_backend
63 changes: 60 additions & 3 deletions api/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"express": "^4.18.2",
"helmet": "^7.0.0",
"mongodb": "^5.5.0",
"mongoose": "^7.2.1",
"morgan": "^1.10.0"
}
}
209 changes: 47 additions & 162 deletions api/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,181 +1,66 @@
import { MongoClient, ServerApiVersion, Document } from 'mongodb';
import cors from 'cors';
import helmet from 'helmet';
// import helmet from 'helmet';
import morgan from 'morgan';
import express from 'express';
import bodyParser from 'body-parser';

// Placeholder for types I haven't come up with yet
type TODO = undefined;

// how many minutes a class can run for
type ClassLength = 50 | 80 | 180;

// what days is a class running
type ClassDays = 'MTW' | 'TH' | 'ONCE';

// range of time and day that a class or professor is available
type Availability = Array<{ day: Day; times: Array<TimeRange> }>;

// start and end of a time block
type TimeRange = { start: number; end: number };

type Day = 'Monday' | 'Tuesday' | 'Wednsday' | 'Thursday' | 'Friday' | 'Saturday' | 'Sunday';

// Programs that our system is planned to support
type Program = 'SENG' | 'CSC' | 'ECE' | 'BIOMED';

interface Room extends Document {
name: string;
size: number;
speakerSystem: boolean;
projector: boolean;
cameras: boolean;
}

interface Professor extends Document {
name: string;
timesICanTeach: Availability;
timesIWant2Teach: Availability;
}

// interface SatisfiedCourse {
// course: Course;
// professor: Professor;
// room: Room;
// }

// TODO check that this starts after 8am and ends before 10pm
// const validClassTime( time: Availability ): boolean

interface Course extends Document {
name: string;
inPerson: boolean;
days: ClassDays;
length: ClassLength;
requiredFor: Array<Program>;
weeksOffered: TODO;
}

/*
Basic structure for any request that requires inserting a type into the database based on the request
*/
async function parseAndStore<T extends Document>(body: T, collection: string): Promise<string> {
try {
console.log(body);
const course: T = body;

// Connect the client to the server (optional starting in v4.7)
await mongoClient.connect();
// Send a ping to confirm a successful connection
await mongoClient.db('admin').command({ ping: 1 });
console.log('Pinged your deployment. You successfully connected to MongoDB!');
const classes = mongoClient.db('schedule_backend').collection<T>(collection);

const result = await classes.insertOne(
// TODO casting to any since I couldn't figure out how to satisfy this
<any>course
);
await mongoClient.close();
return `Inserted ${course} with id ${result.insertedId}`;
} catch (e) {
await mongoClient.close();
return `Failed ${e}`;
}
}

const mongoHost: string = process.env.MONGO_HOST ? process.env.MONGO_HOST : 'localhost';

const mongoUri = 'mongodb://admin:admin@' + mongoHost + ':27017';
console.log(mongoUri);

// Create a MongoClient with a MongoClientOptions object to set the Stable API version
const mongoClient = new MongoClient(mongoUri, {
serverApi: {
version: ServerApiVersion.v1,
strict: true,
deprecationErrors: true
}
});
const user = require('./routes/user.routes');

const app = express();
// adding Helmet to enhance your API's security
app.use(helmet());

// using bodyParser to parse JSON bodies into JS objects
app.use(bodyParser.json());
// adding Helmet to enhance your API's security
// app.use(helmet());

// enabling CORS for all requests
// enabling CORS for all local requests
// var corsOptions = {
// origin: 'http://localhost:10.9.0.4'
// };
// app.use(cors(corsOptions));
app.use(cors());

// adding morgan to log HTTP requests
app.use(morgan('combined'));
// parse requests of content-type - application/json
app.use(express.json());

const port = 3001;
// parse requests of content-type - application/x-www-form-urlencoded
app.use(express.urlencoded({ extended: true }));

// TODO GET SCHEDULE
// Gets the most recently generated schedule
//
// Example Curl Command For Testing
// curl http://localhost:3000/SCHEDULE
app.get('/SCHEDULE', async (_req, res) => {
try {
// Connect the client to the server (optional starting in v4.7)
await mongoClient.connect();
// Send a ping to confirm a successful connection
await mongoClient.db('admin').command({ ping: 1 });
console.log('Pinged your deployment. You successfully connected to MongoDB!');
const classes = mongoClient.db('schedule_backend').collection<Course>('courses');
const newCourse: Course = {
days: 'MTW',
inPerson: false,
length: 50,
name: 'ECE 696',
requiredFor: ['ECE'],
weeksOffered: undefined
};
const result = await classes.insertOne(newCourse);
res.send(`Inserted ${newCourse} with id ${result.insertedId}`);
} catch (e) {
console.log(`Failed ${e}`);
} finally {
// Ensures that the client will close when you finish/error
await mongoClient.close();
}
});

// POST PROFESSOR
// Adds a new professor to the database
app.post('/PROFESSOR', async (req, res) => {
res.send(await parseAndStore<Professor>(req.body, 'professor'));
});

// POST COURSE
// Adds a new course to the database
//
// Example Curl Command For Testing
// curl -H "Content-Type: application/json" -X POST -d '{
// "days": "MTW",
// "inPerson": false,
// "length": 50,
// "name": "ECE 696",
// "requiredFor": ["ECE"]
// }' http://localhost:3000/COURSE
// adding morgan to log HTTP requests
app.use(morgan('combined'));

app.post('/COURSE', async (req, res) => {
res.send(await parseAndStore<Course>(req.body, 'courses'));
// Connect to the database
const db = require('./models');
db.mongoose
.connect(db.url, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
console.log('Connected to the database!');
})
.catch((err) => {
console.log('Cannot connect to the database!', err);
process.exit();
});

app.use('/user', user);

// Global error handling
// eslint-disable-next-line no-unused-vars
app.use((err, _req, res, next) => {
console.log('err', err);
res.status(500).send('Uh oh! An unexpected error occured.');
});

// POST ROOM
// Adds a new class room to the database
app.post('/ROOM', async (req, res) => {
res.send(await parseAndStore<Room>(req.body, 'rooms'));
// simple route
app.get('/', (req, res) => {
res.json({ message: 'Welcome to the backend :3' });
});

app.get('/', (req, res) => {
res.send('Hello Hot reload WOohoo!');
app.post('/', (req, res) => {
console.log('req.body', req.body);
res.json({ message: `Basic post request: ${req.body}` });
});

app.listen(port, () => {
console.log(`listening on ${port}`);
// // set port, listen for requests
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
console.log(`Server is running on port: ${PORT}`);
});
10 changes: 10 additions & 0 deletions api/src/config/db.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const DB_HOST = process.env.DB_HOST || 'localhost';
const DB_PORT = Number(process.env.DB_PORT);
const DB_USERNAME = process.env.DB_ADMIN;
const DB_PASSWORD = process.env.DB_ADMIN_PASS;

export default {
database: {
url: `mongodb://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}`
}
};
Loading

0 comments on commit 9e3257d

Please sign in to comment.