Merge branch 'dev' of Devowo/Mpoknimu into master

This commit is contained in:
Muhammad Iqbal Rifai 2018-07-04 11:24:39 +02:00 committed by Gitea
commit 745f7cdd19
44 changed files with 14685 additions and 1 deletions

9
.editorconfig Normal file
View File

@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = false
trim_trailing_whitespace = false

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
client/dist/
client/node_modules/
client/build/
client/static/
node_modules/
public/assets/

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) <year> <copyright holders>
Copyright (c) 2018 Devowo
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

98
app.js Normal file
View File

@ -0,0 +1,98 @@
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const ejs = require('ejs').__express;
const flash = require('connect-flash');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const passport = require('passport');
const cors = require('cors');
const methodOverride = require('method-override');
require('./config/passport');
const app = express();
//const app = polka();
require('express-helpers')(app);
// view engine setup
//app.disable('etag');
//app.set('views', path.join(__dirname, 'views'));
app.set("views", "./views");
//app.set("views", "./public/dist/");
app.set('view engine', 'ejs');
app.engine('.ejs', ejs); //
app.locals.rmWhitespace = true;
// Routes
const episodes = require('./routes/episodes');
const series = require('./routes/series');
app.locals.moment = require('moment');
const moment = require('moment');
moment.locale('es');
//app.use(express.logger('dev'));
//app.use(logger('dev'));
app.use(cors());
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({ extended: false }));
// Angular DIST output folder
//app.use(express.static(path.join(__dirname, 'dist')));
// Original no angular
app.use(express.static(path.join(__dirname, 'public')));
app.use(logger('dev'));
app.use(methodOverride('_method'));
//login system
app.use(cookieParser());
app.use(session({
cookie: { maxAge: 365 * 24 * 60 * 60 * 1000 },
secret: 'kontol',
saveUninitialized: false,
resave: false
}));
app.use(passport.initialize());
app.use(passport.session());
// Middlewares
app.use(flash());
app.use((req, res, next) => {
res.locals.success_messages = req.flash('success');
res.locals.error_messages = req.flash('error');
res.locals.isAuthenticated = req.user ? true : false;
next();
});
// Routes
app.use('/series', series);
app.use('/', episodes);
app.use('/episodes', episodes);
app.use('/show', episodes);
app.use('/anime', series);
app.use('/episodes', series);
app.use('/users', require('./routes/users'));
// Catach 404 Errors and forward them to error handler
app.use(function (req, res, next) {
var err = new Error('404: Not Found ' + req.originalUrl); //here
err.status = 404;
next(err);// or null
});
module.exports = app;

39
config/passport.js Normal file
View File

@ -0,0 +1,39 @@
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const User = require('../models/user');
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser(async (id, done) => {
try{
const user = await User.findById(id);
done(null, user.id);
}catch(error){
done(error, null);
}
});
passport.use('local', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: false
}, async (email, password, done)=>{
try{
// 1) Check if the email already exists
const user = await User.findOne({ 'email': email});
if (!user){
return done(null,false,{ message: 'Unknown User' })
}
// 2) Check if the password is correct
const isValit = User.comparePasswords(password,user.password);
if(isValit){
return done(null, user);
}else{
return done(null, false,{ message: 'Unknown Password'});
}
}catch(error){
return done(error, false);
}
}));

107
controllers/episodes.js Normal file
View File

@ -0,0 +1,107 @@
const Episode = require("../models/episodes");
const Serie = require("../models/series");
module.exports = {
index: async (req, res, next) => {
try {
// Get all the episodes
const episode = await Episode.find({})
.lean()
.sort({ createdAt: -1 })
.limit(9); // the correct order is -1
//res.render("index", { episode: episode });
//res.render('index', { name: 'John' });
res.json(episode);
} catch (err) {
next(err);
}
},
newEpisode: async (req, res, next) => {
try {
// 1. Find the actual anime
const anime = await Serie.findById(req.body.anime);
// 2. Create a new episode
const newEpisode = req.body;
delete newEpisode.anime;
const episode = new Episode(newEpisode);
episode.anime = anime;
//anime.markModified('episode.anime');
await episode.save();
// 3. Add newly created episode to the actual anime
anime.episodes.push(episode);
//episode.markModified('anime.episodes');
//anime.markModified('anime.serie');
await anime.save();
// We're done!
res.json(episode);
// res.redirect("/");
} catch (err) {
next(err);
}
},
getEpisode: async (req, res, next) => {
try {
const episode = await Episode.findOne({ slug: req.params.slug });
if (!episode) return next();
res.json(episode)
//res.render("show", { episode: episode });
} catch (err) {
next(err);
}
},
/* getEpisode: async (req, res, next) => {
const episode = await Episode.findById(req.params.episodeId);
res.render('show', { episode: episode });
//res.json(episode);
}, */
replaceEpisode: async (req, res, next) => {
try {
const { episodeId } = req.params;
const newEpisode = req.body;
const result = await Episode.findByIdAndUpdate(episodeId, newEpisode);
res.json({ success: true });
} catch (err) {
next(err);
}
},
updateEpisode: async (req, res, next) => {
try {
const { episodeId } = req.params;
const newEpisode = req.body;
const result = await Episode.findByIdAndUpdate(episodeId, newEpisode);
//res.json({ success: true });
res.redirect("/");
} catch (err) {
next(err);
}
},
deleteEpisode: async (req, res, next) => {
try {
const { episodeId } = req.params;
// Get a episode
const episode = await Episode.findById(episodeId);
if (!episode) {
return res.status(404).json({ error: "Episode no existe" });
}
const animeId = episode.anime;
// Get a anime
const anime = await Serie.findById(animeId);
// Remove the episode
await episode.remove();
// Remove episode from the anime's selling list
console.log("anime", anime);
anime.episodes.pull(episode);
console.log("anime", anime);
await anime.save();
res.json({ success: true });
} catch (err) {
next(err);
}
}
};

159
controllers/series.js Normal file
View File

