From b4b5bfc1ed962ea34d1e19110935b67990312014 Mon Sep 17 00:00:00 2001 From: Vitalick Kovalenko Date: Sat, 23 Dec 2023 23:34:14 +0300 Subject: [PATCH] =?UTF-8?q?=D1=81=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20=D0=B0?= =?UTF-8?q?=D0=B2=D1=82=D0=BE=D1=80=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=B0=D0=B1=D0=B2=D0=B8=D0=BB=20=D0=BE=D0=BF=D1=82?= =?UTF-8?q?=D0=B8=D0=BC=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CyberBoom/Controllers/UserController.cs | 119 +++++++++++++++++++----- CyberBoom/DbContext/User.cs | 40 +++++++- CyberBoom/Program.cs | 70 +++++++++++++- 3 files changed, 197 insertions(+), 32 deletions(-) diff --git a/CyberBoom/Controllers/UserController.cs b/CyberBoom/Controllers/UserController.cs index e2cfd1e..e2e5f62 100644 --- a/CyberBoom/Controllers/UserController.cs +++ b/CyberBoom/Controllers/UserController.cs @@ -6,7 +6,9 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Internal; using Microsoft.IdentityModel.Tokens; +using static Consts; namespace CyberBoom.Controllers; @@ -14,10 +16,6 @@ namespace CyberBoom.Controllers; [Route("/api/[controller]")] public class UsersController : ControllerBase { - - - - private readonly ApplicationContext _applicationContext; private readonly UserManager _userManager; @@ -130,6 +128,25 @@ public class UsersController : ControllerBase user, role }); + } + + [HttpGet("stats")] + public async Task GetUserStats(string id) + { + var user = await _userManager.FindByIdAsync(id); + + if(user is null) + return BadRequest(); + + var stats = await _applicationContext.GetStatistic(id); + + var achievmnets = _applicationContext.Achievments.Where(c => c.UserId == id); + + + return Ok(new { + Stats = stats, + Achievments = achievmnets + }); } } @@ -202,7 +219,7 @@ public class MeetingsController : ControllerBase [HttpGet("list")] public IActionResult GetList(int offset, int limit) { - var meetings = _applicationContext.Meetings.Skip(offset).Take(limit); + var meetings = _applicationContext.Meetings.AsNoTracking().Skip(offset).Take(limit); return Ok(meetings); @@ -272,7 +289,7 @@ public class ReviewsController : ControllerBase [HttpGet("list")] public IActionResult GetList(int offset, int limit) { - var reviews = _applicationContext.Reviews + var reviews = _applicationContext.Reviews.AsNoTracking() .Include(c => c.User) .Skip(offset) .Take(limit); @@ -341,7 +358,7 @@ public class QuestionsController : ControllerBase [HttpGet("list")] public IActionResult GetList(int offset, int limit) { - var questions = _applicationContext.Questions + var questions = _applicationContext.Questions.AsNoTracking() .Include(c => c.User) .Skip(offset) .Take(limit); @@ -398,32 +415,23 @@ public class ReactionsController : ControllerBase [HttpGet] public async Task Get(string id) { - var review = await _applicationContext.Reviews + var reaction = await _applicationContext.Reactions .FirstAsync(s => s.Id == id); - var user = await _applicationContext.Users.FirstAsync(s => s.Id == review.UserId); - return Ok(new { - review, - user - }); + + return Ok(reaction); } [HttpGet("list")] public IActionResult GetList(int offset, int limit) { - var reviews = _applicationContext.Reviews + var reactions = _applicationContext.Reactions.AsNoTracking() .Skip(offset) .Take(limit); - var users = _applicationContext.Users.Where(u => reviews.Select(u => u.UserId).Contains(u.Id)); - return Ok( - reviews.Select(s => new { - review = s, - user = users.First(u => u.Id == s.UserId) - }) - ); + return Ok(reactions); } } @@ -449,22 +457,83 @@ public class UserWriteToMetingController : ControllerBase { var dbWr = write.Adapt(); + var meeting = await _applicationContext.Meetings.FirstAsync(m => m.Id == write.MeetingId); + + + + if(DateTime.UtcNow > meeting.Time) + return BadRequest(); + + + await _applicationContext.UserWriteToMetings.AddAsync(dbWr); - await _applicationContext.SaveChangesAsync(); + var user = await _applicationContext.Users.FirstAsync(u => u.Id == write.UserId); + + + var newStats = await _applicationContext.GetStatistic(write.UserId); + + + var achievments = await WriteAchievment(newStats, write.UserId); + + + await _applicationContext.SaveChangesAsync(); + return Ok(new { - dbWr.Id + dbWr.Id, + Achievments = achievments }); + + } + + async Task> WriteAchievment(StatsData stats, string userId) + { + List achievments = new List(); + if(stats.Count > 0 && stats.Count % 5 == 0) + { + var achievment = new Achievment{ + Name = $"Редстоун Наблюдатель Level {stats.Count / 5}", + Text = "Вы cамый настоящий Редстоун Наблюдатель из игры Майнкрафт, который не пропускате ни единой всречи!", + UserId = userId + }; + achievments.Add(achievment); + await _applicationContext.Achievments.AddAsync( + achievment + ); + } + var achievedTags = stats.StatsByTag.Where(st => st.Count > 0 && st.Count % 5 == 0); + if(achievedTags.Count() > 0 && stats.Count % 5 == 0) + { + + foreach(var tag in achievedTags) + { + var achievment = new Achievment{ + Name = $"Вкачаю все в {tag.Tag} Level {tag.Count / 5}", + Text = $"Вы нежалеете очки времени на ветку {tag.Tag}, продолжайте в том же духе!", + UserId = userId + }; + achievments.Add(achievment); + await _applicationContext.Achievments.AddAsync( + achievment + ); + } + + } + return achievments; } [HttpDelete] public async Task Delete(string id) { - var fReview = await _applicationContext.UserWriteToMetings.FirstAsync(r => r.Id == id); + var meeting = await _applicationContext.Meetings.FirstAsync(m => m.Id == fReview.MeetingId); + + if(DateTime.UtcNow > meeting.Time) + return BadRequest(); + _applicationContext.UserWriteToMetings.Remove(fReview); @@ -487,7 +556,7 @@ public class UserWriteToMetingController : ControllerBase [HttpGet("list")] public IActionResult GetList(int offset, int limit) { - var reviews = _applicationContext.UserWriteToMetings + var reviews = _applicationContext.UserWriteToMetings.AsNoTracking() .Skip(offset) .Take(limit); diff --git a/CyberBoom/DbContext/User.cs b/CyberBoom/DbContext/User.cs index ab8689c..86d060b 100644 --- a/CyberBoom/DbContext/User.cs +++ b/CyberBoom/DbContext/User.cs @@ -15,6 +15,8 @@ public class User : IdentityUser public string TelegramBotUrl { get; set; } = null!; public int Level { get; set; } + + } public class UserPost @@ -30,11 +32,28 @@ public class UserPost public string TelegramBotUrl { get; set; } = null!; } +public class StatsData +{ + public double Hours{ get; set; } + + public int Count { get; set; } + + public List StatsByTag { get; set; } = new List(); + + public class TagStats + { + public string Tag { get; set; } = null!; + + public int Count { get; set; } + + public double Hours { get; set; } + } +} public class UserPut { public string Id { get; set; } = null!; - + public IFormFile Avatar { get; set; } = null!; public string Fio { get; set; } = null!; @@ -148,7 +167,7 @@ public class Meeting public string SpeackerImage { get; set; } = null!; - public string Splecializations { get; set; } = null!; + public string Splecializations { get; set; } = null!; //speacker specilization public string Type { get; set; } = "онлайн/офлайн"; @@ -254,6 +273,18 @@ public class Review } +public class Achievment +{ + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public string Id { get; set; } = null!; + + public string UserId { get; set; } = null!; + + public string Name { get; set; } = null!; + + public string Text { get; set; } = null!; +} + public class PostReactionDto { @@ -293,6 +324,9 @@ public class ApplicationContext : IdentityDbContext public DbSet Questions { get; set; } + + public DbSet Achievments { get; set; } + public ApplicationContext(DbContextOptions options) : base(options) { @@ -318,5 +352,7 @@ public class ApplicationContext : IdentityDbContext builder.Entity().HasMany().WithOne().HasForeignKey(c => c.MeetingId); builder.Entity().HasOne().WithMany().HasForeignKey(c => c.UserId); + + builder.Entity().HasOne().WithMany().HasForeignKey(c => c.UserId); } } \ No newline at end of file diff --git a/CyberBoom/Program.cs b/CyberBoom/Program.cs index c0d3d13..9351f3b 100644 --- a/CyberBoom/Program.cs +++ b/CyberBoom/Program.cs @@ -12,9 +12,9 @@ TypeAdapterConfig.NewConfig().Map(d => d.SpeackerImage, TypeAdapterConfig.NewConfig().Map(d => d.SpeackerImage, s => s.SpeackerImage.JoinFileNames()); -TypeAdapterConfig.NewConfig().Map(d => d.Splecializations, s => String.Join(FILES_SEPORATOR_IN_STORE, s.Splecializations)); +TypeAdapterConfig.NewConfig().Map(d => d.Splecializations, s => String.Join(TOKENS_SEPORATOR, s.Splecializations)); -TypeAdapterConfig.NewConfig().Map(d => d.Splecializations, s => String.Join(FILES_SEPORATOR_IN_STORE, s.Splecializations)); +TypeAdapterConfig.NewConfig().Map(d => d.Splecializations, s => String.Join(TOKENS_SEPORATOR, s.Splecializations)); TypeAdapterConfig.NewConfig().Map(d => d.Time, s => s.Time.ToUniversalTime()); @@ -109,13 +109,24 @@ public class AuthOptions public static class Consts { - public const char FILES_SEPORATOR_IN_STORE = ';'; + public const char TOKENS_SEPORATOR = ';'; } -public static class PhileDataHelpers +public static class DataHelpers { public static string JoinFileNames(this IEnumerable files) => files.Select(s => s.FileName).JoinStrings(); - public static string JoinStrings(this IEnumerable files) => String.Join(FILES_SEPORATOR_IN_STORE, files.Select(s => s)); + public static string JoinStrings(this IEnumerable files) => String.Join(TOKENS_SEPORATOR, files.Select(s => s)); + + public static TimeSpan ParseDuration(this string duration) + { + var durArr = duration.Split(TOKENS_SEPORATOR, StringSplitOptions.RemoveEmptyEntries); + + var hours = int.Parse(durArr.First()); + var minutes = int.Parse(durArr[1]); + + return new TimeSpan(hours, minutes, 0); + + } public static async Task WriteFileToDirectory(this IFormFile file) { @@ -133,4 +144,53 @@ public static class PhileDataHelpers } } + + public static async Task GetStatistic(this ApplicationContext applicationContext, string id) + { + var specialities = await applicationContext.UserWriteToMetings.Where(c => c.UserId == id) + .Join(applicationContext.Meetings, + m => m.MeetingId, + m => m.Id, + (c,m) => new { + m.Tags, + m.Id, + m.Duration, + m.Time + } + ).Where(t => DateTime.UtcNow > t.Time).ToArrayAsync(); + + var selectedSpecialities = specialities.Select(s => new { + s.Id, + Tags = s.Tags.Split(TOKENS_SEPORATOR, StringSplitOptions.RemoveEmptyEntries), + Duration = s.Duration.ParseDuration().TotalHours + }); + + var allTags = selectedSpecialities.SelectMany(s => s.Tags).Distinct(); + var count = selectedSpecialities.Count(); + + StatsData stats = new StatsData{ + Count = count, + Hours = selectedSpecialities.Sum(m => m.Duration) * count + + }; + foreach(var tag in allTags) + { + //StatsData.TagStats + var specByTag = selectedSpecialities.Where(f => f.Tags.Contains(tag)); + var countByTag = specByTag.Count(); + var hours = selectedSpecialities.Sum(s => s.Duration) * countByTag; + + var stat = new StatsData.TagStats + { + Count = countByTag, + Tag = tag, + Hours = hours + }; + stats.StatsByTag.Add(stat); + } + + + + return stats; + } }