├── .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 |
--------------------------------------------------------------------------------