Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a6cf9f8db7 | |||
| eaff278e3d |
@@ -2,7 +2,7 @@ import { NextRequest, NextResponse } from 'next/server'
|
|||||||
import { getServerSession } from 'next-auth'
|
import { getServerSession } from 'next-auth'
|
||||||
import { authOptions } from '@/lib/auth'
|
import { authOptions } from '@/lib/auth'
|
||||||
import { prisma } from '@/lib/prisma'
|
import { prisma } from '@/lib/prisma'
|
||||||
import { getPostsPerHour } from '@/lib/mastodon'
|
import { getPostsData } from '@/lib/mastodon'
|
||||||
import { calcPrice } from '@/lib/pricing'
|
import { calcPrice } from '@/lib/pricing'
|
||||||
import { normalizeTag } from '@/lib/utils'
|
import { normalizeTag } from '@/lib/utils'
|
||||||
import { priceUpdateQueue } from '@/lib/queue'
|
import { priceUpdateQueue } from '@/lib/queue'
|
||||||
@@ -49,8 +49,11 @@ export async function POST(req: NextRequest) {
|
|||||||
|
|
||||||
// Query Mastodon
|
// Query Mastodon
|
||||||
let postsPerHour = 0
|
let postsPerHour = 0
|
||||||
|
let hasAnyPosts = false
|
||||||
try {
|
try {
|
||||||
postsPerHour = await getPostsPerHour(tag)
|
const data = await getPostsData(tag)
|
||||||
|
postsPerHour = data.postsPerHour
|
||||||
|
hasAnyPosts = data.hasAnyPosts
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[research] Mastodon fetch failed:', err)
|
console.error('[research] Mastodon fetch failed:', err)
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
@@ -59,18 +62,19 @@ export async function POST(req: NextRequest) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (postsPerHour === 0) {
|
if (!hasAnyPosts) {
|
||||||
// Deduct point for failed research
|
// Deduct point for failed research
|
||||||
await prisma.user.update({
|
await prisma.user.update({
|
||||||
where: { id: session.user.id },
|
where: { id: session.user.id },
|
||||||
data: { researchPoints: { decrement: 1 } },
|
data: { researchPoints: { decrement: 1 } },
|
||||||
})
|
})
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: 'No recent posts found for this hashtag. Research point spent.' },
|
{ error: 'No posts found for this hashtag anywhere recently. Research point spent.' },
|
||||||
{ status: 404 },
|
{ status: 404 },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use the last-hour price, or $0.25 minimum if active but currently quiet
|
||||||
const price = calcPrice(postsPerHour)
|
const price = calcPrice(postsPerHour)
|
||||||
const activeUntil = new Date(Date.now() + parseInt(process.env.HASHTAG_ACTIVE_HOURS ?? '24', 10) * 60 * 60 * 1000)
|
const activeUntil = new Date(Date.now() + parseInt(process.env.HASHTAG_ACTIVE_HOURS ?? '24', 10) * 60 * 60 * 1000)
|
||||||
|
|
||||||
|
|||||||
@@ -110,9 +110,14 @@ export default async function ProfilePage({ params }: Props) {
|
|||||||
<span className="text-slate-600 mx-1.5">·</span>
|
<span className="text-slate-600 mx-1.5">·</span>
|
||||||
{tier.pointsPerDay} research pt{tier.pointsPerDay !== 1 ? 's' : ''}/day
|
{tier.pointsPerDay} research pt{tier.pointsPerDay !== 1 ? 's' : ''}/day
|
||||||
{tier.nextThreshold && (
|
{tier.nextThreshold && (
|
||||||
<span className="text-slate-600 text-xs ml-1.5">
|
<>
|
||||||
|
<span className="hidden sm:inline text-slate-600 text-xs ml-1.5">
|
||||||
(next tier at {formatCurrency(tier.nextThreshold)})
|
(next tier at {formatCurrency(tier.nextThreshold)})
|
||||||
</span>
|
</span>
|
||||||
|
<span className="block sm:hidden text-slate-600 text-xs mt-0.5">
|
||||||
|
next tier at {formatCurrency(tier.nextThreshold)}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
+3
-3
@@ -80,7 +80,7 @@ export async function getPostsPerHour(tag: string): Promise<number> {
|
|||||||
*/
|
*/
|
||||||
export async function getPostsData(
|
export async function getPostsData(
|
||||||
tag: string,
|
tag: string,
|
||||||
): Promise<{ postsPerHour: number; relatedTags: string[]; displayTag?: string }> {
|
): Promise<{ postsPerHour: number; relatedTags: string[]; displayTag?: string; hasAnyPosts: boolean }> {
|
||||||
const maxPages = parseInt(process.env.MAX_PAGES_PER_HASHTAG ?? '5', 10)
|
const maxPages = parseInt(process.env.MAX_PAGES_PER_HASHTAG ?? '5', 10)
|
||||||
const postLimit = Math.min(parseInt(process.env.MASTODON_POST_LIMIT ?? '20', 10), 40)
|
const postLimit = Math.min(parseInt(process.env.MASTODON_POST_LIMIT ?? '20', 10), 40)
|
||||||
const ONE_HOUR_MS = 60 * 60 * 1000
|
const ONE_HOUR_MS = 60 * 60 * 1000
|
||||||
@@ -106,7 +106,7 @@ export async function getPostsData(
|
|||||||
maxId = nextMaxId
|
maxId = nextMaxId
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allPosts.length === 0) return { postsPerHour: 0, relatedTags: [] }
|
if (allPosts.length === 0) return { postsPerHour: 0, relatedTags: [], hasAnyPosts: false }
|
||||||
|
|
||||||
const times = allPosts.map((p) => new Date(p.created_at).getTime())
|
const times = allPosts.map((p) => new Date(p.created_at).getTime())
|
||||||
const newestMs = Math.max(...times)
|
const newestMs = Math.max(...times)
|
||||||
@@ -165,6 +165,6 @@ export async function getPostsData(
|
|||||||
if (topCount / total >= 0.5) displayTag = topVariant
|
if (topCount / total >= 0.5) displayTag = topVariant
|
||||||
}
|
}
|
||||||
|
|
||||||
return { postsPerHour, relatedTags, displayTag }
|
return { postsPerHour, relatedTags, displayTag, hasAnyPosts: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user