├── .bowerrc ├── README.md ├── app ├── models │ ├── user.js │ ├── movie.js │ ├── comment.js │ └── category.js ├── views │ ├── layout.jade │ ├── includes │ │ ├── head.jade │ │ └── header.jade │ └── pages │ │ ├── adminCategory.jade │ │ ├── login.jade │ │ ├── regist.jade │ │ ├── userlist.jade │ │ ├── categoryList.jade │ │ ├── list.jade │ │ ├── index.jade │ │ ├── results.jade │ │ ├── detail.jade │ │ └── admin.jade ├── controllers │ ├── comment.js │ ├── category.js │ ├── index.js │ ├── user.js │ └── movie.js └── schemas │ ├── category.js │ ├── movie.js │ ├── comment.js │ └── user.js ├── public ├── css │ └── style.css └── js │ ├── detail.js │ └── admin.js ├── .gitattributes ├── bower.json ├── gruntfile.js ├── package.json ├── app.js ├── .gitignore └── config └── router.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "public/libs" 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Imovie 2 | 3 | ###这是一个node+mongodb搭建的一个简单的电影网站 4 | 5 | ###主要功能: 6 | >用户的注册和登录 7 | >电影的录入和展示 8 | >用户对电影的评论 9 | >电影的分类和搜索 10 | >上传海报和访客统计 11 | 12 | -------------------------------------------------------------------------------- /app/models/user.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | var UserSchema = require('../schemas/user.js') 3 | var User = mongoose.model('User', UserSchema) 4 | 5 | module.exports = User -------------------------------------------------------------------------------- /app/models/movie.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | var MovieSchema = require('../schemas/movie.js') 3 | var Movie = mongoose.model('Movie', MovieSchema) 4 | 5 | module.exports = Movie -------------------------------------------------------------------------------- /app/views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | meta(charset="utf-8") 5 | title #{title} 6 | include ./includes/head 7 | body 8 | include ./includes/header 9 | block content -------------------------------------------------------------------------------- /app/models/comment.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | var CommentSchema = require('../schemas/comment.js') 3 | var Comment = mongoose.model('Comment', CommentSchema) 4 | 5 | module.exports = Comment -------------------------------------------------------------------------------- /app/models/category.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | var CategorySchema = require('../schemas/category.js') 3 | var Category = mongoose.model('Category', CategorySchema) 4 | 5 | module.exports = Category -------------------------------------------------------------------------------- /public/css/style.css: -------------------------------------------------------------------------------- 1 | /*电影列表的标题和内容位置布局*/ 2 | .table th, .table td { 3 | text-align: center; 4 | } 5 | 6 | /*主要内容距离顶部距离*/ 7 | .contentTop { 8 | margin-top: 70px; 9 | } 10 | 11 | /* 评论区和视频的间距 */ 12 | .panelTop { 13 | margin-top: 30px; 14 | } -------------------------------------------------------------------------------- /app/views/includes/head.jade: -------------------------------------------------------------------------------- 1 | link(href="/libs/bootstrap/dist/css/bootstrap.min.css", rel="stylesheet") 2 | link(href="/css/style.css", rel="stylesheet") 3 | script(src="/libs/jquery/dist/jquery.min.js") 4 | script(src="/libs/bootstrap/dist/js/bootstrap.min.js") 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /app/views/pages/adminCategory.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | .container.contentTop 5 | .row 6 | form.form-horizontal(method="post" action="/admin/category" ) 7 | .form-group 8 | label.col-sm-2.control-label(for="inputCategory") 电影分类 9 | .col-sm-10 10 | input#inputCategory.form-control(type="text", name="category[name]",value="#{category.name}") 11 | .form-group 12 | .col-sm-offset-2.col-sm-10 13 | button.btn.btn-primary(type="submit") 录入 -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Imovie", 3 | "version": "0.0.1", 4 | "homepage": "https://github.com/superpig/Imovie", 5 | "authors": [ 6 | "superpig <940578704@qq.com>" 7 | ], 8 | "description": "node.js开发电影网站", 9 | "main": "app.js", 10 | "keywords": [ 11 | "node.js", 12 | "movie" 13 | ], 14 | "license": "MIT", 15 | "ignore": [ 16 | "**/.*", 17 | "node_modules", 18 | "bower_components", 19 | "public/libs", 20 | "test", 21 | "tests" 22 | ], 23 | "dependencies": { 24 | "bootstrap": "~3.3.2" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/views/pages/login.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | .container.contentTop 5 | .row 6 | .col-md-4 7 | form(method="POST", action="/user/login") 8 | h2 登陆 9 | .form-group 10 | label(for="loginName") 用户名 11 | input#loginName.form-control(name="user[name]", type="text") 12 | .form-group 13 | label(for="loginPassword") 密码 14 | input#loginPassword.form-control(name="user[password]", type="text") 15 | .text-center 16 | button.btn.btn-success(type="submit") 提交 -------------------------------------------------------------------------------- /app/views/pages/regist.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | .container.contentTop 5 | .row 6 | .col-md-4 7 | form(method="POST", action="/user/regist") 8 | h2 注册 9 | .form-group 10 | label(for="signupName") 用户名 11 | input#signupName.form-control(name="user[name]", type="text") 12 | .form-group 13 | label(for="signupPassword") 密码 14 | input#signupPassword.form-control(name="user[password]", type="text") 15 | .text-center 16 | button.btn.btn-default(type="button" data-dismiss="modal") 关闭 17 | button.btn.btn-success(type="submit") 提交 -------------------------------------------------------------------------------- /app/views/pages/userlist.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | .container.contentTop 5 | .row 6 | table.table.table-hover.table-bordered 7 | thead 8 | tr 9 | th 名字 10 | th 时间 11 | th 查看 12 | th 更新 13 | th 删除 14 | tbody 15 | each item in users 16 | tr(class="item-id-#{item._id}") 17 | td #{item.name} 18 | td #{moment(item.meta.updateAt).format('MM/DD/YYYY')} 19 | td: a(target="_blank", href="../movie/#{item._id}") 查看 20 | td: a(target="_blank", href="../admin/update/#{item._id}") 修改 21 | td 22 | button.btn.btn-danger.del(type="button", data-id="#{item._id}") 删除 -------------------------------------------------------------------------------- /app/views/pages/categoryList.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | .container.contentTop 5 | .row 6 | table.table.table-hover.table-bordered 7 | thead 8 | tr 9 | th 分类名 10 | th 录入时间 11 | th 查看 12 | th 更新 13 | th 删除 14 | tbody 15 | each item in categories 16 | tr(class="item-id-#{item._id}") 17 | td #{item.name} 18 | td #{moment(item.meta.updateAt).format('MM/DD/YYYY')} 19 | td: a(target="_blank", href="../movie/#{item._id}") 查看 20 | td: a(target="_blank", href="../admin/update/#{item._id}") 修改 21 | td 22 | button.btn.btn-danger.del(type="button", data-id="#{item._id}") 删除 23 | script(src="/js/admin.js") -------------------------------------------------------------------------------- /public/js/detail.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | $('.headPhoto').click(function (e){ 3 | var target = $(this) 4 | var commentId = target.data('cid') 5 | var toId = target.data('tid') 6 | $('#textareaId').focus() 7 | //console.log($('#textareaId')) 8 | /* 9 | 作用: 设置回复对象为最后点击的对象 10 | 方法:如果隐藏表单存在只对其id复制,否则添加元素 11 | */ 12 | if ($('#commentId').length > 0) { 13 | $('#commentId').val(commentId) 14 | } else { 15 | $('').attr({ 16 | type: 'hidden', 17 | id: 'commentId', 18 | name: 'comment[cid]', 19 | value: commentId 20 | }).appendTo('#commentForm') 21 | } 22 | 23 | if ($('#toId').length > 0) { 24 | $('#toId').val(toId) 25 | } else { 26 | $('').attr({ 27 | type: 'hidden', 28 | id: 'toId', 29 | name: 'comment[tid]', 30 | value: toId 31 | }).appendTo('#commentForm') 32 | } 33 | }) 34 | }) -------------------------------------------------------------------------------- /app/views/pages/list.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | .container.contentTop 5 | .row 6 | table.table.table-hover.table-bordered 7 | thead 8 | tr 9 | th 电影名字 10 | th 导演 11 | th 国家 12 | th 上映年份 13 | th 录入时间 14 | th pv 15 | th 查看 16 | th 更新 17 | th 删除 18 | tbody 19 | each item in movies 20 | tr(class="item-id-#{item._id}") 21 | td #{item.title} 22 | td #{item.director} 23 | td #{item.country} 24 | td #{item.year} 25 | td #{moment(item.meta.updateAt).format('MM/DD/YYYY')} 26 | td #{item.pv} 27 | td: a(target="_blank", href="/movie/#{item._id}") 查看 28 | td: a(target="_blank", href="../movie/update/#{item._id}") 修改 29 | td 30 | button.btn.btn-danger.del(type="button", data-id="#{item._id}") 删除 31 | script(src="/js/admin.js") -------------------------------------------------------------------------------- /app/views/pages/index.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | .container.contentTop 5 | .row 6 | each category in categories 7 | .panel.panel-default 8 | .panel-heading 9 | h4 10 | a(href='/results?cat=#{category._id}&p=0') #{category.name} 11 | .panel-body 12 | if category.movies && category.movies.length > 0 13 | each item in category.movies 14 | .col-md-2.text-center 15 | .thumbnail 16 | a(href="/movie/#{item._id}") 17 | if item.poster.indexOf('http:') > -1 18 | img(src="#{item.poster}", alt="#{item.title}", width="150px" height="170px") 19 | else 20 | img(src="/upload/#{item.poster}", alt="#{item.title}", width="150px" height="170px") 21 | .caption 22 | h4 #{item.title} 23 | p: a.btn.btn-primary(href="/movie/#{item._id}", role="button") 看预告片 -------------------------------------------------------------------------------- /app/controllers/comment.js: -------------------------------------------------------------------------------- 1 | var Comment = require('../models/comment') 2 | 3 | 4 | //post comment 5 | exports.save = function (req, res){ 6 | var _comment = req.body.comment 7 | var movieId = _comment.movie 8 | 9 | if (_comment.cid) { 10 | Comment.findById(_comment.cid, function (err, comment) { 11 | var newReply = { 12 | from: _comment.from, 13 | to: _comment.tid, 14 | content: _comment.content 15 | } 16 | comment.reply.push(newReply) 17 | comment.save(function (err, comment) { 18 | console.log('reply') 19 | console.log(comment) 20 | if (err) { 21 | console.log(err) 22 | } 23 | res.redirect('/movie/' + movieId) 24 | }) 25 | }) 26 | } else { 27 | comment = new Comment(_comment) 28 | 29 | comment.save(function (err, comment){ 30 | if (err) { 31 | console.log(err) 32 | } 33 | res.redirect('/movie/' + movieId) 34 | }) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/schemas/category.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | var Schema = mongoose.Schema 3 | var ObjectId = Schema.Types.ObjectId 4 | 5 | var CategorySchema = new Schema({ 6 | name: { 7 | unique: true, 8 | type: String 9 | }, 10 | movies: [{type: ObjectId, ref: 'Movie'}], 11 | meta: { 12 | createAt: { 13 | type: Date, 14 | default: Date.now() 15 | }, 16 | updateAt: { 17 | type: Date, 18 | default: Date.now() 19 | } 20 | } 21 | }) 22 | 23 | CategorySchema.pre('save', function(next) { 24 | if (this.isNew) { 25 | this.meta.createAt = this.meta.updateAt = Date.now() 26 | } else { 27 | this.meta.updateAt = Date.now() 28 | } 29 | next() 30 | }) 31 | 32 | CategorySchema.statics = { 33 | fetch: function(cb) { 34 | return this 35 | .find({}) 36 | .sort('meta.updateAt') 37 | .exec(cb) 38 | }, 39 | findById: function(id, cb) { 40 | return this 41 | .findOne({_id: id}) 42 | .exec(cb) 43 | } 44 | } 45 | 46 | module.exports = CategorySchema -------------------------------------------------------------------------------- /app/controllers/category.js: -------------------------------------------------------------------------------- 1 | var Category = require('../models/category') 2 | 3 | 4 | //admin new category 5 | exports.new = function (req, res) { 6 | res.render('adminCategory', { 7 | title : '后台录入页', 8 | category: { 9 | name: "" 10 | } 11 | }) 12 | } 13 | 14 | 15 | 16 | // admin post category 17 | exports.save = function (req, res){ 18 | var _category = req.body.category 19 | Category.findOne({name: _category.name}, function (err, category) { 20 | if (!category ) { 21 | var newCategory = new Category(_category) 22 | newCategory.save(function (err, category) { 23 | if (err) { 24 | console.log(err) 25 | } 26 | res.redirect('/admin/category/list') 27 | }) 28 | } 29 | }) 30 | } 31 | 32 | //category list page 33 | exports.list = function(req, res) { 34 | Category.fetch(function (err, categories){ 35 | if (err) { 36 | console.log(err) 37 | } 38 | // console.log("mark") 39 | res.render('categoryList', { 40 | title: '分类列表页', 41 | categories: categories 42 | }) 43 | }) 44 | } 45 | 46 | -------------------------------------------------------------------------------- /gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | grunt.initConfig({ 4 | watch: { 5 | jade: { 6 | files: ['views/**'], 7 | options: { 8 | livereload: true 9 | } 10 | }, 11 | js: { 12 | files: ['public/js/**', 'models/**/*.js', 'schemas/**/*.js'], 13 | // tasks: ['jshint'], 14 | options: { 15 | livereload: true 16 | } 17 | } 18 | }, 19 | 20 | nodemon: { 21 | dev: { 22 | options: { 23 | file: 'app.js', 24 | args: [], 25 | ignoreFiles: ['README.md', 'node_modules/**', 'DS_Store'], 26 | watchedExtensions: ['js'], 27 | watchedFolders: ['./'], 28 | debug: true, 29 | delayTime: 1, 30 | env: { 31 | PORT: 3000 32 | }, 33 | cwd: __dirname 34 | } 35 | } 36 | }, 37 | 38 | concurrent: { 39 | tasks: ['nodemon', 'watch'], 40 | options: { 41 | logConcurrentOutput: true 42 | } 43 | } 44 | }) 45 | 46 | grunt.loadNpmTasks('grunt-contrib-watch') 47 | grunt.loadNpmTasks('grunt-nodemon') 48 | grunt.loadNpmTasks('grunt-concurrent') 49 | 50 | grunt.option('force', true) 51 | grunt.registerTask('default', ['concurrent']) 52 | } -------------------------------------------------------------------------------- /app/schemas/movie.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | var Schema = mongoose.Schema 3 | var ObjectId = Schema.Types.ObjectId 4 | 5 | var MovieSchema = new Schema({ 6 | category: { 7 | type: ObjectId, 8 | ref: 'Category' 9 | }, 10 | pv: { 11 | type: Number, 12 | default: 0 13 | }, 14 | director: String, 15 | title: String, 16 | language: String, 17 | country: String, 18 | summary: String, 19 | flash: String, 20 | poster: String, 21 | year: String, 22 | meta: { 23 | createAt: { 24 | type: Date, 25 | default: Date.now() 26 | }, 27 | updateAt: { 28 | type: Date, 29 | default: Date.now() 30 | } 31 | } 32 | }) 33 | 34 | MovieSchema.pre('save', function(next) { 35 | if (this.isNew) { 36 | this.meta.createAt = this.meta.updateAt = Date.now() 37 | } else { 38 | this.meta.updateAt = Date.now() 39 | } 40 | next() 41 | }) 42 | 43 | MovieSchema.statics = { 44 | fetch: function(cb) { 45 | return this 46 | .find({}) 47 | .sort('meta.updateAt') 48 | .exec(cb) 49 | }, 50 | findById: function(id, cb) { 51 | return this 52 | .findOne({_id: id}) 53 | .exec(cb) 54 | } 55 | } 56 | 57 | module.exports = MovieSchema -------------------------------------------------------------------------------- /app/schemas/comment.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | var Schema = mongoose.Schema 3 | var ObjectId = Schema.Types.ObjectId 4 | 5 | var CommentSchema = new Schema({ 6 | movie: {type: ObjectId, ref: 'Movie'}, 7 | from: {type: ObjectId, ref: 'User'}, 8 | reply: [{ 9 | from: {type: ObjectId, ref: 'User'}, 10 | to: {type: ObjectId, ref: 'User'}, 11 | content: String 12 | }], 13 | to: {type: ObjectId, ref: 'User'}, 14 | content: String, 15 | meta: { 16 | createAt: { 17 | type: Date, 18 | default: Date.now() 19 | }, 20 | updateAt: { 21 | type: Date, 22 | default: Date.now() 23 | } 24 | } 25 | }) 26 | 27 | CommentSchema.pre('save', function(next) { 28 | if (this.isNew) { 29 | this.meta.createAt = this.meta.updateAt = Date.now() 30 | } else { 31 | this.meta.updateAt = Date.now() 32 | } 33 | next() 34 | }) 35 | 36 | CommentSchema.statics = { 37 | fetch: function(cb) { 38 | return this 39 | .find({}) 40 | .sort('meta.updateAt') 41 | .exec(cb) 42 | }, 43 | findById: function(id, cb) { 44 | return this 45 | .findOne({_id: id}) 46 | .exec(cb) 47 | } 48 | } 49 | 50 | module.exports = CommentSchema -------------------------------------------------------------------------------- /app/views/pages/results.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | .container.contentTop 5 | .row 6 | .panel.panel-default 7 | .panel-heading 8 | h4 #{keyword} 9 | .panel-body 10 | if movies && movies.length > 0 11 | each item in movies 12 | .col-md-2.text-center 13 | .thumbnail 14 | a(href="/movie/#{item._id}") 15 | if item.poster.indexOf('http:') > -1 16 | img(src="#{item.poster}", alt="#{item.title}", width="150px" height="170px") 17 | else 18 | img(src="/upload/#{item.poster}", alt="#{item.title}", width="150px" height="170px") 19 | .caption 20 | h4 #{item.title} 21 | p: a.btn.btn-primary(href="/movie/#{item._id}", role="button") 看预告片 22 | ul.pagination 23 | - for (var i = 0; i < totalPage; i++) { 24 | - if (currentPage == (i + 1)) { 25 | li.active 26 | span #{currentPage} 27 | - } 28 | - else { 29 | li 30 | a(href='/results?#{query}&p=#{i}') #{i+1} 31 | - } 32 | - } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Imovie", 3 | "version": "0.0.1", 4 | "description": "node.js搭建电影网站", 5 | "main": "app.js", 6 | "dependencies": { 7 | "body-parser": "~1.10.2", 8 | "bson": "~0.2.18", 9 | "grunt": "~0.4.5", 10 | "express": "~4.11.1", 11 | "grunt-concurrent": "~1.0.0", 12 | "grunt-contrib-watch": "~0.6.1", 13 | "grunt-nodemon": "~0.4.0", 14 | "jade": "~1.9.1", 15 | "koa": "~0.15.0", 16 | "moment": "~2.9.0", 17 | "mongoose": "~3.8.22", 18 | "underscore": "~1.7.0", 19 | "rebuild": "~0.1.2", 20 | "node-gyp": "~1.0.2", 21 | "express-session": "~1.10.2", 22 | "cookie-parser": "~1.3.3", 23 | "connect-mongo": "~0.7.0", 24 | "morgan": "~1.5.1", 25 | "connect-multiparty": "~1.2.5" 26 | }, 27 | "devDependencies": { 28 | "bcrypt-nodejs": "0.0.3" 29 | }, 30 | "scripts": { 31 | "test": "\"echo \\\"Error: no test specified\\\" && exit 1\"" 32 | }, 33 | "repository": { 34 | "type": "git", 35 | "url": "https://github.com/superpig/Imovie.git" 36 | }, 37 | "keywords": [ 38 | "movie", 39 | "web" 40 | ], 41 | "author": "superpig", 42 | "license": "MIT", 43 | "bugs": { 44 | "url": "https://github.com/superpig/Imovie/issues" 45 | }, 46 | "homepage": "https://github.com/superpig/Imovie" 47 | } 48 | -------------------------------------------------------------------------------- /public/js/admin.js: -------------------------------------------------------------------------------- 1 | 2 | $(function(){ 3 | //删除电影列表中的项 4 | $('.del').click(function(e) { 5 | var target = $(e.target) 6 | var id = target.data('id') 7 | var tr = $('.item-id-' + id) 8 | 9 | $.ajax({ 10 | type: 'DELETE', 11 | url: '/admin/movie/list?id=' + id 12 | }) 13 | .done(function(result) { 14 | if (result.success === 1) { 15 | if (tr.length > 0) { 16 | tr.remove() 17 | } 18 | } 19 | }) 20 | }) 21 | 22 | //利用豆瓣api获取电影数据 23 | $('#douban').blur(function() { 24 | var douban = $(this) 25 | var id = douban.val() 26 | 27 | if (id) { 28 | $.ajax({ 29 | url: 'https://api.douban.com/v2/movie/subject/' + id, 30 | cache: true, 31 | type: 'get', 32 | dataType: 'jsonp', 33 | crossDomain: true, 34 | jsonp: 'callback', 35 | success: function(data) { 36 | $('#inputTitle').val(data.title) 37 | $('#inputDirector').val(data.directors[0].name) 38 | $('#inputCountry').val(data.countries[0]) 39 | $('#inputPoster').val(data.images.large) 40 | $('#inputYear').val(data.year) 41 | $('#inputSummary').val(data.summary) 42 | } 43 | }) 44 | .done(function() { 45 | console.log("success"); 46 | }) 47 | .fail(function() { 48 | console.log("error"); 49 | }) 50 | .always(function() { 51 | console.log("complete"); 52 | }) 53 | } 54 | }) 55 | }) -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | var port = process.env.PORT || 3000 3 | var path = require('path') 4 | var bodyParser = require('body-parser') 5 | var mongoose = require('mongoose') 6 | var cookieParser = require('cookie-parser') 7 | var session = require('express-session') 8 | var MongoStore = require('connect-mongo')(session) 9 | var morgan = require('morgan') 10 | var multipart = require('connect-multiparty') 11 | var app = express() 12 | var dbUrl = 'mongodb://localhost/imovie' 13 | 14 | //connect to mongoDB 15 | mongoose.connect(dbUrl) 16 | 17 | app.set('views', './app/views/pages') 18 | app.set('view engine', 'jade') 19 | app.use(cookieParser()) 20 | app.use(multipart()) 21 | 22 | app.use(session({ 23 | secret: 'imovie', 24 | resave: false, 25 | saveUninitialized: false, 26 | store: new MongoStore({ 27 | url: dbUrl, 28 | collection: 'sessions' 29 | }) 30 | })) 31 | 32 | app.use(bodyParser.urlencoded({ extended: true })) 33 | app.use(express.static(path.join(__dirname, 'public'))) 34 | app.locals.moment = require('moment') 35 | app.listen(port) 36 | 37 | //设置入口文件,输出日志和错误信息 38 | if ('development' === app.get('env')) { 39 | app.set('showStackError', true) 40 | app.use(morgan(':method :url :status')) 41 | //格式化源代码 42 | app.locals.pretty =true 43 | mongoose.set('debug', true) 44 | } 45 | 46 | //导出路由模块 47 | require('./config/router')(app) 48 | 49 | console.log('Imovie started on port' + port) 50 | 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | 30 | # ========================= 31 | # Operating System Files 32 | # ========================= 33 | 34 | # OSX 35 | # ========================= 36 | 37 | .DS_Store 38 | .AppleDouble 39 | .LSOverride 40 | 41 | # Thumbnails 42 | ._* 43 | 44 | # Files that might appear on external disk 45 | .Spotlight-V100 46 | .Trashes 47 | 48 | # Directories potentially created on remote AFP share 49 | .AppleDB 50 | .AppleDesktop 51 | Network Trash Folder 52 | Temporary Items 53 | .apdisk 54 | 55 | # Windows 56 | # ========================= 57 | 58 | # Windows image file caches 59 | Thumbs.db 60 | ehthumbs.db 61 | 62 | # Folder config file 63 | Desktop.ini 64 | 65 | # Recycle Bin used on file shares 66 | $RECYCLE.BIN/ 67 | 68 | # Windows Installer files 69 | *.cab 70 | *.msi 71 | *.msm 72 | *.msp 73 | 74 | # Windows shortcuts 75 | *.lnk 76 | -------------------------------------------------------------------------------- /app/controllers/index.js: -------------------------------------------------------------------------------- 1 | var Movie = require('../models/movie') 2 | var Category = require('../models/category') 3 | 4 | //index page 5 | exports.index = function (req, res) { 6 | Category 7 | .find({}) 8 | .populate({path: 'movies', options: {limit: 6}}) 9 | .exec(function (err, categories) { 10 | if (err) { 11 | console.log(err) 12 | } 13 | res.render('index', { 14 | title : 'Imovie 首页', 15 | categories: categories 16 | }) 17 | }) 18 | } 19 | 20 | //search page 21 | exports.search = function (req, res) { 22 | var catId = req.query.cat 23 | var search = req.query.search 24 | var page = parseInt(req.query.p, 10) || 0 25 | var count = 2 26 | var index = page * count 27 | 28 | // console.log(catId) 29 | if (catId) { 30 | Category 31 | .find({_id: catId}) 32 | .populate({ 33 | path: 'movies', 34 | select: 'title poster', 35 | }) 36 | .exec(function (err, categories) { 37 | if (err) { 38 | console.log(err) 39 | } 40 | 41 | 42 | var movies = categories[0].movies || [] 43 | // console.log(movies) 44 | var results = movies.slice(index, index + count) 45 | // console.log(results) 46 | res.render('results', { 47 | title : 'Imovie 首页', 48 | keyword: categories[0].name, 49 | movies: results, 50 | query: 'cat='+catId, 51 | currentPage: (page + 1), 52 | totalPage: Math.ceil(movies.length / 2) 53 | }) 54 | }) 55 | } else { 56 | Movie 57 | .find({title: new RegExp(search + '*', 'i')}) 58 | .exec(function (err, movies) { 59 | if (err) { 60 | console.log(err) 61 | } 62 | var results = movies.slice(index, index + count) 63 | res.render('results', { 64 | keyword: search, 65 | movies: results, 66 | query: 'search='+ search, 67 | currentPage: (page + 1), 68 | totalPage: Math.ceil(movies.length / 2) 69 | }) 70 | }) 71 | 72 | } 73 | } -------------------------------------------------------------------------------- /app/schemas/user.js: -------------------------------------------------------------------------------- 1 | /* 2 | 用户模型 3 | */ 4 | var mongoose = require('mongoose') 5 | //var bcrypt = require('bcrypt') 6 | var bcrypt = require('bcrypt-nodejs') 7 | var SALT_WORK_FACTOR = 10 8 | 9 | // 用户模型的基本属性 10 | var UserSchema = new mongoose.Schema({ 11 | name: { 12 | unique: true, 13 | type: String 14 | }, 15 | /* 16 | 0 normal user 17 | 1 verified user 18 | ... 19 | 10 admin user 20 | >30 super user 21 | */ 22 | role: { 23 | type: Number, 24 | default: 0 25 | }, 26 | password: String, 27 | meta: { 28 | createAt: { 29 | type: Date, 30 | default: Date.now() 31 | }, 32 | updateAt: { 33 | type: Date, 34 | default: Date.now() 35 | } 36 | } 37 | }) 38 | 39 | //保存用户之前的操作:设置meta属性,利用哈希算法和加盐算法重置密码 40 | UserSchema.pre('save', function(next) { 41 | var user = this 42 | if (this.isNew) { 43 | this.meta.createAt = this.meta.updateAt = Date.now() 44 | } else { 45 | this.meta.updateAt = Date.now() 46 | } 47 | /*bcrypt.genSalt(SALT_WORK_FACTOR, function (err, salt) { 48 | if (err) { 49 | return next(err) 50 | } 51 | bcrypt.crypto.Hash(user.password, salt, function (err, hash) { 52 | if (err) { 53 | return next(err) 54 | } 55 | user.password = hash 56 | next() 57 | }) 58 | })*/ 59 | bcrypt.hash(user.password, null, null, function (err, hash){ 60 | if (err) { 61 | return next(err) 62 | } 63 | user.password = hash 64 | next() 65 | }) 66 | }) 67 | 68 | UserSchema.methods = { 69 | comparePassword: function (_password, cb) { 70 | bcrypt.compare(_password, this.password, function (err, res) { 71 | if (err) { 72 | cb(err) 73 | } 74 | cb(null, res) 75 | }) 76 | } 77 | } 78 | 79 | //静态方法:fetch查找所有的用户,findById通过id查找用户,通过模型就可以调用 80 | UserSchema.statics = { 81 | fetch: function(cb) { 82 | return this 83 | .find({}) 84 | .sort('meta.updateAt') 85 | .exec(cb) 86 | }, 87 | findById: function(id, cb) { 88 | return this.findOne({ 89 | _id: id 90 | }).exec(cb) 91 | }, 92 | findByName: function (_name, cb) { 93 | return this.findOne({ 94 | name: _name 95 | }).exec(cb) 96 | } 97 | } 98 | 99 | module.exports = UserSchema -------------------------------------------------------------------------------- /config/router.js: -------------------------------------------------------------------------------- 1 | var _ = require('underscore') 2 | var multipart = require('connect-multiparty') 3 | var Index = require('../app/controllers/index') 4 | var User = require('../app/controllers/user') 5 | var Movie = require('../app/controllers/movie') 6 | var Comment = require('../app/controllers/comment') 7 | var Category = require('../app/controllers/category') 8 | 9 | module.exports = function (app) { 10 | //pre handle user 11 | app.use(function (req, res, next) { 12 | var _user = req.session.user 13 | app.locals.user = _user 14 | console.log(_user) 15 | next() 16 | }) 17 | 18 | /*首页*/ 19 | //index page 20 | app.get('/', Index.index) 21 | app.get('/results', Index.search) 22 | 23 | /*电影*/ 24 | // detail page 25 | app.get('/movie/:id', Movie.detail) 26 | //admin page 27 | app.get('/admin/movie/new', User.loginRequired, User.adminRequired, Movie.new) 28 | //admin update movie 29 | app.get('/admin/movie/update/:id', User.loginRequired, User.adminRequired, Movie.update) 30 | //list page 31 | app.get('/admin/movie/list', User.loginRequired, User.adminRequired, Movie.list) 32 | // admin post movie 33 | app.post('/admin/movie', User.loginRequired, User.adminRequired, Movie.savePoster, Movie.save) 34 | //list delete movie 35 | app.delete('/admin/movie/list', User.loginRequired, User.adminRequired, Movie.delete) 36 | 37 | /*用户*/ 38 | //post regist page 39 | app.post('/user/regist', User.regist) 40 | //post login page 41 | app.post('/user/login', User.login) 42 | //get regist page 43 | app.get('/regist', User.showRegist) 44 | //get login page 45 | app.get('/login', User.showLogin) 46 | //logout page 47 | app.get('/logout', User.logout) 48 | //userlist page 49 | app.get('/admin/user/list', User.loginRequired, User.adminRequired,User.list) 50 | 51 | /*评论*/ 52 | app.post('/user/comment', User.loginRequired, Comment.save) 53 | 54 | /*分类*/ 55 | app.get('/admin/category/new', User.loginRequired, User.adminRequired, Category.new) 56 | app.post('/admin/category', User.loginRequired, User.adminRequired, Category.save) 57 | app.get('/admin/category/list', User.loginRequired, User.adminRequired, Category.list) 58 | 59 | } 60 | -------------------------------------------------------------------------------- /app/controllers/user.js: -------------------------------------------------------------------------------- 1 | var User = require('../models/user') 2 | 3 | //get regist page 4 | exports.showRegist = function (req, res) { 5 | res.render('regist',{}) 6 | } 7 | 8 | //get login page 9 | exports.showLogin = function (req, res) { 10 | res.render('login',{}) 11 | } 12 | 13 | //post regist page 14 | exports.regist = function (req, res) { 15 | var _user = req.body.user 16 | User.findByName(_user.name, function (err, user) { 17 | if (err) { 18 | console.log(err) 19 | } 20 | if (user) { 21 | console.log('用户已存在') 22 | res.redirect('/regist') 23 | } else { 24 | var user = new User(_user) 25 | user.save(function (err, user) { 26 | if (err) { 27 | console.log(err) 28 | } 29 | res.redirect('/') 30 | }) 31 | } 32 | }) 33 | } 34 | 35 | //post login page 36 | exports.login = function (req, res) { 37 | var _user = req.body.user 38 | var name = _user.name 39 | var password = _user.password 40 | User.findByName(name, function (err, user){ 41 | if (err) { 42 | console.log(err) 43 | } 44 | if (user) { 45 | user.comparePassword(password, function (err, isMatch) { 46 | if (err) { 47 | console.log(err) 48 | } 49 | if (isMatch) { 50 | req.session.user = user 51 | console.log('密码正确') 52 | return res.redirect('/') 53 | } else { 54 | console.log('密码错误') 55 | res.redirect('/login') 56 | } 57 | }) 58 | } else { 59 | res.redirect('/login') 60 | } 61 | }) 62 | } 63 | 64 | //logout page 65 | exports.logout = function (req, res) { 66 | delete req.session.user 67 | // delete app.locals.user 68 | res.redirect('/') 69 | } 70 | 71 | 72 | //list page 73 | exports.list = function(req, res) { 74 | User.fetch(function (err, users){ 75 | if (err) { 76 | console.log(err) 77 | } 78 | // console.log("mark") 79 | res.render('userlist', { 80 | users: users 81 | }) 82 | }) 83 | } 84 | 85 | exports.loginRequired = function (req, res, next) { 86 | var user = req.session.user 87 | if (!user) { 88 | return res.redirect('/login') 89 | } 90 | next() 91 | } 92 | 93 | exports.adminRequired = function (req, res, next) { 94 | var user = req.session.user 95 | if (user.role < 10 || !user.role) { 96 | return res.redirect('/login') 97 | } 98 | next() 99 | } -------------------------------------------------------------------------------- /app/views/includes/header.jade: -------------------------------------------------------------------------------- 1 | .navbar.navbar-default.navbar-fixed-top.navbar-inverse 2 | .container-fluid 3 | .navbar-header 4 | a.navbar-brand(href="/") Imovie 5 | .collapse.navbar-collapse 6 | ul.nav.navbar-nav 7 | li 8 | a(href='/results?cat=54d368f4dacdcf5831fe40d3&p=0') 爱情片 9 | li 10 | a(href='/results?cat=54d3690edacdcf5831fe40d4&p=0') 剧情片 11 | li 12 | a(href='/results?cat=54d36919dacdcf5831fe40d5&p=0') 喜剧片 13 | form.navbar-form.navbar-left(method='get', action='/results') 14 | .form-group 15 | input.form-control(type="text", name='search') 16 | button.btn.btn-default(type='submit') 搜索 17 | if user 18 | p.navbar-text.navbar-right 19 | span 欢迎您,#{user.name} 20 | span  |  21 | a.navbar-link(href="/logout") 注销 22 | span    23 | else 24 | p.navbar-text.navbar-right 25 | a.navbar-link(href="#", data-toggle="modal", data-target="#loginModal") 登录 26 | span  |  27 | a.navbar-link(href="#", data-toggle="modal", data-target="#signupModal") 注册 28 | span    29 | #signupModal.modal.fade(tabindex="-1", aria-hidden="true") 30 | .modal-dialog.modal-sm 31 | .modal-content 32 | form(method="POST", action="/user/regist") 33 | .modal-header 34 | h2 注册 35 | .modal-body 36 | .form-group 37 | label(for="signupName") 用户名 38 | input#signupName.form-control(name="user[name]", type="text") 39 | .form-group 40 | label(for="signupPassword") 密码 41 | input#signupPassword.form-control(name="user[password]", type="text") 42 | .modal-footer 43 | button.btn.btn-default(type="button" data-dismiss="modal") 关闭 44 | button.btn.btn-success(type="submit") 提交 45 | #loginModal.modal.fade(tabindex="-1", aria-hidden="true") 46 | .modal-dialog.modal-sm 47 | .modal-content 48 | form(method="POST", action="/user/login") 49 | .modal-header 50 | h2 登录 51 | .modal-body 52 | .form-group 53 | label(for="loginName") 用户名 54 | input#loginName.form-control(name="user[name]", type="text") 55 | .form-group 56 | label(for="loginPassword") 密码 57 | input#loginPassword.form-control(name="user[password]", type="text") 58 | .modal-footer 59 | button.btn.btn-default(type="button" data-dismiss="modal") 关闭 60 | button.btn.btn-success(type="submit") 提交 61 | //- .container 62 | //- .row 63 | //- .page-header 64 | //- h1= title 65 | //- middle 文艺爱情片 66 | 67 | -------------------------------------------------------------------------------- /app/views/pages/detail.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | .container.contentTop 5 | .row 6 | .col-md-7 7 | embed(src="#{movie.flash}", allowFullScreen="true", width="653", height="500", 8 | autostart="true" align="middle", allowScriptAcess="always", type="application/x-shockwave-flash") 9 | .panel.panel-default.panelTop 10 | .panel-heading 11 | h4 评论区 12 | .panel-body 13 | ul.media-list 14 | each item in comments 15 | li.media 16 | if item.from 17 | a.headPhoto.media-left(href="#comments", data-cid="#{item._id}", data-tid="#{item.from._id}") 18 | img.img-circle(src="http://img4.duitang.com/uploads/item/201112/01/20111201233950_aLhAG.thumb.600_0.jpg", 19 | style="width: 64px; height: 64px;", alt="...") 20 | else 21 | a.headPhoto.media-left(href="#comments", data-cid="#{item._id}") 22 | img.img-circle(src="http://img4.duitang.com/uploads/item/201112/01/20111201233950_aLhAG.thumb.600_0.jpg", 23 | style="width: 64px; height: 64px;", alt="...") 24 | .media-body 25 | if item.from 26 | h4.media-heading #{item.from.name} 27 | p #{item.content} 28 | if item.reply && item.reply.length > 0 29 | each reply in item.reply 30 | .media 31 | a.headPhoto.media-left(href="#comments",data-cid="#{item._id}", data-tid="#{reply.from._id}") 32 | img.img-circle(src="http://img4.duitang.com/uploads/item/201112/01/20111201233950_aLhAG.thumb.600_0.jpg", 33 | style="width: 64px; height: 64px;", alt="...") 34 | .media-body 35 | h5.media-heading #{reply.from.name}  回复 #{reply.to.name} : 36 | p #{reply.content} 37 | hr 38 | #comments 39 | form#commentForm(method="POST", action="/user/comment") 40 | input(type="hidden", name="comment[movie]", value="#{movie._id}") 41 | if user 42 | input(type="hidden", name="comment[from]", value="#{user._id}") 43 | .form-group 44 | textarea#textareaId.form-control(name="comment[content]", rows="4") 45 | .pull-right 46 | if user 47 | button.btn.btn-primary(type="submit") 提交 48 | else 49 | a.navbar-link(class="btn btn-primary",href="#", data-toggle="modal", data-target="#loginModal") 登录后评论 50 | .col-md-5 51 | dl.dl-horizontal 52 | dt 电影名字 53 | dd #{movie.title} 54 | dt 导演 55 | dd #{movie.director} 56 | dt 国家 57 | dd #{movie.country} 58 | dt 语言 59 | dd #{movie.language} 60 | dt 上映年份 61 | dd #{movie.year} 62 | dt 简介 63 | dd #{movie.summary} 64 | script(src="/js/detail.js") -------------------------------------------------------------------------------- /app/views/pages/admin.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block content 4 | .container.contentTop 5 | .row 6 | form.form-horizontal(method="post", action="/admin/movie", enctype="multipart/form-data") 7 | .form-group 8 | label.col-sm-2.control-label(for="#douban") 豆瓣 9 | .col-sm-10 10 | input#douban.form-control(type="text") 11 | if movie._id 12 | input(type="hidden", name="movie[_id]", value=movie._id) 13 | .form-group 14 | label.col-sm-2.control-label(for="inputCategory") 电影分类 15 | .col-sm-10 16 | input#inputCategory.form-control(type="text", name="movie[categoryName]", value=movie.categoryName) 17 | .form-group 18 | label.col-sm-2.control-label 分类选择 19 | each category in categories 20 | label.radio-inline 21 | if movie._id 22 | input(type="radio", name="movie[category]", value="#{category._id}", 23 | checked=category._id.toString()==movie.category.toString()) 24 | span #{category.name} 25 | else 26 | input(type="radio", name="movie[category]", value="#{category._id}") 27 | span #{category.name} 28 | .form-group 29 | label.col-sm-2.control-label(for="inputTitle") 电影名字 30 | .col-sm-10 31 | input#inputTitle.form-control(type="text", name="movie[title]", value=movie.title) 32 | .form-group 33 | label.col-sm-2.control-label(for="inputDirector") 电影导演 34 | .col-sm-10 35 | input#inputDirector.form-control(type="text", name="movie[director]", value=movie.director) 36 | .form-group 37 | label.col-sm-2.control-label(for="inputCountry") 国家 38 | .col-sm-10 39 | input#inputCountry.form-control(type="text", name="movie[country]", value=movie.country) 40 | .form-group 41 | label.col-sm-2.control-label(for="inputLanguage") 语种 42 | .col-sm-10 43 | input#inputLanguage.form-control(type="text", name="movie[language]", value=movie.language) 44 | .form-group 45 | label.col-sm-2.control-label(for="inputPoster") 海报地址 46 | .col-sm-10 47 | input#inputPoster.form-control(type="text", name="movie[poster]", value=movie.poster) 48 | .form-group 49 | label.col-sm-2.control-label(for="uploadPoster") 上传海报 50 | .col-sm-10 51 | input#uploadPoster(type="file", name="uploadPoster") 52 | .form-group 53 | label.col-sm-2.control-label(for="inputFlash") 片源地址 54 | .col-sm-10 55 | input#inputFlash.form-control(type="text", name="movie[flash]", value=movie.flash) 56 | .form-group 57 | label.col-sm-2.control-label(for="inputYear") 上映年代 58 | .col-sm-10 59 | input#inputYear.form-control(type="text", name="movie[year]", value=movie.year) 60 | .form-group 61 | label.col-sm-2.control-label(for="inputSummary") 电影简介 62 | .col-sm-10 63 | input#inputSummary.form-control(type="text", name="movie[summary]", value=movie.summary) 64 | .form-group 65 | .col-sm-offset-2.col-sm-10 66 | button.btn.btn-primary(type="submit") 录入 67 | script(src="/js/admin.js") -------------------------------------------------------------------------------- /app/controllers/movie.js: -------------------------------------------------------------------------------- 1 | var _ = require('underscore') 2 | var Movie = require('../models/movie') 3 | var Comment = require('../models/comment') 4 | var Category = require('../models/category') 5 | var fs = require('fs') 6 | var path = require('path') 7 | 8 | // detail page 9 | exports.detail = function (req, res) { 10 | var id = req.params.id 11 | Movie.update({_id: id}, {$inc: {pv: 1}}, function (err) { 12 | if(err) { 13 | console.log(err) 14 | } 15 | }) 16 | Movie.findById(id, function (err, movie){ 17 | Comment 18 | .find({movie: id}) 19 | .populate('from', 'name') 20 | .populate('reply.from reply.to', 'name') 21 | .exec(function (err, comments) { 22 | // console.log('comments:') 23 | // console.log(comments) 24 | res.render('detail', { 25 | title : "" + movie.title, 26 | movie: movie, 27 | comments: comments 28 | }) 29 | }) 30 | }) 31 | } 32 | 33 | //admin page 34 | exports.new = function (req, res) { 35 | Category.find({}, function (err, categories) { 36 | console.log(categories) 37 | res.render('admin', { 38 | title : '后台录入页', 39 | categories: categories, 40 | movie: {} 41 | }) 42 | }) 43 | } 44 | 45 | //admin update movie 46 | exports.update = function (req, res) { 47 | var id = req.params.id 48 | if (id) { 49 | Movie.findById(id, function (err, movie){ 50 | if (err) { 51 | console.log(err) 52 | } 53 | Category.find({}, function (err, categories) { 54 | res.render('admin', { 55 | title: 'Imovie 后台更新页面', 56 | movie: movie, 57 | categories: categories 58 | }) 59 | }) 60 | }) 61 | } 62 | } 63 | 64 | // admin post movie 65 | exports.save = function (req, res){ 66 | // console.log(req.body) 67 | // console.log(req.body.movie) 68 | var id = req.body.movie._id 69 | var movieObj = req.body.movie 70 | // console.log(movieObj) 71 | var _movie 72 | if (req.poster) { 73 | movieObj.poster = req.poster 74 | } 75 | 76 | if (id) { 77 | Movie.findById(id, function (err, movie){ 78 | if (err) { 79 | console.log(err) 80 | } 81 | /* 82 | _.extend(destination, *sources) 83 | Copy all of the properties in the source objects over to the destination object, 84 | and return the destination object. It's in-order, so the last source will override 85 | properties of the same name in previous arguments. 86 | */ 87 | _movie = _.extend(movie, movieObj) 88 | _movie.save(function (err, movie){ 89 | if (err) { 90 | console.log(err) 91 | } 92 | var categoryId = movie.category 93 | Category.findById(categoryId, function (err, category) { 94 | category.movies.push(movie._id) 95 | category.save (function (err, category) { 96 | res.redirect('/movie/' + movie._id) 97 | }) 98 | }) 99 | }) 100 | }) 101 | } else { 102 | _movie = new Movie(movieObj) 103 | 104 | var categoryName = movieObj.categoryName 105 | var categoryId = movieObj.category 106 | 107 | _movie.save(function (err, movie){ 108 | console.log(movie) 109 | if (err) { 110 | console.log(err) 111 | } 112 | if (categoryId) { 113 | Category.findById(categoryId, function (err, category) { 114 | category.movies.push(movie._id) 115 | category.save (function (err, category) { 116 | res.redirect('/movie/' + movie._id) 117 | }) 118 | }) 119 | } else if (categoryName){ 120 | var category = new Category({ 121 | name: categoryName, 122 | movies: [movie._id] 123 | }) 124 | category.save(function (err, category) { 125 | movie.category = category._id 126 | movie.save(function (err, movie) { 127 | res.redirect('/movie/' + movie._id) 128 | }) 129 | }) 130 | } 131 | 132 | }) 133 | } 134 | } 135 | 136 | //list page 137 | exports.list = function(req, res) { 138 | Movie.fetch(function (err, movies){ 139 | if (err) { 140 | console.log(err) 141 | } 142 | // console.log("mark") 143 | res.render('list', { 144 | title: 'Imovie 列表页', 145 | movies: movies 146 | }) 147 | }) 148 | } 149 | 150 | //list delete movie 151 | exports.delete = function (req, res){ 152 | var id = req.query.id 153 | console.log(id) 154 | if (id) { 155 | Movie.remove({_id: id}, function (err, movie) { 156 | if (err) { 157 | console.log(err) 158 | } else { 159 | res.json({success:1}) 160 | } 161 | }) 162 | } 163 | } 164 | 165 | //save movie poster 166 | exports.savePoster = function (req, res, next) { 167 | console.log('hello') 168 | console.log(req.body) 169 | var posterData = req.files.uploadPoster 170 | var filePath = posterData.path 171 | var originalFilename = posterData.originalFilename 172 | 173 | if (originalFilename) { 174 | fs.readFile(filePath, function (err, data) { 175 | var timestamp = Date.now() 176 | var type = posterData.type.split('/')[1] 177 | var poster = timestamp + '.' + type 178 | var newPath = path.join(__dirname, '../../', 'public/upload/' + poster) 179 | 180 | fs.writeFile(newPath, data, function (err) { 181 | req.poster = poster 182 | next() 183 | }) 184 | }) 185 | } else { 186 | next() 187 | } 188 | } 189 | --------------------------------------------------------------------------------