Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 36 additions & 11 deletions src/spesobot/cogs/awarns.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ async def _send_dm(
reason: str,
new_total: float,
is_unawarn: bool,
max_awarn_weight: float = 3.0,
) -> None:
try:
delta_sign = "−" if is_unawarn else "+"
Expand All @@ -155,7 +156,7 @@ async def _send_dm(
)
dm.add_field(
name=f"Текущий вес ({department_name})",
value=f"`{fmt_weight(new_total)}` {weight_bar(new_total)}",
value=f"`{fmt_weight(new_total)}` {weight_bar(new_total, ceiling=max_awarn_weight)}",
inline=False,
)
if reason:
Expand Down Expand Up @@ -242,12 +243,13 @@ async def give(
reason=reason,
)
new_total = await self.db.get_awarn_total(user.id, dept.id)
max_w = dept.max_awarn_weight

# 1) Issuer - ephemeral confirmation card.
await interaction.response.send_message(
embed=self._build_action_embed(
title=f"{AWARN_ICON} Варн выдан",
color=severity_color(new_total),
color=severity_color(new_total, max_w),
target=user,
issuer=interaction.user,
department_name=dept.name,
Expand All @@ -258,6 +260,7 @@ async def give(
new_total=new_total,
is_unawarn=False,
guild=guild,
max_awarn_weight=max_w,
),
ephemeral=True,
)
Expand All @@ -266,7 +269,7 @@ async def give(
guild,
self._build_action_embed(
title=f"{AWARN_ICON} Варн · {dept.name}",
color=severity_color(new_total),
color=severity_color(new_total, max_w),
target=user,
issuer=interaction.user,
department_name=dept.name,
Expand All @@ -277,6 +280,7 @@ async def give(
new_total=new_total,
is_unawarn=False,
guild=guild,
max_awarn_weight=max_w,
),
department_id=dept.id,
)
Expand All @@ -285,7 +289,7 @@ async def give(
guild,
self._build_public_embed(
title=f"{AWARN_ICON} Варн · {dept.name}",
color=severity_color(new_total),
color=severity_color(new_total, max_w),
target=user,
issuer=interaction.user,
department_name=dept.name,
Expand All @@ -296,13 +300,14 @@ async def give(
new_total=new_total,
is_unawarn=False,
guild=guild,
max_awarn_weight=max_w,
),
)
# 4) DM the recipient.
await self._send_dm(
user,
title=f"{AWARN_ICON} Вам выдан варн",
color=severity_color(new_total),
color=severity_color(new_total, max_w),
guild=guild,
department_name=dept.name,
warn_label=label,
Expand All @@ -311,6 +316,7 @@ async def give(
reason=reason,
new_total=new_total,
is_unawarn=False,
max_awarn_weight=max_w,
)

# ---- /awarn remove --------------------------------------------------
Expand Down Expand Up @@ -419,6 +425,7 @@ async def remove(
)
return
new_total = value
max_w = dept.max_awarn_weight

await interaction.response.send_message(
embed=self._build_action_embed(
Expand All @@ -434,6 +441,7 @@ async def remove(
new_total=new_total,
is_unawarn=True,
guild=guild,
max_awarn_weight=max_w,
),
ephemeral=True,
)
Expand All @@ -452,6 +460,7 @@ async def remove(
new_total=new_total,
is_unawarn=True,
guild=guild,
max_awarn_weight=max_w,
),
department_id=dept.id,
)
Expand All @@ -470,6 +479,7 @@ async def remove(
new_total=new_total,
is_unawarn=True,
guild=guild,
max_awarn_weight=max_w,
),
)
await self._send_dm(
Expand All @@ -484,6 +494,7 @@ async def remove(
reason=reason,
new_total=new_total,
is_unawarn=True,
max_awarn_weight=max_w,
)

# ---- public helper: perform a programmatic unawarn -----------------
Expand Down Expand Up @@ -529,6 +540,7 @@ async def perform_unawarn(
# to the bot's own member object so the embed still has an author.
embed_issuer = issuer if issuer is not None else (guild.me or target)
warn_label = WARN_TYPES.get(warn_type, (warn_type, weight))[0]
max_w = department.max_awarn_weight

await self._post_to_log(
guild,
Expand All @@ -546,6 +558,7 @@ async def perform_unawarn(
is_unawarn=True,
guild=guild,
issuer_display_override=issuer_display_override,
max_awarn_weight=max_w,
),
department_id=department.id,
)
Expand All @@ -565,6 +578,7 @@ async def perform_unawarn(
is_unawarn=True,
guild=guild,
issuer_display_override=issuer_display_override,
max_awarn_weight=max_w,
),
)
await self._send_dm(
Expand All @@ -579,6 +593,7 @@ async def perform_unawarn(
reason=reason,
new_total=new_total,
is_unawarn=True,
max_awarn_weight=max_w,
)
return new_total

Expand Down Expand Up @@ -628,9 +643,14 @@ async def get(
depts_with_totals = all_totals

grand_total = sum(t for _, t in depts_with_totals if t > 0)
# For the overall color, use the worst ratio across departments.
worst_ratio = max(
(t / d.max_awarn_weight for d, t in depts_with_totals if d.max_awarn_weight > 0),
default=0.0,
)
embed = discord.Embed(
title=f"{AWARN_ICON} Варны · {target.display_name}",
color=severity_color(grand_total) if depts_with_totals else BRAND_MUTED,
color=severity_color(worst_ratio, 1.0) if depts_with_totals else BRAND_MUTED,
)
set_user_author(embed, target)
if target.display_avatar:
Expand All @@ -642,7 +662,10 @@ async def get(
zero = [(d, t) for d, t in depts_with_totals if t <= 0]
lines: list[str] = []
for d, total in non_zero:
lines.append(f"**{d.name}** - `{fmt_weight(total)}` {weight_bar(total)}")
lines.append(
f"**{d.name}** - `{fmt_weight(total)}` "
f"{weight_bar(total, ceiling=d.max_awarn_weight)}"
)
for d, _total in zero:
lines.append(f"`✓` **{d.name}** - чисто")
embed.add_field(
Expand Down Expand Up @@ -766,12 +789,12 @@ async def set(
)
embed.add_field(
name=f"Шкала ({dept.name})",
value=f"`{fmt_weight(new_total)}` {weight_bar(new_total)}",
value=f"`{fmt_weight(new_total)}` {weight_bar(new_total, ceiling=dept.max_awarn_weight)}",
inline=False,
)
if user.display_avatar:
embed.set_thumbnail(url=user.display_avatar.url)
embed.color = severity_color(new_total)
embed.color = severity_color(new_total, dept.max_awarn_weight)
brand_footer(embed, guild=guild)
await interaction.response.send_message(embed=embed, ephemeral=True)

Expand Down Expand Up @@ -803,6 +826,7 @@ def _build_action_embed(
is_unawarn: bool,
guild: discord.Guild,
issuer_display_override: str | None = None,
max_awarn_weight: float = 3.0,
) -> discord.Embed:
"""Used for both the issuer's ephemeral confirmation and the log channel.

Expand Down Expand Up @@ -833,7 +857,7 @@ def _build_action_embed(
)
embed.add_field(
name=f"Шкала ({department_name})",
value=f"`{fmt_weight(new_total)}` {weight_bar(new_total)}",
value=f"`{fmt_weight(new_total)}` {weight_bar(new_total, ceiling=max_awarn_weight)}",
inline=False,
)
if reason:
Expand All @@ -857,6 +881,7 @@ def _build_public_embed(
is_unawarn: bool,
guild: discord.Guild,
issuer_display_override: str | None = None,
max_awarn_weight: float = 3.0,
) -> discord.Embed:
"""Used in the public warn channel - slightly less detail, focus on who/what."""
delta_sign = "−" if is_unawarn else "+"
Expand All @@ -875,7 +900,7 @@ def _build_public_embed(
embed.add_field(name="Департамент", value=department_name, inline=True)
embed.add_field(
name="Текущий вес",
value=f"`{fmt_weight(new_total)}` {weight_bar(new_total)}",
value=f"`{fmt_weight(new_total)}` {weight_bar(new_total, ceiling=max_awarn_weight)}",
inline=False,
)
if reason:
Expand Down
47 changes: 46 additions & 1 deletion src/spesobot/cogs/departments.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,15 @@ async def _ensure_admin(self, interaction: discord.Interaction) -> bool:
name="create",
description="Создать новый департамент (валюту) на сервере.",
)
@app_commands.describe(name="Название департамента (напр. «Модерация»)")
@app_commands.describe(
name="Название департамента (напр. «Модерация»)",
max_warn_weight="Максимальный вес варнов (шкала заполнится при этом значении). По умолчанию 3.",
)
async def create(
self,
interaction: discord.Interaction,
name: app_commands.Range[str, 1, 80],
max_warn_weight: app_commands.Range[float, 0.25, 100.0] = 3.0,
) -> None:
if not await require_configured_guild(self.db, interaction):
return
Expand Down Expand Up @@ -126,9 +130,11 @@ async def create(
key=key,
name=name.strip(),
sort_order=existing_count,
max_awarn_weight=float(max_warn_weight),
)
embed = success_embed(
f"Департамент «{dept.name}» создан",
f"Максимальный вес варнов: **{max_warn_weight}**. "
"Дальше - назначьте кураторов и (если нужно) донат-роли:",
)
embed.add_field(
Expand Down Expand Up @@ -277,6 +283,44 @@ async def log(
brand_footer(embed, guild=guild)
await interaction.response.send_message(embed=embed, ephemeral=True)

# ---- /department warn_limit ----------------------------------------

@department_group.command(
name="warn_limit",
description="Установить максимальный вес варнов для департамента.",
)
@app_commands.describe(
name="Название департамента",
max_warn_weight="Максимальный вес варнов (шкала заполнится при этом значении).",
)
@app_commands.autocomplete(name=department_autocomplete)
async def warn_limit(
self,
interaction: discord.Interaction,
name: str,
max_warn_weight: app_commands.Range[float, 0.25, 100.0],
) -> None:
if not await require_configured_guild(self.db, interaction):
return
if not await self._ensure_admin(interaction):
return
guild = interaction.guild
assert guild is not None

dept = await self._resolve(guild.id, name)
if dept is None:
await self._respond_unknown(interaction, name)
return

await self.db.set_department_max_awarn_weight(dept.id, float(max_warn_weight))
embed = success_embed(
f"Лимит варнов обновлён · {dept.name}",
f"Максимальный вес варнов для **{dept.name}** установлен: **{max_warn_weight}**.\n"
"Шкала и цвета в эмбедах будут рассчитываться относительно этого значения.",
)
brand_footer(embed, guild=guild)
await interaction.response.send_message(embed=embed, ephemeral=True)

# ---- /department view ----------------------------------------------

@department_group.command(
Expand Down Expand Up @@ -317,6 +361,7 @@ async def view(self, interaction: discord.Interaction) -> None:
f"**Донат-роли:** {' '.join(f'<@&{r}>' for r in dons) if dons else '-'}",
f"**Товаров в магазине:** {shop_count}",
f"**Лог-канал:** {log_str}",
f"**Макс. вес варнов:** {d.max_awarn_weight:g}",
]
embed.add_field(
name=f"🏛 {d.name}",
Expand Down
Loading
Loading