Пример #1
0
        public void Test_Get_Database_Type_EmptyConnection()
        {
            var command      = new SqlCommand();
            var databaseType = EFUtil.GetDataBaseType(command);

            Assert.AreEqual("entityframework", databaseType); // Empty connection will return entityframework by default.
        }
Пример #2
0
        public void Test_Get_Database_Type_SqlServer()
        {
            var connection   = new SqlConnection();
            var command      = new SqlCommand(null, connection);
            var databaseType = EFUtil.GetDataBaseType(command);

            Assert.AreEqual("sqlserver", databaseType);
        }
Пример #3
0
        public async Task <IActionResult> SetUserFinishedReportUploads()
        {
            var history = await EFUtil.GetOrCreateUserUploadHistory(context, CurrentUserId);

            history.LastUploadedReportsAt = CurrentServerTime;
            await context.SaveChangesAsync();

            return(Ok());
        }
Пример #4
0
        public void Test_Get_UserId_FirebirdSql()
        {
            DbConnectionStringBuilder builder = new DbConnectionStringBuilder()
            {
                ConnectionString = firebirdSqlConnectionString
            };
            object result = EFUtil.GetUserId(builder);

            Assert.AreEqual("SYSDBA", result.ToString());
        }
Пример #5
0
        public void Test_Get_UserId_PostgreSql()
        {
            DbConnectionStringBuilder builder = new DbConnectionStringBuilder()
            {
                ConnectionString = postgreSqlConnectionString
            };
            object result = EFUtil.GetUserId(builder);

            Assert.AreEqual("postgres", result.ToString());
        }
Пример #6
0
        public void Test_Get_UserId_Sqlite()
        {
            DbConnectionStringBuilder builder = new DbConnectionStringBuilder()
            {
                ConnectionString = sqliteConnectionString
            };
            object result = EFUtil.GetUserId(builder);

            Assert.IsNull(result);
        }
Пример #7
0
        public void Test_Get_UserId_SqlServer()
        {
            DbConnectionStringBuilder builder = new DbConnectionStringBuilder()
            {
                ConnectionString = sqlServerConnectionString
            };
            object result = EFUtil.GetUserId(builder);

            Assert.AreEqual("myUsername", result.ToString());
        }
Пример #8
0
 public void TestarConexaoBD()
 {
     try
     {
         EFUtil.TestarConexaoBD();
     }
     catch (Exception ex)
     {
         LoggerUtil.ErrorLog(ex.Message, ex);
         throw ex;
     }
 }
