- •Содержание
- •Введение
- •Описание предметной области
- •Постановка задачи и обзор методов ее решения
- •3. Обоснование инструментов разработки
- •4. Реализация
- •4.1 Логическая структура Web-приложения
- •4.2 Физическая структура Web-приложения
- •4.4 Описание ограничений доступа к данным
- •4.3 Описание структуры и формата страниц
- •4.5 Описание используемых библиотек и элементов управления
- •4.6 Описание используемых функций и процедур
- •5. Тестирование
- •6. Применение
- •6.1 Назначение и область применения Web-приложения
- •6.2 Описание организации диалога с пользователем
- •6.3 Программно-аппаратное обеспечение сервера и клиента
- •6.4 Руководство пользователя
- •Заключение
- •Список литературы
- •Приложение
Приложение
Листинг файла package.json
{ "dependencies": { "async": "^2.4.1", "body-parser": "^1.17.2", "connect-mongo": "^1.3.2", "cookie-parser": "^1.4.3", "express": "^4.15.3", "express-session": "^1.15.3", "mongoose": "^4.10.3", "serve-favicon": "^2.4.3" } }
Листинг файла config.js
module.exports = { port: 49002, mongodb: { "main": "mongodb://127.0.0.1:27017/main" }, session: "aXVmN7y{Xw5|9zN%El2m" };
Листинг файла createDB.js
var mongoose = require('./lib/mongoose'); var async = require('async'); async.series([ open, dropDatabase, requireModels, createUsers, createCategory, createGoods ], function(err) { console.log(arguments); }); function open(callback) { mongoose.connection.on('open', callback); } function dropDatabase(callback) { var db = mongoose.connection.db; db.dropDatabase(callback); } function requireModels(callback) { require('./models/user'); require('./models/category'); require('./models/goods'); async.each(Object.keys(mongoose.models), function(modelName, callback) { mongoose.models[modelName].ensureIndexes(callback); }, callback); } function createUsers(callback) { var users = [ {username: 'Вася', password: 'supervasya'}, {username: 'Петя', password: '123'}, {username: 'admin', password: 'thetruehero'} ]; async.each(users, function(userData, callback) { var user = new mongoose.models.User(userData); user.save(callback); }, callback); } function createCategory(callback) { var categories = [ {id: 0, name: 'Товары для собак', img: 'dogs.jpg'}, {id: 1, name: 'Товары для котов', img: 'cats.jpg'} ]; async.each(categories, function(categoryData, callback) { var category = new mongoose.models.Category(categoryData); category.save(callback); }, callback); } function createGoods(callback) { var goods = [ {id: 0, category: 0, price: 10, name: 'Корм для собак Чаппи', img: 'dogs1.jpg'}, {id: 1, category: 0, price: 20, name: 'Корм для собак Trainer Natural Mini Adult', img: 'dogs2.jpg'}, {id: 2, category: 1, price: 30, name: 'Корм Brit Care Crazy для котят', img: 'cats1.jpg'}, {id: 3, category: 0, price: 40, name: 'Корм для собак Acana PACIFICA DOG', img: 'dogs3.jpg'}, {id: 4, category: 1, price: 50, name: 'Корм для кошек Gourmet Кусочки в соусе', img: 'cats2.jpg'}, {id: 5, category: 1, price: 60, name: 'Консервированный корм для кошек Friskies', img: 'cats3.jpg'}, ]; async.each(goods, function(goodsData, callback) { var good = new mongoose.models.Goods(goodsData); good.save(callback); }, callback); }
Листинг файла error.js
var util = require('util'); var http = require('http'); // ошибки для выдачи посетителю function HttpError(status, message) { Error.apply(this, arguments); Error.captureStackTrace(this, HttpError); this.status = status; this.message = message || http.STATUS_CODES[status] || "Error"; } util.inherits(HttpError, Error); HttpError.prototype.name = 'HttpError'; exports.HttpError = HttpError;
Листинг файла index.js
'use strict'; const http = require('http'), express = require('express'), cookieParser = require('cookie-parser'), bodyParser = require('body-parser'), favicon = require('serve-favicon'), config = require('./config'), path = require('path'); var app = express(), port, server; app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(cookieParser()); app.use(bodyParser.urlencoded({limit: '<100mb>'})); app.use(require('./middleware/session')); app.use(require('./middleware/sendHttpError')); app.use(require('./middleware/loadUser')); port = config.port || 49001; app.set('port', port); server = http.createServer(app); server.on('error', serverError); server.on('listening', serverListening); require('./routes')(app); app.use(express.static(path.join(__dirname, 'public'))); server.listen(port); require('./createDB'); function serverError(error) { if (error.syscall !== 'listen') { throw error; } var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port; if (error.code === 'EACCES') { console.error(bind + ' requires elevated privileges'); process.exit(1); } else if (error.code === 'EADDRINUSE') { console.error(bind + ' is already in use'); process.exit(1); } else { throw error; } } function serverListening() { var address = server.address(), bind = typeof address === 'string' ? 'pipe ' + address : 'port ' + address.port; console.log('Listening on ' + bind); }
Листинг файла routes.js
var path = require('path'), checkAuth = require('./middleware/checkAuth'); module.exports = function(app) { app.get('/', function(req, res) { res.sendFile(path.join(__dirname + '/public/template/index.html')); }); app.post('/register', require('./routes/register').post); app.post('/login', require('./routes/login').post); app.get('/login', checkAuth, require('./routes/login').get); app.post('/logout', require('./routes/logout').post); app.get('/categories', checkAuth, require('./routes/categories').get); app.post('/goods', checkAuth, require('./routes/goods').post); };
Листинг файла lib/mongoose.js
var mongoose = require('mongoose'); var config = require('../config'); mongoose.connect(config.mongodb.main); module.exports = mongoose;
Листинг файла lib/session_store.js
const session = require('express-session'); const MongoStore = require('connect-mongo')(session); module.exports = function (mongoose) { return new MongoStore({ mongooseConnection: mongoose.connection }) };
Листинг файла middleware/checkAuth.js
module.exports = function(req, res, next) { if (!req.session.user) { return res.status(401).send({ error: "Вы не авторизованы" }); } next(); };
Листинг файла middleware/loadUser.js
var User = require('../models/user').User; module.exports = function(req, res, next) { req.user = res.locals.user = null; if (!req.session.user) return next(); User.findById(req.session.user, function(err, user) { if (err) return next(err); req.user = res.locals.user = user; next(); }); };
Листинг файла middleware/sendHttpError.js
module.exports = function (req, res, next) { res.sendHttpError = function (error) { res.status(error.status); if (res.req.headers['x-requested-with'] == 'XMLHttpRequest') { res.json(error); } else { res.send(error.message); } }; next(); };
Листинг файла middleware/session.js
var session = require('express-session'), config = require('../config'), mongoose = require('../lib/mongoose'), sessionStore = require('../lib/session_store')(mongoose); module.exports = session({ secret: config.session, name: 'sid', resave: false, saveUninitialized: false, cookie: { maxAge: null }, store: sessionStore });
Листинг файла models/category.js
var util = require('util'); var mongoose = require('../lib/mongoose'), Schema = mongoose.Schema; var schema = new Schema({ id: { type: Number, required: true }, name: { type: String, required: true }, img: { type: String, required: true } }); exports.Category = mongoose.model('Category', schema);
Листинг файла models/goods.js
var util = require('util'); var mongoose = require('../lib/mongoose'), Schema = mongoose.Schema; var schema = new Schema({ id: { type: Number, required: true }, name: { type: String, required: true }, img: { type: String, required: true }, price: { type: Number, required: true }, category: { type: Number, required: true }, quantity: { type: Number, required: true, default: 0 } }); exports.Goods = mongoose.model('Goods', schema);
Листинг файла models/user.js
var crypto = require('crypto'); var async = require('async'); var util = require('util'); var mongoose = require('../lib/mongoose'), Schema = mongoose.Schema; var schema = new Schema({ username: { type: String, unique: true, required: true }, hashedPassword: { type: String, required: true }, salt: { type: String, required: true }, created: { type: Date, default: Date.now } }); schema.methods.encryptPassword = function (password) { return crypto.createHmac('sha1', this.salt).update(password).digest('hex'); }; schema.virtual('password') .set(function (password) { this._plainPassword = password; this.salt = Math.random() + ''; this.hashedPassword = this.encryptPassword(password); }) .get(function () { return this._plainPassword; }); schema.methods.checkPassword = function (password) { return this.encryptPassword(password) === this.hashedPassword; }; schema.statics.authorize = function (username, password, callback) { var User = this; async.waterfall([ function (callback) { User.findOne({username: username}, callback); }, function (user, callback) { if (user) { if (user.checkPassword(password)) { callback(null, user); } else { callback(new AuthError("Неправильный пароль")); } } else { callback(new AuthError("Пользователь с таким логином не зарегистрирован")); } } ], callback); }; schema.statics.register = function (username, password, repeat, callback) { var User = this; async.waterfall([ function (callback) { User.findOne({username: username}, callback); }, function (user, callback) { if (user) { callback(new AuthError("Такой пользователь уже зарегистрирован")); } else { if (password === repeat) { var user = new User({username: username, password: password}); user.save(function (err) { if (err) return callback(err); callback(null, user); }); } else { callback(new AuthError("Пароли не совпадают")); } } } ], callback); }; exports.User = mongoose.model('User', schema); function AuthError(message) { Error.apply(this, arguments); Error.captureStackTrace(this, AuthError); this.message = message; } util.inherits(AuthError, Error); AuthError.prototype.name = 'AuthError'; exports.AuthError = AuthError;
Листинг файла public/app.js
'use strict'; angular .module('myApp', ['ui.router']) .config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) { $stateProvider.state('home', { url: '/home', templateUrl: 'template/home.html', pageTitle: 'Главная', params: {} }).state('chat', { url: '/chat', templateUrl: 'template/chat.html', pageTitle: 'Чат', params: {} }).state('login', { url: '/login', templateUrl: 'template/login.html', pageTitle: 'Вход', params: {} }).state('logout', { url: '/logout', pageTitle: 'Выход', params: {}, controller: function ($http, $state) { $http({method: 'POST', url: '/logout'}); $state.go('home'); window.location.reload(); } }).state('categories', { url: '/categories', templateUrl: 'template/categories.html', pageTitle: 'Каталог', params: {}, resolve:{ access: function($http){ return $http({method: 'GET', url: '/login'}).then(function (res) { return res; }, function (res) { return res; }); }, } }).state('goods', { url: '/goods', templateUrl: 'template/goods.html', pageTitle: 'Товары', params: { category: null }, resolve:{ access: function($http){ return $http({method: 'GET', url: '/login'}).then(function (res) { return res; }, function (res) { return res; }); }, } }).state('cart', { url: '/cart', templateUrl: 'template/cart.html', pageTitle: 'Корзина', params: { category: null }, resolve:{ access: function($http){ return $http({method: 'GET', url: '/login'}).then(function (res) { return res; }, function (res) { return res; }); }, } }).state('about', { url: '/about', templateUrl: 'template/about.html', pageTitle: 'О нас', params: {} }).state('shipping', { url: '/shipping', templateUrl: 'template/shipping.html', pageTitle: 'Доставка', params: {} }).state('profile', { url: '/profile', templateUrl: 'template/profile.html', pageTitle: 'Личный кабинет', params: {} }); $urlRouterProvider.otherwise('/home'); $stateProvider.state("otherwise", {url: '/otherwise'}); }]) .run(['$state', '$rootScope', '$stateParams', 'userService', '$http', function ($state, $rootScope, $stateParams, userService, $http) { $rootScope.$state = $state; $rootScope.$stateParams = $stateParams; $rootScope.$on("$includeContentLoaded", function () { $('body').scrollTop(0); }); $rootScope.$on('$stateChangeSuccess', function () { userService.navChange(); }); $http({ url: "/login", method: "GET" }).then(function (res) { userService.username = res.data.username; }, function (res) { userService.username = false; }); }]) .service('userService', function () { return { goods: null, username: null, order: {} }; }) .controller('navController', function ($state, userService, $http, $scope, $rootScope) { var vm = this; userService.navChange = function () { var tabs = { home: {name: 'Главная', url: 'home', active: false}, login: {name: 'Авторизация', url: 'login', active: false}, logout: {name: 'Выход', url: 'logout', active: false}, categories: {name: 'Каталог', url: 'categories', active: false}, cart: {name: 'Корзина', url: 'cart', active: false}, about: {name: 'О нас', url: 'about', active: false}, profile: {name: 'Личный кабинет', url: 'profile', active: false}, shipping: {name: 'Доставка', url: 'shipping', active: false} }; if (tabs[$state.current.name]) { tabs[$state.current.name].active = true; } else { tabs['categories'].active = true; } if (userService.username) { vm.tabs = [tabs.home, tabs.about, tabs.shipping, tabs.categories, tabs.cart, tabs.profile, tabs.logout]; } else { vm.tabs = [tabs.home, tabs.about, tabs.shipping, tabs.login]; } } }) .controller('homeController', function ($state, $scope, $rootScope) { var vm = this; }) .controller('aboutController', function ($state, $scope, $rootScope) { var vm = this; }) .controller('shippingController', function ($state, $scope, $rootScope) { var vm = this; }) .controller('profileController', function ($state, $scope, $rootScope) { var vm = this; }) .controller('loginController', function ($state, $http, userService, $scope, $rootScope) { var vm = this; vm.loginRegister = true; vm.registerForm = function () { vm.loginRegister = false; vm.error = false; }; vm.loginForm = function () { vm.loginRegister = true; vm.error = false; }; vm.register = function () { if (vm.password === vm.repeat) { $http({ url: "/register", method: "POST", headers: { "content-type": 'application/x-www-form-urlencoded' }, data: 'username=' + vm.username + '&password=' + vm.password + '&repeat=' + vm.repeat }).then(function (res) { userService.username = vm.username; userService.navChange(); $state.go('categories'); }, function (res) { if (res.status === 403) { vm.error = res.data.message; } else { $state.go('error'); } }); } else { vm.error = 'Введенные пароли не совпадают'; } }; vm.login = function () { $http({ url: "/login", method: "POST", headers: { "content-type": 'application/x-www-form-urlencoded' }, data: 'username=' + vm.username + '&password=' + vm.password }).then(function (res) { userService.username = vm.username; userService.navChange(); $state.go('categories'); }, function (res) { if (res.status === 403) { vm.error = res.data.message; } else { $state.go('error'); } }); } }) .controller('categoriesController', function ($state, $http, $scope, $rootScope) { var vm = this; $state.current.resolve.access($http).then(function(res){ if (res.status === 401) { vm.error = res.data.error; } }); $http({ url: "/categories", method: "GET" }).then(function (res) { vm.categories = res.data; }, function (res) { vm.error = res.data.error; }); vm.openCategory = function (id) { $state.go('goods', { category: id }) }; }) .controller('goodsController', function ($state, $http, $scope, $rootScope, $stateParams, userService) { var vm = this; $state.current.resolve.access($http).then(function(res){ if (res.status === 401) { vm.error = res.data.error; } }); $http({ url: "/goods", method: "POST", headers: { "content-type": 'application/x-www-form-urlencoded' }, data: 'category=' + $stateParams.category }).then(function (res) { var good, i; vm.goods = res.data; for (good in userService.order) { for (i = 0; i < vm.goods.length; i++) { if (vm.goods[i].id == good) { vm.goods[i].quantity = userService.order[good]; } } } }, function (res) { $state.go('home'); }); vm.addToCart = function (id, price, quantity) { userService.order[id] = quantity; } }) .controller('cartController', function ($state, $http, $scope, $rootScope, $stateParams, userService) { var vm = this; vm.all = 0; vm.state = 0; vm.locations = [{name:'Минск'},{name:'Минская область'},{name:'Беларусь'}]; $state.current.resolve.access($http).then(function(res){ if (res.status === 401) { vm.error = res.data.error; } }); $http({ url: "/goods", method: "POST" }).then(function (res) { var good, i; vm.goods = res.data; vm.shipping = 0; for (good in userService.order) { for (i = 0; i < vm.goods.length; i++) { if (vm.goods[i].id == good) { vm.goods[i].quantity = userService.order[good]; } } } for (i = 0; i < vm.goods.length; i++) { vm.all += vm.goods[i].quantity * vm.goods[i].price; } vm.locationChange(); }, function (res) { $state.go('home'); }); vm.locationChange = function () { if (vm.state.name === "Минская область") { if (vm.all < 200) { vm.shipping = 20; } else { vm.shipping = 0; } } else if (vm.state.name === "Беларусь") { if (vm.all < 500) { vm.shipping = 50; } else { vm.shipping = 0; } } else { if (vm.all < 100) { vm.shipping = 10; } else { vm.shipping = 0; } } vm.resume = vm.all + vm.shipping; } });
Листинг файла public/template/about.html
<div ng-controller="aboutController as vm"> <p class="lead">За шесть лет своей деятельности мы прошли большой путь от небольшой торговой точки до полноценного магазина товаров для животных. За это время нам удалось не только значительно расширить ассортимент представленных зоотоваров, но и самое важное - завоевать популярность среди владельцев домашних животных. Отличительными чертами нашего магазина стали умеренные цены, качественное обслуживание и большой выбор товаров для животных от ведущих мировых производителей.</p> <p class="lead">Магазин имеет площадь 150 м2, разделен на секции. В настоящий момент ассортимент магазина постоянно расширяется и изменяется. В продаже всегда есть товары, которые популярны благодаря своему отличному соотношению цены и качества. Мы можем предложить вам только те товары, которые уже проверены временем и пользуются заслуженной популярностью у владельцев домашних животных. Для постоянных клиентов действуют скидочные карты 3-5%, проводятся акции и предлагаются скидки на различные категории зоотоваров.</p> <p class="lead">Наш телефон для связи: + 375 29 187-55-64</p> </div>
Листинг файла public/template/cart.html
<div ng-controller="cartController as vm"> <div ng-if="vm.error"> <div class="card card-inverse card-danger text-center"> <div class="card-block"> <blockquote class="card-blockquote">Вы не авторизовались и не можете заказывать товары</blockquote> </div> </div> </div> <div ng-if="!vm.error"> <table class="table"> <thead> <tr> <th>Товар</th> <th>Количество</th> <th>Цена</th> </tr> </thead> <tbody> <tr ng-repeat="item in vm.goods"> <td><img class="categoryImgTumb" src="/img/{{item.img}}"> {{item.name}}</td> <td>{{item.quantity}}</td> <td>{{item.quantity * item.price}}</td> </tr> <tr> <td>Итого</td> <td></td> <td>{{vm.all}}</td> </tr> </tbody> </table> <form ng-if="vm.all"> <div class="form-group"> <select class="form-control" ng-options="location.name for location in vm.locations" ng-init="vm.state=vm.locations[0]" ng-model="vm.state" ng-change="vm.locationChange()" required> </select> </div> <div class="form-group"> <input class="form-control" placeholder="Ваш адрес" ng-model="vm.address" required> </div> <div class="form-group"> <span>Стоимость доставки: {{vm.shipping}}</span> </div> <div class="form-group"> <span>Итого включая доставку: {{vm.resume}}</span> </div> <div class="form-group"> </div> <div class="form-group"> <button class="btn btn-primary btn-block">Подтвердить заказ</button> </div> </form> </div> </div>
Листинг файла public/template/categories.html
<div ng-controller="categoriesController as vm"> <div ng-if="vm.error"> <div class="card card-inverse card-danger text-center"> <div class="card-block"> <blockquote class="card-blockquote">Вы не авторизовались и не можете заказывать товары</blockquote> </div> </div> </div> <div ng-if="!vm.error"> <div class="row"> <div class="col-md-6 col-xs-12 mb-3 cart" ng-repeat="item in vm.categories"> <a ng-click="vm.openCategory(item.id)"> <div class="text-center"><b>{{item.name}}</b></div> <div><img class="categoryImg" src="/img/{{item.img}}"></div> </a> </div> </div> </div> </div>
Листинг файла public/template/goods.html
<div ng-controller="goodsController as vm"> <div ng-if="vm.error"> <div class="card card-inverse card-danger text-center"> <div class="card-block"> <blockquote class="card-blockquote">Вы не авторизовались и не можете заказывать товары</blockquote> </div> </div> </div> <div ng-if="!vm.error"> <div class="row"> <div class="col-md-4 col-xs-12 mb-3" ng-repeat="item in vm.goods"> <div class="text-center"><b>{{item.name}}</b></div> <div class="mb-3"><img class="categoryImg" src="/img/{{item.img}}"></div> <div class="text-center mb-3"><b>Цена за штуку: {{item.price}}</b></div> <form ng-submit="vm.addToCart(item.id, item.price, item.quantity)" class="input-group"><input ng-model="item.quantity" type="number" class="form-control"><button type="submit" class="input-group-addon cart">Добавить в корзину</button></form> </div> </div> </div> </div>
Листинг файла public/template/home.html
<div ng-controller="homeController as vm"> <p class="lead">Мы постоянно расширяем свой ассортимент, поставляя только качественные товары для животных популярных брендов. Всегда умеренные цены, вежливый и отзывчивый персонал, оперативная работа и гарантия качества – все это наш зоомагазин</p> <p class="lead">Самым главным достижением нашего зоомагазина является доверие и любовь владельцев домашних животных. Для постоянных клиентов у нас предусмотрены скидки, проводятся регулярные акции, где можно приобрести товары по специальным ценам.Интернет-магазин зоотоваров предлагает только ту продукцию, которая проверена временем и имеет хорошие отзывы покупателей. Мы тщательно следим за качеством, потому что ценим своих клиентов.</p> <p class="lead">Мы предлагаем большой выбор сухих кормов Acana, Orijen, Royal Canin, Bosch, Hills, Eukanuba и Purina Pro Plan. Разнообразить рацион домашних питомцев помогут консервы, паучи и лакомства Зоогурман, CatNatura, Dr Alders (Германия), Brit, Molina, Triol и многие другие.Кроме того, в нашем зоомагазине вы найдете профессиональную амуницию и средства по уходу, которые идеально подойдут для животных, участвующих в выставках. Цепочки-кобры, ринговые водилки и поводки, ринговки, шампуни для шерсти, расчески – все то, что необходимо для удачного выступления.</p> <p class="lead">Ассортимент игрушек для котов и собак приятно порадует своим разнообразием. Вы можете приобрести кольца, мячики, кусалки-жгуты и разнообразные игрушки Kinologprofi, Puller, Rogz, Trixie, Kong, которые сделают досуг питомцев веселым и разнообразным.Обратите внимание на когтеточки, переноски и домики Trixie, завоевавшие популярность благодаря отличному качеству, долгой службе и привлекательности для домашних любимцев.</p> <p class="lead">Радуйте своих питомцев, а мы будем радовать вас приятными скидками, умеренными ценами и новыми товарами для животных высокого качества.</p> <p class="lead">Авторизуйтесь на сайте, что бы иметь возможность приобретать наши товары.</p> </div>
Листинг файла public/template/index.html
<!DOCTYPE html> <html ng-app="myApp"> <head> <title ng-bind="$state.current.pageTitle"></title> <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"> <link rel="stylesheet" href="/bootstrap.css"/> <script src="/jquery-3.2.1.min.js"></script> <script src="/angular.js"></script> <script src="/angular-ui-router.js"></script> <script src="/app.js"></script> </head> <body> <div class="container"> <div ng-controller="navController as vm"> <ul class="nav nav-pills nav-fill border-bottom-1 mt-2 mb-5"> <img class="logo" src="/img/logo.jpg"> <li class="nav-item" ng-repeat="nav in vm.tabs"> <a class="nav-link {{nav.active ? 'active' : ''}}" ui-sref="{{nav.url}}">{{nav.name}}</a> </li> </ul> </div> <div ui-view></div> </div> <footer class="footer"> <div class="container"> <span class="text-muted">г. Минск, пр. Независимости 46, "Наш зоомагазин". 2017</span> </div> </footer> </body> </html>
Листинг файла public/template/login.html
<div ng-controller="loginController as vm"> <form class="form-horizontal login-form" ng-show="vm.loginRegister" ng-submit="vm.login()"> <div class="form-group"> <input class="form-control" placeholder="Ваш логин" ng-model="vm.username" required> </div> <div class="form-group"> <input type="password" class="form-control" placeholder="Пароль" ng-model="vm.password" required> </div> <div class="form-group" ng-show="vm.error"> <div class="card card-inverse card-danger text-center"> <div class="card-block"> <blockquote class="card-blockquote">{{vm.error}}</blockquote> </div> </div> </div> <div class="form-group"> <button type="submit" class="btn btn-primary cart mr-3">Авторизоваться</button><button type="button" class="btn cart" ng-click="vm.registerForm()">Регистрация</button> </div> </form> <form class="form-horizontal login-form" ng-show="!vm.loginRegister" ng-submit="vm.register()"> <div class="form-group"> <input class="form-control" placeholder="Ваш логин" ng-model="vm.username" required> </div> <div class="form-group"> <input type="password" class="form-control" placeholder="Пароль" ng-model="vm.password" required> </div> <div class="form-group"> <input type="password" class="form-control" placeholder="Повторите пароль" ng-model="vm.repeat" required> </div> <div class="form-group" ng-show="vm.error"> <div class="card card-inverse card-danger text-center"> <div class="card-block"> <blockquote class="card-blockquote">{{vm.error}}</blockquote> </div> </div> </div> <div class="form-group"> <button type="submit" class="btn btn-primary cart mr-3">Зарегистрироваться</button><button type="button" class="btn cart" ng-click="vm.loginForm()">Авторизация</button> </div> </form> </div>
Листинг файла public/template/shipping.html
<div ng-controller="shippingController as vm"> <p class="lead">Бесплатная доставка товаров по г. Минску в пределах МКАД от 100 руб. В остальных случаях стоимость доставки по г. Минску составляет 10 руб.</p> <p class="lead">Бесплатная доставка товаров по Минскому району от 200 руб. В остальных случаях стоимость доставки по Минскому району составляет 20 руб.</p> <p class="lead">Бесплатная доставка товаров по остальной части Беларуси от 500 руб. В остальных случаях стоимость доставки по Беларуси составляет 50 руб.</p> <p class="lead">Доставка товаров по Минску осуществляется ежедневно: пн-пт: 12:00–17:30 и 18:30–22:00, сб-вс: 17:30–22:00.</p> <p class="lead">Оплата осуществляется наличными курьеру по факту доставки</p> </div>
Листинг файла routes/categories.js
var Category = require('../models/category').Category; exports.get = function(req, res) { Category.find({}).exec(function(err, categories) { if (err) return callback(err); res.json(categories); }); };
Листинг файла routes/goods.js
var Goods = require('../models/goods').Goods; var HttpError = require('../error').HttpError; exports.post = function(req, res, next) { if (req.body && req.body.category) { Goods.find({category: req.body.category >= 0 ? req.body.category : 0 }).sort({ id: 1 }).exec(function(err, goods) { if (err) return next(new HttpError(404, err.message)); res.json(goods); }); } else { Goods.find().sort({ id: 1 }).exec(function(err, goods) { if (err) return next(new HttpError(404, err.message)); res.json(goods); }); } };
Листинг файла routes/login.js
var User = require('../models/user').User; var HttpError = require('../error').HttpError; var AuthError = require('../models/user').AuthError; var async = require('async'); exports.get = function (req, res) { res.json(req.session.user); }; exports.post = function (req, res, next) { var username = req.body.username; var password = req.body.password; User.authorize(username, password, function (err, user) { if (err) { if (err instanceof AuthError) { return res.status(403).json({message: err.message}); } else { return next(err); } } req.session.user = user; res.send(req.session.user); }); };
Листинг файла routes/logout.js
exports.post = function(req, res) { req.session.destroy(); res.redirect('/'); };
Листинг файла routes/register.js
var User = require('../models/user').User; var HttpError = require('../error').HttpError; var AuthError = require('../models/user').AuthError; var async = require('async'); exports.post = function(req, res, next) { var username = req.body.username; var password = req.body.password; var repeat = req.body.repeat; User.register(username, password, repeat, function(err, user) { if (err) { if (err instanceof AuthError) { return res.status(403).json({message: err.message}); } else { return next(err); } } req.session.user = user; res.send(req.session.user); }); };