@ -0,0 +1,159 @@
const Serie = require("../models/series");
const Episode = require("../models/episodes");
module.exports = {
/* original code without page (you have to modify the routes leave it alone in /)
index: async (req, res, next) => {
const serie = await Serie.find({})
.sort({ createdAt: -1 })
.limit(9);
res.render("series", {serie: serie});
}, */
index: async (req, res, next) => {
const serie = await Serie.find({})
.sort({ createdAt: -1 })
res.json(serie);
},
/*
Uncomment this code to use the page with ejs
index: async (req, res, next) => {
var perPage = 4;
var page = req.params.page || 1;
try {
const serie = await Serie.find({})
.sort({ createdAt: -1 })
.skip(perPage * page - perPage)
.limit(perPage)
.lean()
.exec(function(err, serie) {
Serie.count().exec(function(err, count) {
if (err) return next(err);
res.render("series", {
serie: serie,
current: page,
pages: Math.ceil(count / perPage)
});
});
});
} catch (err) {
next(err);
}
}, */
newSerie: async (req, res, next) => {
try {
const newSerie = new Serie(req.body);
const serie = await newSerie.save();
//res.render("addserie",{serie: serie})
res.json(serie);
//res.redirect("/users/dashboard");
} catch (err) {
next(err);
}
},
//.lean(true) high performance .populate('episodes', 'slug -_id', null, {sort: { createdAt: -1 } });
getSerie: async (req, res, next) => {
try {
const serie = await Serie.findOne({ slug: req.params.slug }).populate({
path: "episodes",
select: "slug -_id",
//, match: { x: 1 },
options: { sort: { createdAt: -1 }, limit: 9 }
});
if (!serie) return next();
//res.render("anime", { serie: serie });
res.json(serie);
} catch (err) {
next(err);
}
},
/* getSerie: async (req, res, next) => {
const { serieId } = req.params;
const serie = await Serie.findById(serieId);
res.render('anime', { serie: serie });
//res.json(serie);
}, */
replaceSerie: async (req, res, next) => {
// enforce that req.body must contain all the fields
try {
const { serieId } = req.params;
const newSerie = req.body;
const result = await Serie.findByIdAndUpdate(serieId, newSerie);
res.json({ success: true });
} catch (err) {
next(err);
}
},
updateSerie: async (req, res, next) => {
try {
// req.body may contain any number of fields
const { serieId } = req.params;
const newSerie = req.body;
const result = await Serie.findByIdAndUpdate(serieId, newSerie);
//res.json({ success: true });
res.redirect("/");
} catch (err) {
next(err);
}
},
//the same as getseries
getSerieEpisodes: async (req, res, next) => {
try {
const { serieId } = req.params;
const serie = await Serie.findById(serieId).populate("episodes");
//res.render('episodes', { serie : serie });
res.json(serie.episodes);
} catch (err) {
next(err);
}
},
newSerieEpisode: async (req, res, next) => {
try {
const { serieId } = req.params;
// Create a new episode
const newEpisode = new Episode(req.body);
// Get series
const serie = await Serie.findById(serieId);
// Assing serie as episode's anime
newEpisode.anime = serie;
// Save the episode
await newEpisode.save();
// Add episode to the serie's selling array 'episodes'
serie.episodes.push(newEpisode);
// Save the series
await serie.save();
res.json(newEpisode);
} catch (err) {
next(err);
}
}
};
/*
We can interact with mongoose in 3 different ways:
1) Callbacks
2) Promises
3) [X] Async/Await (Promises) - this use for the code
*/
//let is used to isolate a code even if they have the same name are two different variables
//const their values after declaring they can be changed as long as the parent object is called
/* Example promises:
index: (req, res, next) => {
Serie.find({})
.then(series => {
res.status(200).json // res.render(series)
})
.catch(err => {
next(err);
});
},
*/

42
glupfile.js Normal file
View File

@ -0,0 +1,42 @@
let gulp = require('gulp');
let cleanCSS = require('gulp-clean-css');
var pump = require('pump');
var htmlmin = require('gulp-htmlmin');
var concat = require('gulp-concat');
var uglifyes = require('uglify-es');
var composer = require('gulp-uglify/composer');
var minify = composer(uglifyes);
gulp.task('default', () =>
console.log('See you in another video')
);
gulp.task('minify-css', () => {
return gulp.src('public/css/*.css')
.pipe(cleanCSS(
{level: {1: {specialComments: 0}}}))
.pipe(concat('cssbundle.css'))
.pipe(gulp.dest('public/dist/css'));
});
gulp.task('compress', () => {
pump([
gulp.src(['./*.js','controllers/*.js','models/*.js','routes/*.js','helpers/*.js']),
minify(),
concat('jsbundle.js'),
gulp.dest('public/dist/js')
],
);
});
gulp.task('minify-html', () => {
return gulp.src(['views/*.ejs','views/layouts/*.ejs'])
.pipe(htmlmin({collapseWhitespace: true,
collapseInlineTagWhitespace:true,
removeComments: true,
removeRedundantAttributes:true,
useShortDoctype:true,
html5: true }))
.pipe(concat('htmlbundle.ejs'))
.pipe(gulp.dest('public/dist/html'));
});

50
helpers/routeHelper.js Normal file
View File

@ -0,0 +1,50 @@
const Joi = require('joi');
// validation does not work well prevents parameters from being entered into the database
module.exports = {
validateParam: (schema, name) => {
return (req, res, next) => {
const result = Joi.validate({ param: req['params'][name] }, schema);
if (result.error){
return res.status(400).json(result.error);
} else {
if (!req.value)
req.value = {};
if (!req.value['params'])
req.value['params'] = {};
req.value['params'][name] = result.value.param;
next();
}
}
},
// Work but for any rasons not implements
validateBody: (schema) => {
return (req, res, next) => {
const result = Joi.validate(req.body, schema);
if (result.error) {
return res.status(400).json(result.error);
} else {
if (!req.value)
req.value = {};
if (!req.value['body'])
req.value['body'] = {};
req.value['body'] = result.value;
next();
}
}
},
schemas: {
serieSchema: Joi.object().keys({
title: Joi.string().optional(),
synopsis: Joi.string().optional()
}),
idSchema: Joi.object().keys({
param: Joi.string().regex(/^[0-9a-fA-F]{24}$/).required()
})
}
}

65
models/episodes.js Normal file
View File

@ -0,0 +1,65 @@
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const slug = require('slugs');
const episodeSchema= new Schema({
title: {
type: String,index: true
},
slug: String,
serieTitle: String,
chapterTitle: String,
chapter: Number,
server: String,
serverTwo: String,
imageCap: String,
download: String,
anime: {
type: Schema.Types.ObjectId,
ref: 'serie'
}
}, { timestamps: {} }
//{
//toJSON: { virtuals: true },
//toObject: { virtuals: true },
//},
//{ runSettersOnQuery: true }
);
//Da error
/* // Define our indexes
episodeSchema.index({
title: 'text',
});
episodeSchema.index({
location: 'indexloco'
});
*/
episodeSchema.pre('save', async function (next) {
if (!this.isModified('title')) {
next(); // skip it
return; // stop this function from running
}
this.slug = slug(this.title);
// find other stores that have a slug of wes, wes-1, wes-2
const slugRegEx = new RegExp(`^(${this.slug})((-[0-9]*$)?)$`, 'i');
const storesWithSlug = await this.constructor.find({
slug: slugRegEx
});
if (storesWithSlug.length) {
this.slug = `${this.slug}-${storesWithSlug.length + 1}`; //`` blackstring generacion de cadenas
}
next();
// TODO make more resiliant so slugs are unique
});
const Episode = mongoose.model('episode', episodeSchema);
module.exports = Episode;

66
models/series.js Normal file
View File

@ -0,0 +1,66 @@
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const slug = require('slugs');
const serieSchema = new Schema({
title: {
type: String, index: true
},
slug: String,
cover: String,
backgroundimage: String,
frontimage: String,
synopsis: String,
estate: String,
type: String,
tags: [String],
episodes: [{
type: Schema.Types.ObjectId,
ref: 'episode'
}]
}, {
timestamps: {}
});
serieSchema.pre('save', async function (next) {
if (!this.isModified('title')) {
next(); // skip it
return; // stop this function from running
}
this.slug = slug(this.title);
// find other stores that have a slug of wes, wes-1, wes-2
const slugRegEx = new RegExp(`^(${this.slug})((-[0-9]*$)?)$`, 'i');
const storesWithSlug = await this.constructor.find({
slug: slugRegEx
});
if (storesWithSlug.length) {
this.slug = `${this.slug}-${storesWithSlug.length + 1}`; //`` blackstring generacion de cadenas
}
next();
// TODO make more resiliant so slugs are unique
});
serieSchema.statics.getTagsList = function() {
return this.aggregate([
{ $unwind: '$tags' },
{ $group: { _id: '$tags', count: { $sum: 1 } } },
{ $sort: { count: -1 } }
]);
};
/* function autopopulate(next) {
this.populate('episodes', 'slug');
next();
}
serieSchema.pre('find', autopopulate);
serieSchema.pre('findOne', autopopulate);
*/
const Serie = mongoose.model('serie', serieSchema);
module.exports = Serie;

34
models/user.js Normal file
View File

