working
This commit is contained in:
parent
e69bcfc23d
commit
b09e8eafbb
16 changed files with 2531 additions and 258 deletions
2004
Cargo.lock
generated
Normal file
2004
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
||||||
|
use restson::{Error, Response, RestClient, RestPath};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use restson::{RestClient, RestPath, Error, Response};
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Serialize)]
|
#[derive(Debug, Copy, Clone, Serialize)]
|
||||||
struct Email<'a> {
|
struct Email<'a> {
|
||||||
|
|
@ -37,8 +37,8 @@ impl<'a> RestPath<()> for Token<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod token {
|
pub mod token {
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
use crate::util::DateTime;
|
use crate::util::DateTime;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|
@ -114,14 +114,25 @@ where
|
||||||
Ok(tokens.into_inner())
|
Ok(tokens.into_inner())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn email<'a>(client: &'a RestClient, email: &'a str, password: &'a str) -> impl Future<Output=Result<Tokens, Error>> + 'a {
|
pub fn email<'a>(
|
||||||
|
client: &'a RestClient,
|
||||||
|
email: &'a str,
|
||||||
|
password: &'a str,
|
||||||
|
) -> impl Future<Output = Result<Tokens, Error>> + 'a {
|
||||||
authenticate(client, Email { email, password })
|
authenticate(client, Email { email, password })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn phone<'a>(client: &'a RestClient, phone: &'a str, password: &'a str) -> impl Future<Output=Result<Tokens, Error>> + 'a {
|
pub fn phone<'a>(
|
||||||
|
client: &'a RestClient,
|
||||||
|
phone: &'a str,
|
||||||
|
password: &'a str,
|
||||||
|
) -> impl Future<Output = Result<Tokens, Error>> + 'a {
|
||||||
authenticate(client, Phone { phone, password })
|
authenticate(client, Phone { phone, password })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn token<'a>(client: &'a RestClient, token: &'a str) -> impl Future<Output=Result<Tokens, Error>> + 'a {
|
pub fn token<'a>(
|
||||||
|
client: &'a RestClient,
|
||||||
|
token: &'a str,
|
||||||
|
) -> impl Future<Output = Result<Tokens, Error>> + 'a {
|
||||||
authenticate(client, Token { token })
|
authenticate(client, Token { token })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,16 +58,13 @@ impl<'a> Query<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
#[derive(Default)]
|
||||||
pub enum Order {
|
pub enum Order {
|
||||||
|
#[default]
|
||||||
Ascending,
|
Ascending,
|
||||||
Descending,
|
Descending,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Order {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Ascending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for Order {
|
impl std::fmt::Display for Order {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,5 @@ pub async fn identity(client: &RestClient) -> Result<Profile, Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn with_id(client: &RestClient, id: Id) -> Result<Profile, Error> {
|
pub async fn with_id(client: &RestClient, id: Id) -> Result<Profile, Error> {
|
||||||
Ok(client
|
Ok(client.get_with::<_, Profile>(id, &[]).await?.into_inner())
|
||||||
.get_with::<_, Profile>(id, &[])
|
|
||||||
.await?
|
|
||||||
.into_inner())
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,13 +64,10 @@ impl Spond {
|
||||||
#[builder]
|
#[builder]
|
||||||
pub fn response(
|
pub fn response(
|
||||||
&self,
|
&self,
|
||||||
#[builder(start_fn)]
|
#[builder(start_fn)] member: MemberId,
|
||||||
member: MemberId,
|
#[builder(finish_fn)] client: &RestClient,
|
||||||
#[builder(finish_fn)]
|
#[builder(default = true)] accepted: bool,
|
||||||
client: &RestClient,
|
) -> impl Future<Output = Result<Responses, Error>> {
|
||||||
#[builder(default = true)]
|
|
||||||
accepted: bool,
|
|
||||||
) -> impl Future<Output=Result<Responses, Error>> {
|
|
||||||
response(self.id)
|
response(self.id)
|
||||||
.member(member)
|
.member(member)
|
||||||
.accepted(accepted)
|
.accepted(accepted)
|
||||||
|
|
@ -78,27 +75,21 @@ impl Spond {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[builder]
|
#[builder]
|
||||||
pub fn accept(&self,
|
pub fn accept(
|
||||||
#[builder(start_fn)]
|
&self,
|
||||||
member: MemberId,
|
#[builder(start_fn)] member: MemberId,
|
||||||
#[builder(finish_fn)]
|
#[builder(finish_fn)] client: &RestClient,
|
||||||
client: &RestClient,
|
) -> impl Future<Output = Result<Responses, Error>> {
|
||||||
) -> impl Future<Output=Result<Responses, Error>> {
|
self.response(member).accepted(true).call(client)
|
||||||
self.response(member)
|
|
||||||
.accepted(true)
|
|
||||||
.call(client)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[builder]
|
#[builder]
|
||||||
pub fn decline(&self,
|
pub fn decline(
|
||||||
#[builder(start_fn)]
|
&self,
|
||||||
member: MemberId,
|
#[builder(start_fn)] member: MemberId,
|
||||||
#[builder(finish_fn)]
|
#[builder(finish_fn)] client: &RestClient,
|
||||||
client: &RestClient,
|
) -> impl Future<Output = Result<Responses, Error>> {
|
||||||
) -> impl Future<Output=Result<Responses, Error>> {
|
self.response(member).accepted(false).call(client)
|
||||||
self.response(member)
|
|
||||||
.accepted(false)
|
|
||||||
.call(client)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -198,11 +189,8 @@ pub fn decline(
|
||||||
#[builder(start_fn)] spond: Id,
|
#[builder(start_fn)] spond: Id,
|
||||||
#[builder(finish_fn)] client: &RestClient,
|
#[builder(finish_fn)] client: &RestClient,
|
||||||
member: MemberId,
|
member: MemberId,
|
||||||
) -> impl std::future::Future<Output=Result<Responses, Error>> {
|
) -> impl std::future::Future<Output = Result<Responses, Error>> {
|
||||||
response(spond)
|
response(spond).member(member).accepted(false).call(client)
|
||||||
.member(member)
|
|
||||||
.accepted(false)
|
|
||||||
.call(client)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bon::builder]
|
#[bon::builder]
|
||||||
|
|
@ -210,11 +198,8 @@ pub fn accept(
|
||||||
#[builder(start_fn)] spond: Id,
|
#[builder(start_fn)] spond: Id,
|
||||||
#[builder(finish_fn)] client: &RestClient,
|
#[builder(finish_fn)] client: &RestClient,
|
||||||
member: MemberId,
|
member: MemberId,
|
||||||
) -> impl std::future::Future<Output=Result<Responses, Error>> {
|
) -> impl std::future::Future<Output = Result<Responses, Error>> {
|
||||||
response(spond)
|
response(spond).member(member).accepted(true).call(client)
|
||||||
.member(member)
|
|
||||||
.accepted(true)
|
|
||||||
.call(client)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bon::builder]
|
#[bon::builder]
|
||||||
|
|
@ -236,7 +221,8 @@ pub async fn response(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let request = Request{accepted};
|
let request = Request { accepted };
|
||||||
let response: restson::Response<Responses> = client.put_capture((spond, member), &request).await?;
|
let response: restson::Response<Responses> =
|
||||||
|
client.put_capture((spond, member), &request).await?;
|
||||||
Ok(response.into_inner())
|
Ok(response.into_inner())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
33
api/src/util/chrono/datetime.rs
Normal file
33
api/src/util/chrono/datetime.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
use serde::{Deserialize, Serialize, Serializer};
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Deserialize)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub struct DateTime(chrono::DateTime<chrono::Utc>);
|
||||||
|
|
||||||
|
impl Serialize for DateTime {
|
||||||
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
serializer.serialize_str(&self.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DateTime {
|
||||||
|
fn default() -> Self {
|
||||||
|
chrono::Utc::now().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for DateTime {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
self.0.to_rfc3339_opts(chrono::SecondsFormat::Secs, true,)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<chrono::DateTime<chrono::Utc>> for DateTime {
|
||||||
|
fn from(dt: chrono::DateTime<chrono::Utc>) -> Self {
|
||||||
|
Self(dt)
|
||||||
|
}
|
||||||
|
}
|
||||||
5
api/src/util/chrono/mod.rs
Normal file
5
api/src/util/chrono/mod.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
mod datetime;
|
||||||
|
pub use datetime::DateTime;
|
||||||
|
|
||||||
|
mod timestamp;
|
||||||
|
pub use timestamp::Timestamp;
|
||||||
51
api/src/util/chrono/timestamp.rs
Normal file
51
api/src/util/chrono/timestamp.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
use chrono::TimeZone;
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer}; // for timestamp_millis_opt
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Timestamp(chrono::DateTime<chrono::Utc>);
|
||||||
|
|
||||||
|
impl Serialize for Timestamp {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_i64(self.0.timestamp_millis())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Timestamp {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let millis = i64::deserialize(deserializer)?;
|
||||||
|
let dt = chrono::Utc
|
||||||
|
.timestamp_millis_opt(millis)
|
||||||
|
.single()
|
||||||
|
.ok_or_else(|| serde::de::Error::custom("invalid timestamp"))?;
|
||||||
|
|
||||||
|
Ok(Timestamp(dt))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Timestamp {
|
||||||
|
fn default() -> Self {
|
||||||
|
chrono::Utc::now().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Timestamp {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
self.0.to_rfc3339_opts(chrono::SecondsFormat::Secs, true,)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Into<chrono::DateTime<chrono::Utc>>> From<I> for Timestamp {
|
||||||
|
fn from(dt: I) -> Self {
|
||||||
|
Self(dt.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
114
api/src/util/id.rs
Normal file
114
api/src/util/id.rs
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
use std::fmt;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
fn short_type_name(full: &str) -> &str {
|
||||||
|
let generic = full.find('<').unwrap_or(full.len());
|
||||||
|
let last_colon = full[..generic].rfind("::").map_or(0, |idx| idx + 2);
|
||||||
|
|
||||||
|
&full[last_colon..]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Type: Sized {
|
||||||
|
type Type: fmt::Display + Copy;
|
||||||
|
|
||||||
|
fn name() -> &'static str {
|
||||||
|
short_type_name(std::any::type_name::<Self>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Id<T: Type>(T::Type);
|
||||||
|
|
||||||
|
impl<T: Type> AsRef<T::Type> for Id<T> {
|
||||||
|
fn as_ref(&self) -> &T::Type {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Type> Copy for Id<T> {}
|
||||||
|
|
||||||
|
impl<T: Type> Clone for Id<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Type> Id<T> {
|
||||||
|
pub fn new(src: T::Type) -> Self {
|
||||||
|
Self(src)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn load(
|
||||||
|
&self,
|
||||||
|
client: &restson::RestClient,
|
||||||
|
) -> Result<T, restson::Error>
|
||||||
|
where
|
||||||
|
T: restson::RestPath<Id<T>>,
|
||||||
|
T: serde::de::DeserializeOwned,
|
||||||
|
{ Ok(client.get_with::<_, T>(*self, &[]).await?.into_inner()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Type> fmt::Debug for Id<T>
|
||||||
|
where
|
||||||
|
T::Type: fmt::Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "ID<{}:{}>", T::name(), self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Type> fmt::Display for Id<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Serialize for Id<T>
|
||||||
|
where
|
||||||
|
T: Type,
|
||||||
|
T::Type: Serialize,
|
||||||
|
{
|
||||||
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
self.0.serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, T> Deserialize<'de> for Id<T>
|
||||||
|
where
|
||||||
|
T: Type,
|
||||||
|
T::Type: Deserialize<'de>,
|
||||||
|
{
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
Ok(Self(T::Type::deserialize(deserializer)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PartialEq for Id<T>
|
||||||
|
where
|
||||||
|
T: Type,
|
||||||
|
T::Type: PartialEq,
|
||||||
|
{
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.0 == other.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Eq for Id<T>
|
||||||
|
where
|
||||||
|
T: Type,
|
||||||
|
T::Type: Eq,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Hash for Id<T>
|
||||||
|
where
|
||||||
|
T: Type,
|
||||||
|
T::Type: Hash,
|
||||||
|
{
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.0.hash(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
11
api/src/util/mod.rs
Normal file
11
api/src/util/mod.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
pub mod chrono;
|
||||||
|
pub use chrono::{DateTime, Timestamp};
|
||||||
|
|
||||||
|
pub mod x128;
|
||||||
|
pub use x128::X128;
|
||||||
|
|
||||||
|
pub mod id;
|
||||||
|
pub use id::Id;
|
||||||
|
|
||||||
|
pub mod visibility;
|
||||||
|
pub use visibility::Visibility;
|
||||||
36
api/src/util/visibility.rs
Normal file
36
api/src/util/visibility.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum Visibility {
|
||||||
|
Invitees,
|
||||||
|
Unknown(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for Visibility {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let s = match self {
|
||||||
|
Visibility::Invitees => "INVITEES",
|
||||||
|
Visibility::Unknown(other) => other,
|
||||||
|
};
|
||||||
|
|
||||||
|
serializer.serialize_str(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Visibility {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
// Borrow when possible
|
||||||
|
let s = <&str>::deserialize(deserializer)?;
|
||||||
|
|
||||||
|
Ok(match s {
|
||||||
|
"INVITEES" => Visibility::Invitees,
|
||||||
|
other => Visibility::Unknown(other.to_owned()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
84
api/src/util/x128.rs
Normal file
84
api/src/util/x128.rs
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
use std::fmt;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
/// Wrapper for u128 that serializes/deserializes as 32-charachter hex
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
|
pub struct X128(u128);
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("invalid length: {0}")]
|
||||||
|
Length(usize),
|
||||||
|
|
||||||
|
#[error("parser error: {0}")]
|
||||||
|
Parser(#[from] std::num::ParseIntError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl X128 {
|
||||||
|
/// construct a new value
|
||||||
|
pub fn new(value: u128) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// access the inner value explicitely
|
||||||
|
pub fn value(&self) -> u128 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Into<u128>> From<T> for X128 {
|
||||||
|
fn from(src: T) -> Self {
|
||||||
|
Self::new(src.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for X128 {
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Error> {
|
||||||
|
match s.len() {
|
||||||
|
32 => u128::from_str_radix(s, 16)
|
||||||
|
.map(Self::new)
|
||||||
|
.map_err(Error::Parser),
|
||||||
|
len => Err(Error::Length(len)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//impl TryFrom<&str> for X128 {
|
||||||
|
// type Error = Error;
|
||||||
|
//
|
||||||
|
// fn try_from(s: &str) -> Result<Self, Error> {
|
||||||
|
// Self::from_str(s)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
impl Deref for X128 {
|
||||||
|
type Target = u128;
|
||||||
|
|
||||||
|
fn deref(&self) -> &u128 {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for X128 {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{:032X}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for X128 {
|
||||||
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
serializer.serialize_str(&self.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for X128 {
|
||||||
|
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||||
|
let s = String::deserialize(deserializer)?;
|
||||||
|
|
||||||
|
Self::from_str(&s).map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "tb-rs"
|
name = "tb-spond-rs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
|
@ -20,7 +20,6 @@ serde_json = "1.0.149"
|
||||||
serde_qs = "1.0.0"
|
serde_qs = "1.0.0"
|
||||||
spond-api = { version = "0.1.0", path = "../api" }
|
spond-api = { version = "0.1.0", path = "../api" }
|
||||||
thiserror = "2.0.18"
|
thiserror = "2.0.18"
|
||||||
#spond-macros = { version = "0.1.0", path = "../macros" }
|
|
||||||
tokio = { version = "1.49.0", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.49.0", features = ["macros", "rt-multi-thread"] }
|
||||||
url = "2.5.8"
|
url = "2.5.8"
|
||||||
xdg = "3.0.0"
|
xdg = "3.0.0"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use clap::{Args, ArgGroup};
|
use anyhow::{Error, Result};
|
||||||
|
use clap::{ArgGroup, Args};
|
||||||
use restson::RestClient;
|
use restson::RestClient;
|
||||||
use anyhow::{Result, Error};
|
use std::str::FromStr;
|
||||||
use std::str::{FromStr};
|
|
||||||
|
|
||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug)]
|
||||||
#[command(group(
|
#[command(group(
|
||||||
|
|
@ -29,13 +29,24 @@ fn bearer(mut client: RestClient, token: &str) -> Result<RestClient> {
|
||||||
|
|
||||||
impl Authentication {
|
impl Authentication {
|
||||||
pub async fn apply(&self, client: RestClient) -> Result<RestClient> {
|
pub async fn apply(&self, client: RestClient) -> Result<RestClient> {
|
||||||
let client = match (self.access.as_ref(), self.refresh.as_ref(), self.email.as_ref(), self.phone.as_ref()) {
|
let client = match (
|
||||||
(Some(ref v), None, None, None) => v.apply(client)?,
|
self.access.as_ref(),
|
||||||
(None, Some(ref v), None, None) => v.apply(client).await?,
|
self.refresh.as_ref(),
|
||||||
(None, None, Some(ref v), None) => v.apply(client).await?,
|
self.email.as_ref(),
|
||||||
(None, None, None, Some(ref v)) => v.apply(client).await?,
|
self.phone.as_ref(),
|
||||||
|
) {
|
||||||
|
(Some(v), None, None, None) => v.apply(client)?,
|
||||||
|
(None, Some(v), None, None) => v.apply(client).await?,
|
||||||
|
(None, None, Some(v), None) => v.apply(client).await?,
|
||||||
|
(None, None, None, Some(v)) => v.apply(client).await?,
|
||||||
(None, None, None, None) => client,
|
(None, None, None, None) => client,
|
||||||
(a, b, c, d) => anyhow::bail!("invalid authentication: {} + {} + {} + {}", a.is_some(), b.is_some(), c.is_some(), d.is_some()),
|
(a, b, c, d) => anyhow::bail!(
|
||||||
|
"invalid authentication: {} + {} + {} + {}",
|
||||||
|
a.is_some(),
|
||||||
|
b.is_some(),
|
||||||
|
c.is_some(),
|
||||||
|
d.is_some()
|
||||||
|
),
|
||||||
};
|
};
|
||||||
Ok(client)
|
Ok(client)
|
||||||
}
|
}
|
||||||
|
|
@ -63,12 +74,13 @@ impl FromStr for WithPassword {
|
||||||
struct Email(WithPassword);
|
struct Email(WithPassword);
|
||||||
impl Email {
|
impl Email {
|
||||||
async fn apply(&self, client: RestClient) -> Result<RestClient> {
|
async fn apply(&self, client: RestClient) -> Result<RestClient> {
|
||||||
let tokens = spond_api::authentication::email(&client, &self.0.value, &self.0.password).await?;
|
let tokens =
|
||||||
|
spond_api::authentication::email(&client, &self.0.value, &self.0.password).await?;
|
||||||
bearer(client, tokens.access.token.as_ref())
|
bearer(client, tokens.access.token.as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl FromStr for Email {
|
impl FromStr for Email {
|
||||||
type Err= <WithPassword as FromStr>::Err;
|
type Err = <WithPassword as FromStr>::Err;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
Ok(Self(WithPassword::from_str(s)?))
|
Ok(Self(WithPassword::from_str(s)?))
|
||||||
|
|
@ -79,12 +91,13 @@ impl FromStr for Email {
|
||||||
struct Phone(WithPassword);
|
struct Phone(WithPassword);
|
||||||
impl Phone {
|
impl Phone {
|
||||||
async fn apply(&self, client: RestClient) -> Result<RestClient> {
|
async fn apply(&self, client: RestClient) -> Result<RestClient> {
|
||||||
let tokens = spond_api::authentication::phone(&client, &self.0.value, &self.0.password).await?;
|
let tokens =
|
||||||
|
spond_api::authentication::phone(&client, &self.0.value, &self.0.password).await?;
|
||||||
bearer(client, tokens.access.token.as_ref())
|
bearer(client, tokens.access.token.as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl FromStr for Phone {
|
impl FromStr for Phone {
|
||||||
type Err= <WithPassword as FromStr>::Err;
|
type Err = <WithPassword as FromStr>::Err;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
Ok(Self(WithPassword::from_str(s)?))
|
Ok(Self(WithPassword::from_str(s)?))
|
||||||
|
|
|
||||||
171
cli/src/main.rs
171
cli/src/main.rs
|
|
@ -1,8 +1,8 @@
|
||||||
|
use anyhow::Result;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use restson::RestClient;
|
use restson::RestClient;
|
||||||
use anyhow::Result;
|
|
||||||
use url::Url;
|
|
||||||
use spond_api as api;
|
use spond_api as api;
|
||||||
|
use url::Url;
|
||||||
use xdg::BaseDirectories as xdg;
|
use xdg::BaseDirectories as xdg;
|
||||||
|
|
||||||
mod authentication;
|
mod authentication;
|
||||||
|
|
@ -33,7 +33,7 @@ impl Cli {
|
||||||
pub async fn client(&self) -> Result<RestClient> {
|
pub async fn client(&self) -> Result<RestClient> {
|
||||||
let base = self.base.join("/core/v1/")?;
|
let base = self.base.join("/core/v1/")?;
|
||||||
let client = RestClient::new(base.as_str())?;
|
let client = RestClient::new(base.as_str())?;
|
||||||
Ok(self.authentication.apply(client).await?)
|
self.authentication.apply(client).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ struct Seed(u64);
|
||||||
|
|
||||||
impl Default for Seed {
|
impl Default for Seed {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
use rand::{rng, RngExt};
|
use rand::{RngExt, rng};
|
||||||
Self(rng().random())
|
Self(rng().random())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -68,11 +68,11 @@ impl std::fmt::Display for Seed {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Seed {
|
impl Seed {
|
||||||
pub fn shuffle<'a, T, F, W>(&self, input: &'a [T], weight: F) -> Result<Vec<T>>
|
pub fn shuffle<T, F, W>(&self, input: &[T], weight: F) -> Result<Vec<T>>
|
||||||
where
|
where
|
||||||
F: Fn(T) -> W,
|
F: Fn(T) -> W,
|
||||||
W: Into<f64>,
|
W: Into<f64>,
|
||||||
T: Copy
|
T: Copy,
|
||||||
{
|
{
|
||||||
use rand::{SeedableRng, rngs::StdRng};
|
use rand::{SeedableRng, rngs::StdRng};
|
||||||
let len = input.len();
|
let len = input.len();
|
||||||
|
|
@ -89,7 +89,6 @@ impl Seed {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Weights<Id>(std::collections::HashMap<Id, usize>);
|
struct Weights<Id>(std::collections::HashMap<Id, usize>);
|
||||||
|
|
||||||
|
|
@ -135,33 +134,30 @@ where
|
||||||
|
|
||||||
impl<Id> Weights<Id>
|
impl<Id> Weights<Id>
|
||||||
where
|
where
|
||||||
Id: Eq + Hash + Copy + serde::de::DeserializeOwned
|
Id: Eq + Hash + Copy + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
pub fn load(serie: api::SeriesId) -> Result<Self> {
|
pub fn load(serie: api::SeriesId) -> Result<Self> {
|
||||||
let path = Self::path(serie)?;
|
let path = Self::path(serie)?;
|
||||||
log::debug!("load {path:?}");
|
log::debug!("load {path:?}");
|
||||||
let file = std::fs::OpenOptions::new()
|
let file = std::fs::OpenOptions::new().read(true).open(path)?;
|
||||||
.read(true)
|
|
||||||
.open(path)?;
|
|
||||||
|
|
||||||
let data: std::collections::HashMap<Id, usize> = serde_json::from_reader(file)?;
|
let data: std::collections::HashMap<Id, usize> = serde_json::from_reader(file)?;
|
||||||
Ok(Self(data))
|
Ok(Self(data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<Id> Weights<Id>
|
impl<Id> Weights<Id>
|
||||||
where
|
where
|
||||||
Id: Eq + Hash + Copy + serde::Serialize
|
Id: Eq + Hash + Copy + serde::Serialize,
|
||||||
{
|
{
|
||||||
pub fn store(&self, serie: api::SeriesId) -> Result<()> {
|
pub fn store(&self, serie: api::SeriesId) -> Result<()> {
|
||||||
use std::fs::{File, rename};
|
use std::fs::{File, rename};
|
||||||
use std::io::{BufWriter, Write};
|
use std::io::{BufWriter, Write};
|
||||||
|
|
||||||
|
|
||||||
let path = Self::path(serie)?;
|
let path = Self::path(serie)?;
|
||||||
log::debug!("store {path:?}");
|
log::debug!("store {path:?}");
|
||||||
let tmp = path.with_extension("json.tmp");
|
let tmp = path.with_extension("json.tmp");
|
||||||
|
log::trace!("temporary: {tmp:?}");
|
||||||
|
|
||||||
// create temporary file
|
// create temporary file
|
||||||
let file = File::create(&tmp)?;
|
let file = File::create(&tmp)?;
|
||||||
|
|
@ -180,6 +176,7 @@ where
|
||||||
drop(writer);
|
drop(writer);
|
||||||
|
|
||||||
// atomic replace old file
|
// atomic replace old file
|
||||||
|
log::trace!("rename {tmp:?} -> {path:?}");
|
||||||
rename(&tmp, &path)?;
|
rename(&tmp, &path)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -195,12 +192,14 @@ async fn main() -> Result<()> {
|
||||||
let series = cli.series.map(api::SeriesId::new);
|
let series = cli.series.map(api::SeriesId::new);
|
||||||
let heading = cli.heading.as_ref();
|
let heading = cli.heading.as_ref();
|
||||||
let vip: Vec<api::MemberId> = if let Some(ref vip) = cli.vip {
|
let vip: Vec<api::MemberId> = if let Some(ref vip) = cli.vip {
|
||||||
vip.into_iter().map(|id| api::MemberId::new(*id)).collect()
|
vip.iter().map(|id| api::MemberId::new(*id)).collect()
|
||||||
} else {
|
} else {
|
||||||
[
|
[
|
||||||
0xEB07B45E45E6449386E70A7411816B6Fu128,
|
0xEB07B45E45E6449386E70A7411816B6Fu128,
|
||||||
0xD05F8574AC544C8DB1A7DC5B6347AA49u128,
|
0xD05F8574AC544C8DB1A7DC5B6347AA49u128,
|
||||||
].map(|x| api::MemberId::new(x.into())).into()
|
]
|
||||||
|
.map(|x| api::MemberId::new(x.into()))
|
||||||
|
.into()
|
||||||
};
|
};
|
||||||
let client = cli.client().await?;
|
let client = cli.client().await?;
|
||||||
let client = &client;
|
let client = &client;
|
||||||
|
|
@ -213,7 +212,6 @@ async fn main() -> Result<()> {
|
||||||
log::info!("heading: {heading}");
|
log::info!("heading: {heading}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if true {
|
|
||||||
let now = chrono::Utc::now();
|
let now = chrono::Utc::now();
|
||||||
let sponds = api::spond::search()
|
let sponds = api::spond::search()
|
||||||
.include_comments(true)
|
.include_comments(true)
|
||||||
|
|
@ -221,16 +219,22 @@ async fn main() -> Result<()> {
|
||||||
.max(1000)
|
.max(1000)
|
||||||
.min_start_timestamp(now)
|
.min_start_timestamp(now)
|
||||||
.max_end_timestamp(now + chrono::Duration::weeks(1))
|
.max_end_timestamp(now + chrono::Duration::weeks(1))
|
||||||
.call(client).await?;
|
.call(client)
|
||||||
|
.await?;
|
||||||
|
|
||||||
for spond in sponds.iter()
|
for spond in sponds.iter().filter(|spond| {
|
||||||
.filter(|spond| {
|
let result = series
|
||||||
let result = series.is_none_or(|series| spond.series_id.is_some_and(|remote| remote == series))
|
.is_none_or(|series| spond.series_id.is_some_and(|remote| remote == series))
|
||||||
&& heading.is_none_or(|heading| spond.heading == *heading);
|
&& heading.is_none_or(|heading| spond.heading == *heading);
|
||||||
log::trace!("{}: {:?} == {:?} => {:?}", spond.heading, spond.series_id, series, result);
|
log::trace!(
|
||||||
|
"{}: {:?} == {:?} => {:?}",
|
||||||
|
spond.heading,
|
||||||
|
spond.series_id,
|
||||||
|
series,
|
||||||
result
|
result
|
||||||
})
|
);
|
||||||
{
|
result
|
||||||
|
}) {
|
||||||
log::debug!("{:?}", spond.responses);
|
log::debug!("{:?}", spond.responses);
|
||||||
|
|
||||||
let spond = &spond;
|
let spond = &spond;
|
||||||
|
|
@ -243,20 +247,27 @@ async fn main() -> Result<()> {
|
||||||
spond.accept(*id).call(client)
|
spond.accept(*id).call(client)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut weights = spond.series_id.and_then(|series| Weights::load(series).ok()).unwrap_or_else(Weights::default);
|
let mut weights = spond
|
||||||
|
.series_id
|
||||||
|
.and_then(|series| Weights::load(series).ok())
|
||||||
|
.unwrap_or_else(Weights::default);
|
||||||
log::info!("{weights:?}");
|
log::info!("{weights:?}");
|
||||||
|
|
||||||
let (vip, interested) = {
|
let (vip, interested) = {
|
||||||
let mut r = (Vec::new(), Vec::new());
|
let mut r = (Vec::new(), Vec::new());
|
||||||
for id in spond.responses.accepted_ids.iter()
|
for id in spond
|
||||||
.chain(spond.responses.waitinglist_ids.iter()) {
|
.responses
|
||||||
|
.accepted_ids
|
||||||
|
.iter()
|
||||||
|
.chain(spond.responses.waitinglist_ids.iter())
|
||||||
|
{
|
||||||
(if vip.contains(id) { &mut r.0 } else { &mut r.1 }).push(*id);
|
(if vip.contains(id) { &mut r.0 } else { &mut r.1 }).push(*id);
|
||||||
}
|
}
|
||||||
(r.0, seed.shuffle(&r.1, |idx| weights.weight(idx))?)
|
(r.0, seed.shuffle(&r.1, |idx| weights.weight(idx))?)
|
||||||
};
|
};
|
||||||
|
|
||||||
// remove all registered participants
|
// remove all registered participants
|
||||||
let results = futures::future::join_all(interested.iter().map(|id|decline(id))).await;
|
let results = futures::future::join_all(interested.iter().map(&decline)).await;
|
||||||
log::debug!("{results:?}");
|
log::debug!("{results:?}");
|
||||||
|
|
||||||
// register them in order
|
// register them in order
|
||||||
|
|
@ -275,19 +286,27 @@ async fn main() -> Result<()> {
|
||||||
log::debug!("vip: {vip:?}");
|
log::debug!("vip: {vip:?}");
|
||||||
log::debug!("interested: {interested:?}");
|
log::debug!("interested: {interested:?}");
|
||||||
log::debug!("extra: {extra:?}");
|
log::debug!("extra: {extra:?}");
|
||||||
let reorder = responses.accepted_ids.iter()
|
let reorder = responses
|
||||||
|
.accepted_ids
|
||||||
|
.iter()
|
||||||
.chain(responses.waitinglist_ids.iter())
|
.chain(responses.waitinglist_ids.iter())
|
||||||
.filter(|id| !(vip.contains(*id) || interested.contains(*id) || extra.contains(*id)))
|
.filter(|id| {
|
||||||
|
!(vip.contains(*id)
|
||||||
|
|| interested.contains(*id)
|
||||||
|
|| extra.contains(*id))
|
||||||
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
if reorder.is_empty() {
|
if reorder.is_empty() {
|
||||||
let update = interested.iter()
|
let update = interested
|
||||||
|
.iter()
|
||||||
.filter(|id| responses.waitinglist_ids.contains(id))
|
.filter(|id| responses.waitinglist_ids.contains(id))
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
break Ok::<Vec<api::MemberId>, anyhow::Error>(update);
|
break Ok::<Vec<api::MemberId>, anyhow::Error>(update);
|
||||||
}
|
}
|
||||||
let futures = futures::future::join_all(reorder.iter().map(|id|decline(id))).await;
|
let futures =
|
||||||
|
futures::future::join_all(reorder.iter().map(&decline)).await;
|
||||||
log::debug!("{futures:?}");
|
log::debug!("{futures:?}");
|
||||||
|
|
||||||
for id in reorder.into_iter() {
|
for id in reorder.into_iter() {
|
||||||
|
|
@ -308,95 +327,9 @@ async fn main() -> Result<()> {
|
||||||
log::debug!("{weights:?}");
|
log::debug!("{weights:?}");
|
||||||
|
|
||||||
if let Some(series) = spond.series_id {
|
if let Some(series) = spond.series_id {
|
||||||
let _ = weights.store(series)?;
|
weights.store(series)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//for member in spond.responses.accepted_ids.iter()
|
|
||||||
// .chain(spond.responses.waitinglist_ids.iter()) {
|
|
||||||
// let result = map.insert(member, 1);
|
|
||||||
// println!("{:?}: {:?}", member, result);
|
|
||||||
//}
|
|
||||||
//println!("{:?}", map);
|
|
||||||
//println!("{:?}", &spond.responses);
|
|
||||||
//let response = spond.response(member)
|
|
||||||
// .accepted(false)
|
|
||||||
// .call(&client)
|
|
||||||
// .await?;
|
|
||||||
//println!("{:?}", &response);
|
|
||||||
} else if true {
|
|
||||||
let profile = api::profile::identity(&client).await;
|
|
||||||
if let Ok(profile) = profile {
|
|
||||||
println!("profile: {:?}: {profile}", &profile.id);
|
|
||||||
}
|
|
||||||
} else if false {
|
|
||||||
//let query = [
|
|
||||||
// ("includeSponds", "true"),
|
|
||||||
//];
|
|
||||||
//let series = client.get_with::<_, Series>((0xCCBE049C31DA4FB691158E3FBC2DFBC8u128,), &query).await?.into_inner().0;
|
|
||||||
let now = api::util::DateTime::default();
|
|
||||||
let sponds = api::spond::search()
|
|
||||||
.include_comments(true)
|
|
||||||
.order(api::Order::Ascending)
|
|
||||||
.max(100)
|
|
||||||
.series_id(api::SeriesId::new(0x9333BDD4135E48BEAE88F1C3006A5FC0u128.into()))
|
|
||||||
.min_end_timestamp(now)
|
|
||||||
.min_start_timestamp(now)
|
|
||||||
.call(&client).await?;
|
|
||||||
for spond in sponds.iter() {
|
|
||||||
println!("{spond:?}");
|
|
||||||
//let spond = api::spond().call(&client, api::SpondId::new(0xF131CD46F80A42B9909D8E7F4018D8E1u128.into())).await?;
|
|
||||||
//println!("{spond:?}");
|
|
||||||
}
|
|
||||||
//} else if true {
|
|
||||||
//
|
|
||||||
//#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
|
||||||
//struct Spond(serde_json::Value);
|
|
||||||
//
|
|
||||||
//#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
|
||||||
//struct Sponds(Vec<Spond>);
|
|
||||||
//
|
|
||||||
//impl restson::RestPath<()> for Sponds {
|
|
||||||
// fn get_path(_: ()) -> std::result::Result<String, restson::Error> {
|
|
||||||
// Ok(String::from("sponds"))
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
// let now = &DateTime::default();
|
|
||||||
// log::info!("{now:?} | {}", now.to_string());
|
|
||||||
// let query = [
|
|
||||||
// ("includeComments", "true"),
|
|
||||||
// //("includeHidden", "true"),
|
|
||||||
// ("addProfileInfo", "true"),
|
|
||||||
// ("hidden", "true"),
|
|
||||||
// ("scheduled", "true"),
|
|
||||||
// ("order", "asc"),
|
|
||||||
// ("max", "20"),
|
|
||||||
// ("heading", "Schwimmtraining Donnerstag"),
|
|
||||||
// ("seriesId", "CCBE049C31DA4FB691158E3FBC2DFBC8u128"),
|
|
||||||
// ("minStartTimestamp", &now.to_string()),
|
|
||||||
// ];
|
|
||||||
//
|
|
||||||
// for spond in client.get_with::<_, api::spond::Sponds>((), &query).await?.into_inner().0 {
|
|
||||||
// //match spond.0 {
|
|
||||||
// // serde_json::Value::Object(map) => {
|
|
||||||
// // println!("{:?}", map);
|
|
||||||
// // },
|
|
||||||
// // _ => {},
|
|
||||||
// //};
|
|
||||||
// println!("{}", serde_json::to_string_pretty(&spond).unwrap());
|
|
||||||
// }
|
|
||||||
//} else {
|
|
||||||
// let request = api::sponds()
|
|
||||||
// .add_profile_info(false)
|
|
||||||
// .comments(true)
|
|
||||||
// .hidden(false)
|
|
||||||
// .scheduled(true)
|
|
||||||
// ;
|
|
||||||
// for spond in request.call(&client).await? {
|
|
||||||
// println!("{spond:?}");
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,8 @@ fn extract_args(inputs: &Punctuated<syn::FnArg, Comma>, class: Class, default: C
|
||||||
for arg in inputs.iter().skip(1) {
|
for arg in inputs.iter().skip(1) {
|
||||||
if let syn::FnArg::Typed(pat_type) = arg {
|
if let syn::FnArg::Typed(pat_type) = arg {
|
||||||
//if pat_type.attrs.iter().any(|a| a.path().is_ident(path)) {
|
//if pat_type.attrs.iter().any(|a| a.path().is_ident(path)) {
|
||||||
if Class::classify(&pat_type, default) == class {
|
if Class::classify(pat_type, default) == class
|
||||||
if let syn::Pat::Ident(pat_ident) = &*pat_type.pat {
|
&& let syn::Pat::Ident(pat_ident) = &*pat_type.pat {
|
||||||
idents.push(pat_ident.ident.clone());
|
idents.push(pat_ident.ident.clone());
|
||||||
types.push((*pat_type.ty).clone());
|
types.push((*pat_type.ty).clone());
|
||||||
let meta = pat_type.attrs.iter()
|
let meta = pat_type.attrs.iter()
|
||||||
|
|
@ -60,7 +60,6 @@ fn extract_args(inputs: &Punctuated<syn::FnArg, Comma>, class: Class, default: C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
(idents, types, attrs)
|
(idents, types, attrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue