add /galtinn medlemskap
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1b5de65af2
commit
43a8f19c12
3 files changed
+114
-1
No files matched your search
@@ -1,5 +1,6 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import base64
|
import base64
|
||||||
|
import datetime
|
||||||
import hashlib
|
import hashlib
|
||||||
import secrets
|
import secrets
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
@@ -707,6 +708,105 @@ class Galtinn(commands.Cog):
|
|||||||
)
|
)
|
||||||
await interaction.followup.send(embed=embed, view=view)
|
await interaction.followup.send(embed=embed, view=view)
|
||||||
|
|
||||||
|
@app_commands.checks.bot_has_permissions(embed_links=True)
|
||||||
|
@app_commands.checks.cooldown(1, 5)
|
||||||
|
@galtinn_group.command(name="medlemskap", description="Sjekk medlemskap i Det Norske Studentersamfund")
|
||||||
|
@app_commands.rename(username="brukernavn", user="discordbruker")
|
||||||
|
@app_commands.describe(
|
||||||
|
username="Galtinn-brukernavnet",
|
||||||
|
user="Discordbrukeren som er koblet til Galtinn. Standard er deg selv",
|
||||||
|
)
|
||||||
|
async def membership(
|
||||||
|
self, interaction: discord.Interaction, username: str | None = None, user: discord.User | None = None
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Check someone's membership of Det Norske Studentersamfund
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
interaction (discord.Interaction): The slash command interaction
|
||||||
|
username (str | None): The Galtinn username to look up
|
||||||
|
user (discord.User | None): The Discord user to look up. Defaults to the invoking user
|
||||||
|
"""
|
||||||
|
|
||||||
|
if username and user:
|
||||||
|
embed = embed_templates.error_warning("Du kan ikke oppgi både brukernavn og discordbruker")
|
||||||
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
await interaction.response.defer(ephemeral=True)
|
||||||
|
|
||||||
|
# Only users who have linked their Discord account to Galtinn can look up memberships
|
||||||
|
invokers = await self.fetch_galtinn_users(discord_id=interaction.user.id)
|
||||||
|
if invokers is None:
|
||||||
|
embed = embed_templates.error_fatal("Klarte ikke å hente data fra Galtinn. Prøv igjen senere!")
|
||||||
|
await interaction.followup.send(embed=embed)
|
||||||
|
return
|
||||||
|
if not invokers.results:
|
||||||
|
embed = embed_templates.error_warning(
|
||||||
|
"Du må koble Galtinnbrukeren din til Discord med `/galtinn registrer` for å se medlemskap"
|
||||||
|
)
|
||||||
|
await interaction.followup.send(embed=embed)
|
||||||
|
return
|
||||||
|
|
||||||
|
if username:
|
||||||
|
found = await self.fetch_paginated("users", {"username": username}, Users)
|
||||||
|
not_found = "Fant ingen Galtinnbruker med det brukernavnet"
|
||||||
|
elif user and user.id != interaction.user.id:
|
||||||
|
found = await self.fetch_galtinn_users(discord_id=user.id)
|
||||||
|
not_found = "Den brukeren har ikke koblet Discordbrukeren sin til Galtinn"
|
||||||
|
else:
|
||||||
|
found = invokers
|
||||||
|
|
||||||
|
if found is None:
|
||||||
|
embed = embed_templates.error_fatal("Klarte ikke å hente data fra Galtinn. Prøv igjen senere!")
|
||||||
|
await interaction.followup.send(embed=embed)
|
||||||
|
return
|
||||||
|
if not found.results:
|
||||||
|
await interaction.followup.send(embed=embed_templates.error_warning(not_found))
|
||||||
|
return
|
||||||
|
|
||||||
|
await interaction.followup.send(embed=self.membership_embed(found.results[0]))
|
||||||
|
|
||||||
|
def membership_embed(self, galtinn_user: DuskenUser) -> discord.Embed:
|
||||||
|
"""
|
||||||
|
Build the embed that shows a user's membership
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
galtinn_user (DuskenUser): The user to show
|
||||||
|
|
||||||
|
Returns
|
||||||
|
----------
|
||||||
|
(discord.Embed): The embed
|
||||||
|
"""
|
||||||
|
|
||||||
|
membership = galtinn_user.last_membership
|
||||||
|
is_valid = bool(membership and membership.is_valid)
|
||||||
|
|
||||||
|
embed = discord.Embed(color=discord.Color.green() if is_valid else discord.Color.red())
|
||||||
|
embed.set_author(name=galtinn_user.username)
|
||||||
|
if galtinn_user.discord_profile:
|
||||||
|
embed.description = f"<@{galtinn_user.discord_profile.discord_id}>"
|
||||||
|
|
||||||
|
if not membership:
|
||||||
|
embed.add_field(name="Medlem?", value="Har aldri vært medlem")
|
||||||
|
return embed
|
||||||
|
|
||||||
|
embed.add_field(name="Medlem?", value="Ja" if is_valid else "Nei")
|
||||||
|
if membership.membership_type:
|
||||||
|
embed.add_field(name="Medlemskapstype", value=membership.membership_type)
|
||||||
|
if membership.end_date:
|
||||||
|
# Noon, so the date shows up the same in every time zone close to Norway
|
||||||
|
expires = datetime.datetime.combine(membership.end_date, datetime.time(12), tzinfo=misc_utils.TIMEZONE)
|
||||||
|
embed.add_field(
|
||||||
|
name="Gyldig til",
|
||||||
|
value=f"{discord.utils.format_dt(expires, 'D')}\n{discord.utils.format_dt(expires, 'R')}",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
embed.add_field(name="Gyldig til", value="Livstid")
|
||||||
|
return embed
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot: commands.Bot):
|
async def setup(bot: commands.Bot):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ from zoneinfo import ZoneInfo
|
|||||||
import aiohttp
|
import aiohttp
|
||||||
import discord
|
import discord
|
||||||
|
|
||||||
MIDNIGHT = datetime.time(hour=0, minute=0, tzinfo=ZoneInfo("Europe/Oslo"))
|
TIMEZONE = ZoneInfo("Europe/Oslo")
|
||||||
|
MIDNIGHT = datetime.time(hour=0, minute=0, tzinfo=TIMEZONE)
|
||||||
|
|
||||||
# The exceptions discord.py's tasks.loop retries instead of stopping on
|
# The exceptions discord.py's tasks.loop retries instead of stopping on
|
||||||
RETRIED_TASK_EXCEPTIONS = (
|
RETRIED_TASK_EXCEPTIONS = (
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from datetime import date
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
@@ -38,6 +39,16 @@ class UserDiscordProfile(BaseModel):
|
|||||||
user: int
|
user: int
|
||||||
|
|
||||||
|
|
||||||
|
class Membership(BaseModel):
|
||||||
|
"""A membership of Det Norske Studentersamfund"""
|
||||||
|
|
||||||
|
start_date: date
|
||||||
|
end_date: Optional[date] = None # None for lifelong memberships
|
||||||
|
# Galtinn leaves this out for members of the groups it counts as members without a membership
|
||||||
|
membership_type: Optional[str] = None
|
||||||
|
is_valid: bool
|
||||||
|
|
||||||
|
|
||||||
class DuskenUser(BaseModel):
|
class DuskenUser(BaseModel):
|
||||||
"""A Galtinn user"""
|
"""A Galtinn user"""
|
||||||
|
|
||||||
@@ -45,6 +56,7 @@ class DuskenUser(BaseModel):
|
|||||||
username: str
|
username: str
|
||||||
is_volunteer: bool
|
is_volunteer: bool
|
||||||
is_member: bool
|
is_member: bool
|
||||||
|
last_membership: Optional[Membership] = None
|
||||||
groups: list[Group]
|
groups: list[Group]
|
||||||
discord_profile: Optional[UserDiscordProfile]
|
discord_profile: Optional[UserDiscordProfile]
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user