2018-12-01 13:17:53 -05:00
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
2018-04-08 02:44:42 -04:00
|
|
|
|
using SharedLibraryCore.Database;
|
|
|
|
|
using SharedLibraryCore.Database.Models;
|
|
|
|
|
using SharedLibraryCore.Dtos;
|
2018-04-26 20:19:42 -04:00
|
|
|
|
using SharedLibraryCore.Objects;
|
2018-12-01 13:17:53 -05:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Linq.Expressions;
|
|
|
|
|
using System.Threading.Tasks;
|
2018-11-05 22:01:29 -05:00
|
|
|
|
using static SharedLibraryCore.Database.Models.EFClient;
|
2017-11-25 20:29:58 -05:00
|
|
|
|
|
2018-04-08 02:44:42 -04:00
|
|
|
|
namespace SharedLibraryCore.Services
|
2017-11-25 20:29:58 -05:00
|
|
|
|
{
|
|
|
|
|
public class PenaltyService : Interfaces.IEntityService<EFPenalty>
|
|
|
|
|
{
|
2018-04-09 15:17:10 -04:00
|
|
|
|
public async Task<EFPenalty> Create(EFPenalty newEntity)
|
2017-11-25 20:29:58 -05:00
|
|
|
|
{
|
2017-11-29 19:35:50 -05:00
|
|
|
|
using (var context = new DatabaseContext())
|
2017-11-25 20:29:58 -05:00
|
|
|
|
{
|
2017-11-29 19:35:50 -05:00
|
|
|
|
// make bans propogate to all aliases
|
2018-12-29 13:43:40 -05:00
|
|
|
|
if (newEntity.Type == Penalty.PenaltyType.Ban)
|
2017-11-29 19:35:50 -05:00
|
|
|
|
{
|
|
|
|
|
await context.Clients
|
2018-12-29 13:43:40 -05:00
|
|
|
|
.Include(c => c.ReceivedPenalties)
|
|
|
|
|
.Where(c => c.AliasLinkId == newEntity.Link.AliasLinkId)
|
|
|
|
|
.ForEachAsync(c =>
|
|
|
|
|
{
|
|
|
|
|
if (c.Level != Permission.Banned)
|
|
|
|
|
{
|
|
|
|
|
c.Level = Permission.Banned;
|
|
|
|
|
c.ReceivedPenalties.Add(new EFPenalty()
|
|
|
|
|
{
|
|
|
|
|
Active = true,
|
|
|
|
|
OffenderId = c.ClientId,
|
|
|
|
|
PunisherId = newEntity.Punisher.ClientId,
|
|
|
|
|
LinkId = c.AliasLinkId,
|
|
|
|
|
Type = newEntity.Type,
|
|
|
|
|
Expires = newEntity.Expires,
|
|
|
|
|
Offense = newEntity.Offense,
|
|
|
|
|
When = DateTime.UtcNow,
|
|
|
|
|
AutomatedOffense = newEntity.AutomatedOffense,
|
|
|
|
|
IsEvadedOffense = newEntity.IsEvadedOffense
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
2017-11-29 19:35:50 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// make flags propogate to all aliases
|
2018-12-29 13:43:40 -05:00
|
|
|
|
else if (newEntity.Type == Penalty.PenaltyType.Flag)
|
2017-11-29 19:35:50 -05:00
|
|
|
|
{
|
|
|
|
|
await context.Clients
|
2018-12-29 13:43:40 -05:00
|
|
|
|
.Include(c => c.ReceivedPenalties)
|
2018-12-31 21:52:19 -05:00
|
|
|
|
.Where(c => c.AliasLinkId == newEntity.Link.AliasLinkId)
|
2018-12-29 13:43:40 -05:00
|
|
|
|
.ForEachAsync(c =>
|
|
|
|
|
{
|
|
|
|
|
if (c.Level != Permission.Flagged)
|
|
|
|
|
{
|
|
|
|
|
c.Level = Permission.Flagged;
|
|
|
|
|
c.ReceivedPenalties.Add(new EFPenalty()
|
|
|
|
|
{
|
|
|
|
|
Active = true,
|
|
|
|
|
OffenderId = c.ClientId,
|
|
|
|
|
PunisherId = newEntity.Punisher.ClientId,
|
|
|
|
|
LinkId = c.AliasLinkId,
|
|
|
|
|
Type = newEntity.Type,
|
|
|
|
|
Expires = newEntity.Expires,
|
|
|
|
|
Offense = newEntity.Offense,
|
|
|
|
|
When = DateTime.UtcNow,
|
|
|
|
|
AutomatedOffense = newEntity.AutomatedOffense,
|
|
|
|
|
IsEvadedOffense = newEntity.IsEvadedOffense
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we just want to add it to the database
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-12-31 21:52:19 -05:00
|
|
|
|
var penalty = new EFPenalty()
|
2018-12-29 13:43:40 -05:00
|
|
|
|
{
|
|
|
|
|
Active = true,
|
|
|
|
|
OffenderId = newEntity.Offender.ClientId,
|
|
|
|
|
PunisherId = newEntity.Punisher.ClientId,
|
|
|
|
|
LinkId = newEntity.Link.AliasLinkId,
|
|
|
|
|
Type = newEntity.Type,
|
|
|
|
|
Expires = newEntity.Expires,
|
|
|
|
|
Offense = newEntity.Offense,
|
|
|
|
|
When = DateTime.UtcNow,
|
|
|
|
|
AutomatedOffense = newEntity.AutomatedOffense,
|
|
|
|
|
IsEvadedOffense = newEntity.IsEvadedOffense
|
2018-12-31 21:52:19 -05:00
|
|
|
|
};
|
|
|
|
|
|
2019-01-02 19:32:39 -05:00
|
|
|
|
newEntity.Offender.ReceivedPenalties?.Add(penalty);
|
2018-12-31 21:52:19 -05:00
|
|
|
|
context.Penalties.Add(penalty);
|
2017-11-29 19:35:50 -05:00
|
|
|
|
}
|
|
|
|
|
|
2017-11-25 20:29:58 -05:00
|
|
|
|
await context.SaveChangesAsync();
|
2018-12-29 13:43:40 -05:00
|
|
|
|
return newEntity;
|
2017-11-25 20:29:58 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<EFPenalty> CreateProxy()
|
|
|
|
|
{
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<EFPenalty> Delete(EFPenalty entity)
|
|
|
|
|
{
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<IList<EFPenalty>> Find(Func<EFPenalty, bool> expression)
|
|
|
|
|
{
|
2018-04-05 00:38:45 -04:00
|
|
|
|
throw await Task.FromResult(new Exception());
|
2017-11-25 20:29:58 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<EFPenalty> Get(int entityID)
|
|
|
|
|
{
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-10 23:33:42 -05:00
|
|
|
|
public Task<EFPenalty> GetUnique(long entityProperty)
|
2017-11-25 20:29:58 -05:00
|
|
|
|
{
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task<EFPenalty> Update(EFPenalty entity)
|
|
|
|
|
{
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-04 00:22:10 -04:00
|
|
|
|
public async Task<IList<EFPenalty>> GetRecentPenalties(int count, int offset, Penalty.PenaltyType showOnly = Penalty.PenaltyType.Any)
|
2017-11-25 20:29:58 -05:00
|
|
|
|
{
|
2018-09-12 20:53:11 -04:00
|
|
|
|
using (var context = new DatabaseContext(true))
|
2018-12-01 13:17:53 -05:00
|
|
|
|
{
|
2017-11-25 20:29:58 -05:00
|
|
|
|
return await context.Penalties
|
2017-11-29 19:35:50 -05:00
|
|
|
|
.Include(p => p.Offender.CurrentAlias)
|
|
|
|
|
.Include(p => p.Punisher.CurrentAlias)
|
2018-05-04 00:22:10 -04:00
|
|
|
|
.Where(p => showOnly == Penalty.PenaltyType.Any ? p.Type != Penalty.PenaltyType.Any : p.Type == showOnly)
|
2017-11-29 19:35:50 -05:00
|
|
|
|
.Where(p => p.Active)
|
2017-11-25 20:29:58 -05:00
|
|
|
|
.OrderByDescending(p => p.When)
|
|
|
|
|
.Skip(offset)
|
|
|
|
|
.Take(count)
|
2018-12-17 14:45:16 -05:00
|
|
|
|
.ToListAsync();
|
2018-12-01 13:17:53 -05:00
|
|
|
|
}
|
2017-11-25 20:29:58 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<IList<EFPenalty>> GetClientPenaltiesAsync(int clientId)
|
|
|
|
|
{
|
2018-09-12 20:53:11 -04:00
|
|
|
|
using (var context = new DatabaseContext(true))
|
2018-12-01 13:17:53 -05:00
|
|
|
|
{
|
2017-11-25 20:29:58 -05:00
|
|
|
|
return await context.Penalties
|
2017-11-29 19:35:50 -05:00
|
|
|
|
.Where(p => p.OffenderId == clientId)
|
|
|
|
|
.Where(p => p.Active)
|
|
|
|
|
.Include(p => p.Offender.CurrentAlias)
|
|
|
|
|
.Include(p => p.Punisher.CurrentAlias)
|
|
|
|
|
.ToListAsync();
|
2018-12-01 13:17:53 -05:00
|
|
|
|
}
|
2017-11-25 20:29:58 -05:00
|
|
|
|
}
|
|
|
|
|
|
2018-02-14 14:01:26 -05:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get a read-only copy of client penalties
|
|
|
|
|
/// </summary>
|
2018-12-17 14:45:16 -05:00
|
|
|
|
/// <param name="clientId"></param>
|
2018-02-14 14:01:26 -05:00
|
|
|
|
/// <param name="victim">Retreive penalties for clients receiving penalties, other wise given</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<List<ProfileMeta>> ReadGetClientPenaltiesAsync(int clientId, bool victim = true)
|
|
|
|
|
{
|
2018-09-12 20:53:11 -04:00
|
|
|
|
using (var context = new DatabaseContext(true))
|
2018-02-14 14:01:26 -05:00
|
|
|
|
{
|
2018-09-12 20:53:11 -04:00
|
|
|
|
// todo: clean this up
|
2018-02-14 14:01:26 -05:00
|
|
|
|
if (victim)
|
|
|
|
|
{
|
2018-04-13 02:32:30 -04:00
|
|
|
|
var now = DateTime.UtcNow;
|
2018-02-14 14:01:26 -05:00
|
|
|
|
var iqPenalties = from penalty in context.Penalties.AsNoTracking()
|
|
|
|
|
where penalty.OffenderId == clientId
|
|
|
|
|
join victimClient in context.Clients.AsNoTracking()
|
|
|
|
|
on penalty.OffenderId equals victimClient.ClientId
|
2018-04-26 20:19:42 -04:00
|
|
|
|
join victimAlias in context.Aliases.AsNoTracking()
|
2018-02-14 14:01:26 -05:00
|
|
|
|
on victimClient.CurrentAliasId equals victimAlias.AliasId
|
2018-04-26 20:19:42 -04:00
|
|
|
|
join punisherClient in context.Clients.AsNoTracking()
|
2018-02-14 14:01:26 -05:00
|
|
|
|
on penalty.PunisherId equals punisherClient.ClientId
|
2018-04-26 20:19:42 -04:00
|
|
|
|
join punisherAlias in context.Aliases.AsNoTracking()
|
2018-02-14 14:01:26 -05:00
|
|
|
|
on punisherClient.CurrentAliasId equals punisherAlias.AliasId
|
|
|
|
|
//orderby penalty.When descending
|
|
|
|
|
select new ProfileMeta()
|
|
|
|
|
{
|
|
|
|
|
Key = "Event.Penalty",
|
2018-02-21 20:29:23 -05:00
|
|
|
|
Value = new PenaltyInfo
|
2018-02-14 14:01:26 -05:00
|
|
|
|
{
|
2018-06-05 17:31:36 -04:00
|
|
|
|
Id = penalty.PenaltyId,
|
2018-02-14 14:01:26 -05:00
|
|
|
|
OffenderName = victimAlias.Name,
|
|
|
|
|
OffenderId = victimClient.ClientId,
|
|
|
|
|
PunisherName = punisherAlias.Name,
|
|
|
|
|
PunisherId = penalty.PunisherId,
|
|
|
|
|
Offense = penalty.Offense,
|
2018-04-13 02:32:30 -04:00
|
|
|
|
Type = penalty.Type.ToString(),
|
2018-12-01 13:17:53 -05:00
|
|
|
|
TimeRemaining = penalty.Expires.HasValue ? (now > penalty.Expires ? "" : penalty.Expires.ToString()) : DateTime.MaxValue.ToString(),
|
2019-02-17 19:48:40 -05:00
|
|
|
|
AutomatedOffense = penalty.AutomatedOffense,
|
|
|
|
|
Expired = penalty.Expires.HasValue && penalty.Expires <= DateTime.UtcNow
|
2018-02-14 14:01:26 -05:00
|
|
|
|
},
|
2018-03-09 03:01:12 -05:00
|
|
|
|
When = penalty.When,
|
2018-04-28 17:39:45 -04:00
|
|
|
|
Sensitive = penalty.Type == Penalty.PenaltyType.Flag
|
2018-02-14 14:01:26 -05:00
|
|
|
|
};
|
|
|
|
|
// fixme: is this good and fast?
|
2018-04-13 02:32:30 -04:00
|
|
|
|
var list = await iqPenalties.ToListAsync();
|
|
|
|
|
list.ForEach(p =>
|
|
|
|
|
{
|
2018-04-28 17:39:45 -04:00
|
|
|
|
// todo: why does this have to be done?
|
|
|
|
|
if (((PenaltyInfo)p.Value).Type.Length < 2)
|
2018-12-01 13:17:53 -05:00
|
|
|
|
{
|
2018-04-28 17:39:45 -04:00
|
|
|
|
((PenaltyInfo)p.Value).Type = ((Penalty.PenaltyType)Convert.ToInt32(((PenaltyInfo)p.Value).Type)).ToString();
|
2018-12-01 13:17:53 -05:00
|
|
|
|
}
|
2018-04-28 17:39:45 -04:00
|
|
|
|
|
2018-04-13 02:32:30 -04:00
|
|
|
|
var pi = ((PenaltyInfo)p.Value);
|
2018-10-25 09:14:39 -04:00
|
|
|
|
if (pi.TimeRemaining?.Length > 0)
|
2018-12-01 13:17:53 -05:00
|
|
|
|
{
|
2018-04-13 02:32:30 -04:00
|
|
|
|
pi.TimeRemaining = (DateTime.Parse(((PenaltyInfo)p.Value).TimeRemaining) - now).TimeSpanText();
|
2019-02-17 19:48:40 -05:00
|
|
|
|
|
|
|
|
|
if (!pi.Expired)
|
|
|
|
|
{
|
|
|
|
|
pi.TimeRemaining = $"{pi.TimeRemaining} {Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]}";
|
|
|
|
|
}
|
2018-12-01 13:17:53 -05:00
|
|
|
|
}
|
2018-04-28 17:39:45 -04:00
|
|
|
|
});
|
2018-04-13 02:32:30 -04:00
|
|
|
|
return list;
|
2018-02-14 14:01:26 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var iqPenalties = from penalty in context.Penalties.AsNoTracking()
|
|
|
|
|
where penalty.PunisherId == clientId
|
|
|
|
|
join victimClient in context.Clients.AsNoTracking()
|
|
|
|
|
on penalty.OffenderId equals victimClient.ClientId
|
|
|
|
|
join victimAlias in context.Aliases
|
|
|
|
|
on victimClient.CurrentAliasId equals victimAlias.AliasId
|
|
|
|
|
join punisherClient in context.Clients
|
|
|
|
|
on penalty.PunisherId equals punisherClient.ClientId
|
|
|
|
|
join punisherAlias in context.Aliases
|
|
|
|
|
on punisherClient.CurrentAliasId equals punisherAlias.AliasId
|
|
|
|
|
//orderby penalty.When descending
|
|
|
|
|
select new ProfileMeta()
|
|
|
|
|
{
|
|
|
|
|
Key = "Event.Penalty",
|
2018-02-21 20:29:23 -05:00
|
|
|
|
Value = new PenaltyInfo
|
2018-02-14 14:01:26 -05:00
|
|
|
|
{
|
2018-06-05 17:31:36 -04:00
|
|
|
|
Id = penalty.PenaltyId,
|
2018-02-14 14:01:26 -05:00
|
|
|
|
OffenderName = victimAlias.Name,
|
|
|
|
|
OffenderId = victimClient.ClientId,
|
|
|
|
|
PunisherName = punisherAlias.Name,
|
|
|
|
|
PunisherId = penalty.PunisherId,
|
|
|
|
|
Offense = penalty.Offense,
|
2018-05-30 21:50:20 -04:00
|
|
|
|
Type = penalty.Type.ToString(),
|
|
|
|
|
AutomatedOffense = penalty.AutomatedOffense
|
2018-02-14 14:01:26 -05:00
|
|
|
|
},
|
2018-05-14 13:55:10 -04:00
|
|
|
|
When = penalty.When,
|
|
|
|
|
Sensitive = penalty.Type == Penalty.PenaltyType.Flag
|
2018-02-14 14:01:26 -05:00
|
|
|
|
};
|
|
|
|
|
// fixme: is this good and fast?
|
2018-04-26 20:19:42 -04:00
|
|
|
|
var list = await iqPenalties.ToListAsync();
|
|
|
|
|
|
|
|
|
|
list.ForEach(p =>
|
|
|
|
|
{
|
|
|
|
|
// todo: why does this have to be done?
|
|
|
|
|
if (((PenaltyInfo)p.Value).Type.Length < 2)
|
2018-12-01 13:17:53 -05:00
|
|
|
|
{
|
2018-04-26 20:19:42 -04:00
|
|
|
|
((PenaltyInfo)p.Value).Type = ((Penalty.PenaltyType)Convert.ToInt32(((PenaltyInfo)p.Value).Type)).ToString();
|
2018-12-01 13:17:53 -05:00
|
|
|
|
}
|
2018-04-26 20:19:42 -04:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return list;
|
2018-02-14 14:01:26 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-25 21:00:36 -05:00
|
|
|
|
public async Task<List<EFPenalty>> GetActivePenaltiesAsync(int linkId, int? ip = null)
|
2018-02-15 23:01:28 -05:00
|
|
|
|
{
|
2018-09-02 17:59:27 -04:00
|
|
|
|
var now = DateTime.UtcNow;
|
|
|
|
|
|
2018-12-01 13:17:53 -05:00
|
|
|
|
Expression<Func<EFPenalty, bool>> filter = (p) => new Penalty.PenaltyType[]
|
|
|
|
|
{
|
|
|
|
|
Penalty.PenaltyType.TempBan,
|
2018-12-29 13:43:40 -05:00
|
|
|
|
Penalty.PenaltyType.Ban,
|
|
|
|
|
Penalty.PenaltyType.Flag
|
2018-12-01 13:17:53 -05:00
|
|
|
|
}.Contains(p.Type) &&
|
|
|
|
|
p.Active &&
|
|
|
|
|
(p.Expires == null || p.Expires > now);
|
|
|
|
|
|
2018-09-12 20:53:11 -04:00
|
|
|
|
using (var context = new DatabaseContext(true))
|
2018-02-15 23:01:28 -05:00
|
|
|
|
{
|
2018-12-01 13:17:53 -05:00
|
|
|
|
var iqLinkPenalties = context.Penalties
|
|
|
|
|
.Where(p => p.LinkId == linkId)
|
|
|
|
|
.Where(filter);
|
|
|
|
|
|
|
|
|
|
var iqIPPenalties = context.Aliases
|
2018-12-29 13:43:40 -05:00
|
|
|
|
.Where(a => a.IPAddress != null & a.IPAddress == ip)
|
2018-12-01 13:17:53 -05:00
|
|
|
|
.SelectMany(a => a.Link.ReceivedPenalties)
|
|
|
|
|
.Where(filter);
|
|
|
|
|
|
2018-09-12 20:53:11 -04:00
|
|
|
|
#if DEBUG == true
|
2018-12-01 13:17:53 -05:00
|
|
|
|
var penaltiesSql = iqLinkPenalties.ToSql();
|
|
|
|
|
var ipPenaltiesSql = iqIPPenalties.ToSql();
|
2018-09-12 20:53:11 -04:00
|
|
|
|
#endif
|
|
|
|
|
|
2018-12-29 13:43:40 -05:00
|
|
|
|
var activePenalties = (await iqLinkPenalties.ToListAsync())
|
|
|
|
|
.Union(await iqIPPenalties.ToListAsync())
|
|
|
|
|
.Distinct();
|
|
|
|
|
|
2018-09-12 20:53:11 -04:00
|
|
|
|
// this is a bit more performant in memory (ordering)
|
2018-12-01 13:17:53 -05:00
|
|
|
|
return activePenalties.OrderByDescending(p => p.When).ToList();
|
2018-02-15 23:01:28 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-25 20:29:58 -05:00
|
|
|
|
public async Task RemoveActivePenalties(int aliasLinkId)
|
|
|
|
|
{
|
2017-11-29 19:35:50 -05:00
|
|
|
|
using (var context = new DatabaseContext())
|
2017-11-25 20:29:58 -05:00
|
|
|
|
{
|
|
|
|
|
var now = DateTime.UtcNow;
|
|
|
|
|
var penalties = await context.Penalties
|
|
|
|
|
.Include(p => p.Link.Children)
|
|
|
|
|
.Where(p => p.LinkId == aliasLinkId)
|
2018-10-15 20:51:04 -04:00
|
|
|
|
.Where(p => p.Expires > now || p.Expires == null)
|
2017-11-25 20:29:58 -05:00
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
penalties.ForEach(async p =>
|
|
|
|
|
{
|
|
|
|
|
p.Active = false;
|
2017-11-29 19:35:50 -05:00
|
|
|
|
// reset the player levels
|
2018-04-28 01:22:18 -04:00
|
|
|
|
if (p.Type == Penalty.PenaltyType.Ban)
|
2018-04-26 16:26:03 -04:00
|
|
|
|
{
|
|
|
|
|
using (var internalContext = new DatabaseContext())
|
|
|
|
|
{
|
|
|
|
|
await internalContext.Clients
|
|
|
|
|
.Where(c => c.AliasLinkId == p.LinkId)
|
2018-11-05 22:01:29 -05:00
|
|
|
|
.ForEachAsync(c => c.Level = EFClient.Permission.User);
|
2018-04-28 01:22:18 -04:00
|
|
|
|
await internalContext.SaveChangesAsync();
|
2018-04-26 16:26:03 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-11-25 20:29:58 -05:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await context.SaveChangesAsync();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|