Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added git services, db caching and front end API changes #57

Open
wants to merge 12 commits into
base: v2
Choose a base branch
from
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"no-console": "off",
"func-names": "off",
"no-alert": "off",
"prefer-const": "off"
"prefer-const": ["error", {"destructuring": "all"}],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really sure about this change, any specific reason for this update?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added that to warn us if let is used and we never resigned that variable.... {"destructuring": "all"} because of the following....

/*eslint prefer-const: ["error", {"destructuring": "all"}]*/
/*eslint-env es6*/

// 'b' is never reassigned, but all of `a` and `b` should not be const, so those are ignored.
let {a, b} = obj;
a = a + 1;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should avoid this, if we mutate our data some weird bugs may arise.

"no-underscore-dangle": ["error", { "allow": ["_json"] }]
}
}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
.vscode
config/.dev.env
config/.dev.env
filelog-debug.log
22 changes: 22 additions & 0 deletions config/winston.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const winston = require('winston');

const tsFormat = () => (new Date()).toLocaleTimeString();

const logger = new (winston.Logger)({
transports: [
// colorize the output to the console
new (winston.transports.Console)({
timestamp: tsFormat,
colorize: true,
}),
new (winston.transports.File)({
name: 'debug-file',
filename: 'filelog-debug.log',
level: 'debug',
}),
],
});

logger.level = 'info';

module.exports.logger = logger;
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
"express-session": "^1.15.3",
"mongodb": "^2.2.27",
"mongoose": "^4.10.4",
"mongoose-paginate": "^5.0.3",
"passport": "^0.3.2",
"passport-github2": "^0.1.10"
"passport-github2": "^0.1.10",
"request": "^2.81.0",
"winston": "^2.3.1"
}
}
3 changes: 2 additions & 1 deletion public/js/languageSelection.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const ANY_LANGUAGE = 'Any';
const NO_LANGUAGE = 'NoLanguage';
const MAX_PROJECTPERPAGE = 10;
let languageSelected = ANY_LANGUAGE;

