import Component from "@glimmer/component"; import { tracked } from "@glimmer/tracking"; import { action } from "@ember/object"; import { LinkTo } from "@ember/routing"; import { service } from "@ember/service"; import { htmlSafe } from "@ember/template"; import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner"; import DButton from "discourse/components/d-button"; import avatar from "discourse/helpers/avatar"; import loadingSpinner from "discourse/helpers/loading-spinner"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { clipboardCopy } from "discourse/lib/utilities"; import { i18n } from "discourse-i18n"; import AdminUser from "admin/models/admin-user"; import DMenu from "float-kit/components/d-menu"; export default class IpLookup extends Component { @service dialog; @service site; @service toasts; @tracked location; @tracked otherAccounts; @tracked loading = false; @tracked otherAccountsLoading = false; @tracked totalOthersWithSameIP; get otherAccountsToDelete() { const otherAccountsLength = this.otherAccounts?.length || 0; const totalOthers = this.totalOthersWithSameIP || 0; // can only delete up to 50 accounts at a time const total = Math.min(50, totalOthers); const visible = Math.min(50, otherAccountsLength); return Math.max(visible, total); } @action async lookup() { this.loading = true; try { if (!this.location && this.args.ip) { const loc = await ajax("/admin/users/ip-info", { data: { ip: this.args.ip }, }); this.location = loc; } if (!this.otherAccounts && this.args.ip) { this.otherAccountsLoading = true; const data = { ip: this.args.ip, exclude: this.args.userId, order: "trust_level DESC", }; const result = await ajax("/admin/users/total-others-with-same-ip", { data, }); this.totalOthersWithSameIP = result.total; const users = await AdminUser.findAll("active", data); this.otherAccounts = users; this.otherAccountsLoading = false; } } catch (error) { popupAjaxError(error); } finally { this.loading = false; } } @action async copy() { const { location } = this; let text = `IP: ${this.args.ip}`; if (location) { if (location.hostname) { text += "\n" + `${i18n("ip_lookup.hostname")}: ${location.hostname}`; } text += "\n" + i18n("ip_lookup.location"); text += location.location ? `: ${location.location}` : `: ${i18n("ip_lookup.location_not_found")}`; if (location.organization) { text += "\n" + `${i18n("ip_lookup.organisation")}: ${location.organization}`; } } try { await clipboardCopy(text.trim()); this.toasts.success({ duration: 3000, data: { message: i18n("ip_lookup.copied"), }, }); } catch (err) { popupAjaxError(err); } } @action deleteOtherAccounts() { this.dialog.yesNoConfirm({ message: i18n("ip_lookup.confirm_delete_other_accounts"), didConfirm: async () => { // reset state this.otherAccounts = null; this.otherAccountsLoading = true; this.totalOthersWithSameIP = null; try { await ajax("/admin/users/delete-others-with-same-ip.json", { type: "DELETE", data: { ip: this.args.ip, exclude: this.args.userId, order: "trust_level DESC", }, }); } catch (err) { popupAjaxError(err); } }, }); } @action onRegisterApi(api) { this.dMenu = api; } @action close() { this.dMenu.close(); } }