vrobot3 is a chat bot for IRC and Discord.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

297 lines
11KB

  1. //-----------------------------------------------------------------------------
  2. //
  3. // Copyright © 2016 Project Golan
  4. //
  5. // See "LICENSE" for more information.
  6. //
  7. //-----------------------------------------------------------------------------
  8. //
  9. // Logging.
  10. //
  11. //-----------------------------------------------------------------------------
  12. using System;
  13. using System.Linq;
  14. using System.Collections.Generic;
  15. using System.Threading.Tasks;
  16. delegate void HaxFn(String name, String vname);
  17. namespace ProjectGolan.Vrobot3.Modules
  18. {
  19. [BotModuleDiscord, BotModuleDisabled]
  20. public class Mod_DiscordLogger : IBotModule
  21. {
  22. public Mod_DiscordLogger(Bot bot) : base(bot)
  23. {
  24. var client = bot.getClient() as Client.ClientDiscord;
  25. client.client.ChannelCreated +=
  26. catchFunc<Discord.ChannelEventArgs>(
  27. async (_, e) =>
  28. await logMsg(e.Server, "Channel created", getChannel(e.Channel)));
  29. client.client.ChannelDestroyed +=
  30. catchFunc<Discord.ChannelEventArgs>(
  31. async (_, e) =>
  32. await logMsg(e.Server, "Channel destroyed", getChannel(e.Channel)));
  33. client.client.ChannelUpdated +=
  34. catchFunc<Discord.ChannelUpdatedEventArgs>(async (_, e) =>
  35. {
  36. var delta = getChannelDelta(e.Before, e.After);
  37. if(delta != String.Empty)
  38. await logMsg(e.Server, "Channel updated", delta);
  39. });
  40. client.client.MessageDeleted +=
  41. catchFunc<Discord.MessageEventArgs>(async (_, e) =>
  42. {
  43. if(!e.Message.User.IsBot)
  44. await verMsg(e.Server, "Message deleted", getMessage(e.Message));
  45. });
  46. client.client.MessageUpdated +=
  47. catchFunc<Discord.MessageUpdatedEventArgs>(async (_, e) =>
  48. {
  49. var delta = getMessageDelta(e.Before, e.After);
  50. if(delta != String.Empty)
  51. await verMsg(e.Server, "Message edited", delta);
  52. });
  53. client.client.UserBanned +=
  54. catchFunc<Discord.UserEventArgs>(async (_, e) =>
  55. await logMsg(e.Server, "User banned", getUser(e.User)));
  56. client.client.UserUnbanned +=
  57. catchFunc<Discord.UserEventArgs>(async (_, e) =>
  58. await logMsg(e.Server, "User unbanned", getUser(e.User)));
  59. client.client.UserJoined +=
  60. catchFunc<Discord.UserEventArgs>(async (_, e) =>
  61. await logMsg(e.Server, "User joined", getUser(e.User)));
  62. client.client.UserLeft +=
  63. catchFunc<Discord.UserEventArgs>(async (_, e) =>
  64. await logMsg(e.Server, "User removed", getUser(e.User)));
  65. client.client.UserUpdated +=
  66. catchFunc<Discord.UserUpdatedEventArgs>(async (_, e) =>
  67. {
  68. var delta = getUserDelta(e.Before, e.After);
  69. if(delta != String.Empty)
  70. await verMsg(e.Server, "User updated", delta);
  71. });
  72. postSetup();
  73. }
  74. private EventHandler<T> catchFunc<T>(EventHandler<T> fn)
  75. {
  76. return (object sender, T evt) =>
  77. {
  78. try
  79. {fn(sender, evt);}
  80. catch(System.Exception)
  81. {}
  82. };
  83. }
  84. private String yesno(bool arg) => arg ? "Yes" : "No";
  85. private String getTime(DateTime time)
  86. {
  87. var offs = TimeZoneInfo.Local.GetUtcOffset(time);
  88. return $"{time.ToShortDateString()} {time.ToLongTimeString()} " +
  89. $"UTC{offs.Hours.ToString("+#;-#;0")}:{offs.Minutes}";
  90. }
  91. private String discordEscape(String str) =>
  92. Discord.Format.Escape(str ?? String.Empty);
  93. private String getChannel(Discord.Channel channel) =>
  94. $"`Name :` {discordEscape(channel.Name)}\n" +
  95. $"`Topic :` {discordEscape(channel.Topic)}\n" +
  96. $"`Id :` `{channel.Id}`\n" +
  97. $"`Position :` `{channel.Position}`\n" +
  98. $"`Type :` {channel.Type.ToString()}";
  99. private String getUser(Discord.User user) =>
  100. $"`Username :` {discordEscape(user.Name)}\n" +
  101. $"`Nickname :` {discordEscape(user.Nickname)}\n" +
  102. $"`Id :` `{user.Id}`\n" +
  103. $"`Is Bot :` {yesno(user.IsBot)}\n" +
  104. $"`Joined At :` {getTime(user.JoinedAt)}";
  105. private String getMessage(Discord.Message msg) =>
  106. $"`Time Sent :` {getTime(msg.Timestamp)}\n" +
  107. $"`Channel :` {discordEscape(msg.Channel.Name)}\n" +
  108. $"`Id :` `{msg.Id}`\n" +
  109. $"`Content :` {msg.Text}\n" +
  110. $"\nUser info:\n{getUser(msg.User)}";
  111. private String getMessageDelta(Discord.Message bfr, Discord.Message aft)
  112. {
  113. if(bfr.Text == aft.Text) return String.Empty;
  114. return $"`Time Sent :` {getTime(aft.Timestamp)}\n" +
  115. $"`Channel :` {discordEscape(aft.Channel.Name)}\n" +
  116. $"`Id :` `{aft.Id}`\n" +
  117. $"`Old Content :` {bfr.Text}\n" +
  118. $"`New Content :` {aft.Text}\n" +
  119. $"\nUser info:\n{getUser(aft.User)}";
  120. }
  121. private String getPermDelta(Discord.ServerPermissions bfr,
  122. Discord.ServerPermissions aft)
  123. {
  124. var outp = String.Empty;
  125. if(bfr.RawValue != aft.RawValue)
  126. {
  127. outp += $"`Old Value :` `{bfr.RawValue}`\n";
  128. outp += $"`New Value :` `{aft.RawValue}`\n";
  129. HaxFn fn = (String name, String vname) => {
  130. var a = (bool)typeof(Discord.ServerPermissions)
  131. .GetProperty(vname).GetValue(bfr);
  132. var b = (bool)typeof(Discord.ServerPermissions)
  133. .GetProperty(vname).GetValue(aft);
  134. if(a != b)
  135. outp += $"`{name}:` {yesno(b)}\n";
  136. };
  137. fn("Create Invite", "CreateInstantInvite");
  138. fn("Ban Users ", "BanMembers");
  139. fn("Kick Users ", "KickMembers");
  140. fn("Edit Channels", "ManageChannels");
  141. fn("Edit Server ", "ManageServer");
  142. fn("Join Channels", "ReadMessages");
  143. fn("Send Messages", "SendMessages");
  144. fn("Send TTS ", "SendTTSMessages");
  145. fn("Edit Messages", "ManageMessages");
  146. fn("Embed Links ", "EmbedLinks");
  147. fn("Attach Files ", "AttachFiles");
  148. fn("Ping Everyone", "MentionEveryone");
  149. fn("Join Voice ", "Connect");
  150. fn("Speak ", "Speak");
  151. fn("Mute Users ", "MuteMembers");
  152. fn("Deafen Users ", "DeafenMembers");
  153. fn("Move Users ", "MoveMembers");
  154. fn("Use VA ", "UseVoiceActivation");
  155. fn("Change Nick ", "ChangeNickname");
  156. fn("Edit Nicks ", "ManageNicknames");
  157. fn("Edit Roles ", "ManageRoles");
  158. }
  159. return outp;
  160. }
  161. private String getChannelDelta(Discord.Channel bfr, Discord.Channel aft)
  162. {
  163. var outp1 = String.Empty;
  164. var outp2 = String.Empty;
  165. if(bfr.Name != aft.Name)
  166. {
  167. outp1 += "Name changed.\n";
  168. if(!String.IsNullOrEmpty(bfr.Name))
  169. outp2 += $"`Old Name :` {discordEscape(bfr.Name)}\n";
  170. if(!String.IsNullOrEmpty(aft.Name))
  171. outp2 += $"`New Name :` {discordEscape(aft.Name)}\n";
  172. }
  173. if(bfr.Id != aft.Id)
  174. {
  175. outp1 += "Id changed.\n";
  176. outp2 += $"`Old Id :` `{bfr.Id}`\n";
  177. outp2 += $"`New Id :` `{aft.Id}`\n";
  178. }
  179. if(bfr.Topic != aft.Topic)
  180. {
  181. outp1 += "Topic changed.\n";
  182. if(!String.IsNullOrEmpty(bfr.Topic))
  183. outp2 += $"`Old Topic :` {discordEscape(bfr.Topic)}\n";
  184. if(!String.IsNullOrEmpty(aft.Topic))
  185. outp2 += $"`New Topic :` {discordEscape(aft.Topic)}\n";
  186. }
  187. if(bfr.Position != aft.Position)
  188. {
  189. outp1 += "Position changed.\n";
  190. outp2 += $"`Old Position :` `{bfr.Position}`\n";
  191. outp2 += $"`New Position :` `{aft.Position}`\n";
  192. }
  193. if(outp1 != String.Empty)
  194. outp2 += $"\nChannel info:\n{getChannel(aft)}\n";
  195. return outp1 + outp2.Trim();
  196. }
  197. private String getUserDelta(Discord.User bfr, Discord.User aft)
  198. {
  199. var outp1 = String.Empty;
  200. var outp2 = String.Empty;
  201. var perm = getPermDelta(bfr.ServerPermissions, aft.ServerPermissions);
  202. if(bfr.Name != aft.Name)
  203. {
  204. outp1 += "Username changed.\n";
  205. if(!String.IsNullOrEmpty(bfr.Name))
  206. outp2 += $"`Old Username :` {discordEscape(bfr.Name)}\n";
  207. if(!String.IsNullOrEmpty(aft.Name))
  208. outp2 += $"`New Username :` {discordEscape(aft.Name)}\n";
  209. }
  210. if(bfr.Nickname != aft.Nickname)
  211. {
  212. outp1 += "Nickname changed.\n";
  213. if(!String.IsNullOrEmpty(bfr.Nickname))
  214. outp2 += $"`Old Nickname :` {discordEscape(bfr.Nickname)}\n";
  215. if(!String.IsNullOrEmpty(aft.Nickname))
  216. outp2 += $"`New Nickname :` {discordEscape(aft.Nickname)}\n";
  217. }
  218. if(bfr.AvatarId != aft.AvatarId)
  219. {
  220. outp1 += "Avatar changed.\n";
  221. outp2 += $"`Old Avatar Id:` `{bfr.AvatarId}`\n";
  222. outp2 += $"`New Avatar Id:` `{aft.AvatarId}`\n";
  223. outp2 += $"`Old AvatarUrl:` `{bfr.AvatarUrl}`\n";
  224. outp2 += $"`New AvatarUrl:` `{aft.AvatarUrl}`\n";
  225. }
  226. if(bfr.Discriminator != aft.Discriminator)
  227. {
  228. outp1 += "Unique Id changed.\n";
  229. outp2 += $"`Old Unique Id:` `{bfr.Discriminator}`\n";
  230. outp2 += $"`New Unique Id:` `{aft.Discriminator}`\n";
  231. }
  232. if(bfr.Id != aft.Id)
  233. {
  234. outp1 += "Id changed.\n";
  235. outp2 += $"`Old Id :` `{bfr.Id}`\n";
  236. outp2 += $"`New Id :` `{aft.Id}`\n";
  237. }
  238. if(!String.IsNullOrEmpty(perm))
  239. {
  240. outp1 += "Permissions changed.\n";
  241. outp2 += perm;
  242. }
  243. if(outp1 != String.Empty)
  244. outp2 += $"\nUser info:\n{getUser(aft)}\n";
  245. return outp1 + outp2.Trim();
  246. }
  247. private async Task sndMsg(Discord.Server server, String name,
  248. String type, String msg)
  249. {
  250. if(server.Id.ToString() != bot.info.serverAddr) return;
  251. var log = server.FindChannels(name).FirstOrDefault();
  252. if(log == null) return;
  253. var time = getTime(DateTime.Now);
  254. if(msg.Length > 1800)
  255. await log.SendMessage($"{type} at {time}\n[Omitted, too long]");
  256. else
  257. await log.SendMessage($"{type} at {time}\n{msg}");
  258. }
  259. private async Task logMsg(Discord.Server server, String type, String msg)
  260. => await sndMsg(server, "log", type, msg);
  261. private async Task verMsg(Discord.Server server, String type, String msg)
  262. => await sndMsg(server, "log-v", type, msg);
  263. }
  264. }