Browse Source

fix(auth): register/login now function with Vuex

Signed-off-by: Jonathan <theflametrooper@gmail.com>
Jonathan 5 năm trước cách đây
mục cha
commit
cff23ed882

+ 0 - 97
frontend/App.vue

@@ -140,103 +140,6 @@ export default {
       });
     });
   },
-  events: {
-    register: function(recaptchaId) {
-      let {
-        register: { email, username, password }
-      } = this;
-      let _this = this;
-      if (!email || !username || !password)
-        return Toast.methods.addToast("Please fill in all fields", 8000);
-
-      if (!validation.isLength(email, 3, 254))
-        return Toast.methods.addToast(
-          "Email must have between 3 and 254 characters.",
-          8000
-        );
-      if (
-        email.indexOf("@") !== email.lastIndexOf("@") ||
-        !validation.regex.emailSimple.test(email)
-      )
-        return Toast.methods.addToast("Invalid email format.", 8000);
-
-      if (!validation.isLength(username, 2, 32))
-        return Toast.methods.addToast(
-          "Username must have between 2 and 32 characters.",
-          8000
-        );
-      if (!validation.regex.azAZ09_.test(username))
-        return Toast.methods.addToast(
-          "Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _.",
-          8000
-        );
-
-      if (!validation.isLength(password, 6, 200))
-        return Toast.methods.addToast(
-          "Password must have between 6 and 200 characters.",
-          8000
-        );
-      if (!validation.regex.password.test(password))
-        return Toast.methods.addToast(
-          "Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character.",
-          8000
-        );
-
-      this.socket.emit(
-        "users.register",
-        username,
-        email,
-        password,
-        grecaptcha.getResponse(recaptchaId),
-        result => {
-          if (result.status === "success") {
-            Toast.methods.addToast(`You have successfully registered.`, 4000);
-            if (result.SID) {
-              lofig.get("cookie", cookie => {
-                let date = new Date();
-                date.setTime(
-                  new Date().getTime() + 2 * 365 * 24 * 60 * 60 * 1000
-                );
-                let secure = cookie.secure ? "secure=true; " : "";
-                document.cookie = `SID=${
-                  result.SID
-                }; expires=${date.toGMTString()}; domain=${
-                  cookie.domain
-                }; ${secure}path=/`;
-                location.reload();
-              });
-            } else _this.$router.go("/login");
-          } else Toast.methods.addToast(result.message, 8000);
-        }
-      );
-    },
-    login: function() {
-      let {
-        login: { email, password }
-      } = this;
-      let _this = this;
-      this.socket.emit("users.login", email, password, result => {
-        if (result.status === "success") {
-          lofig.get("cookie", cookie => {
-            let date = new Date();
-            date.setTime(new Date().getTime() + 2 * 365 * 24 * 60 * 60 * 1000);
-            let secure = cookie.secure ? "secure=true; " : "";
-            let domain = "";
-            if (cookie.domain !== "localhost")
-              domain = ` domain=${cookie.domain};`;
-            document.cookie = `SID=${
-              result.SID
-            }; expires=${date.toGMTString()}; ${domain}${secure}path=/`;
-            Toast.methods.addToast(
-              `You have been successfully logged in`,
-              2000
-            );
-            location.reload();
-          });
-        } else Toast.methods.addToast(result.message, 2000);
-      });
-    }
-  },
   components: {
     Toast,
     WhatIsNew,

+ 67 - 0
frontend/api/auth.js

@@ -0,0 +1,67 @@
+import io from "../io";
+
+// when Vuex needs to interact with socket.io
+
+export default {
+  register(user, recaptchaId) {
+    return new Promise((resolve, reject) => {
+      const { username, email, password } = user;
+
+      io.getSocket(socket => {
+        socket.emit(
+          "users.register",
+          username,
+          email,
+          password,
+          grecaptcha.getResponse(recaptchaId),
+          res => {
+            if (res.status === "success") {
+              if (res.SID) {
+                lofig.get("cookie", cookie => {
+                  let date = new Date();
+                  date.setTime(
+                    new Date().getTime() + 2 * 365 * 24 * 60 * 60 * 1000
+                  );
+                  let secure = cookie.secure ? "secure=true; " : "";
+                  document.cookie = `SID=${
+                    res.SID
+                  }; expires=${date.toGMTString()}; domain=${
+                    cookie.domain
+                  }; ${secure}path=/`;
+                  return resolve({ status: "success" });
+                });
+              } else
+                return reject({ status: "error", message: "You must login" });
+            } else return reject({ status: "error", message: res.message });
+          }
+        );
+      });
+    });
+  },
+  login(user) {
+    return new Promise((resolve, reject) => {
+      const { email, password } = user;
+
+      io.getSocket(socket => {
+        socket.emit("users.login", email, password, res => {
+          if (res.status === "success") {
+            lofig.get("cookie", cookie => {
+              let date = new Date();
+              date.setTime(
+                new Date().getTime() + 2 * 365 * 24 * 60 * 60 * 1000
+              );
+              let secure = cookie.secure ? "secure=true; " : "";
+              let domain = "";
+              if (cookie.domain !== "localhost")
+                domain = ` domain=${cookie.domain};`;
+              document.cookie = `SID=${
+                res.SID
+              }; expires=${date.toGMTString()}; ${domain}${secure}path=/`;
+              return resolve({ status: "success" });
+            });
+          } else return reject({ status: "error", message: res.message });
+        });
+      });
+    });
+  }
+};

+ 1 - 1
frontend/components/Modals/EditSong.vue

@@ -358,7 +358,7 @@ export default {
       "pauseVideo",
       "editSong"
     ]),
