discord_updates.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import Config from './util/config.js';
  2. import {MessageActionRow, MessageButton, MessageEmbed} from 'discord.js';
  3. import db from './database.js';
  4. import {capture_sentry_exception, gen_url, escape_markdown, recover_sql_query_data, stars_to_color} from './util/helpers.js';
  5. let guild = null;
  6. async function init(discord_client) {
  7. guild = await discord_client.guilds.fetch(Config.discord_guild_id);
  8. }
  9. // Adds the 'Linked account' role and sets the user's nickname to their in-game username
  10. async function sync_discord_info(user, sync_reason) {
  11. if (!guild) return;
  12. if (!user.discord_user_id) return;
  13. let member;
  14. try {
  15. member = await guild.members.fetch(user.discord_user_id);
  16. } catch (err) {
  17. // User left the server; we don't remove them from the database as they could re-join anytime
  18. if (err.message == 'Unknown Member') {
  19. return;
  20. }
  21. console.error(`[Discord] Failed to fetch '${user.username}' <@${user.discord_user_id}>: ${err}`);
  22. capture_sentry_exception(err);
  23. return;
  24. }
  25. try {
  26. await member.roles.add(Config.discord_linked_account_role_id);
  27. } catch (err) {
  28. console.error(`[Discord] Failed to add role to '${user.username}' <@${user.discord_user_id}>: ${err}`);
  29. capture_sentry_exception(err);
  30. }
  31. try {
  32. await member.setNickname(user.username, sync_reason);
  33. } catch (err) {
  34. console.error(`[Discord] Failed to update nickname for '${user.username}' <@${user.discord_user_id}>: ${err}`);
  35. capture_sentry_exception(err);
  36. }
  37. }
  38. async function announce_new_room(lobby) {
  39. if (!guild) return;
  40. let map_pool_info = 'All maps';
  41. if (lobby.data.map_pool == 'collection') {
  42. const name = escape_markdown(lobby.data.collection?.name || 'Untitled collection');
  43. map_pool_info = `[${name}](https://osucollector.com/collections/${lobby.data.collection_id})`;
  44. }
  45. let map_selection_info = 'Random';
  46. if (lobby.data.map_selection_algo == 'pp') {
  47. map_selection_info = 'Average player pp';
  48. } else if (lobby.data.map_selection_algo == 'elo') {
  49. map_selection_info = 'Average player elo';
  50. }
  51. let description = '';
  52. const filters = {...recover_sql_query_data(lobby.data.filter_query)}; // XXX: Cache this
  53. for (const filter of filters.filters) {
  54. const filter_name = filter.name[0].toUpperCase() + filter.name.slice(1);
  55. description += `- ${filter_name} between ${filter.min} and ${filter.max}\n`;
  56. }
  57. if (description != '') {
  58. description = 'Filters:\n' + description;
  59. }
  60. let mods_info = 'None';
  61. if (lobby.data.mod_list.length > 0) {
  62. mods_info = lobby.data.mod_list.join(', ');
  63. }
  64. if (lobby.data.freemod) {
  65. mods_info += ' (freemod)';
  66. }
  67. const fields = [
  68. {name: 'Ruleset', value: ['Standard', 'Taiko', 'Catch', 'Mania'][lobby.data.ruleset], inline: true},
  69. ];
  70. if (lobby.data.ruleset == 3) {
  71. fields.push({name: 'Keys', value: filters.key_counts.join(', '), inline: true});
  72. }
  73. fields.push({name: 'Map pool', value: map_pool_info});
  74. fields.push({name: 'Map selection', value: map_selection_info});
  75. fields.push({name: 'Mods', value: mods_info});
  76. const ann = new MessageEmbed()
  77. .setColor(stars_to_color((lobby.data.min_stars + lobby.data.max_stars) / 2))
  78. .setTitle(escape_markdown(lobby.name))
  79. .setURL(gen_url(lobby.data.ruleset, '/lobbies/'))
  80. .setAuthor({
  81. name: lobby.data.creator,
  82. iconURL: `https://a.ppy.sh/${lobby.data.creator_id}`,
  83. url: gen_url(lobby.data.ruleset, `/u/${lobby.data.creator_id}`),
  84. })
  85. .setDescription(description)
  86. .addFields(fields)
  87. .setTimestamp();
  88. const announce_channel = guild.channels.cache.get(Config.discord_room_announce_channel_id);
  89. await announce_channel.send({
  90. content: 'New lobby created:',
  91. embeds: [ann],
  92. components: [
  93. new MessageActionRow().addComponents([
  94. new MessageButton({
  95. custom_id: 'orl_get_lobby_invite_' + lobby.id,
  96. label: 'Get invite',
  97. style: 'PRIMARY',
  98. }),
  99. ]),
  100. ],
  101. });
  102. }
  103. async function update_the_one_discord_role(user_id, is_the_one) {
  104. if (!guild) return;
  105. const user = db.prepare('SELECT * FROM user WHERE user_id = ?').get(user_id);
  106. if (!user) return;
  107. if (!user.discord_user_id) return;
  108. let member;
  109. try {
  110. member = await guild.members.fetch(user.discord_user_id);
  111. } catch (err) {
  112. // User left the server; we don't remove them from the database as they could re-join anytime
  113. if (err.message == 'Unknown Member') {
  114. return;
  115. }
  116. console.error(`[Discord] Failed to fetch '${user.username}' <@${user.discord_user_id}>: ${err}`);
  117. capture_sentry_exception(err);
  118. return;
  119. }
  120. if (is_the_one) {
  121. try {
  122. await member.roles.add(Config.discord_the_one_role_id);
  123. } catch (err) {
  124. console.error(`[Discord] Failed to add The One role to '${user.username}' <@${user.discord_user_id}>: ${err}`);
  125. capture_sentry_exception(err);
  126. }
  127. } else {
  128. try {
  129. await member.roles.remove(Config.discord_the_one_role_id);
  130. } catch (err) {
  131. console.error(`[Discord] Failed to remove The One role from '${user.username}' <@${user.discord_user_id}>: ${err}`);
  132. capture_sentry_exception(err);
  133. }
  134. }
  135. }
  136. export {
  137. init,
  138. sync_discord_info,
  139. update_the_one_discord_role,
  140. announce_new_room,
  141. };