diff --git a/Migrations/20250605145513_datamemos-more-data.Designer.cs b/Migrations/20250605145513_datamemos-more-data.Designer.cs new file mode 100644 index 00000000..948f674a --- /dev/null +++ b/Migrations/20250605145513_datamemos-more-data.Designer.cs @@ -0,0 +1,389 @@ +// +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using vassago.Models; + +#nullable disable + +namespace vassago.Migrations +{ +#pragma warning disable 612, 618, 8981 + [DbContext(typeof(ChattingContext))] + [Migration("20250605145513_datamemos-more-data")] + partial class datamemosmoredata + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("ProductVersion", "7.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore"); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("AccountUAC", b => + { + b.Property("AccountInChannelsId") + .HasColumnType("uuid"); + + b.Property("UACsId") + .HasColumnType("uuid"); + + b.HasKey("AccountInChannelsId", "UACsId"); + + b.HasIndex("UACsId"); + + b.ToTable("AccountUAC"); + }); + + modelBuilder.Entity("ChannelUAC", b => + { + b.Property("ChannelsId") + .HasColumnType("uuid"); + + b.Property("UACsId") + .HasColumnType("uuid"); + + b.HasKey("ChannelsId", "UACsId"); + + b.HasIndex("UACsId"); + + b.ToTable("ChannelUAC"); + }); + + modelBuilder.Entity("UACUser", b => + { + b.Property("UACsId") + .HasColumnType("uuid"); + + b.Property("UsersId") + .HasColumnType("uuid"); + + b.HasKey("UACsId", "UsersId"); + + b.HasIndex("UsersId"); + + b.ToTable("UACUser"); + }); + + modelBuilder.Entity("vassago.Models.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("text"); + + b.Property("IsBot") + .HasColumnType("boolean"); + + b.Property("IsUserId") + .HasColumnType("uuid"); + + b.Property("Protocol") + .HasColumnType("text"); + + b.Property("SeenInChannelId") + .HasColumnType("uuid"); + + b.Property("Username") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("IsUserId"); + + b.HasIndex("SeenInChannelId"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("vassago.Models.Attachment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Content") + .HasColumnType("bytea"); + + b.Property("ContentType") + .HasColumnType("text"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("numeric(20,0)"); + + b.Property("Filename") + .HasColumnType("text"); + + b.Property("MessageId") + .HasColumnType("uuid"); + + b.Property("Size") + .HasColumnType("integer"); + + b.Property("Source") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("MessageId"); + + b.ToTable("Attachments"); + }); + + modelBuilder.Entity("vassago.Models.Channel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ChannelType") + .HasColumnType("integer"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("text"); + + b.Property("LewdnessFilterLevel") + .HasColumnType("integer"); + + b.Property("LinksAllowed") + .HasColumnType("boolean"); + + b.Property("MaxAttachmentBytes") + .HasColumnType("numeric(20,0)"); + + b.Property("MaxTextChars") + .HasColumnType("bigint"); + + b.Property("MeannessFilterLevel") + .HasColumnType("integer"); + + b.Property("ParentChannelId") + .HasColumnType("uuid"); + + b.Property("Protocol") + .HasColumnType("text"); + + b.Property("ReactionsPossible") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("ParentChannelId"); + + b.ToTable("Channels"); + }); + + modelBuilder.Entity("vassago.Models.Message", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ActedOn") + .HasColumnType("boolean"); + + b.Property("AuthorId") + .HasColumnType("uuid"); + + b.Property("ChannelId") + .HasColumnType("uuid"); + + b.Property("Content") + .HasColumnType("text"); + + b.Property("ExternalId") + .HasColumnType("text"); + + b.Property("MentionsMe") + .HasColumnType("boolean"); + + b.Property("Protocol") + .HasColumnType("text"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.HasIndex("ChannelId"); + + b.ToTable("Messages"); + }); + + modelBuilder.Entity("vassago.Models.UAC", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property>("CommandAliases") + .HasColumnType("hstore"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property>("Localization") + .HasColumnType("hstore"); + + b.Property("OwnerId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("UACs"); + }); + + modelBuilder.Entity("vassago.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("AccountUAC", b => + { + b.HasOne("vassago.Models.Account", null) + .WithMany() + .HasForeignKey("AccountInChannelsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("vassago.Models.UAC", null) + .WithMany() + .HasForeignKey("UACsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ChannelUAC", b => + { + b.HasOne("vassago.Models.Channel", null) + .WithMany() + .HasForeignKey("ChannelsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("vassago.Models.UAC", null) + .WithMany() + .HasForeignKey("UACsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("UACUser", b => + { + b.HasOne("vassago.Models.UAC", null) + .WithMany() + .HasForeignKey("UACsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("vassago.Models.User", null) + .WithMany() + .HasForeignKey("UsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("vassago.Models.Account", b => + { + b.HasOne("vassago.Models.User", "IsUser") + .WithMany("Accounts") + .HasForeignKey("IsUserId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("vassago.Models.Channel", "SeenInChannel") + .WithMany("Users") + .HasForeignKey("SeenInChannelId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("IsUser"); + + b.Navigation("SeenInChannel"); + }); + + modelBuilder.Entity("vassago.Models.Attachment", b => + { + b.HasOne("vassago.Models.Message", "Message") + .WithMany("Attachments") + .HasForeignKey("MessageId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Message"); + }); + + modelBuilder.Entity("vassago.Models.Channel", b => + { + b.HasOne("vassago.Models.Channel", "ParentChannel") + .WithMany("SubChannels") + .HasForeignKey("ParentChannelId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("ParentChannel"); + }); + + modelBuilder.Entity("vassago.Models.Message", b => + { + b.HasOne("vassago.Models.Account", "Author") + .WithMany() + .HasForeignKey("AuthorId"); + + b.HasOne("vassago.Models.Channel", "Channel") + .WithMany("Messages") + .HasForeignKey("ChannelId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("Author"); + + b.Navigation("Channel"); + }); + + modelBuilder.Entity("vassago.Models.Channel", b => + { + b.Navigation("Messages"); + + b.Navigation("SubChannels"); + + b.Navigation("Users"); + }); + + modelBuilder.Entity("vassago.Models.Message", b => + { + b.Navigation("Attachments"); + }); + + modelBuilder.Entity("vassago.Models.User", b => + { + b.Navigation("Accounts"); + }); +#pragma warning restore 612, 618, 8981 + } + } +} diff --git a/Migrations/20250605145513_datamemos-more-data.cs b/Migrations/20250605145513_datamemos-more-data.cs new file mode 100644 index 00000000..3438d7d1 --- /dev/null +++ b/Migrations/20250605145513_datamemos-more-data.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace vassago.Migrations +{ +#pragma warning disable 8981 + /// + public partial class datamemosmoredata : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn>( + name: "CommandAliases", + table: "UACs", + type: "hstore", + nullable: true); + + migrationBuilder.AddColumn>( + name: "Localization", + table: "UACs", + type: "hstore", + nullable: true); + + //NOTE for future me: migrationBuilder.SQL("SELECT localization INTO Aliases from Channels;");, but also make the rows for it. + //too lazy now, really leaning on the "this will work fine for my 0 users" + + migrationBuilder.DropColumn( + name: "Aliases", + table: "Channels"); + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn>( + name: "Aliases", + table: "Channels", + type: "hstore", + nullable: true); + + migrationBuilder.DropColumn( + name: "CommandAliases", + table: "UACs"); + + migrationBuilder.DropColumn( + name: "Localization", + table: "UACs"); + } + } +} +#pragma warning restore 8981 diff --git a/Migrations/ChattingContextModelSnapshot.cs b/Migrations/ChattingContextModelSnapshot.cs index 505991bd..2eb952f2 100644 --- a/Migrations/ChattingContextModelSnapshot.cs +++ b/Migrations/ChattingContextModelSnapshot.cs @@ -148,9 +148,6 @@ namespace vassago.Migrations .ValueGeneratedOnAdd() .HasColumnType("uuid"); - b.Property>("Aliases") - .HasColumnType("hstore"); - b.Property("ChannelType") .HasColumnType("integer"); @@ -236,12 +233,18 @@ namespace vassago.Migrations .ValueGeneratedOnAdd() .HasColumnType("uuid"); + b.Property>("CommandAliases") + .HasColumnType("hstore"); + b.Property("Description") .HasColumnType("text"); b.Property("DisplayName") .HasColumnType("text"); + b.Property>("Localization") + .HasColumnType("hstore"); + b.Property("OwnerId") .HasColumnType("uuid"); diff --git a/Models/Channel.cs b/Models/Channel.cs index 6c066511..9b89d9e4 100644 --- a/Models/Channel.cs +++ b/Models/Channel.cs @@ -36,8 +36,6 @@ public class Channel public Enumerations.LewdnessFilterLevel? LewdnessFilterLevel { get; set; } public Enumerations.MeannessFilterLevel? MeannessFilterLevel { get; set; } public List UACs { get; set; } - //both incoming and outgoing - //public Dictionary Aliases { get; set; } public DefinitePermissionSettings EffectivePermissions { diff --git a/Models/UAC.cs b/Models/UAC.cs index d7a97513..8e904e9f 100644 --- a/Models/UAC.cs +++ b/Models/UAC.cs @@ -5,6 +5,11 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using vassago.Models; + +//TODO: rename. +//"uac" originally meant "user account control". but it might just be channel control. in fact, channel-control is much more fun, +//then the platform manages the permissions for you! +//but now I'm going to add locales to it, so it's kind of... "miscellaneous attached data". Official Sticky Notes, if you will. public class UAC { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] @@ -26,4 +31,7 @@ public class UAC ///it's variably before and after compile time. shrug.emote. /// public string Description { get; set; } + + public Dictionary CommandAliases {get; set;} + public Dictionary Localization {get; set;} } diff --git a/Rememberer.cs b/Rememberer.cs index 0a02a231..ffa0f964 100644 --- a/Rememberer.cs +++ b/Rememberer.cs @@ -15,18 +15,23 @@ public static class Rememberer { dbAccessSemaphore.Wait(); channels = db.Channels.ToList(); + Console.WriteLine($"caching channels. {channels.Count} channels retrieved"); foreach (Channel ch in channels) { if (ch.ParentChannelId != null) { ch.ParentChannel = channels.FirstOrDefault(c => c.Id == ch.ParentChannelId); ch.ParentChannel.SubChannels ??= []; - ch.ParentChannel.SubChannels.Add(ch); + if (!ch.ParentChannel.SubChannels.Contains(ch)) + { + ch.ParentChannel.SubChannels.Add(ch); + } } if (ch.Messages?.Count > 0) { Console.WriteLine($"{ch.DisplayName} got {ch.Messages.Count} messages"); } + ch.SubChannels ??= []; } channelCacheDirty = false; dbAccessSemaphore.Release(); @@ -179,6 +184,8 @@ public static class Rememberer db.Channels.Remove(toForget); db.SaveChanges(); dbAccessSemaphore.Release(); + channelCacheDirty = true; + cacheChannels(); } public static void ForgetMessage(Message toForget) { @@ -211,11 +218,9 @@ public static class Rememberer } public static List ChannelsOverview() { - List toReturn; - dbAccessSemaphore.Wait(); - toReturn = [.. db.Channels.Include(u => u.SubChannels).Include(c => c.ParentChannel)]; - dbAccessSemaphore.Release(); - return toReturn; + if (channelCacheDirty) + Task.Run(() => cacheChannels()).Wait(); + return channels; } public static Account AccountDetail(Guid Id) { @@ -318,5 +323,7 @@ public static class Rememberer db.Update(toRemember); db.SaveChanges(); dbAccessSemaphore.Release(); + if (toRemember.Channels?.Count() > 0) + cacheChannels(); } } diff --git a/WebInterface/Controllers/ChannelsController.cs b/WebInterface/Controllers/ChannelsController.cs index 188d0f1a..1a3c12fd 100644 --- a/WebInterface/Controllers/ChannelsController.cs +++ b/WebInterface/Controllers/ChannelsController.cs @@ -13,32 +13,28 @@ public class ChannelsController() : Controller public IActionResult Details(Guid id) { var allChannels = Rememberer.ChannelsOverview(); - if(allChannels == null) - return Problem("Entity set '_db.Channels' is null."); - //"but adam", says the strawman, "why load *every* channel and walk your way up? surely there's a .Load command that works or something." - //eh. I checked. Not really. You could make an SQL view that recurses its way up, meh idk how. You could just eagerly load *every* related object... - //but that would take in all the messages. - //realistically I expect this will have less than 1MB of total "channels", and several GB of total messages per (text) channel. + if (allChannels == null) + return Problem("no channels."); var channel = allChannels.FirstOrDefault(u => u.Id == id); - if(channel == null) - { - return Problem("couldn't find that channle"); - } - var walker = channel; - while(walker != null) + if (channel == null) { - ViewData["breadcrumbs"] = $"{walker.DisplayName}/" + + return Problem($"couldn't find channle {id}"); + } + var walker = channel; + while (walker != null) + { + ViewData["breadcrumbs"] = $"{walker.DisplayName}/" + ViewData["breadcrumbs"]; walker = walker.ParentChannel; } var sb = new StringBuilder(); sb.Append('['); sb.Append($"{{text: \"{channel.SubChannels?.Count}\", nodes: ["); - var first=true; - foreach(var subChannel in channel.SubChannels) + var first = true; + foreach (var subChannel in channel.SubChannels) { - if(!first) + if (!first) { sb.Append(','); } @@ -46,11 +42,11 @@ public class ChannelsController() : Controller { first = false; } - sb.Append($"{{\"text\": \"{subChannel.DisplayName}\"}}"); + sb.Append($"{{\"text\": \"{subChannel.DisplayName}\"}}"); } sb.Append("]}]"); - ViewData.Add("channelsTree", sb.ToString()); + ViewData.Add("subChannelsTree", sb.ToString()); return View( new Tuple( channel, channel.EffectivePermissions.LewdnessFilterLevel, channel.EffectivePermissions.MeannessFilterLevel diff --git a/WebInterface/Controllers/HomeController.cs b/WebInterface/Controllers/HomeController.cs index 0c3ca2af..10b01372 100644 --- a/WebInterface/Controllers/HomeController.cs +++ b/WebInterface/Controllers/HomeController.cs @@ -43,7 +43,12 @@ public class HomeController : Controller { sb.Append(','); } - sb.Append($"{{\"text\": \"{uac.DisplayName}\"}}"); + var displayedName = uac.DisplayName; + if(string.IsNullOrWhiteSpace(displayedName)) + { + displayedName = $"[unnamed - {uac.Id}]"; + } + sb.Append($"{{\"text\": \"{displayedName}\"}}"); } sb.Append("]}"); } @@ -78,7 +83,7 @@ public class HomeController : Controller //type error, e is not defined //channels sb.Append(",{text: \"channels\", expanded:true, nodes: ["); - var topLevelChannels = Rememberer.ChannelsOverview().Where(x => x.ParentChannel == null); + var topLevelChannels = Rememberer.ChannelsOverview().Where(x => x.ParentChannel == null).ToList(); first = true; foreach (var topLevelChannel in topLevelChannels) { diff --git a/WebInterface/Controllers/api/UACsController.cs b/WebInterface/Controllers/api/UACsController.cs index d9b73a0b..124b4c63 100644 --- a/WebInterface/Controllers/api/UACsController.cs +++ b/WebInterface/Controllers/api/UACsController.cs @@ -8,7 +8,7 @@ namespace vassago.Controllers.api; [Route("api/[controller]")] [ApiController] -public class UACController: ControllerBase +public class UACController : ControllerBase { private readonly ILogger _logger; @@ -34,7 +34,7 @@ public class UACController: ControllerBase var uacFromDb = Rememberer.SearchUAC(uac => uac.Id == uac_guid); if (uacFromDb == null) { - var err =$"attempt to link channel for uac {uac_guid}, not found"; + var err = $"attempt to link channel for uac {uac_guid}, not found"; _logger.LogError(err); return NotFound(err); } @@ -210,4 +210,23 @@ public class UACController: ControllerBase Rememberer.RememberUAC(uacFromDb); return Ok(uacFromDb); } + [HttpPut] + [Route("CreateForChannels/{Id}")] + [Produces("application/json")] + public IActionResult CreateForChannels(Guid Id) + { + _logger.LogDebug($"made it to controller. creating for channel {Id}"); + var targetChannel = Rememberer.ChannelDetail(Id); + if (targetChannel == null) + { + return NotFound(); + } + var newUAC = new UAC() + { + Channels = [targetChannel] + }; + Rememberer.RememberUAC(newUAC); + Rememberer.RememberChannel(targetChannel); + return Ok(newUAC.Id); + } } diff --git a/WebInterface/Views/Channels/Details.cshtml b/WebInterface/Views/Channels/Details.cshtml index d218a0e8..80efad82 100644 --- a/WebInterface/Views/Channels/Details.cshtml +++ b/WebInterface/Views/Channels/Details.cshtml @@ -103,6 +103,12 @@ } + + Datamemos + +
+ + @@ -138,15 +144,49 @@ deleteModel(jsonifyChannel().Id, window.history.back); } } + function createMemo() + { + console.log("creating memo for channel.."); + createMemoFor((newMemoId) => { + window.location.href = "/UACs/Details/" + newMemoId; + }); + } function channelsTree() { - var tree = @Html.Raw(ViewData["channelsTree"]); + //TOOD: see how accountsTree does all our HTML-ification over here in HTML land? but this doesn't? we should pick one and stick with it. + var tree = @Html.Raw(ViewData["subChannelsTree"]); return tree; } + function dataMemosTree(){ + @{ + var dmsb = new StringBuilder(); + dmsb.Append("[{text: \"Data Memos\", \"expanded\":true, nodes: ["); + var firstMemo = true; + if(ThisChannel.UACs != null) foreach(var memo in ThisChannel.UACs) + { + if(!firstMemo) + dmsb.Append(','); + var effectiveDisplayName = memo.DisplayName; + if(string.IsNullOrWhiteSpace(effectiveDisplayName)) + { + effectiveDisplayName = $"[nameless] {memo.Id}"; + } + dmsb.Append($"{{text: \"{effectiveDisplayName}\"}}"); + firstMemo = false; + } + if(!firstMemo) + dmsb.Append(','); + dmsb.Append($"{{text: \"\"}}"); + dmsb.Append("]}]"); + } + var tree = @Html.Raw(dmsb.ToString()); + return tree; +} function accountsTree() { @{ var sb = new StringBuilder(); + sb.Append("[{text: \"accounts\", \"expanded\":true, nodes: ["); var first = true; foreach (var acc in ThisChannel.Users?.OrderBy(a => a?.SeenInChannel?.LineageSummary)) @@ -157,6 +197,7 @@ first=false; } sb.Append("]}]"); + } //console.log(@Html.Raw(sb.ToString())); var tree = @Html.Raw(sb.ToString()); @@ -164,6 +205,7 @@ } $('#channelsTree').bstreeview({ data: channelsTree() }); $('#accountsTree').bstreeview({ data: accountsTree() }); + $('#dataMemosTree').bstreeview({ data: dataMemosTree() }); } diff --git a/WebInterface/Views/Channels/Index.cshtml b/WebInterface/Views/Channels/Index.cshtml deleted file mode 100644 index 282eb5f3..00000000 --- a/WebInterface/Views/Channels/Index.cshtml +++ /dev/null @@ -1,42 +0,0 @@ -@model IEnumerable -@{ - ViewData["Title"] = "Channels"; -} - - - - - - - - - - - - @foreach (var item in Model) { - - - - - - - - } - -
- protocol - type - display name - - Lineage -
-
 
-
-
 
-
- @Html.DisplayFor(modelItem => item.DisplayName) - - @item.LineageSummary - - Details -
diff --git a/wwwroot/js/site.js b/wwwroot/js/site.js index 4ef597ba..e444da81 100644 --- a/wwwroot/js/site.js +++ b/wwwroot/js/site.js @@ -49,7 +49,7 @@ function deleteModel(id, callback) var components = window.location.pathname.split('/'); var type=components[1]; let result = null; - var id=components[3]; + var id=components[3]; //wait... i send it the ID then overwrite it? lmao what? TODO: fix fetch(apiUrl + 'Rememberer/' + type + '/' + id, { method: 'DELETE', headers: { @@ -71,9 +71,37 @@ function deleteModel(id, callback) console.error('Error:', error); }); } +function createMemoFor(callback) +{ + let components = window.location.pathname.split('/'); + let type=components[1]; + type = type.charAt(0).toUpperCase() + type.slice(1).toLowerCase(); + let result = null; + let id=components[3]; + console.log("createMemoFor" + type + "(" + id + ")"); + fetch(apiUrl + "UAC/CreateFor" + type + "/" + id, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + } + }) + .then(response => { + if (!response.ok) { + throw new Error('Network response was not "ok". which is not ok.'); + } + return response.json(); + }) + .then(returnedSuccessdata => { + console.log("success"); + console.log('returnedSuccessdata:', returnedSuccessdata); + if(callback !== null) { callback(returnedSuccessdata); } + }) + .catch(error => { + console.error('Error:', error); + }); +} function linkUAC_Channel(channel_guid, callback) { - var components = window.location.pathname.split('/'); var id=components[3]; let model={"uac_guid": id,