@ -0,0 +1,34 @@
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const bcrypt = require("bcryptjs");
const userSchema = new Schema(
{
email: {
type: String
},
username: String,
password: String
},
{
timestamps: {}
}
);
const User = mongoose.model("user", userSchema);
module.exports = User;
module.exports.hashPassword = async password => {
try {
const salt = await bcrypt.genSalt(10);
return await bcrypt.hash(password, salt);
} catch (error) {
throw new error("Hashing failed", error);
}
};
module.exports.comparePasswords = async (inputPassword, hashedPassword) => {
try {
return await bcrypt.compare(inputPassword, hashedPassword);
} catch (error) {
throw new error("Comparing failed", error);
}
};

8393
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

53
package.json Normal file
View File

@ -0,0 +1,53 @@
{
"name": "MPOKNIMU",
"version": "1.0.0",
"main": "app.js",
"private": true,
"engines": {
"node": ">= 9.3.0"
},
"license": "MIT",
"scripts": {
"prod": "NODE_ENV=production node ./start.js",
"watch": "nodemon ./start.js",
"start": "concurrently \"npm run watch\" --names \"💻,📦\" --prefix name"
},
"dependencies": {
"bcryptjs": "^2.4.3",
"body-parser": "^1.17.2",
"chalk": "^2.0.1",
"connect-flash": "^0.1.1",
"cookie-parser": "^1.4.3",
"cors": "^2.8.4",
"dotenv": "^4.0.0",
"ejs": "^2.5.6",
"express": "^4.16.2",
"express-helpers": "^1.3.2",
"express-messages": "^1.0.1",
"express-session": "^1.15.6",
"joi": "^10.6.0",
"method-override": "^2.3.10",
"moment": "^2.20.1",
"mongoose": "^5.0.1",
"morgan": "^1.9.0",
"passport": "^0.4.0",
"passport-local": "^1.0.0",
"pump": "^2.0.0",
"slugs": "^0.1.3"
},
"browserslist": "last 2 versions",
"devDependencies": {
"autoprefixer": "^7.2.5",
"babel-core": "^6.26.0",
"babel-preset-env": "^1.6.1",
"concurrently": "^3.5.1",
"gulp": "^3.9.1",
"gulp-clean-css": "^3.9.2",
"gulp-concat": "^2.6.1",
"gulp-htmlmin": "^4.0.0",
"gulp-uglify": "^3.0.0",
"node-sass": "^4.7.2",
"nodemon": "^1.14.11",
"uglify-es": "^3.3.7"
}
}

281
public/css/app.css Normal file
View File

@ -0,0 +1,281 @@
/*!
STYLE GUIDE
1. NAV-BAR
2. Series
3.
*/
a{
color: white;
text-decoration: none;
}
.caps{
margin-right: 20px;
margin-left: 20px;
margin-bottom: 25px;
}
body {
width:auto;
margin:auto;
padding: 0;
}
.image{
max-width: 220px;
max-height: 300px;
}
/* videoplayer */
.container{
width: 880px;
margin-top: 15px;
margin-left: auto;
margin-right: auto;
}
.elementoVideo{
color: rgb(255, 255, 255);
display:flex;
flex-flow:row wrap;
flex: 1 1 auto;
}
.elemento{
color: rgb(255, 255, 255);
margin: 10px;
width: auto;
text-align: center;
display:flex;
flex-flow:row wrap;
justify-content:flex-start;
flex: 1 1 auto;
align-items: baseline;
align-content: flex-start;
}
.elementoAnime{
color: rgb(255, 255, 255);
margin: 10px;
width: auto;
text-align: center;
display:flex;
/* height: auto;
flex-basis: auto;*/
flex-flow:column wrap;
justify-content:flex-start;
/* that all encompass 100%
flex-grow:1;*/
/* align-content: center; */
flex: 1 1 auto;
}
.elementoDash{
color: rgb(255, 255, 255);
margin: 10px;
width: auto;
text-align: center;
display:flex;
/* height: auto;
flex-basis: auto;*/
flex-flow:column wrap;
justify-content:flex-start;
/* that all encompass 100%
flex-grow:1;*/
/* align-content: center; */
flex: 1 1 auto;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.sada1 {
margin-right: 30px;
margin-left: 30px;
}
.contenedor {
background:#212121;
width:auto;
height:auto;
margin:auto;
/* Flexbox */
display:flex;
flex-flow:row wrap;
min-height: 100vh;
flex-direction: column;
}
header {
background:#263238;
width:100%;
padding:20px;
/* Flexbox */
display: flex;
justify-content:space-between;
align-items:center;
flex-direction:row;
flex-wrap:wrap;
}
header .logo {
color:#FFFFFF;
font-size:30px;
}
header .logo img {
width:50px;
vertical-align: top;
}
header .logo a {
color:#FFFFFF;
text-decoration: none;
line-height:50px;
}
header nav {
width:50%;
/* Flexbox */
display:flex;
flex-wrap:wrap;
align-items:center;
}
header nav a {
background:#455A64;
color:#FFFFFF;
text-align: center;
text-decoration: none;
padding:10px;
/* Flexbox */
flex-grow:1;
}
header nav a:hover {
background:#78909C;
}
footer {
background:#263238;
width: 100%;
padding:20px;
/* Flexbox */
display: flex;
flex-wrap:wrap;
justify-content:space-between;
}
footer .links {
background:#455A64;
display:flex;
flex-wrap:wrap;
}
footer .links a {
flex-grow:1;
color:#FFFFFF;
padding:10px;
text-align: center;
text-decoration:none;
}
footer .links a:hover {
background:#78909C;
}
footer .social {
background:#455A64;
}
footer .social a {
color:#FFFFFF;
text-decoration: none;
padding:10px;
display: inline-block;
}
@media screen and (max-width: 800px) {
.contenedor {
flex-direction:column;
}
header {
flex-direction:column;
padding:0;
width:100%;
height:100%;
margin-left: auto;
margin-right: auto;
}
header .logo {
margin:20px 0;
}
header nav {
width: 100%;
}
}
.pagination{
display: flex;
flex: 1 1 auto;
align-self: center;
}
.pagination a {
color: #FFFFFF;
padding: 8px 16px;
text-decoration: none;
}
.pagination a.active {
background-color: #455a64;
color: white;
border-radius: 5px;
}
.pagination a:hover:not(.active) {
background-color: #78909C;
border-radius: 5px;
}
@media screen and (max-width: 700px) {
.sada1 {
margin-right: auto;
margin-left: auto;
}
}
@media screen and (max-width: 600px) {
footer {
justify-content:space-around;
}
}
/* Series */
#dash{
color: #FFFFFF;
}

1
public/dist/css/app.css vendored Normal file
View File