const generateLanguageSelector = function generateLanguageSelector() {
Expand Down Expand Up @@ -42,7 +43,7 @@ const selectLanguage = function selectLanguage(event) {
languageSelected = event.target.value;
content.innerHTML = '';
reqNo = Math.floor(Math.random() * 3) + 1;
projectsPerPage = (languageSelected == ANY_LANGUAGE) ? 2 : 100;
projectsPerPage = (languageSelected == ANY_LANGUAGE) ? 2 : MAX_PROJECTPERPAGE;
getData();
};

Expand Down
18 changes: 13 additions & 5 deletions public/js/main.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const MIN_PROJECTS_PER_CALL = 5;
const MAX_PROJECTS_PER_USER = 2;
const MAXAPICALL = 10;
const CONTENT = document.getElementById('content');
const EMOJI = new EmojiConvertor();
let projectsCurrentCall = 0;
Expand All @@ -17,8 +18,12 @@ const moreDataNeeded = function moreDataNeeded() {
return ((allUsersChecked()) && (projectsCurrentCall < MIN_PROJECTS_PER_CALL));
};

const userFormatter = function userFormatter(username) {
return `<a href='https://github.com/${username}?tab=stars'>${username}</a>`;
const userFormatter = function userFormatter(usernames) {
let usernameStr = '';
for (username of usernames) {
usernameStr += `<a href='https://github.com/${username}?tab=stars'>${username}</a>, `;
}
return usernameStr.slice(0, -2);
};

const nFormatter = function nFormatter(num) {
Expand All @@ -40,9 +45,9 @@ const dataCollector = function dataCollector(response, username) {
let innerContent = `<li><span class='link'><a href='${entry.html_url}' target='_blank'>${entry.name}<span> - ${String(entry.description)}</span><br/></a></span>`;
innerContent += "<div class='additional'>";
innerContent += `${nFormatter(entry.stargazers_count)} <i class='fa fa-star'></i>`;
innerContent += `&emsp;${nFormatter(entry.forks)} <i class='fa fa-code-fork'></i>`;
innerContent += `&emsp;${nFormatter(entry.forks_count)} <i class='fa fa-code-fork'></i>`;
innerContent += (entry.language != null) ? `&emsp;${entry.language}` : '';
innerContent += `&emsp;(from ${userFormatter(username)})`;
innerContent += `&emsp;(from ${userFormatter(entry.stargazersLogin)})`;
innerContent += '</div></li>';
innerContent = EMOJI.replace_unified(innerContent);
CONTENT.innerHTML += EMOJI.replace_colons(innerContent);
Expand All @@ -63,8 +68,11 @@ const getData = function getData() {
usersCurrentCall = 0;
callInProgress = true;
reqNo += 1;
if (reqNo > MAXAPICALL) {
return console.log('rejecting request', reqNo);
}
USERNAMES.forEach((username) => {
const url = `https://api.github.com/users/${username}/starred?per_page=${projectsPerPage}&access_token=${accessToken}&page=${reqNo}`;
const url = `http://localhost:3000/api/repos/v1/search?stargazer=${username}&language=${languageSelected}&per_page=${projectsPerPage}&page=${reqNo}`;
axios({
url,
method: 'get',
Expand Down
6 changes: 4 additions & 2 deletions server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ require('./../config/config');
const express = require('express');
const session = require('express-session');
const { mongoose } = require('./db/mongoose');
const { usernameRoutes } = require('./routes/api/username');
const { stargazersRoutes } = require('./routes/api/stargazers');
const { reposRoutes } = require('./routes/api/repos');
const { userRoutes } = require('./routes/user');
const { passport } = require('./auth');

Expand All @@ -19,7 +20,8 @@ app.use(passport.session());
app.use(express.static(`${__dirname}/../public`));

app.use('/user',userRoutes);
app.use('/api/username', usernameRoutes);
app.use('/api/stargazers', stargazersRoutes);
app.use('/api/repos', reposRoutes);

app.listen(port, () => {
console.log(`Starting server on port ${port}.`);
Expand Down
2 changes: 1 addition & 1 deletion server/db/mongoose.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
let mongoose = require('mongoose');
const mongoose = require('mongoose');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯


mongoose.Promise = global.Promise;

Expand Down
40 changes: 38 additions & 2 deletions server/db/repositories.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// Repositories
const mongoose = require('./mongoose');
const mongoosePaginate = require('mongoose-paginate');

const Schema = mongoose.Schema;

const repositorySchema = new Schema({
_id: mongoose.Schema.Types.ObjectId,
githubId: Number,
name: String,
html_url: String,
description: String,
Expand All @@ -13,8 +14,43 @@ const repositorySchema = new Schema({
created_at: Date,
updated_at: Date,
language: String,
});
stargazersLogin: [String],
}, {
timestamps: {
updatedAt: 'recordUpdated_at',
createdAt: 'recordCreated_at',
} });

repositorySchema.statics.updateRepoWithStargazer = function (repo, stargazer) {
const Repository = this;

return new Promise((resolve, reject) => {
Repository.findOne({ githubId: repo.githubId })
.then((repository) => {
if (repository) {
if (repository.stargazersLogin.indexOf(stargazer) === -1) {
repository.stargazersLogin.push(stargazer);
}
repository = Object.assign({}, repository, repo);
repository.save((error, doc) => {
if (error) throw error;
// console.log(`Updated: ${repo.name} from: ${stargazer}`);
});
} else {
repository = new Repository(repo);
repository.stargazersLogin.push(stargazer);
repository.save((error, doc) => {
if (error) throw error;
// console.log(`Added: ${repo.name} from: ${stargazer}`);
});
}
resolve(repository);
})
.catch(e => reject(e));
});
};

repositorySchema.plugin(mongoosePaginate);

const Repository = mongoose.model('Repository', repositorySchema);

Expand Down
25 changes: 25 additions & 0 deletions server/db/stargazers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Schema of stargazers in Github
const mongoose = require('./mongoose');

const Schema = mongoose.Schema;

const stargazersSchema = new Schema({
githubId: Number,
login: String,
name: String,
html_url: String,
location: String,
bio: String,
public_repos: Number,
public_gists: Number,
followers: Number,
}, {
timestamps: {
updatedAt: 'recordUpdated_at',
createdAt: 'recordCreated_at',
} });


const Stargazers = mongoose.model('Stargazers', stargazersSchema);

module.exports.Stargazers = Stargazers;
4 changes: 4 additions & 0 deletions server/db/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ userSchema.statics.findOrCreate = function (profile, accessToken) {
if (user) {
// TODO:Need to update accessToken for this user
user.accessToken = accessToken;
user.save((err) => {
if (err) return handleError(err);
// saved!
});
return Promise.resolve(user);
}
// Create new user
Expand Down
24 changes: 0 additions & 24 deletions server/db/username.js

This file was deleted.

90 changes: 90 additions & 0 deletions server/gitUtility/gitService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const request = require('request');
const { logger } = require('./../../config/winston');

const gitService = {

getUserDetails(login, token) {
if (token) {
headers = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see where headers is defined? Am I missing something here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added header definition now...

'User-Agent': 'request',
Authorization: `token ${token}`,
};
} else {
headers = {
'User-Agent': 'request',
};
}
const options = {
url: `https://api.github.com/users/${login}`,
headers,
};
return new Promise((resolve, reject) => {
logger.info('Calling api.github.com/users/user', { login });
request(options, (error, response, body) => {
if (!error && response.statusCode === 200) {
const user = JSON.parse(body);
const stargazer = {
githubId: user.id,
login: user.login,
name: user.name,
html_url: user.html_url,
location: user.location,
bio: user.bio,
public_repos: user.public_repos,
public_gists: user.public_gists,
followers: user.followers,
};
resolve(stargazer);
} else {
logger.warn('Error api.github.com/users/user', { Error: response.body });
reject(response.body);
}
});
});
},

getStarredRepository(login, token, page = 1) {
let headers;
if (token) {
headers = {
'User-Agent': 'request',
Authorization: `token ${token}`,
};
} else {
headers = {
'User-Agent': 'request',
};
}
const options = {
url: `https://api.github.com/users/${login}/starred?per_page=100&page=${page}`,
headers,
};
return new Promise((resolve, reject) => {
logger.info('Calling api.github.com/users/login/starred', { login, page });
request(options, (error, response, body) => {
if (!error && response.statusCode === 200) {
const repos = JSON.parse(body);
// Only select required info from data received.
const filterRepos = repos.map(repo => ({
githubId: repo.id,
name: repo.name,
html_url: repo.html_url,
description: repo.description,
stargazers_count: repo.stargazers_count,
forks_count: repo.forks_count,
created_at: repo.created_at,
updated_at: repo.updated_at,
language: repo.language,
}));
logger.debug('Data Received:', { login, length: filterRepos.length, currentPage: page });
resolve(filterRepos);
} else {
logger.warn('Error api.github.com/users/login/starred', { err: response.body });
reject(response.body);
}
});
});
},
};

module.exports.gitService = gitService;
Loading