const db = require('../../models'), bcrypt = require('bcrypt-nodejs'), errorMaker = require('../helpers/error.maker'), uuidv4 = require('uuid/v4'); const { Grant, Cause, Region, Organization } = db; // Verify charity exports.verifyCharity = async (req, res, next) => { const charity_id = req.params.charity_id; await db.sequelize.query( 'UPDATE organizations SET verified = 1 WHERE id = :charity_id', { replacements: { charity_id } } ); return res.status(200).json({ message: 'Successfully verified charity' }); }; const log10 = val => { return Math.log(val) / Math.log(10); }; // POST to get suggested organizations based on chosen causes + regions exports.findSuggestedCharities = (req, res, next) => { const { amount, causes, regions } = req.body; if (amount == 0 || causes.length == 0 || regions.length == 0) { return next(errorMaker(400, 'Invalid options for grant suggestions')); } // formula for max amount of organizations to choose const max_orgs = Math.floor(1.5 * log10(amount)); const QUERY = 'SELECT * from organizations ' + 'WHERE primary_cause IN (:causes) or primary_region IN (:regions) ' + 'LIMIT :max_orgs'; db.sequelize .query(QUERY, { replacements: { causes, regions, max_orgs }, type: db.Sequelize.QueryTypes.SELECT }) .then(organizations => { res.status(200).json({ organizations, num_items: organizations.length, max_orgs, distribution: amount / organizations.length }); }) .catch(error => next(error)); }; // GET min and optimal amounts for the chosen causes + regions exports.findOptimalBundleAmounts = (req, res, next) => { const { num_causes, num_regions } = req.body; const feature_factor = parseInt(num_causes) + parseFloat(num_regions / 2); // calculate min amount for chosen causes and regions const min_amount = Math.ceil(feature_factor * 15); // calculate optimal for chosen causes and regions const optimal_amount = Math.ceil(Math.pow(5, feature_factor)); res.status(200).json({ min_amount, optimal_amount }); }; // POST create an organization exports.createOrganization = async (req, res, next) => { let { name, short_description, primary_contact_email, password, address, city, country, state, zip, primary_cause, primary_region, ein, estimate_asset_value, estimate_yearly_operating_cost, is_nonprofit, primary_contact_phone, primary_contact_first_name, primary_contact_last_name } = req.body; // primary_cause = primary_cause.trim().toLowerCase(); // primary_region = primary_region.trim().toLowerCase(); let transaction; try { transaction = await db.sequelize.transaction(); const orgs = await Organization.findAll({ where: { primary_contact_email } }); if (orgs.length >= 1) { return next(errorMaker(409, `Email Exists: ${primary_contact_email}`)); } const CAUSE_QUERY = `SELECT name FROM causes WHERE name = :primary_cause`; const causes = await db.sequelize.query(CAUSE_QUERY, { replacements: { primary_cause }, type: db.Sequelize.QueryTypes.SELECT }); const REGION_QUERY = `SELECT name FROM regions WHERE name = :primary_region`; const regions = await db.sequelize.query(REGION_QUERY, { replacements: { primary_region }, type: db.Sequelize.QueryTypes.SELECT }); // cause or region not found if (!causes.length || !regions.length) { throw errorMaker(400, `No valid cause or region`); } const saltRounds = await bcrypt.genSaltSync(10); // hash with salt rounds const hashedPass = await bcrypt.hashSync(password, saltRounds); // Store hash in DB const org = await Organization.create({ id: uuidv4(), name, short_description, primary_contact_email, password: hashedPass, address, city, country, state, zip, primary_cause, primary_region, ein, estimate_asset_value, estimate_yearly_operating_cost, is_nonprofit, primary_contact_phone, primary_contact_first_name, primary_contact_last_name }); await transaction.commit(); return res.status(201).json({ message: 'Organization created', org }); } catch (error) { console.log(error); await transaction.rollback(); next(error); } }; // FETCH all organizations exports.getAllOrganizations = (req, res, next) => { Organization.findAll() .then(organizations => { res.status(200).json({ organizations, number_items: organizations.length }); }) .catch(error => next(error)); }; // FETCH depending on the given search exports.searchOrganizations = (req, res, next) => { let { search } = req.params; search = '%' + search + '%'; const limit = 10; const QUERY = `SELECT * from organizations WHERE name LIKE :search or primary_cause LIKE :search or primary_region LIKE :search LIMIT :limit`; db.sequelize .query(QUERY, { replacements: { search, limit }, type: db.Sequelize.QueryTypes.SELECT }) .then(organizations => { res.status(200).json({ organizations, number_items: organizations.length }); }) .catch(error => next(error)); };