Пример #1
0
    async def participantsNotifyer(self):
        for orgEvent in self.client.orgEvents.events:
            # Alerts to be removed.
            discardAlerts = []
            for alert in orgEvent.notifications.participantAlerts:
                if(
                    datetime.utcnow() > alert.time and
                    datetime.utcnow() - alert.margin < alert.time
                ):
                    roles = []
                    if orgEvent.roles:
                        roles.append(orgEvent.roles['participant'])

                    self.handleParticipantNotification(
                        alert,
                        orgEvent.dateAndTime,
                        orgEvent.participants,
                        roles
                    )

                if datetime.utcnow() > alert.time:
                    discardAlerts.append(alert)

            for alert in discardAlerts:
                orgEvent.notifications.participantAlerts.remove(alert)

            if discardAlerts:
                utility.saveData(
                    Constants.EVENT_DATA_FILENAME,
                    self.client.orgEvents.json(indent=2)
                )
Пример #2
0
    def clearEventData(self, orgEvent):
        # Remove event from event list if found.
        self.client.orgEvents.events.remove(orgEvent)

        # Save data
        eventData = self.client.orgEvents.json(indent=2)
        saveData(Constants.EVENT_DATA_FILENAME, eventData)
Пример #3
0
    async def set_rsi_handle(self, ctx, *, rsiHandle=''):
        """Sets the RSI handle of the user invoking the command.

        :param rsiHandle: RSI handle
        :type rsiHandle: str

        example:
        !eb.set_rsi_handle myRSIhandle
        """

        if rsiHandle == '':
            await ctx.send(
                'Please specify your RSI handle by typing:\n'
                f'{Constants.CMD_PREFIX}set_rsi_handle <your rsi handle> '
                'without the <>')
            return
        if len(rsiHandle) < 3:
            await ctx.send(
                'RSI handles must be at least 3 characters long. Please enter '
                'a valid RSI handle.')
            return
        if ' ' in rsiHandle:
            await ctx.send(
                'RSI handles cannot contain spaces. Please enter a valid '
                'RSI handle.')
            return

        # Search for user in guild members
        guildMembers = self.client.guildMembers.members
        for m in guildMembers:
            if m.id == ctx.author.id:
                m.rsiHandle = rsiHandle
                break
        else:
            m = event.GuildMember(id=ctx.author.id,
                                  name=ctx.author.name,
                                  rsiHandle=rsiHandle)
            guildMembers.append(m)

        guildMemberData = self.client.guildMembers.json(indent=2)
        utility.saveData(Constants.GUILD_MEMBER_DATA_FILENAME, guildMemberData)

        # Add to sheet if in daymar event, and participant is active.
        orgEvents = self.client.orgEvents.events
        for e in orgEvents:
            if e.eventType == event.EventType.daymar:
                p = e.getParticipant(ctx.author.id)
                if p:
                    if p.active is True:
                        self.addParticipant(m)
                break

        await ctx.send(
            f'Your RSI handle has been set to: **{rsiHandle}**\n'
            'You may change your registered RSI handle name at any time by '
            'running this command again.')
Пример #4
0
    async def setEventManagerId(self, ctx, id):
        """Sets the ID of the event manager.
        """
        user = self.client.get_user(int(id))

        if user:
            await ctx.send(f'Event manager id ({id}) set successfully.')
            self.client.config.eventManagerId = int(id)
            configData = self.client.config.json(indent=2)
            saveData(Constants.CONFIG_DATA_FILENAME, configData)
        else:
            await ctx.send('Could not find any user with that ID.')
Пример #5
0
    async def setGuildId(self, ctx):
        """Sets the ID of the current guild as the event bot guild ID.
        """
        # Get the id of the guild from where the command was invoked.
        guildId = ctx.guild.id
        # Set the id in config object
        self.client.config.guildId = guildId
        # Save config to file
        configData = self.client.config.json(indent=2)
        saveData(Constants.CONFIG_DATA_FILENAME, configData)

        await ctx.send(f'Guild ID ({guildId}) has been set.')
Пример #6
0
    async def handleCancellation(
            self, payload
    ):  # TODO: generalize method to handle more emojis and roles.
        """
        messageId = payload.message_id
        # Check which event was reacted to
        orgEvent = self.getEvent(messageId)
        # Get channel object
        channel = self.client.get_channel(payload.channel_id)
        # Get the Message object.
        message = await channel.fetch_message(messageId)
        # Get the Guild object.
        guild = message.guild
        # Get the user who reacted
        member = guild.get_member(payload.user_id)
        """

        data = await self.gatherPayloadData(payload)
        orgEvent, member, message, memeberRole, collabRole, emoji = data
        guild = message.guild

        # No action should be taken if the bot made the reaction.
        if member.bot:
            return

        # Remove reaction
        await message.remove_reaction(emoji, member)

        person = orgEvent.getParticipant(member.id)
        if person is not None:
            person.active = False
            if person.roles:
                roleId = orgEvent.roles['participant'].id
                person.removeRole(roleId)

                # Get the discord role.
                participantRole = guild.get_role(roleId)
                await member.remove_roles(participantRole)

        utility.saveData(Constants.EVENT_DATA_FILENAME,
                         self.client.orgEvents.json(indent=2))

        # Update embed in discord.
        self.makeUpdate(orgEvent)

        # Do daymar specific actions if daymar event.
        if orgEvent.eventType == event.EventType.daymar:
            cog = self.client.get_cog('Daymar')
            cog.clearParticipant(member)
