platzky-promocode 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 platzky
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,76 @@
1
+ Metadata-Version: 2.3
2
+ Name: platzky_promocode
3
+ Version: 0.2.2
4
+ Summary: Plugin for revealing promo codes.
5
+ License: MIT
6
+ Author: ravenw-wing
7
+ Requires-Python: >=3.10,<4.0
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Description-Content-Type: text/markdown
15
+
16
+ # platzky-promocode
17
+
18
+ A [platzky](https://github.com/platzky/platzky) plugin that adds a click-to-reveal promo code button.
19
+
20
+ The promo code is never present as plain text in the page — it is base64-encoded and decoded client-side only on click.
21
+
22
+ ## Installation
23
+
24
+ ```sh
25
+ pip install platzky_promocode
26
+ ```
27
+
28
+ ## Configuration
29
+
30
+ Register the plugin in your platzky config:
31
+
32
+ ```json
33
+ {
34
+ "plugins": [
35
+ {
36
+ "name": "promocode",
37
+ "config": {
38
+ "promo_code": "SUMMER24",
39
+ "text": "Reveal your discount",
40
+ "color": "#e63946"
41
+ }
42
+ }
43
+ ]
44
+ }
45
+ ```
46
+
47
+ | Field | Required | Default | Description |
48
+ |---|---|---|---|
49
+ | `promo_code` | yes | — | The code to reveal on click |
50
+ | `text` | no | `"Reveal Promo Code"` | Button label before reveal |
51
+ | `color` | no | `"#4caf50"` | Button background (any CSS color literal) |
52
+
53
+ ## Usage in a location pin
54
+
55
+ Add a `promo_code` field to the location data and include it in `visible_data`:
56
+
57
+ ```json
58
+ {
59
+ "promo_code": {
60
+ "code": "SUMMER24",
61
+ "text": "Reveal your discount",
62
+ "color": "#e63946"
63
+ }
64
+ }
65
+ ```
66
+
67
+ When the plugin is enabled, it automatically detects this field and renders it as an interactive button — no extra markup needed in the location data.
68
+
69
+ ## Usage in a Jinja2 template
70
+
71
+ ```html
72
+ {{ promocode_button() }}
73
+ ```
74
+
75
+ The button uses the `text`, `color`, and `promo_code` values from the plugin config.
76
+
@@ -0,0 +1,60 @@
1
+ # platzky-promocode
2
+
3
+ A [platzky](https://github.com/platzky/platzky) plugin that adds a click-to-reveal promo code button.
4
+
5
+ The promo code is never present as plain text in the page — it is base64-encoded and decoded client-side only on click.
6
+
7
+ ## Installation
8
+
9
+ ```sh
10
+ pip install platzky_promocode
11
+ ```
12
+
13
+ ## Configuration
14
+
15
+ Register the plugin in your platzky config:
16
+
17
+ ```json
18
+ {
19
+ "plugins": [
20
+ {
21
+ "name": "promocode",
22
+ "config": {
23
+ "promo_code": "SUMMER24",
24
+ "text": "Reveal your discount",
25
+ "color": "#e63946"
26
+ }
27
+ }
28
+ ]
29
+ }
30
+ ```
31
+
32
+ | Field | Required | Default | Description |
33
+ |---|---|---|---|
34
+ | `promo_code` | yes | — | The code to reveal on click |
35
+ | `text` | no | `"Reveal Promo Code"` | Button label before reveal |
36
+ | `color` | no | `"#4caf50"` | Button background (any CSS color literal) |
37
+
38
+ ## Usage in a location pin
39
+
40
+ Add a `promo_code` field to the location data and include it in `visible_data`:
41
+
42
+ ```json
43
+ {
44
+ "promo_code": {
45
+ "code": "SUMMER24",
46
+ "text": "Reveal your discount",
47
+ "color": "#e63946"
48
+ }
49
+ }
50
+ ```
51
+
52
+ When the plugin is enabled, it automatically detects this field and renders it as an interactive button — no extra markup needed in the location data.
53
+
54
+ ## Usage in a Jinja2 template
55
+
56
+ ```html
57
+ {{ promocode_button() }}
58
+ ```
59
+
60
+ The button uses the `text`, `color`, and `promo_code` values from the plugin config.
@@ -0,0 +1,8 @@
1
+ from platzky_promocode.plugin import PromocodePlugin
2
+
3
+ Plugin = PromocodePlugin
4
+
5
+ __all__ = [
6
+ "Plugin",
7
+ "PromocodePlugin",
8
+ ]
@@ -0,0 +1,117 @@
1
+ """Plugin for revealing promo codes embedded in blog content."""
2
+
3
+ import base64
4
+ import re
5
+ from typing import Any, ClassVar
6
+
7
+ from markupsafe import escape
8
+ from platzky.plugin.content_transformer import ContentTransformerPluginBase
9
+ from platzky.plugin.plugin import ConfigPluginError
10
+ from platzky.shortcodes import Shortcode, ShortcodeAttr, ShortcodeAttrs
11
+ from pydantic import BaseModel, ValidationError, field_validator
12
+
13
+ _COLOR_RE = re.compile(
14
+ r"^(#[0-9a-fA-F]{3,8}"
15
+ r"|rgb\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*\)"
16
+ r"|rgba\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*[\d.]+\s*\)"
17
+ r"|[a-zA-Z]+)$"
18
+ )
19
+
20
+
21
+ class PromocodeConfig(BaseModel):
22
+ """Configuration for the Promocode plugin."""
23
+
24
+ color: str = "#4caf50"
25
+ text: str = "Reveal Promo Code"
26
+
27
+ @field_validator("color")
28
+ @classmethod
29
+ def validate_color(cls, v: str) -> str:
30
+ """Reject values that are not valid CSS color literals."""
31
+ if not _COLOR_RE.match(v.strip()):
32
+ raise ValueError(f"Invalid CSS color: {v!r}")
33
+ return v.strip()
34
+
35
+
36
+ class _PromocodeShortcode(Shortcode):
37
+ """Shortcode that renders a reveal button for a promo code."""
38
+
39
+ name = "promocode"
40
+ description = "Reveal a promo code on click. Hidden until clicked."
41
+ attributes: ClassVar[ShortcodeAttrs] = ShortcodeAttrs(
42
+ [ShortcodeAttr("color", "Button colour (any CSS colour literal)", required=False)]
43
+ )
44
+ example = "[promocode]SUMMER2024[/promocode]"
45
+
46
+ def __init__(self, config: PromocodeConfig) -> None:
47
+ """Initialise with plugin config.
48
+
49
+ Args:
50
+ config: Plugin configuration supplying button text and default colour.
51
+ """
52
+ self._config = config
53
+
54
+ def render(self, attrs: ShortcodeAttrs, content: str) -> str:
55
+ """Render a reveal button for the promo code in content.
56
+
57
+ Args:
58
+ attrs: Parsed shortcode attributes; ``color`` overrides the configured colour.
59
+ content: The promo code to encode.
60
+
61
+ Returns:
62
+ A ``<button>`` element that reveals the code on click.
63
+ """
64
+ code = content.strip()
65
+ encoded = base64.b64encode(code.encode()).decode()
66
+ safe_text = escape(self._config.text)
67
+ color = (
68
+ attrs.color.strip()
69
+ if attrs.color and _COLOR_RE.match(attrs.color.strip())
70
+ else self._config.color
71
+ )
72
+ return (
73
+ f'<button class="platzky-promocode-btn"'
74
+ f' style="--platzky-promocode-color:{color};"'
75
+ f' data-code="{encoded}"'
76
+ f' onclick="platzkyRevealPromocode(this)">'
77
+ f"{safe_text}"
78
+ f"</button>"
79
+ )
80
+
81
+
82
+ class PromocodePlugin(ContentTransformerPluginBase):
83
+ """Plugin that registers a ``[promocode]`` shortcode.
84
+
85
+ Blog authors embed promo codes in post content as::
86
+
87
+ [promocode]SAVE20[/promocode]
88
+
89
+ An optional ``color`` attribute overrides the configured button colour::
90
+
91
+ [promocode color="#e91e63"]SAVE20[/promocode]
92
+
93
+ The actual code is base64-encoded in a ``data-code`` attribute and decoded
94
+ client-side via ``atob()`` so it is never present as plain text in the DOM.
95
+ """
96
+
97
+ shortcodes: ClassVar[dict[str, Shortcode]] = {}
98
+
99
+ def __init__(self, _config: dict[str, Any]) -> None:
100
+ """Initialise the plugin, parse config, and build the shortcode registry.
101
+
102
+ Args:
103
+ _config: Raw configuration dict from the platzky engine.
104
+
105
+ Raises:
106
+ ConfigPluginError: If the configuration is invalid.
107
+ """
108
+ super().__init__(_config)
109
+ try:
110
+ config = PromocodeConfig.model_validate(_config)
111
+ except ValidationError as e:
112
+ raise ConfigPluginError(f"Invalid configuration: {e}") from e
113
+ self.shortcodes = {"promocode": _PromocodeShortcode(config)} # type: ignore[misc]
114
+ self.config = config
115
+
116
+
117
+ Plugin = PromocodePlugin
File without changes
@@ -0,0 +1,2 @@
1
+ /*! For license information please see 540.js.LICENSE.txt */
2
+ "use strict";(self.webpackChunkplatzky_promocode_frontend=self.webpackChunkplatzky_promocode_frontend||[]).push([[540],{287(e,t){var r=Symbol.for("react.element"),n=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),u=Symbol.for("react.strict_mode"),c=Symbol.for("react.profiler"),a=Symbol.for("react.provider"),f=Symbol.for("react.context"),i=Symbol.for("react.forward_ref"),l=Symbol.for("react.suspense"),s=Symbol.for("react.memo"),p=Symbol.for("react.lazy"),y=Symbol.iterator,d={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},_=Object.assign,h={};function m(e,t,r){this.props=e,this.context=t,this.refs=h,this.updater=r||d}function b(){}function v(e,t,r){this.props=e,this.context=t,this.refs=h,this.updater=r||d}m.prototype.isReactComponent={},m.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")},m.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},b.prototype=m.prototype;var S=v.prototype=new b;S.constructor=v,_(S,m.prototype),S.isPureReactComponent=!0;var k=Array.isArray,w=Object.prototype.hasOwnProperty,E={current:null},$={key:!0,ref:!0,__self:!0,__source:!0};function R(e,t,n){var o,u={},c=null,a=null;if(null!=t)for(o in void 0!==t.ref&&(a=t.ref),void 0!==t.key&&(c=""+t.key),t)w.call(t,o)&&!$.hasOwnProperty(o)&&(u[o]=t[o]);var f=arguments.length-2;if(1===f)u.children=n;else if(1<f){for(var i=Array(f),l=0;l<f;l++)i[l]=arguments[l+2];u.children=i}if(e&&e.defaultProps)for(o in f=e.defaultProps)void 0===u[o]&&(u[o]=f[o]);return{$$typeof:r,type:e,key:c,ref:a,props:u,_owner:E.current}}function C(e){return"object"==typeof e&&null!==e&&e.$$typeof===r}var g=/\/+/g;function j(e,t){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(e){return t[e]})}(""+e.key):t.toString(36)}function O(e,t,o,u,c){var a=typeof e;"undefined"!==a&&"boolean"!==a||(e=null);var f=!1;if(null===e)f=!0;else switch(a){case"string":case"number":f=!0;break;case"object":switch(e.$$typeof){case r:case n:f=!0}}if(f)return c=c(f=e),e=""===u?"."+j(f,0):u,k(c)?(o="",null!=e&&(o=e.replace(g,"$&/")+"/"),O(c,t,o,"",function(e){return e})):null!=c&&(C(c)&&(c=function(e,t){return{$$typeof:r,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}(c,o+(!c.key||f&&f.key===c.key?"":(""+c.key).replace(g,"$&/")+"/")+e)),t.push(c)),1;if(f=0,u=""===u?".":u+":",k(e))for(var i=0;i<e.length;i++){var l=u+j(a=e[i],i);f+=O(a,t,o,l,c)}else if(l=function(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=y&&e[y]||e["@@iterator"])?e:null}(e),"function"==typeof l)for(e=l.call(e),i=0;!(a=e.next()).done;)f+=O(a=a.value,t,o,l=u+j(a,i++),c);else if("object"===a)throw t=String(e),Error("Objects are not valid as a React child (found: "+("[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.");return f}function x(e,t,r){if(null==e)return e;var n=[],o=0;return O(e,n,"","",function(e){return t.call(r,e,o++)}),n}function P(e){if(-1===e._status){var t=e._result;(t=t()).then(function(t){0!==e._status&&-1!==e._status||(e._status=1,e._result=t)},function(t){0!==e._status&&-1!==e._status||(e._status=2,e._result=t)}),-1===e._status&&(e._status=0,e._result=t)}if(1===e._status)return e._result.default;throw e._result}var I={current:null},T={transition:null},V={ReactCurrentDispatcher:I,ReactCurrentBatchConfig:T,ReactCurrentOwner:E};function A(){throw Error("act(...) is not supported in production builds of React.")}t.Children={map:x,forEach:function(e,t,r){x(e,function(){t.apply(this,arguments)},r)},count:function(e){var t=0;return x(e,function(){t++}),t},toArray:function(e){return x(e,function(e){return e})||[]},only:function(e){if(!C(e))throw Error("React.Children.only expected to receive a single React element child.");return e}},t.Component=m,t.Fragment=o,t.Profiler=c,t.PureComponent=v,t.StrictMode=u,t.Suspense=l,t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=V,t.act=A,t.cloneElement=function(e,t,n){if(null==e)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+e+".");var o=_({},e.props),u=e.key,c=e.ref,a=e._owner;if(null!=t){if(void 0!==t.ref&&(c=t.ref,a=E.current),void 0!==t.key&&(u=""+t.key),e.type&&e.type.defaultProps)var f=e.type.defaultProps;for(i in t)w.call(t,i)&&!$.hasOwnProperty(i)&&(o[i]=void 0===t[i]&&void 0!==f?f[i]:t[i])}var i=arguments.length-2;if(1===i)o.children=n;else if(1<i){f=Array(i);for(var l=0;l<i;l++)f[l]=arguments[l+2];o.children=f}return{$$typeof:r,type:e.type,key:u,ref:c,props:o,_owner:a}},t.createContext=function(e){return(e={$$typeof:f,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null,_defaultValue:null,_globalName:null}).Provider={$$typeof:a,_context:e},e.Consumer=e},t.createElement=R,t.createFactory=function(e){var t=R.bind(null,e);return t.type=e,t},t.createRef=function(){return{current:null}},t.forwardRef=function(e){return{$$typeof:i,render:e}},t.isValidElement=C,t.lazy=function(e){return{$$typeof:p,_payload:{_status:-1,_result:e},_init:P}},t.memo=function(e,t){return{$$typeof:s,type:e,compare:void 0===t?null:t}},t.startTransition=function(e){var t=T.transition;T.transition={};try{e()}finally{T.transition=t}},t.unstable_act=A,t.useCallback=function(e,t){return I.current.useCallback(e,t)},t.useContext=function(e){return I.current.useContext(e)},t.useDebugValue=function(){},t.useDeferredValue=function(e){return I.current.useDeferredValue(e)},t.useEffect=function(e,t){return I.current.useEffect(e,t)},t.useId=function(){return I.current.useId()},t.useImperativeHandle=function(e,t,r){return I.current.useImperativeHandle(e,t,r)},t.useInsertionEffect=function(e,t){return I.current.useInsertionEffect(e,t)},t.useLayoutEffect=function(e,t){return I.current.useLayoutEffect(e,t)},t.useMemo=function(e,t){return I.current.useMemo(e,t)},t.useReducer=function(e,t,r){return I.current.useReducer(e,t,r)},t.useRef=function(e){return I.current.useRef(e)},t.useState=function(e){return I.current.useState(e)},t.useSyncExternalStore=function(e,t,r){return I.current.useSyncExternalStore(e,t,r)},t.useTransition=function(){return I.current.useTransition()},t.version="18.3.1"},540(e,t,r){e.exports=r(287)}}]);
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @license React
3
+ * react.production.min.js
4
+ *
5
+ * Copyright (c) Facebook, Inc. and its affiliates.
6
+ *
7
+ * This source code is licensed under the MIT license found in the
8
+ * LICENSE file in the root directory of this source tree.
9
+ */
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunkplatzky_promocode_frontend=self.webpackChunkplatzky_promocode_frontend||[]).push([[705],{705(r,t,e){e.r(t),e.d(t,{default:()=>a});var n=e(914);function o(r,t){(null==t||t>r.length)&&(t=r.length);for(var e=0,n=Array(t);e<t;e++)n[e]=r[e];return n}function a(r){var t,e,a=r.code,l=r.text,i=r.color,u=(t=(0,n.useState)(!1),e=2,function(r){if(Array.isArray(r))return r}(t)||function(r,t){var e=null==r?null:"undefined"!=typeof Symbol&&r[Symbol.iterator]||r["@@iterator"];if(null!=e){var n,o,a,l,i=[],u=!0,c=!1;try{if(a=(e=e.call(r)).next,0===t){if(Object(e)!==e)return;u=!1}else for(;!(u=(n=a.call(e)).done)&&(i.push(n.value),i.length!==t);u=!0);}catch(r){c=!0,o=r}finally{try{if(!u&&null!=e.return&&(l=e.return(),Object(l)!==l))return}finally{if(c)throw o}}return i}}(t,e)||function(r,t){if(r){if("string"==typeof r)return o(r,t);var e={}.toString.call(r).slice(8,-1);return"Object"===e&&r.constructor&&(e=r.constructor.name),"Map"===e||"Set"===e?Array.from(r):"Arguments"===e||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e)?o(r,t):void 0}}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()),c=u[0],f=u[1];return n.createElement("button",{type:"button",onClick:function(){return!c&&f(!0)},style:{backgroundColor:c?"#333":i,border:"none",borderRadius:"4px",color:"#fff",cursor:c?"default":"pointer",fontFamily:c?"monospace":"inherit",fontSize:"1rem",letterSpacing:c?"0.1em":"normal",padding:"0.5rem 1.25rem",transition:"opacity 0.2s"}},c?atob(a):l)}}}]);
@@ -0,0 +1 @@
1
+ var promocode;(()=>{"use strict";var e,r,t,o,n,a,i,u,l,f,s,p,d,c,h,v,g,m,b,y={623(e,r,t){var o={"./Button":()=>t.e(705).then(()=>()=>t(705))},n=(e,r)=>(t.R=r,r=t.o(o,e)?o[e]():Promise.resolve().then(()=>{throw new Error('Module "'+e+'" does not exist in container.')}),t.R=void 0,r),a=(e,r)=>{if(t.S){var o="default",n=t.S[o];if(n&&n!==e)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return t.S[o]=e,t.I(o,r)}};t.d(r,{get:()=>n,init:()=>a})}},w={};function S(e){var r=w[e];if(void 0!==r)return r.exports;var t=w[e]={exports:{}};return y[e](t,t.exports,S),t.exports}S.m=y,S.c=w,S.d=(e,r)=>{for(var t in r)S.o(r,t)&&!S.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},S.f={},S.e=e=>Promise.all(Object.keys(S.f).reduce((r,t)=>(S.f[t](e,r),r),[])),S.u=e=>e+".js",S.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),S.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},r="platzky-promocode-frontend:",S.l=(t,o,n,a)=>{if(e[t])e[t].push(o);else{var i,u;if(void 0!==n)for(var l=document.getElementsByTagName("script"),f=0;f<l.length;f++){var s=l[f];if(s.getAttribute("src")==t||s.getAttribute("data-webpack")==r+n){i=s;break}}i||(u=!0,(i=document.createElement("script")).charset="utf-8",S.nc&&i.setAttribute("nonce",S.nc),i.setAttribute("data-webpack",r+n),i.src=t),e[t]=[o];var p=(r,o)=>{i.onerror=i.onload=null,clearTimeout(d);var n=e[t];if(delete e[t],i.parentNode&&i.parentNode.removeChild(i),n&&n.forEach(e=>e(o)),r)return r(o)},d=setTimeout(p.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),u&&document.head.appendChild(i)}},S.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{S.S={};var e={},r={};S.I=(t,o)=>{o||(o=[]);var n=r[t];if(n||(n=r[t]={}),!(o.indexOf(n)>=0)){if(o.push(n),e[t])return e[t];S.o(S.S,t)||(S.S[t]={});var a=S.S[t],i="platzky-promocode-frontend",u=[];return"default"===t&&((e,r,t,o)=>{var n=a[e]=a[e]||{},u=n[r];(!u||!u.loaded&&(1!=!u.eager?o:i>u.from))&&(n[r]={get:()=>S.e(540).then(()=>()=>S(540)),from:i,eager:!1})})("react","18.3.1"),e[t]=u.length?Promise.all(u).then(()=>e[t]=1):1}}})(),(()=>{var e;S.g.importScripts&&(e=S.g.location+"");var r=S.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var o=t.length-1;o>-1&&(!e||!/^http(s?):/.test(e));)e=t[o--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),S.p=e})(),t=e=>{var r=e=>e.split(".").map(e=>+e==e?+e:e),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),o=t[1]?r(t[1]):[];return t[2]&&(o.length++,o.push.apply(o,r(t[2]))),t[3]&&(o.push([]),o.push.apply(o,r(t[3]))),o},o=(e,r)=>{e=t(e),r=t(r);for(var o=0;;){if(o>=e.length)return o<r.length&&"u"!=(typeof r[o])[0];var n=e[o],a=(typeof n)[0];if(o>=r.length)return"u"==a;var i=r[o],u=(typeof i)[0];if(a!=u)return"o"==a&&"n"==u||"s"==u||"u"==a;if("o"!=a&&"u"!=a&&n!=i)return n<i;o++}},n=e=>{var r=e[0],t="";if(1===e.length)return"*";if(r+.5){t+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var o=1,a=1;a<e.length;a++)o--,t+="u"==(typeof(u=e[a]))[0]?"-":(o>0?".":"")+(o=2,u);return t}var i=[];for(a=1;a<e.length;a++){var u=e[a];i.push(0===u?"not("+l()+")":1===u?"("+l()+" || "+l()+")":2===u?i.pop()+" "+i.pop():n(u))}return l();function l(){return i.pop().replace(/^\((.+)\)$/,"$1")}},a=(e,r)=>{if(0 in e){r=t(r);var o=e[0],n=o<0;n&&(o=-o-1);for(var i=0,u=1,l=!0;;u++,i++){var f,s,p=u<e.length?(typeof e[u])[0]:"";if(i>=r.length||"o"==(s=(typeof(f=r[i]))[0]))return!l||("u"==p?u>o&&!n:""==p!=n);if("u"==s){if(!l||"u"!=p)return!1}else if(l)if(p==s)if(u<=o){if(f!=e[u])return!1}else{if(n?f>e[u]:f<e[u])return!1;f!=e[u]&&(l=!1)}else if("s"!=p&&"n"!=p){if(n||u<=o)return!1;l=!1,u--}else{if(u<=o||s<p!=n)return!1;l=!1}else"s"!=p&&"n"!=p&&(l=!1,u--)}}var d=[],c=d.pop.bind(d);for(i=1;i<e.length;i++){var h=e[i];d.push(1==h?c()|c():2==h?c()&c():h?a(h,r):!c())}return!!c()},i=(e,r)=>e&&S.o(e,r),u=e=>(e.loaded=1,e.get()),l=e=>Object.keys(e).reduce((r,t)=>(e[t].eager&&(r[t]=e[t]),r),{}),f=(e,r,t)=>{var n=t?l(e[r]):e[r];return Object.keys(n).reduce((e,r)=>!e||!n[e].loaded&&o(e,r)?r:e,0)},s=(e,r,t,o)=>"Unsatisfied version "+t+" from "+(t&&e[r][t].from)+" of shared singleton module "+r+" (required "+n(o)+")",p=e=>{throw new Error(e)},d=e=>{"undefined"!=typeof console&&console.warn&&console.warn(e)},c=(e,r,t)=>t?t():((e,r)=>p("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),h=(e=>function(r,t,o,n,a){var i=S.I(r);return i&&i.then&&!o?i.then(e.bind(e,r,S.S[r],t,!1,n,a)):e(r,S.S[r],t,o,n,a)})((e,r,t,o,n,l)=>{if(!i(r,t))return c(e,t,l);var p=f(r,t,o);return a(n,p)||d(s(r,t,p,n)),u(r[t][p])}),v={},g={914:()=>h("default","react",!1,[1,18,2,0],()=>S.e(540).then(()=>()=>S(540)))},m={705:[914]},b={},S.f.consumes=(e,r)=>{S.o(m,e)&&m[e].forEach(e=>{if(S.o(v,e))return r.push(v[e]);if(!b[e]){var t=r=>{v[e]=0,S.m[e]=t=>{delete S.c[e],t.exports=r()}};b[e]=!0;var o=r=>{delete v[e],S.m[e]=t=>{throw delete S.c[e],r}};try{var n=g[e]();n.then?r.push(v[e]=n.then(t).catch(o)):t(n)}catch(e){o(e)}}})},(()=>{var e={223:0};S.f.j=(r,t)=>{var o=S.o(e,r)?e[r]:void 0;if(0!==o)if(o)t.push(o[2]);else{var n=new Promise((t,n)=>o=e[r]=[t,n]);t.push(o[2]=n);var a=S.p+S.u(r),i=new Error;S.l(a,t=>{if(S.o(e,r)&&(0!==(o=e[r])&&(e[r]=void 0),o)){var n=t&&("load"===t.type?"missing":t.type),a=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+n+": "+a+")",i.name="ChunkLoadError",i.type=n,i.request=a,o[1](i)}},"chunk-"+r,r)}};var r=(r,t)=>{var o,n,[a,i,u]=t,l=0;if(a.some(r=>0!==e[r])){for(o in i)S.o(i,o)&&(S.m[o]=i[o]);u&&u(S)}for(r&&r(t);l<a.length;l++)n=a[l],S.o(e,n)&&e[n]&&e[n][0](),e[n]=0},t=self.webpackChunkplatzky_promocode_frontend=self.webpackChunkplatzky_promocode_frontend||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})();var k=S(623);promocode=k})();
@@ -0,0 +1,79 @@
1
+ [build-system]
2
+ requires = ["poetry-core"]
3
+ build-backend = "poetry.core.masonry.api"
4
+
5
+ [tool.poetry]
6
+ name = "platzky_promocode"
7
+ version = "0.2.2"
8
+ description = "Plugin for revealing promo codes."
9
+ authors = ["ravenw-wing"]
10
+ license = "MIT"
11
+ readme = "README.md"
12
+ include = ["platzky_promocode/static/**"]
13
+
14
+ [tool.poetry.dependencies]
15
+ python = "^3.10"
16
+
17
+ [tool.poetry.plugins."platzky.plugins"]
18
+ promocode = "platzky_promocode.plugin:PromocodePlugin"
19
+
20
+ [tool.poetry.group.dev.dependencies]
21
+ pytest = "^9.0.3"
22
+ black = "^26.3.1"
23
+ ruff = "^0.8.3"
24
+ pyright = "^1.1.390"
25
+ coverage = "^7.6.9"
26
+ interrogate = "^1.7.0"
27
+ platzky = "2.0.0a0"
28
+
29
+
30
+ [tool.black]
31
+ line-length = 100
32
+ target-version = ["py310"]
33
+
34
+ [tool.ruff]
35
+ line-length = 100
36
+ target-version = "py310"
37
+ show-fixes = true
38
+
39
+ [tool.ruff.lint]
40
+ select = [
41
+ "I",
42
+ "F",
43
+ "E",
44
+ "W",
45
+ "PT",
46
+ "RUF",
47
+ ]
48
+
49
+ [tool.pyright]
50
+ pythonVersion = "3.10"
51
+ pythonPlatform = "All"
52
+ typeCheckingMode = "strict"
53
+ reportMissingImports = true
54
+ reportMissingTypeStubs = false
55
+ reportMissingParameterType = true
56
+ reportUnknownArgumentType = true
57
+ reportUnknownMemberType = true
58
+ reportUnknownVariableType = true
59
+ reportUnknownParameterType = true
60
+ reportUnnecessaryTypeIgnoreComment = true
61
+ reportUntypedClassDecorator = false
62
+ reportUntypedFunctionDecorator = false
63
+ reportUnnecessaryIsInstance = false
64
+ reportUnusedFunction = true
65
+ reportUntypedBaseClass = false
66
+
67
+ [tool.pytest.ini_options]
68
+ markers = [
69
+ "skip_coverage: skip coverage for this test",
70
+ ]
71
+
72
+ [tool.interrogate]
73
+ fail-under = 95
74
+ ignore-init-method = true
75
+ ignore-init-module = true
76
+ ignore-magic = true
77
+ ignore-private = true
78
+ ignore-semiprivate = false
79
+ exclude = ["tests", "docs"]