diff --git a/.env.sample b/.env.sample deleted file mode 100644 index 756620f..0000000 --- a/.env.sample +++ /dev/null @@ -1,10 +0,0 @@ -# In order to run your application, make a copy of this file, rename it to .env -# and fill the lines below. All set. -# You can use this to define whatever environment variable your application might need. -# @see /app/config.js - -NODE_ENV=development -PORT=9000 -PRETTY_HTML=true - -MONGO_URI=mongodb://127.0.0.1:27017/boilerplate diff --git a/.eslintrc.json b/.eslintrc.json index 64286d9..fe7779a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,4 +1,10 @@ { + "env": { + "browser": true, + "commonjs": true, + "es6": true, + "jquery": true + }, "extends": "airbnb-base", "plugins": [ "import" diff --git a/Gruntfile.js b/Gruntfile.js index 06eeacb..26ac7a5 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -16,6 +16,8 @@ module.exports = (grunt) => { grunt.initConfig(tasks); grunt.registerTask('build', ['cssmin', 'uglify']); + grunt.registerTask('watch', ['watch']); + grunt.loadNpmTasks('grunt-contrib-watch'); } catch (error) { console.error(`I can't load Grunt; ${error.message}`); } diff --git a/app/core/controllers/cities.js b/app/core/controllers/cities.js index 021d40c..7e668df 100644 --- a/app/core/controllers/cities.js +++ b/app/core/controllers/cities.js @@ -4,8 +4,11 @@ const m = attract('core/models'); module.exports = { create: async (req, res, next) => { try { - const city = await m.city.create(req.body); - return res.render('cities', city); + await m.city.create(req.body); + return res.render('cities', { + section: 'Cities', + cities: await m.city.find({ 'meta.status': 'active' }) + }); } catch (error) { return next(error); } @@ -15,7 +18,6 @@ module.exports = { if (req.params.city) { return res.send(await m.city.findById(req.params.city)); } - return res.render('cities', { section: 'Cities', cities: await m.city.find({ 'meta.status': 'active' }) @@ -30,5 +32,16 @@ module.exports = { } catch (error) { return next(error); } + }, + + update: async (req, res, next) => { + try { + const city = await m.city.findById(req.params.city).exec(); + await city.update(req.body); + return res.status(200) + .end('success'); + } catch (error) { + return next(error); + } } }; diff --git a/app/core/controllers/users.js b/app/core/controllers/users.js index 11be2e3..244fc3b 100644 --- a/app/core/controllers/users.js +++ b/app/core/controllers/users.js @@ -4,8 +4,12 @@ const m = attract('core/models'); module.exports = { create: async (req, res, next) => { try { - const user = await m.user.create(req.body); - return res.render('users', user); + await m.user.create(req.body); + return res.render('users', { + section: 'Users', + users: await m.user.find({ 'meta.status': 'active' }), + cities: await m.city.find({ 'meta.status': 'active' }) + }); } catch (error) { return next(error); } @@ -15,18 +19,20 @@ module.exports = { if (req.params.user) { return res.send(await m.user.findById(req.params.user)); } - return res.render('users', { section: 'Users', - users: await m.user.find({ 'meta.status': 'active' }) + users: await m.user.find({ 'meta.status': 'active' }), + cities: await m.city.find({ 'meta.status': 'active' }) }); }, delete: async (req, res, next) => { try { - const user = await m.user.findById(req.params.user).exec(); + const user = await m.user.findById(req.params.user) + .exec(); await user.remove(); - return res.status(200).end(); + return res.status(200) + .end('success'); } catch (error) { return next(error); } diff --git a/app/core/routes/cities.js b/app/core/routes/cities.js index 4f58102..6663f40 100644 --- a/app/core/routes/cities.js +++ b/app/core/routes/cities.js @@ -2,7 +2,7 @@ module.exports = (router, controller) => { router.route('/cities/:city?') .get(controller.read) .post(controller.create) - .delete(controller.delete); - + .delete(controller.delete) + .put(controller.update); return router; }; diff --git a/app/core/views/_components/html.pug b/app/core/views/_components/html.pug index 67341d4..2821266 100644 --- a/app/core/views/_components/html.pug +++ b/app/core/views/_components/html.pug @@ -15,3 +15,5 @@ mixin head() mixin body() body block + script(src='https://code.jquery.com/jquery-3.3.1.min.js', integrity='sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=', crossorigin='anonymous') + script(src='/js/boilerplate.min.js', type='text/javascript') diff --git a/app/core/views/cities/index.pug b/app/core/views/cities/index.pug index 60c229b..f81d055 100644 --- a/app/core/views/cities/index.pug +++ b/app/core/views/cities/index.pug @@ -7,3 +7,36 @@ include ../_components/html h3= section p a(href='/') Home + br + a(href='/users') Users + br + + -let n = 1; + + .container + table(id='list-cities' width='20%' border='1') + tbody + tr + td № + td City name + td + td + each item in cities + tr(class='row_table') + td= n + td + input(class='city_name_'+n, type='text', name='cityname' value=item.name) + td + button(class='delete-city', width='100%', height='100%', type='submit', _id=item._id) Delete + td + button(class='update-city', width='100%', height='100%', type='submit', _id=item._id , _idd=n++, _city=item.name) Update + + .container + form(action='/cities', method='post') + p.search + .create-container + b Сreate new city: + input(type='text', size='50' name='name' placeholder='enter city name') + input(type='submit' value='Create') + + diff --git a/app/core/views/users/index.pug b/app/core/views/users/index.pug index 60c229b..9043f7c 100644 --- a/app/core/views/users/index.pug +++ b/app/core/views/users/index.pug @@ -7,3 +7,41 @@ include ../_components/html h3= section p a(href='/') Home + br + a(href='/cities') Cities + br + + -let n = 1; + + b User information: + .container + table(id='users-table' width='20%' border='1') + tbody + tr + td № + td User name + td User email + td + each item in users + tr(class='user-info') + td= n++ + td= item.username + td= item.email + td + button(class='delete-user', width='100%', height='100%' , _id=item._id ) Delete + br + b Create new user: + .container + form(action='/users', method='post', id='create-form') + .flex-container + input(type='text', name='username' placeholder='enter user name') + input(type='email', name='email' placeholder='enter user email') + select(id='city-list', name='city', form='create-form') + each item in cities + option(value=item._id)= item.name + input(type='submit' value='Create') + + + + + diff --git a/app/index.js b/app/index.js index 613cb1d..3ae3280 100644 --- a/app/index.js +++ b/app/index.js @@ -3,6 +3,7 @@ require('attract')({ basePath: __dirname }); const bodyParser = require('body-parser'); const compression = require('compression'); const express = require('express'); +const logger = require('morgan'); const powered = require('powered'); const serveFavicon = require('serve-favicon'); @@ -25,6 +26,7 @@ m.load(config.mongo).then(() => { app.set('views', `${__dirname}/core/views`); app.set('view engine', 'pug'); app.use( + logger('dev'), powered(), compression(), express.static(`${__dirname}/public`), diff --git a/grunt/watch.task.js b/grunt/watch.task.js index 708a0fd..6374cbd 100644 --- a/grunt/watch.task.js +++ b/grunt/watch.task.js @@ -1,5 +1,4 @@ module.exports = (grunt, path) => { - grunt.registerTask('watch', ['watch']); return { scripts: { files: [ diff --git a/package.json b/package.json index e852d6f..7b7f8a6 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,8 @@ "body-parser": "^1.18.2", "compression": "^1.7.2", "express": "^4.16.2", - "mongoose": "^5.0.7", + "mongoose": "^5.0.6", + "morgan": "^1.9.0", "powered": "^1.0.1", "pug": "^2.0.0-beta11", "serve-favicon": "^2.4.5", @@ -37,6 +38,7 @@ "grunt": "^1.0.2", "grunt-contrib-cssmin": "^2.2.1", "grunt-contrib-uglify-es": "git://github.com/gruntjs/grunt-contrib-uglify.git#harmony", + "grunt-contrib-watch": "^1.0.0", "grunt-eslint": "^20.1.0", "grunt-nodemon": "^0.4.2" }, diff --git a/source/css/home.css b/source/css/home.css index 8499f1e..95b596a 100644 --- a/source/css/home.css +++ b/source/css/home.css @@ -1,28 +1,33 @@ html { - min-height: 100%; - position: relative; + min-height: 100%; + position: relative; } body { - font-family: 'Lato', sans-serif; - color: #fff; - background-color: #383837; - padding: 0; - margin: 0; + font-family: 'Lato', sans-serif; + color: #fff; + background-color: #383837; + padding: 0; + margin: 0; + font-size: 18px; } -h3, p { - width: 100%; - text-align: center; - font-size: 1.7rem; - padding: 50px 0 0; - margin: 0; +h3 { + width: 100%; + text-align: center; + font-size: 1.7rem; + padding: 50px 0 0; + margin: 0; +} + +p.search { + font-size: 1rem; + margin: 15px 5px 0 0; + padding: 0; } p { - font-size: 1rem; - margin: 0; - padding: 0; + text-align: center; } a { @@ -38,3 +43,53 @@ a:hover { .actions { margin-top: 30px; } + +.flex-container { + display: flex; + flex-direction: column; +} + +.flex-container input, .flex-container select, .create-container input { + outline: none; + border: 1px solid grey; + padding: 4px; + width: 200px; + max-width: 100%; + height: 35px; + border-radius: 5px; +} + +.flex-container input[type='submit'] { + width: 210px; +} + +.create-container { + display: flex; + flex-direction: column; + margin-left: 15px; +} + +.create-container input { + width: 316px; +} + +.create-container input[type='submit'] { + width: 327px; + height: 43px; +} + +.container { + margin-left: 15px; +} + +b { + margin-left: 15px; +} + +td { + padding: 5px; +} + +#city-list { + width: 210px; +} diff --git a/source/js/aj_logic.js b/source/js/aj_logic.js new file mode 100644 index 0000000..ebc13fa --- /dev/null +++ b/source/js/aj_logic.js @@ -0,0 +1,32 @@ +$(document) + .ready(() => { + $('body .delete-user').click((ev) => { + $.ajax({ + url: `/users/${$(ev.target).attr('_id')}`, + type: 'DELETE', + success() { + $(ev.target).closest('tr').remove(); + } + }); + }); + $('body .delete-city').click((ev) => { + $.ajax({ + url: `/cities/${$(ev.target).attr('_id')}`, + type: 'DELETE', + success() { + $(ev.target).closest('tr').remove(); + } + }); + }); + $('body .update-city').click((ev) => { + const cityId = $(ev.target).attr('_idd'); + const cityname = $(`.city_name_${cityId}`).val(); + $.ajax({ + url: `/cities/${$(ev.target).attr('_id')}`, + type: 'PUT', + data: { + name: cityname + } + }); + }); + });