Пример #7
0
    async def forceNewMessage(self, ctx, oldId):
        # TODO: REFACTOR THIS HOTFIX

        # Convert input to int
        oldId = int(oldId)

        for orgEvent in self.client.orgEvents.events:
            if orgEvent.id == oldId:
                myEvent = orgEvent
                break
        else:
            return

        guild = self.client.get_guild(self.client.config.guildId)

        channel = guild.get_channel(self.client.config.signupChannelId)

        # Delete old message if exists.
        try:
            oldMsg = await channel.fetch_message(oldId)
            await oldMsg.delete()
        except discord.NotFound:
            pass

        user = self.client.get_user(myEvent.organizer.id)

        vc = guild.get_channel(self.client.config.defaultVoiceChannelId)

        embed = myEvent.makeEmbed(True, user, mainVoiceName=vc.name)

        # Post the new embed.
        msg = await channel.send(embed=embed)
        # Register the new event id.
        myEvent.id = msg.id
        # Add reactions to the message. #TODO refactor wet code (make a method for adding the reactions in evntCog)
        await msg.add_reaction(Constants.REACTION_EMOJIS['participate'])
        await msg.add_reaction(Constants.REACTION_EMOJIS['cancel'])
        if True in orgEvent.privateIndication.values():
            await msg.add_reaction(Constants.REACTION_EMOJIS['info'])
        await msg.add_reaction(Constants.REACTION_EMOJIS['help'])

        eventData = self.client.orgEvents.json(indent=2)
        saveData(Constants.EVENT_DATA_FILENAME, eventData)
Пример #8
0
    async def deadlineNotifyer(self):
        for orgEvent in self.client.orgEvents.events:
            discardAlerts = []
            for alert in orgEvent.notifications.deadlineAlerts:
                if(
                    datetime.utcnow() > alert.time and
                    datetime.utcnow() - alert.margin < alert.time
                ):
                    self.handleDeadlineNotification(alert, orgEvent.deadline)

                if datetime.utcnow() > alert.time:
                    discardAlerts.append(alert)

            for alert in discardAlerts:
                orgEvent.notifications.deadlineAlerts.remove(alert)

            if discardAlerts:
                utility.saveData(
                    Constants.EVENT_DATA_FILENAME,
                    self.client.orgEvents.json(indent=2)
                )
Пример #9
0
    async def eventNotifyer(self):
        for orgEvent in self.client.orgEvents.events:
            # Indices of alerts to be removed.
            discardAlerts = []
            for alert in orgEvent.notifications.generalAlerts:
                if(
                    datetime.utcnow() > alert.time and
                    datetime.utcnow() - alert.margin < alert.time
                ):
                    self.handleEventNotification(alert, orgEvent.dateAndTime)

                if datetime.utcnow() > alert.time:
                    discardAlerts.append(alert)

            for alert in discardAlerts:
                orgEvent.notifications.generalAlerts.remove(alert)

            if discardAlerts:
                utility.saveData(
                    Constants.EVENT_DATA_FILENAME,
                    self.client.orgEvents.json(indent=2)
                )
