-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Core, making improvements with progress
- Loading branch information
1 parent
d60d656
commit efd96d0
Showing
18 changed files
with
620 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import moment from 'moment'; | ||
import Helpers from '../helpers/Helpers'; | ||
import { Article, Category, Comment } from '../models'; | ||
import { articles } from '../mock'; | ||
|
||
const Model = new Article(); | ||
|
||
class ArticlesController { | ||
static async store(request, response) { | ||
const { user } = request; | ||
const data = { | ||
...request.body, | ||
authorId: user.id, | ||
createdOn: moment().format('YYYY-MM-DD HH:mm:ss'), | ||
}; | ||
const store = await Model.create(data); | ||
if (store.errors) Helpers.dbError(response, store); | ||
return Helpers.sendResponse(response, 201, 'Article successfully created', data); | ||
} | ||
|
||
static async findAll(request, response) { | ||
const _articles = await Model.all(); | ||
if (_articles.errors) Helpers.dbError(response, _articles); | ||
return Helpers.sendResponse(response, 200, 'Success', _articles.rows); | ||
} | ||
|
||
static async update(request, response) { | ||
const { articleId } = request.params; | ||
const { user } = request; | ||
const data = { | ||
...request.body, | ||
updatedOn: moment().format('YYYY-MM-DD HH:mm:ss'), | ||
}; | ||
const update = await Model.update(data, { | ||
authorId: user.id, | ||
id: articleId, | ||
}); | ||
if (update.errors) return Helpers.dbError(response, update); | ||
if (update.count > 0) { | ||
return Helpers.sendResponse(response, 200, 'Article successfully edited', data); | ||
} | ||
return Helpers.sendResponse(response, 404, 'Article no found !'); | ||
} | ||
|
||
static async destroy(request, response) { | ||
const { articleId } = request.params; | ||
const { user } = request; | ||
const destroy = await Model.delete({ | ||
authorId: user.id, | ||
id: articleId, | ||
}); | ||
if (destroy.errors) return Helpers.dbError(response, destroy); | ||
if (destroy.count > 0) { | ||
return Helpers.sendResponse(response, 204, 'Article successfully deleted'); | ||
} | ||
return Helpers.sendResponse(response, 404, 'Article Not Found !!'); | ||
} | ||
|
||
static async findOne(request, response) { | ||
const { articleId } = request.params; | ||
const result = await Model.getById(articleId); | ||
if (result.errors) return Helpers.dbError(response, result); | ||
if (result.count > 0) { | ||
return Helpers.sendResponse(response, 200, 'Article found !', result.row); | ||
} | ||
return Helpers.sendResponse(response, 404, 'Article not found !'); | ||
} | ||
|
||
static async findByCategory(request, response) { | ||
const { tagId } = request.params; | ||
const categoryModel = new Category(tagId); | ||
const results = await categoryModel.articles(); | ||
if (results.errors) return Helpers.dbError(response, results); | ||
if (results.count < 1) return Helpers.sendResponse(response, 404, 'No articles found !'); | ||
return Helpers.sendResponse(response, 200, 'Success', results.rows); | ||
} | ||
|
||
static async addComment(request, response) { | ||
const commentModel = new Comment(); | ||
const { user } = request; | ||
const { comment } = request.body; | ||
const { articleId } = request.params; | ||
const data = { | ||
comment, | ||
article_id: parseInt(articleId), | ||
employee_id: user.id, | ||
createdOn: moment() | ||
.format('YYYY-MM-DD HH:mm:ss'), | ||
}; | ||
const save = await commentModel.create(data); | ||
if (save.errors) Helpers.dbError(response, save); | ||
return Helpers.sendResponse(response, 201, 'Comment successfully added.', data); | ||
} | ||
|
||
static async findByAuthor(request, response) { | ||
const { authorId } = request.params; | ||
const results = await Model.getByAuthor(authorId); | ||
if (results.errors) return Helpers.dbError(response, results); | ||
if (results.count <= 0) { | ||
return Helpers.sendResponse(response, 404, 'No articles found !', []); | ||
} | ||
return Helpers.sendResponse(response, 200, 'Success', results.rows); | ||
} | ||
} | ||
|
||
export default ArticlesController; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import Helpers from '../helpers/Helpers'; | ||
import users from '../mock/user'; | ||
import { User } from '../models'; | ||
|
||
const user = new User(); | ||
|
||
class UserController { | ||
static async signUp(request, response) { | ||
const data = request.body; | ||
data.password = Helpers.hashPassword(request.body.password); | ||
const checkEmail = await user.getByEmail(data.email); | ||
if (checkEmail.errors) return Helpers.dbError(response, checkEmail); | ||
if (checkEmail.count > 0) return Helpers.sendResponse(response, 409, 'Email already exists !'); | ||
const saveUser = await user.create(data); | ||
if (saveUser.errors) return Helpers.dbError(response, saveUser); | ||
const token = Helpers.generateToken(saveUser.rows[0].id); | ||
return Helpers.sendResponse(response, 201, 'User created successfully', { token }); | ||
} | ||
|
||
static async signIn(request, response) { | ||
const { email, password } = request.body; | ||
const _user = await user.getByEmail(email); | ||
Helpers.dbError(response, _user); | ||
if (_user.count > 0 && Helpers.comparePassword(_user.row.password, password)) { | ||
const token = Helpers.generateToken(_user.row.id); | ||
return Helpers.sendResponse(response, 200, 'User is successfully logged in', { token }); | ||
} | ||
return Helpers.sendResponse(response, 400, 'Invalid credentials'); | ||
} | ||
} | ||
|
||
export default UserController; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import { Pool } from 'pg'; | ||
import dotenv from 'dotenv'; | ||
|
||
dotenv.config(); | ||
|
||
const { | ||
PGUSER, PGHOST, PGPASSWORD, PGDATABASE, PGPORT, PGTESTDATABASE, | ||
} = process.env; | ||
const database = process.env.NODE_ENV === 'test' ? PGTESTDATABASE : PGDATABASE; | ||
|
||
|
||
const pool = new Pool({ | ||
database, | ||
user: PGUSER, | ||
host: PGHOST, | ||
password: PGPASSWORD, | ||
port: PGPORT, | ||
}); | ||
|
||
class Database { | ||
constructor(table) { | ||
this.table = table; | ||
} | ||
|
||
async queryBuilder(query, params) { | ||
try { | ||
const client = await pool.connect(); | ||
const res = await client.query(query, params); | ||
client.end(); | ||
const { rows, rowCount } = res; | ||
return { | ||
rows, | ||
count: rowCount, | ||
}; | ||
} catch (errors) { | ||
return { errors }; | ||
} | ||
} | ||
|
||
async create(data) { | ||
const params = []; | ||
const chunks = []; | ||
const values = []; | ||
const keys = []; | ||
Object.keys(data) | ||
.forEach((key) => { | ||
keys.push(key); | ||
params.push(data[key]); | ||
values.push(`$${params.length}`); | ||
}); | ||
chunks.push(`(${values.join(', ')})`); | ||
const query = `INSERT INTO ${this.table}(${keys.join(', ')}) values${chunks.join(', ')} RETURNING *`; | ||
return await this.queryBuilder(query, params); | ||
} | ||
|
||
async where(column, op = '=', value, orderBy = 'id DESC') { | ||
if (this.table && column && value) { | ||
const sql = `SELECT * FROM ${this.table} WHERE ${column}${op}$1 ORDER BY ${orderBy}`; | ||
const query = await this.queryBuilder(sql, [value]); | ||
if (query.errors) return query; | ||
return { | ||
rows: query.rows, | ||
count: query.count, | ||
}; | ||
} | ||
return { | ||
error: 'Please provide table name & column & value', | ||
}; | ||
} | ||
|
||
async first(column, op = '=', value) { | ||
const query = await this.where(column, op, value); | ||
if (!query.error) { | ||
return { | ||
row: query.rows[0], | ||
count: query.count, | ||
}; | ||
} | ||
return query; | ||
} | ||
|
||
async all(orderBy = 'id DESC') { | ||
const sql = `SELECT * FROM ${this.table} ORDER BY ${orderBy}`; | ||
const query = await this.queryBuilder(sql, []); | ||
return (!query.error) ? { | ||
rows: query.rows, | ||
count: query.count, | ||
} : query; | ||
} | ||
|
||
async delete(where) { | ||
if (where) { | ||
const conditions = this.prepareObject(where, ' AND '); | ||
const sql = `DELETE FROM ${this.table} WHERE ${conditions}`; | ||
return this.queryBuilder(sql); | ||
} | ||
return { error: 'provide condition' }; | ||
} | ||
|
||
async update(data, where) { | ||
if (data && where) { | ||
const updates = this.prepareObject(data); | ||
const conditions = this.prepareObject(where, ' AND '); | ||
const sql = `UPDATE ${this.table} SET ${updates} WHERE ${conditions} RETURNING *`; | ||
const query = await this.queryBuilder(sql); | ||
return (!query.error) ? { | ||
rows: query.rows, | ||
count: query.count, | ||
} : query; | ||
} | ||
return { error: 'provide data & condition' }; | ||
} | ||
|
||
prepareObject(obj, separator = ', ') { | ||
const chunks = []; | ||
Object.keys(obj).forEach((key) => { | ||
chunks.push(`${key}='${obj[key]}'`); | ||
}); | ||
return chunks.join(`${separator}`); | ||
} | ||
} | ||
|
||
export default Database; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { CreateEmployeesTable, CreateArticlesTable, CreateCategoriesTable } from './migrations'; | ||
import CreateCommentsTable from './migrations/create_comments_table'; | ||
|
||
const InitDB = async () => { | ||
await CreateEmployeesTable.run(); | ||
await CreateArticlesTable.run(); | ||
await CreateCommentsTable.run(); | ||
await CreateCategoriesTable.run(); | ||
}; | ||
|
||
module.exports = InitDB; | ||
|
||
require('make-runnable'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import Database from '../database'; | ||
import { Article } from '../../models'; | ||
import Helpers from '../../helpers/Helpers'; | ||
import { articles } from '../../mock'; | ||
|
||
const database = new Database(); | ||
const dummy = { ...articles[0] }; | ||
class CreateArticlesTable { | ||
static up() { | ||
return 'CREATE TABLE IF NOT EXISTS articles(' | ||
+ 'id SERIAL PRIMARY KEY,' | ||
+ 'title VARCHAR (255) NOT NULL,' | ||
+ 'image VARCHAR (255) NULL,' | ||
+ 'article TEXT NOT NULL,' | ||
+ 'authorId INT NOT NULL CHECK (authorId >= 0),' | ||
+ 'category_id INT NULL CHECK (category_id >= 0),' | ||
+ 'createdOn timestamp NOT NULL,' | ||
+ 'updatedOn timestamp NULL' | ||
+ ');'; | ||
} | ||
|
||
static down() { | ||
return 'DROP TABLE IF EXISTS articles;'; | ||
} | ||
|
||
static async seeds() { | ||
const article = new Article(); | ||
const articleMock = { ...dummy }; | ||
if (articleMock) { | ||
delete articleMock.id; | ||
delete articleMock.comments; | ||
delete articleMock.tags; | ||
return await article.create(articleMock); | ||
} | ||
} | ||
|
||
static async run() { | ||
await database.queryBuilder(CreateArticlesTable.down()); | ||
await database.queryBuilder(CreateArticlesTable.up()); | ||
if (process.env.NODE_ENV === 'test') { | ||
await CreateArticlesTable.seeds(); | ||
} | ||
} | ||
} | ||
|
||
export default CreateArticlesTable; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import Database from '../database'; | ||
import { categories } from '../../mock'; | ||
import { Category } from '../../models'; | ||
|
||
const database = new Database(); | ||
const category = new Category(); | ||
class CreateCategoriesTable { | ||
static up() { | ||
return 'CREATE TABLE IF NOT EXISTS categories(' | ||
+ 'id SERIAL PRIMARY KEY,' | ||
+ 'category TEXT NOT NULL' | ||
+ ');'; | ||
} | ||
|
||
static down() { | ||
return 'DROP TABLE IF EXISTS categories;'; | ||
} | ||
|
||
static async seeds() { | ||
const prepare = categories.map((cat, i) => `($${i + 1})`).join(','); | ||
const sql = `INSERT INTO categories(category) VALUES ${prepare}`; | ||
return await category.queryBuilder(sql, categories); | ||
} | ||
|
||
static async run() { | ||
await database.queryBuilder(CreateCategoriesTable.down()); | ||
await database.queryBuilder(CreateCategoriesTable.up()); | ||
await CreateCategoriesTable.seeds(); | ||
} | ||
} | ||
|
||
export default CreateCategoriesTable; |
Oops, something went wrong.