From 5ff25f397f394c9d62904aeb3e0bea224a5184fc Mon Sep 17 00:00:00 2001 From: nugroho Date: Tue, 24 Jun 2025 15:42:10 +0700 Subject: [PATCH] Working up to proker update --- APIHandler.cs | 270 ++++++++++++++++++++++++++++++++++++++------------ Partials.cs | 5 + 2 files changed, 209 insertions(+), 66 deletions(-) diff --git a/APIHandler.cs b/APIHandler.cs index b7770f0..44611de 100644 --- a/APIHandler.cs +++ b/APIHandler.cs @@ -39,72 +39,16 @@ public static partial class APIHandler { units.Run(async runner => { - if (!await runner.RequestValidated(2)) return; + if (!await runner.RequestValidated(3)) return; await runner.WriteJsonResponse(StatusCodes.Status200OK, "Success", Deployments); }); }) - .Map("/chunit", unit => - { - unit.Run(async runner => - { - if (!await runner.RequestValidated(2, "POST", true)) return; - if (await runner.TryGetBodyJsonAsync(["deplid", "unitkerja"], CTS.Token) is Dictionary InElement) - { - Deployment CorrectDeployment = new( - InElement["deplid"].GetInt16(), - InElement["unitkerja"].GetString() ?? "" - ); - if (CorrectDeployment.UnitKerja.Length < 1) - { - await runner.WriteJsonResponse(StatusCodes.Status400BadRequest, "Unit Kerja can't be empty string."); - return; - } - int i = Deployments.FindIndex(depl => depl.DeplID == CorrectDeployment.DeplID); - if (i < 0) - { - await runner.WriteJsonResponse(StatusCodes.Status404NotFound, "Deployment ID not found."); - return; - } - _ = await RunNonQueryAsync(CS, "UPDATE deployment SET unitkerja = @uk WHERE deplid = @id", Comm => - { - Comm.Parameters.AddWithValue("@id", CorrectDeployment.DeplID); - Comm.Parameters.AddWithValue("@uk", CorrectDeployment.UnitKerja); - }, CTS.Token); - Deployments[i] = CorrectDeployment; - await runner.WriteJsonResponse(StatusCodes.Status202Accepted, "Data updated.", Deployments[i]); - } - }); - }) - .Map("/addunit", unit => - { - unit.Run(async runner => - { - if (!await runner.RequestValidated(2, "POST", true)) return; - if (await runner.TryGetBodyJsonAsync(["unitkerja"], CTS.Token) is Dictionary InElement) - { - string UnitKerja = InElement["unitkerja"].GetString() ?? ""; - if (UnitKerja.Length < 1) - { - await runner.WriteJsonResponse(StatusCodes.Status400BadRequest, "Unit Kerja can't be empty string."); - return; - } - short DeplID = (short)await RunScalarAsync(CS, "INSERT INTO deployment OUTPUT INSERTED.deplid VALUES (@uk)", Comm => - { - Comm.Parameters.AddWithValue("@uk", UnitKerja); - }, CTS.Token); - Deployment Inserted = new(DeplID, UnitKerja); - Deployments.Add(Inserted); - // EventsMarker.CacheUpdates = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString("X"); - await runner.WriteJsonResponse(StatusCodes.Status201Created, "Data Created.", Inserted); - } - }); - }) - //============AGENTS============== + //=======AGENTS & USERS============ .Map("/getagents", agents => { agents.Run(async runner => { - if (!await runner.RequestValidated(2)) return; + if (!await runner.RequestValidated(3)) return; await runner.WriteJsonResponse(StatusCodes.Status200OK, "Success", Agents); }); }) @@ -216,7 +160,7 @@ public static partial class APIHandler agent.Run(async runner => { if (!await runner.RequestValidated(0, "POST", true)) return; - if (await runner.TryGetBodyJsonAsync(["agentid","photo", "updates"], CTS.Token) is Dictionary InElement) + if (await runner.TryGetBodyJsonAsync(["agentid", "photo", "updates"], CTS.Token) is Dictionary InElement) { if (InElement["updates"].ValueKind != JsonValueKind.Object) return; string AgentID = InElement["agentid"].GetString() ?? string.Empty; @@ -249,7 +193,7 @@ public static partial class APIHandler { CommandBuilder.Append($" [photourl] = @purl,"); Comm.Parameters.AddWithValue("@purl", PhotoURL); - } + } CommandBuilder.Remove(CommandBuilder.Length - 1, 1); CommandBuilder.Append(" OUTPUT INSERTED.* WHERE agentid = @pagentid"); Comm.CommandText = CommandBuilder.ToString(); @@ -298,7 +242,7 @@ public static partial class APIHandler { users.Run(async runner => { - if (!await runner.RequestValidated(2)) return; + if (!await runner.RequestValidated(3)) return; List SafeAccounts = []; foreach (User UnsafeUser in UserAccounts.Values.ToList()) { @@ -314,9 +258,9 @@ public static partial class APIHandler if ( !await runner.RequestValidated(0, "POST", true) //has to pass this before trying to get bodyjsonasync. - //Let it be for now, move the json check login into trygetjson for later projects. + //Let it be for now, move the json check login into trygetjson for later projects. || await runner.TryGetBodyJsonAsync(["username", "password"], CTS.Token) is not Dictionary InElement - // || !(await runner.RequestValidated(InElement["username"].GetString() ?? string.Empty, "POST") || await runner.RequestValidated(0, "POST")) + // || !(await runner.RequestValidated(InElement["username"].GetString() ?? string.Empty, "POST") || await runner.RequestValidated(0, "POST")) ) return; if (InElement["password"].GetString() is not string PlainPass || PlainPass.Equals(string.Empty) || InElement["username"].GetString() is not string Username || Username.Equals(string.Empty)) { @@ -342,7 +286,7 @@ public static partial class APIHandler InElement["username"].GetString() is not string Username || InElement["password"].GetString() is not string PlainPass || InElement["agentid"].GetString() is not string AgentID || - InElement["level"].GetByte() is byte Level && Level == 0 + InElement["level"].GetByte() is byte Level && Level == 0 ) { await runner.WriteJsonResponse(StatusCodes.Status400BadRequest, "String fields should not be empty and level should not be zero or less."); @@ -362,7 +306,7 @@ public static partial class APIHandler }) .Map("/toggleuser", userstate => { - userstate.Run(async runner=> + userstate.Run(async runner => { if ( @@ -385,7 +329,201 @@ public static partial class APIHandler await runner.WriteJsonResponse(StatusCodes.Status202Accepted, "User account active state updated. See data for current active state", !FoundUser.Active); }); }) + .Map("/rmagent", agent => + { + agent.Run(async runner => + { + await runner.WriteJsonResponse(StatusCodes.Status501NotImplemented, "Not yet finished."); + }); + }) + .Map("/rmuser", user => + { + user.Run(async runner => + { + await runner.WriteJsonResponse(StatusCodes.Status501NotImplemented, "Not yet finished."); + }); + }) //=========ACTIVITIES============= + .Map("/getprokers", prokers=> + { + prokers.Run(async runner => + { + if (!await runner.RequestValidated(3)) return; + List Journals = []; + if (!Auth.TryGetUser(runner, out SafeUser CurrUser)) return; + using SqlDataReader Prokers = await RunReaderAsync(CS, "SELECT * FROM [AllJournal] WHERE [ownerid] = @oi OR @oi IS NULL", Query => + { + Query.Parameters.AddWithValue("@oi", CurrUser.Level < 3 ? DBNull.Value : CurrUser.AgentID); + }, CTS.Token); + Journals = await Prokers.ToListAsync(J => new( + (string)J["prokerid"], + (string)J["ownerid"], + (byte)J["kegiatan"], + (string)J["sasaran"], + J["startday"] == DBNull.Value ? null : (byte)J["startday"], + (byte)J["startmonth"], + (short)J["year"], + (byte)J["timetarget"], + (bool)J["timeunit"], + (string)J["enttarget"], + (string)J["indicators"], + (string)J["actions"], + (string)J["submitter"], + (string)J["notes"], + (byte)J["status"], + J["document"] == DBNull.Value ? null : (string)J["document"], + (DateTime)J["timestamp"] + )); + await runner.WriteJsonResponse(StatusCodes.Status200OK, "Proker Journal Fetched.",Journals); + }); + }) + .Map("/mkproker", proker => + { + proker.Run(async runner => + { + if (!await runner.RequestValidated(3, "POST", true) || + await runner.TryGetBodyJsonAsync(["prokerid", "agentID", "kegiatan", "sasaran", "startDay", "startMonth", + "year", "timeTarget", "targetUnit", "entTarget", "indicator", + "action"], CTS.Token) is not Dictionary InElement) return; + if (InElement["prokerid"].GetString() is not string ProkerID || ProkerID.Equals(string.Empty) + || InElement["agentID"].GetString() is not string AgentID || AgentID.Equals(string.Empty) + || InElement["kegiatan"].GetByte() is byte Kegiatan && (Kegiatan < 0 || Kegiatan > 4) + || InElement["sasaran"].GetString() is not string Sasaran || Sasaran.Equals(string.Empty) + || InElement["startMonth"].GetByte() is byte StartMonth && (StartMonth < 1 || StartMonth > 12) + || InElement["year"].GetInt16() is short Year && Year < 2020 + || InElement["timeTarget"].GetByte() is byte TimeTarget && TimeTarget < 1 + || InElement["targetUnit"].GetByte() is byte targetUnit && (targetUnit < 0 || targetUnit > 1) + || InElement["entTarget"].GetString() is not string EntTarget || EntTarget.Equals(string.Empty) + || InElement["indicator"].GetString() is not string Indicator || Indicator.Equals(string.Empty) + || InElement["action"].GetString() is not string Action || Action.Equals(string.Empty)) + { + await runner.WriteJsonResponse(StatusCodes.Status400BadRequest, "Required property is of invalid format."); + return; + } + byte? StartDay = InElement["startDay"].ValueKind == JsonValueKind.Null ? null : InElement["startDay"].GetByte(); + bool TargetUnit = targetUnit == 1; + await RunTransactionAsync(CS, async (Conn, Trans) => + { + using (SqlCommand CreateProker = Conn.CreateCommand()) + { + CreateProker.Transaction = Trans; + CreateProker.CommandText = "INSERT INTO [proker] VALUES(@pkid, @agid, @kgtn, @ssrn, @stdy, @stmh, @year, @tmtg, @tmun, @entg, @indc, @actn)"; + CreateProker.Parameters.AddWithValue("@pkid", ProkerID); + CreateProker.Parameters.AddWithValue("@agid", AgentID); + CreateProker.Parameters.AddWithValue("@kgtn", Kegiatan); + CreateProker.Parameters.AddWithValue("@ssrn", Sasaran); + CreateProker.Parameters.AddWithValue("@stdy", StartDay is null ? DBNull.Value : StartDay); + CreateProker.Parameters.AddWithValue("@stmh", StartMonth); + CreateProker.Parameters.AddWithValue("@year", Year); + CreateProker.Parameters.AddWithValue("@tmtg", TimeTarget); + CreateProker.Parameters.AddWithValue("@tmun", TargetUnit); + CreateProker.Parameters.AddWithValue("@entg", EntTarget); + CreateProker.Parameters.AddWithValue("@indc", Indicator); + CreateProker.Parameters.AddWithValue("@actn", Action); + _ = await CreateProker.ExecuteNonQueryAsync(CTS.Token); + } + using SqlCommand CreateJournal = Conn.CreateCommand(); + CreateJournal.Transaction = Trans; + CreateJournal.CommandText = "INSERT INTO [proker_journal] VALUES(@pjid, @pkid, @agid, @stts, @nots, @docs, @tstp)"; + CreateJournal.Parameters.AddWithValue("@pjid", GenerateUuidV7()); + CreateJournal.Parameters.AddWithValue("@pkid", ProkerID); + CreateJournal.Parameters.AddWithValue("@agid", AgentID); + CreateJournal.Parameters.AddWithValue("@stts", 0); + CreateJournal.Parameters.AddWithValue("@nots", string.Empty); + CreateJournal.Parameters.AddWithValue("@docs", DBNull.Value); + CreateJournal.Parameters.AddWithValue("@tstp", DateTime.Now); + _ = await CreateJournal.ExecuteNonQueryAsync(CTS.Token); + }, CTS.Token); + await runner.WriteJsonResponse(StatusCodes.Status201Created, "Proker Created and Journaled."); + }); + }) + .Map("/updateproker", proker => + { + proker.Run(async runner => + { + if (!await runner.RequestValidated(3, "POST", true) || + await runner.TryGetBodyJsonAsync(["prokerid", "kegiatan", "sasaran", "startDay", "startMonth", + "year", "timeTarget", "targetUnit", "entTarget", "indicator", + "action"], CTS.Token) is not Dictionary InElement) return; + if (InElement["prokerid"].GetString() is not string ProkerID || ProkerID.Equals(string.Empty) + || InElement["kegiatan"].GetByte() is byte Kegiatan && (Kegiatan < 0 || Kegiatan > 4) + || InElement["sasaran"].GetString() is not string Sasaran || Sasaran.Equals(string.Empty) + || InElement["startMonth"].GetByte() is byte StartMonth && (StartMonth < 1 || StartMonth > 12) + || InElement["year"].GetInt16() is short Year && Year < 2020 + || InElement["timeTarget"].GetByte() is byte TimeTarget && TimeTarget < 1 + || InElement["targetUnit"].GetByte() is byte targetUnit && (targetUnit < 0 || targetUnit > 1) + || InElement["entTarget"].GetString() is not string EntTarget || EntTarget.Equals(string.Empty) + || InElement["indicator"].GetString() is not string Indicator || Indicator.Equals(string.Empty) + || InElement["action"].GetString() is not string Action || Action.Equals(string.Empty)) + { + await runner.WriteJsonResponse(StatusCodes.Status400BadRequest, "Required property is of invalid format."); + return; + } + byte? StartDay = InElement["startDay"].ValueKind == JsonValueKind.Null ? null : InElement["startDay"].GetByte(); + bool TargetUnit = targetUnit == 1; + _ = await RunNonQueryAsync(CS, "UPDATE [proker] SET [kegiatan] = @kgtn, [sasaran] = @ssrn, startday = @stdy, startmonth = @stmh, year = @year, timetarget = @tmtg, timeunit = @tmun, enttarget = @entg, indicators = @indc, actions = @actn WHERE [prokerid] = @pkid", UpdateProker => + { + UpdateProker.Parameters.AddWithValue("@pkid", ProkerID); + UpdateProker.Parameters.AddWithValue("@kgtn", Kegiatan); + UpdateProker.Parameters.AddWithValue("@ssrn", Sasaran); + UpdateProker.Parameters.AddWithValue("@stdy", StartDay is null ? DBNull.Value : StartDay); + UpdateProker.Parameters.AddWithValue("@stmh", StartMonth); + UpdateProker.Parameters.AddWithValue("@year", Year); + UpdateProker.Parameters.AddWithValue("@tmtg", TimeTarget); + UpdateProker.Parameters.AddWithValue("@tmun", TargetUnit); + UpdateProker.Parameters.AddWithValue("@entg", EntTarget); + UpdateProker.Parameters.AddWithValue("@indc", Indicator); + UpdateProker.Parameters.AddWithValue("@actn", Action); + },CTS.Token); + await runner.WriteJsonResponse(StatusCodes.Status202Accepted, "Proker Updated."); + }); + }) + .Map("/approveproker", proker => + { + proker.Run(async runner => + { + if (!await runner.RequestValidated(2, "POST", true) || + await runner.TryGetBodyJsonAsync(["agentid", "year"], CTS.Token) is not Dictionary InElement) return; + if ( + InElement["agentid"].GetString() is not string AgentID || AgentID.Equals(string.Empty) || + InElement["year"].GetInt16() is short Year && Year < 2020 + ) + { + await runner.WriteJsonResponse(StatusCodes.Status400BadRequest, "Required property is of invalid format."); + return; + } + // do inside transaction + // select proker ids first, where prokerid and year + // store in list + // insert with loops; + // _ = await RunNonQueryAsync(CS, "INSERT INTO [proker_journal] SELECT @pjid, VALUES(@pjid, @pkid, @agid, @stts, @nots, @docs, @tstp)", CreateJournal => + // { + // CreateJournal.Parameters.AddWithValue("@pjid", GenerateUuidV7()); + // CreateJournal.Parameters.AddWithValue("@pkid", ProkerID); + // CreateJournal.Parameters.AddWithValue("@agid", AgentID); + // CreateJournal.Parameters.AddWithValue("@stts", 0); + // CreateJournal.Parameters.AddWithValue("@nots", string.Empty); + // CreateJournal.Parameters.AddWithValue("@docs", DBNull.Value); + // CreateJournal.Parameters.AddWithValue("@tstp", DateTime.Now); + // },CTS.Token); + // await runner.WriteJsonResponse(StatusCodes.Status202Accepted, "Proker Updated."); + await runner.WriteJsonResponse(StatusCodes.Status501NotImplemented, "Not yet finished."); + }); + }) + .Map("/pushproker", proker => + { + proker.Run(async runner => + { + await runner.WriteJsonResponse(StatusCodes.Status501NotImplemented, "Not yet finished."); + }); + }) + .Map("/evalproker", proker=> + { + proker.Run(async runner => + { + await runner.WriteJsonResponse(StatusCodes.Status501NotImplemented, "Not yet finished."); + }); + }) ; } diff --git a/Partials.cs b/Partials.cs index f0f5fd6..938c47d 100644 --- a/Partials.cs +++ b/Partials.cs @@ -16,6 +16,9 @@ internal partial record SafeUser(string Username, string AgentID, byte Level, bo } }; internal partial record SimpleApiResponse(int Status, string Message); +internal partial record ProkerJournal(string ProkerID, string OwnerID, byte Kegiatan, string Sasaran, byte? StartDay, + byte StartMonth, short Year, byte TimeTarget, bool IsInMonth, string EntityTarget, string Indicators, string Actions, + string SubmitterID, string Notes, byte Status, string? Document, DateTime TimeStamp); internal partial record User(string Username, string AgentID, string Password, byte Level, bool Active); [JsonSerializable(typeof(Agent))] [JsonSerializable(typeof(ApiResponse))] @@ -24,6 +27,7 @@ internal partial record User(string Username, string AgentID, string Password, b [JsonSerializable(typeof(JsonElement[]))] [JsonSerializable(typeof(LoginUser))] [JsonSerializable(typeof(PasswdUser))] +[JsonSerializable(typeof(ProkerJournal))] [JsonSerializable(typeof(SafeUser))] [JsonSerializable(typeof(SimpleApiResponse))] [JsonSerializable(typeof(User))] @@ -33,6 +37,7 @@ internal partial record User(string Username, string AgentID, string Password, b //////////-------------LISTS--------------////////// [JsonSerializable(typeof(List))] [JsonSerializable(typeof(List))] +[JsonSerializable(typeof(List))] [JsonSerializable(typeof(List))] [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Default, PropertyNameCaseInsensitive = true, PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)] internal partial class SGContext : JsonSerializerContext { }