Skip to content
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
bfdbf01
feat: Opt-in weekly sending of statistics
Hocuri Aug 14, 2025
a1c8beb
small renames
Hocuri Aug 14, 2025
dd3ef4b
fix: Don't reset last_old_contact_id if the user disables&reenables t…
Hocuri Aug 14, 2025
a152d8e
Skip serializing bot, direct_chat, and new if they are false
Hocuri Aug 15, 2025
3ba68a6
Move a struct
Hocuri Aug 15, 2025
4f973be
fix: Looks like yerpc doesn't allow me to have optional parameters
Hocuri Aug 15, 2025
23b8fda
fix: Don't send statistics from a platform other than Android
Hocuri Aug 15, 2025
e283df8
small comment fix
Hocuri Aug 15, 2025
8e3f2e5
cargo fmt
Hocuri Aug 15, 2025
7986b11
clippy
Hocuri Aug 15, 2025
228eda8
Increase sending interval to 1 week
Hocuri Aug 15, 2025
e478341
Document SecurejoinSource
Hocuri Aug 23, 2025
5fac395
refactor: Prefix all relevant configs with `stats`
Hocuri Aug 23, 2025
a3a02e9
some more of iequidoo's suggestions
Hocuri Aug 23, 2025
ebf0a2d
Update src/statistics.rs
Hocuri Aug 25, 2025
7d6aebf
some more of iequidoo's suggestions
Hocuri Aug 23, 2025
c21b8d3
iequidoo's review: Make sure statistics are sent again after rewound …
Hocuri Aug 25, 2025
7ef56d6
iequidoo's review: Rename get_statistics_bot() -> get_statistics_chat…
Hocuri Aug 25, 2025
b77c815
iequidoo's second review
Hocuri Aug 27, 2025
3295ed4
feat: Set the StatsLastSent setting after sending statistics
Hocuri Aug 27, 2025
6c592d9
fix: StatsId is not a bool
Hocuri Aug 27, 2025
c8f58c4
Merge remote-tracking branch 'origin/main' into hoc/send-statistics-s…
Hocuri Sep 18, 2025
52c3157
iequidoo's review
Hocuri Sep 18, 2025
5fc13fd
feat: Make the message statistics aggregate
Hocuri Sep 19, 2025
6d985cd
refactor: Always use "stats", rather than a mix of "statistics" and "…
Hocuri Sep 19, 2025
4c2c312
Small tweaks
Hocuri Sep 19, 2025
e7a6d08
refactor: Extract has_time_passed()
Hocuri Sep 19, 2025
54c4200
Merge remote-tracking branch 'origin/main' into hoc/send-statistics-s…
Hocuri Sep 19, 2025
94a0c14
Merge remote-tracking branch 'origin/main' into hoc/send-statistics-s…
Hocuri Oct 8, 2025
ac370c6
--wip-- [skip ci]
Hocuri Oct 10, 2025
6401875
Make sure that the stats_id is set right after enabling stats sending
Hocuri Oct 10, 2025
dc1f100
iequidoo's review
Hocuri Oct 15, 2025
e745ab0
Update src/config.rs
Hocuri Oct 15, 2025
1bcbb94
Fix tests
Hocuri Oct 16, 2025
749ec74
Merge remote-tracking branch 'origin/main' into hoc/send-statistics-s…
Hocuri Oct 16, 2025
0112010
remove superflous function call
Hocuri Oct 16, 2025
18bf91f
Rename stats_msgs
Hocuri Oct 16, 2025
ee2e91c
Rename wrongly-named stock string
Hocuri Oct 16, 2025
40fd5ae
Rename set_last_counted_msg_id->ensure_last_counted_msg_id
Hocuri Oct 18, 2025
230c058
Use an enum in JsonRPC API
Hocuri Oct 18, 2025
5eadf47
Adapt documentation
Hocuri Oct 18, 2025
d2271e4
Rename SecurejoinUiPath
Hocuri Oct 18, 2025
cbc548c
feat: Record the timestamp of enabling/disabling StatsSending
Hocuri Oct 20, 2025
21ad5d0
feat: Only count messages sent while stats-sending was enabled
Hocuri Oct 20, 2025
f15ba62
refactor: Rename stats_message_body -> stats_msg_body
Hocuri Oct 20, 2025
15a72e3
Update deltachat-jsonrpc/src/api.rs
Hocuri Oct 21, 2025
4925a8c
reviews
Hocuri Oct 21, 2025
b234433
Merge remote-tracking branch 'origin/main' into hoc/send-statistics-s…
Hocuri Oct 21, 2025
e86aae8
Adapt to the removal of protected chats
Hocuri Oct 21, 2025
6799b81
clippy
Hocuri Oct 21, 2025
b95fbc9
fix: Set stats sending interval to 1 week
Hocuri Oct 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
39 changes: 33 additions & 6 deletions deltachat-jsonrpc/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ use self::types::{
},
};
use crate::api::types::chat_list::{get_chat_list_item_by_id, ChatListItemFetchResult};
use crate::api::types::qr::QrObject;
use crate::api::types::qr::{QrObject, SecurejoinSource, SecurejoinUiPath};

