Пример #1
0
        public async Task CreateTagAsync(ulong guildId, ulong creatorId, string name, string content)
        {
            _authorizationService.RequireClaims(AuthorizationClaim.CreateTag);

            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentException("The tag name cannot be blank or whitespace.", nameof(name));
            }

            if (string.IsNullOrWhiteSpace(content))
            {
                throw new ArgumentException("The tag content cannot be blank or whitespace.", nameof(content));
            }

            if (!_tagNameRegex.IsMatch(name))
            {
                throw new ArgumentException("The tag name cannot have punctuation at the end.", nameof(name));
            }

            name = name.Trim().ToLower();

            if (await _modixContext.Set <TagEntity>().Where(x => x.GuildId == guildId).Where(x => x.DeleteActionId == null).AnyAsync(x => x.Name == name))
            {
                throw new InvalidOperationException($"A tag with the name '{name}' already exists.");
            }

            var tag = new TagEntity
            {
                GuildId     = guildId,
                OwnerUserId = creatorId,
                Name        = name,
                Content     = content,
            };

            var createAction = new TagActionEntity()
            {
                GuildId     = guildId,
                Created     = DateTimeOffset.Now,
                Type        = TagActionType.TagCreated,
                CreatedById = creatorId,
            };

            tag.CreateAction = createAction;

            _modixContext.Set <TagEntity>().Add(tag);

            await _modixContext.SaveChangesAsync();
        }
Пример #2
0
        /// <inheritdoc />
        public async Task <PromotionActionSummary?> TryCloseAsync(long campaignId, ulong closedById, PromotionCampaignOutcome outcome)
        {
            var entity = await ModixContext.Set <PromotionCampaignEntity>()
                         .Where(x => x.Id == campaignId)
                         .FirstOrDefaultAsync();

            if ((entity == null) || (entity.CloseActionId != null))
            {
                return(null);
            }

            entity.Outcome     = outcome;
            entity.CloseAction = new PromotionActionEntity()
            {
                GuildId     = entity.GuildId,
                Type        = PromotionActionType.CampaignClosed,
                Created     = DateTimeOffset.Now,
                CreatedById = closedById,
                CampaignId  = entity.Id
            };
            await ModixContext.SaveChangesAsync();

            var action = await ModixContext.Set <PromotionActionEntity>().AsNoTracking()
                         .Where(x => x.Id == entity.CloseActionId)
                         .AsExpandable()
                         .Select(PromotionActionSummary.FromEntityProjection)
                         .FirstAsync();

            return(action);
        }
Пример #3
0
        public async Task <bool> TryUpdateAync(long infractionId, string newReason, ulong updatedById)
        {
            var entity = await ModixContext.Set <InfractionEntity>()
                         .Where(x => x.Id == infractionId)
                         .FirstOrDefaultAsync();

            if (entity == null)
            {
                return(false);
            }

            var originalReason = entity.Reason;

            entity.Reason = newReason;

            entity.UpdateAction = new ModerationActionEntity()
            {
                GuildId                  = entity.GuildId,
                Type                     = ModerationActionType.InfractionUpdated,
                Created                  = DateTimeOffset.Now,
                CreatedById              = updatedById,
                InfractionId             = entity.Id,
                OriginalInfractionReason = originalReason,
            };

            await ModixContext.SaveChangesAsync();

            await RaiseModerationActionCreatedAsync(entity.UpdateAction);

            return(true);
        }
