Add a way to manually mark a certain profile as being from a specific country
This commit is contained in:
parent
db8a85624f
commit
1ac405e5ee
|
@ -15,7 +15,7 @@ Heavily WIP. Doesn't work yet at all, but does read the stream of posts as they
|
||||||
- [x] Handle deleting of posts
|
- [x] Handle deleting of posts
|
||||||
- [x] Handle errors in the web service gracefully
|
- [x] Handle errors in the web service gracefully
|
||||||
- [x] Handle missing profiles in the profile classifier
|
- [x] Handle missing profiles in the profile classifier
|
||||||
- [ ] Add a way to mark a profile as being from a certain country manually
|
- [x] Add a way to mark a profile as being from a certain country manually
|
||||||
- [ ] Handle reconnecting to websocket somehow
|
- [ ] Handle reconnecting to websocket somehow
|
||||||
- [ ] Publish the feed
|
- [ ] Publish the feed
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
extern crate nederlandskie;
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
use clap::Parser;
|
||||||
|
use dotenv::dotenv;
|
||||||
|
|
||||||
|
use nederlandskie::services::{Bluesky, Database};
|
||||||
|
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
struct Args {
|
||||||
|
/// Handle of the user to force the country for
|
||||||
|
#[arg(long)]
|
||||||
|
handle: String,
|
||||||
|
|
||||||
|
/// Country to use, two letters
|
||||||
|
#[arg(long)]
|
||||||
|
country: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
|
dotenv()?;
|
||||||
|
|
||||||
|
let args = Args::parse();
|
||||||
|
|
||||||
|
let database_url =
|
||||||
|
env::var("DATABASE_URL").context("DATABASE_URL environment variable must be set")?;
|
||||||
|
|
||||||
|
let bluesky = Bluesky::new("https://bsky.social");
|
||||||
|
|
||||||
|
let did = bluesky
|
||||||
|
.resolve_handle(&args.handle)
|
||||||
|
.await?
|
||||||
|
.ok_or_else(|| anyhow!("No such user: {}", args.handle))?;
|
||||||
|
|
||||||
|
println!("Resolved handle '{}' to did '{}'", args.handle, did);
|
||||||
|
|
||||||
|
let database = Database::connect(&database_url).await?;
|
||||||
|
|
||||||
|
database.force_profile_country(&did, &args.country).await?;
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Stored '{}' as the country for profile with did '{}'",
|
||||||
|
args.country, did
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -139,6 +139,27 @@ impl Bluesky {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn resolve_handle(&self, handle: &str) -> Result<Option<String>> {
|
||||||
|
use atrium_api::com::atproto::identity::resolve_handle::Parameters;
|
||||||
|
|
||||||
|
let result = self
|
||||||
|
.client
|
||||||
|
.service
|
||||||
|
.com
|
||||||
|
.atproto
|
||||||
|
.identity
|
||||||
|
.resolve_handle(Parameters {
|
||||||
|
handle: handle.to_owned(),
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(result) => Ok(Some(result.did)),
|
||||||
|
Err(e) if is_unable_to_resolve_handle_error(&e) => Ok(None),
|
||||||
|
Err(e) => Err(e.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn subscribe_to_operations<P: CommitProcessor>(
|
pub async fn subscribe_to_operations<P: CommitProcessor>(
|
||||||
&self,
|
&self,
|
||||||
processor: &P,
|
processor: &P,
|
||||||
|
@ -179,3 +200,19 @@ fn is_missing_record_error<T>(error: &atrium_xrpc::error::Error<T>) -> bool {
|
||||||
&& error_message.starts_with("Could not locate record")
|
&& error_message.starts_with("Could not locate record")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_unable_to_resolve_handle_error<T>(error: &atrium_xrpc::error::Error<T>) -> bool {
|
||||||
|
use atrium_xrpc::error::{Error, ErrorResponseBody, XrpcError, XrpcErrorKind};
|
||||||
|
|
||||||
|
matches!(error,
|
||||||
|
Error::XrpcResponse(XrpcError {
|
||||||
|
status: StatusCode::BAD_REQUEST,
|
||||||
|
error:
|
||||||
|
Some(XrpcErrorKind::Undefined(ErrorResponseBody {
|
||||||
|
error: Some(error_code),
|
||||||
|
message: Some(error_message),
|
||||||
|
})),
|
||||||
|
}) if error_code == "InvalidRequest"
|
||||||
|
&& error_message.starts_with("Unable to resolve handle")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -149,6 +149,49 @@ impl Database {
|
||||||
.map(|result| result.rows_affected() > 0)?)
|
.map(|result| result.rows_affected() > 0)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn force_profile_country(
|
||||||
|
&self,
|
||||||
|
did: &str,
|
||||||
|
likely_country_of_living: &str,
|
||||||
|
) -> Result<bool> {
|
||||||
|
let transaction = self.connection_pool.begin().await?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut params = Parameters::new();
|
||||||
|
|
||||||
|
query(
|
||||||
|
&insert_into("Profile")
|
||||||
|
.columns(("did",))
|
||||||
|
.values([params.next()])
|
||||||
|
.on_conflict()
|
||||||
|
.do_nothing()
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
|
.bind(did)
|
||||||
|
.execute(&self.connection_pool)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut params = Parameters::new();
|
||||||
|
query(
|
||||||
|
&update("Profile")
|
||||||
|
.set("has_been_processed", "TRUE")
|
||||||
|
.set("likely_country_of_living", params.next())
|
||||||
|
.where_(format!("did = {}", params.next()))
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
|
.bind(likely_country_of_living)
|
||||||
|
.bind(did)
|
||||||
|
.execute(&self.connection_pool)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.commit().await?;
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn fetch_subscription_cursor(&self, did: &str) -> Result<Option<i32>> {
|
pub async fn fetch_subscription_cursor(&self, did: &str) -> Result<Option<i32>> {
|
||||||
let mut params = Parameters::new();
|
let mut params = Parameters::new();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue