Bump version to 0.2.2, add inline command for listing unviewed videos
Some checks failed
Docker Push / docker (push) Has been cancelled

This commit is contained in:
Shiroyasha 2025-02-09 18:58:24 +03:00
parent fa125b47fb
commit dca70ba2cc
Signed by: shiroyashik
GPG key ID: E4953D3940D7860A
6 changed files with 148 additions and 68 deletions

2
Cargo.lock generated
View file

@ -795,7 +795,7 @@ dependencies = [
[[package]] [[package]]
name = "doggy-watch" name = "doggy-watch"
version = "0.2.0" version = "0.2.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",

View file

@ -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.0" version = "0.2.2"
edition = "2021" edition = "2021"
publish = false publish = false

View file

@ -1,6 +1,6 @@
## Chef ## Chef
# FROM clux/muslrust:stable AS chef # FROM clux/muslrust:stable AS chef
FROM rust:1.84.0-alpine3.20 AS chef FROM rust:alpine 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

View file

@ -1,14 +1,13 @@
use std::sync::Arc; use std::sync::Arc;
use indexmap::IndexMap; use indexmap::IndexMap;
use teloxide::{prelude::*, types::{LinkPreviewOptions, ParseMode}}; use teloxide::{prelude::*, types::{InlineKeyboardButton, InlineKeyboardMarkup, LinkPreviewOptions, ParseMode}};
use sea_orm::{prelude::*, Order, QueryOrder}; use sea_orm::{prelude::*, Order, QueryOrder};
use database::*; use database::*;
use crate::AppState; use crate::AppState;
pub async fn command(bot: Bot, msg: Message, state: Arc<AppState>) -> anyhow::Result<()> {
struct Video { struct Video {
id: i32, id: i32,
title: String, title: String,
@ -16,19 +15,101 @@ pub async fn command(bot: Bot, msg: Message, state: Arc<AppState>) -> anyhow::Re
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();
if !videos.is_empty() { 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")],
];
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 {
let data = format!("Can't find creator for {request:?}"); anyhow::bail!("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?;
@ -76,9 +157,5 @@ pub async fn command(bot: Bot, msg: Message, state: Arc<AppState>) -> anyhow::Re
} }
} }
// result.push_str(&format!("\nВсего: {}", videos_len)); // result.push_str(&format!("\nВсего: {}", videos_len));
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?; Ok(Some(result))
} else {
bot.send_message(msg.chat.id, "Нет видео для просмотра :(").await?;
}
Ok(())
} }

View file

@ -74,6 +74,7 @@ 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))

View file

@ -6,6 +6,7 @@ pub enum InlineCommand {
Unview(i32), Unview(i32),
ArchiveViewed, ArchiveViewed,
ArchiveAll, ArchiveAll,
ListUnviewed,
Cancel, Cancel,
} }
@ -19,6 +20,7 @@ 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,
}) })