Punishments.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. <template>
  2. <div>
  3. <page-metadata title="Admin | Punishments" />
  4. <div class="container">
  5. <advanced-table
  6. :column-default="columnDefault"
  7. :columns="columns"
  8. :filters="filters"
  9. data-action="punishments.getData"
  10. name="admin-punishments"
  11. max-width="1200"
  12. >
  13. <template #column-options="slotProps">
  14. <div class="row-options">
  15. <button
  16. class="
  17. button
  18. is-primary
  19. icon-with-button
  20. material-icons
  21. "
  22. @click="view(slotProps.item._id)"
  23. :disabled="slotProps.item.removed"
  24. content="View Punishment"
  25. v-tippy
  26. >
  27. open_in_full
  28. </button>
  29. </div>
  30. </template>
  31. <template #column-status="slotProps">
  32. <span>{{ slotProps.item.status }}</span>
  33. </template>
  34. <template #column-type="slotProps">
  35. <span
  36. :title="
  37. slotProps.item.type === 'banUserId'
  38. ? 'User ID'
  39. : 'IP Address'
  40. "
  41. >{{
  42. slotProps.item.type === "banUserId"
  43. ? "User ID"
  44. : "IP Address"
  45. }}</span
  46. >
  47. </template>
  48. <template #column-value="slotProps">
  49. <user-id-to-username
  50. v-if="slotProps.item.type === 'banUserId'"
  51. :user-id="slotProps.item.value"
  52. :alt="slotProps.item.value"
  53. :link="true"
  54. />
  55. <span v-else :title="slotProps.item.value">{{
  56. slotProps.item.value
  57. }}</span>
  58. </template>
  59. <template #column-reason="slotProps">
  60. <span :title="slotProps.item.reason">{{
  61. slotProps.item.reason
  62. }}</span>
  63. </template>
  64. </advanced-table>
  65. <div class="card">
  66. <header class="card-header">
  67. <p>Ban an IP</p>
  68. </header>
  69. <div class="card-content">
  70. <label class="label">Expires In</label>
  71. <select v-model="ipBan.expiresAt">
  72. <option value="1h">1 Hour</option>
  73. <option value="12h">12 Hours</option>
  74. <option value="1d">1 Day</option>
  75. <option value="1w">1 Week</option>
  76. <option value="1m">1 Month</option>
  77. <option value="3m">3 Months</option>
  78. <option value="6m">6 Months</option>
  79. <option value="1y">1 Year</option>
  80. </select>
  81. <label class="label">IP</label>
  82. <p class="control is-expanded">
  83. <input
  84. v-model="ipBan.ip"
  85. class="input"
  86. type="text"
  87. placeholder="IP address (xxx.xxx.xxx.xxx)"
  88. />
  89. </p>
  90. <label class="label">Reason</label>
  91. <p class="control is-expanded">
  92. <input
  93. v-model="ipBan.reason"
  94. class="input"
  95. type="text"
  96. placeholder="Reason"
  97. />
  98. </p>
  99. <button class="button is-primary" @click="banIP()">
  100. Ban IP
  101. </button>
  102. </div>
  103. </div>
  104. </div>
  105. <view-punishment
  106. v-if="modals.viewPunishment"
  107. :punishment-id="viewingPunishmentId"
  108. sector="admin"
  109. />
  110. </div>
  111. </template>
  112. <script>
  113. import { mapState, mapGetters, mapActions } from "vuex";
  114. import Toast from "toasters";
  115. import { defineAsyncComponent } from "vue";
  116. // import ws from "@/ws";
  117. import AdvancedTable from "@/components/AdvancedTable.vue";
  118. import UserIdToUsername from "@/components/UserIdToUsername.vue";
  119. export default {
  120. components: {
  121. ViewPunishment: defineAsyncComponent(() =>
  122. import("@/components/modals/ViewPunishment.vue")
  123. ),
  124. AdvancedTable,
  125. UserIdToUsername
  126. },
  127. data() {
  128. return {
  129. viewingPunishmentId: "",
  130. ipBan: {
  131. expiresAt: "1h"
  132. },
  133. columnDefault: {
  134. sortable: true,
  135. hidable: true,
  136. defaultVisibility: "shown",
  137. draggable: true,
  138. resizable: true,
  139. minWidth: 150,
  140. maxWidth: 600
  141. },
  142. columns: [
  143. {
  144. name: "options",
  145. displayName: "Edit",
  146. properties: ["_id"],
  147. sortable: false,
  148. hidable: false,
  149. resizable: false,
  150. minWidth: 51,
  151. defaultWidth: 51
  152. },
  153. {
  154. name: "status",
  155. displayName: "Status",
  156. properties: ["status", "active", "expiresAt"],
  157. sortable: false,
  158. defaultWidth: 150
  159. },
  160. {
  161. name: "type",
  162. displayName: "Type",
  163. properties: ["type"],
  164. sortProperty: "type"
  165. },
  166. {
  167. name: "value",
  168. displayName: "Value",
  169. properties: ["value"],
  170. sortProperty: "value",
  171. defaultWidth: 150
  172. },
  173. {
  174. name: "reason",
  175. displayName: "Reason",
  176. properties: ["reason"],
  177. sortProperty: "reason"
  178. }
  179. ],
  180. filters: [
  181. // {
  182. // name: "status",
  183. // displayName: "Status",
  184. // property: "status",
  185. // filterTypes: ["contains", "exact", "regex"],
  186. // defaultFilterType: "contains"
  187. // },
  188. {
  189. name: "type",
  190. displayName: "Type",
  191. property: "type",
  192. filterTypes: ["contains", "exact", "regex"],
  193. defaultFilterType: "contains"
  194. },
  195. {
  196. name: "value",
  197. displayName: "Value",
  198. property: "value",
  199. filterTypes: ["contains", "exact", "regex"],
  200. defaultFilterType: "contains"
  201. },
  202. {
  203. name: "reason",
  204. displayName: "Reason",
  205. property: "reason",
  206. filterTypes: ["contains", "exact", "regex"],
  207. defaultFilterType: "contains"
  208. }
  209. ]
  210. };
  211. },
  212. computed: {
  213. sortedPunishments() {
  214. return this.punishments;
  215. },
  216. ...mapState("modalVisibility", {
  217. modals: state => state.modals
  218. }),
  219. ...mapGetters({
  220. socket: "websockets/getSocket"
  221. })
  222. },
  223. mounted() {
  224. // ws.onConnect(this.init);
  225. // this.socket.on("event:admin.punishment.created", res =>
  226. // this.punishments.push(res.data.punishment)
  227. // );
  228. },
  229. methods: {
  230. view(punishmentId) {
  231. this.viewingPunishmentId = punishmentId;
  232. this.openModal("viewPunishment");
  233. },
  234. banIP() {
  235. this.socket.dispatch(
  236. "punishments.banIP",
  237. this.ipBan.ip,
  238. this.ipBan.reason,
  239. this.ipBan.expiresAt,
  240. res => {
  241. new Toast(res.message);
  242. }
  243. );
  244. },
  245. // init() {
  246. // this.socket.dispatch("apis.joinAdminRoom", "punishments", () => {});
  247. // },
  248. ...mapActions("modalVisibility", ["openModal"]),
  249. ...mapActions("admin/punishments", ["viewPunishment"])
  250. }
  251. };
  252. </script>
  253. <style lang="scss" scoped>
  254. .night-mode {
  255. .card {
  256. background: var(--dark-grey-3);
  257. p,
  258. .label {
  259. color: var(--light-grey-2);
  260. }
  261. }
  262. }
  263. .card {
  264. display: flex;
  265. flex-grow: 1;
  266. flex-direction: column;
  267. padding: 20px;
  268. margin: 10px 0;
  269. border-radius: 5px;
  270. background-color: var(--white);
  271. color: var(--dark-grey);
  272. box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1);
  273. .card-header {
  274. font-weight: 700;
  275. padding-bottom: 10px;
  276. }
  277. .button.is-primary {
  278. width: 100%;
  279. }
  280. select {
  281. margin-bottom: 10px;
  282. }
  283. }
  284. </style>