using ArcaneLibs.Extensions; using LibMatrix.EventTypes.Common; using LibMatrix.EventTypes.Spec.State.RoomInfo; using LibMatrix.Helpers; using LibMatrix.Responses; using LibMatrix.RoomTypes; using LibMatrix.Utilities.Bot.Interfaces; namespace MiniUtils.Commands; public class MakeRoomCommand() : ICommand { public string Name => "make room"; public string[]? Aliases => ["makeroom", "create room", "createroom"]; public string Description => "Make a new room"; public bool Unlisted => false; public async Task Invoke(CommandContext ctx) { if (ctx.Args.Length == 0) { await ctx.Room.SendMessageEventAsync( new MessageBuilder() .WithTable(tb => { tb.WithTitle("~create room", 3); tb.WithRow(rb => { rb.WithCell("Argument") .WithCell("Alternatives") .WithCell("Description"); }); tb.WithRow(rb => { rb.WithCell("--alias ") .WithCell("") .WithCell("Set the room alias"); }); tb.WithRow(rb => { rb.WithCell("--avatar-url ") .WithCell("") .WithCell("Set the room avatar URL"); }); tb.WithRow(rb => { rb.WithCell("--copy-avatar [room]") .WithCell("") .WithCell("Copy the avatar from another room (or current room if unspecified)"); }); tb.WithRow(rb => { rb.WithCell("--copy-powerlevels [room]") .WithCell("") .WithCell("Copy the power levels from another room (or current room if unspecified)"); }); tb.WithRow(rb => { rb.WithCell("--invite-admin ") .WithCell("") .WithCell("Invite a user as an admin"); }); tb.WithRow(rb => { rb.WithCell("--invite ") .WithCell("") .WithCell("Invite a user"); }); tb.WithRow(rb => { rb.WithCell("--name ") .WithCell("") .WithCell("Set the room name"); }); tb.WithRow(rb => { rb.WithCell("--topic ") .WithCell("") .WithCell("Set the room topic"); }); tb.WithRow(rb => { rb.WithCell("--federate ") .WithCell("") .WithCell("Set whether the room is federatable"); }); tb.WithRow(rb => { rb.WithCell("--join-rule ") .WithCell(""" --public --invite-only --knock --restricted --knock_restricted --private """) .WithCell("Set the room join rule to public, invite-only, knock, restricted, knock-restricted or private"); }); tb.WithRow(rb => { rb.WithCell("--history-visibility ") .WithCell(""" --shared --invited --joined --world_readable """) .WithCell("Set the room history visibility to shared, invited, joined or world_readable"); }); }) .Build() ); return; } var rb = new RoomBuilder() { }; for (int i = 0; i < ctx.Args.Length; i++) { switch (ctx.Args[i]) { case "--alias": rb.AliasLocalPart = ctx.Args[++i]; break; case "--avatar-url": rb.Avatar!.Url = ctx.Args[++i]; break; case "--copy-avatar": { var room = await GetRoomByArgument(ctx, ctx.Args[i + 1]); if (room != ctx.Room) i++; rb.Avatar = await room.GetAvatarUrlAsync() ?? throw new ArgumentException($"Room {room.RoomId} does not have an avatar"); break; } case "--copy-powerlevels": { var room = await GetRoomByArgument(ctx, ctx.Args[i + 1]); if (room != ctx.Room) i++; rb.PowerLevels = await room.GetPowerLevelsAsync() ?? throw new ArgumentException($"Room {room.RoomId} does not have power levels???"); break; } case "--invite-admin": var inviteAdmin = ctx.Args[++i]; if (!inviteAdmin.StartsWith('@')) { throw new ArgumentException("Invalid user reference: " + inviteAdmin); } rb.Invites.Add(inviteAdmin, "Marked explicitly as admin to be invited"); break; case "--invite": var inviteUser = ctx.Args[++i]; if (!inviteUser.StartsWith('@')) { throw new ArgumentException("Invalid user reference: " + inviteUser); } rb.Invites.Add(inviteUser, "Marked explicitly to be invited"); break; case "--name": var nameEvt = rb.Name = new() { Name = "" }; while (i + 1 < ctx.Args.Length && !ctx.Args[i + 1].StartsWith("--")) { nameEvt.Name += (nameEvt.Name.Length > 0 ? " " : "") + ctx.Args[++i]; } break; case "--topic": var topicEvt = rb.Topic = new() { Topic = "" }; while (i + 1 < ctx.Args.Length && !ctx.Args[i + 1].StartsWith("--")) { topicEvt.Topic += (topicEvt.Topic.Length > 0 ? " " : "") + ctx.Args[++i]; } break; case "--federate": rb.IsFederatable = bool.Parse(ctx.Args[++i]); break; case "--public": case "--invite-only": case "--knock": case "--restricted": case "--knock_restricted": case "--private": rb.JoinRules.JoinRule = ctx.Args[i].Replace("--", "").ToLowerInvariant() switch { "public" => RoomJoinRulesEventContent.JoinRules.Public, "invite-only" => RoomJoinRulesEventContent.JoinRules.Invite, "knock" => RoomJoinRulesEventContent.JoinRules.Knock, "restricted" => RoomJoinRulesEventContent.JoinRules.Restricted, "knock_restricted" => RoomJoinRulesEventContent.JoinRules.KnockRestricted, "private" => RoomJoinRulesEventContent.JoinRules.Private, _ => throw new ArgumentException("Unknown join rule: " + ctx.Args[i]) }; break; case "--join-rule": if (i + 1 >= ctx.Args.Length || !ctx.Args[i + 1].StartsWith("--")) { throw new ArgumentException("Expected join rule after --join-rule"); } rb.JoinRules.JoinRule = ctx.Args[++i].ToLowerInvariant() switch { "public" => RoomJoinRulesEventContent.JoinRules.Public, "invite" => RoomJoinRulesEventContent.JoinRules.Invite, "knock" => RoomJoinRulesEventContent.JoinRules.Knock, "restricted" => RoomJoinRulesEventContent.JoinRules.Restricted, "knock_restricted" => RoomJoinRulesEventContent.JoinRules.KnockRestricted, "private" => RoomJoinRulesEventContent.JoinRules.Private, _ => throw new ArgumentException("Unknown join rule: " + ctx.Args[i]) }; break; case "--history-visibility": rb.HistoryVisibility = new RoomHistoryVisibilityEventContent { HistoryVisibility = ctx.Args[++i].ToLowerInvariant() switch { "shared" => RoomHistoryVisibilityEventContent.HistoryVisibilityTypes.Shared, "invited" => RoomHistoryVisibilityEventContent.HistoryVisibilityTypes.Invited, "joined" => RoomHistoryVisibilityEventContent.HistoryVisibilityTypes.Joined, "world_readable" => RoomHistoryVisibilityEventContent.HistoryVisibilityTypes.WorldReadable, _ => throw new ArgumentException("Unknown history visibility: " + ctx.Args[i]) } }; break; default: throw new ArgumentException("Unknown argument: " + ctx.Args[i]); } } // await ctx.Room.SendMessageEventAsync( // new MessageBuilder() // .WithCodeBlock(rb.ToJson(), "json") // .Build() // ); // var result = await ctx.Homeserver.CreateRoom(creationContent); var result = await rb.Create(ctx.Homeserver); await ctx.Room.SendMessageEventAsync(new MessageBuilder() .WithMention($"{result.RoomId}?via={ctx.Homeserver.ServerName}", rb.CanonicalAlias.Alias) .Build()); } private async Task GetRoomByArgument(CommandContext ctx, string roomReference, bool defaultToCurrent = true) { if (roomReference.StartsWith("--")) { return defaultToCurrent ? ctx.Room : throw new ArgumentException("Invalid room reference: " + roomReference); } if (roomReference.StartsWith('!')) { return ctx.Homeserver.GetRoom(roomReference); } if (roomReference.StartsWith('#')) { var resolvedAlias = await ctx.Homeserver.ResolveRoomAliasAsync(roomReference); return ctx.Homeserver.GetRoom(resolvedAlias.RoomId); } throw new ArgumentException("Invalid room reference: " + roomReference); } }