Пример #10
0
    async def handleParticipationRequest(self, payload):
        """
        messageId = payload.message_id
        # Check which event was reacted to
        orgEvent = self.getEvent(messageId)
        # Get the Channel object.
        channel = self.client.get_channel(payload.channel_id)
        # Get the Message object.
        message = await channel.fetch_message(messageId)
        # Get the Guild object.
        guild = message.guild
        # Get the user who reacted
        member = guild.get_member(payload.user_id)
        # Get the role that official members will have.
        memberRole = guild.get_role(Constants.MEMBER_ROLE_ID)
        """

        data = await self.gatherPayloadData(payload)
        orgEvent = data[0]
        member = data[1]

        # No action should be taken if the bot made the reaction.
        if member.bot:
            return

        # Remove reaction
        message = data[2]
        emoji = data[5]
        await message.remove_reaction(emoji, member)

        # Check that event was found in the internal record.
        if not orgEvent:
            self.client.logger.warning(
                'Someone tried to sign up for an untracked event.')
            return

        # Check that event is not over, and handle rejection if required.
        if await self.eventHasPassed(data):
            return

        # Check that the deadline has not passed, and handle rejection if req.
        if await self.deadlineExceeded(data):
            return

        # If event is private, check if user has proper authorization.
        if orgEvent.data['Members Only'].upper() == 'YES':
            # Check that user has member role, handle rejection if not.
            if await self.noMemberRole(data):
                return

        # Attempt to get person object
        person = orgEvent.getParticipant(member.id)
        if person is not None:
            person.active = True
            # Check if user already has role, handle rejection if necessary.
            if await self.userAlreadyHasRole(data):
                return

            orgEvent.moveToBottom(person)

        # If user has passed all flags, add user to event and update
        # the embed.

        # Add role/person with role to internal event object.
        if 'participant' in orgEvent.roles.keys():
            pRole = orgEvent.roles['participant']
        else:
            pRole = None

        if person is None:
            person = event.Person(id=member.id, name=member.name, active=True)
            orgEvent.participants.append(person)

        if pRole is not None:
            person.roles.append(pRole)

        # if person is None:
        #     person = event.Person(id=member.id, name=member.name)
        #     if pRole:
        #         person.roles.append(pRole)
        #     orgEvent.participants.append(person)
        # elif pRole:
        #     person.roles.append(orgEvent.roles['participant'])

        # Add discord role.
        if pRole is not None:
            await self.addDiscordRole(member, orgEvent.roles['participant'])

        # Serialize data.
        utility.saveData(Constants.EVENT_DATA_FILENAME,
                         self.client.orgEvents.json(indent=2))

        # Update embed in discord.
        self.makeUpdate(orgEvent)

        # Send welcome message to the discussion channel.
        if 'discussion' in orgEvent.channels.keys():
            await self.sendWelcomeMsg(member, orgEvent.channels['discussion'])

        # Do extra actions if the event is a daymar event.
        if orgEvent.eventType == event.EventType.daymar:

            # Search through guild member record and add person if not found.
            guildMembers = self.client.guildMembers.members
            for m in guildMembers:
                if m.id == member.id:
                    guildMember = m
                    break
            else:
                guildMember = None

            if guildMember is None:
                guildMember = event.GuildMember(
                    id=member.id,
                    name=member.name,
                )
                guildMembers.append(guildMember)
                utility.saveData(Constants.GUILD_MEMBER_DATA_FILENAME,
                                 self.client.guildMembers.json(indent=2))
            cog = self.client.get_cog('Daymar')
            if guildMember.rsiHandle is not None:
                cog.addParticipant(guildMember)
            else:
                # Ask user to confirm rsi handle.
                # TODO: Link to command more robustly
                await member.send(
                    'In order for Daymar organizers to invite you to their '
                    'server they need to know your in game name (RSI handle).'
                    '\nPlease specify your RSI handle by using the '
                    '**!eb.set_rsi_handle** command.\n'
                    'For detailed help with this command type '
                    '!eb.help set_rsi_handle')
                cog.addParticipant(guildMember)
