сделал авторизация доабвил оптимизацию
This commit is contained in:
		| @@ -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<User> _userManager; | ||||
| @@ -130,6 +128,25 @@ public class UsersController : ControllerBase | ||||
|             user, | ||||
|             role | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     [HttpGet("stats")] | ||||
|     public async Task<IActionResult> 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<IActionResult> 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<UserWriteToMeting>(); | ||||
|          | ||||
|         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<List<Achievment>> WriteAchievment(StatsData stats, string userId) | ||||
|     { | ||||
|         List <Achievment> achievments = new List<Achievment>(); | ||||
|         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<IActionResult> 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); | ||||
|  | ||||
|   | ||||
| @@ -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<TagStats> StatsByTag { get; set; } = new List<TagStats>(); | ||||
|  | ||||
|     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<User> | ||||
|  | ||||
|     public DbSet<Question> Questions { get; set; } | ||||
|  | ||||
|  | ||||
|     public DbSet<Achievment> Achievments { get; set; } | ||||
|  | ||||
|     public ApplicationContext(DbContextOptions<ApplicationContext> options) | ||||
|         : base(options) | ||||
|     { | ||||
| @@ -318,5 +352,7 @@ public class ApplicationContext : IdentityDbContext<User> | ||||
|  | ||||
|         builder.Entity<Meeting>().HasMany<UserWriteToMeting>().WithOne().HasForeignKey(c => c.MeetingId); | ||||
|         builder.Entity<UserWriteToMeting>().HasOne<User>().WithMany().HasForeignKey(c => c.UserId); | ||||
|      | ||||
|         builder.Entity<Achievment>().HasOne<User>().WithMany().HasForeignKey(c => c.UserId); | ||||
|     } | ||||
| } | ||||
| @@ -12,9 +12,9 @@ TypeAdapterConfig<PutMeetingDto, Meeting>.NewConfig().Map(d => d.SpeackerImage, | ||||
| TypeAdapterConfig<PostMeetingDto, Meeting>.NewConfig().Map(d => d.SpeackerImage, s => s.SpeackerImage.JoinFileNames()); | ||||
|  | ||||
|  | ||||
| TypeAdapterConfig<PostMeetingDto, Meeting>.NewConfig().Map(d => d.Splecializations, s => String.Join(FILES_SEPORATOR_IN_STORE, s.Splecializations)); | ||||
| TypeAdapterConfig<PostMeetingDto, Meeting>.NewConfig().Map(d => d.Splecializations, s => String.Join(TOKENS_SEPORATOR, s.Splecializations)); | ||||
|  | ||||
| TypeAdapterConfig<PutMeetingDto, Meeting>.NewConfig().Map(d => d.Splecializations, s => String.Join(FILES_SEPORATOR_IN_STORE, s.Splecializations)); | ||||
| TypeAdapterConfig<PutMeetingDto, Meeting>.NewConfig().Map(d => d.Splecializations, s => String.Join(TOKENS_SEPORATOR, s.Splecializations)); | ||||
|  | ||||
|  | ||||
| TypeAdapterConfig<PostMeetingDto, Meeting>.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<IFormFile> files) => files.Select(s => s.FileName).JoinStrings(); | ||||
|  | ||||
|     public static string JoinStrings(this IEnumerable<string> files) => String.Join(FILES_SEPORATOR_IN_STORE, files.Select(s => s)); | ||||
|     public static string JoinStrings(this IEnumerable<string> 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<StatsData> 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; | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user