feat: mostrar siempre la URL ICS usando token_plain y migración

Co-authored-by: aider (openrouter/openai/gpt-5) <aider@aider.chat>
webui
borja 2 weeks ago
parent 2412b7fa66
commit 3a161e2821

@ -32,6 +32,7 @@ export async function findActiveToken(
user_id: string;
group_id: string | null;
token_hash: string;
token_plain: string | null;
created_at: string;
revoked_at: string | null;
last_used_at: string | null;
@ -39,14 +40,14 @@ export async function findActiveToken(
const db = await getDb();
const sql = groupId
? `
SELECT id, type, user_id, group_id, token_hash, created_at, revoked_at, last_used_at
SELECT id, type, user_id, group_id, token_hash, token_plain, created_at, revoked_at, last_used_at
FROM calendar_tokens
WHERE type = ? AND user_id = ? AND group_id = ? AND revoked_at IS NULL
ORDER BY id DESC
LIMIT 1
`
: `
SELECT id, type, user_id, group_id, token_hash, created_at, revoked_at, last_used_at
SELECT id, type, user_id, group_id, token_hash, token_plain, created_at, revoked_at, last_used_at
FROM calendar_tokens
WHERE type = ? AND user_id = ? AND group_id IS NULL AND revoked_at IS NULL
ORDER BY id DESC
@ -74,10 +75,10 @@ export async function createCalendarTokenUrl(
const createdAt = toIsoSql(new Date());
const insert = db.prepare(`
INSERT INTO calendar_tokens (type, user_id, group_id, token_hash, created_at)
VALUES (?, ?, ?, ?, ?)
INSERT INTO calendar_tokens (type, user_id, group_id, token_hash, token_plain, created_at)
VALUES (?, ?, ?, ?, ?, ?)
`);
const res = insert.run(type, userId, groupId ?? null, tokenHash, createdAt);
const res = insert.run(type, userId, groupId ?? null, tokenHash, token, createdAt);
const id = Number(res.lastInsertRowid || 0);
return { url: buildCalendarIcsUrl(type, token), token, id };

@ -1,6 +1,6 @@
import type { RequestHandler } from './$types';
import { getDb } from '$lib/server/db';
import { findActiveToken, createCalendarTokenUrl } from '$lib/server/calendar-tokens';
import { findActiveToken, createCalendarTokenUrl, buildCalendarIcsUrl } from '$lib/server/calendar-tokens';
export const GET: RequestHandler = async (event) => {
// Requiere sesión
@ -29,7 +29,7 @@ export const GET: RequestHandler = async (event) => {
const personalExisting = await findActiveToken('personal', userId, null);
const personal =
personalExisting
? { url: null }
? { url: personalExisting.token_plain ? buildCalendarIcsUrl('personal', personalExisting.token_plain) : null }
: await (async () => {
const created = await createCalendarTokenUrl('personal', userId, null);
return { url: created.url };
@ -39,7 +39,7 @@ export const GET: RequestHandler = async (event) => {
const aggregateExisting = await findActiveToken('aggregate', userId, null);
const aggregate =
aggregateExisting
? { url: null }
? { url: aggregateExisting.token_plain ? buildCalendarIcsUrl('aggregate', aggregateExisting.token_plain) : null }
: await (async () => {
const created = await createCalendarTokenUrl('aggregate', userId, null);
return { url: created.url };
@ -50,7 +50,8 @@ export const GET: RequestHandler = async (event) => {
for (const g of groups) {
const ex = await findActiveToken('group', userId, g.id);
if (ex) {
groupFeeds.push({ groupId: g.id, groupName: g.name ?? null, url: null });
const url = ex.token_plain ? buildCalendarIcsUrl('group', ex.token_plain) : null;
groupFeeds.push({ groupId: g.id, groupName: g.name ?? null, url });
} else {
const created = await createCalendarTokenUrl('group', userId, g.id);
groupFeeds.push({ groupId: g.id, groupName: g.name ?? null, url: created.url });

@ -359,5 +359,21 @@ export const migrations: Migration[] = [
db.exec(`CREATE INDEX IF NOT EXISTS idx_calendar_tokens_group ON calendar_tokens (group_id);`);
db.exec(`CREATE INDEX IF NOT EXISTS idx_calendar_tokens_type ON calendar_tokens (type);`);
}
},
{
version: 12,
name: 'calendar-tokens-plain',
checksum: 'v12-calendar-tokens-plain-2025-10-14',
up: (db: Database) => {
// Añadir columna para poder mostrar siempre la URL (guardando el token en claro).
// Nota: mantenemos token_hash para validación; token_plain se usa solo para construir la URL en UI.
try {
const cols = db.query(`PRAGMA table_info(calendar_tokens)`).all() as any[];
const hasPlain = Array.isArray(cols) && cols.some((c: any) => String(c.name) === 'token_plain');
if (!hasPlain) {
db.exec(`ALTER TABLE calendar_tokens ADD COLUMN token_plain TEXT NULL;`);
}
} catch {}
}
}
];

Loading…
Cancel
Save