#[derive(Debug)]
struct AccountState {
Expand Down Expand Up @@ -393,11 +393,6 @@ impl CommandApi {
Ok(BlobObject::create_and_deduplicate(&ctx, file, file)?.to_abs_path())
}

async fn draft_self_report(&self, account_id: u32) -> Result<u32> {
let ctx = self.get_context(account_id).await?;
Ok(ctx.draft_self_report().await?.to_u32())
}

/// Sets the given configuration key.
async fn set_config(&self, account_id: u32, key: String, value: Option<String>) -> Result<()> {
let ctx = self.get_context(account_id).await?;
Expand Down Expand Up @@ -896,6 +891,38 @@ impl CommandApi {
Ok(chat_id.to_u32())
}

/// Like `secure_join()`, but allows to pass a source and a UI-path.
/// You only need this if your UI has an option to send statistics
/// to Delta Chat's developers.
///
/// **source**: The source where the QR code came from.
/// E.g. a link that was clicked inside or outside Delta Chat,
/// the "Paste from Clipboard" action,
/// the "Load QR code as image" action,
/// or a QR code scan.
///
/// **uipath**: Which UI path did the user use to arrive at the QR code screen.
/// If the SecurejoinSource was ExternalLink or InternalLink,
/// pass null here, because the QR code screen wasn't even opened.
/// ```
async fn secure_join_with_ux_info(
&self,
account_id: u32,
qr: String,
source: Option<SecurejoinSource>,
uipath: Option<SecurejoinUiPath>,
) -> Result<u32> {
let ctx = self.get_context(account_id).await?;
let chat_id = securejoin::join_securejoin_with_ux_info(
&ctx,
&qr,
source.map(Into::into),
uipath.map(Into::into),
)
.await?;
Ok(chat_id.to_u32())
}

async fn leave_group(&self, account_id: u32, chat_id: u32) -> Result<()> {
let ctx = self.get_context(account_id).await?;
remove_contact_from_chat(&ctx, ChatId::new(chat_id), ContactId::SELF).await
Expand Down
51 changes: 51 additions & 0 deletions deltachat-jsonrpc/src/api/types/qr.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use deltachat::qr::Qr;
use serde::Deserialize;
use serde::Serialize;
use typescript_type_def::TypeDef;

Expand Down Expand Up @@ -304,3 +305,53 @@ impl From<Qr> for QrObject {
}
}
}

#[derive(Deserialize, TypeDef, schemars::JsonSchema)]
pub enum SecurejoinSource {
/// Because of some problem, it is unknown where the QR code came from.
Unknown = 0,
/// The user opened a link somewhere outside Delta Chat
ExternalLink = 1,
/// The user clicked on a link in a message inside Delta Chat
InternalLink = 2,
/// The user clicked "Paste from Clipboard" in the QR scan activity
Clipboard = 3,
/// The user clicked "Load QR code as image" in the QR scan activity
ImageLoaded = 4,
/// The user scanned a QR code
Scan = 5,
}

#[derive(Deserialize, TypeDef, schemars::JsonSchema)]
pub enum SecurejoinUiPath {
/// The UI path is unknown, or the user didn't open the QR code screen at all.
Unknown = 0,
/// The user directly clicked on the QR icon in the main screen
QrIcon = 1,
/// The user first clicked on the `+` button in the main screen,
/// and then on "New Contact"
NewContact = 2,
}

impl From<SecurejoinSource> for deltachat::SecurejoinSource {
fn from(value: SecurejoinSource) -> Self {
match value {
SecurejoinSource::Unknown => deltachat::SecurejoinSource::Unknown,
SecurejoinSource::ExternalLink => deltachat::SecurejoinSource::ExternalLink,
SecurejoinSource::InternalLink => deltachat::SecurejoinSource::InternalLink,
SecurejoinSource::Clipboard => deltachat::SecurejoinSource::Clipboard,
SecurejoinSource::ImageLoaded => deltachat::SecurejoinSource::ImageLoaded,
SecurejoinSource::Scan => deltachat::SecurejoinSource::Scan,
}
}
}

impl From<SecurejoinUiPath> for deltachat::SecurejoinUiPath {
fn from(value: SecurejoinUiPath) -> Self {
match value {
SecurejoinUiPath::Unknown => deltachat::SecurejoinUiPath::Unknown,
SecurejoinUiPath::QrIcon => deltachat::SecurejoinUiPath::QrIcon,
SecurejoinUiPath::NewContact => deltachat::SecurejoinUiPath::NewContact,
}
}
}
5 changes: 5 additions & 0 deletions deltachat-time/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ impl SystemTimeTools {
pub fn shift(duration: Duration) {
*SYSTEM_TIME_SHIFT.write().unwrap() += duration;
}

/// Simulates the system clock being rewound by `duration`.
pub fn shift_back(duration: Duration) {
*SYSTEM_TIME_SHIFT.write().unwrap() -= duration;
}
}

#[cfg(test)]
Expand Down
27 changes: 24 additions & 3 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use tokio::fs;

use crate::blob::BlobObject;
use crate::configure::EnteredLoginParam;
use crate::constants;
use crate::context::Context;
use crate::events::EventType;
use crate::log::{LogExt, info};
Expand All @@ -23,6 +22,7 @@ use crate::mimefactory::RECOMMENDED_FILE_SIZE;
use crate::provider::{Provider, get_provider_by_id};
use crate::sync::{self, Sync::*, SyncData};
use crate::tools::get_abs_path;
use crate::{constants, stats};

/// The available configuration keys.
#[derive(
Expand Down Expand Up @@ -414,9 +414,22 @@ pub enum Config {
/// used for signatures, encryption to self and included in `Autocrypt` header.
KeyId,

/// This key is sent to the self_reporting bot so that the bot can recognize the user
/// Send statistics to Delta Chat's developers.
/// Can be exposed to the user as a setting.
StatsSending,

/// Last time statistics were sent to Delta Chat's developers
StatsLastSent,

/// Last time `update_message_stats()` was called
StatsLastUpdate,

/// This key is sent to the statistics bot so that the bot can recognize the user
/// without storing the email address
SelfReportingId,
StatsId,

/// The last contact id that already existed when statistics-sending was enabled for the first time.
StatsLastOldContactId,

/// MsgId of webxdc map integration.
WebxdcIntegration,
Expand Down Expand Up @@ -726,6 +739,14 @@ impl Context {
if key == Config::SentboxWatch {
self.last_full_folder_scan.lock().await.take();
}
if key == Config::StatsSending {
stats::ensure_last_counted_msg_id(self).await?;
stats::set_last_old_contact_id(self).await?;
// Make sure that StatsId is available for the UI,
// in order to open the survey with the StatsId as a parameter:
stats::stats_id(self).await?;
stats::maybe_send_stats(self).await?;
}
Ok(())
}

Expand Down
2 changes: 2 additions & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ pub const DC_CHAT_ID_LAST_SPECIAL: ChatId = ChatId::new(9);
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
FromPrimitive,
ToPrimitive,
FromSql,
Expand Down
Loading