/// <summary>
    /// Sets the custom role of a character.
    /// </summary>
    /// <param name="guildID">The ID of the guild the user is on.</param>
    /// <param name="userID">The ID of the discord user.</param>
    /// <param name="character">The character.</param>
    /// <param name="characterRole">The role to set.</param>
    /// <param name="ct">The cancellation token in use.</param>
    /// <returns>A modification result which may or may not have succeeded.</returns>
    public async Task <Result> SetCharacterRoleAsync
    (
        Snowflake guildID,
        Snowflake userID,
        Character character,
        CharacterRole characterRole,
        CancellationToken ct = default
    )
    {
        if (character.Role == characterRole)
        {
            return(new UserError("The character already has that role."));
        }

        if (character.IsCurrent)
        {
            if (character.Role is not null)
            {
                var removeRole = await _guildAPI.RemoveGuildMemberRoleAsync
                                 (
                    guildID,
                    userID,
                    character.Role.DiscordID,
                    ct : ct
                                 );

                if (!removeRole.IsSuccess)
                {
                    if (removeRole.Error is not RestResultError <RestError> rre)
                    {
                        return(removeRole);
                    }

                    if (rre.Error.Code is not DiscordError.UnknownRole)
                    {
                        return(removeRole);
                    }

                    // It's probably already removed; that's fine
                }
            }

            var addRole = await _guildAPI.AddGuildMemberRoleAsync(guildID, userID, characterRole.DiscordID, ct : ct);

            if (!addRole.IsSuccess)
            {
                return(addRole);
            }
        }

        character.Role = characterRole;
        await _database.SaveChangesAsync(ct);

        return(Result.FromSuccess());
    }
Ejemplo n.º 2
0
        /// <inheritdoc />
        public async Task <Result <MemberApplication> > Handle(Command request, CancellationToken cancellationToken)
        {
            var app = await _context.MemberApplications
                      .FirstOrDefaultAsync(
                a => a.MemberApplicationId == request.Id && a.GuildId == request.GuildId.Value,
                cancellationToken);

            if (app is null)
            {
                return(new NotFoundError($"Application with ID `{request.Id}` does not exist"));
            }

            var getRoles = await _guildApi.GetGuildRolesAsync(request.GuildId, cancellationToken);

            if (!getRoles.IsSuccess)
            {
                return(Result <MemberApplication> .FromError(getRoles.Error));
            }

            var role = getRoles.Entity
                       .FirstOrDefault(r =>
                                       r.Name.Contains($"[{request.ServerPrefix.ToUpper()}]"));

            if (role is null)
            {
                return(new NotFoundError(
                           $"Could not find a role corresponding to the server prefix: `{request.ServerPrefix}`."));
            }

            var userId = new Snowflake(app.AuthorDiscordId);
            var getUserToPromoteResult =
                await _guildApi.GetGuildMemberAsync(request.GuildId, userId, cancellationToken);

            if (!getUserToPromoteResult.IsSuccess)
            {
                return(Result <MemberApplication> .FromError(getUserToPromoteResult.Error));
            }
            if (getUserToPromoteResult.Entity is null)
            {
                return(new NotFoundError($"Could not find a user with ID: `{app.AuthorDiscordId}`."));
            }

            foreach (var ign in request.Igns)
            {
                var proto = new GenericCommand
                {
                    DiscordChannelId   = request.ChannelId.ToString(),
                    DiscordCommandName = "promote",
                    DefaultCommand     = "ranks add $1 member",
                    Args = { ign }
                };
                var id     = request.ServerPrefix.ToUpperInvariant();
                var server = _ps.GetOnlineServerOrDefault(id);

                if (server is null)
                {
                    return(Result <MemberApplication> .FromError(
                               new NotFoundError($"Could not find server with ID {id}")));
                }

                await _ps.SendMessage(server, proto);
            }

            var addRoleResult =
                await _guildApi.AddGuildMemberRoleAsync(request.GuildId, userId, role.ID, new(), cancellationToken);

            if (!addRoleResult.IsSuccess)
            {
                return(Result <MemberApplication> .FromError(addRoleResult));
            }

            app.AppStatus = ApplicationStatus.Approved;
            await _context.SaveChangesAsync(cancellationToken);

            return(Result <MemberApplication> .FromSuccess(app));
        }
