Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions admin/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ <h3>General</h3>
<input type="text" class="set-interval" placeholder="6"/> <span style="margin-left:5px;color:#333333;">second(s)</span>
<div class="set-interval-button button">Set</div>
</div>
<div>
<span style="color:#333333; font-weight: 600;">Spam Penalty Threshold: </span>
<input type="number" class="set-spam-penalty" min="0" placeholder="0"/>
<span style="margin-left:5px;color:#333333;">open PRs/issues (0 = disabled)</span>
<div class="set-spam-penalty-button button">Set</div>
</div>
</div>
<div class="contributors">
<h3>Contributors Management</h3>
Expand Down
33 changes: 33 additions & 0 deletions admin/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@ submit.addEventListener('click', () => {
const table = document.querySelector('.contributors-list')
const totalTd = document.querySelector('td.total')
const startDateInput = document.querySelector('.set-start-date')
const spamPenaltyInput = document.querySelector('.set-spam-penalty')

loginPanel.classList.add('hide') // hide loading animation
configPanel.classList.remove('hide')
intervalInput.setAttribute('placeholder', delay)
startDateInput.setAttribute('value', startDate)
spamPenaltyInput.setAttribute('placeholder', res.data.spamPenaltyThreshold || 0)

contributors = sortByAlphabet(contributors, 'username')

Expand Down Expand Up @@ -182,6 +184,37 @@ submit.addEventListener('click', () => {
})
})

// Set spam penalty threshold
const setSpamPenaltyButton = document.querySelector('.set-spam-penalty-button.button')
setSpamPenaltyButton.addEventListener('click', () => {
const threshold = document.querySelector('.set-spam-penalty').value

if (threshold === '') {
msgError('your input is empty')
return
}

if (parseInt(threshold) < 0) {
msgError('Threshold cannot be negative')
return
}

axios.post('/api/setSpamPenaltyThreshold', {
token: password,
spamPenaltyThreshold: threshold
}).then( res => {
const { message } = res.data

if (message === 'Success') {
mgsSuccess('Spam penalty threshold updated!')
spamPenaltyInput.value = ''
spamPenaltyInput.setAttribute('placeholder', threshold)
} else {
msgError('Unexpected error')
}
})
})

// Set interval value
const setIntervalButton = document.querySelector('.set-interval-button.button')
setIntervalButton.addEventListener('click', () => {
Expand Down
21 changes: 16 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import axios from 'axios'
import moment from 'moment'
import { io } from 'socket.io-client'

let spamPenaltyThreshold = 0

function refreshTable(newData) {
const table = document.querySelector('table')
const data = newData
Expand All @@ -24,6 +26,15 @@ function refreshTable(newData) {
totalEm.innerText = 'Total: ' + totalNumbers

contributors = contributors.sort((a, b) => {
if (spamPenaltyThreshold > 0) {
const aPenalized = a.openPRsNumber >= spamPenaltyThreshold || a.issuesNumber >= spamPenaltyThreshold
const bPenalized = b.openPRsNumber >= spamPenaltyThreshold || b.issuesNumber >= spamPenaltyThreshold
const aTopTier = !aPenalized && a.mergedPRsNumber > 0
const bTopTier = !bPenalized && b.mergedPRsNumber > 0
if (aTopTier && !bTopTier) return -1
if (!aTopTier && bTopTier) return 1
}

var pref1, pref2, pref3 // preference is specified here
const queryString = window.location.search
const urlParams = new URLSearchParams(queryString)
Expand Down Expand Up @@ -145,18 +156,18 @@ function refreshTable(newData) {
allContributionsInfoRef.innerText = allMergedPRs + ' Merged PRs, ' + allOpenPRs + ' Open PRs, and ' + allIssues + ' Issues.'
}

axios.get('/api/data')
.then(res => {
refreshTable(res.data)
})

axios.get('/api/config')
.then(res => {
const { organization, organizationGithubUrl, organizationHomepage } = res.data
spamPenaltyThreshold = res.data.spamPenaltyThreshold || 0
const footer = document.querySelector('.footer .text-muted')
footer.innerHTML = `
<a href="${organizationHomepage}" target="_blank" rel="noopener noreferrer">${organizationHomepage}</a> |
<a href="${organizationGithubUrl}" target="_blank" rel="noopener noreferrer">Github(${organization})</a>`.trim()
return axios.get('/api/data')
})
.then(res => {
refreshTable(res.data)
})

axios.get('/api/log')
Expand Down
29 changes: 27 additions & 2 deletions src/server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ const server = http
organization: organization,
organizationHomepage: organizationHomepage,
organizationGithubUrl: organizationGithubUrl,
spamPenaltyThreshold: parseInt(jsonfile.readFileSync(configPath).spamPenaltyThreshold) || 0,
})
)
break
Expand Down Expand Up @@ -137,6 +138,7 @@ const server = http
delay,
contributors: contributorsList,
startDate,
spamPenaltyThreshold: parseInt(jsonfile.readFileSync(configPath).spamPenaltyThreshold) || 0,
})
) // success
jsonfile.writeFileSync(admindataPath, contributorsList)
Expand Down Expand Up @@ -238,6 +240,27 @@ const server = http
}
})
break
case '/setSpamPenaltyThreshold':
if (req.method === 'GET') {
res.end('Permission denied\n')
return
}

