Settings.vue 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. <template>
  2. <div>
  3. <main-header />
  4. <div class="container">
  5. <!--Implement Validation-->
  6. <label class="label">Username</label>
  7. <div class="control is-grouped">
  8. <p class="control is-expanded has-icon has-icon-right">
  9. <input
  10. v-model="user.username"
  11. class="input"
  12. type="text"
  13. placeholder="Change username"
  14. />
  15. <!--Remove validation if it's their own without changing-->
  16. </p>
  17. <p class="control">
  18. <button class="button is-success" @click="changeUsername()">
  19. Save changes
  20. </button>
  21. </p>
  22. </div>
  23. <label class="label">Email</label>
  24. <div v-if="user.email" class="control is-grouped">
  25. <p class="control is-expanded has-icon has-icon-right">
  26. <input
  27. v-model="user.email.address"
  28. class="input"
  29. type="text"
  30. placeholder="Change email address"
  31. />
  32. <!--Remove validation if it's their own without changing-->
  33. </p>
  34. <p class="control is-expanded">
  35. <button class="button is-success" @click="changeEmail()">
  36. Save changes
  37. </button>
  38. </p>
  39. </div>
  40. <label v-if="password" class="label">Change Password</label>
  41. <div v-if="password" class="control is-grouped">
  42. <p class="control is-expanded has-icon has-icon-right">
  43. <input
  44. v-model="newPassword"
  45. class="input"
  46. type="password"
  47. placeholder="Change password"
  48. />
  49. </p>
  50. <p class="control is-expanded">
  51. <button class="button is-success" @click="changePassword()">
  52. Change password
  53. </button>
  54. </p>
  55. </div>
  56. <label v-if="!password" class="label">Add password</label>
  57. <div v-if="!password" class="control is-grouped">
  58. <button
  59. v-if="passwordStep === 1"
  60. class="button is-success"
  61. @click="requestPassword()"
  62. >
  63. Request password email
  64. </button>
  65. <br />
  66. <p
  67. v-if="passwordStep === 2"
  68. class="control is-expanded has-icon has-icon-right"
  69. >
  70. <input
  71. v-model="passwordCode"
  72. class="input"
  73. type="text"
  74. placeholder="Code"
  75. />
  76. </p>
  77. <p v-if="passwordStep === 2" class="control is-expanded">
  78. <button class="button is-success" v-on:click="verifyCode()">
  79. Verify code
  80. </button>
  81. </p>
  82. <p
  83. v-if="passwordStep === 3"
  84. class="control is-expanded has-icon has-icon-right"
  85. >
  86. <input
  87. v-model="setNewPassword"
  88. class="input"
  89. type="password"
  90. placeholder="New password"
  91. />
  92. </p>
  93. <p v-if="passwordStep === 3" class="control is-expanded">
  94. <button class="button is-success" @click="setPassword()">
  95. Set password
  96. </button>
  97. </p>
  98. </div>
  99. <a
  100. v-if="passwordStep === 1 && !password"
  101. href="#"
  102. @click="passwordStep = 2"
  103. >Skip this step</a
  104. >
  105. <a
  106. v-if="!github"
  107. class="button is-github"
  108. :href="`${$parent.serverDomain}/auth/github/link`"
  109. >
  110. <div class="icon">
  111. <img class="invert" src="/assets/social/github.svg" />
  112. </div>
  113. &nbsp; Link GitHub to account
  114. </a>
  115. <button
  116. v-if="password && github"
  117. class="button is-danger"
  118. @click="unlinkPassword()"
  119. >
  120. Remove logging in with password
  121. </button>
  122. <button
  123. v-if="password && github"
  124. class="button is-danger"
  125. @click="unlinkGitHub()"
  126. >
  127. Remove logging in with GitHub
  128. </button>
  129. <br />
  130. <button
  131. class="button is-warning"
  132. style="margin-top: 30px;"
  133. @click="removeSessions()"
  134. >
  135. Log out everywhere
  136. </button>
  137. </div>
  138. <main-footer />
  139. </div>
  140. </template>
  141. <script>
  142. import { Toast } from "vue-roaster";
  143. import MainHeader from "../MainHeader.vue";
  144. import MainFooter from "../MainFooter.vue";
  145. import io from "../../io";
  146. import validation from "../../validation";
  147. export default {
  148. components: { MainHeader, MainFooter },
  149. data() {
  150. return {
  151. user: {},
  152. newPassword: "",
  153. password: false,
  154. github: false,
  155. setNewPassword: "",
  156. passwordStep: 1,
  157. passwordCode: ""
  158. };
  159. },
  160. mounted() {
  161. const _this = this;
  162. io.getSocket(socket => {
  163. _this.socket = socket;
  164. _this.socket.emit("users.findBySession", res => {
  165. if (res.status === "success") {
  166. _this.user = res.data;
  167. _this.password = _this.user.password;
  168. _this.github = _this.user.github;
  169. } else {
  170. _this.$parent.isLoginActive = true;
  171. Toast.methods.addToast(
  172. "Your are currently not signed in",
  173. 3000
  174. );
  175. }
  176. });
  177. _this.socket.on("event:user.username.changed", username => {
  178. _this.$parent.username = username;
  179. });
  180. _this.socket.on("event:user.linkPassword", () => {
  181. _this.password = true;
  182. });
  183. _this.socket.on("event:user.linkGitHub", () => {
  184. _this.github = true;
  185. });
  186. _this.socket.on("event:user.unlinkPassword", () => {
  187. _this.password = false;
  188. });
  189. _this.socket.on("event:user.unlinkGitHub", () => {
  190. _this.github = false;
  191. });
  192. });
  193. },
  194. methods: {
  195. changeEmail() {
  196. const email = this.user.email.address;
  197. if (!validation.isLength(email, 3, 254))
  198. return Toast.methods.addToast(
  199. "Email must have between 3 and 254 characters.",
  200. 8000
  201. );
  202. if (
  203. email.indexOf("@") !== email.lastIndexOf("@") ||
  204. !validation.regex.emailSimple.test(email)
  205. )
  206. return Toast.methods.addToast("Invalid email format.", 8000);
  207. return this.socket.emit(
  208. "users.updateEmail",
  209. this.$parent.userId,
  210. email,
  211. res => {
  212. if (res.status !== "success")
  213. Toast.methods.addToast(res.message, 8000);
  214. else
  215. Toast.methods.addToast(
  216. "Successfully changed email address",
  217. 4000
  218. );
  219. }
  220. );
  221. },
  222. changeUsername() {
  223. const { username } = this.user;
  224. if (!validation.isLength(username, 2, 32))
  225. return Toast.methods.addToast(
  226. "Username must have between 2 and 32 characters.",
  227. 8000
  228. );
  229. if (!validation.regex.azAZ09_.test(username))
  230. return Toast.methods.addToast(
  231. "Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _.",
  232. 8000
  233. );
  234. return this.socket.emit(
  235. "users.updateUsername",
  236. this.$parent.userId,
  237. username,
  238. res => {
  239. if (res.status !== "success")
  240. Toast.methods.addToast(res.message, 8000);
  241. else
  242. Toast.methods.addToast(
  243. "Successfully changed username",
  244. 4000
  245. );
  246. }
  247. );
  248. },
  249. changePassword() {
  250. const { newPassword } = this;
  251. if (!validation.isLength(newPassword, 6, 200))
  252. return Toast.methods.addToast(
  253. "Password must have between 6 and 200 characters.",
  254. 8000
  255. );
  256. if (!validation.regex.password.test(newPassword))
  257. return Toast.methods.addToast(
  258. "Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character.",
  259. 8000
  260. );
  261. return this.socket.emit(
  262. "users.updatePassword",
  263. newPassword,
  264. res => {
  265. if (res.status !== "success")
  266. Toast.methods.addToast(res.message, 8000);
  267. else
  268. Toast.methods.addToast(
  269. "Successfully changed password",
  270. 4000
  271. );
  272. }
  273. );
  274. },
  275. requestPassword() {
  276. return this.socket.emit("users.requestPassword", res => {
  277. Toast.methods.addToast(res.message, 8000);
  278. if (res.status === "success") {
  279. this.passwordStep = 2;
  280. }
  281. });
  282. },
  283. verifyCode() {
  284. if (!this.passwordCode)
  285. return Toast.methods.addToast("Code cannot be empty", 8000);
  286. return this.socket.emit(
  287. "users.verifyPasswordCode",
  288. this.passwordCode,
  289. res => {
  290. Toast.methods.addToast(res.message, 8000);
  291. if (res.status === "success") {
  292. this.passwordStep = 3;
  293. }
  294. }
  295. );
  296. },
  297. setPassword() {
  298. const newPassword = this.setNewPassword;
  299. if (!validation.isLength(newPassword, 6, 200))
  300. return Toast.methods.addToast(
  301. "Password must have between 6 and 200 characters.",
  302. 8000
  303. );
  304. if (!validation.regex.password.test(newPassword))
  305. return Toast.methods.addToast(
  306. "Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character.",
  307. 8000
  308. );
  309. return this.socket.emit(
  310. "users.changePasswordWithCode",
  311. this.passwordCode,
  312. newPassword,
  313. res => {
  314. Toast.methods.addToast(res.message, 8000);
  315. }
  316. );
  317. },
  318. unlinkPassword() {
  319. this.socket.emit("users.unlinkPassword", res => {
  320. Toast.methods.addToast(res.message, 8000);
  321. });
  322. },
  323. unlinkGitHub() {
  324. this.socket.emit("users.unlinkGitHub", res => {
  325. Toast.methods.addToast(res.message, 8000);
  326. });
  327. },
  328. removeSessions() {
  329. this.socket.emit(
  330. `users.removeSessions`,
  331. this.$parent.userId,
  332. res => {
  333. Toast.methods.addToast(res.message, 4000);
  334. }
  335. );
  336. }
  337. }
  338. };
  339. </script>
  340. <style lang="scss" scoped>
  341. .container {
  342. padding: 25px;
  343. }
  344. a {
  345. color: #029ce3 !important;
  346. }
  347. </style>