App.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. <template>
  2. <div v-if="!banned">
  3. <h1 v-if="!socketConnected" class="alert">Could not connect to the server.</h1>
  4. <router-view></router-view>
  5. <toast></toast>
  6. <what-is-new></what-is-new>
  7. <login-modal v-if='isLoginActive'></login-modal>
  8. <register-modal v-if='isRegisterActive'></register-modal>
  9. </div>
  10. <h1 v-if="banned">BANNED</h1>
  11. </template>
  12. <script>
  13. import { Toast } from 'vue-roaster';
  14. import WhatIsNew from './components/Modals/WhatIsNew.vue';
  15. import LoginModal from './components/Modals/Login.vue';
  16. import RegisterModal from './components/Modals/Register.vue';
  17. import auth from './auth';
  18. import io from './io';
  19. import validation from './validation';
  20. export default {
  21. replace: false,
  22. data() {
  23. return {
  24. banned: false,
  25. register: {
  26. email: '',
  27. username: '',
  28. password: ''
  29. },
  30. login: {
  31. email: '',
  32. password: ''
  33. },
  34. loggedIn: false,
  35. role: '',
  36. username: '',
  37. userId: '',
  38. isRegisterActive: false,
  39. isLoginActive: false,
  40. serverDomain: '',
  41. socketConnected: true,
  42. userIdMap: {},
  43. currentlyGettingUsernameFrom: {}
  44. }
  45. },
  46. methods: {
  47. logout: function () {
  48. let _this = this;
  49. _this.socket.emit('users.logout', result => {
  50. if (result.status === 'success') {
  51. document.cookie = 'SID=;expires=Thu, 01 Jan 1970 00:00:01 GMT;';
  52. location.reload();
  53. } else Toast.methods.addToast(result.message, 4000);
  54. });
  55. },
  56. 'submitOnEnter': (cb, event) => {
  57. if (event.which == 13) cb();
  58. },
  59. getUsernameFromId: function(userId) {
  60. if (typeof this.userIdMap[userId] !== 'string' && !this.currentlyGettingUsernameFrom[userId]) {
  61. this.currentlyGettingUsernameFrom[userId] = true;
  62. io.getSocket(socket => {
  63. socket.emit('users.getUsernameFromId', userId, (data) => {
  64. if (data.status === 'success') {
  65. this.$set(`userIdMap.${userId}`, data.data);
  66. }
  67. this.currentlyGettingUsernameFrom[userId] = false;
  68. });
  69. });
  70. }
  71. }
  72. },
  73. ready: function () {
  74. let _this = this;
  75. auth.isBanned((banned) => {
  76. console.log("BANNED: ", banned);
  77. _this.banned = banned;
  78. });
  79. auth.getStatus((authenticated, role, username, userId) => {
  80. _this.socket = window.socket;
  81. _this.loggedIn = authenticated;
  82. _this.role = role;
  83. _this.username = username;
  84. _this.userId = userId;
  85. });
  86. io.onConnect(true, () => {
  87. _this.socketConnected = true;
  88. });
  89. io.onConnectError(true, () => {
  90. _this.socketConnected = false;
  91. });
  92. io.onDisconnect(true, () => {
  93. _this.socketConnected = false;
  94. });
  95. lofig.get('serverDomain', res => {
  96. _this.serverDomain = res;
  97. });
  98. if (_this.$route.query.err) {
  99. let err = _this.$route.query.err;
  100. err = err.replace(new RegExp('<', 'g'), '&lt;').replace(new RegExp('>', 'g'), '&gt;');
  101. Toast.methods.addToast(err, 20000);
  102. }
  103. io.getSocket(true, socket => {
  104. socket.on('keep.event:user.session.removed', () => {
  105. location.reload();
  106. });
  107. });
  108. },
  109. events: {
  110. 'register': function (recaptchaId) {
  111. let { register: { email, username, password } } = this;
  112. let _this = this;
  113. if (!email || !username || !password) return Toast.methods.addToast('Please fill in all fields', 8000);
  114. if (!validation.isLength(email, 3, 254)) return Toast.methods.addToast('Email must have between 3 and 254 characters.', 8000);
  115. if (email.indexOf('@') !== email.lastIndexOf('@') || !validation.regex.emailSimple.test(email)) return Toast.methods.addToast('Invalid email format.', 8000);
  116. if (!validation.isLength(username, 2, 32)) return Toast.methods.addToast('Username must have between 2 and 32 characters.', 8000);
  117. if (!validation.regex.azAZ09_.test(username)) return Toast.methods.addToast('Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _.', 8000);
  118. if (!validation.isLength(password, 6, 200)) return Toast.methods.addToast('Password must have between 6 and 200 characters.', 8000);
  119. 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);
  120. this.socket.emit('users.register', username, email, password, grecaptcha.getResponse(recaptchaId), result => {
  121. if (result.status === 'success') {
  122. Toast.methods.addToast(`You have successfully registered.`, 4000);
  123. if (result.SID) {
  124. lofig.get('cookie', cookie => {
  125. let date = new Date();
  126. date.setTime(new Date().getTime() + (2 * 365 * 24 * 60 * 60 * 1000));
  127. let secure = (cookie.secure) ? 'secure=true; ' : '';
  128. document.cookie = `SID=${result.SID}; expires=${date.toGMTString()}; domain=${cookie.domain}; ${secure}path=/`;
  129. location.reload();
  130. });
  131. } else _this.$router.go('/login');
  132. } else Toast.methods.addToast(result.message, 8000);
  133. });
  134. },
  135. 'login': function () {
  136. let { login: { email, password } } = this;
  137. let _this = this;
  138. this.socket.emit('users.login', email, password, result => {
  139. if (result.status === 'success') {
  140. lofig.get('cookie', cookie => {
  141. let date = new Date();
  142. date.setTime(new Date().getTime() + (2 * 365 * 24 * 60 * 60 * 1000));
  143. let secure = (cookie.secure) ? 'secure=true; ' : '';
  144. let domain = '';
  145. if (cookie.domain !== 'localhost') domain = ` domain=${cookie.domain};`;
  146. document.cookie = `SID=${result.SID}; expires=${date.toGMTString()}; ${domain}${secure}path=/`;
  147. Toast.methods.addToast(`You have been successfully logged in`, 2000);
  148. location.reload();
  149. });
  150. } else Toast.methods.addToast(result.message, 2000);
  151. });
  152. },
  153. 'toggleModal': function (type) {
  154. switch(type) {
  155. case 'register':
  156. this.isRegisterActive = !this.isRegisterActive;
  157. break;
  158. case 'login':
  159. this.isLoginActive = !this.isLoginActive;
  160. break;
  161. }
  162. },
  163. 'closeModal': function() {
  164. this.$broadcast('closeModal');
  165. }
  166. },
  167. components: { Toast, WhatIsNew, LoginModal, RegisterModal }
  168. }
  169. </script>
  170. <style type='scss'>
  171. #toast-container { z-index: 10000 !important; }
  172. html {
  173. overflow: auto !important;
  174. }
  175. .modal-card {
  176. margin: 0 !important;
  177. }
  178. .absolute-a {
  179. width: 100%;
  180. height: 100%;
  181. position: absolute;
  182. top: 0;
  183. left: 0;
  184. }
  185. .alert {
  186. padding: 20px;
  187. color: white;
  188. background-color: red;
  189. position: fixed;
  190. top: 50px;
  191. right: 50px;
  192. font-size: 2em;
  193. border-radius: 5px;
  194. z-index: 10000000;
  195. }
  196. .tooltip {
  197. position: relative;
  198. &:after {
  199. position: absolute;
  200. min-width: 80px;
  201. margin-left: -75%;
  202. text-align: center;
  203. padding: 7.5px 6px;
  204. border-radius: 2px;
  205. background-color: #323232;
  206. font-size: .9em;
  207. color: #fff;
  208. content: attr(data-tooltip);
  209. opacity: 0;
  210. transition: all .2s ease-in-out .1s;
  211. visibility: hidden;
  212. }
  213. &:hover:after {
  214. opacity: 1;
  215. visibility: visible;
  216. }
  217. }
  218. .tooltip-top {
  219. &:after {
  220. bottom: 150%;
  221. }
  222. &:hover {
  223. &:after { bottom: 120%; }
  224. }
  225. }
  226. .tooltip-bottom {
  227. &:after {
  228. top: 155%;
  229. }
  230. &:hover {
  231. &:after { top: 125%; }
  232. }
  233. }
  234. .tooltip-left {
  235. &:after {
  236. bottom: -10px;
  237. right: 130%;
  238. min-width: 100px;
  239. }
  240. &:hover {
  241. &:after { right: 110%; }
  242. }
  243. }
  244. .tooltip-right {
  245. &:after {
  246. bottom: -10px;
  247. left: 190%;
  248. min-width: 100px;
  249. }
  250. &:hover {
  251. &:after { left: 200%; }
  252. }
  253. }
  254. .button:focus, .button:active { border-color: #dbdbdb !important; }
  255. .input:focus, .input:active { border-color: #03a9f4 !important; }
  256. button.delete:focus { background-color: rgba(10, 10, 10, 0.3); }
  257. .tag { padding-right: 6px !important; }
  258. .button.is-success { background-color: #00B16A !important; }
  259. </style>