DSWQKJRHGLKXUDXKMRXCIQZKEGXYV3H5LPUMGSV4HQ4HYPTI47GQC #[get("/new")]
// TODO decide if this routing file is the place for this guard to be at?#[rocket::async_trait]impl<'r> FromRequest<'r> for User {type Error = ();async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {let db = try_outcome!(request.guard::<&State<Database>>().await);// &State<Database>>().await);let cookies = request.cookies();let some_id = match get_user_id_from_cookie(cookies) {Some(id) => id,None => return Outcome::Failure((Status::Unauthorized, ())),};match User::find(db, some_id).await {Ok(u) => Outcome::Success(u),Err(_e) => Outcome::Failure((Status::Unauthorized, ())),}}}#[get("/new", rank = 2)]
#[derive(FromForm)]struct ChangelistReq {
/// Because of the overlap with other routes in parameters, this route has/// rank 2. This way the changelist matches first, and if it doesn't, this route/// will respond. Note that in the push flow this order is reversed.#[get("/<org_path>/<proj_path>/.pijul?<channel>&<id>", rank = 2)]async fn remote_id(db: &State<Database>,repoman: &State<RepoMan>,org_path: String,proj_path: String,
// TODO figure out how to stream the response, instead of allocating all nowpub fn changelist(&self, channel: String, from: u64) -> Result<String, anyhow::Error> {let txn = self.pristine()?.mut_txn_begin()?;// TODO validate the txn needs closing?// TODO validate the txn needs closing?//// Or does the drop function do that?let chan = match txn.load_channel(&channel)? {Some(c) => c,None => bail!("failed to read channel transaction"),};let mut out: String = "".to_string();for change in txn.log(&chan.read(), from)? {let (offset, (hash, merkle)) = change?;let h: libpijul::Hash = hash.into();let m: libpijul::Merkle = merkle.into();out.push_str(format!("{}.{}.{}", offset, h.to_base32(), m.to_base32()).as_str());}Ok(out)}