diff options
| -rw-r--r-- | README.md | 1 | ||||
| -rw-r--r-- | deliverables/iteration-02.plan.md | 138 | ||||
| -rw-r--r-- | web/README.md | 30 | ||||
| -rw-r--r-- | web/app.js | 26 | ||||
| -rw-r--r-- | web/models/mockpoints.js | 32 | ||||
| -rw-r--r-- | web/models/points.js | 32 | ||||
| -rw-r--r-- | web/public/javascripts/map.js | 91 | ||||
| -rw-r--r-- | web/routes/index.js | 98 | ||||
| -rw-r--r-- | web/routes/sse.js | 15 | ||||
| -rw-r--r-- | web/views/map.pug | 16 |
10 files changed, 350 insertions, 129 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..acdfd5a --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# SOME README diff --git a/deliverables/iteration-02.plan.md b/deliverables/iteration-02.plan.md new file mode 100644 index 0000000..80aa340 --- /dev/null +++ b/deliverables/iteration-02.plan.md @@ -0,0 +1,138 @@ +# Helpthehomeless by The Dream Team + + > _Note:_ This document is meant to be written during (or shortly after) your initial planning meeting. + > It does not really make sense for you to edit this document much (if at all) while working on the project - Instead, at the end of the planning phase, you can refer back to this document and decide which parts of your plan you are happy with and which parts you would like to change. + + +## Iteration XX + + * Start date: February 15, 2019 + * End date: March 5, 2019 + +## Process + +#### Roles & responsibilities + +Describe the different roles on the team and the responsibilities associated with each role. + * Roles should reflect the structure of your team and be appropriate for your project. Not necessarily one role to one team member. + +List each team member and: + * A description of their role(s) and responsibilities including the components they'll work on and non-software related work + * 3 technical strengths and weaknesses each (e.g. languages, frameworks, libraries, development methodologies, etc.) + + +| Name | Responsibilities | Strengths | Weaknesses | +|-----------------|----------------------------------------|------------------------------|--------------------------------| +| Andrew Mihai | "front end", meetings note taker | Java, MVC methodology, Swift | React, Databases, Javascript | +| Ivan Shen | "front end", Testing, Trello moderator | Java, JavaScript, Testing | Expo, Swift, SQL, React | +| Kumar Damani | Scrum master, server side, API | web, sql, kanban | React, graphic design, apps | +| Mohammed Ahmed | "back end", database | Java, Kanban, Node.js | React, Swift, Data Management | +| Samarth Agarwal | "back end", database | Java, Databases, HTML/CSS | JavaScript, Node.js, React | + +#### Team Rules + +Describe your team's working culture. + +Communications: + * What is the expected frequency? What methods/channels are appropriate? +> We have a slack channel "logistics" where we discuss anything related to scheduling, general communication. +> Anything related to a task, is discussed in the comment section of the corresponding trello card. +> Code reviews are discussed in the comment section of the pull request. +> A github wiki is also maintained for documentation. +> Frequency is ~3-5 hrs for each of them. + +Meetings: + * How are people held accountable for attending meetings, completing action items? Is there a moderator or process? +> We hold an in-person sprint meeting every Tuesday and everyone is expected to attend that meeting. We understand that sometimes other commitments might take priority and the person may not be able to attend in-person, so that person can also attend via video chat over Discord. +> During the meetings, the scrum master goes over each item in the agenda (distributed beforehand). This will involve getting to know what each person has done over the last week, and are currently working on. Readying tasks for the upcoming sprint by ensuring the developer understands exactly what is expected from the task. + +Conflict Resolution: + * List at least three team scenarios/conflicts you discussed in lecture and how you decided you will resolve them. Indecisions? Non-responsive team members? Any other scenarios you can think of? +> Same as iteration-01, see [here](https://github.com/csc301-winter-2019/project-team-02/blob/master/deliverables/iteration-01.planṃd#conflict-resolution). + +#### Events + +Describe meetings (and other events) you are planning to have: + * When and where? Recurring or ad hoc? In-person or online? + > We have mandatory in-person meetings every Tuesday from 3-6 pm inside a booked study room at the Gerstein Library. We have an online meeting on Fridays from 4-6 pm if needed. + * What's the purpose of each meeting? + > The purpose of each meeting is to determine what everybody has done over the previous week and what tasks need to be worked on for the upcoming week. + * Other events could be coding sessions, code reviews, quick weekly sync meeting online, etc. + +> Same as iteration-01, see [here](https://github.com/csc301-winter-2019/project-team-02/blob/master/deliverables/iteration-01.planṃd#conflict-resolution). + +#### Artifacts + +List/describe the artifacts you will produce in order to organize your team. + + * Artifacts can be To-Do lists, Task boards, schedule(s), etc. + * A snapshot of the Trello board to keep track of our tasks: + + + * Link to the [wiki](https://github.com/csc301-winter-2019/project-team-02/wiki) home page. You can see the various pages we've added in the sidebar. + * A snapshot of the Slack channel "meetingnotes" where we post meeting agendas and notes from a meeting: + + + * We want to understand: + * How do you keep track of what needs to get done? + > We create a Trello card in the backlog column + * How do you prioritize tasks? + > Tasks at the top of the Backlog column are the highest priority. These are the tasks necessary to have a MVP. So fancy UI elements will get de-prioritized in place of business logic tasks. + * How do tasks get assigned to team members? + > We want everyone to contribute so those who did not contribute much the previous week will get priority at the upcoming tasks. They can pick whatever task they feel they can complete in that week from the Ready for Work column. + + +#### Deployment and Github Workflow + +Describe your Git / GitHub workflow. Essentially, we want to understand how your team members shares a codebase, avoid conflicts and deploys the application. + + + * Be concise, yet precise. For example, "we use pull-requests" is not a precise statement since it leaves too many open questions - Pull-requests from where to where? Who reviews the pull-requests? Who is responsible for merging them? etc. + +>You can view the detailed description in our repo wiki page [Development Workflow](https://github.com/csc301-winter-2019/project-team-02/wiki/Development-Worklfow) for how our Trello board connects to github and our "process". + +> We have a specific page for dealing with code conflicts in our wiki page [Resolving-Code-Conflicts](https://github.com/csc301-winter-2019/project-team-02/wiki/Resolving-Code-Conflicts) + + * If applicable, specify any naming conventions or standards you decide to adopt. +> Naming of branches reflect the Trello card no. found in the url. Branches begin with either "feat" or "fix" depending on the Trello label, followed by the card no. For eg, feat/4. + + * Describe your overall deployment process from writing code to viewing a live application +>TL;DR + + 1. Developer pushes a feature to their branch. + 2. They create a pull request from their branch into `qa` branch adding at least two reviewers. Once approved, the developer completes the merge and "deploys" it to a qa environment. + 3. Another team member will test it in the qa environment and decide if it is good enough. If good enough, the tester will move the trello card into "Ready for Release" column. + 4. The developer will then create the pull request from their branch into `master` without needing any reviewers, and complete the merge. + 5. They will then deploy it to a production environment and self test that everything is okay. + * What deployment tool(s) are you using and why +> Expo for deploying to mobile. It allows us to write the same code for android and ios. +> Heroku for deploying to the web. It has a nice integration with git, and works well with our tech. stack. + * Don't forget to **explain why** you chose this workflow or particular aspects of it! +> We chose this workflow so that each feature/fix is separated into its own branch so that it is easier to apply filters in the future. +> We deploy to `qa` first so that the `master` branch always has code that is ready to be deployed after it has been thoroughly tested in the `qa` branch among other developing features. This minimizes the likelihood that once we do merge to `master`, nothing *existing* will break. + + + +## Product + +#### Goals and tasks + + * Describe your goals for this iteration and the tasks that you will have to complete in order to achieve these goals. + * Order the items from most to least important. + * Feel free (but not obligated) to specify some/all tasks as user stories. + + >1. Have the mobile send its location to the server. + >2. Have a website display all locations ever sent on first page load on a map. + >3. A new mobile request gets added to the website without a page reload. + +#### Artifacts + +List/describe the artifacts you will produce in order to present your project idea. + + * Artifacts can be text, code, images, videos, interactive mock-ups and/or any other useful artifact you can think of. + * Make sure to explain the purpose of each artifact (i.e. Why is it on your to-do list? Why is it useful for your team?) + * Be concise, yet precise. + For example: "Build the website" is not precise at all, but "Build a static home page and upload it somewhere, so that it is publicly accessible" is much clearer. + + > A video/screencast of the mobile sending its location to the server. + > A video/screencast of the website live updating by adding a new marker on the map based on the new request. diff --git a/web/README.md b/web/README.md index d470960..b7f02b3 100644 --- a/web/README.md +++ b/web/README.md @@ -13,34 +13,8 @@ `docker run -d --name mymongo -p 27017:27017 mongo` -2. enter inside the container: - - `docker exec -it mymongo mongo` - -3. run inside the interactive mongo shell: - - `use helpthehome` - -4. Put in some dummy data to start, run: - -``` -db.pointscollection.insert({ - "type": "MultiPoint", - "name": "points", - "color": "#0000ff", - "style": { - "radius": 8, - "fillColor": "#00ce00", - "color": "#008c00", - "weight": 2, - "opacity": 1, - "fillOpacity": 1 - }, - "coordinates": [-73.9580, 40.8003] -}) -``` - -5. Now you are ready to start the app: + +2. Now you are ready to start the app: From this directory: @@ -3,6 +3,7 @@ var express = require('express'); var path = require('path'); var cookieParser = require('cookie-parser'); var logger = require('morgan'); +var mongoose = require('mongoose'); var indexRouter = require('./routes/index'); var usersRouter = require('./routes/users'); @@ -18,10 +19,33 @@ app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); +app.use(require('./routes/sse')); + +var env = process.env.NODE_ENV || 'development'; +var uri; +if (env === 'development') { + uri = 'mongodb://localhost:27017/helpthehome' + // use for small testing only if really necessary + // uri = 'mongodb+srv://development:dreamteam@cluster0-krnr4.mongodb.net/helpthehome?retryWrites=true' +} else if (env === 'qa') { + uri = process.env.MONGODB_URI +} else if (env === 'production') { + uri = '' +} + +// Mongoose connection to MongoDB +mongoose.connect(uri, { useNewUrlParser: true }, function (error) { + if (error) { + console.log(error); + console.log("App was not able to connect to the mongo server!"); + console.log("... double check that the mongo server is running locally"); + } else { + console.log(`connected to ${uri}`); + } +}); app.use('/', indexRouter); app.use('/users', usersRouter); - // catch 404 and forward to error handler app.use(function(req, res, next) { next(createError(404)); diff --git a/web/models/mockpoints.js b/web/models/mockpoints.js new file mode 100644 index 0000000..ff5e771 --- /dev/null +++ b/web/models/mockpoints.js @@ -0,0 +1,32 @@ +var mongoose = require('mongoose'); + +// Mongoose Schema definition +var Schema = mongoose.Schema; +var dumbJsonSchema = new Schema({ + type: String, + coordinates: Array, + ageRange: String, + clothingDescription: String, + isInjured: Boolean, + reasonForHelp: String +}); + +// Mongoose Model definition +var dumbJson = mongoose.model('dumbJstring', dumbJsonSchema, 'dumbpointscollection'); + +// this function gets ALL the points from the db +// returns the entire document without modifications +exports.get_points = function(callback) { + dumbJson.find({}).exec(function(err, docs) { + if (err) callback(err, null); + callback(null, docs); + }); +} + +// this function stores A user report into the db +exports.save_request = function(data, callback) { + dumbJson.create(data, function(err, result) { + if (err) callback(err, null); + callback(null, result); + }); +} diff --git a/web/models/points.js b/web/models/points.js new file mode 100644 index 0000000..3a07c82 --- /dev/null +++ b/web/models/points.js @@ -0,0 +1,32 @@ +var mongoose = require('mongoose'); + +// Mongoose Schema definition +var Schema = mongoose.Schema; +var JsonSchema = new Schema({ + type: String, + coordinates: Array, + ageRange: String, + clothingDescription: String, + isInjured: Boolean, + reasonForHelp: String +}); + +// Mongoose Model definition +var Json = mongoose.model('Jstring', JsonSchema, 'pointscollection'); + +// this function gets ALL the points from the db +// returns the entire document without modifications +exports.get_points = function(callback) { + Json.find({}).exec(function(err, docs) { + if (err) callback(err, null); + callback(null, docs); + }); +} + +// this function stores A user report into the db +exports.save_request = function(data, callback) { + Json.create(data, function(err, result) { + if (err) callback(err, null); + callback(null, result); + }); +} diff --git a/web/public/javascripts/map.js b/web/public/javascripts/map.js index 44fba38..cb72756 100644 --- a/web/public/javascripts/map.js +++ b/web/public/javascripts/map.js @@ -3,50 +3,57 @@ // attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' // }).addTo(map); +function plotPointsOnMap(points) { + L.geoJson(points, { + pointToLayer: function (feature, latlng) { + //return L.circleMarker(latlng); + latlngbounds.extend(latlng); + return L.marker(latlng); + } + }).bindPopup(function (layer) { + // layer.feature.geometry gives you access to all the fields + return "<p>" + JSON.stringify(layer.feature.geometry) + "</p>"; + }).addTo(map) + + // rezoom the map so that all the markers fit in the view, add 20% padding so + // that marker dont cut off + map.fitBounds(latlngbounds.pad(0.20)); +} + // different basemap L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/toner-lite/{z}/{x}/{y}{r}.{ext}', { - attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> — Map data © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors', - subdomains: 'abcd', - minZoom: 0, - maxZoom: 20, - ext: 'png' + attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> — Map data © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors', + subdomains: 'abcd', + minZoom: 0, + maxZoom: 18, + ext: 'png' }).addTo(map); -// Create point feature for somewhere downtown -var myDataPoint = L.marker([43.6529, -79.3849]).addTo(map); - -// Create line feature and add style and add to map -var myDataLine = L.polyline([ - [43.6529, -79.3849], - [43.6531, -79.3855]], - {color: 'red', weight: 10}).addTo(map); - -// Create area feature add style and add to map -var myArea = L.polygon([ - [43.650948, -79.385655], - [43.66, -79.388], - [43.6634, -79.4011], - [43.66, -79.4011]], - {color: 'blue', weight: 4}).addTo(map); - -// Bind popup to Data Point object -// myDataPoint.bindPopup("This is my city"); -// i can add regular html to this too - neat! -myDataPoint.bindPopup("<h3>City Hall (not really)</h3><p>Toronto, ON<br>Information about city hall.</p>"); - -// Bind popup to area object -myArea.bindPopup("U of T Campus (not really)"); - -// Create an Empty Popup -var popup = L.popup(); - -// Write function to set Properties of the Popup -function onMapClick(e) { - popup - .setLatLng(e.latlng) - .setContent("You clicked the map at " + e.latlng.toString()) - .openOn(map); +// keep track of the boundary of the markers so that we can update the +// map to fit them all +var latlngbounds = new L.latLngBounds(); + +plotPointsOnMap(points); +if (window.EventSource) { + var source = new EventSource('/stream'); + + source.addEventListener('message', function(e) { + var data = JSON.parse(e.data); + if (data.coordinates) { + points.push(data); + plotPointsOnMap(points); + } + }, false) + + source.addEventListener('open', function(e) { + console.log("Connection was opened") + }, false) + + source.addEventListener('error', function(e) { + if (e.readyState == EventSource.CLOSED) { + console.log("Connection was closed") + } + }, false) +} else { + console.log("sse not supported."); } - -// Listen for a click event on the Map element -map.on('click', onMapClick); diff --git a/web/routes/index.js b/web/routes/index.js index ffe1c21..b2ba91f 100644 --- a/web/routes/index.js +++ b/web/routes/index.js @@ -1,61 +1,59 @@ var express = require('express'); var router = express.Router(); - -// Mongoose import -var mongoose = require('mongoose'); - -var env = process.env.NODE_ENV || 'development'; -var uri; -if (env === 'development') { - uri = 'mongodb://localhost:27017/helpthehome' - // use for small testing only if really necessary - // uri = 'mongodb+srv://development:dreamteam@cluster0-krnr4.mongodb.net/helpthehome?retryWrites=true' -} else if (env === 'qa') { - uri = process.env.MONGODB_URI -} else if (env === 'production') { - uri = '' -} - -// Mongoose connection to MongoDB -mongoose.connect(uri, { useNewUrlParser: true }, function (error) { - if (error) { - console.log(error); - console.log("App was not able to connect to the mongo server!"); - console.log("... double check that the mongo server is running locally"); - } else { - console.log(`connected to ${uri}`); - } -}); - -// Mongoose Schema definition -var Schema = mongoose.Schema; -var JsonSchema = new Schema({ - name: String, - type: Schema.Types.Mixed, - coordinates: Array -}); - -// Mongoose Model definition -var Json = mongoose.model('Jstring', JsonSchema, 'pointscollection'); - +var Mockpoints = require('../models/mockpoints'); +var Points = require('../models/points'); +const connections = []; /* GET home page. */ router.get('/', function(req, res, next) { - // for now just redirect to /map - //res.render('index', { title: 'Welcome' }); - res.redirect('/map'); + // for now just redirect to /map + res.redirect('/map'); }); /* GET Map page. */ router.get('/map', function(req,res) { - // we can use the database to fetch a point, SELECT coordinates - Json.findOne({name: "points"}, 'coordinates', function(e,point){ - if (e) return e; - // send the view lat, and long. - res.render('map', { - lat : point.coordinates[1], - lng : point.coordinates[0] - }); - }); + // load the map with all the points + // Mockpoints.get_points(function(err, points){ + Points.get_points(function(err, points){ + res.render('map', { + lat : 43.665234, + lng : -79.383370, + points: points + }); + }); +}); + +router.post('/mobilerequest', function(req, res) { + var data = { + 'coordinates': req.body.coordinates, + 'type': req.body.type, + 'isInjured': req.body.isInjured, + 'reasonForHelp': req.body.reasonForHelp, + 'ageRange': req.body.ageRange, + 'clothingDescription': req.body.clothingDescription + } + Points.save_request(data, function(err, result) { + if (err) { + console.log(`err inserting mobile request into db: ${err}`); + res.status(500).send({ error: "boo:(" }); + } else { + // send event to all connections + for(var i = 0; i < connections.length; i++) { + connections[i].sseSend(data); + } + console.log(result); + res.status(200).send({'status': 'success', 'data': data}); + } + }); + }); + +router.get('/stream', function(req, res){ + // set up server side event (communication line between front end and server) + res.sseSetup(); + // send an event to the front end to open the connection + res.sseSend('ok'); + // push connection to connection array + connections.push(res); +}); module.exports = router; diff --git a/web/routes/sse.js b/web/routes/sse.js new file mode 100644 index 0000000..5cd9a3f --- /dev/null +++ b/web/routes/sse.js @@ -0,0 +1,15 @@ +module.exports = function (req, res, next) { + res.sseSetup = function() { + res.writeHead(200, { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive' + }) + } + + res.sseSend = function(data) { + res.write("data: " + JSON.stringify(data) + "\n\n"); + } + + next() +}
\ No newline at end of file diff --git a/web/views/map.pug b/web/views/map.pug index b7781fa..725c8a8 100644 --- a/web/views/map.pug +++ b/web/views/map.pug @@ -1,11 +1,11 @@ extends layout.pug block content - #sidebar - h1 This is a sidebar - #map - - script(type='text/javascript'). - var map = L.map('map').setView([#{lat},#{lng}], 15); - script(src='/javascripts/map.js') - + #sidebar + h1 This is a sidebar + #map + script(type='text/javascript'). + var map = L.map('map').setView([#{lat},#{lng}], 13); + var points = !{JSON.stringify(points)}; + console.log(points); + script(src='/javascripts/map.js') |
