Skip to content
Open
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
2 changes: 1 addition & 1 deletion registration/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[project]
name = "ICRS Discord Bot"
version = "1.0.6"
version = "1.0.7"
description = "Main ICRS Discord Bot."
requires-python = ">=3.8"
25 changes: 25 additions & 0 deletions registration/src/bot_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
card_office,
who_is_printing,
project_admin_dashboard,
add_mac_address,
trained_member_present
)
from src.utils import (deregister_discord_id, error_msg,
committee_command, SERVER_IP, verified_member,
Expand Down Expand Up @@ -350,6 +352,29 @@ async def permissions_(
async def whois_printing_(
interaction: discord.Interaction):
return await who_is_printing(interaction)

@self.tree.command(
name="add-mac-address",
description="**ADMIN ONLY**: Add a BLE mac address to trained committee"
)
@committee_command
async def add_mac_address_(
interaction : discord.Interaction,
user : str,
mac_addr : str
):
return await add_mac_address(interaction, user, mac_addr)
@self.tree.command(
name="trained-member-present",
description="**ADMIN ONLY**: Check if a lab trained member is present in a time interval"
)
@committee_command
async def trained_member_present_(
interaction: discord.Interaction,
timestamp: str,
interval: int,
):
return await trained_member_present(interaction, timestamp, interval)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this needed? might be nicer to have a status page + webhook like how the printer streaming stuff is done?


async def on_message(self, message): # pylint: disable=arguments-differ
"""
Expand Down
2 changes: 2 additions & 0 deletions registration/src/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from .project import *
from .project_admin import *
from .permissions import *
from .mac_addresses import *

__all__ = []
__all__.extend(project.__all__)
Expand All @@ -27,6 +28,7 @@
__all__.extend(printer_commands.__all__)
__all__.extend(printer_status_commands.__all__)
__all__.extend(induct.__all__)
__all__.extend(mac_addresses.__all__)

__all__.extend(timelapse.__all__)
__all__.extend(quote.__all__)
Expand Down
121 changes: 121 additions & 0 deletions registration/src/commands/mac_addresses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
__all__ = [
"add_mac_address",
"trained_member_present"
]

import logging
import discord
import requests
from datetime import datetime

from src.utils import SERVER_IP
import src.utils as utils

async def add_mac_address(
interaction: discord.Interaction,
user: str | discord.User | discord.Member,
mac_address: str,
):
logging.info(f"Add MAC Address: {user}")

if isinstance(user, str):
if not utils.is_shortcode(user):
logging.info(f"add MAC Address shortcode invalid: {user}")
return await interaction.response.send_message(
embed=utils.invalid_shortcode(), ephemeral=True
)

discord_id = utils.get_discord_from_shortcode(user)
shortcode = user

else:
discord_id = str(user.id)
logging.info(f"add MAC address Discord ID: {discord_id}")

shortcode = utils.get_shortcode_from_discord(discord_id)

if not shortcode:
return await interaction.response.send_message(
embed=utils.error_msg(
f"Couldn't get short code for <@{discord_id}>",
"Add mac address Warning"),
ephemeral=True)

if not utils.is_mac_address(mac_address):
logging.info("invalid mac address format")
return await interaction.response.send_message(
embed=utils.error_msg(
f"Invalid mac address {mac_address}",
"Mac address invalid warning"
),
ephemeral=True
)



response = requests.post(
SERVER_IP + "/member/mac_addresses/add",
params={
"shortcode": shortcode,
"mac_address": mac_address
}
)

if response.status_code == 200:
embed = discord.Embed(
title="Add mac address",
description=f"Successfully added {mac_address} to {shortcode}"
)
return await interaction.response.send_message(
embed=embed,
ephemeral=True,
)

return await interaction.response.send_message(
embed=utils.error_msg(
"Failed to add to db",
"MAC Address not added"
),
ephemeral=True,
)

async def trained_member_present(
interaction: discord.Interaction,
timestamp: str,
interval: int
):
try:
timestamp = datetime.strptime(timestamp, "%Y-%m-%d %H:%M")
except:
return await interaction.response.send_message(
embed=utils.error_msg(
"Format should be YYYY-MM-DD HH:MM",
"Invalid timestamp format"
),
ephemeral=True
)
response = requests.get(
SERVER_IP + "/access/trained_member_present",
params= {
"timestamp": str(timestamp),
"interval": interval
}
)

if len(response.json()) > 0:
embed = discord.Embed(
title="Committee Present",
description="\n".join(response.json())
)
return await interaction.response.send_message(
embed=embed,
ephemeral=True
)
else:
return await interaction.response.send_message(
embed=utils.error_msg(
"No trained members present in that time interval",
"NO TRAINED MEMBER"
),
ephemeral=True
)
15 changes: 12 additions & 3 deletions registration/src/commands/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
CAN_LASER = "Can Laser"
CAN_RESIN = "Can Resin"
PRINTER_OVERRIDE = "Printer Override"
IS_LAB_TRAINED = "Is Lab Trained"


class PermissionSelect(discord.ui.Select):
Expand All @@ -24,7 +25,7 @@ def __init__(
**kwargs) -> None:
super().__init__(
min_values=0,
max_values=5,
max_values=6,
**kwargs)

self.shortcode = shortcode
Expand Down Expand Up @@ -55,6 +56,11 @@ def __init__(
value=PRINTER_OVERRIDE,
default=permission_info.printer_override,
)
self.add_option(
label=IS_LAB_TRAINED,
value=IS_LAB_TRAINED,
default=permission_info.is_lab_trained,
)

async def callback(self, interaction: discord.Interaction):
o = self.values
Expand All @@ -64,15 +70,17 @@ async def callback(self, interaction: discord.Interaction):
can_laser = CAN_LASER in o
can_resin = CAN_RESIN in o
printer_override = PRINTER_OVERRIDE in o
is_lab_trained = IS_LAB_TRAINED in o

logging.info(
f"Selected {can_print} {inducted} {can_laser} {can_resin} {printer_override}")
f"Selected {can_print} {inducted} {can_laser} {can_resin} {printer_override} {is_lab_trained}")

if (self.permissions.print == can_print and
self.permissions.inducted == inducted and
self.permissions.laser == can_laser and
self.permissions.resin == can_resin and
self.permissions.printer_override == printer_override):
self.permissions.printer_override == printer_override and
self.permissions.is_lab_trained == is_lab_trained):
return await interaction.response.edit_message(
embed=discord.Embed(
title="Successfully updated Permssions",
Expand All @@ -91,6 +99,7 @@ async def callback(self, interaction: discord.Interaction):
"laser": can_laser,
"resin": can_resin,
"printer_override": printer_override,
"is_lab_trained": is_lab_trained
},
auth=BASIC_AUTH
)
Expand Down
14 changes: 13 additions & 1 deletion registration/src/commands/whois_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ async def whois(interaction: discord.Interaction, *,
"Inducted: " + str(perms.get("inducted", "Not Found")) + "\n" +
"Can Print: " + str(perms.get("print", "Not Found")) + "\n" +
"Can Laser: " + str(perms.get("laser", "Not Found")) + "\n" +
"Can Resin: " + str(perms.get("resin", "Not Found")) + "\n"
"Can Resin: " + str(perms.get("resin", "Not Found")) + "\n" +
"Print Override: " + str(perms.get("printer_override", "Not Found")) + "\n" +
"Is Lab Trained: " + str(perms.get("is_lab_trained", "Not Found")) + "\n"
),
inline=False)

Expand All @@ -94,6 +96,16 @@ async def whois(interaction: discord.Interaction, *,
f"Started At: {last_print.time_started}"
),
inline=False)

mac_addrs = utils.get_mac_addresses_from_shortcode(shortcode)

if mac_addrs:
embed.add_field(
name="MAC Addresses",
value=(
"\n".join(mac_addrs)
)
)
if discord_id:
res = requests.get(
utils.SERVER_IP + "/user/notes",
Expand Down
15 changes: 15 additions & 0 deletions registration/src/utils/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"get_shortcode_from_discord",
"get_perms_from_shortcode",
"MemberPermissions",
"get_mac_addresses_from_shortcode"
]

"""
Expand Down Expand Up @@ -97,6 +98,7 @@ class MemberPermissions:
card_id: str = ""
resin: bool = False
printer_override: bool = False
is_lab_trained: bool = False


def get_perms_from_shortcode(shortcode: str) -> MemberPermissions:
Expand Down Expand Up @@ -136,6 +138,19 @@ def get_stats_from_discord(discord_id: str):

return Stats()

def get_mac_addresses_from_shortcode(shortcode: str):
res = requests.get(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generally best to return response obj directly - allows you to handle different status codes differently in different scenarios

SERVER_IP + "/member/mac_addresses",
params={
"shortcode": shortcode
},
auth=BASIC_AUTH
)

if res.status_code == 200:
return res.json()

return None

@dataclass
class Print:
Expand Down
6 changes: 6 additions & 0 deletions registration/src/utils/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"validate_card_uid",
"validate_shortcode",
"verified_member",
"is_mac_address"
]


Expand All @@ -25,6 +26,7 @@
SHORTCODE_REGEX = r'^[a-z]{2,3}\d{2,5}$'
UID_REGEX = r'^[0-9A-F]{8,14}$'
DISCORD_ID_REGEX = r'^<@[0-9]{18,19}>$'
MAC_ADDR_REGEX = r'^([0-9A-F]{2}:){5}[0-9A-F]{2}'
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add $ at end



def is_shortcode(message: str) -> bool:
Expand Down Expand Up @@ -63,6 +65,10 @@ def is_not_committee(author: discord.User | discord.Member):
def is_member(author: discord.User | discord.Member):
return "verified member" in [y.name.lower() for y in author.roles]

def is_mac_address(mac_addr : str):
mac_addr = mac_addr.upper()
found = re.findall(MAC_ADDR_REGEX, mac_addr)
return any(found)

def committee_command(function: Callable):
@functools.wraps(function)
Expand Down