@ -0,0 +1 @@
body{background-color:#ff0!important}

1
public/dist/html/anime.ejs vendored Normal file
View File

@ -0,0 +1 @@
<% include ./layouts/header %> <body><h1>Anime View</h1><h4 class="card-title"> <%- serie.title %> </h4><br> <%- serie.synopsis.substring(0,48) %>...<br><br><h6>Type:</h6><ul> <%- link_to(serie.type) %> </ul><h6>Genre:</h6><ul> <% for(var i=0; i<serie.tags.length; i++) {%> <li> <%- link_to(serie.tags[i], '/'+serie.tags[i]) %> </li> <% } %> </ul><h6>Episode:</h6><ul> <% for(var i=0; i<serie.episodes.length; i++) {%> <li> <%- link_to(serie.episodes[i].slug, '/'+serie.episodes[i].slug) %> </li> <% } %> </ul></body>

1
public/dist/html/episodes.ejs vendored Normal file
View File

@ -0,0 +1 @@
<% include ./layouts/header %> <body><h4>Episodes</h4> <%- serie.serieTitle %> </body>

1
public/dist/html/footer.ejs vendored Normal file
View File

@ -0,0 +1 @@
<!-- FOOT -->

1
public/dist/html/header.ejs vendored Normal file
View File

@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><title>MPOKNIMU</title><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><link href="/dist/pure-min.css" rel="stylesheet"><link href="/dist/app.css" rel="stylesheet"><nav class="navbar navbar-expand-lg navbar-light bg-light"><a class="navbar-brand" href="#">Anime</a><button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarNav"><ul class="navbar-nav"><li class="nav-item active"><a class="nav-link" href="http://localhost:9000/">Home</a></li><li class="nav-item"><a class="nav-link" href="/series">Series</a></li><li class="nav-item"><a class="nav-link" href="#">Login</a></li></ul></div></nav><div class="hola" id="hola">Hello</div></head></html>

21
public/dist/html/htmlbundle.ejs vendored Normal file
View File

@ -0,0 +1,21 @@
<% include ./layouts/header %> <body><h1>View Anime</h1><h4 class="card-title"> <%- serie.title %> </h4><br> <%- serie.synopsis.substring(0,48) %>...<br><br><h6>Type:</h6><ul> <%- link_to(serie.type) %> </ul><h6>Genre:</h6><ul> <% for(var i=0; i<serie.tags.length; i++) {%> <li> <%- link_to(serie.tags[i], '/'+serie.tags[i]) %> </li> <% } %> </ul><h6>Chapters:</h6><ul> <% for(var i=0; i<serie.episodes.length; i++) {%> <li> <%- link_to(serie.episodes[i].slug, '/'+serie.episodes[i].slug) %> </li> <% } %> </ul></body>
<% include ./layouts/header %> <body><h4>Episodes</h4> <%- serie.serieTitle %> </body>
<% include ./layouts/header %> <body> <% episode.forEach(function(episode) { %> <div class="container" style="width: 720px;margin-top: 15px;"><div class="row"> <% const episodeUrl = '/episodes/' + episode.slug; %> <div class="col"><div class="card-group" style="margin-right: 190px;"><div class="card"><a href="<%- episode.slug %>" class="card-link"><img class="card-img-top img-fluid" src="<%- episode.imageCap %> " alt="Card image cap"></a><div class="card-block"><h4 class="card-title"><a href="<%- episode.slug %>" class="card-link"> <%- episode.serieTitle %> </a></h4><h7 class="card-title"> <%- episode.serieTitle %> </h7><p class="card-text"><small class="text-muted"><%- episode.createdAt %></small></p></div></div></div></div> <% }); %> </div></div></body>
<% include ./layouts/header %> <body><div class="container" style="width: 720px;margin-top: 15px;"><div class="row"> <% serie.forEach(function(serie) { %> <div class="col"> <% const serieUrl = '/series/' + serie.slug; %> <div class="card-group"><div class="card" style="width: 20rem; margin-bottom: 15px;"><a href="anime/<%- serie.slug %>" class="card-link"><img class="card-img-top" id="image-home" src="<%- serie.cover %>" alt="Card image cap"></a><div class="card-block"><h4 class="card-title"> <%- serie.title.substring(0,18) %>...</h4><p class="card-text"> <%- serie.synopsis.substring(0,48) %>...</p></div><ul class="list-group list-group-flush"><li class="list-group-item"> <%- serie.type %> <%- serie.episodes %> </li></ul><div class="card-block"><a href="#" class="card-link">Watch Anime</a></div></div></div></div> <% }); %> </div></div><nav aria-label="Page navigation example"><ul class="pagination justify-content-center"><li class="page-item"><a class="page-link" href="#">Previous</a></li><li class="page-item"><a class="page-link" href="#">1</a></li><li class="page-item"><a class="page-link" href="#">2</a></li><li class="page-item"><a class="page-link" href="#">3</a></li><li class="page-item"><a class="page-link" href="#">Next</a></li></ul></nav></body>
<% include ./layouts/header %> <script src="https://content.jwplatform.com/libraries/bfIbW5Pe.js"></script><body><div class="container" style="width: 720px;margin-top: 15px;"><div class="row"><h1> <%- episode.serieTitle %> <%- episode.chapter %> </h1><br> <%- episode.server %> <br><div id="myElement"></div><script type="text/javascript">var playerInstance = jwplayer("myElement");
playerInstance.setup({
file: "<%- episode.server %>",
height: "440",
width: "720",
autostart: false,
playbackRateControls: [0.25, 0.75, 1, 1.25, 2, 3],
title: "<%- episode.serieTitle %> <%- episode.chapter %>",
image: "<%- episode.imageCap %>",
abouttext: "<%- episode.serieTitle %> <%- episode.chapter %>",
displaytitle: true,
timeSliderAbove: true,
primary: "html5",
preload: "metadata"
});</script></div></div></body>
<!DOCTYPE html><html lang="en"><head><title>MPOKNIMU</title><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><link href="/dist/pure-min.css" rel="stylesheet"><link href="/dist/app.css" rel="stylesheet"><nav class="navbar navbar-expand-lg navbar-light bg-light"><a class="navbar-brand" href="#">Anime</a><button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarNav"><ul class="navbar-nav"><li class="nav-item active"><a class="nav-link" href="http://localhost:9000/">Home</a></li><li class="nav-item"><a class="nav-link" href="/series">Series</a></li><li class="nav-item"><a class="nav-link" href="#">Login</a></li></ul></div></nav><div class="hola" id="hola">Hallo</div></head></html>

1
public/dist/html/index.ejs vendored Normal file
View File

@ -0,0 +1 @@
<% include ./layouts/header %> <body> <% episode.forEach(function(episode) { %> <div class="container" style="width: 720px;margin-top: 15px;"><div class="row"> <% const episodeUrl = '/episodes/' + episode.slug; %> <div class="col"><div class="card-group" style="margin-right: 190px;"><div class="card"><a href="<%- episode.slug %>" class="card-link"><img class="card-img-top img-fluid" src="<%- episode.imageCap %> " alt="Card image cap"></a><div class="card-block"><h4 class="card-title"><a href="<%- episode.slug %>" class="card-link"> <%- episode.serieTitle %> </a></h4><h7 class="card-title"> <%- episode.serieTitle %> </h7><p class="card-text"><small class="text-muted"><%- episode.createdAt %></small></p></div></div></div></div> <% }); %> </div></div></body>

1
public/dist/html/series.ejs vendored Normal file
View File

@ -0,0 +1 @@
<% include ./layouts/header %> <body><div class="container" style="width: 720px;margin-top: 15px;"><div class="row"> <% serie.forEach(function(serie) { %> <div class="col"> <% const serieUrl = '/series/' + serie.slug; %> <div class="card-group"><div class="card" style="width: 20rem; margin-bottom: 15px;"><a href="anime/<%- serie.slug %>" class="card-link"><img class="card-img-top" id="image-home" src="<%- serie.cover %>" alt="Card image cap"></a><div class="card-block"><h4 class="card-title"> <%- serie.title.substring(0,18) %>...</h4><p class="card-text"> <%- serie.synopsis.substring(0,48) %>...</p></div><ul class="list-group list-group-flush"><li class="list-group-item"> <%- serie.type %> <%- serie.episodes %> </li></ul><div class="card-block"><a href="#" class="card-link">Watch Anime</a></div></div></div></div> <% }); %> </div></div><nav aria-label="Page navigation example"><ul class="pagination justify-content-center"><li class="page-item"><a class="page-link" href="#">Previous</a></li><li class="page-item"><a class="page-link" href="#">1</a></li><li class="page-item"><a class="page-link" href="#">2</a></li><li class="page-item"><a class="page-link" href="#">3</a></li><li class="page-item"><a class="page-link" href="#">Next</a></li></ul></nav></body>

15
public/dist/html/show.ejs vendored Normal file
View File

@ -0,0 +1,15 @@
<% include ./layouts/header %> <script src="https://content.jwplatform.com/libraries/bfIbW5Pe.js"></script><body><div class="container" style="width: 720px;margin-top: 15px;"><div class="row"><h1> <%- episode.serieTitle %> <%- episode.chapter %> </h1><br> <%- episode.server %> <br><div id="myElement"></div><script type="text/javascript">var playerInstance = jwplayer("myElement");
playerInstance.setup({
file: "<%- episode.server %>",
height: "440",
width: "720",
autostart: false,
playbackRateControls: [0.25, 0.75, 1, 1.25, 2, 3],
title: "<%- episode.serieTitle %> <%- episode.chapter %>",
image: "<%- episode.imageCap %>",
abouttext: "<%- episode.serieTitle %> <%- episode.chapter %>",
displaytitle: true,
timeSliderAbove: true,
primary: "html5",
preload: "metadata"
});</script></div></div></body>

1
public/dist/js/app.js vendored Normal file
View File

@ -0,0 +1 @@
const path=require("path"),express=require("express"),bodyParser=require("body-parser"),ejs=require("ejs").__express,chalk=require("chalk"),log=console.log,error=chalk.bold.red,app=express();require("express-helpers")(app),app.set("views","./views"),app.set("view engine","ejs"),app.engine(".ejs",ejs),app.locals.rmWhitespace=!0;const episodes=require("./routes/episodes"),series=require("./routes/series");app.use(bodyParser.json({limit:"50mb"})),app.use(bodyParser.urlencoded({extended:!1})),app.use(express.static(path.join(__dirname,"public"))),app.use("/series",series),app.use("/",episodes),app.use("/episodes",episodes),app.use("/show",episodes),app.use("/anime",series),app.use("/episodes",series),app.use(function(e,s,p){var r=new Error("404: Not Found "+e.originalUrl);r.status=404,p(r)}),module.exports=app;

1
public/dist/js/gulpfile.js vendored Normal file
View File

@ -0,0 +1 @@
let gulp=require("gulp"),cleanCSS=require("gulp-clean-css");var pump=require("pump"),htmlmin=require("gulp-htmlmin"),uglifyes=require("uglify-es"),composer=require("gulp-uglify/composer"),minify=composer(uglifyes);gulp.task("default",()=>console.log("See you in another video kids")),gulp.task("minify-css",()=>gulp.src("public/css/*.css").pipe(cleanCSS({level:{1:{specialComments:0}}})).pipe(gulp.dest("public/dist/css"))),gulp.task("compress",()=>{pump([gulp.src("./*.js"),minify(),gulp.dest("public/dist/js")])}),gulp.task("minify-html",function(){return gulp.src("views/*.ejs").pipe(htmlmin({collapseWhitespace:!0,collapseInlineTagWhitespace:!0,removeComments:!0,removeRedundantAttributes:!0,useShortDoctype:!0,html5:!0})).pipe(gulp.dest("public/dist/html"))});

10
public/dist/js/jsbundle.js vendored Normal file
View File

@ -0,0 +1,10 @@
const path=require("path"),express=require("express"),bodyParser=require("body-parser"),ejs=require("ejs").__express,app=express();require("express-helpers")(app),app.set("views","./views"),app.set("view engine","ejs"),app.engine(".ejs",ejs),app.locals.rmWhitespace=!0;const episodes=require("./routes/episodes"),series=require("./routes/series");app.use(bodyParser.json({limit:"50mb"})),app.use(bodyParser.urlencoded({extended:!1})),app.use(express.static(path.join(__dirname,"public"))),app.use("/series",series),app.use("/",episodes),app.use("/episodes",episodes),app.use("/show",episodes),app.use("/anime",series),app.use("/episodes",series),app.use(function(e,s,p){var r=new Error("404: Not Found "+e.originalUrl);r.status=404,p(r)}),module.exports=app;
let gulp=require("gulp"),cleanCSS=require("gulp-clean-css");var pump=require("pump"),htmlmin=require("gulp-htmlmin"),concat=require("gulp-concat"),uglifyes=require("uglify-es"),composer=require("gulp-uglify/composer"),minify=composer(uglifyes);gulp.task("default",()=>console.log("See you in another vineyard")),gulp.task("minify-css",()=>gulp.src("public/css/*.css").pipe(cleanCSS({level:{1:{specialComments:0}}})).pipe(concat("bundle-css.css")).pipe(gulp.dest("public/dist/css"))),gulp.task("compress",()=>{pump([gulp.src(["./*.js","controllers/*.js","models/*.js","routes/*.js","helpers/*.js"]),minify(),concat("jsbundle.js"),gulp.dest("public/dist/js")])}),gulp.task("minify-html",()=>gulp.src(["views/*.ejs","views/layouts/*.ejs"]).pipe(htmlmin({collapseWhitespace:!0,collapseInlineTagWhitespace:!0,removeComments:!0,removeRedundantAttributes:!0,useShortDoctype:!0,html5:!0})).pipe(concat("bundle-html.html")).pipe(gulp.dest("public/dist/html")));
const mongoose=require("mongoose"),chalk=require("chalk"),log=console.log,error=chalk.bold.red;require("dotenv").config({path:"variables.env"}),mongoose.Promise=global.Promise;let mongodbUri=mongoose.connect("mongodb://YOUR MONGODB URL",{useMongoClient:!0,poolSize:3,reconnectTries:240,reconnectInterval:900,autoReconnect:!0,noDelay:!0,loggerLevel:"error"});const db=mongoose.connection;db.on("error",console.error.bind(console,"MongoDB connection error:")),db.once("open",function(){log(chalk.hex("#FFEB3B")("Te conectaste a la base de datos sin errores 👏 "),chalk.greenBright("😁"))}),process.on("unhandledRejection",(e,o)=>{console.log("Unhandled Rejection at: Promise",o,"reason:",e)});const appp=require("./app");appp.set("port",process.env.PORT||9e3);const server=appp.listen(appp.get("port"),()=>{log(chalk.underline.hex("#DEADED")("Server is listening music on port:"),chalk.hex("#4CAF50")(`🌏 PORT → ${server.address().port} 🎶`))});
const Episode=require("../models/episodes"),Serie=require("../models/series");module.exports={index:async(e,s,i)=>{const d=await Episode.find({}).sort({createdAt:-1}).limit(9);s.render("index",{episode:d})},newEpisode:async(e,s,i)=>{const d=await Serie.findById(e.body.anime),o=e.body;delete o.anime;const a=new Episode(o);a.anime=d,await a.save(),d.episodes.push(a),await d.save(),s.json(a)},getEpisode:async(e,s,i)=>{const d=await Episode.findOne({slug:e.params.slug});if(!d)return i();s.render("show",{episode:d})},replaceEpisode:async(e,s,i)=>{const{episodeId:d}=e.params,o=e.body;await Episode.findByIdAndUpdate(d,o);s.json({success:!0})},updateEpisode:async(e,s,i)=>{const{episodeId:d}=e.params,o=e.body;await Episode.findByIdAndUpdate(d,o);s.json({success:!0})},deleteEpisode:async(e,s,i)=>{const{episodeId:d}=e.params,o=await Episode.findById(d);if(!o)return s.status(404).json({error:"Episode no existe"});const a=o.anime,n=await Serie.findById(a);await o.remove(),console.log("anime",n),n.episodes.pull(o),console.log("anime",n),await n.save(),s.json({success:!0})}};
const Serie=require("../models/series"),Episode=require("../models/episodes");module.exports={index:async(e,s,i)=>{const a=await Serie.find({}).sort({createdAt:-1}).limit(9);s.render("series",{serie:a})},newSerie:async(e,s,i)=>{const a=new Serie(e.body),r=await a.save();s.json(r)},getSerie:async(e,s,i)=>{const a=await Serie.findOne({slug:e.params.slug}).populate({path:"episodes",select:"slug -_id",options:{sort:{createdAt:-1},limit:9}});if(!a)return i();s.render("anime",{serie:a})},replaceSerie:async(e,s,i)=>{const{serieId:a}=e.params,r=e.body;await Serie.findByIdAndUpdate(a,r);s.json({success:!0})},updateSerie:async(e,s,i)=>{const{serieId:a}=e.params,r=e.body;await Serie.findByIdAndUpdate(a,r);s.json({success:!0})},getSerieEpisodes:async(e,s,i)=>{const{serieId:a}=e.params,r=await Serie.findById(a).populate("episodes");s.json(r.episodes)},newSerieEpisode:async(e,s,i)=>{const{serieId:a}=e.params,r=new Episode(e.body),d=await Serie.findById(a);r.anime=d,await r.save(),d.episodes.push(r),await d.save(),s.json(r)}};
const mongoose=require("mongoose"),Schema=mongoose.Schema,slug=require("slugs"),episodeSchema=new Schema({title:{type:String},slug:String,serieTitle:String,chapterTitle:String,chapter:Number,server:String,serverTwo:String,imageCap:String,anime:{type:Schema.Types.ObjectId,ref:"serie"}},{timestamps:{}});episodeSchema.pre("save",async function(e){if(!this.isModified("title"))return void e();this.slug=slug(this.title);const s=new RegExp(`^(${this.slug})((-[0-9]*$)?)$`,"i"),i=await this.constructor.find({slug:s});i.length&&(this.slug=`${this.slug}-${i.length+1}`),e()});const Episode=mongoose.model("episode",episodeSchema);module.exports=Episode;
const mongoose=require("mongoose"),Schema=mongoose.Schema,slug=require("slugs"),serieSchema=new Schema({title:{type:String},slug:String,cover:String,backgroundimage:String,frontimage:String,synopsis:String,estate:String,type:String,tags:[String],episodes:[{type:Schema.Types.ObjectId,ref:"episode"}]},{timestamps:{}});serieSchema.pre("save",async function(e){if(!this.isModified("title"))return void e();this.slug=slug(this.title);const t=new RegExp(`^(${this.slug})((-[0-9]*$)?)$`,"i"),s=await this.constructor.find({slug:t});s.length&&(this.slug=`${this.slug}-${s.length+1}`),e()}),serieSchema.statics.getTagsList=function(){return this.aggregate([{$unwind:"$tags"},{$group:{_id:"$tags",count:{$sum:1}}},{$sort:{count:-1}}])};const Serie=mongoose.model("serie",serieSchema);module.exports=Serie;
const router=require("express-promise-router")(),EpisodesController=require("../controllers/episodes");router.route("/").get(EpisodesController.index).post(EpisodesController.newEpisode),router.route("/:slug").get(EpisodesController.getEpisode).put(EpisodesController.replaceEpisode).patch(EpisodesController.updateEpisode).delete(EpisodesController.deleteEpisode),module.exports=router;
const express=require("express"),router=require("express-promise-router")(),SeriesController=require("../controllers/series");router.route("/").get(SeriesController.index).post(SeriesController.newSerie),router.route("/:slug").get(SeriesController.getSerie).put(SeriesController.replaceSerie).patch(SeriesController.updateSerie),router.route("/:serieId/episodes").get(SeriesController.getSerieEpisodes).post(SeriesController.newSerieEpisode),module.exports=router;
const Joi=require("joi");module.exports={validateParam:(a,e)=>(r,o,i)=>{const s=Joi.validate({param:r.params[e]},a);if(s.error)return o.status(400).json(s.error);r.value||(r.value={}),r.value.params||(r.value.params={}),r.value.params[e]=s.value.param,i()},validateBody:a=>(e,r,o)=>{const i=Joi.validate(e.body,a);if(i.error)return r.status(400).json(i.error);e.value||(e.value={}),e.value.body||(e.value.body={}),e.value.body=i.value,o()},schemas:{serieSchema:Joi.object().keys({title:Joi.string().optional(),synopsis:Joi.string().optional()}),idSchema:Joi.object().keys({param:Joi.string().regex(/^[0-9a-fA-F]{24}$/).required()})}};

1
public/dist/js/start.js vendored Normal file
View File

@ -0,0 +1 @@
const mongoose=require("mongoose"),chalk=require("chalk"),log=console.log,error=chalk.bold.red;require("dotenv").config({path:"variables.env"}),mongoose.Promise=global.Promise;let mongodbUri=mongoose.connect("mongodb://YOUR MONGODB URL",{useMongoClient:!0,poolSize:3,reconnectTries:240,reconnectInterval:900,autoReconnect:!0,noDelay:!0,loggerLevel:"error"});const db=mongoose.connection;db.on("error",console.error.bind(console,"MongoDB connection error:")),db.once("open",function(){log(chalk.hex("#FFEB3B")("Did you connect to the database without errors"),chalk.greenBright("😁"))}),process.on("unhandledRejection",(e,o)=>{console.log("Unhandled Rejection at: Promise",o,"reason:",e)});const app=require("./app");app.set("port",process.env.PORT||9e3);const server=app.listen(app.get("port"),()=>{log(chalk.underline.hex("#DEADED")("Server is listening music on port:"),chalk.hex("#4CAF50")(`🌏 PORT → ${server.address().port} 🎶`))});

23
routes/episodes.js Normal file
View File

@ -0,0 +1,23 @@
const express = require("express");
const router = express.Router();
//const router = require("express-promise-router")();
const EpisodesController = require("../controllers/episodes");
router
.route("/")
.get(EpisodesController.index)
.post(EpisodesController.newEpisode);
router
.route("/:slug")
.get(EpisodesController.getEpisode)
/* .put(EpisodesController.replaceEpisode)
.patch(EpisodesController.updateEpisode) */
.delete(EpisodesController.deleteEpisode);
router
.route("/:episodeId")
.put(EpisodesController.replaceEpisode)
.patch(EpisodesController.updateEpisode);
module.exports = router;

35
routes/series.js Normal file
View File

@ -0,0 +1,35 @@
const express = require("express");
const router = express.Router();
//const router = require("express-promise-router")(); // Elimina la necesidad de usar try catch
const SeriesController = require("../controllers/series");
//const { validateParam, validateBody, schemas } = require('../helpers/routeHelper');
/* router
.route("/")
.post(SeriesController.newSerie);
*/
router
.route("/:page")
.get(SeriesController.index)
.post(SeriesController.newSerie);
router
.route("/:page/:slug")
.get(SeriesController.getSerie);
/*.put(SeriesController.replaceSerie)
.patch(SeriesController.updateSerie);
.delete(); */
router
.route("/:serieId")
.put(SeriesController.replaceSerie)
.patch(SeriesController.updateSerie);
router
.route("/:serieId/episodes")
.get(SeriesController.getSerieEpisodes)
.post(SeriesController.newSerieEpisode);
module.exports = router;

110
routes/users.js Normal file
View File

@ -0,0 +1,110 @@
const express = require("express");
const router = express.Router();
const Joi = require("joi");
const User = require("../models/user.js");
const passport = require("passport");
const userSchema = Joi.object().keys({
email: Joi.string()
.email()
.required(),
username: Joi.string()
.regex(/^[a-zA-Z0-9]{4,12}$/)
.required(),
password: Joi.string()
.regex(/^[a-zA-Z0-9]{3,30}$/)
.required(),
confirmPassword: Joi.any()
.valid(Joi.ref("password"))
.required()
});
const isAuthenticated = (req, res, next) => {
if (req.isAuthenticated()) {
// GOOD
return next();
} else {
req.flash("error", "Sorry, but you must be registered first!");
res.redirect("/");
}
};
// Revisar esta parte
/* const isNotAuthenticated = (req, res, next) => {
if (req.isAuthenticated()) {
// GOOD
return next();
req.flash("error", "Sorry, but you are already logged in!");
} else {
res.redirect("/");
}
}; */
router
.route("/register")
.get((req, res) => {
res.render("register");
})
.post(async (req, res, next) => {
try {
const result = Joi.validate(req.body, userSchema);
//console.log("result", result);
if (result.error) {
req.flash("error", "Data is not valid. Please try again.");
res.redirect("/users/register");
return;
}
// Check email
const user = await User.findOne({ email: result.value.email });
if (user) {
req.flash("error", "Email is already in use.");
res.redirect("/users/register");
return;
}
// Hash the password
const hash = await User.hashPassword(result.value.password);
//console.log('hash', hash);
// Save to DB
delete result.value.confirmPassword;
// Override the password with the hash
result.value.password = hash;
//console.log('new values', result.value);
const newUser = await new User(result.value);
console.log("newUser", newUser);
await newUser.save();
req.flash("success", "You may now login.");
res.redirect("/users/login");
return;
} catch (error) {
next(error);
}
});
router
.route("/login")
.get((req, res) => {
res.render("login");
})
.post(
passport.authenticate("local", {
successRedirect: "/users/dashboard",
failureRedirect: "/users/login",
failureFlash: true
})
);
router.route("/dashboard").get(isAuthenticated, (req, res) => {
res.render("dashboard", {
username: req.user.username
});
});
router.route("/logout").get(isAuthenticated,(req, res) => {
req.logout();
req.flash("success", "Successfully logged out, Hope to see you soon!");
res.redirect("/");
});
module.exports = router;

46
start.js Normal file
View File

@ -0,0 +1,46 @@
const mongoose = require('mongoose');
const chalk = require('chalk');
const log = console.log;
const error = chalk.bold.red;
//require('dotenv').config({ path: 'variables.env' });
mongoose.Promise = global.Promise;
// It is necessary to explicitly declare the connection url or it will not work in production
let mongodbUri = mongoose.connect('mongodb://YOUR MONGODB URL', {
poolSize: 5, //Number of connections in the connection pool for each server instance, set to 5 as default for legacy reasons.
reconnectTries: 240, //try to connect 60 times every few milliseconds, default 30
reconnectInterval: 900, //milliseconds
autoReconnect: true,
noDelay: true,
loggerLevel: "error",//warn, info, debug. Default: "error"
//appname: "RedMagic Corp."
});
//mongoose.set('debug', true);
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB connection error:'));
db.once('open', function () { log(chalk.hex('#FFEB3B')("You connected to the database without errors 👏 "),chalk.greenBright( "😁"))}); // 1 speed
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
// application specific logging, throwing an error, or other logic here
});
const start = require('./app');
// Start the server
/* app.set('port', process.env.PORT || 9000);
const server = app.listen(app.get('port'), () => log(chalk.underline.hex('#DEADED')('Server is listening music on port:'), chalk.hex('#4CAF50')(`\uD83C\uDF0F http://localhost:${port} 🎶`)));
*/
start.set('port', process.env.PORT || 9000);
const server = start.listen(start.get('port'), () => {
log(chalk.underline.hex('#DEADED')('Server is listening music on port:'), chalk.hex('#4CAF50')(`\uD83C\uDF0F PORT → ${server.address().port} 🎶`));
//console.log(`Express running → PORT ${server.address().port}`);
});