Ejemplo n.º 3
0
    /// <summary>
    /// Applies the given autorole to the given user, if it is applicable. If the user no longer qualifies,
    /// the autorole is removed.
    /// </summary>
    /// <param name="autorole">The autorole.</param>
    /// <param name="guildID">The ID of the guild the user is on.</param>
    /// <param name="userID">The ID of the user.</param>
    /// <param name="ct">The cancellation token in use.</param>
    /// <returns>A modification result which may or may not have succeeded.</returns>
    public async Task <Result <AutoroleUpdateStatus> > UpdateAutoroleForUserAsync
    (
        AutoroleConfiguration autorole,
        Snowflake guildID,
        Snowflake userID,
        CancellationToken ct = default
    )
    {
        if (!autorole.IsEnabled)
        {
            return(Disabled);
        }

        if (!autorole.Conditions.Any())
        {
            return(Unconditional);
        }

        var getRoles = await _guildAPI.GetGuildRolesAsync(guildID, ct);

        if (!getRoles.IsSuccess)
        {
            return(Result <AutoroleUpdateStatus> .FromError(getRoles));
        }

        var roles = getRoles.Entity;

        if (roles.All(r => r.ID != autorole.DiscordRoleID))
        {
            // If the role can't be found any longer, we disable it
            var disableAutoroleAsync = await _autoroles.DisableAutoroleAsync(autorole, ct);

            return(!disableAutoroleAsync.IsSuccess
                ? Result <AutoroleUpdateStatus> .FromError(disableAutoroleAsync)
                : Disabled);
        }

        var getIsUserQualified = await _autoroles.IsUserQualifiedForAutoroleAsync(autorole, userID, ct);

        if (!getIsUserQualified.IsSuccess)
        {
            return(Result <AutoroleUpdateStatus> .FromError(getIsUserQualified));
        }

        var isUserQualified = getIsUserQualified.Entity;

        var getMember = await _guildAPI.GetGuildMemberAsync(guildID, userID, ct);

        if (!getMember.IsSuccess)
        {
            return(Result <AutoroleUpdateStatus> .FromError(getMember));
        }

        var member = getMember.Entity;

        if (!member.User.IsDefined(out var user))
        {
            return(Unqualified);
        }

        if (user.IsBot.IsDefined(out var isBot) && isBot)
        {
            return(Unqualified);
        }

        var userHasRole = member.Roles.Contains(autorole.DiscordRoleID);

        switch (isUserQualified)
        {
        case true when userHasRole:
        {
            return(Unchanged);
        }

        case false when userHasRole:
        {
            var removeRole = await _guildAPI.RemoveGuildMemberRoleAsync
                             (
                guildID,
                userID,
                autorole.DiscordRoleID,
                ct : ct
                             );

            if (!removeRole.IsSuccess)
            {
                return(Result <AutoroleUpdateStatus> .FromError(removeRole));
            }

            var getConfirmation = await _autoroles.GetOrCreateAutoroleConfirmationAsync
                                  (
                autorole,
                userID,
                ct
                                  );

            if (!getConfirmation.IsSuccess)
            {
                return(Removed);
            }

            // Remove any existing affirmation
            var confirmation       = getConfirmation.Entity;
            var removeConfirmation = await _autoroles.RemoveAutoroleConfirmationAsync(confirmation, ct);

            return(!removeConfirmation.IsSuccess
                    ? Result <AutoroleUpdateStatus> .FromError(removeConfirmation)
                    : Removed);
        }

        case false:
        {
            // At this point, the user doesn't have the role, and either is or is not qualified.
            // We consider a no-op for an unqualified user a success.
            return(Unqualified);
        }
        }

        if (autorole.RequiresConfirmation)
        {
            var getConfirmation = await _autoroles.GetOrCreateAutoroleConfirmationAsync
                                  (
                autorole,
                userID,
                ct
                                  );

            if (!getConfirmation.IsSuccess)
            {
                return(Result <AutoroleUpdateStatus> .FromError(getConfirmation));
            }

            var confirmation = getConfirmation.Entity;
            if (!confirmation.IsConfirmed)
            {
                // We consider a no-op for an qualified but not affirmed user a success.
                return(RequiresAffirmation);
            }
        }

        var addRole = await _guildAPI.AddGuildMemberRoleAsync(guildID, userID, autorole.DiscordRoleID, ct : ct);

        return(!addRole.IsSuccess
            ? Result <AutoroleUpdateStatus> .FromError(addRole)
            : Applied);
    }