Cliente SOAP + servicios de personaje SOAP (revive/unstuck) en Next.js
- lib/soap.ts: executeSoapCommand (port de ac_soap.py; POST SOAP + basic auth al worldserver, timeout 5s, null si inaccesible). AC_SOAP_* en .env.local. - lib/characters.ts: getGameCharacters / characterIsOfflineAndOwned (acore_characters). - lib/character-services.ts: soapCharacterAction genérico (valida propiedad+offline, cooldown 12h vía home_revive/unstuckhistory, SOAP, registra historial) -> reviveCharacter / unstuckCharacter. - components/CharacterActionForm.tsx (cliente reutilizable: select + botón). - Routes /api/character/revive|unstuck (guard de sesión) y páginas app/[locale]/revive|unstuck (SSR, guardas, i18n). Namespace Services. Verificado: API sin sesión 401, páginas redirigen a login, cliente SOAP devuelve null limpio sin worldserver. Patrón base para el resto de servicios de personaje. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
import { getTranslations, setRequestLocale } from 'next-intl/server'
|
||||
import { redirect } from '@/i18n/navigation'
|
||||
import { getSession } from '@/lib/session'
|
||||
import { getGameCharacters } from '@/lib/characters'
|
||||
import { CharacterActionForm } from '@/components/CharacterActionForm'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
export default async function RevivePage({ params }: { params: Promise<{ locale: string }> }) {
|
||||
const { locale } = await params
|
||||
setRequestLocale(locale)
|
||||
const t = await getTranslations('Services')
|
||||
const session = await getSession()
|
||||
if (!session.bnetId) redirect({ href: '/login', locale })
|
||||
if (!session.username) redirect({ href: '/select-account', locale })
|
||||
const chars = await getGameCharacters(session.accountId!)
|
||||
|
||||
return (
|
||||
<main className="mx-auto max-w-3xl px-4 py-8">
|
||||
<h1 className="mb-6 text-center text-2xl font-bold text-amber-500">{t('reviveTitle')}</h1>
|
||||
<CharacterActionForm characters={chars.map((c) => c.name)} endpoint="/api/character/revive" actionLabel={t('reviveAction')} />
|
||||
</main>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { getTranslations, setRequestLocale } from 'next-intl/server'
|
||||
import { redirect } from '@/i18n/navigation'
|
||||
import { getSession } from '@/lib/session'
|
||||
import { getGameCharacters } from '@/lib/characters'
|
||||
import { CharacterActionForm } from '@/components/CharacterActionForm'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
export default async function UnstuckPage({ params }: { params: Promise<{ locale: string }> }) {
|
||||
const { locale } = await params
|
||||
setRequestLocale(locale)
|
||||
const t = await getTranslations('Services')
|
||||
const session = await getSession()
|
||||
if (!session.bnetId) redirect({ href: '/login', locale })
|
||||
if (!session.username) redirect({ href: '/select-account', locale })
|
||||
const chars = await getGameCharacters(session.accountId!)
|
||||
|
||||
return (
|
||||
<main className="mx-auto max-w-3xl px-4 py-8">
|
||||
<h1 className="mb-6 text-center text-2xl font-bold text-amber-500">{t('unstuckTitle')}</h1>
|
||||
<CharacterActionForm characters={chars.map((c) => c.name)} endpoint="/api/character/unstuck" actionLabel={t('unstuckAction')} />
|
||||
</main>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { getSession } from '@/lib/session'
|
||||
import { reviveCharacter } from '@/lib/character-services'
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const session = await getSession()
|
||||
if (!session.accountId) return Response.json({ success: false, error: 'notAuthenticated' }, { status: 401 })
|
||||
let character = ''
|
||||
try {
|
||||
const body = await request.json()
|
||||
character = String(body.character ?? '')
|
||||
} catch {
|
||||
return Response.json({ success: false, error: 'invalidRequest' }, { status: 400 })
|
||||
}
|
||||
return Response.json(await reviveCharacter(session.accountId, character))
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { getSession } from '@/lib/session'
|
||||
import { unstuckCharacter } from '@/lib/character-services'
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const session = await getSession()
|
||||
if (!session.accountId) return Response.json({ success: false, error: 'notAuthenticated' }, { status: 401 })
|
||||
let character = ''
|
||||
try {
|
||||
const body = await request.json()
|
||||
character = String(body.character ?? '')
|
||||
} catch {
|
||||
return Response.json({ success: false, error: 'invalidRequest' }, { status: 400 })
|
||||
}
|
||||
return Response.json(await unstuckCharacter(session.accountId, character))
|
||||
}
|
||||
Reference in New Issue
Block a user