Пример #4
0
        /// <inheritdoc />
        public async Task <bool> TryUpdateAsync(ulong userId, ulong guildId, Action <GuildUserMutationData> updateAction)
        {
            if (updateAction == null)
            {
                throw new ArgumentNullException(nameof(updateAction));
            }

            var entity = await ModixContext.Set <GuildUserEntity>()
                         .Where(x => x.UserId == userId)
                         .Where(x => x.GuildId == guildId)
                         .Include(x => x.User)
                         .FirstOrDefaultAsync();

            if (entity == null)
            {
                return(false);
            }

            var data = GuildUserMutationData.FromEntity(entity);

            updateAction.Invoke(data);
            data.ApplyTo(entity);

            ModixContext.UpdateProperty(entity.User, x => x.Username);
            ModixContext.UpdateProperty(entity.User, x => x.Discriminator);
            ModixContext.UpdateProperty(entity, x => x.Nickname);
            ModixContext.UpdateProperty(entity, x => x.LastSeen);

            await ModixContext.SaveChangesAsync();

            return(true);
        }
        /// <inheritdoc />
        public async Task CreateAsync(DeletedMessageBatchCreationData data)
        {
            if (data is null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            var entity = data.ToEntity();

            await ModixContext.Set <DeletedMessageBatchEntity>().AddAsync(entity);

            await ModixContext.SaveChangesAsync();

            entity.CreateAction.DeletedMessageBatchId = entity.Id;
            await ModixContext.SaveChangesAsync();

            var deletedMessageEntities = data.Data.Select(x =>
            {
                x.BatchId = entity.Id;
                return(x.ToBatchEntity());
            });

            await ModixContext.Set <DeletedMessageEntity>().AddRangeAsync(deletedMessageEntities);

            await ModixContext.SaveChangesAsync();

            await RaiseModerationActionCreatedAsync(entity.CreateAction);
        }
Пример #6
0
        /// <inheritdoc />
        public async Task <bool> TryDeleteAsync(long infractionId, ulong deletedById)
        {
            var entity = await ModixContext.Set <InfractionEntity>()
                         .Where(x => x.Id == infractionId)
                         .FirstOrDefaultAsync();

            if ((entity == null) || (entity.DeleteActionId != null))
            {
                return(false);
            }

            entity.DeleteAction = new ModerationActionEntity()
            {
                GuildId      = entity.GuildId,
                Type         = ModerationActionType.InfractionDeleted,
                Created      = DateTimeOffset.Now,
                CreatedById  = deletedById,
                InfractionId = entity.Id
            };
            await ModixContext.SaveChangesAsync();

            await RaiseModerationActionCreatedAsync(entity.DeleteAction);

            return(true);
        }
Пример #7
0
 /// <inheritdoc />
 public async Task <IReadOnlyCollection <InfractionSummary> > SearchSummariesAsync(InfractionSearchCriteria searchCriteria, IEnumerable <SortingCriteria>?sortingCriteria = null)
 => await ModixContext.Set <InfractionEntity>().AsNoTracking()
 .FilterBy(searchCriteria)
 .AsExpandable()
 .Select(InfractionSummary.FromEntityProjection)
 .SortBy(sortingCriteria, InfractionSummary.SortablePropertyMap)
 .ToArrayAsync();
Пример #8
0
        /// <inheritdoc />
        public async Task <IReadOnlyList <MessageCountByDate> > GetGuildUserMessageCountByDate(ulong guildId, ulong userId, TimeSpan timespan)
        {
            var earliestDateTime = DateTimeOffset.UtcNow - timespan;
            var results          = await ModixContext.Set <MessageCountByDate>()
                                   .FromSqlRaw(
                @"select date(""Timestamp""::timestamp AT TIME ZONE 'UTC') as ""Date"", count(""Id"") as ""MessageCount""
                      from ""Messages""
                      where ""GuildId"" = :GuildId
                      and ""AuthorId"" = :UserId
                      and ""Timestamp"" > :StartTimestamp
                      group by date(""Timestamp""::timestamp AT TIME ZONE 'UTC')",
                new NpgsqlParameter(":GuildId", NpgsqlDbType.Bigint)
            {
                Value = unchecked ((long)guildId)
            },
                new NpgsqlParameter(":UserId", NpgsqlDbType.Bigint)
            {
                Value = unchecked ((long)userId)
            },
                new NpgsqlParameter(":StartTimestamp", NpgsqlDbType.TimestampTz)
            {
                Value = earliestDateTime
            })
                                   .ToArrayAsync();

            return(results);
        }
Пример #9
0
        /// <inheritdoc />
        public async Task CreateAsync(
            GuildUserCreationData data,
            CancellationToken cancellationToken)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            var guildDataEntity = data.ToGuildDataEntity();

            guildDataEntity.User = await ModixContext
                                   .Set <UserEntity>()
                                   .AsQueryable()
                                   .FirstOrDefaultAsync(x => x.Id == data.UserId, cancellationToken)
                                   ?? data.ToUserEntity();

            await ModixContext.Set <GuildUserEntity>().AddAsync(guildDataEntity, cancellationToken);

            if ((guildDataEntity.User.Username != data.Username) && !(data.Username is null))
            {
                guildDataEntity.User.Username = data.Username;
            }

            if ((guildDataEntity.User.Discriminator != data.Discriminator) && !(data.Discriminator is null))
            {
                guildDataEntity.User.Discriminator = data.Discriminator;
            }

            await ModixContext.SaveChangesAsync(cancellationToken);
        }
