/// <summary> /// Returns the details for a media. /// </summary> public async Task <MediaVM> GetMediaAsync(string key) { var id = PageHelper.GetMediaId(key); var media = await _db.Media .Include(x => x.Tags) .ThenInclude(x => x.Object) .Where(x => x.IsDeleted == false) .FirstOrDefaultAsync(x => x.Id == id); if (media == null) { throw new KeyNotFoundException(); } var descr = await _markdown.CompileAsync(media.Description); return(new MediaVM { Type = media.Type, IsProcessed = media.IsProcessed, Title = media.Title, Description = descr, Date = FuzzyDate.TryParse(media.Date), Tags = GetMediaTagsVMs(media.Tags).ToList(), Event = GetPageTitle(media.Tags.FirstOrDefault(x => x.Type == MediaTagType.Event)), Location = GetPageTitle(media.Tags.FirstOrDefault(x => x.Type == MediaTagType.Location)), OriginalPath = media.FilePath, PreviewPath = GetSizedMediaPath(media.FilePath, MediaSize.Large) }); }
public void LeapYearDefinedTest() { var leapYears = new int[] { 1996, 2000, 2004, 2008, 2012, 2016 }; for (int year = 1995; year <= 2019; year++) { var date = new FuzzyDate(year); if (leapYears.Contains(year)) { Assert.IsTrue(date.IsLeapYear()); } else { Assert.IsFalse(date.IsLeapYear()); } } }
/// <summary> /// Applies date filtering to the list of media. /// </summary> private IReadOnlyList <Media> TryFilterMediaByDate(FolderContentsRequestVM request, IReadOnlyList <Media> source) { var dateFrom = TryParse(request.From); var dateTo = TryParse(request.To); if (dateFrom == null && dateTo == null) { return(source); } return(source.Select(x => new { Date = FuzzyDate.TryParse(x.Date), Media = x }) .Where(x => x.Date != null) .Where(x => (dateFrom == null || x.Date >= dateFrom) && (dateTo == null || x.Date <= dateTo)) .Select(x => x.Media) .ToList()); FuzzyDate?TryParse(string value) { var date = value?.TryParse <DateTime?>(); return(date == null ? (FuzzyDate?)null : new FuzzyDate(date.Value)); } }
/// <summary> /// Performs additional checks on the registration request. /// </summary> private async Task ValidateRegisterRequestAsync(RegisterUserVM vm, bool usePasswordAuth) { var val = new Validator(); if (FuzzyDate.TryParse(vm.Birthday) == null) { val.Add(nameof(vm.Birthday), "Дата рождения указана неверно."); } var emailExists = await _db.Users.AnyAsync(x => x.Email == vm.Email); if (emailExists) { val.Add(nameof(vm.Email), "Адрес электронной почты уже зарегистрирован."); } if (usePasswordAuth) { if (vm.Password == null || vm.Password.Length < 6) { val.Add(nameof(vm.Password), "Пароль должен содержать как минимум 6 символов."); } if (vm.Password != vm.PasswordCopy) { val.Add(nameof(vm.PasswordCopy), "Пароли не совпадают."); } } val.ThrowIfInvalid(); }
internal static void RunRules(FuzzyDate date) { foreach (var rule in _fuzzyDateRules) { rule.Verify(date); } }
/// <summary> /// Uploads a new media file. /// </summary> public async Task <MediaUploadResultVM> UploadAsync(MediaUploadRequestVM vm, IFormFile file, ClaimsPrincipal principal) { var id = Guid.NewGuid(); var key = PageHelper.GetMediaKey(id); var handler = _mediaHandlers.FirstOrDefault(x => x.SupportedMimeTypes.Contains(file.ContentType)); if (handler == null) { throw new UploadException("Неизвестный тип файла!"); } var userId = _userMgr.GetUserId(principal); var user = await _db.Users.GetAsync(x => x.Id == userId, "Пользователь не найден"); var paths = await SaveUploadAsync(file, key, handler); var tags = await GetTagsForUploadedMedia(vm); var meta = await handler.ExtractMetadataAsync(paths.LocalPath, file.ContentType); var media = new Media { Id = id, Key = key, Type = handler.MediaType, MimeType = file.ContentType, Title = vm.Title, FilePath = paths.UrlPath, UploadDate = DateTimeOffset.Now, Uploader = user, IsProcessed = handler.IsImmediate, Date = FuzzyDate.TryParse(vm.Date) != null ? vm.Date : meta?.Date?.Date.ToString("yyyy.MM.dd", CultureInfo.InvariantCulture), Tags = tags }; _db.Media.Add(media); if (!handler.IsImmediate) { _db.MediaJobs.Add(new MediaEncodingJob { Id = Guid.NewGuid(), MediaId = media.Id }); } var changeset = await GetChangesetAsync(null, _mapper.Map <MediaEditorVM>(media), id, principal, null); _db.Changes.Add(changeset); return(_mapper.Map <MediaUploadResultVM>(media)); }
public void YearGreaterThanZeroIsValid() { try { _ = new FuzzyDate(1950); } catch (Exception ex) { Assert.Fail($"Expect no exception, but got {ex.Message}"); } }
public void TwentyNinthOfFebruaryInLeapYearIsValid() { try { _ = new FuzzyDate(2020, 2, 29); } catch (Exception ex) { Assert.Fail($"Expect no exception, but got {ex.Message}"); } }
public void DayInRangeIsValid() { try { _ = new FuzzyDate(2019, 9, 3); } catch (Exception ex) { Assert.Fail($"Expect no exception, but got {ex.Message}"); } }
/// <summary> /// Infers page-related events for the current month. /// </summary> private IEnumerable <CalendarEventVM> GetPageEvents(int year, int month, RelationContext context) { var maxDate = new FuzzyDate(new DateTime(year, month, 1).AddMonths(1).AddSeconds(-1)); foreach (var page in context.Pages.Values) { if (page.BirthDate is FuzzyDate birth) { var showBirth = birth.Month == month && (birth.Year == null || birth.Year <= year) && (page.DeathDate == null || page.DeathDate >= maxDate); if (showBirth) { var title = (year == birth.Year && !birth.IsDecade) ? "Дата рождения" : (birth.Year == null || birth.IsDecade) ? "День рождения" : $"День рождения ({year - birth.Year.Value})"; yield return(new CalendarEventVM { Day = birth.Day, Title = title, Type = CalendarEventType.Birth, RelatedPage = Map(page) }); } } if (page.DeathDate is FuzzyDate death) { var showDeath = death.Month == month && (death.Year == null || death.Year <= year); if (showDeath) { var title = (year == death.Year && !death.IsDecade) ? "Дата смерти" : (death.Year == null || death.IsDecade) ? "Годовщина смерти" : (year - death.Year.Value) + "-ая годовщина смерти"; yield return(new CalendarEventVM { Day = death.Day, Title = title, Type = CalendarEventType.Death, RelatedPage = Map(page) }); } } } }
public void Configure(IProfileExpression profile) { profile.CreateMap <Data.Models.Media, MediaThumbnailExtendedVM>() .MapMember(x => x.Id, x => x.Id) .MapMember(x => x.Key, x => x.Key) .MapMember(x => x.Type, x => x.Type) .MapMember(x => x.Date, x => FuzzyDate.TryParse(x.Date)) .MapMember(x => x.UploadDate, x => x.UploadDate) .MapMember(x => x.Title, x => x.Title) .MapMember(x => x.MediaTagsCount, x => x.Tags.Count(y => y.Type == MediaTagType.DepictedEntity)) .MapMember(x => x.ThumbnailUrl, x => MediaPresenterService.GetSizedMediaPath(x.FilePath, MediaSize.Small)); }
public void AddToNoDayTest() { try { var fd = new FuzzyDate(2019, 9); var newDate = fd.AddDays(10); Assert.IsFalse(newDate.Day.HasValue); } catch (Exception ex) { Assert.Fail($"Expect no exception, but got {ex.Message}"); } }
/// <summary> /// Performs additional checks on the registration request. /// </summary> private async Task ValidateRegisterRequestAsync(RegisterUserVM vm) { var val = new Validator(); if (FuzzyDate.TryParse(vm.Birthday) == null) val.Add(nameof(vm.Birthday), "Дата рождения указана неверно."); var emailExists = await _db.Users.AnyAsync(x => x.Email == vm.Email); if (emailExists) val.Add(nameof(vm.Email), "Адрес электронной почты уже зарегистрирован."); val.ThrowIfInvalid(); }
/// <summary> /// Infers relation-based events for the current month. /// </summary> private IEnumerable <CalendarEventVM> GetRelationEvents(int year, int month, RelationContext context) { var visited = new HashSet <string>(); var maxDate = new FuzzyDate(CreateDate(year, month).AddMonths(1).AddSeconds(-1)); foreach (var rel in context.Relations.SelectMany(x => x.Value)) { if (!(rel.Duration is FuzzyRange duration) || !(duration.RangeStart is FuzzyDate start) || start.Month != month) { continue; } if (duration.RangeEnd is FuzzyDate end && end <= maxDate) { continue; } var hash = string.Concat(rel.SourceId.ToString(), rel.DestinationId.ToString(), duration.ToString()); if (visited.Contains(hash)) { continue; } var inverseHash = string.Concat(rel.DestinationId.ToString(), rel.SourceId.ToString(), duration.ToString()); visited.Add(hash); visited.Add(inverseHash); var title = (year == start.Year && !start.IsDecade) ? "День свадьбы" : (start.Year == null || start.IsDecade) ? "Годовщина" : (year - start.Year.Value) + "-ая годовщина"; yield return(new CalendarEventVM { Day = start.Day, Title = title, Type = CalendarEventType.Wedding, RelatedPage = rel.EventId == null ? new PageTitleExtendedVM { Title = "Свадьба", MainPhotoPath = "~/assets/img/unknown-event.svg" } : Map(context.Pages[rel.EventId.Value]), OtherPages = new [] { Map(context.Pages[rel.SourceId]), Map(context.Pages[rel.DestinationId]) } }); } }
/// <summary> /// Renders the property values. /// </summary> public async Task <IReadOnlyList <ChangePropertyValue> > RenderValuesAsync(string json) { var result = new List <ChangePropertyValue>(); var data = JsonConvert.DeserializeObject <RelationEditorVM>(StringHelper.Coalesce(json, "{}")); if (data.SourceIds == null) { data.SourceIds = Array.Empty <Guid>(); } var pageIds = data.SourceIds .Concat(new[] { data.DestinationId ?? Guid.Empty, data.EventId ?? Guid.Empty }) .ToList(); var namesLookup = await _db.Pages .Where(x => pageIds.Contains(x.Id)) .ToDictionaryAsync(x => x.Id, x => x.Title); Add(nameof(RelationEditorVM.DestinationId), "Основная страница", namesLookup.TryGetValue(data.DestinationId ?? Guid.Empty)); Add(nameof(RelationEditorVM.Type), "Тип связи", string.IsNullOrEmpty(json) ? null : data.Type.GetEnumDescription()); if (data.SourceIds.Length == 0) { Add(nameof(RelationEditorVM.SourceIds), "Связанная страница", null); } else if (data.SourceIds.Length == 1) { var name = namesLookup.TryGetValue(data.SourceIds[0]); Add(nameof(RelationEditorVM.SourceIds), "Связанная страница", name); } else { var pageNames = data.SourceIds .Select(x => namesLookup.TryGetValue(x)) .Where(x => !string.IsNullOrEmpty(x)); Add(nameof(RelationEditorVM.SourceIds), "Связанные страницы", ViewHelper.RenderBulletList(_html, pageNames)); } Add(nameof(RelationEditorVM.EventId), "Событие", namesLookup.TryGetValue(data.EventId ?? Guid.Empty)); Add(nameof(RelationEditorVM.DurationStart), "Начало", FuzzyDate.TryParse(data.DurationStart)?.ReadableDate); Add(nameof(RelationEditorVM.DurationEnd), "Конец", FuzzyDate.TryParse(data.DurationEnd)?.ReadableDate); return(result); void Add(string prop, string name, string value) { result.Add(new ChangePropertyValue(prop, name, value)); } }
public void ParseFromYearMonthDayAmbiguousTest() { try { var date = FuzzyDate.Parse("2019/02/10"); Assert.AreEqual(2019, date.Year.Value); Assert.AreEqual(2, date.Month.Value); Assert.AreEqual(10, date.Day.Value); } catch (Exception ex) { Assert.Fail($"Expect no exception, but got {ex.Message}"); } }
public void ParseFromMonthDayYearTest() { try { var date = FuzzyDate.Parse("09/15/2019"); Assert.AreEqual(2019, date.Year.Value); Assert.AreEqual(9, date.Month.Value); Assert.AreEqual(15, date.Day.Value); } catch (Exception ex) { Assert.Fail($"Expect no exception, but got {ex.Message}"); } }
public void ParseFromYearMonthTest() { try { var date = FuzzyDate.Parse("2019/09"); Assert.AreEqual(2019, date.Year.Value); Assert.AreEqual(9, date.Month.Value); Assert.IsFalse(date.Day.HasValue); } catch (Exception ex) { Assert.Fail($"Expect no exception, but got {ex.Message}"); } }
public void ParseWithHyphenDelimiterTest() { try { var date = FuzzyDate.Parse("09-15-2019"); Assert.AreEqual(2019, date.Year.Value); Assert.AreEqual(9, date.Month.Value); Assert.AreEqual(15, date.Day.Value); } catch (Exception ex) { Assert.Fail($"Expect no exception, but got {ex.Message}"); } }
public void ParseFromEmptyTest() { try { var date = FuzzyDate.Parse(""); Assert.IsFalse(date.Year.HasValue); Assert.IsFalse(date.Month.HasValue); Assert.IsFalse(date.Day.HasValue); } catch (Exception ex) { Assert.Fail($"Expect no exception, but got {ex.Message}"); } }
public void AddPositiveDaysTest() { try { var fd = new FuzzyDate(2019, 9, 29); var newDate = fd.AddDays(10); Assert.AreEqual(2019, newDate.Year); Assert.AreEqual(10, newDate.Month); Assert.AreEqual(9, newDate.Day); } catch (Exception ex) { Assert.Fail($"Expect no exception, but got {ex.Message}"); } }
public void AddPositiveMonthsTest() { try { var fd = new FuzzyDate(2019, 9); var newDate = fd.AddMonths(10); Assert.AreEqual(2020, newDate.Year); Assert.AreEqual(7, newDate.Month); Assert.IsFalse(newDate.Day.HasValue); } catch (Exception ex) { Assert.Fail($"Expect no exception, but got {ex.Message}"); } }
public void AddZeroYearsTest() { try { var fd = new FuzzyDate(2019); var newDate = fd.AddYears(0); Assert.AreEqual(2019, newDate.Year); Assert.IsFalse(newDate.Month.HasValue); Assert.IsFalse(newDate.Day.HasValue); } catch (Exception ex) { Assert.Fail($"Expect no exception, but got {ex.Message}"); } }
/// <summary> /// Returns the last N uploaded images. /// </summary> public async Task <IReadOnlyList <MediaThumbnailVM> > GetLastUploadedMediaAsync(int count) { return(await _db.Media .Where(x => !x.IsDeleted) .OrderByDescending(x => x.UploadDate) .Take(count) .Select(x => new MediaThumbnailVM { Key = x.Key, Type = x.Type, ThumbnailUrl = GetSizedMediaPath(x.FilePath, MediaSize.Small), Date = FuzzyDate.TryParse(x.Date), }) .ToListAsync()); }
public void AddToNullTest() { try { var fd = new FuzzyDate(); var newDate = fd.AddYears(10); Assert.IsFalse(newDate.Year.HasValue); Assert.IsFalse(newDate.Month.HasValue); Assert.IsFalse(newDate.Day.HasValue); } catch (Exception ex) { Assert.Fail($"Expect no exception, but got {ex.Message}"); } }
/// <summary> /// Returns the photo model. /// </summary> public static MediaThumbnailVM GetMediaThumbnail(Media media, MediaSize size = MediaSize.Small) { if (media == null) { return(null); } return(new MediaThumbnailVM { Type = media.Type, Key = media.Key, ThumbnailUrl = GetSizedMediaPath(media.FilePath, size), Date = FuzzyDate.TryParse(media.Date) }); }
public void ConvertNormalDateToDateTimeTest() { try { var fDate = new FuzzyDate(2019, 9, 3); var converted = fDate.ToDateTime(); Assert.AreEqual(fDate.Year.Value, converted.Year); Assert.AreEqual(fDate.Month.Value, converted.Month); Assert.AreEqual(fDate.Day.Value, converted.Day); } catch (Exception ex) { Assert.Fail($"Expect no exception, but got {ex.Message}"); } }
/// <summary> /// Returns the media details. /// </summary> public async Task <MediaVM> GetMediaAsync(string key, UserContext ctx) { var errorKey = $"Media ({key})"; var media = await _db.Media .AsNoTracking() .Include(x => x.Tags) .ThenInclude(x => x.Tag) .Include(x => x.Folder) .GetAsync(x => x.Key == key, errorKey); if (ctx.Link != null) { // subfolders disallowed: only media immediately inside current folder are available if (ctx.Link.Scope == SearchScope.CurrentFolder && media.FolderKey != ctx.Link.Folder.Key) { throw new NotFoundException(errorKey); } // inside subfolder if (!media.Folder.Path.StartsWith(ctx.Link.Folder.Path)) { throw new NotFoundException(errorKey); } // must have tags if (!string.IsNullOrEmpty(ctx.Link.Tags)) { var tagIds = ctx.Link.Tags.TryParseList <int>(","); if (!media.Tags.Any(x => tagIds.Contains(x.TagId))) { throw new NotFoundException(errorKey); } } var mediaDate = FuzzyDate.TryParse(media.Date); var dateFrom = FuzzyDate.TryParse(ctx.Link.DateFrom); var dateTo = FuzzyDate.TryParse(ctx.Link.DateTo); if ((dateFrom != null && !(mediaDate >= dateFrom)) || (dateTo != null && !(mediaDate <= dateTo))) { throw new NotFoundException(errorKey); } } return(_mapper.Map <MediaVM>(media)); }
private void TestGenerator() { var dateNames = new string[] { "_fdNone", "_fdYear", "_fdMonth", "_fdDay" }; var dates = new FuzzyDate[] { _fdNone, _fdYear, _fdMonth, _fdDay }; for (int firstFrom = 0; firstFrom < dates.Length; firstFrom++) { var firstFromDate = dates[firstFrom]; var firstFromName = dateNames[firstFrom]; for (int firstTo = 0; firstTo < dates.Length; firstTo++) { var firstToDate = dates[firstTo]; var firstToName = dateNames[firstTo]; for (int secondFrom = 0; secondFrom < dates.Length; secondFrom++) { var secondFromDate = dates[secondFrom]; var secondFromName = dateNames[secondFrom]; for (int secondTo = 0; secondTo < dates.Length; secondTo++) { var secondToDate = dates[secondTo]; var secondToName = dateNames[secondTo]; var compareResult = new FuzzyDateRange(firstFromDate, firstToDate).CompareTo(new FuzzyDateRange(secondFromDate, secondToDate)); Trace.WriteLine($"Assert.AreEqual({compareResult}, new FuzzyDateRange({firstFromName}, {firstToName}).CompareTo(new FuzzyDateRange({secondFromName}, {secondToName})));"); } } } } }
public void ConvertToTimeSpanTest() { try { var dayFrom = 2; var dayTo = 15; var from = new FuzzyDate(2019, 9, dayFrom); var to = new FuzzyDate(2019, 9, dayTo); var range = new FuzzyDateRange(from, to); var converted = range.ToTimeSpan(); Assert.AreEqual(dayTo - dayFrom, converted.TotalDays); } catch (Exception ex) { Assert.Fail($"Expect no exception, but got {ex.Message}"); } }