9
variable.env Normal file
View File

@ -0,0 +1,9 @@
NODE_ENV=development
DATABASE=Your Mongodb Url
MAIL_USER=Your Mail
MAIL_PASS=Your Password
MAIL_HOST=Your Mail Host
MAIL_PORT=2525
PORT=9000
SECRET=Your Secret
KEY=Your Key

77
views/anime.ejs Normal file
View File

@ -0,0 +1,77 @@
<% include ./layouts/header %>
<body>
<div class="elementoAnime">
<h1>View Anime </h1>
<h4 class="card-title">
<%- serie.title %>
<!--<%- serie._id %>-->
</h4>
<br>
<%- serie.synopsis.substring(0,48) %>...
<br>
<br>
<h6>Type:</h6>
<ul>
<%- link_to(serie.type) %>
</ul>
<h6>Genre:</h6>
<ul>
<% for(var i=0; i<serie.tags.length; i++) {%>
<li>
<%- link_to(serie.tags[i], '/'+serie.tags[i]) %>
</li>
<% } %>
</ul>
<h6>Episode:</h6>
<ul>
<% for(var i=0; i<serie.episodes.length; i++) {%>
<li>
<%- link_to(serie.episodes[i].slug, '/'+serie.episodes[i].slug) %>
</li>
<% } %>
</ul>
<% if(isAuthenticated){ %>
&nbsp;
<h2>Add episode to this anime</h2>
&nbsp;
<h4>id: <%- serie._id %></h4>
<form class="lel" id="lel" action="/" method="POST">
<label>Id Anime</label>
<input id="anime" name="anime" type="text" placeholder="<%- serie._id %>">
<label>Title</label>
<input id="title" name="title" type="text" placeholder="title">
<label>Server</label>
<input id="server" name="server" type="text" placeholder="server">
<label>ImageCap</label>
<input id="imageCap" name="imageCap" type="text" placeholder="imageCap">
<button type="submit" class="button-primary" id="btn" style="background-color: white;">Submit</button>
</form>
&nbsp;
<h2>Update Anime</h2>
<form class="lel" id="lel" action="/series/<%= serie._id %>?_method=PATCH" method="POST">
<label>Title</label>
<input id="title" type="text" name="title" value=" <%= serie.title %>">
<label>slug</label>
<input id="slug" type="text" name="slug" value=" <%= serie.slug %>">
<label>Image URL</label>
<input id="cover" type="text" name="cover" value="<%= serie.cover %>">
<label>Sinopsis</label>
<textarea id="synopsis" name="synopsis"><%= serie.synopsis %> </textarea>
<button type="submit" class="button-primary" id="btnn" style="background-color: white;">Submit</button>
</form>
<% } %>
</div>
</body>
<% include ./layouts/footer %>
</html>

