wip: plist ios shortcut

This commit is contained in:
Per Stark
2025-01-06 00:03:51 +01:00
parent 669875094b
commit 9e89127200
6 changed files with 164 additions and 4 deletions

23
Cargo.lock generated
View File

@@ -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",

View File

@@ -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"

File diff suppressed because one or more lines are too long

View File

@@ -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",

View File

@@ -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()
// }

View File

@@ -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