Skip to main content

kernoid_client/
account.rs

1// SPDX-License-Identifier: MIT
2//! The account's own everyday settings over kernoid's API (`/v1/account/…`): its name, picture, the language kernoid
3//! writes to it in, and its mail settings. They take a session or an access token of kernoid's apps with the scope
4//! `urn:kernoid:data` (RFC 0001) – not an app password, which gets [`Error::Unauthorized`](crate::Error).
5
6use reqwest::Method;
7use serde::{Deserialize, Serialize};
8use serde_json::json;
9
10use crate::{Body, Client, Error, Result};
11
12fn parse<T: serde::de::DeserializeOwned>(text: &str) -> Result<T> {
13    serde_json::from_str(text).map_err(|error| Error::Protocol(error.to_string()))
14}
15
16/// Changes the account's display name.
17pub async fn set_name(client: &Client, name: &str) -> Result<()> {
18    client.rest(Method::PATCH, "/v1/account", Some(Body::Json(json!({ "display_name": name })))).await?;
19    Ok(())
20}
21
22/// The language kernoid writes its emails to the account in.
23#[derive(Debug, Clone, Deserialize)]
24pub struct Language {
25    /// The account's own choice; none follows the tenant's.
26    pub language: Option<String>,
27    /// What kernoid writes in for the account now.
28    pub used: String,
29    /// The languages kernoid writes in.
30    pub available: Vec<String>,
31}
32
33pub async fn language(client: &Client) -> Result<Language> {
34    parse(&client.rest(Method::GET, "/v1/account/language", None).await?)
35}
36
37/// Chooses the language; `None` follows the tenant's.
38pub async fn set_language(client: &Client, language: Option<&str>) -> Result<()> {
39    client.rest(Method::PUT, "/v1/account/language", Some(Body::Json(json!({ "language": language })))).await?;
40    Ok(())
41}
42
43/// How the account writes mail and how long its Trash keeps it.
44#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)]
45pub struct MailSettings {
46    /// Days the Trash keeps an email; none follows the tenant.
47    pub trash_retention_days: Option<i32>,
48    /// The tenant's days; none keeps emails in the Trash until they are deleted. Only read.
49    #[serde(default, skip_serializing)]
50    pub tenant_trash_retention_days: Option<i32>,
51    /// The address new emails come from; none is the account's primary address.
52    pub default_from: Option<String>,
53    /// Seconds an email waits before it goes out, to be taken back (0 to 30).
54    pub undo_send_seconds: i32,
55}
56
57pub async fn mail_settings(client: &Client) -> Result<MailSettings> {
58    parse(&client.rest(Method::GET, "/v1/account/mail-settings", None).await?)
59}
60
61pub async fn set_mail_settings(client: &Client, settings: &MailSettings) -> Result<()> {
62    let body = serde_json::to_value(settings).map_err(|error| Error::Protocol(error.to_string()))?;
63    client.rest(Method::PUT, "/v1/account/mail-settings", Some(Body::Json(body))).await?;
64    Ok(())
65}
66
67/// Sets the account's picture: a PNG, JPEG or WebP image of up to 1 MiB, best square (the server does not cut it).
68pub async fn set_avatar(client: &Client, image: Vec<u8>, media_type: &str) -> Result<()> {
69    client.rest(Method::PUT, "/v1/account/avatar", Some(Body::Bytes(image, media_type.to_owned()))).await?;
70    Ok(())
71}
72
73pub async fn remove_avatar(client: &Client) -> Result<()> {
74    client.rest(Method::DELETE, "/v1/account/avatar", None).await?;
75    Ok(())
76}
77
78/// The picture of an account of the tenant – the own one too –, or none.
79pub async fn avatar(client: &Client, account: &str) -> Result<Option<Vec<u8>>> {
80    match client.rest_bytes(&format!("/v1/avatars/{}", crate::encode(account))).await {
81        Ok(bytes) => Ok(Some(bytes)),
82        Err(Error::Status(404, _)) => Ok(None),
83        Err(error) => Err(error),
84    }
85}