feat: ncue /go ref로 author_id 설정
- ref_type/ref(이메일 또는 IP) 수신 시 쿠키로 유지 - 링크 저장 시 ref 기반으로 author_id(text) 채움 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -91,3 +91,12 @@ python app.py
|
|||||||
|
|
||||||
- 초기 화면은 DB에서 **첫 페이지(기본 30개)** 만 가져와 SSR로 즉시 렌더링합니다.
|
- 초기 화면은 DB에서 **첫 페이지(기본 30개)** 만 가져와 SSR로 즉시 렌더링합니다.
|
||||||
- 메타데이터 추출은 캐시를 사용합니다(성공/실패 TTL 각각 적용).
|
- 메타데이터 추출은 캐시를 사용합니다(성공/실패 TTL 각각 적용).
|
||||||
|
|
||||||
|
## ncue.net 연동 (ref 전달)
|
||||||
|
|
||||||
|
`ncue.net`의 `/go`에서 아래와 같이 전달되는 값을 받아 `author_id(text)`에 저장합니다.
|
||||||
|
|
||||||
|
- 로그인 사용자: `ref_type=email&ref=<email>`
|
||||||
|
- 비로그인 사용자: `ref_type=ip&ref=<ip>`
|
||||||
|
|
||||||
|
이 값은 최초 진입 시 쿼리스트링으로 들어오며, 이후 요청에서도 유지되도록 서버가 쿠키로 저장합니다.
|
||||||
|
|||||||
26
app.py
26
app.py
@@ -9,7 +9,7 @@ import psycopg2
|
|||||||
import requests
|
import requests
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from flask import Flask, jsonify, render_template, request
|
from flask import Flask, jsonify, make_response, render_template, request
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
@@ -210,6 +210,14 @@ def get_request_identity(req) -> tuple[str | None, str | None]:
|
|||||||
- 이메일: 프록시/SSO가 주입하는 헤더에서 추출
|
- 이메일: 프록시/SSO가 주입하는 헤더에서 추출
|
||||||
- IP: X-Forwarded-For / X-Real-IP / remote_addr 순
|
- IP: X-Forwarded-For / X-Real-IP / remote_addr 순
|
||||||
"""
|
"""
|
||||||
|
# 0) ncue.net/go 연동: ref_type/ref 를 쿼리스트링 또는 쿠키로 전달받을 수 있음
|
||||||
|
ref_type = (req.args.get("ref_type") or req.cookies.get("ref_type") or "").strip()
|
||||||
|
ref = (req.args.get("ref") or req.cookies.get("ref") or "").strip()
|
||||||
|
if ref_type in ("email", "ip") and ref:
|
||||||
|
if ref_type == "email":
|
||||||
|
return ref, None
|
||||||
|
return None, ref
|
||||||
|
|
||||||
email_headers = [
|
email_headers = [
|
||||||
"X-User-Email",
|
"X-User-Email",
|
||||||
"X-Forwarded-Email",
|
"X-Forwarded-Email",
|
||||||
@@ -234,6 +242,17 @@ def get_request_identity(req) -> tuple[str | None, str | None]:
|
|||||||
return email, ip
|
return email, ip
|
||||||
|
|
||||||
|
|
||||||
|
def _maybe_set_ref_cookies(resp):
|
||||||
|
ref_type = (request.args.get("ref_type") or "").strip()
|
||||||
|
ref = (request.args.get("ref") or "").strip()
|
||||||
|
if ref_type in ("email", "ip") and ref:
|
||||||
|
# JS 요청(/links)에서도 유지되도록 쿠키 저장 (SameSite=Lax)
|
||||||
|
max_age = 60 * 60 * 24 * 30 # 30일
|
||||||
|
resp.set_cookie("ref_type", ref_type, max_age=max_age, samesite="Lax")
|
||||||
|
resp.set_cookie("ref", ref, max_age=max_age, samesite="Lax")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
|
||||||
def fetch_links_page_from_db(limit: int, offset: int):
|
def fetch_links_page_from_db(limit: int, offset: int):
|
||||||
table = os.getenv("TABLE", "news_link")
|
table = os.getenv("TABLE", "news_link")
|
||||||
schema = os.getenv("DB_SCHEMA", DEFAULT_SCHEMA)
|
schema = os.getenv("DB_SCHEMA", DEFAULT_SCHEMA)
|
||||||
@@ -268,13 +287,16 @@ def index():
|
|||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
error_message = f"DB 조회 실패: {exc}"
|
error_message = f"DB 조회 실패: {exc}"
|
||||||
return render_template(
|
resp = make_response(
|
||||||
|
render_template(
|
||||||
"index.html",
|
"index.html",
|
||||||
links=links,
|
links=links,
|
||||||
error_message=error_message,
|
error_message=error_message,
|
||||||
placeholder_data_uri=PLACEHOLDER_DATA_URI,
|
placeholder_data_uri=PLACEHOLDER_DATA_URI,
|
||||||
default_image=DEFAULT_IMAGE,
|
default_image=DEFAULT_IMAGE,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
return _maybe_set_ref_cookies(resp)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/links")
|
@app.get("/links")
|
||||||
|
|||||||
Reference in New Issue
Block a user