Fix edgecases for automatic user creation

- make eventdescription !wp case insensitive

- Create accounts for users in channel without subscription when event starts

- Make sent messages caused by VoiceState event dependant on creation result (created, enabled)

- Create tmp user if normal user exists but is disabled
This commit is contained in:
Sammy 2023-06-09 23:56:45 +02:00
parent c0b24ee3ad
commit 1e1ab93667
3 changed files with 49 additions and 26 deletions

View File

@ -1,8 +1,8 @@
import { GuildScheduledEvent, GuildScheduledEventStatus, Collection, Snowflake, GuildScheduledEventUser } from "discord.js"; import { GuildMember, GuildScheduledEvent, GuildScheduledEventStatus } from "discord.js";
import { logger } from "../logger";
import { jellyfinHandler } from "../.."
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import { jellyfinHandler } from "../..";
import { getGuildSpecificTriggerRoleId } from "../helper/roleFilter"; import { getGuildSpecificTriggerRoleId } from "../helper/roleFilter";
import { logger } from "../logger";
export const name = 'guildScheduledEventUpdate' export const name = 'guildScheduledEventUpdate'
@ -12,14 +12,23 @@ export async function execute(oldEvent: GuildScheduledEvent, newEvent: GuildSche
logger.info(JSON.stringify(newEvent, null, 2)) logger.info(JSON.stringify(newEvent, null, 2))
const requestId = uuid() const requestId = uuid()
if (newEvent.description?.includes("!WP") && [GuildScheduledEventStatus.Active, GuildScheduledEventStatus.Completed].includes(newEvent.status)) { if (newEvent.description?.toLowerCase().includes("!wp") && [GuildScheduledEventStatus.Active, GuildScheduledEventStatus.Completed].includes(newEvent.status)) {
const roles = getGuildSpecificTriggerRoleId(newEvent.guildId).map((key, value)=> value) const roles = getGuildSpecificTriggerRoleId(newEvent.guildId).map((key, value)=> value)
const members = (await newEvent.fetchSubscribers({ withMember: true })).filter(member => !member.member.roles.cache.hasAny(...roles)) const eventMembers = (await newEvent.fetchSubscribers({ withMember: true })).filter(member => !member.member.roles.cache.hasAny(...roles)).map((value, _) => value.member)
const channelMembers = newEvent.channel?.members.filter(member => !member.roles.cache.hasAny(...roles)).map((value, _) => value )
const allMembers = eventMembers.concat(channelMembers ?? [])
const members: GuildMember[] = []
for(const member of allMembers){
if(!members.find(x => x.id == member.id))
members.push(member)
}
if (newEvent.status === GuildScheduledEventStatus.Active) if (newEvent.status === GuildScheduledEventStatus.Active)
createJFUsers(members, newEvent.name, requestId) createJFUsers(members, newEvent.name, requestId)
else { else {
members.forEach(member => { members.forEach(member => {
member.member.createDM().then(channel => channel.send(`Die Watchparty ist vorbei, dein Account wurde wieder gelöscht. Wenn du einen permanenten Account haben möchtest, melde dich bei Samantha oder Marukus.`)) member.createDM().then(channel => channel.send(`Die Watchparty ist vorbei, dein Account wurde wieder gelöscht. Wenn du einen permanenten Account haben möchtest, melde dich bei Samantha oder Marukus.`))
}) })
deleteJFUsers(newEvent.guildId, requestId) deleteJFUsers(newEvent.guildId, requestId)
} }
@ -28,11 +37,11 @@ export async function execute(oldEvent: GuildScheduledEvent, newEvent: GuildSche
logger.error(error) logger.error(error)
} }
} }
async function createJFUsers(members: Collection<Snowflake, GuildScheduledEventUser<true>>, movieName: string, requestId?: string) { async function createJFUsers(members: GuildMember[], movieName: string, requestId?: string) {
logger.info(`Creating users for: \n ${JSON.stringify(members, null, 2)}`) logger.info(`Creating users for: \n ${JSON.stringify(members, null, 2)}`)
members.forEach(member => { members.forEach(member => {
member.member.createDM().then(channel => channel.send(`Hey! Du hast dich für die Watchparty von ${movieName} angemeldet! Es geht gleich los!`)) member.createDM().then(channel => channel.send(`Hey! Du hast dich für die Watchparty von ${movieName} angemeldet! Es geht gleich los!`))
jellyfinHandler.upsertUser(member.member, "TEMPORARY", requestId) jellyfinHandler.upsertUser(member, "TEMPORARY", requestId)
}) })
} }

View File

