1 Commits

Author SHA1 Message Date
b906bfa777 refactor: improve code formatting and readability in group duty pin command and tests
All checks were successful
CI / lint-and-test (push) Successful in 25s
Docker Build and Release / build-and-push (push) Successful in 54s
Docker Build and Release / release (push) Successful in 8s
- Enhanced the `pin_duty_cmd` function by improving code formatting for better readability, ensuring consistent style across the codebase.
- Updated unit tests for `pin_duty_cmd` to follow the same formatting improvements, enhancing clarity and maintainability.
- No functional changes were made; the focus was solely on code style and organization.
2026-02-25 14:58:03 +03:00
4 changed files with 59 additions and 11 deletions

View File

@@ -266,14 +266,18 @@ async def pin_duty_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No
)
pinned = True
except (BadRequest, Forbidden) as e:
logger.warning("Failed to pin message for pin_duty chat_id=%s: %s", chat_id, e)
logger.warning(
"Failed to pin message for pin_duty chat_id=%s: %s", chat_id, e
)
await loop.run_in_executor(None, _sync_save_pin, chat_id, msg.message_id)
next_end = await loop.run_in_executor(None, _get_next_shift_end_sync)
await _schedule_next_update(context.application, chat_id, next_end)
if pinned:
await update.message.reply_text(t(lang, "pin_duty.pinned"))
else:
await update.message.reply_text(t(lang, "pin_duty.could_not_pin_make_admin"))
await update.message.reply_text(
t(lang, "pin_duty.could_not_pin_make_admin")
)
return
try:
await context.bot.pin_chat_message(

View File

@@ -328,11 +328,17 @@ async def test_pin_duty_cmd_no_message_id_creates_sends_pins_saves_schedules_rep
with patch("duty_teller.handlers.group_duty_pin.get_lang", return_value="en"):
with patch.object(mod, "_sync_get_message_id", return_value=None):
with patch.object(mod, "_get_duty_message_text_sync", return_value="Duty text"):
with patch.object(
mod, "_get_duty_message_text_sync", return_value="Duty text"
):
with patch.object(mod, "_sync_save_pin") as mock_save:
with patch.object(mod, "_get_next_shift_end_sync", return_value=None):
with patch.object(
mod, "_get_next_shift_end_sync", return_value=None
):
with patch.object(mod, "_schedule_next_update", AsyncMock()):
with patch("duty_teller.handlers.group_duty_pin.t") as mock_t:
with patch(
"duty_teller.handlers.group_duty_pin.t"
) as mock_t:
mock_t.return_value = "Pinned"
await mod.pin_duty_cmd(update, context)
context.bot.send_message.assert_called_once_with(chat_id=100, text="Duty text")
@@ -363,7 +369,9 @@ async def test_pin_duty_cmd_no_message_id_send_message_raises_replies_failed():
with patch.object(mod, "_sync_get_message_id", return_value=None):
with patch.object(mod, "_get_duty_message_text_sync", return_value="Duty"):
with patch.object(mod, "_sync_save_pin") as mock_save:
with patch.object(mod, "_schedule_next_update", AsyncMock()) as mock_schedule:
with patch.object(
mod, "_schedule_next_update", AsyncMock()
) as mock_schedule:
with patch("duty_teller.handlers.group_duty_pin.t") as mock_t:
mock_t.return_value = "Failed"
await mod.pin_duty_cmd(update, context)
@@ -398,9 +406,13 @@ async def test_pin_duty_cmd_no_message_id_pin_raises_saves_and_replies_could_not
with patch.object(mod, "_sync_get_message_id", return_value=None):
with patch.object(mod, "_get_duty_message_text_sync", return_value="Duty"):
with patch.object(mod, "_sync_save_pin") as mock_save:
with patch.object(mod, "_get_next_shift_end_sync", return_value=None):
with patch.object(
mod, "_get_next_shift_end_sync", return_value=None
):
with patch.object(mod, "_schedule_next_update", AsyncMock()):
with patch("duty_teller.handlers.group_duty_pin.t") as mock_t:
with patch(
"duty_teller.handlers.group_duty_pin.t"
) as mock_t:
mock_t.return_value = "Make me admin to pin"
await mod.pin_duty_cmd(update, context)
context.bot.send_message.assert_called_once_with(chat_id=100, text="Duty")

View File

@@ -126,9 +126,14 @@ function buildDutyItemTimePrefix(item, idx, total, hintDay, sep, fromLabel, toLa
timePrefix = toLabel + sep + endHHMM;
}
} else if (idx > 0) {
if (startHHMM) timePrefix = fromLabel + sep + startHHMM;
if (endHHMM && endSameDay && endHHMM !== startHHMM) {
timePrefix += (timePrefix ? " " : "") + toLabel + sep + endHHMM;
if (startSameDay && startHHMM) {
timePrefix = fromLabel + sep + startHHMM;
if (endHHMM && endSameDay && endHHMM !== startHHMM) {
timePrefix += " " + toLabel + sep + endHHMM;
}
} else if (endHHMM) {
/* Continuation from previous day — only end time */
timePrefix = toLabel + sep + endHHMM;
}
}
return timePrefix;

View File

@@ -82,6 +82,33 @@ describe("getDutyMarkerRows", () => {
expect(rows[0].timePrefix).toContain("06:00");
});
it("second duty continuation from previous day shows only end time (to HH:MM)", () => {
const hintDay = "2025-02-23";
const duties = [
{
full_name: "A",
start_at: "2025-02-23T00:00:00",
end_at: "2025-02-23T09:00:00",
},
{
full_name: "B",
start_at: "2025-02-22T09:00:00",
end_at: "2025-02-23T09:00:00",
},
];
const rows = getDutyMarkerRows(duties, hintDay, SEP, FROM, TO);
expect(rows).toHaveLength(2);
expect(rows[0].fullName).toBe("A");
expect(rows[0].timePrefix).toContain(FROM);
expect(rows[0].timePrefix).toContain("00:00");
expect(rows[0].timePrefix).toContain(TO);
expect(rows[0].timePrefix).toContain("09:00");
expect(rows[1].fullName).toBe("B");
expect(rows[1].timePrefix).not.toContain(FROM);
expect(rows[1].timePrefix).toContain(TO);
expect(rows[1].timePrefix).toContain("09:00");
});
it("multiple duties in one day — correct order when input is pre-sorted", () => {
const hintDay = "2025-02-25";
const duties = [