Added telegram bot
Build and Publish / Build and Publish Docker Image (push) Successful in 3m8s

This commit is contained in:
Ultradesu
2026-06-30 18:36:53 +03:00
parent 3def3afeda
commit 3a4bc23a58
12 changed files with 915 additions and 19 deletions
+64
View File
@@ -17,6 +17,7 @@ pub struct User {
email: Option<String>,
display_name: Option<String>,
avatar_url: Option<String>,
telegram_id: Option<String>,
role: LimitedString<32>,
is_active: bool,
}
@@ -53,6 +54,7 @@ impl User {
email: email.map(str::to_owned),
display_name: display_name.map(str::to_owned),
avatar_url: None,
telegram_id: None,
role: LimitedString::new(role).unwrap(),
is_active: true,
};
@@ -75,6 +77,7 @@ impl User {
email: email.map(str::to_owned),
display_name: display_name.map(str::to_owned),
avatar_url: None,
telegram_id: None,
role: LimitedString::new(role).unwrap(),
is_active: true,
};
@@ -117,6 +120,21 @@ impl User {
cot::db::query!(User, $email == Some(email)).get(db).await
}
/// Find a user linked to a non-empty Telegram ID.
pub async fn get_by_telegram_id(
db: &Database,
telegram_id: &str,
) -> cot::db::Result<Option<Self>> {
let telegram_id = telegram_id.trim();
if telegram_id.is_empty() {
return Ok(None);
}
let telegram_id = telegram_id.to_owned();
cot::db::query!(User, $telegram_id == Some(telegram_id))
.get(db)
.await
}
/// Count all users in the database.
pub async fn count_all(db: &Database) -> cot::db::Result<u64> {
Self::objects().count(db).await
@@ -140,6 +158,16 @@ impl User {
self.save(db).await
}
/// Store a Telegram link state. `Some("")` means the user declined linking.
pub async fn set_telegram_id(
&mut self,
db: &Database,
telegram_id: Option<&str>,
) -> cot::db::Result<()> {
self.telegram_id = telegram_id.map(str::to_owned);
self.save(db).await
}
/// Delete this user by primary key.
pub async fn delete_by_id(db: &Database, user_id: i64) -> cot::db::Result<()> {
cot::db::query!(User, $id == Auto::Fixed(user_id))
@@ -165,6 +193,10 @@ impl User {
self.display_name.clone().unwrap_or_default()
}
pub fn telegram_id(&self) -> Option<&str> {
self.telegram_id.as_deref()
}
pub fn role_str(&self) -> &str {
&self.role
}
@@ -391,9 +423,41 @@ pub mod db_migrations {
&[Operation::custom(create_oidc_link_indexes).build()];
}
// -- M0007: Telegram link state on amnezia_fellow__user ----------------
#[cot::db::migrations::migration_op]
async fn add_user_telegram_id(ctx: migrations::MigrationContext<'_>) -> cot::db::Result<()> {
ctx.db
.raw("ALTER TABLE amnezia_fellow__user ADD COLUMN telegram_id TEXT")
.await?;
ctx.db
.raw(
"CREATE UNIQUE INDEX idx_amnezia_fellow_user_telegram_id \
ON amnezia_fellow__user (telegram_id) \
WHERE telegram_id IS NOT NULL AND telegram_id != ''",
)
.await?;
Ok(())
}
#[derive(Debug, Copy, Clone)]
pub struct M0007UserTelegramId;
impl migrations::Migration for M0007UserTelegramId {
const APP_NAME: &'static str = "amnezia_fellow";
const MIGRATION_NAME: &'static str = "m_0007_user_telegram_id";
const DEPENDENCIES: &'static [migrations::MigrationDependency] =
&[migrations::MigrationDependency::migration(
"amnezia_fellow",
"m_0004_oidc_link_indexes",
)];
const OPERATIONS: &'static [Operation] = &[Operation::custom(add_user_telegram_id).build()];
}
pub const MIGRATIONS: &[&SyncDynMigration] = &[
&M0002CreateUser,
&M0003CreateOidcLink,
&M0004OidcLinkIndexes,
&M0007UserTelegramId,
];
}