<repo_name>marcopandolfo/He4rt-Cup<file_sep>/src/app/Dao/ChallengesDAO.js
/* eslint-disable no-underscore-dangle */
function challengeDAO(connection) {
  this._connection = connection;
}

challengeDAO.prototype.create = function create(gameId) {
  return new Promise((resolve, reject) => {
    this._connection.query('INSERT INTO challenges (game_id) VALUES (?)', [gameId], (err, result) => {
      if (err) return reject(err);

      return resolve(result);
    });
  });
};

challengeDAO.prototype.setTitle = function setTitle(gameId, title) {
  return new Promise((resolve, reject) => {
    this._connection.query('UPDATE challenges SET challenge_title = ? WHERE game_id = ?', [title, gameId], (err, result) => {
      if (err) return reject(err);

      return resolve(result);
    });
  });
};

// eslint-disable-next-line func-names
module.exports = function () {
  return challengeDAO;
};
<file_sep>/src/app/Dao/VotesDAO.js
/* eslint-disable no-underscore-dangle */
function VotesDAO(connection) {
  this._connection = connection;
}

VotesDAO.prototype.incrementVotes = function incrementVote(team, gameId) {
  return new Promise((resolve, reject) => {
    const aux = `${team}_votes`;
    this._connection.query(`UPDATE game SET ${aux} = ${aux} + 1  WHERE game_id = ?`, [gameId], (err, result) => {
      if (err) return reject(err);

      return resolve(result);
    });
  });
};

VotesDAO.prototype.getVotes = function getVotes(gameId) {
  return new Promise((resolve, reject) => {
    this._connection.query('SELECT red_votes, blue_votes from game WHERE game_id = ?', [gameId], (err, result) => {
      if (err) return reject(err);

      return resolve(result[0]);
    });
  });
};

VotesDAO.prototype.savePlayerVote = function savePlayerVote(gameId, nick, amount, team) {
  return new Promise((resolve, reject) => {
    this._connection.query('INSERT INTO votes (game_id, nick, amount, team) VALUES (?, ?, ?, ?)', [gameId, nick, amount, team], (err, result) => {
      if (err) return reject(err);

      return resolve(result);
    });
  });
};

VotesDAO.prototype.getPlayersVotes = function getPlayersVotes(gameId) {
  return new Promise((resolve, reject) => {
    this._connection.query('SELECT * FROM votes WHERE game_id = ?', [gameId], (err, result) => {
      if (err) return reject(err);

      return resolve(result);
    });
  });
};

// eslint-disable-next-line func-names
module.exports = function () {
  return VotesDAO;
};
<file_sep>/src/app/controllers/challenges.js
/* eslint-disable camelcase */
module.exports = (app) => {
  const connection = app.infra.connectionFactory();
  const challengesDao = new app.Dao.ChallengesDAO(connection);

  app.post('/challenges/title', (req, res) => {
    const { challenge_title, game_id } = req.body;

    challengesDao
      .setTitle(game_id, challenge_title)
      .then(() => res.status(200).send())
      .catch(err => res.status(400).json(err));
  });
};
<file_sep>/src/twitchService/index.js
const tmi = require('tmi.js');

const client = new tmi.Client({
  options: {
    debug: JSON.parse(process.env.npm_config_argv).original[1] === 'dev',
  },
  connection: {
    secure: true,
    reconnect: true,
  },
  identity: {
    username: 'he4rtdevs',
    password: process.env.TWITCH_TOKEN,
  },
});

client.on('connected', () => {
  console.log('> Twitch Connected');
});
client.connect();

module.exports = client;
<file_sep>/src/config/custom-express.js
const express = require('express');
const consign = require('consign');
const bodyParser = require('body-parser');
const cors = require('cors');
require('dotenv').config();

// App
const app = express();

// CORS
app.use(cors());

// BodyParser
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

// Define path
let rootPath = 'src\\app';
if (process.platform === 'linux') rootPath = 'src/app';

// Consign
consign({ cwd: rootPath })
  .include('infra')
  .then('Dao')
  .then('controllers')
  .into(app);

