Meteor.startup(function () { reCAPTCHA.config({ privatekey: '6LcVxg0TAAAAAI2fgIEEWHFxwNXeVIs8mzq5cfRM' }); Avatar.setOptions({ fallbackType: "initials", defaultImageUrl: "/notes.png", generateCSS: true, imageSizes: { 'header': 40 } }); var stations = [{tag: "edm", display: "EDM"}, {tag: "pop", display: "Pop"}]; //Rooms to be set on server startup for (var i in stations) { if (Rooms.find({type: stations[i]}).count() === 0) { createRoom(stations[i].display, stations[i].tag, false, "Room description goes here."); } } emojione.ascii = true; Accounts.config({ sendVerificationEmail: true }); if (Songs.find().count() === 0 || Songs.find({mid: default_song.mid}).count() === 0) { Songs.insert(default_song); } }); var default_song = { id: "xKVcVSYmesU", mid: "ABCDEF", likes: 0, dislikes: 0, title: "Immortals", artist: "Fall Out Boy", img: "http://c.directlyrics.com/img/upload/fall-out-boy-sixth-album-cover.jpg", type: "YouTube", duration: 181, skipDuration: 0, requestedBy: "NONE", approvedBy: "GOD", genres: ["edm", "pop"] }; var default_private_playlist = { name: "default", displayName: "Default Playlist", songs: [{id: "60ItHLz5WEA", duration: 213, title: "Alan Walker - Faded"}], owner: "NONE" }; Alerts.update({active: true}, {$set: {active: false}}, {multi: true}); var stations = []; var communityStations = []; var voteNum = 0; var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_"; function createUniqueSongId() { var code = ""; for (var i = 0; i < 6; i++) { code += chars[Math.floor(Math.random() * chars.length)]; } if (Playlists.find({"songs.mid": code}).count() > 0) { return createUniqueSongId(); } else { return code; } } function checkUsersPR() { var output = {}; var connections = Meteor.server.stream_server.open_sockets; _.each(connections, function (connection) { // named subscriptions if (connection._meteorSession !== undefined && connection._meteorSession !== null) { var subs = connection._meteorSession._namedSubs; //var ip = connection.remoteAddress; var used_subs = []; for (var sub in subs) { var mySubName = subs[sub]._name; if (subs[sub]._params.length > 0) { mySubName += subs[sub]._params[0]; // assume one id parameter for now } if (used_subs.indexOf(mySubName) === -1) { used_subs.push(mySubName); if (!output[mySubName]) { output[mySubName] = 1; } else { output[mySubName] += 1; } } } } // there are also these 'universal subscriptions' //not sure what these are, i count none in my tests //var usubs = connection._meteorSession._universalSubs; }); var emptyStations = []; var emptyCommunityStations = []; stations.forEach(function (station) { emptyStations.push(station); }); communityStations.forEach(function (station) { emptyCommunityStations.push(station); }); for (var key in output) { if (key.startsWith("pr_")) { var tempKey = key.substring(3); getCommunityStation(tempKey, function (station) { emptyCommunityStations.splice(emptyCommunityStations.indexOf(station), 1); CommunityStations.update({name: tempKey}, {$set: {users: output[key]}}); }); } else { getStation(key, function (station) { emptyStations.splice(emptyStations.indexOf(station), 1); Rooms.update({type: key}, {$set: {users: output[key]}}); }); } } emptyStations.forEach(function (emptyStation) { Rooms.update({type: emptyStation.type}, {$set: {users: 0}}); }); emptyCommunityStations.forEach(function (emptyStation) { CommunityStations.update({name: emptyStation.name}, {$set: {users: 0}}); }); return output; } function getStation(type, cb) { stations.forEach(function (station) { if (station.type === type) { cb(station); return; } }); //TODO Return error } function getCommunityStation(name, cb) { communityStations.forEach(function (station) { if (station.name === name) { cb(station); return; } }); //TODO Return error } function createRoom(display, tag, private, desc) { var type = tag; if (Rooms.find({type: type}).count() === 0) { Rooms.insert({ display: display, type: type, users: 0, private: private, currentSong: {song: default_song, started: 0}, roomDesc: desc }, function (err) { if (err) { throw err; } else { stations.push(new Station(type)); } }); } else { return "Room already exists"; } } function createCommunityStation(name, display, private, desc, owner) { if (CommunityStations.find({name: name}).count() === 0) { CommunityStations.insert({ name: name, displayName: display, private: private, roomDesc: desc, owner: owner }, function (err) { if (err) { throw err; } else { communityStations.push(new CommunityStation(name)); } }); } else { return "Community room with that name already exists"; } } function Station(type) { if (Playlists.find({type: type}).count() === 0) { Playlists.insert({type: type, songs: [default_song.mid], lastSong: 0}); } if (Songs.find({genres: type}).count() > 0) { var list = Songs.find({genres: type}).fetch(); list.forEach(function(song){ if (Playlists.findOne({type: type, songs: song.mid}) === undefined) { Playlists.update({type: type}, {$push: {songs: song.mid}}); } }); } if (Playlists.findOne({type: type}).songs.length === 0) { Playlists.update({type: type}, {$push: {songs: default_song.mid}}); } var usersObj = {}; Rooms.update({type: type}, {$set: {userList: []}}); Meteor.publish(type, function () { var user = Meteor.users.findOne(this.userId); if (this.userId !== undefined && user !== undefined && user.profile !== undefined && user.profile.username !== undefined) { var username = user.profile.username; if (usersObj[username] === undefined) { usersObj[username] = 1; } else { usersObj[username]++; } Rooms.update({type: type}, {$push: {userList: username}}); this.onStop(function() { usersObj[username]--; var list = Rooms.findOne({type: type}).userList; var index = list.indexOf(username); if (index >= 0) { list.splice(index, 1); Rooms.update({type: type}, {$set: {userList: list}}); } }); } return undefined; }); var self = this; var startedAt = Date.now(); var playlist = Playlists.findOne({type: type}); var songs = playlist.songs; var currentSong = playlist.lastSong; if (currentSong < (songs.length - 1)) { currentSong++; } else currentSong = 0; var currentMid = songs[currentSong]; var song = Songs.findOne({mid: currentMid}); if (song === undefined) { Playlists.remove({}, {$pull: {songs: currentMid}}); song = default_song; } var res = Rooms.update({type: type}, { $set: { currentSong: {song: song, started: startedAt}, users: 0 } }); this.skipSong = function () { self.voted = []; voteNum = 0; Rooms.update({type: type}, {$set: {votes: 0}}); songs = Playlists.findOne({type: type}).songs; songs.forEach(function (mid, index) { if (mid === currentMid) { currentSong = index; } }); if (currentSong < (songs.length - 1)) { currentSong++; } else currentSong = 0; if (songs); if (currentSong === 0) { this.shufflePlaylist(); } else { currentMid = songs[currentSong]; Playlists.update({type: type}, {$set: {lastSong: currentSong}}); Rooms.update({type: type}, {$set: {timePaused: 0}}); this.songTimer(); Rooms.update({type: type}, {$set: {currentSong: {song: Songs.findOne({mid: songs[currentSong]}), started: Date.now()}}}); } }; this.shufflePlaylist = function () { voteNum = 0; Rooms.update({type: type}, {$set: {votes: 0}}); self.voted = []; songs = Playlists.findOne({type: type}).songs; currentSong = 0; Playlists.update({type: type}, {$set: {"songs": []}}); songs = shuffle(songs); songs.forEach(function (song) { Playlists.update({type: type}, {$push: {"songs": song}}); }); currentMid = songs[currentSong]; Playlists.update({type: type}, {$set: {lastSong: currentSong}}); Rooms.update({type: type}, {$set: {timePaused: 0}}); this.songTimer(); Rooms.update({type: type}, {$set: {currentSong: {song: Songs.findOne({mid: songs[currentSong]}), started: Date.now()}}}); }; Rooms.update({type: type}, {$set: {timePaused: 0}}); var timer; var timerInitialised = false; this.songTimer = function () { if (state !== "paused") { startedAt = Date.now(); if (timer !== undefined) { timer.pause(); } timerInitialised = true; timer = new Timer(function () { self.skipSong(); }, Songs.findOne({mid: songs[currentSong]}).duration * 1000); } }; var state = Rooms.findOne({type: type}).state; this.pauseRoom = function () { if (state !== "paused") { timer.pause(); Rooms.update({type: type}, {$set: {state: "paused"}}); state = "paused"; } }; this.resumeRoom = function () { if (state !== "playing") { if (!timerInitialised) { timer = new Timer(function () { self.skipSong(); }, Songs.findOne({mid: songs[currentSong]}).duration * 1000); } timer.resume(); Rooms.update({type: type}, {$set: {state: "playing", timePaused: timer.timeWhenPaused()}}); state = "playing"; } }; this.cancelTimer = function () { timer.pause(); }; this.getState = function () { return state; }; this.type = type; var private = Rooms.findOne({type: type}).private; if (typeof private !== "boolean") { Rooms.update({type: type}, {$set: {"private": false}}); private = false; } this.private = private; this.unlock = function () { if (self.private) { self.private = false; Rooms.update({type: type}, {$set: {"private": false}}); } }; this.lock = function () { if (!self.private) { self.private = true; Rooms.update({type: type}, {$set: {"private": true}}); } }; /* This function fetches all songs with the genre of this room that isn't in the playlist yet, and then puts it in the playlist */ this.fetchSongs = function() { var genreSongs = Songs.find({genres: type}).fetch(); genreSongs.forEach(function(song) { if (songs.indexOf(song.mid) === -1) { Playlists.update({type: type}, {$push: {songs: song.mid}}); } }); }; /* This function removes all songs that are in the playlist but do not have the type of the playlist in their genre */ this.removeSongs = function() { songs.forEach(function(mid) { var song = Songs.findOne({mid: mid}); if (song === undefined || song.genres.indexOf(type) === -1) { Playlists.update({type: type}, {$pull: {songs: mid}}); } }); }; this.removeSongs(); this.fetchSongs(); this.skipSong(); this.voted = []; } function CommunityStation(name) { var usersObj = {}; CommunityStations.update({name: name}, {$set: {userList: []}}); Meteor.publish("pr_" + name, function () { var user = Meteor.users.findOne(this.userId); if (this.userId !== undefined && user !== undefined && user.profile !== undefined && user.profile.username !== undefined) { var username = user.profile.username; if (usersObj[username] === undefined) { usersObj[username] = 1; } else { usersObj[username]++; } CommunityStations.update({name: name}, {$push: {userList: username}}); this.onStop(function () { usersObj[username]--; var room = CommunityStations.findOne({name: name}); if (room !== undefined) { var list = room.userList; var index = list.indexOf(username); if (index >= 0) { list.splice(index, 1); CommunityStations.update({name: name}, {$set: {userList: list}}); } } }); } return undefined; }); this.isPartyModeEnabled = function() { return CommunityStations.findOne({name: name}).partyModeEnabled; }; var self = this; var startedAt = Date.now(); var _room = CommunityStations.findOne({name: name}); var playlist; if (_room !== undefined) { playlist = PrivatePlaylists.findOne({name: _room.playlist, owner: _room.owner}); } if (playlist === undefined) { playlist = default_private_playlist; } var songs = playlist.songs; var currentSong = 0; if (currentSong < (songs.length - 1)) { currentSong++; } else currentSong = 0; var currentId = songs[currentSong]; var song = songs[songs.indexOf(currentId)]; if (song === undefined) song = {}; if (this.isPartyModeEnabled()) { var res = CommunityStations.update({name: name}, { $set: { users: 0 } }); } else { var res = CommunityStations.update({name: name}, { $set: { currentSong: {song: song, started: startedAt}, users: 0 } }); } var queue = _room.queue; this.skipSong = function () { self.voted = []; voteNum = 0; CommunityStations.update({name: name}, {$set: {votes: 0}}); //TODO Party mode if (this.isPartyModeEnabled()) { var queue = CommunityStations.findOne({name: name}).queue; if (queue.length > 0) { CommunityStations.update({name: name}, {$pop: {queue: -1}}); queue.shift(); if (queue.length > 0) { CommunityStations.update({name: name}, { $set: { currentSong: { song: queue[0].song, requestedBy: queue[0].requestedBy, started: Date.now() } } }); CommunityStations.update({name: name}, {$set: {timePaused: 0}}); this.songTimer(); } else { CommunityStations.update({name: name}, { $set: { currentSong: {}, timePaused: 0 } }); } } else { CommunityStations.update({name: name}, {$set: {currentSong: {}}}); } } else { playlist = PrivatePlaylists.findOne({name: _room.playlist, owner: _room.owner}); if (playlist === undefined) { playlist = default_private_playlist; } if (playlist !== undefined && playlist.songs.length === 0) { CommunityStations.update({name: name}, {$unset: {"playlist": 1}}); playlist = default_private_playlist; } songs = playlist.songs; songs.forEach(function (id, index) { if (id === currentId) { currentSong = index; } }); if (currentSong < (songs.length - 1)) { currentSong++; } else currentSong = 0; currentId = songs[currentSong]; CommunityStations.update({name: name}, {$set: {timePaused: 0}}); this.songTimer(); CommunityStations.update({name: name}, { $set: { currentSong: { song: songs[currentSong], started: Date.now() } } }); } }; CommunityStations.update({name: name}, {$set: {timePaused: 0}}); var timer; var timerInitialised = false; this.songTimer = function () { if (state !== "paused") { startedAt = Date.now(); if (timer !== undefined) { timer.pause(); } timerInitialised = true; if (this.isPartyModeEnabled()) { if (timer !== undefined) { timer.resetTimeWhenPaused(); } timer = new Timer(function () { self.skipSong(); }, queue[0].song.duration * 1000); timerInitialised = true; } else { if (timer !== undefined) { timer.resetTimeWhenPaused(); } timer = new Timer(function () { self.skipSong(); }, songs[currentSong].duration * 1000); timerInitialised = true; } } else { startedAt = Date.now(); if (timer !== undefined) { timer.pause(); } timerInitialised = true; if (this.isPartyModeEnabled()) { if (timer !== undefined) { timer.resetTimeWhenPaused(); } timer = new Timer(function () { self.skipSong(); }, queue[0].song.duration * 1000); timerInitialised = true; timer.pause(); } else { if (timer !== undefined) { timer.resetTimeWhenPaused(); } timer = new Timer(function () { self.skipSong(); }, songs[currentSong].duration * 1000); timerInitialised = true; timer.pause(); } } }; var state = CommunityStations.findOne({name: name}).state; this.pauseRoom = function () { if (state !== "paused") { if (timer !== undefined) { timer.pause(); } CommunityStations.update({name: name}, {$set: {state: "paused"}}); state = "paused"; } }; this.resumeRoom = function () { if (state !== "playing") { if (this.isPartyModeEnabled()) { var station = CommunityStations.findOne({name: name}); queue = station.queue; if (queue.length === 0) { CommunityStations.update({name: name}, {$set: {currentSong: {}}}); } } if (!timerInitialised) { if (this.isPartyModeEnabled()) { if (queue.length > 0) { timer = new Timer(function () { self.skipSong(); }, queue[0].song.duration * 1000); timerInitialised = true; } } else { timer = new Timer(function () { self.skipSong(); }, songs[currentSong].duration * 1000); timerInitialised = true; } } if (timer !== undefined) { timer.resume(); CommunityStations.update({name: name}, {$set: {state: "playing", timePaused: timer.timeWhenPaused()}}); } else { CommunityStations.update({name: name}, {$set: {state: "playing"}}); } state = "playing"; } }; this.cancelTimer = function () { timer.pause(); }; this.getState = function () { return state; }; this.name = name; var privacy = CommunityStations.findOne({name: name}).privacy; this.privacy = privacy; this.setPrivacy = function (privacy) { if (self.privacy !== privacy) { self.privacy = privacy; return CommunityStations.update({name: name}, {$set: {"privacy": privacy}}); } }; this.setPlaylist = function (plName) { if (PrivatePlaylists.findOne({name: plName, owner: _room.owner}) !== undefined) { CommunityStations.update({name: name}, {$set: {"playlist": plName}}); _room.playlist = plName; playlist = PrivatePlaylists.findOne({name: plName, owner: _room.owner}); songs = playlist.songs; currentSong = 0; } }; this.addAllowed = function (allowed) { if (_room.allowed.indexOf(allowed) === -1 && _room.owner !== allowed) { CommunityStations.update({name: name}, {$push: {allowed: allowed}}); _room = CommunityStations.findOne({name: name}); } }; this.removeAllowed = function (allowed) { if (_room.allowed.indexOf(allowed) !== -1) { CommunityStations.update({name: name}, {$pull: {allowed: allowed}}); _room = CommunityStations.findOne({name: name}); } }; this.setPartyMode = function(partyMode) { partyMode = (typeof partyMode === "boolean") ? partyMode : false; CommunityStations.update({name: name}, { $set: { partyModeEnabled: partyMode, currentSong: {} } }); this.skipSong(); }; this.setQueueLocked = function(queueLocked) { queueLocked = (typeof queueLocked === "boolean") ? queueLocked : false; CommunityStations.update({name: name}, { $set: { queueLocked: queueLocked } }); this.queueLocked = queueLocked; }; this.addSongToQueue = function(id, userId) { if (!this.queueLocked) { var duplicate = false; queue = CommunityStations.findOne({name: name}).queue; queue.forEach(function (song) { if (song.song.id === id) { duplicate = true; } }); if (!duplicate) { var data = getSongDataYT(id); if (data !== 0) { var duration = data.duration; if ((this.getQueueDuration() + duration) <= 7200) { if ((this.getQueueDurationFromUser(userId) + duration) <= 900) { if ((this.getSongsInQueueFromUser(userId)) <= 1) { data.id = id; var res = CommunityStations.update( { name: name, "queue.song.id": {"$ne" : data.id} }, { $push: { queue: { requestedBy: userId, song: data } } }); if (res === 0) { throw new Meteor.Error(500, "Something went wrong there. Maybe your song is already in the queue?"); } queue = CommunityStations.findOne({name: name}).queue; if (queue.length === 1) { CommunityStations.update({name: name}, { $set: { timePaused: 0, currentSong: { song: queue[0].song, requestedBy: queue[0].requestedBy, started: Date.now() } } }); this.songTimer(); } } else { throw new Meteor.Error(500, "Adding this song would exceed your max amount of songs allowed in the queue (2 songs)."); } } else { throw new Meteor.Error(500, "Adding this song would exceed the max duration of your songs (15m)."); } } else { throw new Meteor.Error(500, "Adding this song would exceed the max duration of the queue (2h)."); } } else { throw new Meteor.Error(500, "Invalid song id."); } } else { throw new Meteor.Error(500, "This song is already in the queue."); } } else { throw new Meteor.Error(500, "The queue is currently locked."); } }; this.removeSongFromQueue = function(id) { var exists = false; var obj; var station = CommunityStations.findOne({name: name}); queue = station.queue; queue.forEach(function(song) { if (song.song.id === id) { obj = song; exists = true; } }); if (exists) { CommunityStations.update({name: name}, {$pull: {queue: obj}}); if (station.currentSong.song.id === id) { this.skipSong(); } return true; } else { throw new Meteor.Error(500, "This song is not in the queue."); } }; this.getQueueDuration = function() { var queue = CommunityStations.findOne({name: name}).queue; var totalDuration = 0; queue.forEach(function(song) { totalDuration += song.song.duration; }); return totalDuration; }; this.getQueueDurationFromUser = function(userId) { var queue = CommunityStations.findOne({name: name}).queue; var totalDuration = 0; queue.forEach(function(song) { if (song.requestedBy === userId) { totalDuration += song.song.duration; } }); return totalDuration; }; this.getSongsInQueueFromUser = function(userId) { var queue = CommunityStations.findOne({name: name}).queue; var totalSongs = 0; queue.forEach(function(song) { if (song.requestedBy === userId) { totalSongs++; } }); return totalSongs; }; this.queuelocked = _room.queueLocked; this.skipSong(); this.voted = []; } function shuffle(array) { var currentIndex = array.length, temporaryValue, randomIndex; // While there remain elements to shuffle... while (0 !== currentIndex) { // Pick a remaining element... randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; // And swap it with the current element. temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue; } return array; } function Timer(callback, delay) { var timerId, start, remaining = delay; var timeWhenPaused = 0; var timePaused = Date.now(); this.pause = function () { Meteor.clearTimeout(timerId); remaining -= Date.now() - start; timePaused = Date.now(); }; this.resume = function () { start = Date.now(); Meteor.clearTimeout(timerId); timerId = Meteor.setTimeout(callback, remaining); timeWhenPaused += Date.now() - timePaused; }; this.resetTimeWhenPaused = function() { timeWhenPaused = 0; }; this.timeWhenPaused = function () { return timeWhenPaused; }; this.resume(); } Meteor.users.deny({ update: function () { return true; } }); Meteor.users.deny({ insert: function () { return true; } }); Meteor.users.deny({ remove: function () { return true; } }); function getSongDuration(query, artistName) { var duration; var search = query; var res = Meteor.http.get('https://api.spotify.com/v1/search?q=' + encodeURIComponent(query) + '&type=track'); for (var i in res.data) { for (var j in res.data[i].items) { if (search.indexOf(res.data[i].items[j].name) !== -1 && artistName.indexOf(res.data[i].items[j].artists[0].name) !== -1) { duration = res.data[i].items[j].duration_ms / 1000; return duration; } } } return 0; } function getSongDataYT(id) { var res = Meteor.http.get('https://www.googleapis.com/youtube/v3/videos?id=' + encodeURIComponent(id) + '&part=snippet,contentDetails&key=AIzaSyAgBdacEWrHCHVPPM4k-AFM7uXg-Q__YXY'); if (res.data !== undefined && res.data.items.length !== 0) { var dur = res.data.items[0].contentDetails.duration; dur = dur.replace("PT", ""); var durInSec = 0; dur = dur.replace(/([\d]*)H/, function(v, v2) { v2 = Number(v2); durInSec = (v2 * 60 * 60) return ""; }); dur = dur.replace(/([\d]*)M/, function(v, v2) { v2 = Number(v2); durInSec = (v2 * 60) return ""; }); dur = dur.replace(/([\d]*)S/, function(v, v2) { v2 = Number(v2); durInSec += v2; return ""; }); return {duration: durInSec, title: res.data.items[0].snippet.title}; } else { return 0; } } function getSongAlbumArt(query, artistName) { var albumart; var search = query; var res = Meteor.http.get('https://api.spotify.com/v1/search?q=' + encodeURIComponent(query) + '&type=track'); for (var i in res.data) { for (var j in res.data[i].items) { if (search.indexOf(res.data[i].items[j].name) !== -1 && artistName.indexOf(res.data[i].items[j].artists[0].name) !== -1) { albumart = res.data[i].items[j].album.images[1].url return albumart; } } } } //var room_types = ["edm", "nightcore"]; var songsArr = []; Rooms.find({}).fetch().forEach(function (room) { var type = room.type; if (Playlists.find({type: type}).count() === 0) { Playlists.insert({type: type, songs: []}); } if (Playlists.findOne({type: type}).songs.length === 0) { Playlists.update({type: type}, {$push: {songs: default_song.mid}}, function() { stations.push(new Station(type)); }); } else { stations.push(new Station(type)); } }); CommunityStations.find({}).fetch().forEach(function (room) { var name = room.name; communityStations.push(new CommunityStation(name)); }); Accounts.validateNewUser(function (user) { var username; if (user.services) { if (user.services.github) { username = user.services.github.username; } else if (user.services.facebook) { username = user.services.facebook.first_name; } else if (user.services.password) { username = user.username; } } if (Meteor.users.find({"profile.usernameL": username.toLowerCase()}).count() !== 0) { throw new Meteor.Error(403, "An account with that username already exists."); } else { return true; } }); Accounts.onCreateUser(function (options, user) { var username; if (user.services) { if (user.services.github) { username = user.services.github.username; } else if (user.services.facebook) { username = user.services.facebook.first_name; } else if (user.services.password) { username = user.username; } } user.profile = { username: username, usernameL: username.toLowerCase(), rank: "default", liked: [], disliked: [], settings: {showRating: true}, realname: "" }; return user; }); Meteor.publish("alerts", function () { return Alerts.find({active: true}) }); Meteor.publish("allAlerts", function () { return Alerts.find({}) }); Meteor.publish("news", function () { return News.find({}) }); Meteor.publish("userData", function (userId) { if (userId !== undefined) { return Meteor.users.find(userId, {fields: {"services.github.username": 1, "punishments": 1}}); } else { return undefined; } }); Meteor.publish("usernames", function () { return Meteor.users.find({}, {fields: {"profile.username": 1, "profile.usernameL": 1}}) }); Meteor.publish("playlists", function () { return Playlists.find({}) }); Meteor.publish("rooms", function () { return Rooms.find({}); }); Meteor.publish("community_stations", function () { var userId = this.userId; if (userId) { var user = Meteor.users.findOne(userId); if (user.profile.rank === "admin" || user.profile.rank === "moderator") { return CommunityStations.find({}); } else { return CommunityStations.find({$or: [{owner: userId}, {privacy: "public"}]}); } } else { return CommunityStations.find({privacy: "public"}); } }); Meteor.publish("community_station", function (name) { var userId = this.userId; if (userId) { var user = Meteor.users.findOne(userId); if (user.profile.rank === "admin" || user.profile.rank === "moderator") { return CommunityStations.find({name: name}); } else { return CommunityStations.find({name: name, $or: [{owner: userId}, {privacy: "public"}]}); } } else { return CommunityStations.find({name: name, $or: [{privacy: "public"}, {privacy: "unlisted"}]}); } }); Meteor.publish("private_playlists", function () { if (this.userId !== undefined) { return PrivatePlaylists.find({owner: this.userId}); } else { return null; } }); Meteor.publish("songsType", function (type) { return Songs.find({genres: type}); }); Meteor.publish("songs", function () { return Songs.find(); }); Meteor.publish("queues", function () { return Queues.find({}); }); Meteor.publish("reports", function () { return Reports.find({}); }); Meteor.publish("chat", function () { return Chat.find({}); }); Meteor.publish("userProfiles", function (username) { username = username.toLowerCase(); var settings = Meteor.users.findOne({"profile.usernameL": username}, {fields: {"profile.settings": 1}}); if (settings !== undefined && settings.profile.settings) { settings = settings.profile.settings; if (settings.showRating === true) { return Meteor.users.find({"profile.usernameL": username}, { fields: { "profile.username": 1, "profile.usernameL": 1, "profile.rank": 1, createdAt: 1, "profile.liked": 1, "profile.disliked": 1, "profile.settings": 1, "profile.realname": 1 } }); } } return Meteor.users.find({"profile.usernameL": username}, { fields: { "profile.username": 1, "profile.usernameL": 1, "profile.rank": 1, createdAt: 1, "profile.settings": 1, "profile.realname": 1 } }); }); Meteor.publish("isAdmin", function () { return Meteor.users.find({_id: this.userId, "profile.rank": "admin"}); }); Meteor.publish("isModerator", function () { return Meteor.users.find({_id: this.userId, "profile.rank": "moderator"}); }); Meteor.publish("feedback", function(){ return Feedback.find(); }) function isCommunityStationOwner(name) { var room = CommunityStations.findOne({name: name}); if (Meteor.userId() && room !== undefined && Meteor.userId() === room.owner) { return true; } else { return false; } } function isAdmin() { var userData = Meteor.users.find(Meteor.userId()); if (Meteor.userId() && userData.count !== 0 && userData.fetch()[0].profile.rank === "admin") { return true; } else { return false; } } function isModerator() { var userData = Meteor.users.find(Meteor.userId()); if (Meteor.userId() && userData.count !== 0 && userData.fetch()[0].profile.rank === "moderator") { return true; } else { return isAdmin(); } } function isBanned() { var userData = Meteor.users.findOne(Meteor.userId()); if (Meteor.userId() && userData !== undefined && userData.punishments !== undefined && userData.punishments.ban !== undefined) { var ban = userData.punishments.ban; if (new Date(ban.bannedUntil).getTime() <= new Date().getTime()) { Meteor.users.update(Meteor.userId(), {$unset: {"punishments.ban": ""}}); return false; } else { return true; } } else { return false; } } function isMuted() { var userData = Meteor.users.findOne(Meteor.userId()); if (Meteor.userId() && userData !== undefined && userData.punishments !== undefined && userData.punishments.mute !== undefined) { var mute = userData.punishments.mute; if (new Date(mute.bannedUntil).getTime() <= new Date().getTime()) { Meteor.users.update(Meteor.userId(), {$unset: {"punishments.mute": ""}}); return false; } else { return true; } } else { return false; } } Meteor.updatedMethods({ deleteCommunityStation: function(roomName) { if ((isAdmin() || isCommunityStationOwner(roomName)) && !isBanned()) { CommunityStations.remove({name: roomName}); getCommunityStation(roomName, function(room) { room.cancelTimer(); delete communityStations[communityStations.indexOf(room)]; }); } else { throw new Meteor.Error(403, "Invalid permissions."); } }, changeCommunityStationDescription: function(roomName, newDescription) { if ((isAdmin() || isCommunityStationOwner(roomName)) && !isBanned()) { CommunityStations.update({name: roomName}, {$set: {roomDesc: newDescription}}); } else { throw new Meteor.Error(403, "Invalid permissions."); } }, changeCommunityStationDisplayName: function(roomName, newDisplayName) { if ((isAdmin() || isCommunityStationOwner(roomName)) && !isBanned()) { CommunityStations.update({name: roomName}, {$set: {displayName: newDisplayName}}); } else { throw new Meteor.Error(403, "Invalid permissions."); } }, changeCommunityStationPrivacy: function(roomName, newPrivacy) { if ((isAdmin() || isCommunityStationOwner(roomName)) && !isBanned()) { CommunityStations.update({name: roomName}, {$set: {privacy: newPrivacy}}); } else { throw new Meteor.Error(403, "Invalid permissions."); } }, setCommunityStationPartyMode: function(roomName, partyMode) { if ((isAdmin() || isCommunityStationOwner(roomName)) && !isBanned()) { getCommunityStation(roomName, function(room) { if (room !== 0) { room.setPartyMode(partyMode); } else { throw new Meteor.Error(500, "Room not found."); } }); } else { throw new Meteor.Error(403, "Invalid permissions."); } }, setCommunityStationQueueLocked: function(roomName, queueLocked) { if ((isAdmin() || isCommunityStationOwner(roomName)) && !isBanned()) { getCommunityStation(roomName, function(room) { if (room !== 0) { room.setQueueLocked(queueLocked); } else { throw new Meteor.Error(500, "Room not found."); } }); } else { throw new Meteor.Error(403, "Invalid permissions."); } }, addSongToCommunityStationQueue: { code: function(name, id) { getCommunityStation(name, function(station) { station.addSongToQueue(id, Meteor.userId()); }); }, requirements: ["login"] }, addVideoToPrivatePlaylist: { code: function(name, id) { var pl = PrivatePlaylists.findOne({owner: Meteor.userId(), name: name}); if (pl !== undefined) { var copy = false; pl.songs.forEach(function(song) { if (song.id === id) { copy = true; } }); if (!copy) { var data = getSongDataYT(id); data.id = id; PrivatePlaylists.update({owner: Meteor.userId(), name: name}, {$push: {songs: data}}); } else { throw new Meteor.Error(500, "Video is already in playlist."); } } else { throw new Meteor.Error(404, "Playlist not found."); } }, requirements: ["login"] }, removeVideoFromPrivatePlaylist: { code: function(name, id) { var pl = PrivatePlaylists.findOne({owner: Meteor.userId(), name: name}); if (pl !== undefined) { var copy = false; var data; pl.songs.forEach(function(song) { if (song.id === id) { data = song; copy = true; } }); if (copy) { PrivatePlaylists.update({owner: Meteor.userId(), name: name}, {$pull: {songs: data}}); } else { throw new Meteor.Error(500, "Video is not in playlist."); } } else { throw new Meteor.Error(404, "Playlist not found."); } }, requirements: ["login"] }, moveVideoToTopOfPrivatePlaylist: { code: function(name, id) { var pl = PrivatePlaylists.findOne({owner: Meteor.userId(), name: name}); if (pl !== undefined) { var songs = pl.songs; var song; songs.forEach(function(currentSong) { if (id === currentSong.id) { song = currentSong; } }); if (song !== undefined) { var index = songs.indexOf(song); if (index > 0 && songs.length > 1) { PrivatePlaylists.update({owner: Meteor.userId(), name: name}, {$pull: {songs: song}}); PrivatePlaylists.update({owner: Meteor.userId(), name: name}, {$push: { songs: { $each: [song], $position: 0 } }}); return true; } else { return false; } } else { throw new Meteor.Error(404, "Song not found."); } } else { throw new Meteor.Error(404, "Playlist not found."); } }, requirements: ["login"] }, moveVideoToBottomOfPrivatePlaylist: { code: function(name, id) { var pl = PrivatePlaylists.findOne({owner: Meteor.userId(), name: name}); if (pl !== undefined) { var songs = pl.songs; var song; songs.forEach(function(currentSong) { if (id === currentSong.id) { song = currentSong; } }); if (song !== undefined) { var index = songs.indexOf(song); if (index < (songs.length - 1) && index !== -1) { PrivatePlaylists.update({owner: Meteor.userId(), name: name}, {$pull: {songs: song}}); PrivatePlaylists.update({owner: Meteor.userId(), name: name}, {$push: {songs: song}}); return true; } } else { throw new Meteor.Error(404, "Song not found."); } } else { throw new Meteor.Error(404, "Playlist not found."); } }, requirements: ["login"] }, deletePrivatePlaylist: { code: function(name) { var pl = PrivatePlaylists.findOne({owner: Meteor.userId(), name: name}); if (pl !== undefined) { PrivatePlaylists.remove({owner: Meteor.userId(), name: name}); Deleted.insert({type: "PrivatePlaylist", data: pl}); } else { throw new Meteor.Error(404, "Playlist not found."); } }, requirements: ["login"] }, renamePrivatePlaylistDisplayName: { code: function(name, newDisplayName) { var pl = PrivatePlaylists.findOne({owner: Meteor.userId(), name: name}); if (pl !== undefined) { if (PrivatePlaylists.findOne({owner: Meteor.userId(), displayName: newDisplayName}) === undefined) { PrivatePlaylists.update({owner: Meteor.userId(), name: name}, {$set: {displayName: newDisplayName}}); } else { throw new Meteor.Error(500, "A playlist with that display name already exists."); } } else { throw new Meteor.Error(404, "Playlist not found."); } }, requirements: ["login"] }, renamePrivatePlaylistName: { code: function(name, newName) { var pl = PrivatePlaylists.findOne({owner: Meteor.userId(), name: name}); if (pl !== undefined) { if (PrivatePlaylists.findOne({owner: Meteor.userId(), name: newName}) === undefined) { var currentName = pl.name; PrivatePlaylists.update({owner: Meteor.userId(), name: name}, {$set: {name: newName}}); var stations = CommunityStations.find({owner: Meteor.userId(), playlist: currentName}).fetch(); stations.forEach(function(stationObj) { getCommunityStation(stationObj.name, function(station) { station.setPlaylist(newName); }); }); } else { throw new Meteor.Error(500, "A playlist with that name already exists."); } } else { throw new Meteor.Error(404, "Playlist not found."); } }, requirements: ["login"] }, activateAlert: { code: function(id) { Alerts.update(id, {$set: {active: true}}); }, requirements: ["admin"] }, deactivateAlert: { code: function(id) { Alerts.update(id, {$set: {active: false}}); }, requirements: ["admin"] }, deleteAlert: { code: function(id) { Alerts.remove(id); }, requirements: ["admin"] }, fetchSong: { code: function(type) { getStation(type, function (station) { station.fetchSongs(); }); }, requirements: ["admin"] }, removeSongs: { code: function(type) { getStation(type, function (station) { station.removeSongs(); }); }, requirements: ["admin"] }, lockRoom: { code: function (type) { getStation(type, function (station) { station.lock(); }); }, requirements: ["admin"] }, unlockRoom: { code: function (type) { getStation(type, function (station) { station.unlock(); }); }, requirements: ["admin"] }, banUser: { code: function (username, period, reason) { var user = Meteor.user(); var bannedUser = Meteor.users.findOne({"profile.usernameL": username.toLowerCase()}); var bannedUntil = (new Date).getTime() + (period * 1000); if (bannedUntil > 8640000000000000) { bannedUntil = 8640000000000000; } bannedUntil = new Date(bannedUntil); var banObject = { bannedBy: user.profile.usernameL, bannedAt: new Date(Date.now()), bannedReason: reason, bannedUntil: bannedUntil }; Meteor.users.update({"profile.usernameL": bannedUser.profile.usernameL}, {$set: {"punishments.ban": banObject}}); Meteor.users.update({"profile.usernameL": bannedUser.profile.usernameL}, {$push: {"punishments.bans": banObject}}); }, requirements: ["admin"] }, muteUser: { code: function (username, period) { var user = Meteor.user(); var mutedUser = Meteor.users.findOne({"profile.usernameL": username.toLowerCase()}); if (period === undefined || Number(period) === 0) { mutedUntil = 8640000000000000; } else { var mutedUntil = (new Date).getTime() + (period * 1000); if (mutedUntil > 8640000000000000) { mutedUntil = 8640000000000000; } } mutedUntil = new Date(mutedUntil); var muteObject = {mutedBy: user.profile.usernameL, mutedAt: new Date(Date.now()), mutedUntil: mutedUntil}; Meteor.users.update({"profile.usernameL": mutedUser.profile.usernameL}, {$set: {"punishments.mute": muteObject}}); Meteor.users.update({"profile.usernameL": mutedUser.profile.usernameL}, {$push: {"punishments.mutes": muteObject}}); }, requirements: ["admin"] }, unbanUser: { code: function (username) { Meteor.users.update({"profile.usernameL": username.toLowerCase()}, {$unset: "punishments.ban"}); }, requirements: ["admin"] }, unsilenceUser: { code: function (username) { Meteor.users.update({"profile.usernameL": username.toLowerCase()}, {$unset: "punishments.mute"}); }, requirements: ["admin"] }, isBanned: function () { return Meteor.isBanned(); }, isMuted: function () { return isMuted(); }, updateSettings: { code: function (showRating) { var user = Meteor.user(); if (showRating !== true && showRating !== false) { showRating = true; } if (user.profile.settings) { Meteor.users.update({"profile.username": user.profile.username}, {$set: {"profile.settings.showRating": showRating}}); } else { Meteor.users.update({"profile.username": user.profile.username}, {$set: {"profile.settings": {showRating: showRating}}}); } }, requirements: ["login"] }, addAlert: { code: function (description) { var username = Meteor.user().profile.username; description = htmlEntities(description); Alerts.insert({description: description, active: true, createdBy: username}); return true; }, requirements: ["admin"] }, sendMessage: { code: function (type, message) { var user = Meteor.user(); var time = new Date(); var rawrank = user.profile.rank; var username = user.profile.username; var profanity = false; message = htmlEntities(message); if (!message.replace(/\s/g, "").length > 0) { throw new Meteor.Error(406, "Message length cannot be 0."); } if (message.length > 300) { throw new Meteor.Error(406, "Message length cannot be more than 300 characters long.."); } else if (user.profile.rank === "admin") { /*HTTP.call("GET", "http://www.wdyl.com/profanity?q=" + encodeURIComponent(message), function (err, res) { if (res.content.indexOf("true") > -1) { return true; } else {*/ Chat.insert({ type: type, rawrank: rawrank, rank: "[A]", message: message, time: time, username: username }); /*} });*/ return true; } else if (user.profile.rank === "moderator") { /*HTTP.call("GET", "http://www.wdyl.com/profanity?q=" + encodeURIComponent(message), function (err, res) { if (res.content.indexOf("true") > -1) { return true; } else {*/ Chat.insert({ type: type, rawrank: rawrank, rank: "[M]", message: message, time: time, username: username }); /*} });*/ return true; } else { /*HTTP.call("GET", "http://www.wdyl.com/profanity?q=" + encodeURIComponent(message), function (err, res) { if (res.content.indexOf("true") > -1) { return true; } else {*/ Chat.insert({ type: type, rawrank: rawrank, rank: "", message: message, time: time, username: username }); /*} });*/ return true; } }, requirements: ["login", "noMute"] }, likeSong: { code: function (mid) { var user = Meteor.user(); if (user.profile.liked.indexOf(mid) === -1) { Meteor.users.update({"profile.username": user.profile.username}, {$push: {"profile.liked": mid}}); Songs.update({mid: mid}, {$inc: {"likes": 1}}) } else { Meteor.users.update({"profile.username": user.profile.username}, {$pull: {"profile.liked": mid}}); Songs.update({mid: mid}, {$inc: {likes: -1}}) } if (user.profile.disliked.indexOf(mid) !== -1) { Meteor.users.update({"profile.username": user.profile.username}, {$pull: {"profile.disliked": mid}}); Songs.update({mid: mid}, {$inc: {dislikes: -1}}) } return true; }, requirements: ["login"] }, dislikeSong: { code: function (mid) { var user = Meteor.user(); if (user.profile.disliked.indexOf(mid) === -1) { Meteor.users.update({"profile.username": user.profile.username}, {$push: {"profile.disliked": mid}}); Songs.update({mid: mid}, {$inc: {dislikes: 1}}); } else { Meteor.users.update({"profile.username": user.profile.username}, {$pull: {"profile.disliked": mid}}); Songs.update({mid: mid}, {$inc: {dislikes: -1}}); } if (user.profile.liked.indexOf(mid) !== -1) { Meteor.users.update({"profile.username": user.profile.username}, {$pull: {"profile.liked": mid}}); Songs.update({mid: mid}, {$inc: {likes: -1}}); } return true; }, requirements: ["login"] }, voteSkip: { code: function (type) { var user = Meteor.user(); getStation(type, function (station) { if (station.voted.indexOf(user.profile.username) === -1) { station.voted.push(user.profile.username); Rooms.update({type: type}, {$set: {votes: station.voted.length}}); if (station.voted.length === 3) { station.skipSong(); } } else { throw new Meteor.Error(401, "Already voted."); } }); }, requirements: ["login"] }, votePrivateSkip: { code: function (name) { var user = Meteor.user(); getCommunityStation(name, function (station) { if (station.voted.indexOf(user.profile.username) === -1) { station.voted.push(user.profile.username); CommunityStations.update({name: name}, {$set: {votes: station.voted.length}}); if (station.voted.length === 3) { station.skipSong(); } } else { throw new Meteor.Error(401, "Already voted."); } }); }, requirements: ["login"] }, submitReport: { code: function (room, reportData) { room = room.toLowerCase(); if (Rooms.find({type: room}).count() === 1) { if (Reports.find({room: room}).count() === 0) { Reports.insert({room: room, report: []}); } if (reportData !== undefined) { Reports.update({room: room}, { $push: { report: { song: reportData.song, type: reportData.type, reason: reportData.reason, other: reportData.other } } }); return true; } else { throw new Meteor.Error(403, "Invalid data."); } } else { throw new Meteor.Error(403, "Invalid genre."); } }, requirements: ["login"] }, shufflePlaylist: { code: function (type) { getStation(type, function (station) { if (station === undefined) { throw new Meteor.Error(404, "Station not found."); } else { station.cancelTimer(); station.shufflePlaylist(); } }); }, requirements: ["admin"] }, skipSong: { code: function (type) { getStation(type, function (station) { if (station === undefined) { throw new Meteor.Error(404, "Station not found."); } else { station.skipSong(); } }); }, requirements: ["admin"] }, pauseRoom: { code: function (type) { getStation(type, function (station) { if (station === undefined) { throw new Meteor.Error(403, "Room doesn't exist."); } else { station.pauseRoom(); } }); }, requirements: ["admin"] }, resumeRoom: { code: function (type) { getStation(type, function (station) { if (station === undefined) { throw new Meteor.Error(403, "Room doesn't exist."); } else { station.resumeRoom(); } }); }, requirements: ["admin"] }, skipPrivateSong: function (name) { if ((isAdmin() || isCommunityStationOwner(name)) && !isBanned()) { getCommunityStation(name, function (station) { if (station === undefined) { throw new Meteor.Error(404, "Station not found."); } else { station.skipSong(); } }); } }, pauseCommunityStation: function (name) { if ((isAdmin() || isCommunityStationOwner(name)) && !isBanned()) { getCommunityStation(name, function (station) { if (station === undefined) { throw new Meteor.Error(403, "Room doesn't exist."); } else { station.pauseRoom(); } }); } else { throw new Meteor.Error(403, "Invalid permissions."); } }, resumeCommunityStation: function (name) { if ((isAdmin() || isCommunityStationOwner(name)) && !isBanned()) { getCommunityStation(name, function (station) { if (station === undefined) { throw new Meteor.Error(403, "Room doesn't exist."); } else { station.resumeRoom(); } }); } else { throw new Meteor.Error(403, "Invalid permissions."); } }, removeIdFromCommunityStationQueue: function (name, id) { if (isCommunityStationOwner(name) && !isBanned()) { getCommunityStation(name, function (station) { if (station === undefined) { throw new Meteor.Error(403, "Room doesn't exist."); } else { station.removeSongFromQueue(id); } }); } else { throw new Meteor.Error(403, "Invalid permissions."); } }, addAllowedToCommunityStation: function (name, allowed) { if (isCommunityStationOwner(name) && !isBanned()) { getCommunityStation(name, function (station) { if (station === undefined) { throw new Meteor.Error(403, "Room doesn't exist."); } else { allowed = allowed.toLowerCase(); allowed = Meteor.users.findOne({"profile.usernameL": allowed})._id; station.addAllowed(allowed); } }); } else { throw new Meteor.Error(403, "Invalid permissions."); } }, removeAllowedFromCommunityStation: function (name, allowed) { if (isCommunityStationOwner(name) && !isBanned()) { getCommunityStation(name, function (station) { if (station === undefined) { throw new Meteor.Error(403, "Room doesn't exist."); } else { station.removeAllowed(allowed); } }); } else { throw new Meteor.Error(403, "Invalid permissions."); } }, setPlaylistForCommunityStation: function (name, playlist) { if ((isCommunityStationOwner(name)) && !isBanned()) { getCommunityStation(name, function (station) { if (station === undefined) { throw new Meteor.Error(403, "Room doesn't exist."); } else { station.setPlaylist(playlist); } }); } else { throw new Meteor.Error(403, "Invalid permissions."); } }, createUserMethod: { code: function (formData, captchaData) { var verifyCaptchaResponse = reCAPTCHA.verifyCaptcha(this.connection.clientAddress, captchaData); if (!verifyCaptchaResponse.success) { throw new Meteor.Error(422, 'reCAPTCHA Failed: ' + verifyCaptchaResponse.error); } else { Accounts.createUser({ username: formData.username, email: formData.email, password: formData.password }); } return true; }, requirements: [] }, promoteUserMethod: { code: function(user) { Meteor.users.find({"profile.usernameL": username.toLowerCase()}) } }, createArticle: { code: function(data) { var userId = Meteor.userId(); var requiredProperties = ["title", "content", "anonymous"]; if (data !== undefined && Object.keys(data).length === requiredProperties.length) { for (var property in requiredProperties) { if (data[requiredProperties[property]] === undefined) { throw new Meteor.Error(403, "Invalid data."); } } if (data.anonymous === false) { data.author = Meteor.user().profile.username } else { data.author = "A Musare Admin"; } delete data.anonymous; data.time = new Date(); data.content = htmlEntities(data.content); News.insert(data, function(err, res) { if (err) { console.log(err); throw err.sanitizedError; } else { return true; } }); } else { throw new Meteor.Error(403, "Invalid data."); } }, requirements: ["moderator"] }, addSongToQueue: { code: function (songData) { var userId = Meteor.userId(); var requiredProperties = ["title", "artist", "id", "genres"]; if (songData !== undefined && Object.keys(songData).length === requiredProperties.length) { for (var property in requiredProperties) { if (songData[requiredProperties[property]] === undefined) { throw new Meteor.Error(403, "Invalid data."); } } songData.duration = Number(getSongDuration(songData.title, songData.artist)); songData.img = getSongAlbumArt(songData.title, songData.artist) | ""; songData.skipDuration = 0; songData.likes = 0; songData.dislikes = 0; songData.requestedBy = userId; var mid = createUniqueSongId(); if (mid !== undefined) { songData.mid = mid; Queues.insert(songData, function(err, res) { if (err) { console.log(err); throw err.sanitizedError; } else { var songsRequested = (Meteor.user().profile !== undefined && Meteor.user().profile.statistics !== undefined && Meteor.user().profile.statistics.songsRequested !== undefined) ? Meteor.user().profile.statistics.songsRequested : 0; songsRequested++; Meteor.users.update(Meteor.userId(), {$set: {"profile.statistics.songsRequested": songsRequested}}); // TODO Make mongo query use $inc correctly. return true; } }); } else { throw new Meteor.Error(500, "Am error occured."); } } else { throw new Meteor.Error(403, "Invalid data."); } }, requirements: ["login"] }, updateQueueSong: { code: function (mid, newSong) { Queues.update({mid: mid}, {$set: { "title": newSong.title, "artist": newSong.artist, "id": newSong.id, "img": newSong.img, "duration" : newSong.duration, "skipDuration" : newSong.skipDuration, "genres": newSong.genres }}, function(err) { console.log(err); if (err) { throw err.sanitizedError; } else { return true; } }); }, requirements: ["moderator"] }, updatePlaylistSong: { code: function (mid, newSong) { Songs.update({mid: mid}, {$set: { "title": newSong.title, "artist": newSong.artist, "id": newSong.id, "img": newSong.img, "duration": newSong.duration, "skipDuration": newSong.skipDuration, "approvedBy": Meteor.userId(), "genres": newSong.genres }}, function(err) { console.log(err); if (err) { throw err.sanitizedError; } else { return true; } }); return true; }, requirements: ["moderator"] }, removeSongFromQueue: { code: function (mid) { Queues.remove({mid: mid}); }, requirements: ["moderator"] }, removeSongFromPlaylist: { code: function (type, mid) { Playlists.update({type: type}, {$pull: {songs: mid}}); }, requirements: ["moderator"] }, deleteSong: { code: function (mid) { Songs.remove({mid: mid}) }, requirements: ["moderator"] }, addSongToPlaylist: { code: function (songData) { var requiredProperties = ["_id", "mid", "id", "title", "artist", "duration", "skipDuration", "img", "likes", "dislikes", "requestedBy", "genres"]; if (songData !== undefined && Object.keys(songData).length === requiredProperties.length) { for (var property in requiredProperties) { if (songData[requiredProperties[property]] === undefined) { throw new Meteor.Error(403, "Invalid data."); } } delete songData._id; songData.approvedBy = Meteor.userId(); Songs.insert(songData); Queues.remove({mid: songData.mid}); songData.genres.forEach(function(genre) { genre = genre.toLowerCase(); if (Playlists.findOne({type: genre}) === undefined) { Playlists.insert({type: genre, songs: [songData.mid]}); } else { Playlists.update({type: genre}, {$push: {songs: songData.mid}}); } }); return true; } else { throw new Meteor.Error(403, "Invalid data."); } }, requirements: ["moderator"] }, createRoom: { code: function (display, tag, private, desc) { createRoom(display, tag, private, desc); }, requirements: ["admin"] }, createCommunityStation: { code: function (name, display, private, desc) { name = name.toLowerCase(); createCommunityStation(name, display, private, desc, Meteor.userId()); }, requirements: ["login"] }, createPrivatePlaylist: { code: function (name, display) { name = name.toLowerCase(); if (PrivatePlaylists.findOne({name: name, owner: Meteor.userId()}) === undefined) { PrivatePlaylists.insert({name: name, displayName: display, songs: [{id: "60ItHLz5WEA", duration: 213, title: "Alan Walker - Faded"}], owner: Meteor.userId()}); } }, requirements: ["login"] }, deleteRoom: { code: function (type) { Rooms.remove({type: type}); return true; }, requirements: ["admin"] }, getUserNum: { code: function () { return Object.keys(Meteor.default_server.sessions).length; }, requirements: [] }, getTotalUsers: function () { return Meteor.users.find().count(); }, updateRealName: { code: function (realname) { var oldName = Meteor.users.findOne(Meteor.userId()).profile.realname; Meteor.users.update(Meteor.userId(), { $set: {"profile.realname": realname}, $push: {"profile.realnames": oldName} }); }, requirements: ["login"] }, updateUserName: { code: function (newUserName) { var oldUsername = Meteor.users.findOne(Meteor.userId()).profile.username; Meteor.users.update(Meteor.userId(), { $set: { "username": newUserName, "profile.username": newUserName, "profile.usernameL": newUserName.toLowerCase() }, $push: {"profile.usernames": oldUsername} }); }, requirements: ["login"] }, promoteUserRank: { code: function(username){ if (Meteor.userId()) { Meteor.users.update({"username": username}, {$set: {"profile.rank": "admin"}}); } else { throw new Meteor.Error(403, "Invalid permissions."); } } }, demoteUserRank: { code: function(username){ if (Meteor.userId()) { Meteor.users.update({"username": username}, {$set: {"profile.rank": "default"}}); } else { throw new Meteor.Error(403, "Invalid permissions."); } } }, deleteAccount: { code: function () { var user = Meteor.users.findOne(Meteor.userId()); Meteor.users.remove({_id: Meteor.userId()}); }, requirements: ["login"] }, sendFeedback: { code: function(message){ /*HTTP.call("GET", "http://www.wdyl.com/profanity?q=" + encodeURIComponent(message), function (err, res) { if (res.content.indexOf("true") > -1) { return true; } else {*/ Feedback.insert({ "username": Meteor.user().profile.username, "message": message, "upvotes": 0, "upvotedBy": [] }) /*} });*/ }, requirements: ["login"] }, upvoteFeedback: { code: function(message){ //TODO Fix feedback upvoting to use Id's if(Feedback.findOne({"message": message}).upvotedBy.indexOf(Meteor.user().profile.username) === -1){ Feedback.update({"message": message}, {$inc: {"upvotes": 1}}); Feedback.update({"message": message}, {$push: {"upvotedBy": Meteor.user().profile.username}}); } else{ Feedback.update({"message": message}, {$inc: {"upvotes": -1}}); Feedback.update({"message": message}, {$pull: {"upvotedBy": Meteor.user().profile.username}}); } }, requirements: ["login"] }, deleteFeedback: { code: function(message){ Feedback.remove({"message": message}); }, requirements: ["admin"] }, updateFeedback: { code: function(oldMessage, newMessage){ Feedback.update({"message": oldMessage}, {$set: {"message": newMessage}}); }, requirements: ["admin"] }, editRoomDesc: { code: function(type, description){ Rooms.update({type: type}, {$set: {"roomDesc": description}}); }, requirements: ["admin"] }, removeReport: { code: function(query, obj){ Reports.update(query, {$pull: {"report": obj}}); }, requirements: ["admin"] } }); Meteor.setInterval(function () { checkUsersPR(); }, 10000); Meteor.users.after.insert(function (err, user) { Accounts.sendVerificationEmail(user._id); }); function htmlEntities(str) { return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); }