Punishments.vue 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. <template>
  2. <div class="admin-tab container">
  3. <page-metadata title="Admin | Punishments" />
  4. <div class="card tab-info">
  5. <div class="info-row">
  6. <h1>Punishments</h1>
  7. <p>Manage punishments or ban an IP</p>
  8. </div>
  9. </div>
  10. <advanced-table
  11. :column-default="columnDefault"
  12. :columns="columns"
  13. :filters="filters"
  14. data-action="punishments.getData"
  15. name="admin-punishments"
  16. :max-width="1200"
  17. >
  18. <template #column-options="slotProps">
  19. <div class="row-options">
  20. <button
  21. class="button is-primary icon-with-button material-icons"
  22. @click="
  23. openModal({
  24. modal: 'viewPunishment',
  25. data: { punishmentId: slotProps.item._id }
  26. })
  27. "
  28. :disabled="slotProps.item.removed"
  29. content="View Punishment"
  30. v-tippy
  31. >
  32. open_in_full
  33. </button>
  34. </div>
  35. </template>
  36. <template #column-status="slotProps">
  37. <span>{{ slotProps.item.status }}</span>
  38. </template>
  39. <template #column-type="slotProps">
  40. <span
  41. :title="
  42. slotProps.item.type === 'banUserId'
  43. ? 'User ID'
  44. : 'IP Address'
  45. "
  46. >{{
  47. slotProps.item.type === "banUserId"
  48. ? "User ID"
  49. : "IP Address"
  50. }}</span
  51. >
  52. </template>
  53. <template #column-value="slotProps">
  54. <user-link
  55. v-if="slotProps.item.type === 'banUserId'"
  56. :user-id="slotProps.item.value"
  57. :alt="slotProps.item.value"
  58. />
  59. <span v-else :title="slotProps.item.value">{{
  60. slotProps.item.value
  61. }}</span>
  62. </template>
  63. <template #column-reason="slotProps">
  64. <span :title="slotProps.item.reason">{{
  65. slotProps.item.reason
  66. }}</span>
  67. </template>
  68. <template #column-punishedBy="slotProps">
  69. <user-link :user-id="slotProps.item.punishedBy" />
  70. </template>
  71. <template #column-punishedAt="slotProps">
  72. <span :title="new Date(slotProps.item.punishedAt)">{{
  73. getDateFormatted(slotProps.item.punishedAt)
  74. }}</span>
  75. </template>
  76. <template #column-expiresAt="slotProps">
  77. <span :title="new Date(slotProps.item.expiresAt)">{{
  78. getDateFormatted(slotProps.item.expiresAt)
  79. }}</span>
  80. </template>
  81. </advanced-table>
  82. <div class="card">
  83. <h4>Ban an IP</h4>
  84. <hr class="section-horizontal-rule" />
  85. <div class="card-content">
  86. <label class="label">Expires In</label>
  87. <p class="control is-expanded select">
  88. <select v-model="ipBan.expiresAt">
  89. <option value="1h">1 Hour</option>
  90. <option value="12h">12 Hours</option>
  91. <option value="1d">1 Day</option>
  92. <option value="1w">1 Week</option>
  93. <option value="1m">1 Month</option>
  94. <option value="3m">3 Months</option>
  95. <option value="6m">6 Months</option>
  96. <option value="1y">1 Year</option>
  97. </select>
  98. </p>
  99. <label class="label">IP</label>
  100. <p class="control is-expanded">
  101. <input
  102. v-model="ipBan.ip"
  103. class="input"
  104. type="text"
  105. placeholder="IP address (xxx.xxx.xxx.xxx)"
  106. />
  107. </p>
  108. <label class="label">Reason</label>
  109. <p class="control is-expanded">
  110. <input
  111. v-model="ipBan.reason"
  112. class="input"
  113. type="text"
  114. placeholder="Reason"
  115. />
  116. </p>
  117. <button class="button is-primary" @click="banIP()">
  118. Ban IP
  119. </button>
  120. </div>
  121. </div>
  122. </div>
  123. </template>
  124. <script>
  125. import { mapGetters, mapActions } from "vuex";
  126. import Toast from "toasters";
  127. import AdvancedTable from "@/components/AdvancedTable.vue";
  128. export default {
  129. components: {
  130. AdvancedTable
  131. },
  132. data() {
  133. return {
  134. ipBan: {
  135. expiresAt: "1h"
  136. },
  137. columnDefault: {
  138. sortable: true,
  139. hidable: true,
  140. defaultVisibility: "shown",
  141. draggable: true,
  142. resizable: true,
  143. minWidth: 150,
  144. maxWidth: 600
  145. },
  146. columns: [
  147. {
  148. name: "options",
  149. displayName: "Options",
  150. properties: ["_id"],
  151. sortable: false,
  152. hidable: false,
  153. resizable: false,
  154. minWidth: 76,
  155. defaultWidth: 76
  156. },
  157. {
  158. name: "status",
  159. displayName: "Status",
  160. properties: ["status"],
  161. sortable: false,
  162. defaultWidth: 150
  163. },
  164. {
  165. name: "type",
  166. displayName: "Type",
  167. properties: ["type"],
  168. sortProperty: "type"
  169. },
  170. {
  171. name: "value",
  172. displayName: "Value",
  173. properties: ["value"],
  174. sortProperty: "value",
  175. defaultWidth: 150
  176. },
  177. {
  178. name: "reason",
  179. displayName: "Reason",
  180. properties: ["reason"],
  181. sortProperty: "reason"
  182. },
  183. {
  184. name: "punishedBy",
  185. displayName: "Punished By",
  186. properties: ["punishedBy"],
  187. sortProperty: "punishedBy",
  188. defaultWidth: 200,
  189. defaultVisibility: "hidden"
  190. },
  191. {
  192. name: "punishedAt",
  193. displayName: "Punished At",
  194. properties: ["punishedAt"],
  195. sortProperty: "punishedAt",
  196. defaultWidth: 200,
  197. defaultVisibility: "hidden"
  198. },
  199. {
  200. name: "expiresAt",
  201. displayName: "Expires At",
  202. properties: ["expiresAt"],
  203. sortProperty: "verifiedAt",
  204. defaultWidth: 200,
  205. defaultVisibility: "hidden"
  206. }
  207. ],
  208. filters: [
  209. {
  210. name: "status",
  211. displayName: "Status",
  212. property: "status",
  213. filterTypes: ["exact"],
  214. defaultFilterType: "exact",
  215. dropdown: [
  216. ["Active", "Active"],
  217. ["Inactive", "Inactive"]
  218. ]
  219. },
  220. {
  221. name: "type",
  222. displayName: "Type",
  223. property: "type",
  224. filterTypes: ["exact"],
  225. defaultFilterType: "exact",
  226. dropdown: [
  227. ["banUserId", "User ID"],
  228. ["banUserIp", "IP Address"]
  229. ]
  230. },
  231. {
  232. name: "value",
  233. displayName: "Value",
  234. property: "value",
  235. filterTypes: ["contains", "exact", "regex"],
  236. defaultFilterType: "contains"
  237. },
  238. {
  239. name: "reason",
  240. displayName: "Reason",
  241. property: "reason",
  242. filterTypes: ["contains", "exact", "regex"],
  243. defaultFilterType: "contains"
  244. },
  245. {
  246. name: "punishedBy",
  247. displayName: "Punished By",
  248. property: "punishedBy",
  249. filterTypes: ["contains", "exact", "regex"],
  250. defaultFilterType: "contains"
  251. },
  252. {
  253. name: "punishedAt",
  254. displayName: "Punished At",
  255. property: "punishedAt",
  256. filterTypes: ["datetimeBefore", "datetimeAfter"],
  257. defaultFilterType: "datetimeBefore"
  258. },
  259. {
  260. name: "expiresAt",
  261. displayName: "Expires At",
  262. property: "expiresAt",
  263. filterTypes: ["datetimeBefore", "datetimeAfter"],
  264. defaultFilterType: "datetimeBefore"
  265. }
  266. ]
  267. };
  268. },
  269. computed: {
  270. ...mapGetters({
  271. socket: "websockets/getSocket"
  272. })
  273. },
  274. methods: {
  275. banIP() {
  276. this.socket.dispatch(
  277. "punishments.banIP",
  278. this.ipBan.ip,
  279. this.ipBan.reason,
  280. this.ipBan.expiresAt,
  281. res => {
  282. new Toast(res.message);
  283. }
  284. );
  285. },
  286. getDateFormatted(createdAt) {
  287. const date = new Date(createdAt);
  288. const year = date.getFullYear();
  289. const month = `${date.getMonth() + 1}`.padStart(2, 0);
  290. const day = `${date.getDate()}`.padStart(2, 0);
  291. const hour = `${date.getHours()}`.padStart(2, 0);
  292. const minute = `${date.getMinutes()}`.padStart(2, 0);
  293. return `${year}-${month}-${day} ${hour}:${minute}`;
  294. },
  295. ...mapActions("modalVisibility", ["openModal"])
  296. }
  297. };
  298. </script>
  299. <style lang="less" scoped>
  300. .card .button.is-primary {
  301. width: 100%;
  302. }
  303. </style>