66
views/dashboard.ejs Normal file
View File

@ -0,0 +1,66 @@
<% include ./layouts/header %>
<h1 id="dash">Dashboard</h1>
<body>
<div class="elementoDash">
<form class="lel" id="lel" action="/series/1" method="POST">
<legend>Add a series</legend>
<label>Title</label>
<input id="title" name="title" type="text" placeholder="title">
<label>Cover</label>
<input id="cover" name="cover" type="text" placeholder="cover">
<label>Sinopsis</label>
<input id="synopsis" name="synopsis" type="text" placeholder="synopsis">
<select name="estate" id="estate">
<option value="Activo">Active</option>
<option value="Finalizado">Finalized</option>
<option value="Suspendido">Discontinued</option>
<option value="Cancelado">Canceled</option>
</select>
<select name="type" id="type">
<option value="Anime">Anime</option>
<option value="OVA">OVA</option>
<option value="Pelicula">Movie</option>
<option value="Corto">Short</option>
</select>
<select multiple="multiple" name="tags" type="text" id="tags" >
<option value="Action">Action</option>
<option value="Adventure">Adventure</option>
<option value="Comedy">Comedy</option>
<option value="Drama">Drama</option>
<option value="Fantasy">Fantasy</option>
<option value="Horror">Horror</option>
<option value="Mecha">Mecha</option>
<option value="Mystery">Mystery</option>
<option value="Romance">Romance</option>
<option value="Seinen">Seinen</option>
<option value="Slice of Life">Slice of Life</option>
<option value="Yuri">Yuri</option>
</select>
<button type="submit" class="button-primary" id="btn" style="background-color: white;">Submit</button>
</form>
&nbsp;
<h2>Add new chapter</h2>
&nbsp;
</div>
<script>
$('#lel').on('btn', function(e) {
e.preventDefault();
var cuisines = $('tags').val().join(',');
});
</script>
<% include ./layouts/footer %>
</html>

