All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.dv8tion.jda.internal.entities.mentions.AbstractMentions Maven / Gradle / Ivy

Go to download

Java wrapper for the popular chat & VOIP service: Discord https://discord.com

There is a newer version: 5.1.0
Show newest version
/*
 * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.dv8tion.jda.internal.entities.mentions;

import gnu.trove.map.TLongObjectMap;
import gnu.trove.map.hash.TLongObjectHashMap;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.interactions.commands.ICommandReference;
import net.dv8tion.jda.api.interactions.commands.SlashCommandReference;
import net.dv8tion.jda.api.utils.MiscUtil;
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.entities.GuildImpl;
import net.dv8tion.jda.internal.utils.Checks;
import net.dv8tion.jda.internal.utils.Helpers;
import org.apache.commons.collections4.Bag;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.bag.HashBag;

import javax.annotation.Nonnull;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.stream.Collector;
import java.util.stream.Collectors;

public abstract class AbstractMentions implements Mentions
{
    protected final String content;
    protected final JDAImpl jda;
    protected final GuildImpl guild;
    protected final boolean mentionsEveryone;

    protected List mentionedUsers;
    protected List mentionedMembers;
    protected List mentionedRoles;
    protected List mentionedChannels;
    protected List mentionedEmojis;
    protected List mentionedSlashCommands;

    public AbstractMentions(String content, JDAImpl jda, GuildImpl guild, boolean mentionsEveryone)
    {
        this.content = content;
        this.jda = jda;
        this.guild = guild;
        this.mentionsEveryone = mentionsEveryone;
    }

    @Nonnull
    @Override
    public JDA getJDA()
    {
        return jda;
    }

    @Override
    public boolean mentionsEveryone()
    {
        return mentionsEveryone;
    }

    @Nonnull
    @Override
    public synchronized List getUsers()
    {
        if (mentionedUsers != null)
            return mentionedUsers;
        return mentionedUsers = processMentions(Message.MentionType.USER, true, this::matchUser, Helpers.toUnmodifiableList());
    }

    @Nonnull
    @Override
    public Bag getUsersBag()
    {
        Bag bag = processMentions(Message.MentionType.USER, false, this::matchUser, toBag());

        // Handle reply mentions
        for (User user : getUsers())
        {
            if (!bag.contains(user))
                bag.add(user, 1);
        }

        return bag;
    }

    @Nonnull
    @Override
    public synchronized List getChannels()
    {
        if (mentionedChannels != null)
            return mentionedChannels;
        return mentionedChannels = processMentions(Message.MentionType.CHANNEL, true, this::matchChannel, Helpers.toUnmodifiableList());
    }

    @Nonnull
    @Override
    public Bag getChannelsBag()
    {
        return processMentions(Message.MentionType.CHANNEL, false, this::matchChannel, toBag());
    }

    @Nonnull
    @Override
    public  List getChannels(@Nonnull Class clazz)
    {
        Checks.notNull(clazz, "clazz");
        return getChannels().stream()
                .filter(clazz::isInstance)
                .map(clazz::cast)
                .collect(Collectors.toList());
    }

    @Nonnull
    @Override
    public  Bag getChannelsBag(@Nonnull Class clazz)
    {
        Checks.notNull(clazz, "clazz");
        Function matchTypedChannel = matcher -> {
            GuildChannel channel = this.matchChannel(matcher);
            return clazz.isInstance(channel) ? clazz.cast(channel) : null;
        };

        return processMentions(Message.MentionType.CHANNEL, false, matchTypedChannel, toBag());
    }

    @Nonnull
    @Override
    public synchronized List getRoles()
    {
        if (guild == null)
            return Collections.emptyList();
        if (mentionedRoles != null)
            return mentionedRoles;
        return mentionedRoles = processMentions(Message.MentionType.ROLE, true, this::matchRole, Helpers.toUnmodifiableList());
    }

    @Nonnull
    @Override
    public Bag getRolesBag()
    {
        if (guild == null)
            return new HashBag<>();
        return processMentions(Message.MentionType.ROLE, false, this::matchRole, toBag());
    }

    @Nonnull
    @Override
    public synchronized List getCustomEmojis()
    {
        if (mentionedEmojis != null)
            return mentionedEmojis;
        return mentionedEmojis = processMentions(Message.MentionType.EMOJI, true, this::matchEmoji, Helpers.toUnmodifiableList());
    }

    @Nonnull
    @Override
    public Bag getCustomEmojisBag()
    {
        return processMentions(Message.MentionType.EMOJI, false, this::matchEmoji, toBag());
    }

    @Nonnull
    @Override
    public synchronized List getMembers()
    {
        if (guild == null)
            return Collections.emptyList();
        if (mentionedMembers != null)
            return mentionedMembers;
        return mentionedMembers = processMentions(Message.MentionType.USER, true, this::matchMember, Helpers.toUnmodifiableList());
    }

    @Nonnull
    @Override
    public Bag getMembersBag()
    {
        if (guild == null)
            return new HashBag<>();
        Bag bag = processMentions(Message.MentionType.USER, false, this::matchMember, toBag());

        // Handle reply mentions
        for (Member member : getMembers())
        {
            if (!bag.contains(member))
                bag.add(member, 1);
        }

        return bag;
    }

    @Nonnull
    @Override
    public synchronized List getSlashCommands()
    {
        if (mentionedSlashCommands != null)
            return mentionedSlashCommands;
        return mentionedSlashCommands = processMentions(Message.MentionType.SLASH_COMMAND, true, this::matchSlashCommand, Helpers.toUnmodifiableList());
    }

    @Nonnull
    @Override
    public Bag getSlashCommandsBag()
    {
        return processMentions(Message.MentionType.SLASH_COMMAND, false, this::matchSlashCommand, toBag());
    }

    @Nonnull
    @Override
    @SuppressWarnings("ConstantConditions")
    public List getMentions(@Nonnull Message.MentionType... types)
    {
        if (types == null || types.length == 0)
            return getMentions(Message.MentionType.values());
        List mentions = new ArrayList<>();
        // Conversion to set to prevent duplication of types
        for (Message.MentionType type : EnumSet.of(types[0], types))
        {
            switch (type)
            {
            case CHANNEL:
                mentions.addAll(getChannels());
                break;
            case USER:
                TLongObjectMap set = new TLongObjectHashMap<>();
                for (User u : getUsers())
                    set.put(u.getIdLong(), u);
                for (Member m : getMembers())
                    set.put(m.getIdLong(), m);
                mentions.addAll(set.valueCollection());
                break;
            case ROLE:
                mentions.addAll(getRoles());
                break;
            case EMOJI:
                mentions.addAll(getCustomEmojis());
                break;
            case SLASH_COMMAND:
                mentions.addAll(getSlashCommands());
                break;
//            case EVERYONE:
//            case HERE:
//            default: continue;
            }
        }

        // Sort mentions by occurrence
        mentions.sort(Comparator.comparingInt(it -> content.indexOf(it.getId())));
        return Collections.unmodifiableList(mentions);
    }

    @Override
    public boolean isMentioned(@Nonnull IMentionable mentionable, @Nonnull Message.MentionType... types)
    {
        Checks.notNull(types, "Mention Types");
        if (types.length == 0)
            return isMentioned(mentionable, Message.MentionType.values());
        for (Message.MentionType type : types)
        {
            switch (type)
            {
            case HERE:
                if (isMass("@here") && mentionable instanceof UserSnowflake)
                    return true;
                break;
            case EVERYONE:
                if (isMass("@everyone") && mentionable instanceof UserSnowflake)
                    return true;
                break;
            case USER:
                if (isUserMentioned(mentionable))
                    return true;
                break;
            case ROLE:
                if (isRoleMentioned(mentionable))
                    return true;
                break;
            case CHANNEL:
                if (mentionable instanceof GuildChannel && getChannels().contains(mentionable))
                    return true;
                break;
            case EMOJI:
                if (mentionable instanceof CustomEmoji && getCustomEmojis().contains(mentionable))
                    return true;
                break;
            case SLASH_COMMAND:
                if (isSlashCommandMentioned(mentionable))
                    return true;
                break;
//           default: continue;
            }
        }
        return false;
    }

    // Internal parsing methods

    protected  > C processMentions(Message.MentionType type, boolean distinct, Function mapping, Collector collector)
    {
        A accumulator = collector.supplier().get();
        Matcher matcher = type.getPattern().matcher(content);
        Set unique = distinct ? new HashSet<>() : null;
        while (matcher.find())
        {
            try
            {
                T elem = mapping.apply(matcher);
                if (elem != null && (unique == null || unique.add(elem)))
                    collector.accumulator().accept(accumulator, elem);
            }
            catch (NumberFormatException ignored) {}
        }
        return collector.finisher().apply(accumulator);
    }

    protected static  Collector> toBag()
    {
        return Collectors.toCollection(HashBag::new);
    }

    protected abstract User matchUser(Matcher matcher);

    protected abstract Member matchMember(Matcher matcher);

    protected abstract GuildChannel matchChannel(Matcher matcher);

    protected abstract Role matchRole(Matcher matcher);

    protected CustomEmoji matchEmoji(Matcher m)
    {
        long emojiId = MiscUtil.parseSnowflake(m.group(2));
        String name = m.group(1);
        boolean animated = m.group(0).startsWith("




© 2015 - 2024 Weber Informatics LLC | Privacy Policy