Oysiyl commited on
Commit
61aae8d
·
1 Parent(s): 9159846

feat(shortener): honor gateway-injected link_lifetime for permanent paid-tier links

Browse files

- GenerateRequest.link_lifetime (server-set by qr-gateway from install entitlement)
- build_generation_kwargs passes it through
- generate_standard_qr/generate_artistic_qr accept and forward to shortener
- _maybe_shorten_url_for_qr sends permanent:true when link_lifetime=permanent
Paired with qrcut-shortener key-gated permanent flag + qr-gateway credit-aware injection.

Files changed (2) hide show
  1. app.py +12 -1
  2. qr_modal_contract.py +4 -0
app.py CHANGED
@@ -821,6 +821,7 @@ def _maybe_shorten_url_for_qr(
821
  original_input: str,
822
  input_type: str,
823
  use_temporary_short_link: bool,
 
824
  request: Any | None = None,
825
  ) -> Mapping[str, Any]:
826
  fallback_qr_text = _normalize_qr_text_for_validation(original_input, input_type)
@@ -847,7 +848,13 @@ def _maybe_shorten_url_for_qr(
847
  "error": "shortener is not configured on the server",
848
  }
849
 
850
- request_body = json.dumps({"url": str(original_input or ""), "reuse_existing": False}).encode("utf-8")
 
 
 
 
 
 
851
  # Set an explicit User-Agent: urllib's default "Python-urllib/3.x" is blocked
852
  # by Cloudflare WAF (Error 1010) at the qrcut.co edge, which surfaced as
853
  # "HTTP Error 403" → "short link unavailable, using normal link" in the UI.
@@ -2986,6 +2993,7 @@ def generate_standard_qr(
2986
  text_input: str = "",
2987
  input_type: str = "URL",
2988
  use_temporary_short_link: bool = False,
 
2989
  image_size: int = 512,
2990
  border_size: int = 4,
2991
  error_correction: str = "Medium (15%)",
@@ -3031,6 +3039,7 @@ def generate_standard_qr(
3031
  original_input=text_input,
3032
  input_type=input_type,
3033
  use_temporary_short_link=use_temporary_short_link,
 
3034
  request=request,
3035
  )
3036
  qr_text_input = str(shortener_result.get("effective_qr_text") or qr_text_input)
@@ -3295,6 +3304,7 @@ def generate_artistic_qr(
3295
  text_input: str = "",
3296
  input_type: str = "URL",
3297
  use_temporary_short_link: bool = False,
 
3298
  image_size: int = 512,
3299
  border_size: int = 4,
3300
  error_correction: str = "Medium (15%)",
@@ -3357,6 +3367,7 @@ def generate_artistic_qr(
3357
  original_input=text_input,
3358
  input_type=input_type,
3359
  use_temporary_short_link=use_temporary_short_link,
 
3360
  request=request,
3361
  )
3362
  qr_text_input = str(shortener_result.get("effective_qr_text") or qr_text_input)
 
821
  original_input: str,
822
  input_type: str,
823
  use_temporary_short_link: bool,
824
+ link_lifetime: str | None = None,
825
  request: Any | None = None,
826
  ) -> Mapping[str, Any]:
827
  fallback_qr_text = _normalize_qr_text_for_validation(original_input, input_type)
 
848
  "error": "shortener is not configured on the server",
849
  }
850
 
851
+ # link_lifetime is injected by the qr-gateway from the install's entitlement:
852
+ # "permanent" => paid-tier (Pro or credit-funded) => the short link never
853
+ # expires. Anything else => default rolling inactivity expiry.
854
+ permanent_link = str(link_lifetime or "").strip().lower() == "permanent"
855
+ request_body = json.dumps(
856
+ {"url": str(original_input or ""), "reuse_existing": False, "permanent": permanent_link}
857
+ ).encode("utf-8")
858
  # Set an explicit User-Agent: urllib's default "Python-urllib/3.x" is blocked
859
  # by Cloudflare WAF (Error 1010) at the qrcut.co edge, which surfaced as
860
  # "HTTP Error 403" → "short link unavailable, using normal link" in the UI.
 
2993
  text_input: str = "",
2994
  input_type: str = "URL",
2995
  use_temporary_short_link: bool = False,
2996
+ link_lifetime: str | None = None,
2997
  image_size: int = 512,
2998
  border_size: int = 4,
2999
  error_correction: str = "Medium (15%)",
 
3039
  original_input=text_input,
3040
  input_type=input_type,
3041
  use_temporary_short_link=use_temporary_short_link,
3042
+ link_lifetime=link_lifetime,
3043
  request=request,
3044
  )
3045
  qr_text_input = str(shortener_result.get("effective_qr_text") or qr_text_input)
 
3304
  text_input: str = "",
3305
  input_type: str = "URL",
3306
  use_temporary_short_link: bool = False,
3307
+ link_lifetime: str | None = None,
3308
  image_size: int = 512,
3309
  border_size: int = 4,
3310
  error_correction: str = "Medium (15%)",
 
3367
  original_input=text_input,
3368
  input_type=input_type,
3369
  use_temporary_short_link=use_temporary_short_link,
3370
+ link_lifetime=link_lifetime,
3371
  request=request,
3372
  )
3373
  qr_text_input = str(shortener_result.get("effective_qr_text") or qr_text_input)
qr_modal_contract.py CHANGED
@@ -26,6 +26,9 @@ class GenerateRequest(BaseModel):
26
  include_svg: bool = Field(default=False)
27
  include_image_base64: bool = Field(default=True)
28
  use_temporary_short_link: bool = Field(default=False)
 
 
 
29
  analytics_opt_in: bool = Field(default=False)
30
  enable_freeu: bool = Field(default=True)
31
  negative_prompt: str = Field(
@@ -75,6 +78,7 @@ def build_generation_kwargs(
75
  "text_input": request.qr_text,
76
  "input_type": request.input_type,
77
  "use_temporary_short_link": request.use_temporary_short_link,
 
78
  "image_size": request.image_size,
79
  "border_size": request.border_size,
80
  "error_correction": request.error_correction,
 
26
  include_svg: bool = Field(default=False)
27
  include_image_base64: bool = Field(default=True)
28
  use_temporary_short_link: bool = Field(default=False)
29
+ # Server-set by the qr-gateway from the install's entitlement (never trust
30
+ # client-supplied values for it): "permanent" => paid-tier link, no expiry.
31
+ link_lifetime: str | None = Field(default=None)
32
  analytics_opt_in: bool = Field(default=False)
33
  enable_freeu: bool = Field(default=True)
34
  negative_prompt: str = Field(
 
78
  "text_input": request.qr_text,
79
  "input_type": request.input_type,
80
  "use_temporary_short_link": request.use_temporary_short_link,
81
+ "link_lifetime": request.link_lifetime,
82
  "image_size": request.image_size,
83
  "border_size": request.border_size,
84
  "error_correction": request.error_correction,