mirror of
https://github.com/shiroyashik/doggy-watch.git
synced 2025-12-06 12:31:13 +03:00
Compare commits
No commits in common. "master" and "v0.2.1" have entirely different histories.
12 changed files with 282 additions and 468 deletions
493
Cargo.lock
generated
493
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "doggy-watch"
|
name = "doggy-watch"
|
||||||
authors = ["Shiroyashik <shiroyashik@shsr.ru>"]
|
authors = ["Shiroyashik <shiroyashik@shsr.ru>"]
|
||||||
version = "0.2.2"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
|
|
@ -26,7 +26,6 @@ tracing-panic = "0.1"
|
||||||
lazy_static = "1.5"
|
lazy_static = "1.5"
|
||||||
indexmap = "2.7"
|
indexmap = "2.7"
|
||||||
dashmap = "6.1"
|
dashmap = "6.1"
|
||||||
url = "2.5"
|
|
||||||
|
|
||||||
# https://github.com/teloxide/teloxide/issues/1154
|
# https://github.com/teloxide/teloxide/issues/1154
|
||||||
# [profile.dev]
|
# [profile.dev]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
## Chef
|
## Chef
|
||||||
# FROM clux/muslrust:stable AS chef
|
# FROM clux/muslrust:stable AS chef
|
||||||
FROM rust:alpine AS chef
|
FROM rust:1.84.0-alpine3.20 AS chef
|
||||||
USER root
|
USER root
|
||||||
RUN apk add --no-cache musl-dev libressl-dev
|
RUN apk add --no-cache musl-dev libressl-dev
|
||||||
RUN cargo install cargo-chef
|
RUN cargo install cargo-chef
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,6 @@ ID канала для проверки подписки.
|
||||||
`trace, debug, info, warn, error`
|
`trace, debug, info, warn, error`
|
||||||
Также можно указать отдельный уровень логирования для отдельных целей.
|
Также можно указать отдельный уровень логирования для отдельных целей.
|
||||||
|
|
||||||
`TELEGRAM_API_URL=<url>`
|
|
||||||
|
|
||||||
Сторонний Telegram Bot API сервер (необязательно).
|
|
||||||
|
|
||||||
### Только для Docker
|
### Только для Docker
|
||||||
|
|
||||||
`TZ=<TZ_identifier>`
|
`TZ=<TZ_identifier>`
|
||||||
|
|
|
||||||
|
|
@ -108,22 +108,22 @@ impl MigrationTrait for Migration {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
// Actions
|
// Videos
|
||||||
manager
|
manager
|
||||||
.drop_table(Table::drop().table(Actions::Table).to_owned())
|
.drop_table(Table::drop().table(Videos::Table).to_owned())
|
||||||
.await?;
|
.await?;
|
||||||
// Requests
|
// Requests
|
||||||
manager
|
manager
|
||||||
.drop_table(Table::drop().table(Requests::Table).to_owned())
|
.drop_table(Table::drop().table(Requests::Table).to_owned())
|
||||||
.await?;
|
.await?;
|
||||||
|
// Actions
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(Actions::Table).to_owned())
|
||||||
|
.await?;
|
||||||
// Archived
|
// Archived
|
||||||
manager
|
manager
|
||||||
.drop_table(Table::drop().table(Archived::Table).to_owned())
|
.drop_table(Table::drop().table(Archived::Table).to_owned())
|
||||||
.await?;
|
.await?;
|
||||||
// Videos
|
|
||||||
manager
|
|
||||||
.drop_table(Table::drop().table(Videos::Table).to_owned())
|
|
||||||
.await?;
|
|
||||||
// Moderators
|
// Moderators
|
||||||
manager
|
manager
|
||||||
.drop_table(Table::drop().table(Moderators::Table).to_owned())
|
.drop_table(Table::drop().table(Moderators::Table).to_owned())
|
||||||
|
|
|
||||||
|
|
@ -10,17 +10,10 @@ use crate::{check_subscription, markup, notify, AppState, DialogueState, MyDialo
|
||||||
pub async fn message(bot: Bot, msg: Message, dialogue: MyDialogue) -> anyhow::Result<()> {
|
pub async fn message(bot: Bot, msg: Message, dialogue: MyDialogue) -> anyhow::Result<()> {
|
||||||
use youtube::*;
|
use youtube::*;
|
||||||
if let Some(text) = msg.clone().text() {
|
if let Some(text) = msg.clone().text() {
|
||||||
if let Some(user) = check_subscription(&bot, &msg.clone().from.ok_or(anyhow::anyhow!("Message not from user!"))?.id).await {
|
if let Some(user) = check_subscription(&bot, &msg.from.ok_or(anyhow::anyhow!("Message not from user!"))?.id).await {
|
||||||
// Get ready!
|
// Get ready!
|
||||||
if let Some(ytid) = extract_youtube_video_id(text) {
|
if let Some(ytid) = extract_youtube_video_id(text) {
|
||||||
let meta = match get_video_metadata(&ytid).await {
|
let meta = get_video_metadata(&ytid).await?;
|
||||||
Ok(meta) => meta,
|
|
||||||
Err(err) => {
|
|
||||||
tracing::error!("Caused an exception in get_video_metadata due: {err:?}");
|
|
||||||
bot.send_message(msg.chat.id, "Ошибка при получении метаданных видео!").await?;
|
|
||||||
return Ok(());
|
|
||||||
},
|
|
||||||
};
|
|
||||||
// Post
|
// Post
|
||||||
bot.send_message(msg.chat.id, format!(
|
bot.send_message(msg.chat.id, format!(
|
||||||
"Вы уверены что хотите добавить <b>{}</b>",
|
"Вы уверены что хотите добавить <b>{}</b>",
|
||||||
|
|
@ -28,7 +21,6 @@ pub async fn message(bot: Bot, msg: Message, dialogue: MyDialogue) -> anyhow::Re
|
||||||
)).parse_mode(ParseMode::Html).reply_markup(markup::inline_yes_or_no()).await?;
|
)).parse_mode(ParseMode::Html).reply_markup(markup::inline_yes_or_no()).await?;
|
||||||
dialogue.update(DialogueState::AcceptVideo { ytid, uid: user.id.0, title: meta.title }).await?;
|
dialogue.update(DialogueState::AcceptVideo { ytid, uid: user.id.0, title: meta.title }).await?;
|
||||||
} else {
|
} else {
|
||||||
tracing::debug!("Not a YouTube video: {:?}", msg);
|
|
||||||
bot.send_message(msg.chat.id, "Это не похоже на YouTube видео... Долбоёб").await?;
|
bot.send_message(msg.chat.id, "Это не похоже на YouTube видео... Долбоёб").await?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,115 +1,34 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use teloxide::{prelude::*, types::{InlineKeyboardButton, InlineKeyboardMarkup, LinkPreviewOptions, ParseMode}};
|
use teloxide::{prelude::*, types::{LinkPreviewOptions, ParseMode}};
|
||||||
use sea_orm::{prelude::*, Order, QueryOrder};
|
use sea_orm::{prelude::*, Order, QueryOrder};
|
||||||
|
|
||||||
use database::*;
|
use database::*;
|
||||||
|
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
|
|
||||||
struct Video {
|
pub async fn command(bot: Bot, msg: Message, state: Arc<AppState>) -> anyhow::Result<()> {
|
||||||
|
struct Video {
|
||||||
id: i32,
|
id: i32,
|
||||||
title: String,
|
title: String,
|
||||||
url: String,
|
url: String,
|
||||||
contributors: u64,
|
contributors: u64,
|
||||||
status: String,
|
status: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn command(bot: Bot, msg: Message, state: Arc<AppState>) -> anyhow::Result<()> {
|
|
||||||
let videos: Vec<(requests::Model, Option<videos::Model>)> = requests::Entity::find()
|
let videos: Vec<(requests::Model, Option<videos::Model>)> = requests::Entity::find()
|
||||||
.find_also_related(videos::Entity).filter(videos::Column::Banned.eq(false)).all(&state.db).await?;
|
.find_also_related(videos::Entity).filter(videos::Column::Banned.eq(false)).all(&state.db).await?;
|
||||||
|
// let videos_len = videos.len();
|
||||||
let result = generate_list(videos, &state).await;
|
if !videos.is_empty() {
|
||||||
match result {
|
|
||||||
Ok(list) => {
|
|
||||||
let result = if let Some(list) = list {
|
|
||||||
list
|
|
||||||
} else {
|
|
||||||
"Нет видео для просмотра :(".to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
let keyboard: Vec<Vec<InlineKeyboardButton>> = vec![
|
|
||||||
vec![InlineKeyboardButton::callback("Непросмотренные", "list_unviewed")],
|
|
||||||
];
|
|
||||||
|
|
||||||
bot.send_message(msg.chat.id, result).parse_mode(ParseMode::Html)
|
|
||||||
.link_preview_options(LinkPreviewOptions {
|
|
||||||
is_disabled: true,
|
|
||||||
url: None,
|
|
||||||
prefer_small_media: false,
|
|
||||||
prefer_large_media: false,
|
|
||||||
show_above_text: false
|
|
||||||
}).reply_markup(InlineKeyboardMarkup::new(keyboard)).await?;
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("{:?}", e);
|
|
||||||
bot.send_message(msg.chat.id, "Произошла ошибка!").await?;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn inline(state: Arc<AppState>, bot: Bot, q: CallbackQuery) -> anyhow::Result<()> {
|
|
||||||
bot.answer_callback_query(&q.id).await?;
|
|
||||||
let videos: Vec<(requests::Model, Option<videos::Model>)> = requests::Entity::find()
|
|
||||||
.find_also_related(videos::Entity).filter(videos::Column::Banned.eq(false)).filter(requests::Column::ViewedAt.is_null()).all(&state.db).await?;
|
|
||||||
let result = generate_list(videos, &state).await;
|
|
||||||
match result {
|
|
||||||
Ok(list) => {
|
|
||||||
let result = if let Some(list) = list {
|
|
||||||
list
|
|
||||||
} else {
|
|
||||||
"Нет видео для просмотра :(".to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
let keyboard: Vec<Vec<InlineKeyboardButton>> = vec![
|
|
||||||
vec![InlineKeyboardButton::callback("Обновить", "list_unviewed")],
|
|
||||||
];
|
|
||||||
|
|
||||||
if let Some(message) = q.regular_message() {
|
|
||||||
bot.edit_message_text(message.chat.id, message.id, result).parse_mode(ParseMode::Html)
|
|
||||||
.link_preview_options(LinkPreviewOptions {
|
|
||||||
is_disabled: true,
|
|
||||||
url: None,
|
|
||||||
prefer_small_media: false,
|
|
||||||
prefer_large_media: false,
|
|
||||||
show_above_text: false
|
|
||||||
}).reply_markup(InlineKeyboardMarkup::new(keyboard)).await?;
|
|
||||||
} else if let Some(message_id) = q.inline_message_id {
|
|
||||||
bot.edit_message_text_inline(&message_id, result)
|
|
||||||
.parse_mode(ParseMode::Html).disable_web_page_preview(true).reply_markup(InlineKeyboardMarkup::new(keyboard)).await?;
|
|
||||||
} else {
|
|
||||||
bot.send_message(q.from.id, result).parse_mode(ParseMode::Html)
|
|
||||||
.reply_markup(InlineKeyboardMarkup::new(keyboard))
|
|
||||||
.link_preview_options(LinkPreviewOptions {
|
|
||||||
is_disabled: true,
|
|
||||||
url: None,
|
|
||||||
prefer_small_media: false,
|
|
||||||
prefer_large_media: false,
|
|
||||||
show_above_text: false
|
|
||||||
}).await?;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("{:?}", e);
|
|
||||||
bot.send_message(q.from.id, "Произошла ошибка!").await?;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn generate_list(videos: Vec<(requests::Model, Option<videos::Model>)>, state: &AppState) -> anyhow::Result<Option<String>> {
|
|
||||||
if videos.is_empty() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let mut by_date: IndexMap<Date, Vec<Video>> = IndexMap::new();
|
let mut by_date: IndexMap<Date, Vec<Video>> = IndexMap::new();
|
||||||
for (request, video) in videos {
|
for (request, video) in videos {
|
||||||
let video = video.unwrap();
|
let video = video.unwrap();
|
||||||
let creator = if let Some(c) = request.find_related(actions::Entity).order_by(actions::Column::Id, Order::Asc).one(&state.db).await? {
|
let creator = if let Some(c) = request.find_related(actions::Entity).order_by(actions::Column::Id, Order::Asc).one(&state.db).await? {
|
||||||
c
|
c
|
||||||
} else {
|
} else {
|
||||||
anyhow::bail!("Can't find creator for {request:?}");
|
let data = format!("Can't find creator for {request:?}");
|
||||||
|
bot.send_message(msg.chat.id, data.clone()).await?;
|
||||||
|
anyhow::bail!(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
let contributors = request.find_related(actions::Entity).count(&state.db).await?;
|
let contributors = request.find_related(actions::Entity).count(&state.db).await?;
|
||||||
|
|
@ -157,5 +76,9 @@ async fn generate_list(videos: Vec<(requests::Model, Option<videos::Model>)>, st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// result.push_str(&format!("\nВсего: {}", videos_len));
|
// result.push_str(&format!("\nВсего: {}", videos_len));
|
||||||
Ok(Some(result))
|
bot.send_message(msg.chat.id, result).parse_mode(ParseMode::Html).link_preview_options(LinkPreviewOptions { is_disabled: true, url: None, prefer_small_media: false, prefer_large_media: false, show_above_text: false }).await?;
|
||||||
|
} else {
|
||||||
|
bot.send_message(msg.chat.id, "Нет видео для просмотра :(").await?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -19,7 +19,6 @@ pub fn schema() -> UpdateHandler<anyhow::Error> {
|
||||||
use dptree::case;
|
use dptree::case;
|
||||||
let moderator_commands = dptree::entry()
|
let moderator_commands = dptree::entry()
|
||||||
.branch(case![Command::Start].endpoint(start::command_mod))
|
.branch(case![Command::Start].endpoint(start::command_mod))
|
||||||
.branch(case![Command::Help].endpoint(start::command_mod))
|
|
||||||
.branch(case![Command::List].endpoint(list::command))
|
.branch(case![Command::List].endpoint(list::command))
|
||||||
.branch(case![Command::Archive].endpoint(archive::command))
|
.branch(case![Command::Archive].endpoint(archive::command))
|
||||||
.branch(case![Command::Mods].endpoint(moderator::list::command))
|
.branch(case![Command::Mods].endpoint(moderator::list::command))
|
||||||
|
|
@ -74,7 +73,6 @@ pub fn schema() -> UpdateHandler<anyhow::Error> {
|
||||||
InlineCommand::parse(&q.data?)
|
InlineCommand::parse(&q.data?)
|
||||||
}))
|
}))
|
||||||
.branch(case![InlineCommand::Cancel].endpoint(cancel))
|
.branch(case![InlineCommand::Cancel].endpoint(cancel))
|
||||||
.branch(case![InlineCommand::ListUnviewed].endpoint(list::inline))
|
|
||||||
.branch(filter(|com: InlineCommand| {
|
.branch(filter(|com: InlineCommand| {
|
||||||
matches!(com, InlineCommand::ArchiveAll | InlineCommand::ArchiveViewed)
|
matches!(com, InlineCommand::ArchiveAll | InlineCommand::ArchiveViewed)
|
||||||
}).endpoint(archive::inline))
|
}).endpoint(archive::inline))
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ pub async fn inline(bot: Bot, q: CallbackQuery, state: Arc<AppState>, uid: Strin
|
||||||
if let Some(data) = q.clone().data {
|
if let Some(data) = q.clone().data {
|
||||||
let text= if &data == "yes" {
|
let text= if &data == "yes" {
|
||||||
if let Ok(uid) = uid.parse::<u64>() {
|
if let Ok(uid) = uid.parse::<u64>() {
|
||||||
if Entity::delete_by_id(uid as i64).exec(&state.db).await?.rows_affected != 0 {
|
if Entity::delete_by_id(uid as i32).exec(&state.db).await?.rows_affected != 0 {
|
||||||
"Модератор удалён!"
|
"Модератор удалён!"
|
||||||
} else {
|
} else {
|
||||||
"Произошла ошибка!\nПо всей видимости такого модератора не существует."
|
"Произошла ошибка!\nПо всей видимости такого модератора не существует."
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use crate::AppState;
|
||||||
|
|
||||||
/// Invert notify status for moderator
|
/// Invert notify status for moderator
|
||||||
pub async fn command(bot: Bot, msg: Message, uid: UserId, state: Arc<AppState>) -> anyhow::Result<()> {
|
pub async fn command(bot: Bot, msg: Message, uid: UserId, state: Arc<AppState>) -> anyhow::Result<()> {
|
||||||
let text = if let Some(moder) = moderators::Entity::find_by_id(uid.0 as i64).one(&state.db).await? {
|
let text = if let Some(moder) = moderators::Entity::find_by_id(uid.0 as i32).one(&state.db).await? {
|
||||||
let moder = match moder.notify {
|
let moder = match moder.notify {
|
||||||
true => {
|
true => {
|
||||||
let mut moder = moder.into_active_model();
|
let mut moder = moder.into_active_model();
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ pub enum InlineCommand {
|
||||||
Unview(i32),
|
Unview(i32),
|
||||||
ArchiveViewed,
|
ArchiveViewed,
|
||||||
ArchiveAll,
|
ArchiveAll,
|
||||||
ListUnviewed,
|
|
||||||
Cancel,
|
Cancel,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -20,7 +19,6 @@ impl InlineCommand {
|
||||||
"unview" => Self::Unview(parts.next()?.parse().ok()?),
|
"unview" => Self::Unview(parts.next()?.parse().ok()?),
|
||||||
"archive_viewed" => Self::ArchiveViewed,
|
"archive_viewed" => Self::ArchiveViewed,
|
||||||
"archive_all" => Self::ArchiveAll,
|
"archive_all" => Self::ArchiveAll,
|
||||||
"list_unviewed" => Self::ListUnviewed,
|
|
||||||
"cancel" => Self::Cancel,
|
"cancel" => Self::Cancel,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
17
src/main.rs
17
src/main.rs
|
|
@ -17,7 +17,6 @@ mod markup;
|
||||||
|
|
||||||
mod inline;
|
mod inline;
|
||||||
pub use inline::InlineCommand;
|
pub use inline::InlineCommand;
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
pub const COOLDOWN_DURATION: Duration = Duration::from_secs(10);
|
pub const COOLDOWN_DURATION: Duration = Duration::from_secs(10);
|
||||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
@ -29,12 +28,6 @@ lazy_static! {
|
||||||
pub static ref TOKEN: String = {
|
pub static ref TOKEN: String = {
|
||||||
var("TOKEN").expect("TOKEN env not set.")
|
var("TOKEN").expect("TOKEN env not set.")
|
||||||
};
|
};
|
||||||
pub static ref TELEGRAM_API_URL: Url = {
|
|
||||||
match var("TELEGRAM_API_URL") {
|
|
||||||
Ok(url) => url.parse().expect("Can't parse TELEGRAM_API_URL"),
|
|
||||||
Err(_) => teloxide::net::TELEGRAM_API_URL.parse().expect("Failed to parse default Telegram bot API url")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pub static ref DATABASE_URL: String = {
|
pub static ref DATABASE_URL: String = {
|
||||||
var("DATABASE_URL").expect("DATABASE_URL env not set.")
|
var("DATABASE_URL").expect("DATABASE_URL env not set.")
|
||||||
};
|
};
|
||||||
|
|
@ -67,8 +60,8 @@ async fn main() -> anyhow::Result<()> {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
tracing::info!("Doggy-Watch v{VERSION}");
|
tracing::info!("Doggy-Watch v{VERSION}");
|
||||||
tracing::info!("admins: {:?} tg api: {}", *ADMINISTRATORS, TELEGRAM_API_URL.as_str());
|
tracing::info!("{:?}", *ADMINISTRATORS);
|
||||||
let bot = Bot::new(&*TOKEN).set_api_url(TELEGRAM_API_URL.clone());
|
let bot = Bot::new(&*TOKEN);
|
||||||
|
|
||||||
let mut opt = ConnectOptions::new(&*DATABASE_URL);
|
let mut opt = ConnectOptions::new(&*DATABASE_URL);
|
||||||
opt.sqlx_logging_level(tracing::log::LevelFilter::Trace);
|
opt.sqlx_logging_level(tracing::log::LevelFilter::Trace);
|
||||||
|
|
@ -100,7 +93,7 @@ async fn main() -> anyhow::Result<()> {
|
||||||
// Pass the shared state to the handler as a dependency.
|
// Pass the shared state to the handler as a dependency.
|
||||||
.dependencies(dptree::deps![state, InMemStorage::<DialogueState>::new()])
|
.dependencies(dptree::deps![state, InMemStorage::<DialogueState>::new()])
|
||||||
.default_handler(|upd| async move {
|
.default_handler(|upd| async move {
|
||||||
tracing::debug!("Unhandled update: {:?}", upd);
|
tracing::warn!("Unhandled update: {:?}", upd);
|
||||||
})
|
})
|
||||||
.enable_ctrlc_handler()
|
.enable_ctrlc_handler()
|
||||||
.build()
|
.build()
|
||||||
|
|
@ -127,8 +120,6 @@ pub enum DialogueState {
|
||||||
enum Command {
|
enum Command {
|
||||||
#[command(description = "запустить бота и/или вывести этот текст.")]
|
#[command(description = "запустить бота и/или вывести этот текст.")]
|
||||||
Start,
|
Start,
|
||||||
#[command(description = "вывести этот текст.")]
|
|
||||||
Help,
|
|
||||||
#[command(description = "вывести список.")]
|
#[command(description = "вывести список.")]
|
||||||
List,
|
List,
|
||||||
#[command(description = "действия с архивом.")]
|
#[command(description = "действия с архивом.")]
|
||||||
|
|
@ -193,7 +184,7 @@ impl AppState {
|
||||||
async fn check_rights(&self, uid: &UserId) -> anyhow::Result<Rights> {
|
async fn check_rights(&self, uid: &UserId) -> anyhow::Result<Rights> {
|
||||||
use database::moderators::Entity as Moderators;
|
use database::moderators::Entity as Moderators;
|
||||||
|
|
||||||
Ok(if let Some(moder) = Moderators::find_by_id(uid.0 as i64).one(&self.db).await? {
|
Ok(if let Some(moder) = Moderators::find_by_id(uid.0 as i32).one(&self.db).await? {
|
||||||
Rights::Moderator { can_add_mods: moder.can_add_mods }
|
Rights::Moderator { can_add_mods: moder.can_add_mods }
|
||||||
} else {
|
} else {
|
||||||
Rights::None
|
Rights::None
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue