diff --git a/README.md b/README.md index 2fbf185..049687f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Lizardboard +# Lizardboard Team Name: #Shaggy-Sheathbill An open source clone of [geckoboard](https://www.geckoboard.com/). Interested in contributing? Take a look at the [project page](https://github.com/GuildCrafts/lizardboard/projects) and [issues page](https://github.com/GuildCrafts/lizardboard/issues) for outstanding issues. @@ -14,6 +14,18 @@ A mongodb database named lizardboard must be created prior to starting the appli - Ensure `mongo` is running - yarn install +### Specs +- [x] Setup Api for getting json responses of various dashboard queries following: + - [x] GET /dashboards - get all dashboards + - [x] POST /dashboards { data } - create a new dashboard entry + - [x] GET /dashboards/:id - get single dashboard entry + - [x] PUT /dashboards/:id { data } - update single dashboard entry + - [x] DELETE /dashboards/:id - delete single dashboard entry + - [x] GET /dashboards/:id/widgets - get all widgets for single dashboard entry + - [x] POST /dashboards/:id/widgets - create widgets for single dashboard entry +- [x] [Create New Dashboard #23](https://github.com/GuildCrafts/lizardboard/issues/23) +- [x] [Delete Dashboard #25](https://github.com/GuildCrafts/lizardboard/issues/25) + ## Technical Stack ### Back End @@ -24,11 +36,11 @@ A mongodb database named lizardboard must be created prior to starting the appli ### Database - [Mongodb](https://docs.mongodb.com/) - -[Mongoose](http://mongoosejs.com/docs/guide.html) - -[Migrate-Mongoose](https://github.com/balmasi/migrate-mongoose) +- [Mongoose](http://mongoosejs.com/docs/guide.html) +- [Migrate-Mongoose](https://github.com/balmasi/migrate-mongoose) ## Front End - [React](https://facebook.github.io/react/) ## Testing -TBD \ No newline at end of file +TBD diff --git a/models/widgets.js b/models/widgets.js index 0953b97..dfa38b6 100644 --- a/models/widgets.js +++ b/models/widgets.js @@ -1,13 +1,68 @@ const mongoose = require('mongoose') const { Schema } = mongoose -const WidgetSchema = new Schema ({ - type: String, - title: String, - size: { type: Number, required: true }, - contents: String +const WidgetDescriptorSchema = new Schema({ + category: { type: String, required: true }, + source: { type: String, required: true }, + type: { type: String, required: true }, // GithubPullRequest + title: { type: String, required: true }, + size: { type: String, required: true, default: '1x1' }, + fields: [ ] }) -const Widget = mongoose.model( 'Widget', WidgetSchema ) +const WidgetDescriptor = mongoose.model( + 'WidgetDescriptor', WidgetDescriptorSchema +) -module.exports = { WidgetSchema, Widget } + + + +// { +// type: 'GithubPullRequest', +// title: 'Github Pull Requests', +// fields: [ { title: 'Github ID', key: 'githubId', type: 'Text' } ] +// } + +// const newWidget = new WidgetDescriptor({ request.body }) + + +WidgetDescriptor.create({ + category: 'Dashboard Tools', + source: 'Geckoboard', + type: 'Clock', + title: 'Clock', + size: '1x1', + fields: [ + Field.create({ title: 'Format', key: 'format', type: 'Dropdown', defaultValue: '12 hour', options: [ '12 hour', '24 hour' ] }), + Field.create({ + title: 'Location', + key: 'location', + type: 'Dropdown', + options: [ 'All', 'the', 'countries' ], + fields: [ + Field.create({ title: 'Timezone', key: 'timezone', type: 'Dropdown', options: [ 'all', 'timezones' ]}) + ] + }) + ] +}) + +WidgetDescriptor.create({ + type: 'QR', + title: 'QR Code', + fields: [ Field.create({ title: 'url', key: 'url', type: 'Text' }) ] +}) + +WidgetDescriptor.create({ + type: 'Text', + title: 'Text', + fields: [ + Field.create({ title: 'Message one', key: 'messageOne', type: 'Text'}) + Field.create({ title: 'Message one type', key: 'messageOneType', type: 'Dropdown', defaultValue: 'Text', options: [ 'Text', 'Alert', 'Info' ]}) + Field.create({ title: 'Message two', key: 'messageTwo', type: 'Text'}) + Field.create({ title: 'Message two type', key: 'messageTwoType', type: 'Dropdown', defaultValue: 'Text', options: [ 'Text', 'Alert', 'Info' ]}) + Field.create({ title: 'Message three', key: 'messageThree', type: 'Text'}) + Field.create({ title: 'Message three type', key: 'messageThreeType', type: 'Dropdown', defaultValue: 'Text', options: [ 'Text', 'Alert', 'Info' ]}) + Field.create({ title: 'Message four', key: 'messageFour', type: 'Text'}) + Field.create({ title: 'Message four type', key: 'messageFourType', type: 'Dropdown', defaultValue: 'Text', options: [ 'Text', 'Alert', 'Info' ]}) + ] +}) diff --git a/routes/api/v1/dashboard/addWidget.js b/routes/api/v1/dashboard/addWidget.js index bfa3790..dfef539 100644 --- a/routes/api/v1/dashboard/addWidget.js +++ b/routes/api/v1/dashboard/addWidget.js @@ -4,5 +4,4 @@ const addWidget = widgetData => dashboard => { dashboard.widgets.push( new Widget( widgetData )) return dashboard.save() } - module.exports = addWidget diff --git a/routes/api/v1/dashboards.js b/routes/api/v1/dashboards.js index 54765fb..c4294d9 100644 --- a/routes/api/v1/dashboards.js +++ b/routes/api/v1/dashboards.js @@ -43,4 +43,16 @@ router.post( '/:id/widgets', ( request, response ) => { .catch( errorResponse( response )) }) +router.put( '/:id/widgets/:widgetId', ( request, response ) => { + Widget.findByIdAndUpdate( request.params.widgetId, request.body ).exec() + .then( widget => response.json( widget )) + .catch( errorResponse( response )) +}) + +router.delete( '/:id/widgets/:widgetId', ( request, response ) => { + Widget.findByIdAndRemove( request.params.widgetId ).exec() + .then( widget => response.json( widget )) + .catch( errorResponse( response )) +}) + module.exports = router diff --git a/routes/api/v1/errorResponse.js b/routes/api/v1/errorResponse.js new file mode 100644 index 0000000..2a6f4b5 --- /dev/null +++ b/routes/api/v1/errorResponse.js @@ -0,0 +1,13 @@ +const errorResponse = response => error => { + if( error.name === 'CastError' ) { + response.status( 404 ).json({}) + } + else if( error.name === 'ValidationError' ) { + response.status( 400 ).json({}) + } + else { + response.status( 500 ).json({}) + } +} + +module.exports = errorResponse diff --git a/routes/api/v1/widgetDescriptor.js b/routes/api/v1/widgetDescriptor.js new file mode 100644 index 0000000..feb4808 --- /dev/null +++ b/routes/api/v1/widgetDescriptor.js @@ -0,0 +1,3 @@ +// GET / all widgets, group by different categories +// GET /:type +// document API Trossello diff --git a/server/app.js b/server/app.js new file mode 100644 index 0000000..03a89d6 --- /dev/null +++ b/server/app.js @@ -0,0 +1,66 @@ +const express = require( 'express' ) +const path = require( 'path' ) +const favicon = require( 'serve-favicon' ) +const logger = require( 'morgan' ) +const cookieParser = require( 'cookie-parser' ) +const bodyParser = require( 'body-parser' ) + +const api = require( '../routes/api/manifest' ).v1 + +const app = express() + +app.set( 'env', process.env.PORT || '3000' ) +if( process.env.NODE_ENV !== 'test' ) app.use( logger( 'dev' )) +// app.use( cookieSession({ +// name: 'session', +// keys: [[ process.env.SESSION_KEY ]] +// })) +// app.use(express.static(buildpath+'/public')) +app.use(bodyParser.json()) + +// uncomment after placing your favicon in /public +//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))) +app.use( logger( 'dev' )) +app.use( bodyParser.json()) +app.use( bodyParser.urlencoded({ extended: false })) +app.use( cookieParser()) + +app.use( express.static( path.join( __dirname, '../front_end/public' ))) + +app.use( express.static( path.join( __dirname, 'public' ))) + +app.use( '/api/v1/dashboards', api.dashboards ) +app.use( '/api/v1/users', api.users ) + +// catch 404 and forward to error handler +app.use( function( req, res, next ) { + var err = new Error( 'Not Found' ) + err.status = 404 + next( err ) +}) + +// error handlers + +// development error handler +// will print stacktrace +if ( app.get( 'env' ) === 'development' ) { + app.use( function( err, req, res, next ) { + res.status( err.status || 500 ) + res.send({ + message: err.message, + error: err + }) + }) +} + +// production error handler +// no stacktraces leaked to user +app.use( function( err, req, res, next ) { + res.status( err.status || 500 ) + res.send({ + message: err.message, + error: {} + }) +}) + +module.exports = app