Skip to content

Commit

Permalink
feat: fetch data from Github API + cache
Browse files Browse the repository at this point in the history
  • Loading branch information
oleksiikhr committed May 26, 2019
1 parent cc66d56 commit 14ac2e5
Show file tree
Hide file tree
Showing 9 changed files with 432 additions and 86 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -2,3 +2,4 @@
node_modules/
config.js
dist/
cache/
60 changes: 60 additions & 0 deletions config.example.js
@@ -0,0 +1,60 @@
/* eslint-disable */
'use strict'

module.exports = {

/**
* The value is the name of the folder, all templates
* you can find by the current path:
* ./src/templates
* You can also create your own template, which is
* described in this file:
* README.md
* @var {string}
* @default default
*/
template: 'default',

/**
* Set your login from github, after the build we will receive
* data from this profile (name, projects, etc.)
* @var {string}
* @example
* You can find the login from the address bar, for example:
* https://github.com/alexeykhr
* The value will be:
* alexeykhr
*/
username: 'nwtgck',

/**
* Various configurations are stored that will filter
* the received data with the Github API.
* @var {Object}
*/
parseGithub: {

/**
* @see https://developer.github.com/v3/repos/#list-user-repositories docs
*/
repositories: {
/**
* @var {string} - all, owner, member
* @default owner
*/
type: 'owner',

/**
* @var {string} - created, updated, pushed, full_name
* @default full_name
*/
sort: 'full_name',

/**
* @var {string} - asc, desc
* @default asc when using full_name, otherwise desc
*/
direction: 'asc'
}
}
}
12 changes: 11 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 11 additions & 7 deletions package.json
@@ -1,35 +1,39 @@
{
"name": "wportfolio",
"name": "gportfolio",
"version": "1.0.0",
"description": "Creating a portfolio based on github profile",
"description": "Creating an automatic portfolio based on Github profile",
"scripts": {
"dev": "webpack-dev-server --watch",
"build": "webpack --mode production",
"lint": "eslint --ext .js src --fix"
},
"repository": {
"type": "git",
"url": "git+https://github.com/WPortfolio/WPortfolio.git"
"url": "git+https://github.com/GPortfolio/GPortfolio.git"
},
"keywords": [
"wportfolio",
"github-portfolio",
"gitportfolio",
"gportfolio",
"portfolio",
"github",
"git",
"projects",
"cv",
"resume"
"resume",
"open-source"
],
"author": "Alexey Khrushch, alexeykhr@outlook.com",
"license": "MIT",
"bugs": {
"url": "https://github.com/WPortfolio/WPortfolio/issues"
"url": "https://github.com/GPortfolio/GPortfolio/issues"
},
"homepage": "https://github.com/WPortfolio/WPortfolio#readme",
"homepage": "https://github.com/GPortfolio/GPortfolio#readme",
"dependencies": {},
"devDependencies": {
"@babel/core": "^7.4.4",
"@babel/preset-env": "^7.4.4",
"axios": "^0.18.0",
"babel-eslint": "^10.0.1",
"babel-loader": "^8.0.6",
"clean-webpack-plugin": "^2.0.2",
Expand Down
64 changes: 64 additions & 0 deletions utils/jsonHelper.js
@@ -0,0 +1,64 @@
'use strict'

const path = require('path')
const fs = require('fs')

/** @type {string} */
const BASE_PATH = path.resolve(__dirname, '../cache') + '/'

/**
* Create cache folder if not exists
*/
if (!fs.existsSync(BASE_PATH)) {
try {
console.log('Create cache folder')
fs.mkdirSync(BASE_PATH)
} catch (e) {
console.warn(e)
}
}

module.exports = {

/**
* Get data from .json file if exists
* @param {string} fileName - path in <root>/data folder (ext is required)
* @return {{}}
*/
tryReadJsonFile(fileName) {
const path = BASE_PATH + fileName

if (!fs.existsSync(path)) {
return {}
}

const data = fs.readFileSync(path, { encoding: 'UTF-8' })

try {
return JSON.parse(data)
} catch (e) {
console.warn(e)
return {}
}
},

/**
* Set data to .json file
* @param {string} fileName - path in <root>/data folder (ext is required)
* @param {object} data
*/
writeJsonFile(fileName, data) {
const path = BASE_PATH + fileName

fs.writeFileSync(path, JSON.stringify(data))
},

/**
* Check if .json file exists
* @param {string} fileName - path in <root>/data folder (ext is required)
* @return {boolean}
*/
existsJsonFile(fileName) {
return fs.existsSync(BASE_PATH + fileName)
}
}
68 changes: 68 additions & 0 deletions utils/parseProfile.js
@@ -0,0 +1,68 @@
'use strict'

const jsonHelper = require('./jsonHelper')
const variables = require('./variables')
const config = require('../config')
const axios = require('axios')

/**
* Waiting before the next request to the API.
* 1 hour
* @type {number} - milliseconds
*/
const TIME_WAIT = 1000 * 60 * 60

/**
* How to save in timestamp
* @type {string}
*/
const CACHE_NAME = 'profile'

/**
* @return {Promise<?object>}
* null - failed
* {} - success
*/
module.exports = async () => {

const timestamp = jsonHelper.tryReadJsonFile(variables.FILE_TIMESTAMP_JSON)
const profileFileExists = jsonHelper.existsJsonFile(variables.FILE_PROFILE_JSON)
const canRepeatRequestByTimestamp = (+timestamp[CACHE_NAME] || 0) + TIME_WAIT <= Date.now()

/** @type {?object} - data from API */
let githubUser = null

if (canRepeatRequestByTimestamp || !profileFileExists) {

/**
* Make a Github API request to get user data.
* @see https://developer.github.com/v3/users/#get-a-single-user docs
*/
try {
console.log(`[Profile] Fetching data from api.. | ${config.username} username`)
const fetchGithubData = await axios(`${variables.API_GITHUB}/users/${config.username}`)
githubUser = fetchGithubData.data
console.log(`[Profile] Complete, ${githubUser.name}`)
} catch (e) {
console.warn(`[Profile]: ${e}`)
return null
}

/*
* Update cache
*/
jsonHelper.writeJsonFile(variables.FILE_PROFILE_JSON, githubUser)

/*
* Update timestamp
*/
jsonHelper.writeJsonFile(variables.FILE_TIMESTAMP_JSON,
Object.assign({}, timestamp, { [CACHE_NAME]: Date.now() })
)
} else {
githubUser = jsonHelper.tryReadJsonFile(variables.FILE_PROFILE_JSON)
console.log(`[Profile] Get profile from cache, ${githubUser.name}`)
}

return githubUser
}
81 changes: 81 additions & 0 deletions utils/parseRepositories.js
@@ -0,0 +1,81 @@
'use strict'

const jsonHelper = require('./jsonHelper')
const variables = require('./variables')
const config = require('../config')
const axios = require('axios')

/**
* Waiting before the next request to the API.
* 2 hours
* @type {number} - milliseconds
*/
const TIME_WAIT = 1000 * 60 * 60 * 2

/**
* How to save in timestamp
* @type {string}
*/
const CACHE_NAME = 'repositories'

/**
* @return {Promise<?array>}
* null - failed
* [] - success
*/
module.exports = async () => {

const timestamp = jsonHelper.tryReadJsonFile(variables.FILE_TIMESTAMP_JSON)
const repositoriesFileExists = jsonHelper.existsJsonFile(variables.FILE_REPOSITORIES_JSON)
const canRepeatRequestByTimestamp = (+timestamp[CACHE_NAME] || 0) + TIME_WAIT <= Date.now()

/** @type {array} - data from API */
let repositories = []

if (canRepeatRequestByTimestamp || !repositoriesFileExists) {

/**
* Make a Github API request to get user repositories.
* @see https://developer.github.com/v3/repos/#list-user-repositories docs
*/
try {
let fetchRepositories
let page = 1

do {
console.log(`[Repositories] Fetching data from API.. | ${page} page`)
fetchRepositories = await axios(`${variables.API_GITHUB}/users/${config.username}/repos`, {
params: {
...config.parseGithub.repositories,
per_page: 100,
page: page++
}
})
repositories.push(...fetchRepositories.data)

} while (fetchRepositories.data.length === 100)

console.log(`[Repositories] Complete, ${repositories.length} length`)
} catch (e) {
console.warn(`[Repositories]: ${e}`)
return null
}

/*
* Update repositories cache
*/
jsonHelper.writeJsonFile(variables.FILE_REPOSITORIES_JSON, repositories)

/*
* Update timestamp cache
*/
jsonHelper.writeJsonFile(variables.FILE_TIMESTAMP_JSON,
Object.assign({}, timestamp, { [CACHE_NAME]: Date.now() })
)
} else {
repositories = jsonHelper.tryReadJsonFile(variables.FILE_REPOSITORIES_JSON)
console.log(`[Repositories] Get repositories from cache, ${repositories.length} length`)
}

return Array.isArray(repositories) ? repositories : null
}
17 changes: 17 additions & 0 deletions utils/variables.js
@@ -0,0 +1,17 @@
'use strict'

module.exports = {

/**
* @var {string}
*/
API_GITHUB: 'https://api.github.com',

/**
* Files in <root>/data folder
* @var {string}
*/
FILE_PROFILE_JSON: 'profile.json',
FILE_TIMESTAMP_JSON: 'timestamp.json',
FILE_REPOSITORIES_JSON: 'repositories.json'
}

0 comments on commit 14ac2e5

Please sign in to comment.