Пример #10
0
        /// <inheritdoc />
        public async Task CreateAsync(MessageCreationData data)
        {
            var entity = data.ToEntity();
            await ModixContext.Set <MessageEntity>().AddAsync(entity);

            await ModixContext.SaveChangesAsync();
        }
Пример #11
0
        /// <inheritdoc />
        public async Task <IReadOnlyDictionary <EphemeralEmoji, int> > GetCountsAsync(EmojiSearchCriteria criteria)
        {
            if (criteria is null)
            {
                throw new ArgumentNullException(nameof(criteria));
            }

            var emoji = await ModixContext.Set <EmojiEntity>().AsNoTracking()
                        .FilterBy(criteria)
                        .GroupBy(x => new
            {
                x.EmojiId,
                EmojiName = x.EmojiId == null
                        ? x.EmojiName
                        : null
            },
                                 x => new { x.EmojiId, x.EmojiName, x.IsAnimated, x.Timestamp })
                        .ToArrayAsync();

            var counts = emoji.ToDictionary(
                x =>
            {
                var mostRecentEmoji = x.OrderByDescending(y => y.Timestamp).First();
                return(EphemeralEmoji.FromRawData(mostRecentEmoji.EmojiName, mostRecentEmoji.EmojiId, mostRecentEmoji.IsAnimated));
            },
                x => x.Count());

            return(counts);
        }
Пример #12
0
        /// <inheritdoc />
        public async Task <bool> TryUpdateAsync(ulong roleId, Action <GuildRoleMutationData> updateAction)
        {
            if (updateAction == null)
            {
                throw new ArgumentNullException(nameof(updateAction));
            }

            var entity = await ModixContext.Set <GuildRoleEntity>()
                         .Where(x => x.RoleId == roleId)
                         .FirstOrDefaultAsync();

            if (entity == null)
            {
                return(false);
            }

            var data = GuildRoleMutationData.FromEntity(entity);

            updateAction.Invoke(data);
            data.ApplyTo(entity);

            ModixContext.UpdateProperty(entity, x => x.Name);
            ModixContext.UpdateProperty(entity, x => x.Position);

            await ModixContext.SaveChangesAsync();

            return(true);
        }
Пример #13
0
 /// <inheritdoc />
 public Task <DateTimeOffset?> ReadExpiresFirstOrDefaultAsync(InfractionSearchCriteria searchCriteria, IEnumerable <SortingCriteria>?sortingCriteria = null)
 => ModixContext.Set <InfractionEntity>().AsNoTracking()
 .FilterBy(searchCriteria)
 .AsExpandable()
 .Select(InfractionSummary.FromEntityProjection)
 .SortBy(sortingCriteria, InfractionSummary.SortablePropertyMap)
 .Select(x => x.Expires)
 .FirstOrDefaultAsync();
Пример #14
0
 /// <inheritdoc />
 public async Task <MessageBrief> GetMessage(ulong messageId)
 {
     return(await ModixContext.Set <MessageEntity>()
            .AsNoTracking()
            .Where(x => x.Id == messageId)
            .Select(MessageBrief.FromEntityProjection)
            .FirstOrDefaultAsync());
 }
Пример #15
0
 /// <inheritdoc />
 public async Task <IReadOnlyCollection <ModerationActionSummary> > SearchSummariesAsync(ModerationActionSearchCriteria searchCriteria)
 {
     return(await ModixContext.Set <ModerationActionEntity>().AsNoTracking()
            .FilterBy(searchCriteria)
            .AsExpandable()
            .Select(ModerationActionSummary.FromEntityProjection)
            .ToArrayAsync());
 }
        public async Task <List <MessageContentPatternDto> > GetPatterns(ulong guildId)
        {
            var key = GetKeyForCache(guildId);

            if (!_memoryCache.TryGetValue(key, out List <MessageContentPatternDto> patterns))
            {
                patterns = await _db
                           .Set <MessageContentPatternEntity>()
                           .Where(x => x.GuildId == guildId)
                           .Select(x => new MessageContentPatternDto(x.Pattern, x.PatternType))
                           .ToListAsync();

                _memoryCache.Set(key, patterns, _patternCacheEntryOptions);
            }

            return(patterns);
        }