Пример #11
0
    async def processData(self, eventData,
                          keys):  # TODO: Rename? processEventCreation

        # Get the event type.
        eventType = self.getEventType(eventData)

        # Get the event organizer
        organizer = self.getEventOrganizer(eventData)

        # Create roles for event
        discordRoles = await self.createRoles(eventData)
        # Convert discordRoles to internal roles for persistant storage.
        if discordRoles:
            roles = {
                'spectator':
                event.Role(id=discordRoles['spectator'].id,
                           name=discordRoles['spectator'].name),
                'participant':
                event.Role(id=discordRoles['participant'].id,
                           name=discordRoles['participant'].name)
            }
        else:
            roles = {}

        discordChannels = await self.createChannels(eventData,
                                                    discordRoles,
                                                    eventType=eventType)

        # Convert discordChannels to internal channels for persistent storage.
        channels = {}
        for key, channel in discordChannels.items():
            channels[key] = event.Channel(id=channel.id,
                                          name=channel.name,
                                          channelType=event.ChannelType(
                                              channel.type.value))

        # Convert the dates from string to datetime objects
        dateAndTime, deadline = self.convertDates(eventData, 'Date Time',
                                                  'Deadline')

        # Get the image url if found in resource channel.
        imageUrl = await self.getImageUrl(eventData['Event'])

        # Create default general alerts list.
        generalAlerts = self.makeAlerts(eventData['Event'],
                                        dateAndTime,
                                        deadline,
                                        channels,
                                        general=True)
        strings = ['The following general alerts were created:\n']
        [strings.append(str(a.time) + '\n') for a in generalAlerts]

        self.client.logger.debug(''.join(strings))

        if deadline is not None:
            deadlineAlerts = self.makeAlerts(eventData['Event'],
                                             dateAndTime,
                                             deadline,
                                             channels,
                                             deadlineAlerts=True)

            strings = ['The following deadline alerts were created:\n']
            [strings.append(str(a.time) + '\n') for a in deadlineAlerts]

            self.client.logger.debug(''.join(strings))
        else:
            deadlineAlerts = []

        # Create default participant alerts list.
        participantAlerts = self.makeAlerts(eventData['Event'],
                                            dateAndTime,
                                            deadline,
                                            channels,
                                            participant=True)
        strings = ['The following participant alerts was created:\n']
        [strings.append(str(a.time) + '\n') for a in participantAlerts]

        self.client.logger.debug(''.join(strings))

        # Create notifications for event.
        notifications = event.Notifications(
            generalAlerts=generalAlerts,
            deadlineAlerts=deadlineAlerts,
            participantAlerts=participantAlerts)

        # Instanciate event object.
        eventInstance = event.Event(data=eventData,
                                    eventType=eventType,
                                    dateAndTime=dateAndTime,
                                    deadline=deadline,
                                    keys=keys,
                                    organizer=organizer,
                                    imageUrl=imageUrl,
                                    roles=roles,
                                    channels=channels,
                                    lastUpdate=datetime.utcnow(),
                                    notifications=notifications)
        # TODO: Line below should be done in class initialisation, but idk how
        # to do that correctly with pydantic BaseModel classes.
        # Maybe inherit from datamodel instead?
        eventInstance.privateIndication = eventInstance.decodePrivate(
            eventData['Color Code'])

        # Assign ID by posting message to discord and saving the returned ID
        # in the event object.
        registeredEvent = await self.assignId(eventInstance)

        # If event contains private information, post the uncensored embed in
        # the newly opened channel.
        # TODO: Make sure that private channel embed is also updated when the
        # main embed is updated.
        if 'briefing' in discordChannels:
            user = self.client.get_user(registeredEvent.organizer.id)
            embed = registeredEvent.makeEmbed(False,
                                              user,
                                              includeAuthor=False,
                                              includeFooter=False,
                                              includePreamble=False,
                                              includeRollCall=False,
                                              includeVoiceChnl=False)
            channel = discordChannels['briefing']
            privateMsg = await channel.send(embed=embed)

            if eventData['Additional Info'] != '':
                await channel.send(eventData['Additional Info'])
            # TODO: Figure out how to store privateMsg. This is the embed
            # msg sent to private briefing channels. In order to update, the
            # d.py message object id must be stored.

        # Write IDs back to google sheets.
        self.writeIdToSheets(eventInstance)

        # If event is a daymar event the daymar spreadsheet is cleared.
        if eventInstance.eventType == event.EventType.daymar:
            try:
                cog = self.client.get_cog('Daymar')
                cog.clearDaymarSheet()
            except Exception:  # TODO: Specify exception.
                self.client.logger.warning(
                    'Not able to connect to Spreadsheet')

        # Append the event to the clients list of events
        self.client.orgEvents.events.append(registeredEvent)
        utility.saveData(Constants.EVENT_DATA_FILENAME,
                         self.client.orgEvents.json(indent=2))
Пример #12
0
 def test_saveData_fileCreatedForValidData(self):
     testString = 'something'
     success = utility.saveData('saveDataTest.json', testString)
     self.assertTrue(os.path.exists('saveDataTest.json'))
     if success:
         os.remove('saveDataTest.json')
Пример #13
0
        maxBytes=8 * 1024 * 1024,  # Max size is 8MB
        backupCount=1,
        encoding='utf-8')
    handler.setFormatter(
        logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s'))
    logger.addHandler(handler)
    client.logger = logger

    # TODO: Clean up wet code. Deserialization should done in a function.
    # Deserialize configuration data.
    configData = loadData(Constants.CONFIG_DATA_FILENAME)
    if configData is None:
        client.logger.info('Config data not found.')
        client.config = configuration.Configuration()
        configData = client.config.json(indent=2)
        saveData(Constants.CONFIG_DATA_FILENAME, configData)
    else:
        try:
            # Attempt to parse persistent config data to config.
            client.config = configuration.Configuration.parse_obj(configData)
            client.logger.info('Config data successfully parsed.')
        except ValidationError as e:
            client.logger.warning(
                'Exception thrown, error message is as follows:\n'
                f'{e}\n'
                'Config data was found, but could not be loaded. '
                'Starting clean')

            client.config = configuration.Configuration()
            configData = client.config.json(indent=2)
            saveData(Constants.CONFIG_DATA_FILENAME, configData)
Пример #14
0
 async def serializeConfig(self, ctx, attribute, id):
     setattr(self.client.config, attribute, id)
     configData = self.client.config.json(indent=2)
     saveData(Constants.CONFIG_DATA_FILENAME, configData)
     await ctx.send(f'{attribute} successfully set, ID is {id}')