diff --git a/admin/index.html b/admin/index.html
index be11af0..afa0039 100644
--- a/admin/index.html
+++ b/admin/index.html
@@ -32,6 +32,12 @@
Contributors Management
diff --git a/admin/src/index.js b/admin/src/index.js
index bcd1573..c040a07 100644
--- a/admin/src/index.js
+++ b/admin/src/index.js
@@ -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')
@@ -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', () => {
diff --git a/src/index.js b/src/index.js
index 2729b02..1f727da 100644
--- a/src/index.js
+++ b/src/index.js
@@ -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
@@ -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)
@@ -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 = `
${organizationHomepage} |
Github(${organization})`.trim()
+ return axios.get('/api/data')
+ })
+ .then(res => {
+ refreshTable(res.data)
})
axios.get('/api/log')
diff --git a/src/server/app.js b/src/server/app.js
index 666970f..becaff5 100644
--- a/src/server/app.js
+++ b/src/server/app.js
@@ -93,6 +93,7 @@ const server = http
organization: organization,
organizationHomepage: organizationHomepage,
organizationGithubUrl: organizationGithubUrl,
+ spamPenaltyThreshold: parseInt(jsonfile.readFileSync(configPath).spamPenaltyThreshold) || 0,
})
)
break
@@ -137,6 +138,7 @@ const server = http
delay,
contributors: contributorsList,
startDate,
+ spamPenaltyThreshold: parseInt(jsonfile.readFileSync(configPath).spamPenaltyThreshold) || 0,
})
) // success
jsonfile.writeFileSync(admindataPath, contributorsList)
@@ -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')
@@ -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) {
@@ -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))
diff --git a/src/server/config-example.json b/src/server/config-example.json
index 0937fa2..e59dc37 100644
--- a/src/server/config-example.json
+++ b/src/server/config-example.json
@@ -134,6 +134,7 @@
"abdelazeem777\t"
],
"startDate": "1970-01-15",
+ "spamPenaltyThreshold": 10,
"includedRepositories": [
"Rocket.Chat",
"Opensource-Contribution-Leaderboard",
diff --git a/src/server/util/API.js b/src/server/util/API.js
index 71b3c8d..9514a67 100644
--- a/src/server/util/API.js
+++ b/src/server/util/API.js
@@ -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')
@@ -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
}