1
0

Settings.vue 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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 { mapState } from "vuex";
  143. import { Toast } from "vue-roaster";
  144. import MainHeader from "../MainHeader.vue";
  145. import MainFooter from "../MainFooter.vue";
  146. import io from "../../io";
  147. import validation from "../../validation";
  148. export default {
  149. components: { MainHeader, MainFooter },
  150. data() {
  151. return {
  152. user: {},
  153. newPassword: "",
  154. password: false,
  155. github: false,
  156. setNewPassword: "",
  157. passwordStep: 1,
  158. passwordCode: ""
  159. };
  160. },
  161. computed: mapState({
  162. userId: state => state.user.auth.userId
  163. }),
  164. mounted() {
  165. const _this = this;
  166. io.getSocket(socket => {
  167. _this.socket = socket;
  168. _this.socket.emit("users.findBySession", res => {
  169. if (res.status === "success") {
  170. _this.user = res.data;
  171. _this.password = _this.user.password;
  172. _this.github = _this.user.github;
  173. } else {
  174. _this.$parent.isLoginActive = true;
  175. Toast.methods.addToast(
  176. "Your are currently not signed in",
  177. 3000
  178. );
  179. }
  180. });
  181. _this.socket.on("event:user.linkPassword", () => {
  182. _this.password = true;
  183. });
  184. _this.socket.on("event:user.linkGitHub", () => {
  185. _this.github = true;
  186. });
  187. _this.socket.on("event:user.unlinkPassword", () => {
  188. _this.password = false;
  189. });
  190. _this.socket.on("event:user.unlinkGitHub", () => {
  191. _this.github = false;
  192. });
  193. });
  194. },
  195. methods: {
  196. changeEmail() {
  197. const email = this.user.email.address;
  198. if (!validation.isLength(email, 3, 254))
  199. return Toast.methods.addToast(
  200. "Email must have between 3 and 254 characters.",
  201. 8000
  202. );
  203. if (
  204. email.indexOf("@") !== email.lastIndexOf("@") ||
  205. !validation.regex.emailSimple.test(email)
  206. )
  207. return Toast.methods.addToast("Invalid email format.", 8000);
  208. return this.socket.emit(
  209. "users.updateEmail",
  210. this.userId,
  211. email,
  212. res => {
  213. if (res.status !== "success")
  214. Toast.methods.addToast(res.message, 8000);
  215. else
  216. Toast.methods.addToast(
  217. "Successfully changed email address",
  218. 4000
  219. );
  220. }
  221. );
  222. },
  223. changeUsername() {
  224. const { username } = this.user;
  225. if (!validation.isLength(username, 2, 32))
  226. return Toast.methods.addToast(
  227. "Username must have between 2 and 32 characters.",
  228. 8000
  229. );
  230. if (!validation.regex.azAZ09_.test(username))
  231. return Toast.methods.addToast(
  232. "Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _.",
  233. 8000
  234. );
  235. return this.socket.emit(
  236. "users.updateUsername",
  237. this.userId,
  238. username,
  239. res => {
  240. if (res.status !== "success")
  241. Toast.methods.addToast(res.message, 8000);
  242. else
  243. Toast.methods.addToast(
  244. "Successfully changed username",
  245. 4000
  246. );
  247. }
  248. );
  249. },
  250. changePassword() {
  251. const { newPassword } = this;
  252. if (!validation.isLength(newPassword, 6, 200))
  253. return Toast.methods.addToast(
  254. "Password must have between 6 and 200 characters.",
  255. 8000
  256. );
  257. if (!validation.regex.password.test(newPassword))
  258. return Toast.methods.addToast(
  259. "Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character.",
  260. 8000
  261. );
  262. return this.socket.emit(
  263. "users.updatePassword",
  264. newPassword,
  265. res => {
  266. if (res.status !== "success")
  267. Toast.methods.addToast(res.message, 8000);
  268. else
  269. Toast.methods.addToast(
  270. "Successfully changed password",
  271. 4000
  272. );
  273. }
  274. );
  275. },
  276. requestPassword() {
  277. return this.socket.emit("users.requestPassword", res => {
  278. Toast.methods.addToast(res.message, 8000);
  279. if (res.status === "success") {
  280. this.passwordStep = 2;
  281. }
  282. });
  283. },
  284. verifyCode() {
  285. if (!this.passwordCode)
  286. return Toast.methods.addToast("Code cannot be empty", 8000);
  287. return this.socket.emit(
  288. "users.verifyPasswordCode",
  289. this.passwordCode,
  290. res => {
  291. Toast.methods.addToast(res.message, 8000);
  292. if (res.status === "success") {
  293. this.passwordStep = 3;
  294. }
  295. }
  296. );
  297. },
  298. setPassword() {
  299. const newPassword = this.setNewPassword;
  300. if (!validation.isLength(newPassword, 6, 200))
  301. return Toast.methods.addToast(
  302. "Password must have between 6 and 200 characters.",
  303. 8000
  304. );
  305. if (!validation.regex.password.test(newPassword))
  306. return Toast.methods.addToast(
  307. "Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character.",
  308. 8000
  309. );
  310. return this.socket.emit(
  311. "users.changePasswordWithCode",
  312. this.passwordCode,
  313. newPassword,
  314. res => {
  315. Toast.methods.addToast(res.message, 8000);
  316. }
  317. );
  318. },
  319. unlinkPassword() {
  320. this.socket.emit("users.unlinkPassword", res => {
  321. Toast.methods.addToast(res.message, 8000);
  322. });
  323. },
  324. unlinkGitHub() {
  325. this.socket.emit("users.unlinkGitHub", res => {
  326. Toast.methods.addToast(res.message, 8000);
  327. });
  328. },
  329. removeSessions() {
  330. this.socket.emit(`users.removeSessions`, this.userId, res => {
  331. Toast.methods.addToast(res.message, 4000);
  332. });
  333. }
  334. }
  335. };
  336. </script>
  337. <style lang="scss" scoped>
  338. .container {
  339. padding: 25px;
  340. }
  341. a {
  342. color: #029ce3 !important;
  343. }
  344. </style>