Skip to content

Commit

Permalink
Core, making improvements with progress
Browse files Browse the repository at this point in the history
  • Loading branch information
JustineRobert committed Nov 8, 2019
1 parent d60d656 commit efd96d0
Show file tree
Hide file tree
Showing 18 changed files with 620 additions and 4 deletions.
Empty file added .DS_Store
Empty file.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
4 changes: 2 additions & 2 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ app.use(express.static(path.join(__dirname, 'public')));

app.get('/', (req, res) => res.send('TEAMWORK'));

//Team routes
app.use('/users', require('./routes/users'));
//User routes
app.use('/users', require('./servers/routes/users'));;

const PORT = process.env.PORT || 5000;

Expand Down
106 changes: 106 additions & 0 deletions servers/controllers/ArticlesController.js
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;
32 changes: 32 additions & 0 deletions servers/controllers/UserController.js
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;
123 changes: 123 additions & 0 deletions servers/database/database.js
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;
13 changes: 13 additions & 0 deletions servers/database/init_db.js
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');
46 changes: 46 additions & 0 deletions servers/database/migrations/create_articles_table.js
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;
32 changes: 32 additions & 0 deletions servers/database/migrations/create_categories_table.js
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;
Loading

0 comments on commit efd96d0

Please sign in to comment.