feat(atward): Support reading configuration from cookies
Adds support for reading configuration (currently only the `cs` parameter) from cookies and from URL query parameters. The latter take precedence if set explicitly. This is useful for users which can not edit their search query parameters. To make this easier to use the atward landing page has been updated with a simple form where settings can be toggled. This requires Javascript, but the script is small, embedded and MIT licensed (as is the rest of this project). Users without Javascript will be shown a notice about this. It is of course possible to set the cookies manually, too. Change-Id: Ie9a9dbeab4d9a97a349d7988e21f1b46037e1f72 Reviewed-on: https://cl.tvl.fyi/c/depot/+/3110 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
This commit is contained in:
parent
2a97eda3b3
commit
ebf6301941
2 changed files with 139 additions and 15 deletions
|
@ -6,7 +6,28 @@
|
||||||
<link rel="icon" type="image/webp" href="https://tvl.fyi/static/favicon.webp">
|
<link rel="icon" type="image/webp" href="https://tvl.fyi/static/favicon.webp">
|
||||||
<link rel="search" type="application/opensearchdescription+xml" title="TVL Search" href="https://at.tvl.fyi/opensearch.xml">
|
<link rel="search" type="application/opensearchdescription+xml" title="TVL Search" href="https://at.tvl.fyi/opensearch.xml">
|
||||||
<title>TVL Search</title>
|
<title>TVL Search</title>
|
||||||
<body class="light">
|
<script>
|
||||||
|
/* Initialise the state of all settings. */
|
||||||
|
function loadSettings() {
|
||||||
|
loadSetting(document.getElementById('cs-setting'), 'cs');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialise the state of a setting from a cookie. */
|
||||||
|
function loadSetting(checkbox, name) {
|
||||||
|
if (document.cookie.split(';').some(function(cookie) {
|
||||||
|
return cookie.indexOf(`${name}=true`) >= 0;
|
||||||
|
})) {
|
||||||
|
checkbox.checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Persist the state of a checkbox in a cookie */
|
||||||
|
function saveSetting(checkbox, name) {
|
||||||
|
console.log(`setting atward parameter '${name}' to ${checkbox.checked.toString()}`);
|
||||||
|
document.cookie = `${name}=${checkbox.checked.toString()};`;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<body class="light" onload="loadSettings();">
|
||||||
<header>
|
<header>
|
||||||
<h1><a class="blog-title" href="/">atward</a></h1>
|
<h1><a class="blog-title" href="/">atward</a></h1>
|
||||||
<hr/>
|
<hr/>
|
||||||
|
@ -47,12 +68,28 @@
|
||||||
<li><kbd>cs=true</kbd> - use Sourcegraph instead of cgit to view code</li>
|
<li><kbd>cs=true</kbd> - use Sourcegraph instead of cgit to view code</li>
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
<p class="cheddar-callout cheddar-todo">
|
<p>
|
||||||
In <b>Firefox</b>, configuring query parameters is difficult as
|
In some browsers (like Firefox) users can not edit query
|
||||||
users can not edit search engines directly. There are browser
|
parameters for search engines. As an alternative configuration can
|
||||||
extensions and other workarounds for this issue, but we do not
|
be supplied via cookies with the same names as the configuration
|
||||||
recommend any particular one.
|
parameters.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
The form below can set this configuration:
|
||||||
|
<form class="cheddar-callout cheddar-todo">
|
||||||
|
<input type="checkbox"
|
||||||
|
id="cs-setting"
|
||||||
|
onchange="saveSetting(this, 'cs');"
|
||||||
|
> Use Sourcegraph instead of cgit</input>
|
||||||
|
</form>
|
||||||
|
</p>
|
||||||
|
<noscript>
|
||||||
|
<p class="cheddar-callout cheddar-warning">
|
||||||
|
The form above only works with Javascript enabled. Only a few
|
||||||
|
lines of Javascript are used, and they are licensed under a
|
||||||
|
free-software license (MIT).
|
||||||
|
</p>
|
||||||
|
</noscript>
|
||||||
|
|
||||||
<h3>Source code</h3>
|
<h3>Source code</h3>
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
//! browsers and attempts to send users to useful locations based on
|
//! browsers and attempts to send users to useful locations based on
|
||||||
//! their search query (falling back to another search engine).
|
//! their search query (falling back to another search engine).
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use rouille::Response;
|
use rouille::input::cookies;
|
||||||
|
use rouille::{Request, Response};
|
||||||
|
|
||||||
/// A query handler supported by atward. It consists of a pattern on
|
/// A query handler supported by atward. It consists of a pattern on
|
||||||
/// which to match and trigger the query, and a function to execute
|
/// which to match and trigger the query, and a function to execute
|
||||||
|
@ -23,6 +24,7 @@ struct Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An Atward query supplied by a user.
|
/// An Atward query supplied by a user.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
struct Query {
|
struct Query {
|
||||||
/// Query string itself.
|
/// Query string itself.
|
||||||
query: String,
|
query: String,
|
||||||
|
@ -31,19 +33,38 @@ struct Query {
|
||||||
cs: bool,
|
cs: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper function for setting a parameter based on a query
|
||||||
|
/// parameter.
|
||||||
|
fn query_setting(req: &Request, config: &mut bool, param: &str) {
|
||||||
|
match req.get_param(param) {
|
||||||
|
Some(s) if s == "true" => *config = true,
|
||||||
|
Some(s) if s == "false" => *config = false,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Query {
|
impl Query {
|
||||||
fn from_request(req: &rouille::Request) -> Option<Query> {
|
fn from_request(req: &Request) -> Option<Query> {
|
||||||
let query = match req.get_param("q") {
|
// First extract the actual search query ...
|
||||||
Some(q) => q,
|
let mut query = match req.get_param("q") {
|
||||||
|
Some(query) => Query { query, cs: false },
|
||||||
None => return None,
|
None => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let cs = match req.get_param("cs") {
|
// ... then apply settings to it. Settings in query parameters
|
||||||
Some(s) if s == "true" => true,
|
// take precedence over cookies.
|
||||||
_ => false,
|
for cookie in cookies(req) {
|
||||||
};
|
match cookie {
|
||||||
|
("cs", "true") => {
|
||||||
|
query.cs = true;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Some(Query { query, cs })
|
query_setting(req, &mut query.cs, "cs");
|
||||||
|
|
||||||
|
Some(query)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,4 +249,70 @@ mod tests {
|
||||||
None
|
None
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn request_to_query() {
|
||||||
|
assert_eq!(
|
||||||
|
Query::from_request(&Request::fake_http("GET", "/?q=b%2F42", vec![], vec![]))
|
||||||
|
.expect("request should parse to a query"),
|
||||||
|
Query {
|
||||||
|
query: "b/42".to_string(),
|
||||||
|
cs: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Query::from_request(&Request::fake_http("GET", "/", vec![], vec![])),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn settings_from_cookie() {
|
||||||
|
assert_eq!(
|
||||||
|
Query::from_request(&Request::fake_http(
|
||||||
|
"GET",
|
||||||
|
"/?q=b%2F42",
|
||||||
|
vec![("Cookie".to_string(), "cs=true;".to_string())],
|
||||||
|
vec![]
|
||||||
|
))
|
||||||
|
.expect("request should parse to a query"),
|
||||||
|
Query {
|
||||||
|
query: "b/42".to_string(),
|
||||||
|
cs: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn settings_from_query_parameter() {
|
||||||
|
assert_eq!(
|
||||||
|
Query::from_request(&Request::fake_http(
|
||||||
|
"GET",
|
||||||
|
"/?q=b%2F42&cs=true",
|
||||||
|
vec![],
|
||||||
|
vec![]
|
||||||
|
))
|
||||||
|
.expect("request should parse to a query"),
|
||||||
|
Query {
|
||||||
|
query: "b/42".to_string(),
|
||||||
|
cs: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Query parameter should override cookie
|
||||||
|
assert_eq!(
|
||||||
|
Query::from_request(&Request::fake_http(
|
||||||
|
"GET",
|
||||||
|
"/?q=b%2F42&cs=false",
|
||||||
|
vec![("Cookie".to_string(), "cs=true;".to_string())],
|
||||||
|
vec![]
|
||||||
|
))
|
||||||
|
.expect("request should parse to a query"),
|
||||||
|
Query {
|
||||||
|
query: "b/42".to_string(),
|
||||||
|
cs: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue