mirror of
https://github.com/perstarkse/minne.git
synced 2026-11-13 19:13:28 +01:00
wip: plist ios shortcut
This commit is contained in:
1 parent
669875094b
commit
9e89127200
6 files changed
+164
-4
No files matched your search
Generated
+23
@@ -3692,6 +3692,19 @@ version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||
|
||||
[[package]]
|
||||
name = "plist"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"indexmap 2.6.0",
|
||||
"quick-xml",
|
||||
"serde",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "2.8.0"
|
||||
@@ -3859,6 +3872,15 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick_cache"
|
||||
version = "0.5.2"
|
||||
@@ -6382,6 +6404,7 @@ dependencies = [
|
||||
"minijinja",
|
||||
"minijinja-autoreload",
|
||||
"mockall",
|
||||
"plist",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
|
||||
@@ -21,6 +21,7 @@ mime_guess = "2.0.5"
|
||||
minijinja = { version = "2.5.0", features = ["loader", "multi_template"] }
|
||||
minijinja-autoreload = "2.5.0"
|
||||
mockall = "0.13.0"
|
||||
plist = "1.7.0"
|
||||
serde = { version = "1.0.210", features = ["derive"] }
|
||||
serde_json = "1.0.128"
|
||||
sha2 = "0.10.8"
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
*,:after,:before{--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:rgba(59,130,246,.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:rgba(59,130,246,.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: }/*! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-tap-highlight-color:transparent}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-size:1em;font-variation-settings:normal}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-feature-settings:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]:where(:not([hidden=until-found])){display:none}:root,[data-theme]{background-color:var(--fallback-b1,oklch(var(--b1)/1));color:var(--fallback-bc,oklch(var(--bc)/1))}@supports not (color:oklch(0% 0 0)){:root{color-scheme:light;--fallback-p:#491eff;--fallback-pc:#d4dbff;--fallback-s:#ff41c7;--Line truncated
|
||||
*,:after,:before{--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:rgba(59,130,246,.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:rgba(59,130,246,.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: }/*! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-tap-highlight-color:transparent}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-size:1em;font-variation-settings:normal}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-feature-settings:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]:where(:not([hidden=until-found])){display:none}:root,[data-theme]{background-color:var(--fallback-b1,oklch(var(--b1)/1));color:var(--fallback-bc,oklch(var(--bc)/1))}@supports not (color:oklch(0% 0 0)){:root{color-scheme:light;--fallback-p:#491eff;--fallback-pc:#d4dbff;--fallback-s:#ff41c7;--Line truncated
|
||||
+2
-1
@@ -23,7 +23,7 @@ use zettle_db::{
|
||||
ingress::ingress_data, query::query_handler, queue_length::queue_length_handler,
|
||||
},
|
||||
html::{
|
||||
account::{delete_account, set_api_key, show_account_page},
|
||||
account::{delete_account, set_api_key, show_account_page, show_ios_shortcut},
|
||||
documentation::index::show_documentation_index,
|
||||
gdpr::{accept_gdpr, deny_gdpr},
|
||||
index::index_handler,
|
||||
@@ -160,6 +160,7 @@ fn html_routes(
|
||||
)
|
||||
.route("/account", get(show_account_page))
|
||||
.route("/set-api-key", post(set_api_key))
|
||||
.route("/get-ios-shortcut", get(show_ios_shortcut))
|
||||
.route("/delete-account", delete(delete_account))
|
||||
.route(
|
||||
"/signup",
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use axum::{
|
||||
extract::State,
|
||||
extract::{Query, State},
|
||||
http::{StatusCode, Uri},
|
||||
response::{IntoResponse, Redirect},
|
||||
response::{Html, IntoResponse, Redirect},
|
||||
};
|
||||
use axum_htmx::HxRedirect;
|
||||
use axum_session_auth::AuthSession;
|
||||
@@ -96,3 +98,134 @@ pub async fn delete_account(
|
||||
|
||||
Ok((HxRedirect::from(Uri::from_static("/")), StatusCode::OK).into_response())
|
||||
}
|
||||
|
||||
pub async fn show_ios_shortcut(
|
||||
State(state): State<AppState>,
|
||||
auth: AuthSession<User, String, SessionSurrealPool<Any>, Surreal<Any>>,
|
||||
) -> Result<impl IntoResponse, HtmlError> {
|
||||
let user = match &auth.current_user {
|
||||
Some(user) => user,
|
||||
None => return Ok(Redirect::to("/").into_response()),
|
||||
};
|
||||
let base_url = "https://minne.starks.cloud";
|
||||
let shortcut_url = format!(
|
||||
"{}/api/shortcuts/template?key={:?}",
|
||||
base_url,
|
||||
user.api_key.as_ref().unwrap()
|
||||
);
|
||||
let deep_link = format!("shortcuts://import-workflow?url={}", &shortcut_url);
|
||||
|
||||
Ok(Html(format!(
|
||||
r#"
|
||||
<div class="p-4 mt-4 flex flex-col justify-center items-center border rounded-lg bg-base-200">
|
||||
<h3 class="text-lg font-bold mb-2">Install iOS Shortcut</h3>
|
||||
<ol class="list-decimal list-inside space-y-2 mb-4">
|
||||
<li>Open Settings > Shortcuts</li>
|
||||
<li>Enable "Allow Untrusted Shortcuts"</li>
|
||||
<li><a href="{}" class="btn btn-primary">Click here to install shortcut</a></li>
|
||||
</ol>
|
||||
</div>
|
||||
"#,
|
||||
deep_link
|
||||
))
|
||||
.into_response())
|
||||
}
|
||||
|
||||
// pub async fn serve_shortcut_template(
|
||||
// Query(params): Query<HashMap<String, String>>,
|
||||
// ) -> impl IntoResponse {
|
||||
// let api_key = params.get("key").cloned().unwrap_or_default();
|
||||
|
||||
// // Create the shortcut structure as a plist Value
|
||||
// let shortcut = Value::Dictionary(plist::Dictionary::from_iter([
|
||||
// (
|
||||
// "WFWorkflowActions".into(),
|
||||
// Value::Array(vec![
|
||||
// // Text input action
|
||||
// Value::Dictionary(plist::Dictionary::from_iter([
|
||||
// (
|
||||
// "WFWorkflowActionIdentifier".into(),
|
||||
// Value::String("is.workflow.actions.ask".into()),
|
||||
// ),
|
||||
// (
|
||||
// "WFWorkflowActionParameters".into(),
|
||||
// Value::Dictionary(plist::Dictionary::from_iter([
|
||||
// (
|
||||
// "WFAskActionPrompt".into(),
|
||||
// Value::String("Enter content or notes".into()),
|
||||
// ),
|
||||
// ("WFInputType".into(), Value::String("Text".into())),
|
||||
// ])),
|
||||
// ),
|
||||
// ])),
|
||||
// // File picker action
|
||||
// Value::Dictionary(plist::Dictionary::from_iter([
|
||||
// (
|
||||
// "WFWorkflowActionIdentifier".into(),
|
||||
// Value::String("is.workflow.actions.documentpicker".into()),
|
||||
// ),
|
||||
// (
|
||||
// "WFWorkflowActionParameters".into(),
|
||||
// Value::Dictionary(plist::Dictionary::from_iter([(
|
||||
// "WFAllowMultipleSelection".into(),
|
||||
// Value::Boolean(true),
|
||||
// )])),
|
||||
// ),
|
||||
// ])),
|
||||
// // API request action
|
||||
// Value::Dictionary(plist::Dictionary::from_iter([
|
||||
// (
|
||||
// "WFWorkflowActionIdentifier".into(),
|
||||
// Value::String("is.workflow.actions.downloadurl".into()),
|
||||
// ),
|
||||
// (
|
||||
// "WFWorkflowActionParameters".into(),
|
||||
// Value::Dictionary(plist::Dictionary::from_iter([
|
||||
// ("Method".into(), Value::String("POST".into())),
|
||||
// (
|
||||
// "URL".into(),
|
||||
// Value::String("http://your-api-endpoint.com/api/v2/ingress".into()),
|
||||
// ),
|
||||
// (
|
||||
// "Advanced".into(),
|
||||
// Value::Dictionary(plist::Dictionary::from_iter([(
|
||||
// "Headers".into(),
|
||||
// Value::Dictionary(plist::Dictionary::from_iter([(
|
||||
// "X-API-Key".into(),
|
||||
// Value::String(api_key),
|
||||
// )])),
|
||||
// )])),
|
||||
// ),
|
||||
// ])),
|
||||
// ),
|
||||
// ])),
|
||||
// ]),
|
||||
// ),
|
||||
// (
|
||||
// "WFWorkflowName".into(),
|
||||
// Value::String("Share to Your App".into()),
|
||||
// ),
|
||||
// (
|
||||
// "WFWorkflowTypes".into(),
|
||||
// Value::Array(vec![
|
||||
// Value::String("NCWidget".into()),
|
||||
// Value::String("WatchKit".into()),
|
||||
// Value::String("QuickActions".into()),
|
||||
// ]),
|
||||
// ),
|
||||
// ]));
|
||||
|
||||
// // Create a buffer to write the binary plist
|
||||
// let mut buffer = Cursor::new(Vec::new());
|
||||
// plist::to_writer_binary(&mut buffer, &shortcut).unwrap();
|
||||
// // ...
|
||||
|
||||
// Response::builder()
|
||||
// .header("Content-Type", "application/x-ios-workflow")
|
||||
// .header(
|
||||
// "Content-Disposition",
|
||||
// "attachment; filename=\"share_to_app.shortcut\"",
|
||||
// )
|
||||
// .body(buffer.into_inner())
|
||||
// .unwrap()
|
||||
// }
|
||||
@@ -21,6 +21,8 @@
|
||||
{% block api_key_section %}
|
||||
{% if user.api_key %}
|
||||
<input type="text" name="api-key" value="{{ user.api_key }}" class="input input-bordered w-full" disabled />
|
||||
<button hx-get="/get-ios-shortcut" class="btn btn-accent mt-4" hx-swap="outerHTML">Download iOS
|
||||
shortcut</button>
|
||||
{% else %}
|
||||
<button hx-post="/set-api-key" class="btn btn-secondary w-full" hx-swap="outerHTML">
|
||||
Create API-Key
|
||||
|
||||
Reference in new issue
Block a user