Skip to content

Commit

Permalink
Resolução de conflito no merge;
Browse files Browse the repository at this point in the history
Add: Estilo de cores e nome padrão para o Instagram;

Merge branch 'master' of https://github.com/teogenesmoura/spreadsheetsGoogle
  • Loading branch information
rodrigofegui committed Apr 4, 2018
2 parents dd1ab60 + 768ad6a commit 00068e2
Show file tree
Hide file tree
Showing 11 changed files with 486 additions and 104 deletions.
26 changes: 23 additions & 3 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,39 @@ module.exports = {
"node": true,
"browser": false,
"commonjs": true,
"jest":true,
"jest": true,
"es6": true
},
"extends": "eslint:recommended",
"extends": [
"eslint:recommended",
"airbnb-base"
],
"parserOptions": {
"sourceType": "module"
"sourceType": "module",
"ecmaVersion": 2017,
},
"rules": {
"no-console": "off",
"indent": [
"error",
"tab"
],
"no-tabs": 0,
"prefer-destructuring": 0,
"no-param-reassign": 0,
"no-use-before-define": 0,
"object-shorthand": 0,
"arrow-body-style": [
1,
"always"
],
"space-before-function-paren": [
2,
{
"anonymous": "always",
"named": "never"
}
],
"linebreak-style": [
"error",
"unix"
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
.DS_Store
/node_modules
credentials.json
credentials.json
controllers/*.png
yarn-error.log
logs/
23 changes: 7 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,26 +99,18 @@ npm test

## Guia de estilo

O código conta com duas camadas de estilo: A provida pelo comando
*"use strict"* do próprio Javascript e a biblioteca [Eslint](https://eslint.org/), com as configurações presentes no arquivo *".eslintrc.js"* para manter boas práticas de programação.
O código conta com a biblioteca [Eslint](https://eslint.org/), com as configurações presentes no arquivo *".eslintrc.js"* para manter boas práticas de programação, extendidas do [Guia de Estilo para Javascript da Airbnb](https://github.com/airbnb/javascript) com algumas mudanças de acordo com as necessidades do nosso projeto.

Para executar o eslint, instale globalmente a biblioteca com:
Para executar o linter:

```shell
npm install eslint --save-dev
npm run lint
```
É sempre bom usar um plugin no seu editor de texto para ter um feedback em tempo real do código que você escreve, evitando perder tempo reescrevendo muitos trechos de código. No caso do Visual Studio Code, o próprio ESLint oferece um plugin.

Então, execute o linter com o seguinte comando:
## Hooks

```shell
eslint controllers/spreadsheets.js
```

Este comando analisará somente o arquivo *"controllers/spreadsheet.js"*. Para analisar toda a pasta, use o seguinte comando:

```shell
eslint ./
```
Este projeto conta com apenas um hook de pré-commit, isso significa o comando `npm run lint && npm run test` é executado antes de todo commit feito, garantindo que nenhum commit seja realizado com código mal-estilizado ou com testes falhando.

## Documentação

Expand Down Expand Up @@ -153,14 +145,13 @@ Este é apenas um esqueleto de projeto para que o grupo comece a trabalhar. Rest
* Implementar mais casos de teste unitário
* Implementar testes de comportamento (BDD)
* Gerar mais de um gráfico
* Incluir mecanismo de logging
* Expandir quantidade dos dados utilizados
* Pesar o custo de gerar gráficos server-side e verificar se vale a pena fazê-lo no cliente
* Implementar mecanismo para automatização da coleta recorrente dos dados
* Persistir dados coletados em base estruturada
* Disponibilizar uma API publica para que leigos possam gerar visualizações interessantes
* Adicionar mais regras ao Linter para aumentar a qualidade da padronização de código
* Google Spreadsheets vs MongoDB?
* Ignorar os docs no repositório já que eles são gerados automaticamente? Discutir

## Licença

Expand Down
56 changes: 56 additions & 0 deletions config/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
const winston = require("winston");
const fs = require("fs");

const format = winston.format;
const { combine, printf } = format;

// Create the logs directory if it does not exist
const logDir = "logs";
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir);
}

const customLevels = {
levels: {
trace: 4,
info: 3,
warn: 2,
error: 1,
critical: 0,
},
colors: {
trace: "gray",
info: "green",
warn: "yello",
error: "red",
critical: "purple",
},
};

const tsLvlMsgFormat = printf((info) => {
return `[${info.timestamp}] - [${info.level}] - ${info.message}`;
});

winston.addColors(customLevels.colors);

const logger = winston.createLogger({
level: "info",
format: combine(
winston.format.timestamp({
format: "YYYY-MM-DD HH:mm:ss",
}),
tsLvlMsgFormat,
),
transports: [
//
// - Write to all logs with level `info` and below to `combined.log`
// - Write all logs error (and below) to `error.log`.
//
new winston.transports.Console({ level: "info" }),
new winston.transports.File({ filename: "logs/error.log", level: "error" }),
new winston.transports.File({ filename: "logs/combined.log" }),
],
levels: customLevels.levels,
});

module.exports = logger;
Binary file modified controllers/frentePopularInstagram_Rod.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
117 changes: 56 additions & 61 deletions controllers/spreadsheets.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
"use strict";
const {google} = require("googleapis");
const { google } = require("googleapis");
const ChartjsNode = require("chartjs-node");
const instagram = require("../templates/instagram");
const logger = require("../config/logger");

const fileName = "frentePopularInstagram_Rod.png";
const pathOfFile = __dirname + "/" + fileName;
const pathOfFile = `${__dirname}/${fileName}`;
const chartSize = 600;
const tweetsRow = 8,
seguindoRow = 9,
seguidoresRow = 10,
curtidasRow = 11;
const tweetsRow = 8;
const seguindoRow = 9;
const seguidoresRow = 10;
const curtidasRow = 11;


/**
* Contacts the Google API and generates a token. Returns the path of the
* Contacts the Google API and generates a token. Returns the path of the
* chart generated on disk and calls the res object to send the image
* to the browser.
* @param {object} client - client object for authentication with Google
Expand All @@ -21,46 +22,55 @@ const tweetsRow = 8,
* @returns {String} pathOfFile - path of the chart generated on disk
* @returns {File} outputFile - Promise containing resized image or error
*/
let authenticate = (client,req,res) => {
const authenticate = (client, req, res) => {
if (req.query.code === undefined) {
logger.error("Undefined auth code");
return res.status(500).send("No code query parameter");
}
const code = req.query.code;
client.getToken(code, (err, tokens) => {

return client.getToken(code, async (err, tokens) => {
if (err) {
console.error("Error getting oAuth tokens:");
throw err;
logger.error(`Error getting oAuth tokens: ${err}`);
return res.status(500).send("Error");
}
client.credentials = tokens;
listCollectives(client)
.then(collectives => {
return generateCharts(collectives);
})
.then(() => {
res.sendFile(pathOfFile);
return pathOfFile;
});

try {
const collectives = await listCollectives(client);
await generateCharts(collectives);
res.sendFile(pathOfFile);
return pathOfFile;
} catch (e) {
logger.error(e);
return res.status(500).send("Error");
}
});
};

/**
* Returns data from a given spreadsheeet in JSON format
* @params {object} auth - auth object generated by Google authentication
* @param {object} auth - auth object generated by Google authentication
* @returns {Promise} collectivesPromise - Promise object that resolves when rows of Google
* Spreadsheet's data are collected and fails when the API returns an error
* Spreadsheet's data are collected and fails when the API returns an error
*/
let listCollectives = (auth) => {
const collectivesPromise = new Promise(function(resolve, reject){

const listCollectives = (auth) => {
const collectivesPromise = new Promise((resolve, reject) => {
const sheets = google.sheets("v4");
sheets.spreadsheets.values.get({
auth: auth,
spreadsheetId: "1W4kmkNTZrDUHyZx_siToEr9EDZvTGEwDTp05I18Ach4",
range: "A:S"
range: "A:S",
}, (err, res) => {
if (err) {
console.error("The API returned an error.");
logger.error("The API returned an error.");
reject(err);
}
const rows = res.data.values;
if (rows.length === 0) {
console.warn("No data found.");
logger.error("No data found.");
reject(rows);
} else {
resolve(rows);
}
Expand All @@ -70,24 +80,25 @@ let listCollectives = (auth) => {
};

/**
* Generates a Pie chart from data collected from the Spreadsheets API.
* Generates a Pie chart from data collected from the Spreadsheets API.
* This example refers to the "Movimento Frente Popular" row in the spreadsheet,
* and plots the "Tweets","Seguindo","Seguidores" and "Curtidas" column for that
* organization.
* @params {object} collectives - JSON object that contains information for social movements
* @returns {Promise} Promise object that resolves when
* the chart's image file is written to disk data are collected and fails when
* @param {object} collectives - JSON object that contains information for social movements
* @returns {Promise} Promise object that resolves when
* the chart's image file is written to disk data are collected and fails when
* chartJSNode fails to do so.
*/
let generateCharts = (collectives) => {
console.log(JSON.stringify(collectives));

const generateCharts = async (collectives) => {
logger.trace("Generating graph from collectives");
const chartNode = new ChartjsNode(chartSize, chartSize);
/* In sequence: Tweets, Seguindo, Seguidores, Curtidas */
const data = [
collectives[2][tweetsRow],
collectives[2][seguidoresRow],
collectives[2][seguidoresRow],
collectives[2][curtidasRow]
collectives[2][curtidasRow],
];
/* INSTAGRAM */
const label = collectives[0][instagram.label];
Expand All @@ -98,7 +109,7 @@ let generateCharts = (collectives) => {
collectives[1][curtidasRow], // Curtidas
];
const config = {
type: "pie", //"doughnut", //"pie",
type: "pie", // "doughnut"
data: {
datasets: [{
data: data,
Expand All @@ -107,40 +118,24 @@ let generateCharts = (collectives) => {
instagram.purpleViolet,
instagram.orange,
instagram.redOrange],
label: label
label: instagram.label,

}],
labels: labels
labels: labels,
},
options: {
responsive: true,
legend: {position: "bottom"},
cutoutPercentage: 25,
title: {
display: true,
text: instagram.label
}
}
text: instagram.label,
},
},
};
return chartNode.drawChart(config)
.then(() => {
// chart is created
// get image as png buffer
return chartNode.getImageBuffer("image/png");
})
.then(buffer => {
Array.isArray(buffer); // => true
// as a stream
return chartNode.getImageStream("image/png");
})
.then(streamResult => {
// using the length property you can do things like
// directly upload the image to s3 by using the
// stream and length properties
streamResult.stream; // => Stream object
streamResult.length; // => Integer length of stream
// write to a file
return chartNode.writeImageToFile("image/png", pathOfFile);
});
await chartNode.drawChart(config);
return chartNode.writeImageToFile("image/png", pathOfFile);
};

module.exports = {generateCharts, authenticate, fileName};
module.exports = {generateCharts, authenticate, fileName};

Loading

0 comments on commit 00068e2

Please sign in to comment.