Last active
August 2, 2025 01:14
-
-
Save abiriadev/612ac1240fbec18d15261db2cf988ffa to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const History = require('../schemas/history') | |
const { HistoryTypes } = require('../utils/types') | |
const editTypeKeys = ['Create', 'Modify', 'Delete', 'Move', 'ACL', 'Revert'] | |
const rangeMap = { | |
all: '전체', | |
'1m': '1달', | |
'2w': '2주', | |
'1w': '1주', | |
'3d': '3일', | |
'1d': '하루', | |
} | |
const rangeToDate = r => { | |
const n = Date.now() | |
const d1 = 24 * 60 * 60 * 1000 | |
// prettier-ignore | |
const d = r === 'all' ? n | |
: r === '1m' ? d1 * 30 | |
: r === '2w' ? d1 * 14 | |
: r === '1w' ? d1 * 7 | |
: r === '3d' ? d1 * 3 | |
: d1 // 1d | |
return new Date(n - d) | |
} | |
module.exports = { | |
type: 'page', | |
menus: { | |
config: [ | |
{ | |
l: '/admin/contrib-stat', | |
t: '문서 기여 통계', | |
}, | |
], | |
}, | |
url: '/admin/contrib-stat', | |
async handler(req, res) { | |
if (!req.permissions.includes('admin')) res.error('권한이 부족합니다.') | |
const range = req.query.range || 'all' | |
if (!Object.keys(rangeMap).includes(range)) | |
res.error('유효하지 않은 범위입니다.') | |
let editTypes = req.query.editTypes || editTypeKeys | |
if (!Array.isArray(editTypes)) editTypes = [editTypes] | |
if (!editTypes.every(type => editTypeKeys.includes(type))) | |
res.error('유효하지 않은 편집 유형이 포함되어 있습니다.') | |
let mode = req.query.mode | |
if (mode && mode !== 'diffLen') res.error('유효하지 않은 집계 기준입니다.') | |
let excludeHidden = !!req.query.excludeHidden | |
let excludeDeletedUsers = !!req.query.excludeDeletedUsers | |
const d = await History.aggregate([ | |
{ | |
$lookup: { | |
from: 'users', | |
localField: 'user', | |
foreignField: 'uuid', | |
as: 'userDetails', | |
}, | |
}, | |
{ | |
$match: { | |
createdAt: { | |
$gte: rangeToDate(range), | |
}, | |
type: { | |
$in: editTypes.map(type => HistoryTypes[type]), | |
}, | |
...(excludeHidden | |
? { | |
troll: { $eq: false }, | |
hideLog: { $eq: false }, | |
hidden: { $eq: false }, | |
} | |
: {}), | |
...(excludeDeletedUsers ? { userDetails: { $ne: [] } } : {}), | |
}, | |
}, | |
{ | |
$group: { | |
_id: '$user', | |
totalContributions: | |
mode === 'diffLen' | |
? { | |
$sum: '$diffLength', | |
} | |
: { | |
$count: {}, | |
}, | |
userDetails: { $first: '$userDetails' }, | |
}, | |
}, | |
{ | |
$sort: { totalContributions: -1 }, | |
}, | |
{ | |
$limit: 100, | |
}, | |
{ | |
$project: { | |
_id: 0, | |
uuid: '$_id', | |
totalContributions: 1, | |
name: { $arrayElemAt: ['$userDetails.name', 0] }, | |
ip: { $arrayElemAt: ['$userDetails.ip', 0] }, | |
}, | |
}, | |
]) | |
res.renderSkin('문서 기여 통계', { | |
contentHtml: ` | |
<div class="wiki-content"> | |
<p class="wiki-paragraph">최대 100명만 보여줍니다.</p> | |
<form class="search-form flex box search-form"> | |
<div class="button-block"> | |
<select name="range">${Object.entries(rangeMap) | |
.map( | |
([k, v]) => | |
`<option value="${k}" ${k === range ? 'selected' : ''}>${v}</option>`, | |
) | |
.join('')}</select> | |
<!-- <input class="input search-input" placeholder="" /> --> | |
<div style="display: inline-flex"> | |
${editTypeKeys | |
.map( | |
type => ` | |
<label> | |
<input type="checkbox" name="editTypes" value="${type}" ${editTypes.includes(type) ? 'checked' : ''} /> | |
${type} | |
</label> | |
`, | |
) | |
.join('')} | |
</div> | |
<label> | |
<input type="checkbox" name="excludeHidden" value="true" ${excludeHidden ? 'checked' : ''} /> | |
숨겨진 리비전 또는 반달로 표시된 리비전 또는 편집 요약이 숨겨진 리비전을 집계에서 제외 | |
</label> | |
<label> | |
<input type="checkbox" name="excludeDeletedUsers" value="true" ${excludeDeletedUsers ? 'checked' : ''} /> | |
삭제된 사용자 제외 | |
</label> | |
<label> | |
<input type="checkbox" name="mode" value="diffLen" ${mode === 'diffLen' ? 'checked' : ''} /> | |
기여 글자수를 기준으로 집계 | |
</label> | |
<button type="submit">검색</button> | |
</div> | |
</form> | |
<div class="wiki-table-wrap"> | |
<table class="wiki-table"> | |
<thead><tr>${['순위', '총 기여', '사용자'] | |
.map( | |
th => `<td style="text-align: center;"><strong>${th}</strong></td>`, | |
) | |
.join('')}</tr></thead> | |
<tbody>${d | |
.map( | |
({ uuid, name, ip, totalContributions }, i) => `<tr> | |
<td>${i + 1}</td> | |
<td><a href="/contribution/${uuid}/document">${totalContributions}</td> | |
<td>${name ? `<a href="/w/사용자:${name}">${name}</a>` : ip ? `<a href="/contribution/${uuid}/document" style="color: green;">${ip}</a>` : `<a href="/w/삭제된사용자:${uuid}" style="color: gray;">삭제된사용자:${uuid}</a>`}</td> | |
</tr>`, | |
) | |
.join('')}</tbody> | |
</table> | |
</div> | |
</div>`, | |
}) | |
}, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment