index.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. 'use strict';
  2. const coreClass = require("../../core");
  3. const mongoose = require('mongoose');
  4. const config = require('config');
  5. /*const bluebird = require('bluebird');
  6. mongoose.Promise = bluebird;*/
  7. module.exports = class extends coreClass {
  8. initialize() {
  9. return new Promise((resolve, reject) => {
  10. this.setStage(1);
  11. this._schemas = {};
  12. this._models = {};
  13. const mongoUrl = config.get("mongo").url;
  14. mongoose.connect(mongoUrl, {
  15. useNewUrlParser: true,
  16. useCreateIndex: true,
  17. reconnectInterval: 3000,
  18. reconnectTries: 10
  19. })
  20. .then(() => {
  21. this._schemas = {
  22. convertSchema: new mongoose.Schema(require(`./schemas/convertSchema`)),
  23. accountSchema: new mongoose.Schema(require(`./schemas/accountSchema`)),
  24. account: new mongoose.Schema(require(`./schemas/account`))
  25. };
  26. this._models = {
  27. convertSchema: mongoose.model('convertSchema', this._schemas.convertSchema),
  28. accountSchema: mongoose.model('accountSchema', this._schemas.accountSchema),
  29. account: mongoose.model('account', this._schemas.account)
  30. };
  31. mongoose.connection.on('error', err => {
  32. this.logger.error("DB_MODULE", err);
  33. });
  34. mongoose.connection.on('disconnected', () => {
  35. this.logger.error("DB_MODULE", "Disconnected, going to try to reconnect...");
  36. this.setState("RECONNECTING");
  37. });
  38. mongoose.connection.on('reconnected', () => {
  39. this.logger.success("DB_MODULE", "Reconnected.");
  40. this.setState("INITIALIZED");
  41. });
  42. mongoose.connection.on('reconnectFailed', () => {
  43. this.logger.error("DB_MODULE", "Reconnect failed, stopping reconnecting.");
  44. this.failed = true;
  45. this._lockdown();
  46. });
  47. /*// User
  48. this.schemas.user.path('username').validate((username) => {
  49. return (isLength(username, 2, 32) && regex.custom("a-zA-Z0-9_-").test(username));
  50. }, 'Invalid username.');
  51. this.schemas.user.path('email.address').validate((email) => {
  52. if (!isLength(email, 3, 254)) return false;
  53. if (email.indexOf('@') !== email.lastIndexOf('@')) return false;
  54. return regex.emailSimple.test(email) && regex.ascii.test(email);
  55. }, 'Invalid email.');
  56. // Station
  57. this.schemas.station.path('name').validate((id) => {
  58. return (isLength(id, 2, 16) && regex.az09_.test(id));
  59. }, 'Invalid station name.');
  60. this.schemas.station.path('displayName').validate((displayName) => {
  61. return (isLength(displayName, 2, 32) && regex.ascii.test(displayName));
  62. }, 'Invalid display name.');
  63. this.schemas.station.path('description').validate((description) => {
  64. if (!isLength(description, 2, 200)) return false;
  65. let characters = description.split("");
  66. return characters.filter((character) => {
  67. return character.charCodeAt(0) === 21328;
  68. }).length === 0;
  69. }, 'Invalid display name.');
  70. this.schemas.station.path('owner').validate({
  71. validator: (owner) => {
  72. return new Promise((resolve, reject) => {
  73. this.models.station.countDocuments({ owner: owner }, (err, c) => {
  74. if (err) reject(new Error("A mongo error happened."));
  75. else if (c >= 3) reject(new Error("User already has 3 stations."));
  76. else resolve();
  77. });
  78. });
  79. },
  80. message: 'User already has 3 stations.'
  81. });
  82. /*
  83. this.schemas.station.path('queue').validate((queue, callback) => { //Callback no longer works, see station max count
  84. let totalDuration = 0;
  85. queue.forEach((song) => {
  86. totalDuration += song.duration;
  87. });
  88. return callback(totalDuration <= 3600 * 3);
  89. }, 'The max length of the queue is 3 hours.');
  90. this.schemas.station.path('queue').validate((queue, callback) => { //Callback no longer works, see station max count
  91. if (queue.length === 0) return callback(true);
  92. let totalDuration = 0;
  93. const userId = queue[queue.length - 1].requestedBy;
  94. queue.forEach((song) => {
  95. if (userId === song.requestedBy) {
  96. totalDuration += song.duration;
  97. }
  98. });
  99. return callback(totalDuration <= 900);
  100. }, 'The max length of songs per user is 15 minutes.');
  101. this.schemas.station.path('queue').validate((queue, callback) => { //Callback no longer works, see station max count
  102. if (queue.length === 0) return callback(true);
  103. let totalSongs = 0;
  104. const userId = queue[queue.length - 1].requestedBy;
  105. queue.forEach((song) => {
  106. if (userId === song.requestedBy) {
  107. totalSongs++;
  108. }
  109. });
  110. if (totalSongs <= 2) return callback(true);
  111. if (totalSongs > 3) return callback(false);
  112. if (queue[queue.length - 2].requestedBy !== userId || queue[queue.length - 3] !== userId) return callback(true);
  113. return callback(false);
  114. }, 'The max amount of songs per user is 3, and only 2 in a row is allowed.');
  115. */
  116. // Song
  117. /*let songTitle = (title) => {
  118. return isLength(title, 1, 100);
  119. };
  120. this.schemas.song.path('title').validate(songTitle, 'Invalid title.');
  121. this.schemas.queueSong.path('title').validate(songTitle, 'Invalid title.');
  122. this.schemas.song.path('artists').validate((artists) => {
  123. return !(artists.length < 1 || artists.length > 10);
  124. }, 'Invalid artists.');
  125. this.schemas.queueSong.path('artists').validate((artists) => {
  126. return !(artists.length < 0 || artists.length > 10);
  127. }, 'Invalid artists.');
  128. let songArtists = (artists) => {
  129. return artists.filter((artist) => {
  130. return (isLength(artist, 1, 64) && artist !== "NONE");
  131. }).length === artists.length;
  132. };
  133. this.schemas.song.path('artists').validate(songArtists, 'Invalid artists.');
  134. this.schemas.queueSong.path('artists').validate(songArtists, 'Invalid artists.');
  135. let songGenres = (genres) => {
  136. if (genres.length < 1 || genres.length > 16) return false;
  137. return genres.filter((genre) => {
  138. return (isLength(genre, 1, 32) && regex.ascii.test(genre));
  139. }).length === genres.length;
  140. };
  141. this.schemas.song.path('genres').validate(songGenres, 'Invalid genres.');
  142. this.schemas.queueSong.path('genres').validate(songGenres, 'Invalid genres.');
  143. let songThumbnail = (thumbnail) => {
  144. if (!isLength(thumbnail, 1, 256)) return false;
  145. if (config.get("cookie.secure") === true) return thumbnail.startsWith("https://");
  146. else return thumbnail.startsWith("http://") || thumbnail.startsWith("https://");
  147. };
  148. this.schemas.song.path('thumbnail').validate(songThumbnail, 'Invalid thumbnail.');
  149. this.schemas.queueSong.path('thumbnail').validate(songThumbnail, 'Invalid thumbnail.');
  150. // Playlist
  151. this.schemas.playlist.path('displayName').validate((displayName) => {
  152. return (isLength(displayName, 1, 32) && regex.ascii.test(displayName));
  153. }, 'Invalid display name.');
  154. this.schemas.playlist.path('createdBy').validate((createdBy) => {
  155. this.models.playlist.countDocuments({ createdBy: createdBy }, (err, c) => {
  156. return !(err || c >= 10);
  157. });
  158. }, 'Max 10 playlists per user.');
  159. this.schemas.playlist.path('songs').validate((songs) => {
  160. return songs.length <= 5000;
  161. }, 'Max 5000 songs per playlist.');
  162. this.schemas.playlist.path('songs').validate((songs) => {
  163. if (songs.length === 0) return true;
  164. return songs[0].duration <= 10800;
  165. }, 'Max 3 hours per song.');
  166. // Report
  167. this.schemas.report.path('description').validate((description) => {
  168. return (!description || (isLength(description, 0, 400) && regex.ascii.test(description)));
  169. }, 'Invalid description.');*/
  170. resolve();
  171. })
  172. .catch(err => {
  173. this.logger.error("DB_MODULE", err);
  174. reject(err);
  175. });
  176. })
  177. }
  178. async schema(name) {
  179. return new Promise(async resolve => {
  180. try { await this._validateHook(); } catch { return; }
  181. resolve(this._schemas[name]);
  182. });
  183. }
  184. async model(name) {
  185. return new Promise(async resolve => {
  186. try { await this._validateHook(); } catch { return; }
  187. resolve(this._models[name]);
  188. });
  189. }
  190. }