commit 2eb4cd0a091b28169b6f4cf3a7eb20a0ad604b01 Author: Ross Trottier Date: Thu May 2 11:51:32 2024 -0600 Initialize diff --git a/css/federated-my-account.css b/css/federated-my-account.css new file mode 100644 index 0000000..9fc6994 --- /dev/null +++ b/css/federated-my-account.css @@ -0,0 +1,1000 @@ +/* +! tailwindcss v3.4.3 | MIT License | https://tailwindcss.com +*/ + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +7. Disable tap highlights on iOS +*/ + +html, +:host { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + /* 4 */ + font-feature-settings: normal; + /* 5 */ + font-variation-settings: normal; + /* 6 */ + -webkit-tap-highlight-color: transparent; + /* 7 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font-family by default. +2. Use the user's configured `mono` font-feature-settings by default. +3. Use the user's configured `mono` font-variation-settings by default. +4. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + /* 1 */ + font-feature-settings: normal; + /* 2 */ + font-variation-settings: normal; + /* 3 */ + font-size: 1em; + /* 4 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-feature-settings: inherit; + /* 1 */ + font-variation-settings: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + font-weight: inherit; + /* 1 */ + line-height: inherit; + /* 1 */ + letter-spacing: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +input:where([type='button']), +input:where([type='reset']), +input:where([type='submit']) { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Reset default styling for dialogs. +*/ + +dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ + +[hidden] { + display: none; +} + +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: ; +} + +.pointer-events-none { + pointer-events: none; +} + +.absolute { + position: absolute; +} + +.relative { + position: relative; +} + +.inset-0 { + inset: 0px; +} + +.right-6 { + right: 1.5rem; +} + +.top-6 { + top: 1.5rem; +} + +.mx-auto { + margin-left: auto; + margin-right: auto; +} + +.mt-2 { + margin-top: 0.5rem; +} + +.mt-8 { + margin-top: 2rem; +} + +.mt-6 { + margin-top: 1.5rem; +} + +.inline-flex { + display: inline-flex; +} + +.h-6 { + height: 1.5rem; +} + +.w-6 { + width: 1.5rem; +} + +.max-w-2xl { + max-width: 42rem; +} + +.divide-y > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); +} + +.divide-gray-200 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 1; + border-color: rgb(229 231 235 / var(--tw-divide-opacity)); +} + +.overflow-hidden { + overflow: hidden; +} + +.rounded-lg { + border-radius: 0.5rem; +} + +.rounded-md { + border-radius: 0.375rem; +} + +.rounded-bl-lg { + border-bottom-left-radius: 0.5rem; +} + +.rounded-br-lg { + border-bottom-right-radius: 0.5rem; +} + +.rounded-tl-lg { + border-top-left-radius: 0.5rem; +} + +.rounded-tr-lg { + border-top-right-radius: 0.5rem; +} + +.bg-gray-200 { + --tw-bg-opacity: 1; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)); +} + +.bg-indigo-50 { + --tw-bg-opacity: 1; + background-color: rgb(238 242 255 / var(--tw-bg-opacity)); +} + +.bg-purple-50 { + --tw-bg-opacity: 1; + background-color: rgb(250 245 255 / var(--tw-bg-opacity)); +} + +.bg-rose-50 { + --tw-bg-opacity: 1; + background-color: rgb(255 241 242 / var(--tw-bg-opacity)); +} + +.bg-sky-50 { + --tw-bg-opacity: 1; + background-color: rgb(240 249 255 / var(--tw-bg-opacity)); +} + +.bg-teal-50 { + --tw-bg-opacity: 1; + background-color: rgb(240 253 250 / var(--tw-bg-opacity)); +} + +.bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} + +.bg-yellow-50 { + --tw-bg-opacity: 1; + background-color: rgb(254 252 232 / var(--tw-bg-opacity)); +} + +.bg-indigo-600 { + --tw-bg-opacity: 1; + background-color: rgb(79 70 229 / var(--tw-bg-opacity)); +} + +.bg-emerald-50 { + --tw-bg-opacity: 1; + background-color: rgb(236 253 245 / var(--tw-bg-opacity)); +} + +.bg-zinc-50 { + --tw-bg-opacity: 1; + background-color: rgb(250 250 250 / var(--tw-bg-opacity)); +} + +.bg-pink-50 { + --tw-bg-opacity: 1; + background-color: rgb(253 242 248 / var(--tw-bg-opacity)); +} + +.bg-lime-50 { + --tw-bg-opacity: 1; + background-color: rgb(247 254 231 / var(--tw-bg-opacity)); +} + +.bg-amber-50 { + --tw-bg-opacity: 1; + background-color: rgb(255 251 235 / var(--tw-bg-opacity)); +} + +.p-3 { + padding: 0.75rem; +} + +.p-6 { + padding: 1.5rem; +} + +.px-3 { + padding-left: 0.75rem; + padding-right: 0.75rem; +} + +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; +} + +.py-24 { + padding-top: 6rem; + padding-bottom: 6rem; +} + +.text-center { + text-align: center; +} + +.text-base { + font-size: 1rem; + line-height: 1.5rem; +} + +.text-sm { + font-size: 0.875rem; + line-height: 1.25rem; +} + +.text-4xl { + font-size: 2.25rem; + line-height: 2.5rem; +} + +.text-lg { + font-size: 1.125rem; + line-height: 1.75rem; +} + +.font-semibold { + font-weight: 600; +} + +.font-bold { + font-weight: 700; +} + +.leading-6 { + line-height: 1.5rem; +} + +.leading-8 { + line-height: 2rem; +} + +.tracking-tight { + letter-spacing: -0.025em; +} + +.text-gray-300 { + --tw-text-opacity: 1; + color: rgb(209 213 219 / var(--tw-text-opacity)); +} + +.text-gray-500 { + --tw-text-opacity: 1; + color: rgb(107 114 128 / var(--tw-text-opacity)); +} + +.text-gray-900 { + --tw-text-opacity: 1; + color: rgb(17 24 39 / var(--tw-text-opacity)); +} + +.text-indigo-700 { + --tw-text-opacity: 1; + color: rgb(67 56 202 / var(--tw-text-opacity)); +} + +.text-purple-700 { + --tw-text-opacity: 1; + color: rgb(126 34 206 / var(--tw-text-opacity)); +} + +.text-rose-700 { + --tw-text-opacity: 1; + color: rgb(190 18 60 / var(--tw-text-opacity)); +} + +.text-sky-700 { + --tw-text-opacity: 1; + color: rgb(3 105 161 / var(--tw-text-opacity)); +} + +.text-teal-700 { + --tw-text-opacity: 1; + color: rgb(15 118 110 / var(--tw-text-opacity)); +} + +.text-yellow-700 { + --tw-text-opacity: 1; + color: rgb(161 98 7 / var(--tw-text-opacity)); +} + +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.text-rose-300 { + --tw-text-opacity: 1; + color: rgb(253 164 175 / var(--tw-text-opacity)); +} + +.text-emerald-700 { + --tw-text-opacity: 1; + color: rgb(4 120 87 / var(--tw-text-opacity)); +} + +.text-zinc-700 { + --tw-text-opacity: 1; + color: rgb(63 63 70 / var(--tw-text-opacity)); +} + +.text-pink-700 { + --tw-text-opacity: 1; + color: rgb(190 24 93 / var(--tw-text-opacity)); +} + +.text-lime-700 { + --tw-text-opacity: 1; + color: rgb(77 124 15 / var(--tw-text-opacity)); +} + +.text-amber-700 { + --tw-text-opacity: 1; + color: rgb(180 83 9 / var(--tw-text-opacity)); +} + +.text-gray-600 { + --tw-text-opacity: 1; + color: rgb(75 85 99 / var(--tw-text-opacity)); +} + +.shadow { + --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.shadow-sm { + --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.ring-4 { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.ring-white { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(255 255 255 / var(--tw-ring-opacity)); +} + +.focus-within:ring-2:focus-within { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.focus-within:ring-inset:focus-within { + --tw-ring-inset: inset; +} + +.focus-within:ring-indigo-500:focus-within { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity)); +} + +.hover:bg-indigo-500:hover { + --tw-bg-opacity: 1; + background-color: rgb(99 102 241 / var(--tw-bg-opacity)); +} + +.focus:outline-none:focus { + outline: 2px solid transparent; + outline-offset: 2px; +} + +.focus-visible:outline:focus-visible { + outline-style: solid; +} + +.focus-visible:outline-2:focus-visible { + outline-width: 2px; +} + +.focus-visible:outline-offset-2:focus-visible { + outline-offset: 2px; +} + +.focus-visible:outline-indigo-600:focus-visible { + outline-color: #4f46e5; +} + +.group:hover .group-hover:text-gray-400 { + --tw-text-opacity: 1; + color: rgb(156 163 175 / var(--tw-text-opacity)); +} + +@media (min-width: 640px) { + .sm:grid { + display: grid; + } + + .sm:grid-cols-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .sm:gap-px { + gap: 1px; + } + + .sm:divide-y-0 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(0px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(0px * var(--tw-divide-y-reverse)); + } + + .sm:rounded-bl-lg { + border-bottom-left-radius: 0.5rem; + } + + .sm:rounded-bl-none { + border-bottom-left-radius: 0px; + } + + .sm:rounded-tr-lg { + border-top-right-radius: 0.5rem; + } + + .sm:rounded-tr-none { + border-top-right-radius: 0px; + } + + .sm:py-32 { + padding-top: 8rem; + padding-bottom: 8rem; + } + + .sm:text-6xl { + font-size: 3.75rem; + line-height: 1; + } +} + +@media (min-width: 1024px) { + .lg:px-8 { + padding-left: 2rem; + padding-right: 2rem; + } +} \ No newline at end of file diff --git a/federated.php b/federated.php new file mode 100644 index 0000000..fcc0e42 --- /dev/null +++ b/federated.php @@ -0,0 +1,17 @@ + 'POST', + 'callback' => 'federated_update_provision_status_failed_subscriptions', + 'permissions_callback' => 'check_federated_permissions' + ) + ); +} + +function federated_update_provision_status_failed_subscriptions($request){ + $subscription_id = $request['subscription_id']; + $error_message = $request['error_message']; + + $subscription = wcs_get_subscription($subscription_id); + update_field('provision_status', 'provision_failed', $subscription_id); + update_field('error_message', $error_message, $subscription_id); + + $output = array(); + + $output['message'] = 'Marked as failed'; + $output['success'] = true; + return $output; +} + +//Get needs provision, get needs removal +add_action('rest_api_init', 'federated_route_update_provision_status_removed_register'); + +function federated_route_update_provision_status_removed_register(){ + //register routes here + register_rest_route( + 'federated-rest/v1', + 'set-to-removed', + array( + 'methods' => 'POST', + 'callback' => 'federated_update_provision_status_removed_subscriptions', + 'permissions_callback' => 'check_federated_permissions' + ) + ); +} + +function federated_update_provision_status_removed_subscriptions($request){ + $subscription_id = $request['subscription_id']; + + $subscription = wcs_get_subscription($subscription_id); + update_field('provision_status', 'removed', $subscription_id); + + $output = array(); + + $output['message'] = 'Removed'; + $output['success'] = true; + return $output; +} +//Get needs provision, get needs removal +add_action('rest_api_init', 'federated_route_update_provision_status_provisioned_register'); + +function federated_route_update_provision_status_provisioned_register(){ + //register routes here + register_rest_route( + 'federated-rest/v1', + 'set-to-provisioned', + array( + 'methods' => 'POST', + 'callback' => 'federated_update_provision_status_provisioned_subscriptions', + 'permissions_callback' => 'check_federated_permissions' + ) + ); +} + +function federated_update_provision_status_provisioned_subscriptions($request){ + $subscription_id = $request['subscription_id']; + + $subscription = wcs_get_subscription($subscription_id); + update_field('provision_status', 'provisioned', $subscription_id); + + $output = array(); + + $output['message'] = 'Provisioned'; + $output['success'] = true; + return $output; +} +//Get needs provision, get needs removal +add_action('rest_api_init', 'federated_route_update_backup_key_register'); + +function federated_route_update_backup_key_register(){ + //register routes here + register_rest_route( + 'federated-rest/v1', + 'update-backup-key', + array( + 'methods' => 'POST', + 'callback' => 'federated_update_backup_key_subscriptions', + 'permissions_callback' => 'check_federated_permissions' + ) + ); +} + +function federated_update_backup_key_subscriptions($request){ + $subscription_id = $request['subscription_id']; + $backup_key = $request['key']; + + $subscription = wcs_get_subscription($subscription_id); + update_field('backup_gpg_key', $backup_key, $subscription_id); + + $output = array(); + + $output['subscription_id'] = $subscription_id; + $output['result'] = 'Success'; + return $output; +} +//Get needs provision, get needs removal +add_action('rest_api_init', 'federated_route_update_backup_directory_register'); + +function federated_route_update_backup_directory_register(){ + //register routes here + register_rest_route( + 'federated-rest/v1', + 'update-backup-directory', + array( + 'methods' => 'POST', + 'callback' => 'federated_update_backup_directory_subscriptions', + 'permissions_callback' => 'check_federated_permissions' + ) + ); +} + +function federated_update_backup_directory_subscriptions($request){ + $subscription_id = $request['subscription_id']; + $backup_directory = $request['directory']; + + $subscription = wcs_get_subscription($subscription_id); + update_field('backup_directory', $backup_directory, $subscription_id); + + $output = array(); + + $output['subscription_id'] = $subscription_id; + $output['result'] = 'Success'; + return $output; +} + +//Get needs provision, get needs removal +add_action('rest_api_init', 'federated_route_update_mount_point_register'); + +function federated_route_update_mount_point_register(){ + //register routes here + register_rest_route( + 'federated-rest/v1', + 'update-mount-point', + array( + 'methods' => 'POST', + 'callback' => 'federated_update_mount_point_subscriptions', + 'permissions_callback' => 'check_federated_permissions' + ) + ); +} + +function federated_update_mount_point_subscriptions($request){ + $subscription_id = $request['subscription_id']; + $mount_point = $request['mount_point']; + + $subscription = wcs_get_subscription($subscription_id); + update_field('nfs_mount_point', $mount_point, $subscription_id); + + $output = array(); + + $output['subscription_id'] = $subscription_id; + $output['result'] = 'Success'; + return $output; +} + +//Get needs provision, get needs removal +add_action('rest_api_init', 'federated_route_update_internal_ip_register'); + +function federated_route_update_internal_ip_register(){ + //register routes here + register_rest_route( + 'federated-rest/v1', + 'update-internal-ip', + array( + 'methods' => 'POST', + 'callback' => 'federated_update_internal_ip_subscriptions', + 'permissions_callback' => 'check_federated_permissions' + ) + ); +} + +function federated_update_internal_ip_subscriptions($request){ + $subscription_id = $request['subscription_id']; + $internal_ip = $request['address']; + + $subscription = wcs_get_subscription($subscription_id); + update_field('internal_ip_address', $internal_ip, $subscription_id); + + $output = array(); + + $output['subscription_id'] = $subscription_id; + $output['result'] = 'Success'; + return $output; +} + +//Get needs provision, get needs removal +add_action('rest_api_init', 'federated_route_update_external_ip_register'); + +function federated_route_update_external_ip_register(){ + //register routes here + register_rest_route( + 'federated-rest/v1', + 'update-external-ip', + array( + 'methods' => 'POST', + 'callback' => 'federated_update_external_ip_subscriptions', + 'permissions_callback' => 'check_federated_permissions' + ) + ); +} + +function federated_update_external_ip_subscriptions($request){ + $subscription_id = $request['subscription_id']; + $external_ip = $request['address']; + + $subscription = wcs_get_subscription($subscription_id); + update_field('external_ip_address', $external_ip, $subscription_id); + + $output = array(); + + $output['subscription_id'] = $subscription_id; + $output['result'] = 'Success'; + return $output; +} + +//Get needs provision, get needs removal +add_action('rest_api_init', 'federated_route_update_initial_admin_password_register'); + +function federated_route_update_initial_admin_password_register(){ + //register routes here + register_rest_route( + 'federated-rest/v1', + 'update-admin-pass', + array( + 'methods' => 'POST', + 'callback' => 'federated_update_initial_admin_password_subscriptions', + 'permissions_callback' => 'check_federated_permissions' + ) + ); +} + +function federated_update_initial_admin_password_subscriptions($request){ + $subscription_id = $request['subscription_id']; + $pass = $request['password']; + + $subscription = wcs_get_subscription($subscription_id); + update_field('initial_admin_password', $pass, $subscription_id); + + $output = array(); + + $output['subscription_id'] = $subscription_id; + $output['result'] = 'Success'; + return $output; +} + +//Get needs provision, get needs removal +add_action('rest_api_init', 'federated_route_update_domain_register'); + +function federated_route_update_domain_register(){ + //register routes here + register_rest_route( + 'federated-rest/v1', + 'update-domain', + array( + 'methods' => 'POST', + 'callback' => 'federated_update_domain_subscriptions', + 'permissions_callback' => 'check_federated_permissions' + ) + ); +} + +function federated_update_domain_subscriptions($request){ + $subscription_id = $request['subscription_id']; + $domain = $request['domain']; + + $subscription = wcs_get_subscription($subscription_id); + update_field('domain', $domain, $subscription_id); + $vm_id = get_field('vm_id', $subscription_id); + + if($domain !== $vm_id){ + update_field('domain_status', 'custom', $subscription_id); + } + + $output = array(); + + $output['subscription_id'] = $subscription_id; + $output['result'] = 'Success'; + return $output; +} + +//Get needs provision, get needs removal +add_action('rest_api_init', 'federated_route_update_vm_id_register'); + +function federated_route_update_vm_id_register(){ + //register routes here + register_rest_route( + 'federated-rest/v1', + 'update-vm-id', + array( + 'methods' => 'POST', + 'callback' => 'federated_update_vm_id_subscriptions', + 'permissions_callback' => 'check_federated_permissions' + ) + ); +} + +function federated_update_vm_id_subscriptions($request){ + $subscription_id = $request['subscription_id']; + $vm_id = $request['vm_id']; + + $subscription = wcs_get_subscription($subscription_id); + update_field('vm_id', $vm_id, $subscription_id); + + $output = array(); + + $output['subscription_id'] = $subscription_id; + $output['result'] = 'Success'; + return $output; +} + +//Get needs provision, get needs removal +add_action('rest_api_init', 'federated_route_start_provision_register'); + +function federated_route_start_provision_register(){ + //register routes here + register_rest_route( + 'federated-rest/v1', + 'set-to-provisioning', + array( + 'methods' => 'POST', + 'callback' => 'federated_start_provision_subscriptions', + 'permissions_callback' => 'check_federated_permissions' + ) + ); +} + +function federated_start_provision_subscriptions($request){ + $subscription_id = $request['subscription_id']; + + $subscription = wcs_get_subscription($subscription_id); + update_field('provision_status', 'provisioning', $subscription_id); + + $output = array(); + + $output['subscription_id'] = $subscription_id; + $output['tier'] = get_subscription_tier($subscription); + $output['email'] = $subscription->get_user()->data->user_email; + $output['country_code'] = $subscription->get_billing_country(); + return $output; +} + +//Get needs provision, get needs removal +add_action('rest_api_init', 'federated_route_needs_removal_register'); + +function federated_route_needs_removal_register(){ + //register routes here + register_rest_route( + 'federated-rest/v1', + 'needs-removal', + array( + 'methods' => 'GET', + 'callback' => 'federated_needs_removal_subscriptions', + 'permissions_callback' => 'check_federated_permissions' + ) + ); +} + +function federated_needs_removal_subscriptions(){ + $args = array( + 'numberposts' => -1, + 'post_type' => 'shop_subscription', + 'post_status' => 'wc-cancelled', + 'meta_key' => 'provision_status', + 'meta_value' => 'needs_removal' + ); + + $posts = get_posts($args); + $output = array(); + + foreach($posts as $post){ + //Get data + $post_id = $post->ID; + $vm_id = get_field('vm_id', $post_id); + //Create object + $data = array(); + $data['subscription_id'] = $post_id; + $data['vm_id'] = $vm_id; + //Add to output + array_push($output, $data); + } + + return $output; +} + +//Get needs provision, get needs removal +add_action('rest_api_init', 'federated_route_needs_provision_register'); + +function federated_route_needs_provision_register(){ + //register routes here + register_rest_route( + 'federated-rest/v1', + 'needs-provision', + array( + 'methods' => 'GET', + 'callback' => 'federated_needs_provision_subscriptions', + 'permissions_callback' => 'check_federated_permissions' + ) + ); +} + +function federated_needs_provision_subscriptions(){ + $args = array( + 'numberposts' => -1, + 'post_type' => 'shop_subscription', + 'post_status' => 'wc-active', + 'meta_key' => 'provision_status', + 'meta_value' => 'needs_provision' + ); + + $posts = get_posts($args); + + return array_map('get_subscription_id', $posts); +} + +//Shared Functions +function get_subscription_id($subscription){ + return $subscription->ID; +} + +function check_federated_permissions(){ + if(current_user_can('administrator')){ + return true; + } else { + return new WP_Error( 'rest_forbidden', esc_html__( 'OMG you can not view private data.', 'my-text-domain' ), array( 'status' => 401 ) ); + } +} \ No newline at end of file diff --git a/woocommerce/federated_woocommerce_shared_functions.php b/woocommerce/federated_woocommerce_shared_functions.php new file mode 100644 index 0000000..1c88542 --- /dev/null +++ b/woocommerce/federated_woocommerce_shared_functions.php @@ -0,0 +1,14 @@ +get_items() as $line_item ) { + $product_id = $line_item['product_id']; + $is_core_product = get_field('subscription_type', $product_id) === 'core'; + + if($is_core_product){ + $tier = get_field('subscription_tier', $product_id); + } + } + return $tier; +} \ No newline at end of file diff --git a/woocommerce/my_account_customizations.php b/woocommerce/my_account_customizations.php new file mode 100644 index 0000000..d3ae7a5 --- /dev/null +++ b/woocommerce/my_account_customizations.php @@ -0,0 +1,172 @@ +query_vars, home_url() ); + if($this_page_url != 'http://feddev.local?page&pagename=my-account'){ + return; + } + + $user = wp_get_current_user(); + + // Loop through user subscriptions + foreach ( wcs_get_users_subscriptions($user->ID) as $subscription ) { + if($subscription->has_status( 'active' )){ + echo_subscription_info($subscription); + } + } +} + +function echo_subscription_info($subscription){ + $subscription_id = $subscription->ID; + $domain = get_field('domain', $subscription_id); + $domain_status = get_field('domain_status', $subscription_id); + $provision_status = get_field('provision_status', $subscription_id); + $initial_admin_password = get_field('initial_admin_password', $subscription_id); + + $tier = get_subscription_tier($subscription); + + if(!empty($domain) && $provision_status === 'provisioned'){ + echo '
'; + echo '
'; + echo '

Apps for ' . $domain . '

'; + echo '

Click the links below to access your apps. Also, check out our helpful articles here for tips and tutorials on how to use these amazing open source tools.

'; + if($domain_status === 'default'){ + echo '

This is a default domain, please do not change your admin password until you have switched to your custom domain.

'; + } + echo '

Admin Username: admin@' . $domain . ' \\ Initial Admin Password: ' . $initial_admin_password . '

'; + echo '
'; + echo '
'; + echo_links($tier, $domain); + } else if($provision_status === 'needs_provision' || $provision_status === 'provisioning') { + echo '
'; + echo '
'; + echo '

Welcome To Federated, Your Core is being provisioned as we speak.

'; + echo '

Your Federated Core is your very own, we provision each one made-to-order. Your apps, on your server, without having to share with anyone else. This only takes about 5 - 10 minutes, please check back shortly.

'; + echo '
'; + echo '
'; + } +} + +function echo_links($tier, $domain){ + //echo container + echo '
'; + if($tier === 'starter' || $tier === 'creator' || $tier === 'team' || $tier === 'enterprise'){ + echo_base_app_links($domain); + } + if($tier === 'creator' || $tier === 'team' || $tier === 'enterprise'){ + echo_creator_app_links($domain); + } + if($tier === 'team' || $tier === 'enterprise'){ + echo_team_app_links($domain); + } + if($tier === 'enterprise'){ + echo_enterprise_app_links($domain); + } + echo '
'; +} + +function echo_base_app_links($domain){ + echo_link_for_core_app($domain, 'panel', 'User Management', 'teal', '', 'Use panel to create users for your core. The first default user is your admin user.'); + echo_link_for_core_app($domain, 'nextcloud', 'Email, File Storage, and Documents', 'purple', '', 'Use Nextcloud for Email, File Storage, Project Management, Documents, and more.'); + echo_link_for_core_app($domain, 'vaultwarden', 'Password Management', 'sky', '', 'Manage Passwords with Vaultwarden'); +} + +function echo_creator_app_links($domain){ + echo_link_for_core_app($domain, 'element', 'Team Chat', 'yellow', '', 'Chat with your team using Element and Matrix.'); + echo_link_for_core_app($domain, '', 'Website', 'rose', '', 'Create the website of your dreams with WordPress.'); +} + +function echo_team_app_links($domain){ + echo_link_for_core_app($domain, 'espocrm', 'CRM', 'indigo', '', 'Perfect your sales pipeline with EspoCRM.'); + echo_link_for_core_app($domain, 'freescout', 'Helpdesk', 'sky', '', 'Provide amazing customer support with FreeScout.'); +} + +function echo_enterprise_app_links($domain){ + echo_link_for_core_app($domain, 'jitsi', 'Video Chat', 'zinc', '', 'Host secure video calls with your clients and team.'); + echo_link_for_core_app($domain, 'listmonk', 'Email Marketing', 'pink', '', 'Boost sales and engagement with ListMonk.'); + echo_link_for_core_app($domain, 'baserow', 'Visual Databases', 'yellow', '', 'Maintain your data, or build a back end for your next web app with Baserow.'); + echo_link_for_core_app($domain, 'bookstack', 'Wiki Documentation', 'amber', '', 'Create and maintain beautiful documentation for your personal knowledge, company processes, and more.'); + echo_link_for_core_app($domain, 'gitea', 'GIT Source Control', 'emerald', '', 'Manage your repos and CI/CD with confidence using GiTea source control.'); + echo_link_for_core_app($domain, 'castopod', 'Podcast Broadcasting', 'yellow', '', 'Keep your audience engaged and aggregate your podcast easily with Castopod.'); +} + +function echo_link_for_core_app($domain, $subdomain = '', $app_title = '', $color = 'emerald', $svg = '', $app_description = ''){ + $url = ''; + if (isset($subdomain) && $subdomain !== '') { + $url = $subdomain . '.' . $domain; + } else { + $url = $domain; + } + echo '
'; + echo '
'; + echo '
'; + echo ''; + echo $svg; + echo ''; + echo '
'; + echo '
'; + echo '

'; + echo ''; + echo ''; + echo $app_title; + echo ''; + echo '

'; + echo '

' . $app_description . '

'; + echo '
'; + echo ''; + echo '
'; +} + +add_action( 'woocommerce_account_provision-info_endpoint', 'federated_provision_info_content' ); +// Note: add_action must follow 'woocommerce_account_{your-endpoint-slug}_endpoint' format \ No newline at end of file diff --git a/woocommerce/new_subscription_set_to_needs_provision.php b/woocommerce/new_subscription_set_to_needs_provision.php new file mode 100644 index 0000000..2c86832 --- /dev/null +++ b/woocommerce/new_subscription_set_to_needs_provision.php @@ -0,0 +1,7 @@ +ID); +} + +add_action('woocommerce_checkout_subscription_created', 'federated_set_new_subscription_provision_status'); \ No newline at end of file diff --git a/woocommerce/thank_you_page_customizations.php b/woocommerce/thank_you_page_customizations.php new file mode 100644 index 0000000..748ace9 --- /dev/null +++ b/woocommerce/thank_you_page_customizations.php @@ -0,0 +1,10 @@ +You will receive an email within 15 minutes of this order with your login details. Please watch the welcome video below for your next steps.'; + echo '
'; + echo ''; + echo '
'; +} \ No newline at end of file