Пример #17
0
 /// <inheritdoc />
 public async Task <IReadOnlyCollection <PromotionCampaignSummary> > GetPromotionsForUserAsync(ulong guildId, ulong userId)
 => await ModixContext.Set <PromotionCampaignEntity>().AsNoTracking()
 .Where(x => x.GuildId == guildId &&
        x.SubjectId == userId &&
        x.Outcome == PromotionCampaignOutcome.Accepted)
 .AsExpandable()
 .Select(PromotionCampaignSummary.FromEntityProjection)
 .ToArrayAsync();
Пример #18
0
        /// <inheritdoc />
        public async Task <int> GetTotalMessageCountAsync(ulong guildId, TimeSpan timespan)
        {
            var earliestDateTime = DateTimeOffset.UtcNow - timespan;

            return(await ModixContext.Set <MessageEntity>().AsNoTracking()
                   .Where(x => x.GuildId == guildId &&
                          x.Timestamp >= earliestDateTime)
                   .CountAsync());
        }
Пример #19
0
 /// <inheritdoc />
 public Task <GuildUserSummary> ReadSummaryAsync(ulong userId, ulong guildId)
 {
     return(ModixContext.Set <GuildUserEntity>()
            .AsNoTracking()
            .Where(x => x.UserId == userId)
            .Where(x => x.GuildId == guildId)
            .AsExpandable()
            .Select(GuildUserSummary.FromEntityProjection)
            .FirstOrDefaultAsync());
 }
Пример #20
0
        /// <inheritdoc />
        public async Task UpdateStarboardColumn(ulong messageId, ulong?starboardEntryId)
        {
            var entity = await ModixContext.Set <MessageEntity>()
                         .Where(x => x.Id == messageId)
                         .FirstOrDefaultAsync();

            entity.StarboardEntryId = starboardEntryId;

            ModixContext.Set <MessageEntity>().Update(entity);
            await ModixContext.SaveChangesAsync();
        }
Пример #21
0
        /// <inheritdoc />
        public async Task DeleteAsync(EmojiSearchCriteria criteria)
        {
            if (criteria is null)
            {
                throw new ArgumentNullException(nameof(criteria));
            }

            var entities = ModixContext.Set <EmojiEntity>().FilterBy(criteria);

            ModixContext.RemoveRange(entities);
            await ModixContext.SaveChangesAsync();
        }
Пример #22
0
        /// <inheritdoc />
        public async Task DeleteAsync(ulong messageId)
        {
            var entity = await ModixContext.Set <MessageEntity>()
                         .Where(x => x.Id == messageId)
                         .FirstOrDefaultAsync();

            if (entity is MessageEntity)
            {
                ModixContext.Set <MessageEntity>().Remove(entity);
                await ModixContext.SaveChangesAsync();
            }
        }
Пример #23
0
        /// <inheritdoc />
        public async Task CreateAsync(GuildRoleCreationData data)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            var entity = data.ToEntity();

            await ModixContext.Set <GuildRoleEntity>().AddAsync(entity);

            await ModixContext.SaveChangesAsync();
        }
