···2626- `app.bsky.feed.like` is the collection
2727- `3mhbs2cnrl22r` is the record key
28282929-Using what you learned from day 1 find the following record {generate the at://uri here} and enter the verification code
2929+Using what you learned from day 1 find the following record `{{at_uri}}` and enter the verification code
3030found in the record
3131for it below
3232
+90-17
shared/src/advent/challenges/day_two.rs
···44};
55use crate::atrium::safe_check_unknown_record_parse;
66use crate::lexicons::codes::advent;
77+use crate::lexicons::record::KnownRecord;
78use crate::{OAuthAgentType, PasswordAgent};
89use async_trait::async_trait;
910use atrium_api::types::Collection;
1111+use serde_json::json;
1012use sqlx::PgPool;
11131214pub struct DayTwo {
···3234 /// We are overriding the start challenge and using extra code
3335 async fn start_challenge(&self, did: String, part: AdventPart) -> Result<String, AdventError> {
3436 let code = get_random_token();
3737+3838+ // For part one, create a record via the challenge agent and store the at_uri
3939+ let additional_context: Option<serde_json::Value> = match part {
4040+ AdventPart::One => {
4141+ match &self.challenge_agent {
4242+ Some(agent) => {
4343+ let agent_did = agent.did().await.ok_or_else(|| {
4444+ AdventError::ShouldNotHappen(
4545+ "Challenge agent has no DID".to_string(),
4646+ )
4747+ })?;
4848+4949+ let record_data = advent::challenge::day::RecordData {
5050+ part_one: code.clone(),
5151+ part_two: None,
5252+ created_at: None,
5353+ };
5454+ let known_record: KnownRecord = record_data.into();
5555+ let record_value: atrium_api::types::Unknown = known_record.into();
5656+5757+ // Use a unique rkey per user based on the did to avoid collisions
5858+ let rkey = did.replace(":", "_").replace(".", "_");
5959+6060+ let put_result = agent
6161+ .api
6262+ .com
6363+ .atproto
6464+ .repo
6565+ .put_record(
6666+ atrium_api::com::atproto::repo::put_record::InputData {
6767+ collection: advent::challenge::Day::NSID.parse().unwrap(),
6868+ repo: agent_did.as_ref().parse().unwrap(),
6969+ rkey: rkey.parse().unwrap(),
7070+ record: record_value,
7171+ swap_commit: None,
7272+ swap_record: None,
7373+ validate: Some(false),
7474+ }
7575+ .into(),
7676+ )
7777+ .await;
7878+7979+ match put_result {
8080+ Ok(output) => Some(json!({"at_uri": output.uri})),
8181+ Err(e) => {
8282+ log::error!("Failed to create challenge record via agent: {e}");
8383+ None
8484+ }
8585+ }
8686+ }
8787+ None => {
8888+ log::warn!("No challenge agent configured, skipping record creation for day two");
8989+ None
9090+ }
9191+ }
9292+ }
9393+ AdventPart::Two => None,
9494+ };
9595+3596 match part {
3636- AdventPart::One => sqlx::query(
3737- "INSERT INTO challenges (user_did, day, time_started, verification_code_one)
3838- VALUES ($1, $2, NOW(), $3)
3939- ON CONFLICT (user_did, day)
4040- DO UPDATE SET verification_code_one = $3
4141- WHERE challenges.user_did = $1 AND challenges.day = $2",
4242- ),
9797+ AdventPart::One => {
9898+ sqlx::query(
9999+ "INSERT INTO challenges (user_did, day, time_started, verification_code_one, additional_context)
100100+ VALUES ($1, $2, NOW(), $3, $4)
101101+ ON CONFLICT (user_did, day)
102102+ DO UPDATE SET verification_code_one = $3, additional_context = $4
103103+ WHERE challenges.user_did = $1 AND challenges.day = $2",
104104+ )
105105+ .bind(&did)
106106+ .bind(self.day() as i16)
107107+ .bind(&code)
108108+ .bind(&additional_context)
109109+ .execute(self.pool())
110110+ .await?;
111111+ }
43112 //TODO just going leave these as an update. It should never ideally be an insert
4444- AdventPart::Two => sqlx::query(
4545- "UPDATE challenges
4646- SET verification_code_two = $3
4747- WHERE challenges.user_did = $1 AND challenges.day = $2",
4848- ),
113113+ AdventPart::Two => {
114114+ sqlx::query(
115115+ "UPDATE challenges
116116+ SET verification_code_two = $3
117117+ WHERE challenges.user_did = $1 AND challenges.day = $2",
118118+ )
119119+ .bind(&did)
120120+ .bind(self.day() as i16)
121121+ .bind(&code)
122122+ .execute(self.pool())
123123+ .await?;
124124+ }
49125 }
5050- .bind(did)
5151- .bind(self.day() as i16)
5252- .bind(code.clone())
5353- .execute(self.pool())
5454- .await?;
126126+55127 Ok(code)
56128 }
129129+57130 async fn check_part_one(
58131 &self,
59132 did: String,
+16-2
shared/src/advent/mod.rs
···135135 fn markdown_text_part_one(
136136 &self,
137137 verification_code: Option<String>,
138138+ additional_context: Option<&serde_json::Value>,
138139 ) -> Result<String, AdventError> {
139140 let day = self.day();
140141···150151151152 let day_one_text = std::str::from_utf8(day_one_file.data.as_ref())?;
152153 let code = verification_code.unwrap_or_else(|| "Login to get a code".to_string());
154154+ let mut context = json!({"code": code});
155155+ if let Some(serde_json::Value::Object(map)) = additional_context {
156156+ if let serde_json::Value::Object(ref mut ctx_map) = context {
157157+ ctx_map.extend(map.iter().map(|(k, v)| (k.clone(), v.clone())));
158158+ }
159159+ }
153160 let handlebar_rendered =
154154- reg.render_template(day_one_text, &json!({"code": code}))?;
161161+ reg.render_template(day_one_text, &context)?;
155162156163 Ok(
157164 markdown::to_html_with_options(&handlebar_rendered, &get_markdown_options())
···165172 fn markdown_text_part_two(
166173 &self,
167174 verification_code: Option<String>,
175175+ additional_context: Option<&serde_json::Value>,
168176 ) -> Result<Option<String>, AdventError> {
169177 match self.get_day_markdown_file(AdventPart::Two)? {
170178 None => Ok(None),
···174182175183 let day_two_text = std::str::from_utf8(day_two_file.data.as_ref())?;
176184 let code = verification_code.unwrap_or_else(|| "Login to get a code".to_string());
185185+ let mut context = json!({"code": code});
186186+ if let Some(serde_json::Value::Object(map)) = additional_context {
187187+ if let serde_json::Value::Object(ref mut ctx_map) = context {
188188+ ctx_map.extend(map.iter().map(|(k, v)| (k.clone(), v.clone())));
189189+ }
190190+ }
177191 let handlebar_rendered =
178178- reg.render_template(day_two_text, &json!({"code": code}))?;
192192+ reg.render_template(day_two_text, &context)?;
179193180194 Ok(Some(
181195 markdown::to_html_with_options(&handlebar_rendered, &get_markdown_options())