module.exports = app;
<file_sep>/src/server.js
const app = require('./config/custom-express');

// Port
const port = process.env.PORT || 3000;

// Auto create mysql tables
const connection = app.infra.connectionFactory();
app.infra.createTables(connection);

app.listen(port, () => {
  console.log(`> Servidor rodando na porta [${port}]`);
});
<file_sep>/README.md
<h1 align="center">
  He4rt Cup - API
</h1>

<h3 align="center">
  <img src="https://heartdevs.com/wp-content/uploads/2018/12/logo.png" width="215"><br>
    He4rt Cup API made in NodeJS
    <br>
    <br>
	<a href="https://discord.gg/J78z3FV" target="_blank">
	<img src="https://discordapp.com/api/guilds/452926217558163456/embed.png" alt="Discord server"/></a><br>
</h3>

## :rocket: 5 minutes quick start

:bulb: Install all packages of the `package.json` on your Node project. This will download everything you need.

```
npm install
```

:gear: Configure the file `.env-example` and rename to `.env`

:bulb: If you want to run this on `development` mode (recommended):

```
npm run dev
```

:bulb: Or run this on  `production` mode:

```
npm start
```
<br>

## :book: API Doc:
- Check the API <a href="https://documenter.getpostman.com/view/6227429/SVYouezy?version=latest#intro">Documentation:</a>

## :pushpin: Tips:
- Install the extensions `editorconfig` and `eslint` in your IDE for make a better code

## ✌️ Contributions

Contributions are 100% welcome, just make a PR or ISSUE :)


## :mailbox_with_mail: License

This software was created for study purposes only. Feel free to try it out.


<file_sep>/src/app/controllers/votes.js
/* eslint-disable camelcase */
/* eslint-disable object-curly-newline */
module.exports = (app) => {
  const connection = app.infra.connectionFactory();
  const votesDao = new app.Dao.VotesDAO(connection);

  // POST
  app.post('/votes', async (req, res) => {
    const { nick, team, amount, game_id } = req.body;

    // TODO: validate
    await votesDao.incrementVotes(team, game_id);
    votesDao.savePlayerVote(game_id, nick, amount, team);
    const votes = await votesDao.getVotes(game_id);
    votes.game_id = game_id;

    return res.status(201).json(votes);
  });

  // GET
  app.get('/votes/:gameId', async (req, res) => {
    const { gameId } = req.params;
    const votes = await votesDao.getVotes(gameId);

    return res.status(200).json(votes);
  });

  // GET
  app.get('/votes/players/:gameId', (req, res) => {
    const { gameId } = req.params;

    votesDao
      .getPlayersVotes(gameId)
      .then(result => res.status(200).json(result))
      .catch(err => res.status(400).json(err));
  });
};
<file_sep>/src/app/models/game.js
class Game {
  constructor(body) {
    this.timer = body.timer;
    this.state = body.state;
    this.description = body.description;
    this.blueVotes = '';
    this.redVotes = '';

    // challenges for default is none

    // Players
    this.playerCSSRed = body.player_css_red;
    this.playerCSSBlue = body.player_css_blue;

    this.playerHTMLRed = body.player_html_red;
    this.playerHTMLBlue = body.player_html_blue;

    this.playerJSRed = body.player_js_red;
    this.playerJSBlue = body.player_js_blue;
  }
}

module.exports = Game;
<file_sep>/src/app/infra/connectionFactory.js
/* eslint-disable func-names */
const mysql = require('mysql');

function createDBConnection() {
  return mysql.createConnection({
    multipleStatements: true,
    host: process.env.MYSQL_HOST,
    user: process.env.MYSQL_USER,
    password: process.env.MYSQL_PASSWORD,
    database: process.env.MYSQL_DB_NAME,
  });
}

module.exports = function () {
  return createDBConnection;
};
<file_sep>/src/app/controllers/game.js
/* eslint-disable camelcase */
const Game = require('../models/game');