Пример #9
0
        public List <GastosTO> SelectAll(FiltroTelaTO filtroGastos)
        {
            using (var contexto = new Context())
            {
                StringBuilder sqlQuery = new StringBuilder();

                sqlQuery.Append(@"SELECT 
	                                    g.data,
	                                    g.id_gastos,
                                        g.id_tipo_gastos,
	                                    g.local,
	                                    g.valor,
                                        t.tipo TIPO
                                    FROM gastos g
                                    JOIN tipo_gastos t ON t.id_tipo_gastos = g.id_tipo_gastos
                                    WHERE 1 = 1 ");

                List <MySqlParameter> parametros = new List <MySqlParameter>();

                if (filtroGastos.DataInicio != null)
                {
                    sqlQuery.AppendFormat(" AND g.data >= {0}", filtroGastos.DataInicio.ToString("yyyyMMdd"));
                }

                if (filtroGastos.DataFim != null)
                {
                    sqlQuery.AppendFormat(" AND g.data <= {0}", filtroGastos.DataFim.ToString("yyyyMMdd"));
                }

                if (filtroGastos.IdTipoGasto > 0)
                {
                    sqlQuery.AppendFormat(" AND g.id_tipo_gastos = {0}", filtroGastos.IdTipoGasto);
                }

                if (!String.IsNullOrEmpty(filtroGastos.Local))
                {
                    sqlQuery.AppendFormat(" AND g.local like '%{0}%'", filtroGastos.Local);
                }

                try
                {
                    var retorno = EFUtil.ExecuteSql <GastosTO>(sqlQuery.ToString()).ToList();
                    return(retorno);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }
Пример #10
0
        public void Save(List <T> listaObjetoModel)
        {
            //Inserir
            if (listaObjetoModel.FindAll(x => x.StatusBD == StatusTransacao.Insert).Count > 0)
            {
                EFUtil.Insert(listaObjetoModel.FindAll(x => x.StatusBD == StatusTransacao.Insert));
            }

            //Alterar
            if (listaObjetoModel.FindAll(x => x.StatusBD == StatusTransacao.Update).Count > 0)
            {
                EFUtil.Update(listaObjetoModel.FindAll(x => x.StatusBD == StatusTransacao.Update));
            }

            //Deletar
            if (listaObjetoModel.FindAll(x => x.StatusBD == StatusTransacao.Delete).Count > 0)
            {
                EFUtil.Delete(listaObjetoModel.FindAll(x => x.StatusBD == StatusTransacao.Delete));
            }
        }
Пример #11
0
        public List <TipoGastosTO> SelectAll(FiltroTelaTO filtroTela)
        {
            using (var contexto = new Context())
            {
                StringBuilder sqlQuery = new StringBuilder();

                sqlQuery.Append(@"SELECT 
                                    t.id_tipo_gastos,
                                    t.tipo,
                                    t.excluido
                                  FROM tipo_gastos t
                                  WHERE 1 = 1 ");

                if (filtroTela.IdTipoGasto > 0)
                {
                    sqlQuery.AppendFormat(" AND t.id_tipo_gastos = {0} ", filtroTela.IdTipoGasto);
                }

                if (!String.IsNullOrEmpty(filtroTela.TipoGasto))
                {
                    sqlQuery.AppendFormat(" AND t.tipo LIKE '%{0}%' ", filtroTela.TipoGasto);
                }

                if (filtroTela.Excluido == 1)
                {
                    sqlQuery.Append(" AND IFNULL(t.excluido, false) = true ");
                }

                try
                {
                    var retorno = EFUtil.ExecuteSql <TipoGastosTO>(sqlQuery.ToString()).ToList();
                    return(retorno);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }
Пример #12
0
        public async Task <IActionResult> IgnoreReports([FromBody] List <long> reportIds)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            var previousIgnoredReports = await CurrentSets.IgnoredReport.Where(r => reportIds.Contains(r.ReportId)).Select(r => r.ReportId).ToListAsync();

            var previousReports = await CurrentSets.Report.Where(r => reportIds.Contains(r.ReportId)).Select(r => r.ReportId).ToListAsync();

            var reportsToIgnore = reportIds
                                  .Except(previousIgnoredReports)
                                  .Except(previousReports);

            foreach (var id in reportsToIgnore)
            {
                var newRecord = new Scaffold.IgnoredReport
                {
                    ReportId      = id,
                    WorldId       = CurrentWorldId,
                    AccessGroupId = CurrentAccessGroupId
                };

                context.Add(newRecord);
            }

            await context.SaveChangesAsync();

            var history = await EFUtil.GetOrCreateUserUploadHistory(context, CurrentUserId);

            history.LastUploadedReportsAt = CurrentServerTime;
            await context.SaveChangesAsync();

            return(Ok());
        }
Пример #13
0
        public async Task<IActionResult> PostCurrentArmy([FromBody]JSON.PlayerArmy currentArmySetJson)
        {
            if (!ModelState.IsValid)
                return ValidationProblem(ModelState);

            if (currentArmySetJson.TroopData.Count == 0)
                return Ok();

            var villageIds = currentArmySetJson.TroopData.Select(a => a.VillageId.Value).ToList();

            var scaffoldCurrentVillages = await Profile("Get existing scaffold current villages", () => (
                from cv in CurrentSets.CurrentVillage
                                        .Include(v => v.ArmyOwned)
                                        .Include(v => v.ArmyAtHome)
                                        .Include(v => v.ArmyStationed)
                                        .Include(v => v.ArmySupporting)
                                        .Include(v => v.ArmyTraveling)
                where villageIds.Contains(cv.VillageId)
                select cv
            ).ToListAsync());

            var villagesWithPlayerIds = await Profile("Get village player IDs", () => (
                from v in CurrentSets.Village
                where villageIds.Contains(v.VillageId)
                select new { v.PlayerId, v.VillageId }
            ).ToListAsync());

            var villageIdsByPlayerId = villagesWithPlayerIds.ToDictionary(v => v.VillageId, v => v.PlayerId);

            var mappedScaffoldVillages = villageIds.ToDictionary(id => id, id => scaffoldCurrentVillages.SingleOrDefault(cv => cv.VillageId == id));
            var missingScaffoldVillageIds = mappedScaffoldVillages.Where(kvp => kvp.Value == null).Select(kvp => kvp.Key).ToList();

            var missingVillageData = mappedScaffoldVillages.Values.Count(v => v == null) == 0
                ? new List<Scaffold.Village>()
                : await Profile("Get missing village data", () => (
                        from v in CurrentSets.Village
                        where missingScaffoldVillageIds.Contains(v.VillageId)
                        select v
                    ).ToListAsync()
                );

            var mappedMissingVillageData = missingVillageData.ToDictionary(vd => vd.VillageId, vd => vd);

            //  Get or make CurrentVillage

            Profile("Populating missing village data", () =>
            {
                foreach (var missingVillageId in missingScaffoldVillageIds)
                {
                    var village = mappedMissingVillageData[missingVillageId];
                    var newCurrentVillage = new Scaffold.CurrentVillage();
                    newCurrentVillage.VillageId = missingVillageId;
                    newCurrentVillage.WorldId = CurrentWorldId;
                    newCurrentVillage.AccessGroupId = CurrentAccessGroupId;

                    context.CurrentVillage.Add(newCurrentVillage);

                    mappedScaffoldVillages[missingVillageId] = newCurrentVillage;
                }
            });

            Profile("Generate scaffold armies", () =>
            {
                foreach (var armySetJson in currentArmySetJson.TroopData)
                {
                    var currentVillage = mappedScaffoldVillages[armySetJson.VillageId.Value];
                    var villagePlayerId = villageIdsByPlayerId[currentVillage.VillageId];

                    if (!Configuration.Security.AllowUploadArmyForNonOwner
                            && villagePlayerId != CurrentPlayerId)
                    {
                        context.InvalidDataRecord.Add(MakeInvalidDataRecord(
                            JsonConvert.SerializeObject(currentArmySetJson),
                            $"Attempted to upload current army to village {villagePlayerId} but that village is not owned by the requestor"
                        ));
                    }

                    var fullArmy = armySetJson.AtHome + armySetJson.Traveling + armySetJson.Supporting;
                    currentVillage.ArmyOwned = ArmyConvert.JsonToArmy(fullArmy, CurrentWorldId, currentVillage.ArmyOwned, context, emptyIfNull: true);
                    currentVillage.ArmyStationed = ArmyConvert.JsonToArmy(armySetJson.Stationed, CurrentWorldId, currentVillage.ArmyStationed, context, emptyIfNull: true);
                    currentVillage.ArmyTraveling = ArmyConvert.JsonToArmy(armySetJson.Traveling, CurrentWorldId, currentVillage.ArmyTraveling, context, emptyIfNull: true);
                    currentVillage.ArmyAtHome = ArmyConvert.JsonToArmy(armySetJson.AtHome, CurrentWorldId, currentVillage.ArmyAtHome, context, emptyIfNull: true);
                    currentVillage.ArmySupporting = ArmyConvert.JsonToArmy(armySetJson.Supporting, CurrentWorldId, currentVillage.ArmySupporting, context, emptyIfNull: true);


                    currentVillage.ArmyOwned.LastUpdated = CurrentServerTime;
                    currentVillage.ArmyStationed.LastUpdated = CurrentServerTime;
                    currentVillage.ArmyTraveling.LastUpdated = CurrentServerTime;
                    currentVillage.ArmyAtHome.LastUpdated = CurrentServerTime;
                    currentVillage.ArmySupporting.LastUpdated = CurrentServerTime;
                }
            });

            var currentPlayer = await EFUtil.GetOrCreateCurrentPlayer(context, CurrentPlayerId, CurrentWorldId, CurrentAccessGroupId);
            currentPlayer.CurrentPossibleNobles = currentArmySetJson.PossibleNobles;

            await Profile("Save changes", () => context.SaveChangesAsync());

            //  Run upload history update in separate query to prevent creating multiple history
            //  entries
            var userUploadHistory = await EFUtil.GetOrCreateUserUploadHistory(context, CurrentUserId);
            userUploadHistory.LastUploadedTroopsAt = CurrentServerTime;
            await context.SaveChangesAsync();

            return Ok();
        }
Пример #14
0
 /// <summary>
 /// 获取缓存对象的键,返回诸如 EH_DeviceInfo:7335 之类的字符串;
 /// </summary>
 /// <returns></returns>
 public virtual string GetKey()
 {
     return(EFUtil.GetCacheKey(this.GetType(), this.Id.ToString()));
 }
Пример #15
0
        public async Task <IActionResult> Post([FromBody] JSON.Report jsonReport)
        {
            if (ModelState.IsValid)
            {
                if (!Configuration.Security.ReportIgnoreExpectedPopulationBounds &&
                    !ArmyValidate.MeetsPopulationRestrictions(jsonReport.AttackingArmy))
                {
                    context.InvalidDataRecord.Add(MakeInvalidDataRecord(
                                                      JsonConvert.SerializeObject(jsonReport),
                                                      "Troops in attacking army exceed possible village population"
                                                      ));
                    return(BadRequest());
                }

                if (!Configuration.Security.ReportIgnoreExpectedPopulationBounds &&
                    !ArmyValidate.MeetsPopulationRestrictions(jsonReport.TravelingTroops))
                {
                    context.InvalidDataRecord.Add(MakeInvalidDataRecord(
                                                      JsonConvert.SerializeObject(jsonReport),
                                                      "Troops in traveling army exceed possible village population"
                                                      ));
                }

                if (jsonReport.OccurredAt.Value > CurrentServerTime)
                {
                    context.InvalidDataRecord.Add(MakeInvalidDataRecord(
                                                      JsonConvert.SerializeObject(jsonReport),
                                                      "The report 'OccurredAt' is in the future"
                                                      ));
                    //  Return 200/OK to trick malicious actors
                    return(Ok());
                }

                bool isDuplicate    = false;
                var  scaffoldReport = await Profile("Find existing report by ID", () => (
                                                        from report in CurrentSets.Report.IncludeReportData()
                                                        where report.ReportId == jsonReport.ReportId.Value
                                                        select report
                                                        ).FirstOrDefaultAsync()
                                                    );

                if (scaffoldReport == null)
                {
                    await Profile("Find existing report by contents", async() =>
                    {
                        var reportsMatchingDetails = await(
                            from report in CurrentSets.Report.IncludeReportData()
                            where report.OccuredAt == jsonReport.OccurredAt
                            where report.AttackerPlayerId == jsonReport.AttackingPlayerId
                            where report.AttackerVillageId == jsonReport.AttackingVillageId
                            where report.DefenderPlayerId == jsonReport.DefendingPlayerId
                            where report.DefenderVillageId == jsonReport.DefendingVillageId
                            select report
                            ).ToListAsync();

                        var existingDuplicate = reportsMatchingDetails.FirstOrDefault((r) =>
                                                                                      jsonReport.AttackingArmy == r.AttackerArmy &&
                                                                                      jsonReport.DefendingArmy == r.DefenderArmy &&
                                                                                      jsonReport.AttackingArmyLosses == r.AttackerLossesArmy &&
                                                                                      jsonReport.DefendingArmyLosses == r.DefenderLossesArmy &&
                                                                                      jsonReport.TravelingTroops == r.DefenderTravelingArmy
                                                                                      );

                        isDuplicate = existingDuplicate != null;
                    });
                }

                var tx = BuildTransaction();
                context.Transaction.Add(tx);

                if (isDuplicate)
                {
                    var isIgnored = await context.IgnoredReport.AnyAsync(r => r.ReportId == jsonReport.ReportId.Value);

                    if (!isIgnored)
                    {
                        context.IgnoredReport.Add(new IgnoredReport
                        {
                            AccessGroupId = CurrentAccessGroupId,
                            ReportId      = jsonReport.ReportId.Value,
                            WorldId       = CurrentWorldId
                        });
                    }
                }
                else
                {
                    Profile("Populate scaffold report", () =>
                    {
                        if (scaffoldReport == null)
                        {
                            scaffoldReport               = new Scaffold.Report();
                            scaffoldReport.WorldId       = CurrentWorldId;
                            scaffoldReport.AccessGroupId = CurrentAccessGroupId;
                            context.Report.Add(scaffoldReport);
                        }
                        else
                        {
                            var existingJsonReport = ReportConvert.ModelToJson(scaffoldReport);

                            if (existingJsonReport != jsonReport && scaffoldReport.TxId.HasValue)
                            {
                                context.ConflictingDataRecord.Add(new Scaffold.ConflictingDataRecord
                                {
                                    ConflictingTx = tx,
                                    OldTxId       = scaffoldReport.TxId.Value
                                });
                            }
                        }

                        jsonReport.ToModel(CurrentWorldId, scaffoldReport, context);

                        scaffoldReport.Tx = tx;
                    });

                    if (jsonReport.AttackingPlayerId != null)
                    {
                        await Profile("Update command troop type", async() =>
                        {
                            var lostAllTroops = jsonReport.AttackingArmy == jsonReport.AttackingArmyLosses;

                            var command = await Model.UtilQuery.FindCommandForReport(scaffoldReport, context);

                            if (command == null && !lostAllTroops && (jsonReport.Loyalty == null || jsonReport.Loyalty > 0))
                            {
                                //  WARNING - This will auto-generate a command with a random ID,
                                //      if a new TW command is uploaded with the given ID any backtime
                                //      calculations for this old command will get screwy
                                try
                                {
                                    await context.SaveChangesAsync();
                                }
                                catch (Exception e)
                                {
                                    throw e;
                                }

                                command                 = new Scaffold.Command();
                                command.Tx              = tx;
                                command.WorldId         = CurrentWorldId;
                                command.AccessGroupId   = CurrentAccessGroupId;
                                command.IsReturning     = true;
                                command.FirstSeenAt     = CurrentServerTime;
                                command.IsAttack        = true;
                                command.SourcePlayerId  = jsonReport.AttackingPlayerId.Value;
                                command.TargetPlayerId  = jsonReport.DefendingPlayerId;
                                command.SourceVillageId = jsonReport.AttackingVillageId.Value;
                                command.TargetVillageId = jsonReport.DefendingVillageId.Value;
                                command.LandsAt         = jsonReport.OccurredAt.Value;

                                bool madeCommand = false;

                                //  Need to auto-generate a random command ID
                                while (!madeCommand)
                                {
                                    try
                                    {
                                        command.CommandId = Random.NextLong >> 14;
                                        context.Add(command);
                                        await context.SaveChangesAsync();
                                        madeCommand = true;
                                    }
                                    catch (Exception) { }
                                }
                            }

                            if (command != null)
                            {
                                JSON.TroopType?slowestType = null;
                                float slowestSpeed         = -1;
                                foreach (var troopType in jsonReport.AttackingArmy.Where(kvp => kvp.Value > 0).Select(kvp => kvp.Key))
                                {
                                    var travelSpeed = Native.ArmyStats.TravelSpeed[troopType];
                                    if (slowestType == null)
                                    {
                                        slowestType  = troopType;
                                        slowestSpeed = travelSpeed;
                                    }
                                    else if (travelSpeed > slowestSpeed)
                                    {
                                        slowestType  = troopType;
                                        slowestSpeed = travelSpeed;
                                    }
                                }

                                var attackingVillage = await CurrentSets.Village
                                                       .FromWorld(CurrentWorldId)
                                                       .Where(v => v.VillageId == jsonReport.AttackingVillageId)
                                                       .FirstOrDefaultAsync();

                                var defendingVillage = await CurrentSets.Village
                                                       .FromWorld(CurrentWorldId)
                                                       .Where(v => v.VillageId == jsonReport.DefendingVillageId)
                                                       .FirstOrDefaultAsync();

                                var travelCalculator = new Features.Simulation.TravelCalculator(CurrentWorldSettings.GameSpeed, CurrentWorldSettings.UnitSpeed);
                                var travelTime       = travelCalculator.CalculateTravelTime(slowestType.Value, attackingVillage, defendingVillage);

                                command.TroopType = slowestType.Value.ToTroopString();

                                command.Army = ArmyConvert.JsonToArmy(jsonReport.AttackingArmy - jsonReport.AttackingArmyLosses, CurrentWorldId, command.Army, context);
                                if (command.Army != null)
                                {
                                    command.Army.WorldId = CurrentWorldId;
                                }
                                command.ReturnsAt   = scaffoldReport.OccuredAt + travelTime;
                                command.IsReturning = true;
                            }
                        });
                    }
                }

                //if (jsonReport.Loyalty <= 0)
                //{
                //    var conquer = new Scaffold.Conquer
                //    {
                //        WorldId = CurrentWorldId,
                //        OldOwner = jsonReport.DefendingPlayerId,
                //        NewOwner = jsonReport.AttackingPlayerId,
                //        VillageId = jsonReport.DefendingVillageId,
                //        UnixTimestamp = new DateTimeOffset(jsonReport.OccurredAt.Value).ToUnixTimeSeconds()
                //    };

                //    context.Add(conquer);
                //}

                await Profile("Save changes", () => context.SaveChangesAsync());

                //  Run upload history update in separate query to prevent creating multiple history
                //  entries
                var userUploadHistory = await EFUtil.GetOrCreateUserUploadHistory(context, CurrentUserId);

                userUploadHistory.LastUploadedReportsAt = CurrentServerTime;
                await context.SaveChangesAsync();

                return(Ok());
            }
            else
            {
                return(BadRequest(ModelState));
            }
        }
Пример #16
0
        public async Task <IActionResult> Post([FromBody] JSON.ManyCommands jsonCommands)
        {
            if (ModelState.IsValid)
            {
                var mappedCommands = jsonCommands.Commands.ToDictionary(c => c.CommandId, c => c);
                var commandIds     = jsonCommands.Commands.Select(c => c.CommandId).ToList();

                var allVillageIds = jsonCommands.Commands
                                    .Select(c => c.SourceVillageId)
                                    .Concat(jsonCommands.Commands.Select(c => c.TargetVillageId))
                                    .Select(id => id.Value)
                                    .Distinct();

                var allCurrentVillageIds = await CurrentSets.CurrentVillage.Where(v => allVillageIds.Contains(v.VillageId)).Select(v => v.VillageId).ToListAsync();

                var allVillagesMissingCurrentEntries = allVillageIds.Except(allCurrentVillageIds).ToList();
                if (allVillagesMissingCurrentEntries.Count > 0)
                {
                    foreach (var id in allVillagesMissingCurrentEntries)
                    {
                        context.Add(new CurrentVillage
                        {
                            VillageId     = id,
                            AccessGroupId = CurrentAccessGroupId,
                            WorldId       = CurrentWorldId
                        });
                    }

                    await context.SaveChangesAsync();
                }

                var villageIdsFromCommandsMissingTroopType = jsonCommands.Commands
                                                             .Where(c => c.TroopType == null)
                                                             .SelectMany(c => new[] { c.SourceVillageId, c.TargetVillageId })
                                                             .Distinct()
                                                             .ToList();

                var scaffoldCommands = await Profile("Get existing commands", () => (
                                                         from command in CurrentSets.Command.IncludeCommandData()
                                                         where commandIds.Contains(command.CommandId)
                                                         select command
                                                         ).ToListAsync());

                var villageIdsFromCommandsMissingTroopTypes = await Profile("Get villages for commands missing troop type", () => (
                                                                                from village in CurrentSets.Village
                                                                                where villageIdsFromCommandsMissingTroopType.Contains(village.VillageId)
                                                                                select village
                                                                                ).ToListAsync());

                var allVillages = await Profile("Get all relevant villages", () => (
                                                    from village in CurrentSets.Village
                                                    where allVillageIds.Contains(village.VillageId)
                                                    select village
                                                    ).ToListAsync());

                var mappedScaffoldCommands = scaffoldCommands.ToDictionary(c => c.CommandId, c => c);
                var villagesById           = allVillages.ToDictionary(v => v.VillageId, v => v);

                var tx = BuildTransaction();
                context.Transaction.Add(tx);

                Profile("Generate scaffold commands", () =>
                {
                    foreach (var jsonCommand in jsonCommands.Commands)
                    {
                        if (!Configuration.Security.AllowCommandArrivalBeforeServerTime &&
                            jsonCommand.LandsAt.HasValue &&
                            jsonCommand.LandsAt.Value < CurrentServerTime)
                        {
                            context.InvalidDataRecord.Add(MakeInvalidDataRecord(
                                                              JsonConvert.SerializeObject(jsonCommand),
                                                              "Command.landsAt is earlier than current server time"
                                                              ));
                            continue;
                        }

                        if (!Configuration.Security.ReportIgnoreExpectedPopulationBounds &&
                            !ArmyValidate.MeetsPopulationRestrictions(jsonCommand.Troops))
                        {
                            context.InvalidDataRecord.Add(MakeInvalidDataRecord(
                                                              JsonConvert.SerializeObject(jsonCommand),
                                                              "Troops in command exceed possible village population"
                                                              ));
                            continue;
                        }

                        var scaffoldCommand = mappedScaffoldCommands.GetValueOrDefault(jsonCommand.CommandId.Value);
                        //  Don't process/update commands that are already "complete" (have proper army data attached to them)
                        if (scaffoldCommand?.Army != null)
                        {
                            continue;
                        }

                        var travelCalculator = new Features.Simulation.TravelCalculator(CurrentWorldSettings.GameSpeed, CurrentWorldSettings.UnitSpeed);
                        var timeRemaining    = jsonCommand.LandsAt.Value - CurrentServerTime;
                        var sourceVillage    = villagesById[jsonCommand.SourceVillageId.Value];
                        var targetVillage    = villagesById[jsonCommand.TargetVillageId.Value];
                        var estimatedType    = travelCalculator.EstimateTroopType(timeRemaining, sourceVillage, targetVillage);

                        if (jsonCommand.TroopType == null)
                        {
                            jsonCommand.TroopType = estimatedType;
                        }
                        else
                        {
                            var estimatedTravelSpeed = Native.ArmyStats.TravelSpeed[estimatedType];
                            var reportedTravelSpeed  = Native.ArmyStats.TravelSpeed[jsonCommand.TroopType.Value];

                            //  ie if command is tagged as "spy" but travel speed is effective for
                            //  rams
                            if (estimatedTravelSpeed > reportedTravelSpeed)
                            {
                                jsonCommand.TroopType = estimatedType;
                            }
                        }

                        if (scaffoldCommand == null)
                        {
                            scaffoldCommand               = new Scaffold.Command();
                            scaffoldCommand.World         = CurrentWorld;
                            scaffoldCommand.AccessGroupId = CurrentAccessGroupId;
                            jsonCommand.ToModel(CurrentWorldId, CurrentAccessGroupId, scaffoldCommand, CurrentServerTime, context);
                            context.Command.Add(scaffoldCommand);
                        }
                        else
                        {
                            var existingJsonCommand = CommandConvert.ModelToJson(scaffoldCommand);
                            if (existingJsonCommand.IsReturning == jsonCommand.IsReturning && existingJsonCommand != jsonCommand)
                            {
                                context.ConflictingDataRecord.Add(new Scaffold.ConflictingDataRecord
                                {
                                    OldTxId       = scaffoldCommand.TxId.Value,
                                    ConflictingTx = tx
                                });
                            }

                            jsonCommand.ToModel(CurrentWorldId, CurrentAccessGroupId, scaffoldCommand, CurrentServerTime, context);
                        }

                        if (String.IsNullOrWhiteSpace(scaffoldCommand.UserLabel) || scaffoldCommand.UserLabel == "Attack")
                        {
                            scaffoldCommand.UserLabel = scaffoldCommand.TroopType.Capitalized();
                        }

                        if (jsonCommand.TroopType != null)
                        {
                            var travelTime            = travelCalculator.CalculateTravelTime(jsonCommand.TroopType.Value, sourceVillage, targetVillage);
                            scaffoldCommand.ReturnsAt = scaffoldCommand.LandsAt + travelTime;
                        }

                        scaffoldCommand.Tx = tx;
                    }
                });

                await Profile("Save changes", () => context.SaveChangesAsync());

                //  Run upload history update in separate query to prevent creating multiple history
                //  entries
                var userUploadHistory = await EFUtil.GetOrCreateUserUploadHistory(context, CurrentUserId);

                if (jsonCommands.IsOwnCommands.Value)
                {
                    userUploadHistory.LastUploadedCommandsAt = CurrentServerTime;
                }
                else
                {
                    userUploadHistory.LastUploadedIncomingsAt = CurrentServerTime;
                }

                await context.SaveChangesAsync();

                return(Ok());
            }
            else
            {
                return(BadRequest(ModelState));
            }
        }