twitter_archive/structs/screen_name_change.rs
1#!/usr/bin/env rust
2
3//! Tweeter archives as of 2023-08-31 have private data found under;
4//!
5//! twitter-<DATE>-<UID>.zip:data/screen-name-change.js
6//!
7//! ## Example file reader
8//!
9//! ```no_build
10//! use std::io::Read;
11//! use std::{fs, path};
12//! use zip::read::ZipArchive;
13//!
14//! use twitter_archive::structs::screen_name_change;
15//!
16//! fn main() {
17//! let input_file = "~/Downloads/twitter-archive.zip";
18//!
19//! let file_descriptor = fs::File::open(input_file).expect("Unable to read --input-file");
20//! let mut zip_archive = ZipArchive::new(file_descriptor).unwrap();
21//! let mut zip_file = zip_archive.by_name("data/screen-name-change.js").unwrap();
22//! let mut buff = String::new();
23//! zip_file.read_to_string(&mut buff).unwrap();
24//!
25//! let json = buff.replacen("window.YTD.screen_name_change.part0 = ", "", 1);
26//! let data: Vec<screen_name_change::ScreenNameChangeObject> = serde_json::from_str(&json).expect("Unable to parse");
27//!
28//! for (index, object) in data.iter().enumerate() {
29//! /* Do stuff with each ScreenNameChange */
30//! println!("Screen name change index: {index}");
31//! println!("Account ID: {}", object.screen_name_change.account_id);
32//! println!("Changed At: {}", object.screen_name_change.screen_name_change.changed_at);
33//! println!("Changed From: {}", object.screen_name_change.screen_name_change.changed_from);
34//! println!("Changed To: {}", object.screen_name_change.screen_name_change.changed_to);
35//! }
36//! }
37//! ```
38//!
39//! ## Example `twitter-<DATE>-<UID>.zip:data/screen-name-change.js` content
40//!
41//! ```javascript
42//! window.YTD.screen_name_change.part0 = [
43//! {
44//! "screenNameChange" : {
45//! "accountId" : "111111111",
46//! "screenNameChange" : {
47//! "changedAt" : "2023-08-12T17:10:37.000Z",
48//! "changedFrom" : "SomeOneElse",
49//! "changedTo" : "SomeOneNew"
50//! }
51//! }
52//! }
53//! ]
54//! ```
55
56use chrono::{DateTime, Utc};
57use derive_more::Display;
58use serde::{Deserialize, Serialize};
59
60use crate::convert;
61
62/// ## Example
63///
64/// ```
65/// use chrono::{DateTime, NaiveDateTime, Utc};
66///
67/// use twitter_archive::convert::{created_at, date_time_iso_8601};
68///
69/// use twitter_archive::structs::screen_name_change::ScreenNameChangeObject;
70///
71/// let changed_at_string = "2023-08-12T17:10:37.000Z";
72/// let changed_at_native_time = NaiveDateTime::parse_from_str(&changed_at_string, date_time_iso_8601::FORMAT).unwrap();
73/// let changed_at_date_time = DateTime::<Utc>::from_naive_utc_and_offset(changed_at_native_time, Utc);
74///
75/// let json = format!(r#"{{
76/// "screenNameChange": {{
77/// "accountId": "111111111",
78/// "screenNameChange": {{
79/// "changedAt": "{changed_at_string}",
80/// "changedFrom": "SomeOneElse",
81/// "changedTo": "SomeOneNew"
82/// }}
83/// }}
84/// }}"#);
85///
86/// let data: ScreenNameChangeObject = serde_json::from_str(&json).unwrap();
87///
88/// // De-serialized properties
89/// assert_eq!(data.screen_name_change.account_id, "111111111");
90/// assert_eq!(data.screen_name_change.screen_name_change.changed_at, changed_at_date_time);
91/// assert_eq!(data.screen_name_change.screen_name_change.changed_from, "SomeOneElse");
92/// assert_eq!(data.screen_name_change.screen_name_change.changed_to, "SomeOneNew");
93///
94/// // Re-serialize is equivalent to original data
95/// assert_eq!(serde_json::to_string_pretty(&data).unwrap(), json);
96/// ```
97#[derive(Deserialize, Serialize, Debug, Clone, Display)]
98#[display(fmt = "{}", "serde_json::to_value(self).unwrap()")]
99#[serde(rename_all = "camelCase")]
100pub struct ScreenNameChangeObject {
101 /// Why they wrapped a list of name changes within unnecessary object label is anyone's guess
102 ///
103 /// ## Example JSON data
104 ///
105 /// ```json
106 /// {
107 /// "screenNameChange": {
108 /// "accountId": "111111111",
109 /// "screenNameChange": {
110 /// "changedAt": "2023-08-12T17:10:37.000Z",
111 /// "changedFrom": "SomeOneElse",
112 /// "changedTo": "SomeOneNew"
113 /// }
114 /// }
115 /// }
116 /// ```
117 pub screen_name_change: ScreenNameChangeEntry,
118}
119
120/// ## Example
121///
122/// ```
123/// use chrono::{DateTime, NaiveDateTime, Utc};
124///
125/// use twitter_archive::convert::{created_at, date_time_iso_8601};
126///
127/// use twitter_archive::structs::screen_name_change::ScreenNameChangeEntry;
128///
129/// let changed_at_string = "2023-08-12T17:10:37.000Z";
130/// let changed_at_native_time = NaiveDateTime::parse_from_str(&changed_at_string, date_time_iso_8601::FORMAT).unwrap();
131/// let changed_at_date_time = DateTime::<Utc>::from_naive_utc_and_offset(changed_at_native_time, Utc);
132///
133/// let json = format!(r#"{{
134/// "accountId": "111111111",
135/// "screenNameChange": {{
136/// "changedAt": "{changed_at_string}",
137/// "changedFrom": "SomeOneElse",
138/// "changedTo": "SomeOneNew"
139/// }}
140/// }}"#);
141///
142/// let data: ScreenNameChangeEntry = serde_json::from_str(&json).unwrap();
143///
144/// // De-serialized properties
145/// assert_eq!(data.account_id, "111111111");
146/// assert_eq!(data.screen_name_change.changed_at, changed_at_date_time);
147/// assert_eq!(data.screen_name_change.changed_from, "SomeOneElse");
148/// assert_eq!(data.screen_name_change.changed_to, "SomeOneNew");
149///
150/// // Re-serialize is equivalent to original data
151/// assert_eq!(serde_json::to_string_pretty(&data).unwrap(), json);
152/// ```
153#[derive(Deserialize, Serialize, Debug, Clone, Display)]
154#[display(fmt = "{}", "serde_json::to_value(self).unwrap()")]
155#[serde(rename_all = "camelCase")]
156pub struct ScreenNameChangeEntry {
157 /// ## Example JSON data
158 ///
159 /// ```json
160 /// { "accountId": "111111111" }
161 /// ```
162 pub account_id: String,
163
164 /// ## Example JSON data
165 ///
166 /// ```json
167 /// {
168 /// "screenNameChange": {
169 /// "changedAt": "2023-08-12T17:10:37.000Z",
170 /// "changedFrom": "SomeOneElse",
171 /// "changedTo": "SomeOneNew"
172 /// }
173 /// }
174 /// ```
175 pub screen_name_change: ScreenNameChange,
176}
177
178/// ## Example
179///
180/// ```
181/// use chrono::{DateTime, NaiveDateTime, Utc};
182///
183/// use twitter_archive::convert::{created_at, date_time_iso_8601};
184///
185/// use twitter_archive::structs::screen_name_change::ScreenNameChange;
186///
187/// let changed_at_string = "2023-08-12T17:10:37.000Z";
188/// let changed_at_native_time = NaiveDateTime::parse_from_str(&changed_at_string, date_time_iso_8601::FORMAT).unwrap();
189/// let changed_at_date_time = DateTime::<Utc>::from_naive_utc_and_offset(changed_at_native_time, Utc);
190///
191/// let json = format!(r#"{{
192/// "changedAt": "{changed_at_string}",
193/// "changedFrom": "SomeOneElse",
194/// "changedTo": "SomeOneNew"
195/// }}"#);
196///
197/// let data: ScreenNameChange = serde_json::from_str(&json).unwrap();
198///
199/// // De-serialized properties
200/// assert_eq!(data.changed_at, changed_at_date_time);
201/// assert_eq!(data.changed_from, "SomeOneElse");
202/// assert_eq!(data.changed_to, "SomeOneNew");
203///
204/// // Re-serialize is equivalent to original data
205/// assert_eq!(serde_json::to_string_pretty(&data).unwrap(), json);
206/// ```
207#[derive(Deserialize, Serialize, Debug, Clone, Display)]
208#[display(fmt = "{}", "serde_json::to_value(self).unwrap()")]
209#[serde(rename_all = "camelCase")]
210pub struct ScreenNameChange {
211 /// ## Example JSON data
212 ///
213 /// ```json
214 /// { "changedAt": "2023-08-12T17:10:37.000Z" }
215 /// ```
216 #[serde(with = "convert::date_time_iso_8601")]
217 pub changed_at: DateTime<Utc>,
218
219 /// ## Example JSON data
220 ///
221 /// ```json
222 /// { "changedFrom": "SomeOneElse" }
223 /// ```
224 pub changed_from: String,
225
226 /// ## Example JSON data
227 ///
228 /// ```json
229 /// { "changedTo": "SomeOneNew" }
230 /// ```
231 pub changed_to: String,
232}