One Calendar is a privacy-first calendar web app built with Next.js. It has modern security features, including e2ee, password-protected sharing, and self-destructing share links 📅 calendar.xyehr.cn
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #147 from EvanTechDev/codex/add-api-to-list-database-tables

feat: add API to list DB tables and run it daily via Vercel cron

authored by

Evan Huang and committed by
GitHub
35689a95 7b5a6430

+55 -56
+47
app/api/db/tables/route.ts
··· 1 + import { NextResponse } from "next/server"; 2 + import { Pool } from "pg"; 3 + 4 + const pool = new Pool({ 5 + connectionString: process.env.POSTGRES_URL, 6 + ssl: { rejectUnauthorized: false }, 7 + }); 8 + 9 + export async function GET(request: Request) { 10 + try { 11 + const authHeader = request.headers.get("authorization"); 12 + const cronSecret = process.env.CRON_SECRET; 13 + 14 + if (!cronSecret) { 15 + return NextResponse.json({ error: "Missing CRON_SECRET" }, { status: 500 }); 16 + } 17 + 18 + if (authHeader !== `Bearer ${cronSecret}`) { 19 + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); 20 + } 21 + 22 + const client = await pool.connect(); 23 + 24 + try { 25 + const result = await client.query<{ table_name: string }>( 26 + `SELECT table_name 27 + FROM information_schema.tables 28 + WHERE table_schema = 'public' 29 + AND table_type = 'BASE TABLE' 30 + ORDER BY table_name ASC` 31 + ); 32 + 33 + const tables = result.rows.map((row) => row.table_name); 34 + 35 + return NextResponse.json({ tables }); 36 + } finally { 37 + client.release(); 38 + } 39 + } catch (error) { 40 + return NextResponse.json( 41 + { 42 + error: error instanceof Error ? error.message : "Unknown error", 43 + }, 44 + { status: 500 } 45 + ); 46 + } 47 + }
-56
db.py
··· 1 - import os 2 - import psycopg2 3 - from datetime import datetime 4 - 5 - def ping_postgres(): 6 - # 获取 DB_URL 环境变量 7 - db_url = os.environ.get("DB_URL") 8 - 9 - if not db_url: 10 - print("Error: DB_URL not set") 11 - exit(1) 12 - 13 - try: 14 - # 建立数据库连接 15 - conn = psycopg2.connect(db_url) 16 - cursor = conn.cursor() 17 - 18 - # 检查 keep_alive 表是否存在 19 - cursor.execute(""" 20 - SELECT EXISTS ( 21 - SELECT FROM information_schema.tables 22 - WHERE table_name = 'keep_alive' 23 - ) 24 - """) 25 - table_exists = cursor.fetchone()[0] 26 - 27 - # 如果表不存在,创建 keep_alive 表 28 - if not table_exists: 29 - cursor.execute(""" 30 - CREATE TABLE keep_alive ( 31 - id SERIAL PRIMARY KEY, 32 - timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP 33 - ) 34 - """) 35 - conn.commit() 36 - print("Created keep_alive table") 37 - 38 - # 插入活跃记录 39 - cursor.execute("INSERT INTO keep_alive (timestamp) VALUES (CURRENT_TIMESTAMP) RETURNING id, timestamp") 40 - result = cursor.fetchone() 41 - 42 - print(f"Ping successful at {datetime.utcnow()}: Recorded ID {result[0]}, Timestamp {result[1]}") 43 - 44 - # 提交事务 45 - conn.commit() 46 - 47 - # 清理 48 - cursor.close() 49 - conn.close() 50 - 51 - except Exception as e: 52 - print(f"Error pinging PostgreSQL: {str(e)}") 53 - exit(1) 54 - 55 - if __name__ == "__main__": 56 - ping_postgres()
+8
vercel.json
··· 1 + { 2 + "crons": [ 3 + { 4 + "path": "/api/db/tables", 5 + "schedule": "0 0 * * *" 6 + } 7 + ] 8 + }