Added telegram bot WEB App
Build and Publish / Build and Publish Docker Image (push) Successful in 6m0s
Build and Publish / Build and Publish Docker Image (push) Successful in 6m0s
This commit is contained in:
+110
@@ -18,6 +18,8 @@ pub struct User {
|
||||
display_name: Option<String>,
|
||||
avatar_url: Option<String>,
|
||||
telegram_id: Option<String>,
|
||||
telegram_link_code: Option<String>,
|
||||
telegram_link_code_created_at: Option<i64>,
|
||||
role: LimitedString<32>,
|
||||
is_active: bool,
|
||||
}
|
||||
@@ -55,6 +57,8 @@ impl User {
|
||||
display_name: display_name.map(str::to_owned),
|
||||
avatar_url: None,
|
||||
telegram_id: None,
|
||||
telegram_link_code: None,
|
||||
telegram_link_code_created_at: None,
|
||||
role: LimitedString::new(role).unwrap(),
|
||||
is_active: true,
|
||||
};
|
||||
@@ -78,6 +82,8 @@ impl User {
|
||||
display_name: display_name.map(str::to_owned),
|
||||
avatar_url: None,
|
||||
telegram_id: None,
|
||||
telegram_link_code: None,
|
||||
telegram_link_code_created_at: None,
|
||||
role: LimitedString::new(role).unwrap(),
|
||||
is_active: true,
|
||||
};
|
||||
@@ -135,6 +141,21 @@ impl User {
|
||||
.await
|
||||
}
|
||||
|
||||
/// Find a user waiting for this Telegram link code.
|
||||
pub async fn get_by_telegram_link_code(
|
||||
db: &Database,
|
||||
code: &str,
|
||||
) -> cot::db::Result<Option<Self>> {
|
||||
let code = code.trim();
|
||||
if code.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
let code = code.to_owned();
|
||||
cot::db::query!(User, $telegram_link_code == Some(code))
|
||||
.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
|
||||
@@ -168,6 +189,46 @@ impl User {
|
||||
self.save(db).await
|
||||
}
|
||||
|
||||
/// Store or clear a pending Telegram link code.
|
||||
pub async fn set_telegram_link_code(
|
||||
&mut self,
|
||||
db: &Database,
|
||||
code: Option<&str>,
|
||||
created_at: Option<i64>,
|
||||
) -> cot::db::Result<()> {
|
||||
self.telegram_link_code = code.map(str::to_owned);
|
||||
self.telegram_link_code_created_at = code.and(created_at);
|
||||
self.save(db).await
|
||||
}
|
||||
|
||||
/// Complete Telegram linking and clear any pending code.
|
||||
pub async fn complete_telegram_link(
|
||||
&mut self,
|
||||
db: &Database,
|
||||
telegram_id: &str,
|
||||
) -> cot::db::Result<()> {
|
||||
self.telegram_id = Some(telegram_id.to_owned());
|
||||
self.telegram_link_code = None;
|
||||
self.telegram_link_code_created_at = None;
|
||||
self.save(db).await
|
||||
}
|
||||
|
||||
/// Remove Telegram credentials and pending link data.
|
||||
pub async fn clear_telegram_link(&mut self, db: &Database) -> cot::db::Result<()> {
|
||||
self.telegram_id = None;
|
||||
self.telegram_link_code = None;
|
||||
self.telegram_link_code_created_at = None;
|
||||
self.save(db).await
|
||||
}
|
||||
|
||||
/// Store an explicit opt-out and clear pending link data.
|
||||
pub async fn decline_telegram_link(&mut self, db: &Database) -> cot::db::Result<()> {
|
||||
self.telegram_id = Some(String::new());
|
||||
self.telegram_link_code = None;
|
||||
self.telegram_link_code_created_at = None;
|
||||
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))
|
||||
@@ -197,6 +258,14 @@ impl User {
|
||||
self.telegram_id.as_deref()
|
||||
}
|
||||
|
||||
pub fn telegram_link_code(&self) -> Option<&str> {
|
||||
self.telegram_link_code.as_deref()
|
||||
}
|
||||
|
||||
pub fn telegram_link_code_created_at(&self) -> Option<i64> {
|
||||
self.telegram_link_code_created_at
|
||||
}
|
||||
|
||||
pub fn role_str(&self) -> &str {
|
||||
&self.role
|
||||
}
|
||||
@@ -454,10 +523,51 @@ pub mod db_migrations {
|
||||
const OPERATIONS: &'static [Operation] = &[Operation::custom(add_user_telegram_id).build()];
|
||||
}
|
||||
|
||||
// -- M0008: pending Telegram link code on amnezia_fellow__user ---------
|
||||
|
||||
#[cot::db::migrations::migration_op]
|
||||
async fn add_user_telegram_link_code(
|
||||
ctx: migrations::MigrationContext<'_>,
|
||||
) -> cot::db::Result<()> {
|
||||
ctx.db
|
||||
.raw("ALTER TABLE amnezia_fellow__user ADD COLUMN telegram_link_code TEXT")
|
||||
.await?;
|
||||
ctx.db
|
||||
.raw(
|
||||
"ALTER TABLE amnezia_fellow__user \
|
||||
ADD COLUMN telegram_link_code_created_at INTEGER",
|
||||
)
|
||||
.await?;
|
||||
ctx.db
|
||||
.raw(
|
||||
"CREATE UNIQUE INDEX idx_amnezia_fellow_user_telegram_link_code \
|
||||
ON amnezia_fellow__user (telegram_link_code) \
|
||||
WHERE telegram_link_code IS NOT NULL AND telegram_link_code != ''",
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct M0008UserTelegramLinkCode;
|
||||
|
||||
impl migrations::Migration for M0008UserTelegramLinkCode {
|
||||
const APP_NAME: &'static str = "amnezia_fellow";
|
||||
const MIGRATION_NAME: &'static str = "m_0008_user_telegram_link_code";
|
||||
const DEPENDENCIES: &'static [migrations::MigrationDependency] =
|
||||
&[migrations::MigrationDependency::migration(
|
||||
"amnezia_fellow",
|
||||
"m_0007_user_telegram_id",
|
||||
)];
|
||||
const OPERATIONS: &'static [Operation] =
|
||||
&[Operation::custom(add_user_telegram_link_code).build()];
|
||||
}
|
||||
|
||||
pub const MIGRATIONS: &[&SyncDynMigration] = &[
|
||||
&M0002CreateUser,
|
||||
&M0003CreateOidcLink,
|
||||
&M0004OidcLinkIndexes,
|
||||
&M0007UserTelegramId,
|
||||
&M0008UserTelegramLinkCode,
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user