using System.Security.Cryptography.Pkcs; using System.Text.Json; using System.Text.RegularExpressions; namespace perubahan; public static partial class APIHandler { public static void Handle(IApplicationBuilder App) { App //===========TEST ONLY============ .Map("/hostcheck", host => { host.Run(async runner => { await runner.WriteJsonResponse(200, $"{runner.Request.Host} : {HttpOnly.Domain}"); }); }) .Map("/numbertest", test => { test.Run(async runner => { Dictionary ELE = (await runner.TryGetBodyJsonAsync(["num"], CTS.Token))!; await runner.WriteJsonResponse(200, $"{ELE["num"].GetByte()}"); }); }) //============MISC================= .Map("/updatecache", cache => { cache.Run(async runner => { await UpdateCache(); await runner.WriteJsonResponse(StatusCodes.Status200OK, "Cache Updated."); }); }) // -------ADD-/sse-later-------- //===========UNITS================= .Map("/getunits", units => { units.Run(async runner => { if (!await runner.RequestValidated(3)) return; await runner.WriteJsonResponse(StatusCodes.Status200OK, "Success", Deployments); }); }) //=======AGENTS & USERS============ .Map("/getagents", agents => { agents.Run(async runner => { if (!await runner.RequestValidated(3)) return; await runner.WriteJsonResponse(StatusCodes.Status200OK, "Success", Agents); }); }) .Map("/addagent", agent => { agent.Run(async runner => { if (!await runner.RequestValidated(1, "POST", true)) return; if (await runner.TryGetBodyJsonAsync(["agentid", "name", "jabatan", "deplid", "skangkat", "tmt", "skper", "tgper", "vision", "mission", "photo", "seleksi", "nilaipilih", "eviden", "dokumentasi", "createuser", "uname", "pass", "level"], CTS.Token) is Dictionary InElement) { string AgentID = InElement["agentid"].GetString() ?? string.Empty; string Name = InElement["name"].GetString() ?? string.Empty; string Jabatan = InElement["jabatan"].GetString() ?? string.Empty; short DeploymentID = InElement["deplid"].GetInt16(); string SKAngkat = InElement["skangkat"].GetString() ?? string.Empty; DateOnly TMT = DateOnly.Parse(InElement["tmt"].GetString()?[..10] ?? "1970-01-01"); string SKPer = InElement["skper"].GetString() ?? string.Empty; DateOnly? TGPer = InElement["tgper"].GetString()?.Length > 0 ? DateOnly.Parse(InElement["tgper"].GetString()![..10]) : null; string Vision = InElement["vision"].GetString() ?? "-"; string Mission = InElement["mission"].GetString() ?? "-"; string Photo = InElement["photo"].GetString() ?? string.Empty; string PhotoURL = string.Empty; string? Seleksi = InElement["seleksi"].GetString(); DateOnly? NilaiPilih = InElement["nilaipilih"].ValueKind == JsonValueKind.Null ? null : DateOnly.FromDateTime(InElement["nilaipilih"].GetDateTime()); string? Eviden = InElement["eviden"].GetString(); string? Dokumentasi = InElement["dokumentasi"].GetString(); bool CreateUser = InElement["createuser"].GetBoolean(); string UName = InElement["uname"].GetString() ?? string.Empty; string PlainPass = InElement["pass"].GetString() ?? string.Empty; byte Level = InElement["level"].GetByte(); Match PhotoMatch = Base64Regex().Match(Photo); if (AgentID.Equals(string.Empty) || Name.Equals(string.Empty) || Jabatan.Equals(string.Empty) || //DeploymentID.Equals(0) || SKAngkat.Equals(string.Empty) || TMT.Equals(DateOnly.Parse("1970-01-01")) || (!SKPer.Equals(string.Empty) && TGPer is null) || (CreateUser && UName.Equals(string.Empty)) || (CreateUser && PlainPass.Equals(string.Empty)) || (!Photo.Equals(string.Empty) && !PhotoMatch.Success) || (!await runner.RequestValidated(Level, "POST")) ) { await runner.WriteJsonResponse(StatusCodes.Status400BadRequest, "One or more input(s) are not acceptable, in an unsupported format, or an attempt to create user account of a higher level than the creator is made."); return; } if (!Photo.Equals(string.Empty)) { string Format = PhotoMatch.Groups["format"].Value.ToLowerInvariant(); string Data = PhotoMatch.Groups["data"].Value; byte[] ImageBytes = Convert.FromBase64String(Data); uint CRC32Hash = Crc32.Compute(ImageBytes); string PhotoFileName = $"{CRC32Hash:X8}.{(Format == "jpeg" ? "jpg" : Format)}"; string PhotoPath = Path.Combine(AppContext.BaseDirectory, "wwwroot/assets/images/uploads", PhotoFileName); if (!File.Exists(PhotoPath)) await File.WriteAllBytesAsync(PhotoPath, ImageBytes, CTS.Token); PhotoURL = Path.Combine("/assets/images/uploads", PhotoFileName); } Agent NewAgent = new(AgentID, Name, Jabatan, DeploymentID, SKAngkat, TMT, SKPer.Length == 0 ? null : SKPer, SKPer.Length == 0 ? null : TGPer, Vision, Mission, Photo.Length == 0 ? null : PhotoURL, Seleksi, NilaiPilih, Eviden, Dokumentasi); await RunTransactionAsync(CS, async (Conn, Trans) => { using (SqlCommand CreateAgent = Conn.CreateCommand()) { CreateAgent.Transaction = Trans; CreateAgent.CommandText = "INSERT INTO agents VALUES(@agid, @nama, @jabt, @deid, @skng, @tmt, @skpr, @tmpr, @visi, @misi, @poto, @sl, @np, @ev, @do)"; CreateAgent.Parameters.AddWithValue("@agid", AgentID); CreateAgent.Parameters.AddWithValue("@nama", Name); CreateAgent.Parameters.AddWithValue("@jabt", Jabatan); CreateAgent.Parameters.AddWithValue("@deid", DeploymentID); CreateAgent.Parameters.AddWithValue("@skng", SKAngkat); CreateAgent.Parameters.AddWithValue("@tmt", TMT); CreateAgent.Parameters.AddWithValue("@skpr", SKPer.Equals(string.Empty) ? DBNull.Value : SKPer); CreateAgent.Parameters.AddWithValue("@tmpr", SKPer.Equals(string.Empty) ? DBNull.Value : TGPer); CreateAgent.Parameters.AddWithValue("@visi", Vision); CreateAgent.Parameters.AddWithValue("@misi", Mission); CreateAgent.Parameters.AddWithValue("@poto", PhotoURL.Equals(string.Empty) ? DBNull.Value : PhotoURL); CreateAgent.Parameters.AddWithValue("@sl", string.IsNullOrEmpty(Seleksi) ? DBNull.Value : Seleksi); CreateAgent.Parameters.AddWithValue("@np", NilaiPilih is null ? DBNull.Value : NilaiPilih); CreateAgent.Parameters.AddWithValue("@ev", string.IsNullOrEmpty(Eviden) ? DBNull.Value : Eviden); CreateAgent.Parameters.AddWithValue("@do", string.IsNullOrEmpty(Dokumentasi) ? DBNull.Value : Dokumentasi); _ = await CreateAgent.ExecuteNonQueryAsync(); Agents.Add(NewAgent); } if (CreateUser) { string HashedPass = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(PlainPass))).ToLowerInvariant(); User NewUser = new(UName, AgentID, HashedPass, Level, true); using (SqlCommand CreateUser = Conn.CreateCommand()) { CreateUser.Transaction = Trans; CreateUser.CommandText = "INSERT INTO useraccounts VALUES(@unam, @pass, @agid, @levl, 1)"; CreateUser.Parameters.AddWithValue("@unam", UName); CreateUser.Parameters.AddWithValue("@pass", HashedPass); CreateUser.Parameters.AddWithValue("@agid", AgentID); CreateUser.Parameters.AddWithValue("@levl", Level); _ = await CreateUser.ExecuteNonQueryAsync(); } UserAccounts.TryAdd(UName, NewUser); } }, CTS.Token ); string OutMessage = CreateUser ? "New Agent and respective User Account created" : "New Agent created. User account creation is possible."; await runner.WriteJsonResponse(StatusCodes.Status201Created, OutMessage, CreateUser ? new SafeUser(UName, AgentID, Level, true) : NewAgent); } }); }) .Map("/chagent", agent => { 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 (InElement["updates"].ValueKind != JsonValueKind.Object) return; string AgentID = InElement["agentid"].GetString() ?? string.Empty; string Photo = InElement["photo"].GetString() ?? string.Empty; string PhotoURL = ""; Match PhotoMatch = Base64Regex().Match(Photo); if (!Photo.Equals(string.Empty)) { string Format = PhotoMatch.Groups["format"].Value.ToLowerInvariant(); string Data = PhotoMatch.Groups["data"].Value; byte[] ImageBytes = Convert.FromBase64String(Data); uint CRC32Hash = Crc32.Compute(ImageBytes); string PhotoFileName = $"{CRC32Hash:X8}.{(Format == "jpeg" ? "jpg" : Format)}"; string PhotoPath = Path.Combine(AppContext.BaseDirectory, "wwwroot/assets/images/uploads", PhotoFileName); if (!File.Exists(PhotoPath)) await File.WriteAllBytesAsync(PhotoPath, ImageBytes, CTS.Token); PhotoURL = Path.Combine("/assets/images/uploads", PhotoFileName); } JsonElement UpdateFields = InElement["updates"]; using SqlDataReader Updated = await RunReaderAsync(CS, "", Comm => { StringBuilder CommandBuilder = new(); CommandBuilder.Append("UPDATE agents SET"); foreach (JsonProperty Prop in UpdateFields.EnumerateObject()) { Comm.Parameters.AddWithValue($"@p{Prop.Name}", Prop.Value.ValueKind == JsonValueKind.Null ? DBNull.Value : Prop.Value.ValueKind == JsonValueKind.String ? Prop.Value.GetString() : Prop.Value.GetInt16()); CommandBuilder.Append($" [{Prop.Name}] = @p{Prop.Name},"); } Comm.Parameters.AddWithValue("@pagentid", AgentID); if (!string.IsNullOrEmpty(PhotoURL)) { 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(); }, CTS.Token); Agent UpAgent = (await Updated.ToListAsync(a => new ( AgentID, (string)a["name"], (string)a["jabatan"], (short)a["deplid"], (string)a["skangkat"], DateOnly.FromDateTime((DateTime)a["tmt"]), a["skperubahan"] == DBNull.Value ? null : (string)a["skperubahan"], a["tgperubahan"] == DBNull.Value ? null : DateOnly.FromDateTime((DateTime)a["tgperubahan"]), a["vision"] == DBNull.Value ? null : (string)a["vision"], a["mission"] == DBNull.Value ? null : (string)a["mission"], a["photourl"] == DBNull.Value ? null : (string)a["photourl"], a["seleksi"] == DBNull.Value ? null : (string)a["seleksi"], a["nilaipilih"] == DBNull.Value ? null : DateOnly.FromDateTime((DateTime)a["nilaipilih"]), a["eviden"] == DBNull.Value ? null : (string)a["eviden"], a["dokumentasi"] == DBNull.Value ? null : (string)a["dokumentasi"] ), CTS.Token))[0]; int AgentIdx = Agents.FindIndex(a => a.AgentID == UpAgent.AgentID); Agents[AgentIdx] = Agents[AgentIdx] with { Name = UpAgent.Name, Jabatan = UpAgent.Jabatan, DeplID = UpAgent.DeplID, SKAngkat = UpAgent.SKAngkat, TMT = UpAgent.TMT, SKPerb = UpAgent.SKPerb, TMUbah = UpAgent.TMUbah, Vision = UpAgent.Vision, Mission = UpAgent.Mission, PhotoURL = UpAgent.PhotoURL, Seleksi = UpAgent.Seleksi, NilaiPilih = UpAgent.NilaiPilih, Eviden = UpAgent.Eviden, Dokumentasi = UpAgent.Dokumentasi }; await runner.WriteJsonResponse(StatusCodes.Status202Accepted, "Data updated.", UpAgent); } }); }) .Map("/getusers", users => { users.Run(async runner => { if (!await runner.RequestValidated(3)) return; List SafeAccounts = []; foreach (User UnsafeUser in UserAccounts.Values.ToList()) { SafeAccounts.Add(SafeUser.FromUser(UnsafeUser)); } await runner.WriteJsonResponse(StatusCodes.Status200OK, "Success", SafeAccounts); }); }) .Map("/passwd", passwd => { passwd.Run(async runner => { 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. || 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")) ) return; if (InElement["password"].GetString() is not string PlainPass || PlainPass.Equals(string.Empty) || InElement["username"].GetString() is not string Username || Username.Equals(string.Empty)) { await runner.WriteJsonResponse(StatusCodes.Status400BadRequest, "Username and/or Password can't be empty"); return; } string HashedPass = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(PlainPass))).ToLowerInvariant(); _ = await RunNonQueryAsync(CS, "UPDATE useraccounts SET [pass] = @hp WHERE [uname] = @un", Act => { Act.Parameters.AddWithValue("@un", Username); Act.Parameters.AddWithValue("@hp", HashedPass); }, CTS.Token); UserAccounts[Username] = UserAccounts[Username] with { Password = HashedPass }; await runner.WriteJsonResponse(StatusCodes.Status202Accepted, "Password Updated."); }); }) .Map("/adduser", user => { user.Run(async runner => { if (!await runner.RequestValidated(ValidMethod: "POST", CheckJson: true) || await runner.TryGetBodyJsonAsync(["username", "password", "agentid", "level"], CTS.Token) is not Dictionary InElement) return; if ( 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 ) { await runner.WriteJsonResponse(StatusCodes.Status400BadRequest, "String fields should not be empty and level should not be zero or less."); return; } string HashedPass = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(PlainPass))).ToLowerInvariant(); await RunNonQueryAsync(CS, "INSERT INTO useraccounts VALUES(@un, @pw, @ai, @lv, 1)", Conf => { Conf.Parameters.AddWithValue("@un", Username); Conf.Parameters.AddWithValue("@pw", HashedPass); Conf.Parameters.AddWithValue("@ai", AgentID); Conf.Parameters.AddWithValue("@lv", Level); }, CTS.Token); UserAccounts.TryAdd(Username, new(Username, AgentID, HashedPass, Level, true)); await runner.WriteJsonResponse(StatusCodes.Status201Created, $"New user account created for Agent ID {AgentID}. Check data for created username", Username); }); }) .Map("/toggleuser", userstate => { userstate.Run(async runner => { 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. || await runner.TryGetBodyJsonAsync(["username"], CTS.Token) is not Dictionary InElement || InElement["username"].GetString() is not string Username ) return; if (UserAccounts[Username] is not User FoundUser) { await runner.WriteJsonResponse(StatusCodes.Status404NotFound, "Username not found.", Username); return; } await RunNonQueryAsync(CS, "UPDATE useraccounts SET [active] = @ac WHERE [uname]=@un", Conf => { Conf.Parameters.AddWithValue("@un", Username); Conf.Parameters.AddWithValue("@ac", !FoundUser.Active); }, CTS.Token); UserAccounts[Username] = UserAccounts[Username] with { Active = !FoundUser.Active }; 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) || !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, [year] DESC, [kegiatan] ASC, [prokerid] ASC, [prokerjid] DESC", 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["prokerjid"], (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(); DateTime Now = DateTime.Now; CreateJournal.Transaction = Trans; CreateJournal.CommandText = "INSERT INTO [proker_journal] VALUES(@pjid, @pkid, @agid, @stts, @nots, @docs, @tstp)"; CreateJournal.Parameters.AddWithValue("@pjid", GenerateUuidV7(Now)); 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", 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("/processpk", proker => { proker.Run(async runner => { 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) ) { await runner.WriteJsonResponse(StatusCodes.Status400BadRequest, "Required property is of invalid format."); return; } await RunTransactionAsync(CS, async(Conn, Trans) => { 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."); }); }) .Map("/submitpk", proker => { proker.Run(async runner => { if (!await runner.RequestValidated(3, "POST", true) || !Auth.TryGetUser(runner, out SafeUser CurrUser) || 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 values is invalid or out of allowed range."); return; } List PKIDList = []; await RunTransactionAsync(CS, async(Conn, Trans) => { 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.", PKIDList); }); }) .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."); }); }) ; } }