module.exports = (app) => {
  const connection = app.infra.connectionFactory();
  const gameDao = new app.Dao.GameDAO(connection);
  const challengesDao = new app.Dao.ChallengesDAO(connection);


  // POST: Create new Game
  app.post('/game/create', (req, res) => {
    req.body.state = 'waiting';
    // TODO: validate

    const game = new Game(req.body);
    gameDao
      .create(game)
      .then((result) => {
        challengesDao.create(result.insertId);
        return res.status(201).json({ game_id: result.insertId });
      })
      .catch(err => res.status(400).json(err));
  });

  // PUT: Att Description
  app.put('/game/description', (req, res) => {
    const { game_id, description } = req.body;

    // TOOD: validate
    gameDao
      .updateDescription(description, game_id)
      .then(() => res.status(200).send())
      .catch(err => res.status(400).json(err));
  });

  app.put('/game/updatePlayer', (req, res) => {
    const {
      game_id,
      team, lang,
      player,
    } = req.body;

    // TOOD: validate

    gameDao
      .updatePlayer(game_id, team, lang, player)
      .then(() => res.status(200).send())
      .catch(err => res.status(400).json(err));
  });

  // GET
  app.get('/game/:gameId', (req, res) => {
    const { gameId } = req.params;

    gameDao
      .getGame(gameId)
      .then((game) => {
        console.log('[GET GAME]');
        return res.status(200).json(game);
      })
      .catch(err => res.status(400).json(err));
  });

  app.put('/game/updateState', (req, res) => {
    const { game_id, state } = req.body;

    // TOOD: validate
    gameDao
      .updateState(game_id, state)
      .then(() => res.status(200).send())
      .catch(err => res.status(400).json(err));
  });
};
<file_sep>/src/twitchService/commands/sendWhisper.js
const client = require('../index');

module.exports = (nick, msg) => {
  client.whisper(nick, msg)
    .catch(() => {
      console.log(`Não foi possivel enviar whipser para o usuario ${nick}`);
    });
};
<file_sep>/src/app/Dao/GameDAO.js
/* eslint-disable no-underscore-dangle */
function GameDAO(connection) {
  this._connection = connection;
}

GameDAO.prototype.create = function create(game) {
  return new Promise((resolve, reject) => {
    this._connection.query(`
    INSERT INTO game
    (state, player_css_blue, player_css_red, player_html_blue, player_html_red, player_js_blue, player_js_red, description, timer)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
    [game.state, game.playerCSSBlue, game.playerCSSRed,
      game.playerHTMLBlue, game.playerHTMLRed, game.playerJSBlue,
      game.playerJSRed, game.description, game.timer],
    (err, result) => {
      if (err) return reject(err);

      return resolve(result);
    });
  });
};

GameDAO.prototype.updateDescription = function updateDescription(description, gameId) {
  return new Promise((resolve, reject) => {
    this._connection.query('UPDATE game SET description = ? WHERE game_id = ?', [description, gameId], (err, result) => {
      if (err) return reject(err);

      return resolve(result);
    });
  });
};

GameDAO.prototype.updatePlayer = function updatePlayer(gameId, team, lang, player) {
  return new Promise((resolve, reject) => {
    this._connection.query(`UPDATE game SET player_${lang}_${team} = ? WHERE game_id = ?`, [player, gameId], (err, result) => {
      if (err) return reject(err);

      return resolve(result);
    });
  });
};

GameDAO.prototype.updateState = function updateState(gameId, state) {
  return new Promise((resolve, reject) => {
    this._connection.query('UPDATE game SET state = ? WHERE game_id = ?', [state, gameId], (err, result) => {
      if (err) return reject(err);

      return resolve(result);
    });
  });
};

GameDAO.prototype.getGame = function getGame(gameId) {
  return new Promise((resolve, reject) => {
    this._connection.query('SELECT * FROM game WHERE game_id = ?', [gameId], (err, result) => {
      if (err) return reject(err);

      return resolve(result[0]);
    });
  });
};

// eslint-disable-next-line func-names
module.exports = function () {
  return GameDAO;
};
