From 0b7a8147918870472903e9fae46235afc73f4c13 Mon Sep 17 00:00:00 2001 From: dsyoon Date: Sun, 8 Feb 2026 11:58:24 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20ncue=20/go=20ref=EB=A1=9C=20author=5Fid?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ref_type/ref(이메일 또는 IP) 수신 시 쿠키로 유지 - 링크 저장 시 ref 기반으로 author_id(text) 채움 Co-authored-by: Cursor --- README.md | 9 +++++++++ app.py | 26 ++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 80a5748..dcd3dc4 100644 --- a/README.md +++ b/README.md @@ -91,3 +91,12 @@ python app.py - 초기 화면은 DB에서 **첫 페이지(기본 30개)** 만 가져와 SSR로 즉시 렌더링합니다. - 메타데이터 추출은 캐시를 사용합니다(성공/실패 TTL 각각 적용). + +## ncue.net 연동 (ref 전달) + +`ncue.net`의 `/go`에서 아래와 같이 전달되는 값을 받아 `author_id(text)`에 저장합니다. + +- 로그인 사용자: `ref_type=email&ref=` +- 비로그인 사용자: `ref_type=ip&ref=` + +이 값은 최초 진입 시 쿼리스트링으로 들어오며, 이후 요청에서도 유지되도록 서버가 쿠키로 저장합니다. diff --git a/app.py b/app.py index d77866b..24f8bfb 100644 --- a/app.py +++ b/app.py @@ -9,7 +9,7 @@ import psycopg2 import requests from bs4 import BeautifulSoup 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() @@ -210,6 +210,14 @@ def get_request_identity(req) -> tuple[str | None, str | None]: - 이메일: 프록시/SSO가 주입하는 헤더에서 추출 - 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 = [ "X-User-Email", "X-Forwarded-Email", @@ -234,6 +242,17 @@ def get_request_identity(req) -> tuple[str | None, str | None]: 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): table = os.getenv("TABLE", "news_link") schema = os.getenv("DB_SCHEMA", DEFAULT_SCHEMA) @@ -268,13 +287,16 @@ def index(): ) except Exception as exc: error_message = f"DB 조회 실패: {exc}" - return render_template( + resp = make_response( + render_template( "index.html", links=links, error_message=error_message, placeholder_data_uri=PLACEHOLDER_DATA_URI, default_image=DEFAULT_IMAGE, + ) ) + return _maybe_set_ref_cookies(resp) @app.get("/links")