Пример #24
0
        /// <inheritdoc />
        public async Task CreateAsync(GuildChannelCreationData data, CancellationToken cancellationToken = default)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            var entity = data.ToEntity();

            await ModixContext.Set <GuildChannelEntity>().AddAsync(entity, cancellationToken);

            await ModixContext.SaveChangesAsync(cancellationToken);
        }
        /// <inheritdoc />
        public async Task <PromotionActionSummary> TryUpdateAsync(long commentId, ulong userId, Action <PromotionCommentMutationData> updateAction)
        {
            if (updateAction is null)
            {
                throw new ArgumentNullException(nameof(updateAction));
            }

            var oldComment = await ModixContext.Set <PromotionCommentEntity>()
                             .Include(x => x.Campaign)
                             .SingleAsync(x => x.Id == commentId);

            var modifyAction = new PromotionActionEntity
            {
                CampaignId  = oldComment.CampaignId,
                Created     = DateTimeOffset.Now,
                CreatedById = userId,
                GuildId     = oldComment.Campaign.GuildId,
                Type        = PromotionActionType.CommentModified,
            };

            await ModixContext.Set <PromotionActionEntity>().AddAsync(modifyAction);

            await ModixContext.SaveChangesAsync();

            var data = PromotionCommentMutationData.FromEntity(oldComment);

            updateAction(data);

            var newComment = data.ToEntity();

            newComment.CreateActionId = modifyAction.Id;

            await ModixContext.Set <PromotionCommentEntity>().AddAsync(newComment);

            await ModixContext.SaveChangesAsync();

            modifyAction.OldCommentId = oldComment.Id;
            modifyAction.NewCommentId = newComment.Id;
            oldComment.ModifyActionId = modifyAction.Id;
            newComment.CreateActionId = modifyAction.Id;
            await ModixContext.SaveChangesAsync();

            var actionSummary = await ModixContext.Set <PromotionActionEntity>().AsNoTracking()
                                .Where(x => x.Id == modifyAction.Id)
                                .AsExpandable()
                                .Select(PromotionActionSummary.FromEntityProjection)
                                .FirstAsync();

            return(actionSummary);
        }
Пример #26
0
        /// <inheritdoc />
        public async Task <IReadOnlyDictionary <ulong, int> > GetTotalMessageCountByChannelAsync(ulong guildId, TimeSpan timespan)
        {
            var earliestDateTime = DateTimeOffset.UtcNow - timespan;

            var messages = await ModixContext.Set <MessageEntity>()
                           .AsNoTracking()
                           .Where(x => x.GuildId == guildId && x.Timestamp >= earliestDateTime)
                           .Select(x => x.ChannelId)
                           .ToListAsync();

            return(messages
                   .GroupBy(channelId => channelId)
                   .ToDictionary(x => x.Key, x => x.Count()));
        }
Пример #27
0
        /// <inheritdoc />
        public async Task <long> CreateAsync(EmojiCreationData data)
        {
            if (data is null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            var entity = data.ToEntity();

            await ModixContext.Set <EmojiEntity>().AddAsync(entity);

            await ModixContext.SaveChangesAsync();

            return(entity.Id);
        }
Пример #28
0
        /// <inheritdoc />
        public async Task <SingleEmojiUsageStatistics> GetEmojiStatsAsync(ulong guildId, EphemeralEmoji emoji, TimeSpan?dateFilter = null)
        {
            var query      = GetQuery();
            var parameters = GetParameters();

            var stats = await ModixContext
                        .Set <SingleEmojiStatsDto>()
                        .FromSqlRaw(query, parameters)
                        .AsNoTracking()
                        .FirstOrDefaultAsync();

            return(SingleEmojiUsageStatistics.FromDto(stats ?? new SingleEmojiStatsDto()));

            NpgsqlParameter[] GetParameters() =>
            new[]
Пример #29
0
        /// <inheritdoc />
        public async Task <IReadOnlyCollection <EmojiSummary> > SearchSummariesAsync(EmojiSearchCriteria criteria)
        {
            if (criteria is null)
            {
                throw new ArgumentNullException(nameof(criteria));
            }

            var emoji = await ModixContext.Set <EmojiEntity>().AsNoTracking()
                        .FilterBy(criteria)
                        .AsExpandable()
                        .Select(EmojiSummary.FromEntityProjection)
                        .ToArrayAsync();

            return(emoji);
        }
        /// <inheritdoc />
        public async Task <int> DeleteAsync(DesignatedChannelMappingSearchCriteria criteria, ulong deletedById)
        {
            var entities = await ModixContext.Set <DesignatedChannelMappingEntity>()
                           .Where(x => x.DeleteActionId == null)
                           .FilterBy(criteria)
                           .ToArrayAsync();

            foreach (var entity in entities)
            {
                DoEntityDelete(entity, deletedById);
            }

            await ModixContext.SaveChangesAsync();

            return(entities.Length);
        }