-    ...mapActions("modals", ["toggleModal"])
+    ...mapActions("modals", ["toggleModal", "closeCurrentModal"])
   },
   mounted: function() {
     let _this = this;

+ 22 - 7
frontend/components/Modals/Login.vue

@@ -10,7 +10,7 @@
         <!-- validation to check if exists http://bulma.io/documentation/elements/form/ -->
         <label class="label">Email</label>
         <p class="control">
-          <input class="input" type="text" placeholder="Email..." v-model="$parent.login.email" />
+          <input class="input" type="text" placeholder="Email..." v-model="email" />
         </p>
         <label class="label">Password</label>
         <p class="control">
@@ -18,13 +18,13 @@
             class="input"
             type="password"
             placeholder="Password..."
-            v-model="$parent.login.password"
+            v-model="password"
             v-on:keypress="$parent.submitOnEnter(submitModal, $event)"
           />
         </p>
         <p>
           By logging in/registering you agree to our
-          <router-link to="/terms">Terms of Service</router-link>and&nbsp;
+          <router-link to="/terms">Terms of Service</router-link>&nbsp;and
           <router-link to="/privacy">Privacy Policy</router-link>.
         </p>
       </section>
@@ -48,20 +48,35 @@
 <script>
 import { mapActions } from "vuex";
 
+import { Toast } from "vue-roaster";
+
 export default {
+  data: function() {
+    return {
+      email: "",
+      password: ""
+    };
+  },
   methods: {
     submitModal: function() {
-      // this.$dispatch('login');
-      //this.toggleModal();
+      this.login({
+        email: this.email,
+        password: this.password
+      })
+        .then(res => {
+          if (res.status == "success") location.reload();
+        })
+        .catch(err => Toast.methods.addToast(err.message, 5000));
     },
     resetPassword: function() {
+      this.toggleModal({ sector: "header", modal: "login" });
       this.$router.go("/reset_password");
-      //this.toggleModal();
     },
     githubRedirect: function() {
       localStorage.setItem("github_redirect", this.$route.path);
     },
-    ...mapActions("modals", ["toggleModal", "closeCurrentModal"])
+    ...mapActions("modals", ["toggleModal", "closeCurrentModal"]),
+    ...mapActions("user/auth", ["login"])
   }
 };
 </script>

+ 23 - 18
frontend/components/Modals/Register.vue

@@ -10,22 +10,11 @@
         <!-- validation to check if exists http://bulma.io/documentation/elements/form/ -->
         <label class="label">Email</label>
         <p class="control">
-          <input
-            class="input"
-            type="text"
-            placeholder="Email..."
-            v-model="$parent.register.email"
-            autofocus
-          />
+          <input class="input" type="text" placeholder="Email..." v-model="email" autofocus />
         </p>
         <label class="label">Username</label>
         <p class="control">
-          <input
-            class="input"
-            type="text"
-            placeholder="Username..."
-            v-model="$parent.register.username"
-          />
+          <input class="input" type="text" placeholder="Username..." v-model="username" />
         </p>
         <label class="label">Password</label>
         <p class="control">
@@ -33,14 +22,14 @@
             class="input"
             type="password"
             placeholder="Password..."
-            v-model="$parent.register.password"
+            v-model="password"
             v-on:keypress="$parent.submitOnEnter(submitModal, $event)"
           />
         </p>
         <div id="recaptcha"></div>
         <p>
           By logging in/registering you agree to our
-          <router-link to="/terms">Terms of Service</router-link>and
+          <router-link to="/terms">Terms of Service</router-link>&nbsp;and
           <router-link to="/privacy">Privacy Policy</router-link>.
         </p>
       </section>
@@ -63,9 +52,14 @@
 <script>
 import { mapActions } from "vuex";
 
+import { Toast } from "vue-roaster";
+
 export default {
   data() {
     return {
+      username: "",
+      email: "",
+      password: "",
       recaptcha: {
         key: ""
       }
@@ -82,13 +76,24 @@ export default {
   },
   methods: {
     submitModal: function() {
-      // this.$dispatch('register', this.recaptcha.id);
-      this.toggleModal();
+      this.register(
+        {
+          username: this.username,
+          email: this.email,
+          password: this.password
+        },
+        this.recaptcha.id
+      )
+        .then(res => {
+          if (res.status == "success") location.reload();
+        })
+        .catch(err => Toast.methods.addToast(err.message, 5000));
     },
     githubRedirect: function() {
       localStorage.setItem("github_redirect", this.$route.path);
     },
-    ...mapActions("modals", ["toggleModal", "closeCurrentModal"])
+    ...mapActions("modals", ["toggleModal", "closeCurrentModal"]),
+    ...mapActions("user/auth", ["register"])
   }
 };
 </script>

+ 138 - 111
frontend/components/Modals/WhatIsNew.vue

@@ -1,127 +1,154 @@
 <template>
-	<div class='modal' :class='{ "is-active": isModalActive }' v-if='news !== null'>
-		<div class='modal-background'></div>
-		<div class='modal-card'>
-			<header class='modal-card-head'>
-				<p class='modal-card-title'><strong>{{ news.title }}</strong> ({{ formatDate(news.createdAt) }})</p>
-				<button class='delete' v-on:click='toggleModal()'></button>
-			</header>
-			<section class='modal-card-body'>
-				<div class='content'>
-					<p>{{ news.description }}</p>
-				</div>
-				<div class='sect' v-show='news.features.length > 0'>
-					<div class='sect-head-features'>The features are so great</div>
-					<ul class='sect-body'>
-						<li v-for='li in news.features'>{{ li }}</li>
-					</ul>
-				</div>
-				<div class='sect' v-show='news.improvements.length > 0'>
-					<div class='sect-head-improvements'>Improvements</div>
-					<ul class='sect-body'>
-						<li v-for='li in news.improvements'>{{ li }}</li>
-					</ul>
-				</div>
-				<div class='sect' v-show='news.bugs.length > 0'>
-					<div class='sect-head-bugs'>Bugs Smashed</div>
-					<ul class='sect-body'>
-						<li v-for='li in news.bugs'>{{ li }}</li>
-					</ul>
-				</div>
-				<div class='sect' v-show='news.upcoming.length > 0'>
-					<div class='sect-head-upcoming'>Coming Soon to a Musare near you</div>
-					<ul class='sect-body'>
-						<li v-for='li in news.upcoming'>{{ li }}</li>
-					</ul>
-				</div>
-			</section>
-		</div>
-	</div>
+  <div class="modal" :class="{ 'is-active': isModalActive }" v-if="news !== null">
+    <div class="modal-background"></div>
+    <div class="modal-card">
+      <header class="modal-card-head">
+        <p class="modal-card-title">
+          <strong>{{ news.title }}</strong>
+          ({{ formatDate(news.createdAt) }})
+        </p>
+        <button class="delete" v-on:click="toggleModal()"></button>
+      </header>
+      <section class="modal-card-body">
+        <div class="content">
+          <p>{{ news.description }}</p>
+        </div>
+        <div class="sect" v-show="news.features.length > 0">
+          <div class="sect-head-features">The features are so great</div>
+          <ul class="sect-body">
+            <li v-for="(feature, index) in news.features" :key="index">{{ feature }}</li>
+          </ul>
+        </div>
+        <div class="sect" v-show="news.improvements.length > 0">
+          <div class="sect-head-improvements">Improvements</div>
+          <ul class="sect-body">
+            <li v-for="(improvement, index) in news.improvements" :key="index">{{ improvement }}</li>
+          </ul>
+        </div>
+        <div class="sect" v-show="news.bugs.length > 0">
+          <div class="sect-head-bugs">Bugs Smashed</div>
+          <ul class="sect-body">
+            <li v-for="(bug, index) in news.bugs" :key="index">{{ bug }}</li>
+          </ul>
+        </div>
+        <div class="sect" v-show="news.upcoming.length > 0">
+          <div class="sect-head-upcoming">Coming Soon to a Musare near you</div>
+          <ul class="sect-body">
+            <li v-for="(upcoming, index) in news.upcoming" :key="index">{{ upcoming }}</li>
+          </ul>
+        </div>
+      </section>
+    </div>
+  </div>
 </template>
 
 <script>
-	import io from '../../io';
+import io from "../../io";
 
-	export default {
-		data() {
-			return {
-				isModalActive: false,
-				news: null
-			}
-		},
-		mounted: function () {
-			let _this = this;
-			io.getSocket(true, socket => {
-				_this.socket = socket;
-				_this.socket.emit('news.newest', res => {
-					_this.news = res.data;
-					if (_this.news && localStorage.getItem('firstVisited')) {
-						if (localStorage.getItem('whatIsNew')) {
-							if (parseInt(localStorage.getItem('whatIsNew')) < res.data.createdAt) {
-								this.toggleModal();
-								localStorage.setItem('whatIsNew', res.data.createdAt);
-							}
-						} else {
-							if (parseInt(localStorage.getItem('firstVisited')) < res.data.createdAt) {
-								this.toggleModal();
-							}
-							localStorage.setItem('whatIsNew', res.data.createdAt);
-						}
-					} else {
-						if (!localStorage.getItem('firstVisited')) localStorage.setItem('firstVisited', Date.now());
-					}
-				});
-			});
-		},
-		methods: {
-			toggleModal: function () {
-				this.isModalActive = !this.isModalActive;
-			},
-			formatDate: unix => {
-				return moment(unix).format('DD-MM-YYYY');
-			}
-		},
-		events: {
-			closeModal: function() {
-				this.isModalActive = false;
-			}
-		}
-	}
+export default {
+  data() {
+    return {
+      isModalActive: false,
+      news: null
+    };
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(true, socket => {
+      _this.socket = socket;
+      _this.socket.emit("news.newest", res => {
+        _this.news = res.data;
+        if (_this.news && localStorage.getItem("firstVisited")) {
+          if (localStorage.getItem("whatIsNew")) {
+            if (
+              parseInt(localStorage.getItem("whatIsNew")) < res.data.createdAt
+            ) {
+              this.toggleModal();
+              localStorage.setItem("whatIsNew", res.data.createdAt);
+            }
+          } else {
+            if (
+              parseInt(localStorage.getItem("firstVisited")) <
+              res.data.createdAt
+            ) {
+              this.toggleModal();
+            }
+            localStorage.setItem("whatIsNew", res.data.createdAt);
+          }
+        } else {
+          if (!localStorage.getItem("firstVisited"))
+            localStorage.setItem("firstVisited", Date.now());
+        }
+      });
+    });
+  },
+  methods: {
+    toggleModal: function() {
+      this.isModalActive = !this.isModalActive;
+    },
+    formatDate: unix => {
+      return moment(unix).format("DD-MM-YYYY");
+    }
+  },
+  events: {
+    closeModal: function() {
+      this.isModalActive = false;
+    }
+  }
+};
 </script>
 
 <style lang='scss' scoped>
-	.modal-card-head {
-		border-bottom: none;
-		background-color: ghostwhite;
-		padding: 15px;
-	}
+.modal-card-head {
+  border-bottom: none;
+  background-color: ghostwhite;
+  padding: 15px;
+}
 
-	.modal-card-title { font-size: 14px; }
+.modal-card-title {
+  font-size: 14px;
+}
 
-	.delete {
-		background: transparent;
-		&:hover { background: transparent; }
+.delete {
+  background: transparent;
+  &:hover {
+    background: transparent;
+  }
 
-		&:before, &:after { background-color: #bbb; }
-	}
+  &:before,
+  &:after {
+    background-color: #bbb;
+  }
+}
 
-	.sect {
-		div[class^='sect-head'], div[class*=' sect-head']{
-			padding: 12px;
-			text-transform: uppercase;
-			font-weight: bold;
-			color: #fff;
-		}
+.sect {
+  div[class^="sect-head"],
+  div[class*=" sect-head"] {
+    padding: 12px;
+    text-transform: uppercase;
+    font-weight: bold;
+    color: #fff;
+  }
 
-		.sect-head-features { background-color: dodgerblue; }
-		.sect-head-improvements { background-color: seagreen; }
-		.sect-head-bugs { background-color: brown; }
-		.sect-head-upcoming { background-color: mediumpurple; }
+  .sect-head-features {
+    background-color: dodgerblue;
+  }
+  .sect-head-improvements {
+    background-color: seagreen;
+  }
+  .sect-head-bugs {
+    background-color: brown;
+  }
+  .sect-head-upcoming {
+    background-color: mediumpurple;
+  }
 
-		.sect-body {
-			padding: 15px 25px;
+  .sect-body {
+    padding: 15px 25px;
 
-			li { list-style-type: disc; }
-		}
-	}
+    li {
+      list-style-type: disc;
+    }
+  }
+}
 </style>

+ 111 - 21
frontend/store/modules/user.js

@@ -1,31 +1,121 @@
+import auth from "../../api/auth.js";
+import validation from "../../validation.js";
+
 const state = {};
 const getters = {};
 const actions = {};
 const mutations = {};
 
 const modules = {
-	playlists: {
-		namespaced: true,
-		state: {
-			editing: ""
-		},
-		getters: {},
-		actions: {
-			editPlaylist: ({ commit }, id) => commit("editPlaylist", id)
-		},
-		mutations: {
-			editPlaylist(state, id) {
-				state.editing = id;
-			}
-		}
-	}
+  auth: {
+    namespaced: true,
+    state: {},
+    getters: {},
+    actions: {
+      register: ({ commit }, user, recaptchaId) => {
+        return new Promise((resolve, reject) => {
+          const { username, email, password } = user;
+
+          if (!email || !username || !password)
+            return reject({
+              status: "error",
+              message: "Please fill in all fields"
+            });
+
+          if (!validation.isLength(email, 3, 254))
+            return reject({
+              status: "error",
+              message: "Email must have between 3 and 254 characters."
+            });
+
+          if (
+            email.indexOf("@") !== email.lastIndexOf("@") ||
+            !validation.regex.emailSimple.test(email)
+          )
+            return reject({
+              status: "error",
+              message: "Invalid email format."
+            });
+
+          if (!validation.isLength(username, 2, 32))
+            return reject({
+              status: "error",
+              message: "Username must have between 2 and 32 characters."
+            });
+
+          if (!validation.regex.azAZ09_.test(username))
+            return reject({
+              status: "error",
+              message:
+                "Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _."
+            });
+
+          if (!validation.isLength(password, 6, 200))
+            return reject({
+              status: "error",
+              message: "Password must have between 6 and 200 characters."
+            });
+
+          if (!validation.regex.password.test(password))
+            return reject({
+              status: "error",
+              message:
+                "Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character."
+            });
+
+          auth
+            .register(user, recaptchaId)
+            .then(res => {
+              return resolve({
+                status: "success",
+                message: "Account registered!"
+              });
+            })
+            .catch(err => {
+              return reject({ status: "error", message: err.message });
+            });
+        });
+      },
+      login: ({ commit }, user) => {
+        return new Promise((resolve, reject) => {
+          auth
+            .login(user)
+            .then(res => {
+              return resolve({
+                status: "success",
+                message: "Logged in!"
+              });
+            })
+            .catch(err => {
+              return reject({ status: "error", message: err.message });
+            });
+        });
+      }
+    },
+    mutations: {}
+  },
+  playlists: {
+    namespaced: true,
+    state: {
+      editing: ""
+    },
+    getters: {},
+    actions: {
+      editPlaylist: ({ commit }, id) => commit("editPlaylist", id)
+    },
+    mutations: {
+      editPlaylist(state, id) {
+        state.editing = id;
+      }
+    }
+  }
 };
 
 export default {
-	namespaced: true,
-	state,
-	getters,
-	actions,
-	mutations,
-	modules
+  namespaced: true,
+  state,
+  getters,
+  actions,
+  mutations,
+  modules
 };