mirror of
https://github.com/System-End/scraps.git
synced 2026-04-19 22:05:09 +00:00
Update hackatime.ts
This commit is contained in:
parent
12431325af
commit
c46fd4d92e
1 changed files with 61 additions and 55 deletions
|
|
@ -1,29 +1,26 @@
|
|||
import { Elysia } from 'elysia'
|
||||
import { getUserFromSession } from '../lib/auth'
|
||||
import { config } from '../config'
|
||||
|
||||
const HACKATIME_API = 'https://hackatime.hackclub.com/api/v1'
|
||||
const HACKATIME_ADMIN_API = 'https://hackatime.hackclub.com/api/admin/v1'
|
||||
const SCRAPS_START_DATE = '2026-02-03'
|
||||
|
||||
interface HackatimeStatsProject {
|
||||
interface HackatimeAdminProject {
|
||||
name: string
|
||||
total_seconds: number
|
||||
}
|
||||
|
||||
interface HackatimeDetailsProject {
|
||||
name: string
|
||||
total_seconds: number
|
||||
total_heartbeats: number
|
||||
total_duration: number
|
||||
first_heartbeat: number
|
||||
last_heartbeat: number
|
||||
languages: string[]
|
||||
repo_url: string | null
|
||||
repo: string | null
|
||||
repo_mapping_id: number | null
|
||||
archived: boolean
|
||||
}
|
||||
|
||||
interface HackatimeStatsResponse {
|
||||
data: {
|
||||
projects: HackatimeStatsProject[]
|
||||
}
|
||||
}
|
||||
|
||||
interface HackatimeDetailsResponse {
|
||||
projects: HackatimeDetailsProject[]
|
||||
interface HackatimeAdminProjectsResponse {
|
||||
user_id: number
|
||||
username: string
|
||||
projects: HackatimeAdminProject[]
|
||||
}
|
||||
|
||||
const hackatime = new Elysia({ prefix: '/hackatime' })
|
||||
|
|
@ -32,56 +29,65 @@ hackatime.get('/projects', async ({ headers }) => {
|
|||
const user = await getUserFromSession(headers as Record<string, string>)
|
||||
if (!user) return { error: 'Unauthorized' }
|
||||
|
||||
if (!user.slackId) {
|
||||
console.log('[HACKATIME] No slackId found for user:', user.id)
|
||||
return { error: 'No Slack ID found for user', projects: [] }
|
||||
if (!user.email) {
|
||||
console.log('[HACKATIME] No email found for user:', user.id)
|
||||
return { error: 'No email found for user', projects: [] }
|
||||
}
|
||||
|
||||
const statsParams = new URLSearchParams({
|
||||
features: 'projects',
|
||||
start_date: SCRAPS_START_DATE
|
||||
})
|
||||
const statsUrl = `${HACKATIME_API}/users/${encodeURIComponent(user.slackId)}/stats?${statsParams}`
|
||||
const detailsUrl = `${HACKATIME_API}/users/${encodeURIComponent(user.slackId)}/projects/details`
|
||||
console.log('[HACKATIME] Fetching projects:', { userId: user.id, slackId: user.slackId, statsUrl })
|
||||
|
||||
try {
|
||||
// Fetch both stats (for hours after start date) and details (for repo URLs and languages)
|
||||
const [statsResponse, detailsResponse] = await Promise.all([
|
||||
fetch(statsUrl, { headers: { 'Accept': 'application/json' } }),
|
||||
fetch(detailsUrl, { headers: { 'Accept': 'application/json' } })
|
||||
])
|
||||
// Step 1: Get hackatime user_id by email
|
||||
const emailResponse = await fetch(`${HACKATIME_ADMIN_API}/user/get_user_by_email`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${config.hackatimeAdminKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ email: user.email })
|
||||
})
|
||||
|
||||
if (!statsResponse.ok) {
|
||||
const errorText = await statsResponse.text()
|
||||
console.log('[HACKATIME] Stats API error:', { status: statsResponse.status, body: errorText })
|
||||
if (!emailResponse.ok) {
|
||||
const errorText = await emailResponse.text()
|
||||
console.log('[HACKATIME] Email lookup error:', { status: emailResponse.status, body: errorText })
|
||||
return { projects: [] }
|
||||
}
|
||||
|
||||
const statsData: HackatimeStatsResponse = await statsResponse.json()
|
||||
const detailsData: HackatimeDetailsResponse = detailsResponse.ok
|
||||
? await detailsResponse.json()
|
||||
: { projects: [] }
|
||||
const { user_id } = await emailResponse.json() as { user_id: number }
|
||||
console.log('[HACKATIME] Found hackatime user_id:', user_id, 'for email:', user.email)
|
||||
|
||||
const projects = statsData.data?.projects || []
|
||||
// Step 2: Get projects via admin endpoint with start_date
|
||||
const projectsParams = new URLSearchParams({
|
||||
user_id: String(user_id),
|
||||
start_date: SCRAPS_START_DATE
|
||||
})
|
||||
const projectsUrl = `${HACKATIME_ADMIN_API}/user/projects?${projectsParams}`
|
||||
console.log('[HACKATIME] Fetching admin projects:', projectsUrl)
|
||||
|
||||
const projectsResponse = await fetch(projectsUrl, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${config.hackatimeAdminKey}`,
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
if (!projectsResponse.ok) {
|
||||
const errorText = await projectsResponse.text()
|
||||
console.log('[HACKATIME] Projects API error:', { status: projectsResponse.status, body: errorText })
|
||||
return { projects: [] }
|
||||
}
|
||||
|
||||
const data: HackatimeAdminProjectsResponse = await projectsResponse.json()
|
||||
const projects = data.projects || []
|
||||
console.log('[HACKATIME] Projects fetched:', projects.length)
|
||||
|
||||
// Create a map of project details for quick lookup
|
||||
const detailsMap = new Map(
|
||||
detailsData.projects?.map(p => [p.name, p]) || []
|
||||
)
|
||||
|
||||
return {
|
||||
slackId: user.slackId,
|
||||
projects: projects.map((p) => {
|
||||
const details = detailsMap.get(p.name)
|
||||
return {
|
||||
name: p.name,
|
||||
hours: Math.round(p.total_seconds / 3600 * 10) / 10,
|
||||
repoUrl: details?.repo_url || null,
|
||||
languages: details?.languages || []
|
||||
}
|
||||
})
|
||||
projects: projects.map((p) => ({
|
||||
name: p.name,
|
||||
hours: Math.round(p.total_duration / 3600 * 10) / 10,
|
||||
repoUrl: p.repo || null,
|
||||
languages: p.languages || []
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[HACKATIME] Error fetching projects:', error)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue