diff --git a/APIHandler.cs b/APIHandler.cs index 6f223ea..9d4d1df 100644 --- a/APIHandler.cs +++ b/APIHandler.cs @@ -1,3 +1,4 @@ +using System.Security.Cryptography.Pkcs; using System.Text.Json; using System.Text.RegularExpressions; @@ -350,7 +351,7 @@ public static partial class APIHandler { if (!await runner.RequestValidated(3) || !Auth.TryGetUser(runner, out SafeUser CurrUser)) return; List Journals = []; - using SqlDataReader Prokers = await RunReaderAsync(CS, "SELECT * FROM [AllJournal] WHERE [ownerid] = @oi OR @oi IS NULL ORDER BY [ownerid] ASC, [kegiatan] ASC, [prokerid] ASC, [prokerjid] DESC", Query => + using SqlDataReader Prokers = await RunReaderAsync(CS, "SELECT * FROM [AllJournal] WHERE [ownerid] = @oi OR @oi IS NULL ORDER BY [ownerid] ASC, [year] DESC, [kegiatan] ASC, [prokerid] ASC, [prokerjid] DESC", Query => { Query.Parameters.AddWithValue("@oi", CurrUser.Level < 3 ? DBNull.Value : CurrUser.AgentID); }, CTS.Token); @@ -367,6 +368,7 @@ public static partial class APIHandler (string)J["enttarget"], (string)J["indicators"], (string)J["actions"], + (string)J["prokerjid"], (string)J["submitter"], (string)J["notes"], (byte)J["status"], @@ -482,29 +484,59 @@ public static partial class APIHandler { proker.Run(async runner => { - if (!await runner.RequestValidated(2, "POST", true) || !Auth.TryGetUser(runner, out SafeUser CurrUser) || + if (!await runner.RequestValidated(2, "POST", true) || !Auth.TryGetUser(runner, out SafeUser CurrUser) || await runner.TryGetBodyJsonAsync(["agentid", "year", "newstatus", "notes"], CTS.Token) is not Dictionary InElement) return; + if (CurrUser.Level != 2) + { + await runner.WriteJsonResponse(StatusCodes.Status401Unauthorized, "Only Level 2 Users may process Proker submission."); + return; + } if ( - InElement["agentid"].GetString() is not string AgentID || AgentID.Equals(string.Empty) || - InElement["year"].GetInt16() is short Year && Year < 2020 || - InElement["newstatus"].GetByte() is byte Status && Status != 1 && Status != 3 || - InElement["notes"].GetString() is not string Notes || Notes.Equals(string.Empty) - ) + InElement["agentid"].GetString() is not string AgentID || AgentID.Equals(string.Empty) || + InElement["year"].GetInt16() is short Year && Year < 2020 || + InElement["newstatus"].GetByte() is byte Status && Status != 1 && Status != 3 || + InElement["notes"].GetString() is not string Notes || Notes.Equals(string.Empty) + ) { await runner.WriteJsonResponse(StatusCodes.Status400BadRequest, "Required property is of invalid format."); return; } - await RunNonQueryAsync(CS, "INSERT INTO [proker_journal] SELECT @pjid, [prokerid], @agid, @st, @nots, null, @tstp FROM [LatestJournal] WHERE [ownerid] = @oi AND [year] = @yr AND [status] = 2 ORDER BY [kegiatan]", Query => + await RunTransactionAsync(CS, async(Conn, Trans) => { - DateTime Now = DateTime.Now; - Query.Parameters.AddWithValue("@pjid", GenerateUuidV7(Now)); - Query.Parameters.AddWithValue("@agid", CurrUser.AgentID); - Query.Parameters.AddWithValue("@st", Status); - Query.Parameters.AddWithValue("@nots", Notes); - Query.Parameters.AddWithValue("@tstp", Now); - Query.Parameters.AddWithValue("@oi", AgentID); - Query.Parameters.AddWithValue("@yr", Year); + List PKIDList = []; + using (SqlCommand PKIDFetch = Conn.CreateCommand()) + { + PKIDFetch.Transaction = Trans; + PKIDFetch.CommandText = "SELECT [prokerid] FROM [LatestJournal] WHERE [ownerid] = @oi AND [year] = @yr AND [status] = 2 ORDER BY [kegiatan]"; + PKIDFetch.Parameters.AddWithValue("@oi", AgentID); + PKIDFetch.Parameters.AddWithValue("@yr", Year); + PKIDList = await (await PKIDFetch.ExecuteReaderAsync(CTS.Token)).ToListAsync(PKID => (string)PKID["prokerid"], CTS.Token); + } + foreach (string PKID in PKIDList) + { + DateTime Now = DateTime.Now; + using SqlCommand PJUpdate = Conn.CreateCommand(); + PJUpdate.Transaction = Trans; + PJUpdate.CommandText = "INSERT INTO [proker_journal] VALUES(@pjid, @pkid, @agid, @st, @nots, null, @tstp)"; + PJUpdate.Parameters.AddWithValue("@pjid", GenerateUuidV7(Now)); + PJUpdate.Parameters.AddWithValue("@pkid", PKID); + PJUpdate.Parameters.AddWithValue("@agid", CurrUser.AgentID); + PJUpdate.Parameters.AddWithValue("@st", Status); + PJUpdate.Parameters.AddWithValue("@nots", Notes); + PJUpdate.Parameters.AddWithValue("@tstp", Now); + } }, CTS.Token); + // await RunNonQueryAsync(CS, "INSERT INTO [proker_journal] SELECT @pjid, [prokerid], @agid, @st, @nots, null, @tstp FROM [LatestJournal] WHERE [ownerid] = @oi AND [year] = @yr AND [status] = 2 ORDER BY [kegiatan]", Query => + // { + // DateTime Now = DateTime.Now; + // Query.Parameters.AddWithValue("@pjid", GenerateUuidV7(Now)); + // Query.Parameters.AddWithValue("@agid", CurrUser.AgentID); + // Query.Parameters.AddWithValue("@st", Status); + // Query.Parameters.AddWithValue("@nots", Notes); + // Query.Parameters.AddWithValue("@tstp", Now); + // Query.Parameters.AddWithValue("@oi", AgentID); + // Query.Parameters.AddWithValue("@yr", Year); + // }, CTS.Token); await runner.WriteJsonResponse(StatusCodes.Status202Accepted, "Proker submission processed."); }); }) @@ -513,23 +545,46 @@ public static partial class APIHandler proker.Run(async runner => { if (!await runner.RequestValidated(3, "POST", true) || !Auth.TryGetUser(runner, out SafeUser CurrUser) || - await runner.TryGetBodyJsonAsync(["year"], CTS.Token) is not Dictionary InElement) return; + await runner.TryGetBodyJsonAsync(["agentid","year"], CTS.Token) is not Dictionary InElement) return; + if (CurrUser.Level != 3) + { + await runner.WriteJsonResponse(StatusCodes.Status401Unauthorized, "Only Level 3 Users may submit their own Prokers."); + 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."); + await runner.WriteJsonResponse(StatusCodes.Status400BadRequest, "Required property values is invalid or out of allowed range."); return; } - await RunNonQueryAsync(CS, "INSERT INTO [proker_journal] SELECT @pjid, [prokerid], @oi, @st, @nots, null, @tstp FROM [LatestJournal] WHERE [ownerid] = @oi AND [year] = @yr AND [status] = 0 OR [status] = 1 ORDER BY [kegiatan]", Query => + List PKIDList = []; + await RunTransactionAsync(CS, async(Conn, Trans) => { - DateTime Now = DateTime.Now; - Query.Parameters.AddWithValue("@pjid", GenerateUuidV7(Now)); - Query.Parameters.AddWithValue("@tstp", Now); - Query.Parameters.AddWithValue("@oi", CurrUser.AgentID); - Query.Parameters.AddWithValue("@yr", Year); + using (SqlCommand PKIDFetch = Conn.CreateCommand()) + { + PKIDFetch.Transaction = Trans; + PKIDFetch.CommandText = "SELECT [prokerid] FROM [LatestJournal] WHERE [ownerid] = @oi AND [year] = @yr AND [status] = 0 OR [status] = 1 ORDER BY [kegiatan]"; + PKIDFetch.Parameters.AddWithValue("@oi", AgentID); + PKIDFetch.Parameters.AddWithValue("@yr", Year); + using SqlDataReader PKRd = await PKIDFetch.ExecuteReaderAsync(CTS.Token); + PKIDList = await PKRd.ToListAsync(PKID => (string)PKID["prokerid"], CTS.Token); + } + foreach (string PKID in PKIDList) + { + DateTime Now = DateTime.Now; + using SqlCommand PJUpdate = Conn.CreateCommand(); + PJUpdate.Transaction = Trans; + PJUpdate.CommandText = "INSERT INTO [proker_journal] VALUES(@pjid, @pkid, @oi, 2, 'Pengajuan Program Kerja', null, @tstp)"; + PJUpdate.Parameters.AddWithValue("@pjid", GenerateUuidV7(Now)); + PJUpdate.Parameters.AddWithValue("@pkid", PKID); + PJUpdate.Parameters.AddWithValue("@oi", AgentID); + PJUpdate.Parameters.AddWithValue("@tstp", Now); + _ = await PJUpdate.ExecuteNonQueryAsync(CTS.Token); + } }, CTS.Token); - await runner.WriteJsonResponse(StatusCodes.Status202Accepted, "Proker draft submitted."); + await runner.WriteJsonResponse(StatusCodes.Status202Accepted, "Proker draft submitted.", PKIDList); }); }) .Map("/pushproker", proker => diff --git a/Partials.cs b/Partials.cs index 7b2c6bb..93467eb 100644 --- a/Partials.cs +++ b/Partials.cs @@ -20,7 +20,7 @@ internal partial record Proker(string ProkerID, string AgentID, byte Kegiatan, s byte StartMonth, short Year, byte TimeTarget, bool IsInMonth, string EntityTarget, string Indicators, string Actions); 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); + string JournalID, 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))]