Util.post(req, (params) => {
const { token, spamPenaltyThreshold } = params

if (token !== adminPassword) {
res.end(JSON.stringify({ message: 'Authentication failed' }))
} else {
const Config = jsonfile.readFileSync(configPath)
Config.spamPenaltyThreshold = parseInt(spamPenaltyThreshold) || 0
jsonfile.writeFileSync(configPath, Config, { spaces: 2 })
jsonfile.writeFileSync(configBackupPath, Config, { spaces: 2 })

res.end(JSON.stringify({ message: 'Success' }))
}
})
break
case '/remove':
if (req.method === 'GET') {
res.end('Permission denied\n')
Expand Down Expand Up @@ -350,10 +373,11 @@ const server = http
jsonfile.readFile(dataPath, async (err, obj) => {
if (err) console.log('[ERROR]' + err)
const query = url.parse(req.url, true).query
const Config = jsonfile.readFileSync(configPath)

// Gets list of contributors sorted by parameter if provided
// else defaults to sorting by mergedprs
const contributors = await API.getRanks(obj, query.parameter)
const contributors = await API.getRanks(obj, query.parameter, Config.spamPenaltyThreshold)

// Responds with rank of username
if (query.username) {
Expand Down Expand Up @@ -400,7 +424,8 @@ const server = http
} else if (query.rank) {
// Gets list of contributors sorted by parameter if provided
// else defaults to sorting by mergedprs
const contributors = await API.getRanks(obj, query.parameter)
const Config = jsonfile.readFileSync(configPath)
const contributors = await API.getRanks(obj, query.parameter, Config.spamPenaltyThreshold)
res.end(JSON.stringify(obj[contributors[query.rank - 1]]))
} else {
res.end(JSON.stringify(obj))
Expand Down
1 change: 1 addition & 0 deletions src/server/config-example.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@
"abdelazeem777\t"
],
"startDate": "1970-01-15",
"spamPenaltyThreshold": 10,
"includedRepositories": [
"Rocket.Chat",
"Opensource-Contribution-Leaderboard",
Expand Down
13 changes: 12 additions & 1 deletion src/server/util/API.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ async function getStats(data) {
}
}

async function getRanks(data, parameter = 'mergedprs') {
async function getRanks(data, parameter = 'mergedprs', spamPenaltyThreshold = 0) {
var pref1, pref2, pref3 // preference is specified here
switch (
parameter //assigns according to parameter-sort (default 'mergedprs')
Expand All @@ -209,8 +209,19 @@ async function getRanks(data, parameter = 'mergedprs') {
break
}

const threshold = parseInt(spamPenaltyThreshold) || 0

const contributors = Object.keys(data)
return contributors.sort((a, b) => {
if (threshold > 0) {
const aPenalized = data[a].openPRsNumber >= threshold || data[a].issuesNumber >= threshold
const bPenalized = data[b].openPRsNumber >= threshold || data[b].issuesNumber >= threshold
const aTopTier = !aPenalized && data[a].mergedPRsNumber > 0
const bTopTier = !bPenalized && data[b].mergedPRsNumber > 0
if (aTopTier && !bTopTier) return -1
if (!aTopTier && bTopTier) return 1
}

if (data[a][pref1] < data[b][pref1]) {
return 1
}
Expand Down