Articles routing progress
All articles, and querys for limit and offset working.
This commit is contained in:
parent
f1cb95d88a
commit
0c3c909ae6
|
|
@ -1,4 +1,7 @@
|
|||
|
||||
import { IUserModel } from '../models/user-model';
|
||||
|
||||
|
||||
export interface IArticle {
|
||||
slug: string;
|
||||
title: string;
|
||||
|
|
@ -9,4 +12,5 @@ export interface IArticle {
|
|||
updatedAt: Date;
|
||||
favorited: boolean;
|
||||
favoritesCount: number;
|
||||
author: IUserModel;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,3 +5,11 @@ export interface IUser {
|
|||
bio?: string;
|
||||
image?: string;
|
||||
}
|
||||
|
||||
|
||||
export interface IProfile {
|
||||
username: string;
|
||||
bio: string;
|
||||
image: string;
|
||||
following: boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
|
||||
import { model, Model, Schema, Document } from 'mongoose';
|
||||
import { IArticle } from '../interfaces/article-interface';
|
||||
import { IUserModel } from './user-model';
|
||||
// import * as mongoose from 'mongoose';
|
||||
// const User = mongoose.model('User');
|
||||
import { IUserModel, User } from './user-model';
|
||||
|
||||
|
||||
export interface IArticleModel extends IArticle, Document {
|
||||
toArticleJSON(user);
|
||||
formatAsArticleJSON(user);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -22,21 +20,22 @@ const ArticleSchema = new Schema({
|
|||
}, {timestamps: true});
|
||||
|
||||
|
||||
ArticleSchema.methods.toArticleJSON = function(user: IUserModel) {
|
||||
ArticleSchema.methods.formatAsArticleJSON = function(user: IUserModel) {
|
||||
|
||||
return {
|
||||
slug: this.slug,
|
||||
title: this.title,
|
||||
description: this.description,
|
||||
body: this.body,
|
||||
tagList: this.tagList,
|
||||
createdAt: this.createdAt,
|
||||
updatedAt: this.updatedAt,
|
||||
tagList: this.tagList,
|
||||
favorited: user ? user.isFavorite(this._id) : false,
|
||||
favoritesCount: this.favoritesCount,
|
||||
author: this.author
|
||||
author: this.author.formatAsProfileJSON(user)
|
||||
};
|
||||
|
||||
};
|
||||
// TODO: taglist
|
||||
// TODO fix author
|
||||
|
||||
|
||||
export const Article: Model<IArticleModel> = model<IArticleModel>('Article', ArticleSchema);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
import { Document, Schema, Model, model } from 'mongoose';
|
||||
import { IUser } from '../interfaces/user-interface';
|
||||
import * as jwt from 'jsonwebtoken';
|
||||
import { jwtSecret } from './authentication';
|
||||
import { jwtSecret } from '../utilities/authentication';
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
|
||||
export interface IUserModel extends IUser, Document {
|
||||
token: string;
|
||||
token?: string;
|
||||
generateJWT();
|
||||
formatAsUserJSON();
|
||||
setPassword(password);
|
||||
|
|
|
|||
|
|
@ -1,46 +1,182 @@
|
|||
|
||||
import { Router, Response, NextFunction } from 'express';
|
||||
import { authentication } from '../models/authentication';
|
||||
import { JWTRequest } from '../interfaces/requests-interface';
|
||||
import { Router, NextFunction, Response } from 'express';
|
||||
import { authentication } from '../utilities/authentication';
|
||||
import { ProfileRequest } from '../interfaces/requests-interface';
|
||||
import { Article, IArticleModel } from '../models/article-model';
|
||||
|
||||
import { IUserModel, User } from '../models/user-model';
|
||||
// import * as Promise from 'bluebird';
|
||||
|
||||
const router: Router = Router();
|
||||
const Promise = require('bluebird');
|
||||
|
||||
|
||||
/**
|
||||
* // GET /api/articles
|
||||
* GET /api/articles
|
||||
*/
|
||||
router.get('/', authentication.optional, (req: JWTRequest, res: Response, next: NextFunction) => {
|
||||
router.get('/', authentication.optional, (req: ProfileRequest, res: Response, next: NextFunction) => {
|
||||
|
||||
Article
|
||||
.findOne()
|
||||
.then( (article: IArticleModel) => {
|
||||
// res.status(200).json({article: article.toArticleJSON()});
|
||||
res.json({message: 'working on this...'});
|
||||
}
|
||||
)
|
||||
.catch(next);
|
||||
// Handle all URL query parameters
|
||||
const limit: number = req.query.limit ? Number(req.query.limit) : 20;
|
||||
const offset: number = req.query.offset ? Number(req.query.offset) : 0;
|
||||
|
||||
// .findById(req.payload.id)
|
||||
// .then((user: IUserModel) => {
|
||||
// res.status(200).json({user: user.formatAsUserJSON()});
|
||||
// }
|
||||
// )
|
||||
// .catch(next);
|
||||
//
|
||||
|
||||
// Try to determine the user making the request
|
||||
let thisUser: IUserModel;
|
||||
|
||||
// If authentication was performed was successful look up the profile relative to authenticated user
|
||||
if (req.payload) {
|
||||
User
|
||||
.findById(req.payload.id)
|
||||
.then( (user: IUserModel) => {
|
||||
return thisUser = req.profile.formatAsProfileJSON(user);
|
||||
})
|
||||
.catch();
|
||||
|
||||
// If authentication was NOT performed or successful look up profile relative to that same user (following = false)
|
||||
} else {
|
||||
thisUser = req.profile;
|
||||
}
|
||||
);
|
||||
|
||||
// TODO: Remining routes
|
||||
|
||||
// Define promises
|
||||
const p1 = thisUser;
|
||||
|
||||
const p2 = Article.count( {});
|
||||
|
||||
const p3 = Article.find().limit(limit).skip(offset).populate('author').catch();
|
||||
|
||||
// Resolve and use promise results
|
||||
Promise
|
||||
.all([p1, p2, p3])
|
||||
.then(results => {
|
||||
const user: IUserModel = results[0];
|
||||
const articlesCount: number = results[1];
|
||||
const articles = results[2];
|
||||
|
||||
res.json(
|
||||
{articles: articles.map((article: IArticleModel) => {
|
||||
return article.formatAsArticleJSON(user);
|
||||
}),
|
||||
articlesCount});
|
||||
})
|
||||
.catch(next);
|
||||
|
||||
});
|
||||
|
||||
|
||||
// PREVIOUS ATTEMPT:
|
||||
// router.get('/', authentication.optional, (req: ProfileRequest, res: Response, next: NextFunction) => {
|
||||
//
|
||||
// let articlesCount = 0;
|
||||
// let thisUser: IUserModel;
|
||||
//
|
||||
// // If authentication was performed was successful look up the profile relative to authenticated user
|
||||
// if (req.payload) {
|
||||
// User
|
||||
// .findById(req.payload.id)
|
||||
// .then( (user: IUserModel) => {
|
||||
// return thisUser = req.profile.formatAsProfileJSON(user);
|
||||
// })
|
||||
// .catch();
|
||||
//
|
||||
// // If authentication was NOT performed or successful look up profile relative to that same user (following = false)
|
||||
// } else {
|
||||
// thisUser = req.profile;
|
||||
// }
|
||||
//
|
||||
// Article
|
||||
// .count( (err, count) => {
|
||||
// articlesCount = count;
|
||||
// })
|
||||
// .find()
|
||||
// .sort({updatedAt: 'desc'})
|
||||
// .then( (articles: IArticleModel[]) => {
|
||||
// res.json({articles: articles.map(article => {
|
||||
// console.log(article);
|
||||
// return article.formatAsArticleJSON(thisUser);
|
||||
// }), articlesCount
|
||||
// });
|
||||
// })
|
||||
// .catch(next);
|
||||
// });
|
||||
|
||||
|
||||
// WORKING:
|
||||
// interface IQuery {
|
||||
// tagList: {$in: any[]};
|
||||
// author: string;
|
||||
// _id: {$in: any[]};
|
||||
// limit: number;
|
||||
// offset: number;
|
||||
// }
|
||||
// let query: IQuery;
|
||||
// let limit = 20;
|
||||
// let offset = 0;
|
||||
//
|
||||
// if (typeof req.query.limit !== 'undefined') {
|
||||
// limit = req.query.limit;
|
||||
// }
|
||||
//
|
||||
// if (typeof req.query.offset !== 'undefined') {
|
||||
// offset = req.query.offset;
|
||||
// }
|
||||
//
|
||||
// if ( typeof req.query.tag !== 'undefined' ) {
|
||||
// query.tagList = {$in : [req.query.tag]};
|
||||
// }
|
||||
//
|
||||
// Promise.all([
|
||||
// req.query.author ? User.findOne({username: req.query.author}) : null,
|
||||
// req.query.favorited ? User.findOne({username: req.query.favorited}) : null
|
||||
// ]).then(function(results){
|
||||
// const author = results[0];
|
||||
// const favoriter = results[1];
|
||||
//
|
||||
// if (author) {
|
||||
// query.author = author._id;
|
||||
// }
|
||||
//
|
||||
// if (favoriter) {
|
||||
// query._id = {$in: favoriter.favorites};
|
||||
// } else if (req.query.favorited) {
|
||||
// query._id = {$in: []};
|
||||
// }
|
||||
//
|
||||
// Promise.all([
|
||||
// Article.find(query)
|
||||
// .limit(Number(limit))
|
||||
// .skip(Number(offset))
|
||||
// .sort({createdAt: 'desc'})
|
||||
// .populate('author')
|
||||
// .exec(),
|
||||
// Article.count(query).exec(),
|
||||
// req.payload ? User.findById(req.payload.id) : null,
|
||||
// ]).then(function(results){
|
||||
// const articles = results[0];
|
||||
// const articlesCount = results[1];
|
||||
// const user = results[2];
|
||||
//
|
||||
// return res.json({
|
||||
// articles: articles.map(function(article) {
|
||||
// return article.formatAsArticleJSON(user);
|
||||
// }),
|
||||
// articlesCount
|
||||
// });
|
||||
// });
|
||||
// }).catch(next);
|
||||
|
||||
|
||||
// TODO: Remaining routes
|
||||
// GET /api/articles/feed
|
||||
// GET /api/articles/:slug
|
||||
// POST /api/articles
|
||||
// PUT /api/articles/:slug
|
||||
// DELETE /api/articles/:slug
|
||||
|
||||
// POST /api/articles/:slug/comments
|
||||
// GET /api/articles/:slug/comments
|
||||
// DELETE /api/articles/:slug/comments/:id
|
||||
|
||||
// POST /api/articles/:slug/favorite
|
||||
// DELETE /api/articles/:slug/favorite
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
import { NextFunction, Request, Response, Router } from 'express';
|
||||
import { NextFunction, Response, Router } from 'express';
|
||||
import { IUserModel, User } from '../models/user-model';
|
||||
import { authentication } from '../models/authentication';
|
||||
import { authentication } from '../utilities/authentication';
|
||||
import { ProfileRequest } from '../interfaces/requests-interface';
|
||||
|
||||
const router: Router = Router();
|
||||
|
|
@ -28,7 +28,7 @@ router.param('username', (req: ProfileRequest, res: Response, next: NextFunction
|
|||
*/
|
||||
router.get('/:username', authentication.optional, (req: ProfileRequest, res: Response, next: NextFunction) => {
|
||||
|
||||
// If authentication was performed and successful look up the profile relative to authenticated user
|
||||
// If authentication was performed and was successful look up the profile relative to authenticated user
|
||||
if (req.payload) {
|
||||
User
|
||||
.findById(req.payload.id)
|
||||
|
|
@ -39,15 +39,9 @@ router.get('/:username', authentication.optional, (req: ProfileRequest, res: Res
|
|||
|
||||
// If authentication was NOT performed or successful look up profile relative to that same user (following = false)
|
||||
} else {
|
||||
// User
|
||||
// .findOne({username: req.params.username})
|
||||
// .then( (user: IUserModel) => {
|
||||
// res.status(200).json({profile: user.formatAsProfileJSON(user)});
|
||||
// })
|
||||
// .catch(next);
|
||||
res.status(200).json({profile: req.profile.formatAsProfileJSON(req.profile)});
|
||||
}
|
||||
// ISSUE: why have to repeat query? Why route-level variable not accessible here?
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -87,7 +81,6 @@ router.delete('/:username/follow', authentication.required, (req: ProfileRequest
|
|||
})
|
||||
.catch(next);
|
||||
});
|
||||
// TODO: DELETE route working on first try
|
||||
|
||||
|
||||
export const ProfilesRoutes: Router = router;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
import { IUserModel, User } from '../models/user-model';
|
||||
import { authentication } from '../models/authentication';
|
||||
import { authentication } from '../utilities/authentication';
|
||||
import { NextFunction, Response, Router } from 'express';
|
||||
import { JWTRequest } from '../interfaces/requests-interface';
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import * as passport from 'passport';
|
|||
import { User } from '../models/user-model';
|
||||
import * as passportLocal from 'passport-local';
|
||||
|
||||
|
||||
const LocalStrategy = passportLocal.Strategy;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,15 @@
|
|||
"integrity": "sha512-rBfrD56OxaqVjghtVqp2EEX0ieHkRk6IefDVrQXIVGvlhDOEBTvZff4Q02uo84ukVkH4k5eB1cPKGDM2NlFL8A==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/bluebird-global": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/bluebird-global/-/bluebird-global-3.5.3.tgz",
|
||||
"integrity": "sha512-EP8wk7BRKtb9MhdHSc/xeUSfBByHQpm6pFwvQV1dO0d2o0wShYB9xEOx+OGP+2VNtADaBnhvXJ+Z5sgseR+f/w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/bluebird": "3.5.8"
|
||||
}
|
||||
},
|
||||
"@types/bson": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/bson/-/bson-1.0.4.tgz",
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
"homepage": "https://",
|
||||
"devDependencies": {
|
||||
"@types/bluebird": "^3.5.8",
|
||||
"@types/bluebird-global": "^3.5.3",
|
||||
"@types/express": "^4.0.37",
|
||||
"@types/express-jwt": "0.0.37",
|
||||
"@types/express-session": "^1.15.3",
|
||||
|
|
|
|||
Loading…
Reference in New Issue