Settings.vue 9.1 KB

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