15
views/episodes.ejs Normal file
View File

@ -0,0 +1,15 @@
<% include ./layouts/header %>
<body>
<h4>Episodes</h4>
<%- serie.serieTitle %>
</body>
</html>

25
views/index.ejs Normal file
View File

@ -0,0 +1,25 @@
<% include ./layouts/header %>
<body>
<div class="elemento">
<% episode.forEach(function(episode) { %>
<div class="caps">
<% const episodeUrl = '/episodes/' + episode.slug; %>
<div class="l-box">
<a href="<%- episode.slug %>"> <img class="image" src="<%- episode.imageCap %> "></a>
<h4>
<a href="<%- episode.slug %>">
<% if(episode.title.length > 28) { %>
<%- episode.title.substring(0,28) %>...
<% } else { %>
<%- episode.title %>
<% }; %>
</a>
</h4>
<p><small><%= moment(episode.createdAt).fromNow(); %></small></p>
</div>
</div>
<% }); %>
</div>
</body>
<% include ./layouts/footer %>
</html>

14
views/layouts/footer.ejs Normal file
View File

@ -0,0 +1,14 @@
<footer>
<section class="links">
<a href="#">Start</a>
<a href="#">Blog</a>
<a href="#">Project</a>
<a href="#">Contact</a>
</section>
<div class="social">
<a href="#">Facebook</a>
<a href="#">Twitter</a>
</div>
</footer>
</div>

