user.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /* eslint no-param-reassign: 0 */
  2. /* eslint-disable import/no-cycle */
  3. import validation from "@/validation";
  4. import ws from "@/ws";
  5. import auth from "@/api/auth";
  6. const state = {};
  7. const getters = {};
  8. const actions = {};
  9. const mutations = {};
  10. const modules = {
  11. auth: {
  12. namespaced: true,
  13. state: {
  14. userIdMap: {},
  15. userIdRequested: {},
  16. pendingUserIdCallbacks: {},
  17. loggedIn: false,
  18. role: "",
  19. username: "",
  20. email: "",
  21. userId: "",
  22. banned: false,
  23. ban: {},
  24. gotData: false
  25. },
  26. actions: {
  27. /* eslint-disable-next-line */
  28. register: ({ commit }, user) =>
  29. new Promise((resolve, reject) => {
  30. const { username, email, password } = user;
  31. if (!email || !username || !password)
  32. reject(new Error("Please fill in all fields"));
  33. else if (!validation.isLength(email, 3, 254))
  34. reject(
  35. new Error(
  36. "Email must have between 3 and 254 characters."
  37. )
  38. );
  39. else if (
  40. email.indexOf("@") !== email.lastIndexOf("@") ||
  41. !validation.regex.emailSimple.test(email)
  42. )
  43. reject(new Error("Invalid email format."));
  44. else if (!validation.isLength(username, 2, 32))
  45. reject(
  46. new Error(
  47. "Username must have between 2 and 32 characters."
  48. )
  49. );
  50. else if (!validation.regex.azAZ09_.test(username))
  51. reject(
  52. new Error(
  53. "Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _."
  54. )
  55. );
  56. else if (username.replaceAll(/[_]/g, "").length === 0)
  57. reject(
  58. new Error(
  59. "Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _, and there has to be at least one letter or number."
  60. )
  61. );
  62. else if (!validation.isLength(password, 6, 200))
  63. reject(
  64. new Error(
  65. "Password must have between 6 and 200 characters."
  66. )
  67. );
  68. else if (!validation.regex.password.test(password))
  69. reject(
  70. new Error(
  71. "Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character."
  72. )
  73. );
  74. else
  75. auth.register(user)
  76. .then(res => resolve(res))
  77. .catch(err => reject(new Error(err.message)));
  78. }),
  79. /* eslint-disable-next-line */
  80. login: ({ commit }, user) =>
  81. new Promise((resolve, reject) => {
  82. auth.login(user)
  83. .then(() => {
  84. lofig.get("cookie.SIDname").then(sid => {
  85. const bc = new BroadcastChannel(
  86. `${sid}.user_login`
  87. );
  88. bc.postMessage(true);
  89. bc.close();
  90. });
  91. resolve({
  92. status: "success",
  93. message: "Logged in!"
  94. });
  95. })
  96. .catch(err => reject(new Error(err.message)));
  97. }),
  98. logout: () =>
  99. new Promise<void>((resolve, reject) => {
  100. auth.logout()
  101. .then(() => resolve())
  102. .catch(() => reject());
  103. }),
  104. getBasicUser: ({ commit, state }, userId) =>
  105. new Promise(resolve => {
  106. if (typeof state.userIdMap[`Z${userId}`] !== "string") {
  107. if (state.userIdRequested[`Z${userId}`] !== true) {
  108. commit("requestingUserId", userId);
  109. ws.socket.dispatch(
  110. "users.getBasicUser",
  111. userId,
  112. res => {
  113. if (res.status === "success") {
  114. const user = res.data;
  115. commit("mapUserId", {
  116. userId,
  117. user: {
  118. name: user.name,
  119. username: user.username
  120. }
  121. });
  122. state.pendingUserIdCallbacks[
  123. `Z${userId}`
  124. ].forEach(cb => cb(user));
  125. commit("clearPendingCallbacks", userId);
  126. return resolve(user);
  127. }
  128. return resolve(null);
  129. }
  130. );
  131. } else {
  132. commit("pendingUser", {
  133. userId,
  134. callback: user => resolve(user)
  135. });
  136. }
  137. } else {
  138. resolve(state.userIdMap[`Z${userId}`]);
  139. }
  140. }),
  141. authData: ({ commit }, data) => {
  142. commit("authData", data);
  143. },
  144. banUser: ({ commit }, ban) => {
  145. commit("banUser", ban);
  146. },
  147. updateUsername: ({ commit }, username) => {
  148. commit("updateUsername", username);
  149. }
  150. },
  151. mutations: {
  152. mapUserId(state, data) {
  153. state.userIdMap[`Z${data.userId}`] = data.user;
  154. state.userIdRequested[`Z${data.userId}`] = false;
  155. },
  156. requestingUserId(state, userId) {
  157. state.userIdRequested[`Z${userId}`] = true;
  158. if (!state.pendingUserIdCallbacks[`Z${userId}`])
  159. state.pendingUserIdCallbacks[`Z${userId}`] = [];
  160. },
  161. pendingUser(state, data) {
  162. state.pendingUserIdCallbacks[`Z${data.userId}`].push(
  163. data.callback
  164. );
  165. },
  166. clearPendingCallbacks(state, userId) {
  167. state.pendingUserIdCallbacks[`Z${userId}`] = [];
  168. },
  169. authData(state, data) {
  170. state.loggedIn = data.loggedIn;
  171. state.role = data.role;
  172. state.username = data.username;
  173. state.email = data.email;
  174. state.userId = data.userId;
  175. state.gotData = true;
  176. },
  177. banUser(state, ban) {
  178. state.banned = true;
  179. state.ban = ban;
  180. },
  181. updateUsername(state, username) {
  182. state.username = username;
  183. }
  184. }
  185. },
  186. playlists: {
  187. namespaced: true,
  188. state: {
  189. playlists: [],
  190. fetchedPlaylists: false
  191. },
  192. actions: {
  193. setPlaylists: ({ commit }, playlists) =>
  194. commit("setPlaylists", playlists),
  195. updatePlaylists: ({ commit }, playlists) =>
  196. commit("updatePlaylists", playlists),
  197. addPlaylist: ({ commit }, playlist) =>
  198. commit("addPlaylist", playlist),
  199. removePlaylist: ({ commit }, playlistId) =>
  200. commit("removePlaylist", playlistId)
  201. },
  202. mutations: {
  203. setPlaylists(state, playlists) {
  204. state.fetchedPlaylists = true;
  205. state.playlists = playlists;
  206. },
  207. updatePlaylists(state, playlists) {
  208. state.playlists = playlists;
  209. },
  210. addPlaylist(state, playlist) {
  211. state.playlists.push(playlist);
  212. },
  213. removePlaylist(state, playlistId) {
  214. state.playlists.forEach((playlist, index) => {
  215. if (playlist._id === playlistId)
  216. state.playlists.splice(index, 1);
  217. });
  218. }
  219. }
  220. },
  221. preferences: {
  222. namespaced: true,
  223. state: {
  224. nightmode: false,
  225. autoSkipDisliked: true,
  226. activityLogPublic: false,
  227. anonymousSongRequests: false,
  228. activityWatch: false
  229. },
  230. actions: {
  231. changeNightmode: ({ commit }, nightmode) => {
  232. commit("changeNightmode", nightmode);
  233. },
  234. changeAutoSkipDisliked: ({ commit }, autoSkipDisliked) => {
  235. commit("changeAutoSkipDisliked", autoSkipDisliked);
  236. },
  237. changeActivityLogPublic: ({ commit }, activityLogPublic) => {
  238. commit("changeActivityLogPublic", activityLogPublic);
  239. },
  240. changeAnonymousSongRequests: (
  241. { commit },
  242. anonymousSongRequests
  243. ) => {
  244. commit("changeAnonymousSongRequests", anonymousSongRequests);
  245. },
  246. changeActivityWatch: ({ commit }, activityWatch) => {
  247. commit("changeActivityWatch", activityWatch);
  248. }
  249. },
  250. mutations: {
  251. changeNightmode(state, nightmode) {
  252. state.nightmode = nightmode;
  253. },
  254. changeAutoSkipDisliked(state, autoSkipDisliked) {
  255. state.autoSkipDisliked = autoSkipDisliked;
  256. },
  257. changeActivityLogPublic(state, activityLogPublic) {
  258. state.activityLogPublic = activityLogPublic;
  259. },
  260. changeAnonymousSongRequests(state, anonymousSongRequests) {
  261. state.anonymousSongRequests = anonymousSongRequests;
  262. },
  263. changeActivityWatch(state, activityWatch) {
  264. state.activityWatch = activityWatch;
  265. }
  266. }
  267. }
  268. };
  269. export default {
  270. namespaced: true,
  271. state,
  272. getters,
  273. actions,
  274. mutations,
  275. modules
  276. };