mirror of
https://github.com/System-End/scraps.git
synced 2026-04-19 22:05:09 +00:00
Merge pull request #3 from System-End/main
feat: auto-submit projects to ysws thingie on review submission
This commit is contained in:
commit
7e52a1aa85
7 changed files with 96 additions and 8 deletions
|
|
@ -36,5 +36,8 @@ export const config = {
|
|||
airtableToken: process.env.AIRTABLE_TOKEN,
|
||||
airtableBaseId: process.env.AIRTABLE_BASE_ID,
|
||||
airtableProjectsTableId: process.env.AIRTABLE_PROJECTS_TABLE_ID!,
|
||||
airtableUsersTableId: process.env.AIRTABLE_USERS_TABLE_ID!
|
||||
airtableUsersTableId: process.env.AIRTABLE_USERS_TABLE_ID!,
|
||||
|
||||
// YSWS
|
||||
fraudToken: process.env.FRAUD_TOKEN
|
||||
}
|
||||
|
|
|
|||
54
backend/src/lib/ysws.ts
Normal file
54
backend/src/lib/ysws.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import { config } from '../config'
|
||||
|
||||
const YSWS_API_URL = 'https://joe.fraud.hackclub.com/api/v1/ysws/events/new-ui-api'
|
||||
|
||||
export async function submitProjectToYSWS(project: {
|
||||
name: string
|
||||
githubUrl: string | null
|
||||
playableUrl: string | null
|
||||
hackatimeProject: string | null
|
||||
slackId: string | null
|
||||
}) {
|
||||
if (!config.fraudToken) {
|
||||
console.log('[YSWS] Missing FRAUD_TOKEN, skipping submission')
|
||||
return null
|
||||
}
|
||||
|
||||
const hackatimeProjects = project.hackatimeProject
|
||||
? project.hackatimeProject.split(',').map(n => n.trim()).filter(n => n.length > 0)
|
||||
: []
|
||||
|
||||
const payload = {
|
||||
name: project.name,
|
||||
codeLink: project.githubUrl || '',
|
||||
demoLink: project.playableUrl || '',
|
||||
submitter: {
|
||||
slackId: project.slackId || ''
|
||||
},
|
||||
hackatimeProjects
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(`${YSWS_API_URL}/projects`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${config.fraudToken}`
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
|
||||
if (!res.ok) {
|
||||
const text = await res.text()
|
||||
console.error('[YSWS] submission failed:', res.status, text)
|
||||
return null
|
||||
}
|
||||
|
||||
const data = await res.json()
|
||||
console.log('[YSWS] submitted project:', project.name)
|
||||
return data
|
||||
} catch (e) {
|
||||
console.error('[YSWS] submission error:', e)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
|
@ -775,9 +775,12 @@ admin.get('/second-pass', async ({ headers, query }) => {
|
|||
const offset = (page - 1) * limit
|
||||
const sort = (query.sort as string) || 'oldest'
|
||||
|
||||
const orderClause = sort === 'newest'
|
||||
? desc(projectsTable.updatedAt)
|
||||
: asc(projectsTable.updatedAt)
|
||||
const submittedAtOrderExpr = sql<Date | null>`COALESCE((
|
||||
SELECT MAX(pa.created_at)
|
||||
FROM project_activity pa
|
||||
WHERE pa.project_id = projects.id
|
||||
AND pa.action = 'project_submitted'
|
||||
), ${projectsTable.updatedAt})`
|
||||
|
||||
const [projects, countResult] = await Promise.all([
|
||||
db.select({
|
||||
|
|
@ -804,10 +807,18 @@ admin.get('/second-pass', async ({ headers, query }) => {
|
|||
feedbackGood: projectsTable.feedbackGood,
|
||||
feedbackImprove: projectsTable.feedbackImprove,
|
||||
createdAt: projectsTable.createdAt,
|
||||
updatedAt: projectsTable.updatedAt
|
||||
updatedAt: projectsTable.updatedAt,
|
||||
submittedAt: sql<Date | null>`(
|
||||
SELECT MAX(pa.created_at)
|
||||
FROM project_activity pa
|
||||
WHERE pa.project_id = projects.id
|
||||
AND pa.action = 'project_submitted'
|
||||
)`
|
||||
}).from(projectsTable)
|
||||
.where(eq(projectsTable.status, 'pending_admin_approval'))
|
||||
.orderBy(orderClause)
|
||||
.orderBy(sort === 'newest'
|
||||
? desc(submittedAtOrderExpr)
|
||||
: asc(submittedAtOrderExpr))
|
||||
.limit(limit)
|
||||
.offset(offset),
|
||||
db.select({ count: sql<number>`count(*)` }).from(projectsTable)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { projectActivityTable } from '../schemas/activity'
|
|||
import { getUserFromSession, fetchUserIdentity } from '../lib/auth'
|
||||
import { syncSingleProject } from '../lib/hackatime-sync'
|
||||
import { notifyProjectSubmitted } from '../lib/slack'
|
||||
import { submitProjectToYSWS } from '../lib/ysws'
|
||||
import { config } from '../config'
|
||||
import { computeEffectiveHoursForProject } from '../lib/effective-hours'
|
||||
|
||||
|
|
@ -643,6 +644,15 @@ projects.post("/:id/submit", async ({ params, headers, body }) => {
|
|||
action: 'project_submitted'
|
||||
})
|
||||
|
||||
// Submit to YSWS
|
||||
submitProjectToYSWS({
|
||||
name: updated[0].name,
|
||||
githubUrl: updated[0].githubUrl,
|
||||
playableUrl: updated[0].playableUrl,
|
||||
hackatimeProject: updated[0].hackatimeProject,
|
||||
slackId: user.slackId
|
||||
}).catch(err => console.error('[YSWS] failed:', err))
|
||||
|
||||
// Send Slack DM notification that the project is waiting for review
|
||||
if (config.slackBotToken && user.slackId) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ export default {
|
|||
sort: 'sort:',
|
||||
default: 'default',
|
||||
favorites: 'favorites',
|
||||
favoritesSortHint: 'most wished, then yours',
|
||||
probability: 'probability',
|
||||
cost: 'cost (low to high)',
|
||||
loadingItems: 'Loading items...',
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ export default {
|
|||
sort: 'ordenar:',
|
||||
default: 'predeterminado',
|
||||
favorites: 'favoritos',
|
||||
favoritesSortHint: 'más deseados, luego los tuyos',
|
||||
probability: 'probabilidad',
|
||||
cost: 'costo (bajo a alto)',
|
||||
loadingItems: 'Cargando artículos...',
|
||||
|
|
|
|||
|
|
@ -59,7 +59,15 @@
|
|||
let sortedItems = $derived.by(() => {
|
||||
let items = [...filteredItems];
|
||||
if (sortBy === 'favorites') {
|
||||
return items.sort((a, b) => b.heartCount - a.heartCount);
|
||||
return items.sort((a, b) => {
|
||||
if (b.heartCount !== a.heartCount) {
|
||||
return b.heartCount - a.heartCount;
|
||||
}
|
||||
if (a.userHearted !== b.userHearted) {
|
||||
return a.userHearted ? -1 : 1;
|
||||
}
|
||||
return a.id - b.id;
|
||||
});
|
||||
} else if (sortBy === 'probability') {
|
||||
return items.sort((a, b) => b.effectiveProbability - a.effectiveProbability);
|
||||
} else if (sortBy === 'cost') {
|
||||
|
|
@ -224,7 +232,7 @@
|
|||
? 'bg-black text-white'
|
||||
: 'hover:border-dashed'}"
|
||||
>
|
||||
{$t.shop.favorites}
|
||||
{$t.shop.favorites} ({$t.shop.favoritesSortHint})
|
||||
</button>
|
||||
<button
|
||||
onclick={() => (sortBy = 'probability')}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue