149 lines
5.2 KiB
Python
149 lines
5.2 KiB
Python
import logging
|
|
from datetime import datetime
|
|
from telegram import Update
|
|
from telegram.ext import ContextTypes
|
|
from models.session import set_state, get_data, clear_data, MENU
|
|
from handlers import get_menu_keyboard, MENU_TEXT
|
|
from handlers.chantier import nom_depuis_dossier
|
|
from services.nextcloud import upload_photo, create_deck_card
|
|
from services.telegram import notify_fin_chantier as send_notification
|
|
from config import DECK_BOARD_ID, DECK_COL_FIN
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
_albums: dict[str, dict] = {}
|
|
|
|
|
|
async def handle_photo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
msg = update.message
|
|
if not msg or not msg.photo:
|
|
if msg:
|
|
await msg.reply_text("❌ Veuillez envoyer une photo.")
|
|
return
|
|
|
|
caption = msg.caption or ""
|
|
group_id = msg.media_group_id
|
|
ouvrier = msg.from_user.full_name
|
|
file_id = msg.photo[-1].file_id
|
|
user_id = msg.from_user.id
|
|
chantier_folder = get_data(user_id, "chantier_folder")
|
|
|
|
if group_id:
|
|
if group_id not in _albums:
|
|
_albums[group_id] = {
|
|
"photos": [],
|
|
"caption": "",
|
|
"ouvrier": ouvrier,
|
|
"chat_id": msg.chat_id,
|
|
"user_id": user_id,
|
|
"chantier_folder": chantier_folder,
|
|
}
|
|
context.job_queue.run_once(
|
|
_process_album_job,
|
|
3,
|
|
data={"group_id": group_id},
|
|
name=str(group_id),
|
|
)
|
|
if caption:
|
|
_albums[group_id]["caption"] = caption
|
|
_albums[group_id]["photos"].append(file_id)
|
|
else:
|
|
if not chantier_folder and not caption:
|
|
await msg.reply_text(
|
|
"❌ Légende obligatoire.\nFormat : `NOM_Ville / Notes`",
|
|
parse_mode="Markdown",
|
|
)
|
|
return
|
|
await msg.reply_text("⏳ Upload en cours...")
|
|
try:
|
|
await _upload_photos([file_id], ouvrier, context.bot, chantier_folder=chantier_folder, caption=caption)
|
|
except Exception as exc:
|
|
log.error("_upload_photos single : %s", exc)
|
|
await msg.reply_text("❌ Erreur lors de l'upload.")
|
|
finally:
|
|
clear_data(user_id)
|
|
set_state(user_id, MENU)
|
|
await msg.reply_text(MENU_TEXT, reply_markup=get_menu_keyboard())
|
|
|
|
|
|
async def _process_album_job(context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
group_id = context.job.data["group_id"]
|
|
album = _albums.pop(group_id, None)
|
|
if not album:
|
|
return
|
|
|
|
caption = album.get("caption", "")
|
|
chat_id = album["chat_id"]
|
|
user_id = album["user_id"]
|
|
chantier_folder = album.get("chantier_folder")
|
|
|
|
if not chantier_folder and not caption:
|
|
await context.bot.send_message(
|
|
chat_id=chat_id,
|
|
text="❌ Album reçu sans chantier ni légende.\nFormat : `NOM_Ville / Notes`",
|
|
parse_mode="Markdown",
|
|
)
|
|
set_state(user_id, MENU)
|
|
await context.bot.send_message(chat_id=chat_id, text=MENU_TEXT, reply_markup=get_menu_keyboard())
|
|
return
|
|
|
|
n = len(album["photos"])
|
|
await context.bot.send_message(chat_id=chat_id, text=f"⏳ Upload de {n} photo(s) en cours...")
|
|
try:
|
|
await _upload_photos(album["photos"], album["ouvrier"], context.bot, chantier_folder=chantier_folder, caption=caption)
|
|
except Exception as exc:
|
|
log.error("_upload_photos album : %s", exc)
|
|
await context.bot.send_message(chat_id=chat_id, text="❌ Erreur lors de l'upload.")
|
|
finally:
|
|
clear_data(user_id)
|
|
set_state(user_id, MENU)
|
|
await context.bot.send_message(chat_id=chat_id, text=MENU_TEXT, reply_markup=get_menu_keyboard())
|
|
|
|
|
|
async def _upload_photos(
|
|
file_ids: list[str],
|
|
ouvrier: str,
|
|
bot,
|
|
*,
|
|
chantier_folder: str | None = None,
|
|
caption: str = "",
|
|
) -> None:
|
|
now = datetime.now()
|
|
if chantier_folder:
|
|
nc_dir = f"Chantiers/{chantier_folder}/30_Photos_Chantier"
|
|
chantier_name = nom_depuis_dossier(chantier_folder)
|
|
notes = caption.strip()
|
|
else:
|
|
chantier_name, notes = _parse_caption(caption)
|
|
nc_dir = f"Chantiers/{now.strftime('%y%m%d')}_{chantier_name}/30_Photos_Chantier"
|
|
|
|
uploaded = 0
|
|
for i, file_id in enumerate(file_ids):
|
|
try:
|
|
tg_file = await bot.get_file(file_id)
|
|
file_bytes = bytes(await tg_file.download_as_bytearray())
|
|
ts = now.strftime("%y%m%d_%H%M%S")
|
|
ok = await upload_photo(file_bytes, f"{nc_dir}/photo_{i + 1:02d}_{ts}.jpg")
|
|
if ok:
|
|
uploaded += 1
|
|
except Exception as exc:
|
|
log.error("Erreur upload photo %d : %s", i + 1, exc)
|
|
|
|
try:
|
|
await send_notification(bot, ouvrier, chantier_name, uploaded, f"Nextcloud/{nc_dir}/")
|
|
except Exception as exc:
|
|
log.error("notify_fin_chantier : %s", exc)
|
|
|
|
if DECK_BOARD_ID and DECK_COL_FIN:
|
|
await create_deck_card(
|
|
DECK_BOARD_ID,
|
|
DECK_COL_FIN,
|
|
f"Fin chantier — {chantier_name}",
|
|
f"Ouvrier : {ouvrier}\n{len(file_ids)} photo(s)\nNotes : {notes}",
|
|
)
|
|
|
|
|
|
def _parse_caption(caption: str) -> tuple[str, str]:
|
|
chantier, _, notes = caption.partition("/")
|
|
return chantier.strip(), notes.strip()
|