38
views/layouts/header.ejs Normal file
View File

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>MPOKNIMU</title>
<meta charset="UTF-8">
<link href="/css/app.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1" />
</head>
<div class="contenedor">
<header>
<div class="logo">
<img src="#" width="150" alt="">
<a href="/">Home</a>
</div>
<nav>
<a href="/series/1">Series</a>
<% if(isAuthenticated){ %>
<a href="/users/dashboard">Dashboard</a>
<a href="/users/logout">Logout</a>
<% } else{ %>
<a href="/users/login">Login</a>
<a href="/users/register">Register</a>
<% } %>
</nav>
</header>
<% if (success_messages) { %>
<div class="alert alert-success"><%= success_messages %></div>
<% } %>
<% if (error_messages) { %>
<div class="alert alert-danger"><%= error_messages %></div>
<% } %>

17
views/login.ejs Normal file
View File

@ -0,0 +1,17 @@
<% include ./layouts/header %>
<div class="elemento">
<form class="pure-form pure-form-stacked" action="/users/login" method="POST">
<fieldset>
<legend>Login</legend>
<label for="email">Email</label>
<input id="inputEmail" name="email" type="email" placeholder="Email">
<label for="password">Password</label>
<input id="inputPassword" name="password" type="password" placeholder="Password">
<button type="submit" class="pure-button pure-button-primary">Sign in</button>
</fieldset>
</form>
</div>
<% include ./layouts/footer %>

24
views/register.ejs Normal file
View File

@ -0,0 +1,24 @@
<% include ./layouts/header %>
<div class="elemento">
<form class="pure-form pure-form-stacked" action="/users/register" method="POST" onsubmit="if(document.getElementById('agree').checked) { return true; } else { alert('Please indicate that you have read and agree to the Terms and Conditions and Privacy Policy'); return false; }">
<fieldset>
<legend>Register</legend>
<label for="email">Email</label>
<input id="inputEmail" name="email" type="email" placeholder="Email">
<label for="inputUsername">Username</label>
<input id="inputUsername" name="username" type="text" placeholder="Username">
<label for="password">Password</label>
<input id="inputPassword" name="password" type="password" placeholder="Password">
<label for="inputConfirmPassword">Confirm Password</label>
<input id="inputConfirmPassword" name="confirmPassword" type="password" placeholder="Confirm Password">
<input type="checkbox" name="checkbox" value="check" id="agree"> I have read and agree to the Terms and Conditions and Privacy Policy</input>
<button type="submit" class="pure-button pure-button-primary">Sign in</button>
</fieldset>
</form>
</div>
<% include ./layouts/footer %>

51
views/series.ejs Normal file
View File

@ -0,0 +1,51 @@
<% include ./layouts/header %>
<body>
<div class="elemento">
<% serie.forEach(function(serie) { %>
<% const serieUrl = '/series/' + serie.slug; %>
<div class="sada1">
<a href="anime/<%- serie.slug %>" class="card-link"> <img class="image" id="image-home" src="<%- serie.cover %>" alt="Card image cap"></a>
<h4 class="card-title">
<%- serie.title.substring(0,18) %>
</h4>
<p class="card-text">
<%- serie.synopsis.substring(0,20) %>...
</p>
</div>
<% }); %>
</div>
<div class="pagination">
<% if (pages > 0) { %>
<ul class="pagination text-center">
<% if (current == 1) { %>
<a class="disabled"><<</a>
<% } else { %>
<a href="/series/1"><<</a>
<% } %>
<% var i = (Number(current) > 5 ? Number(current) - 4 : 1) %>
<% if (i !== 1) { %>
<a class="disabled">...</a>
<% } %>
<% for (; i <= (Number(current) + 4) && i <= pages; i++) { %>
<% if (i == current) { %>
<a class="active"><%= i %></a>
<% } else { %>
<a href="/series/<%= i %>"><%= i %></a>
<% } %>
<% if (i == Number(current) + 4 && i < pages) { %>
<a class="disabled">...</a>
<% } %>
<% } %>
<% if (current == pages) { %>
<a class="disabled">>></a>
<% } else { %>
<a href="/series/<%= pages %>">>></a>
<% } %>
</ul>
<% } %>
</div>
</body>
<% include ./layouts/footer %>
</html>

58
views/show.ejs Normal file
View File

@ -0,0 +1,58 @@
<% include ./layouts/header %>
<!-- <script type="text/javascript" src="https://content.jwplatform.com/libraries/es3tFzVf.js"></script>
<script src="player/jwplayer/jwplayer.js"></script>
<script>jwplayer.key="pTXQ0hR1iHUrKsQ//UZzTZRBTAKZzsF0FVIV";</script>-->
<script src="https://content.jwplatform.com/libraries/bfIbW5Pe.js"></script>
<body>
<div class="elementoVideo">
<div class="container" style="">
<div class="row">
<h1>
<%- episode.serieTitle %> <%- episode.chapter %>
</h1>
<div class="media80">
<div id="myElement"></div>
<script type="text/javascript">
var playerInstance = jwplayer("myElement");
playerInstance.setup({
file: "/assets/cap3.mp4",
width: "100%",
aspectratio: "16:9",
playbackRateControls: [0.25, 0.75, 1, 1.25, 2, 3],
image: "<%- episode.imageCap %>",
preload: "metadata"
});
</script>
</div>
</div>
</div>
<div>
<% if(isAuthenticated){ %>
<h2>Update Anime</h2>
<form class="lel" id="lel" action="/episodes/<%= episode._id %>?_method=PATCH" method="POST">
<label>Title</label>
<input id="title" type="text" name="title" value=" <%= episode.title %>">
<label>slug</label>
<input id="slug" type="text" name="slug" value=" <%= episode.slug %>">
<label>imageCap</label>
<input id="imageCap" type="text" name="imageCap" value="<%= episode.imageCap %>">
<label>Server</label>
<input id="server" type="text" name="server" value="<%= episode.server %>">
<button type="submit" class="button-primary" id="btnn" style="background-color: white;">Submit</button>
</form>
<% } %>
</div>
</div>
</body>
<% include ./layouts/footer %>
</html>

4618
yarn.lock Normal file

File diff suppressed because it is too large Load Diff