@ -1,7 +1,8 @@
import { GuildScheduledEvent, GuildScheduledEventStatus, Collection, Snowflake, GuildScheduledEventUser, User, VoiceState } from "discord.js"; import { VoiceState } from "discord.js";
import { logger } from "../logger";
import { jellyfinHandler } from "../.."
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import { jellyfinHandler } from "../..";
import { UserUpsertResult } from "../jellyfin/handler";
import { logger } from "../logger";
export const name = 'voiceStateUpdate' export const name = 'voiceStateUpdate'
@ -9,13 +10,15 @@ export const name = 'voiceStateUpdate'
export async function execute(oldState: VoiceState, newState: VoiceState) { export async function execute(oldState: VoiceState, newState: VoiceState) {
try { try {
logger.info(JSON.stringify(newState, null, 2))
//ignore events like mute/unmute //ignore events like mute/unmute
if(newState.channel?.id === oldState.channel?.id) { if(newState.channel?.id === oldState.channel?.id) {
logger.info("Not handling VoiceState event because channelid of old and new was the same (i.e. mute/unmute event)")
return return
} }
const scheduledEvents = (await newState.guild.scheduledEvents.fetch()) const scheduledEvents = (await newState.guild.scheduledEvents.fetch())
.filter((key, value) => key.description?.includes("!WP") && key.isActive()) .filter((key, value) => key.description?.toLowerCase().includes("!wp") && key.isActive())
.map((key, value) => key) .map((key, value) => key)
const scheduledEventUsers = (await Promise.all(scheduledEvents.map(event => event.fetchSubscribers({withMember: true})))) const scheduledEventUsers = (await Promise.all(scheduledEvents.map(event => event.fetchSubscribers({withMember: true}))))
@ -29,19 +32,26 @@ export async function execute(oldState: VoiceState, newState: VoiceState) {
userFound = true; userFound = true;
}) })
}) })
if(userFound) if(userFound) {
logger.info(`Not handling VoiceState event because user was already subscribed and got an account from there. User: ${JSON.stringify(newState.member, null, 2)}`)
return return
}
if (scheduledEvents.find(event => event.channelId === newState.channelId)) { if (scheduledEvents.find(event => event.channelId === newState.channelId)) {
if(newState.member){ if(newState.member){
logger.info("YO! Da ist jemand dem Channel mit dem Event beigetreten, ich kümmer mich mal um nen Account!") logger.info("YO! Da ist jemand dem Channel mit dem Event beigetreten, ich kümmer mich mal um nen Account!")
const result = await jellyfinHandler.upsertUser(newState.member, "TEMPORARY", uuid())
newState.member.createDM().then(channel => channel.send(`Hey! Du bist unserer Watchparty beigetreten, ich leg dir mal nen Account an, damit du mitschauen kannst!`)) if (result === UserUpsertResult.created) {
jellyfinHandler.upsertUser(newState.member, "TEMPORARY", uuid()) newState.member.createDM().then(channel => channel.send(`Hey! Du bist unserer Watchparty beigetreten, ich hab dir gerade die Zugangsdaten für den Mediaserver geschickt!`))
} else {
newState.member.createDM().then(channel => channel.send(`Hey! Du bist unserer Watchparty beigetreten aber du hast bereits einen Account. Falls du ein neues Passwort brauchst nutze /reset_passwort!`))
}
} else { } else {
logger.error("WTF? Expected Member?? When doing things") logger.error("WTF? Expected Member?? When doing things")
} }
} else {
logger.info("VoiceState channelId was not the id of any channel with events")
} }
}catch(error){ }catch(error){
logger.error(error) logger.error(error)

View File

@ -1,12 +1,11 @@
import { GuildMember } from "discord.js"; import { GuildMember } from "discord.js";
import { Config } from "../configuration";
import { Maybe, PermissionLevel } from "../interfaces";
import { logger } from "../logger";
import { CreateUserByNameOperationRequest, DeleteUserRequest, SystemApi, UpdateUserPasswordOperationRequest, UpdateUserPolicyOperationRequest, UserApi } from "./apis"; import { CreateUserByNameOperationRequest, DeleteUserRequest, SystemApi, UpdateUserPasswordOperationRequest, UpdateUserPolicyOperationRequest, UserApi } from "./apis";
import { UpdateUserPasswordRequest } from "./models";
import { UserDto } from "./models/UserDto"; import { UserDto } from "./models/UserDto";
import { Configuration, ConfigurationParameters } from "./runtime"; import { Configuration, ConfigurationParameters } from "./runtime";
import { CreateUserByNameRequest, UpdateUserEasyPasswordRequest, UpdateUserPasswordRequest, UpdateUserPolicyRequest } from "./models";
import { Config } from "../configuration";
import { logger } from "../logger";
import { Maybe, PermissionLevel } from "../interfaces";
import { v4 as uuid } from "uuid";
export class JellyfinHandler { export class JellyfinHandler {
@ -210,15 +209,20 @@ export class JellyfinHandler {
} }
} }
public async upsertUser(newMember: GuildMember, level: PermissionLevel, requestId?: string) { public async upsertUser(newMember: GuildMember, level: PermissionLevel, requestId?: string): Promise<UserUpsertResult> {
logger.error(`Trying to upsert user ${newMember.displayName}, with permissionLevel ${level}`, { guildId: newMember.guild.id, requestId }) logger.info(`Trying to upsert user ${newMember.displayName}, with permissionLevel ${level}`, { guildId: newMember.guild.id, requestId })
const jfuser = await this.getUser(newMember, requestId) const jfuser = await this.getUser(newMember, requestId)
if (jfuser) { if (jfuser && !jfuser.policy?.isDisabled) {
logger.info(`User with name ${newMember.displayName} is already present`, { guildId: newMember.guild.id, requestId }) logger.info(`User with name ${newMember.displayName} is already present`, { guildId: newMember.guild.id, requestId })
await this.enableUser(jfuser, newMember.guild.id, requestId) await this.enableUser(jfuser, newMember.guild.id, requestId)
return UserUpsertResult.enabled
} else { } else {
this.createUserAccountForDiscordUser(newMember, level, newMember.guild.id, requestId) this.createUserAccountForDiscordUser(newMember, level, newMember.guild.id, requestId)
return UserUpsertResult.created
} }
} }
}
}
export enum UserUpsertResult {enabled, created}