Implement user profiles

Existing installations will have to apply the following SQL:
```sql
ALTER TABLE `registrations` ADD `profile_image` VARCHAR( 255 ) NOT NULL ,
ADD `profile_text` TEXT NOT NULL
```
This commit is contained in:
calzoneman 2013-05-12 20:41:02 -04:00
parent c6446d6f84
commit ebe48798fe
8 changed files with 83 additions and 50 deletions

View File

@ -502,7 +502,8 @@ Channel.prototype.sendUserlist = function(user) {
name: this.users[i].name, name: this.users[i].name,
rank: this.users[i].rank, rank: this.users[i].rank,
leader: this.users[i] == this.leader, leader: this.users[i] == this.leader,
meta: this.users[i].meta meta: this.users[i].meta,
profile: this.users[i].profile
}); });
} }
} }
@ -550,7 +551,8 @@ Channel.prototype.broadcastNewUser = function(user) {
name: user.name, name: user.name,
rank: user.rank, rank: user.rank,
leader: this.leader == user, leader: this.leader == user,
meta: user.meta meta: user.meta,
profile: user.profile
}); });
this.sendRankStuff(user); this.sendRankStuff(user);
if(user.rank > Rank.Guest) { if(user.rank > Rank.Guest) {
@ -558,12 +560,13 @@ Channel.prototype.broadcastNewUser = function(user) {
} }
} }
Channel.prototype.broadcastRankUpdate = function(user) { Channel.prototype.broadcastUserUpdate = function(user) {
this.sendAll("updateUser", { this.sendAll("updateUser", {
name: user.name, name: user.name,
rank: user.rank, rank: user.rank,
leader: this.leader == user, leader: this.leader == user,
meta: user.meta meta: user.meta,
profile: user.profile
}); });
this.sendRankStuff(user); this.sendRankStuff(user);
} }
@ -1317,7 +1320,7 @@ Channel.prototype.tryPromoteUser = function(actor, data) {
if(receiver.loggedIn) { if(receiver.loggedIn) {
this.saveRank(receiver); this.saveRank(receiver);
} }
this.broadcastRankUpdate(receiver); this.broadcastUserUpdate(receiver);
} }
else { else {
Database.saveChannelRank(this.name, { Database.saveChannelRank(this.name, {
@ -1357,7 +1360,7 @@ Channel.prototype.tryDemoteUser = function(actor, data) {
if(receiver.loggedIn) { if(receiver.loggedIn) {
this.saveRank(receiver); this.saveRank(receiver);
} }
this.broadcastRankUpdate(receiver); this.broadcastUserUpdate(receiver);
} }
else { else {
Database.saveChannelRank(this.name, { Database.saveChannelRank(this.name, {
@ -1374,7 +1377,7 @@ Channel.prototype.changeLeader = function(name) {
if(this.leader != null) { if(this.leader != null) {
var old = this.leader; var old = this.leader;
this.leader = null; this.leader = null;
this.broadcastRankUpdate(old); this.broadcastUserUpdate(old);
} }
if(name == "") { if(name == "") {
this.logger.log("*** Resuming autolead"); this.logger.log("*** Resuming autolead");
@ -1389,7 +1392,7 @@ Channel.prototype.changeLeader = function(name) {
if(this.users[i].name == name) { if(this.users[i].name == name) {
this.logger.log("*** Assigned leader: " + name); this.logger.log("*** Assigned leader: " + name);
this.leader = this.users[i]; this.leader = this.users[i];
this.broadcastRankUpdate(this.leader); this.broadcastUserUpdate(this.leader);
} }
} }
} }

View File

@ -69,6 +69,8 @@ exports.init = function() {
`global_rank` INT NOT NULL, \ `global_rank` INT NOT NULL, \
`session_hash` VARCHAR(64) NOT NULL, \ `session_hash` VARCHAR(64) NOT NULL, \
`expire` BIGINT NOT NULL, \ `expire` BIGINT NOT NULL, \
`profile_image` VARCHAR( 255 ) NOT NULL , \
`profile_text` TEXT NOT NULL, \
PRIMARY KEY (`id`)) \ PRIMARY KEY (`id`)) \
ENGINE = MyISAM;"; ENGINE = MyISAM;";
var results = db.querySync(query); var results = db.querySync(query);
@ -384,3 +386,19 @@ exports.getChannelRanks = function(channame) {
return []; return [];
} }
} }
exports.setProfile = function(name, data) {
var db = exports.getConnection();
if(!db) {
return false;
}
var query = "UPDATE registrations SET profile_image='{1}',profile_text='{2}' WHERE uname='{3}'"
.replace("{1}", sqlEscape(data.image))
.replace("{2}", sqlEscape(data.text))
.replace("{3}", sqlEscape(name));
var results = db.querySync(query);
db.closeSync();
return results;
}

View File

@ -2,7 +2,7 @@
"author": "Calvin Montgomery", "author": "Calvin Montgomery",
"name": "CyTube", "name": "CyTube",
"description": "Online media synchronizer and chat", "description": "Online media synchronizer and chat",
"version": "1.6.5", "version": "1.7.0",
"repository": { "repository": {
"url": "http://github.com/calzoneman/sync" "url": "http://github.com/calzoneman/sync"
}, },

View File

@ -9,7 +9,7 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
const VERSION = "1.6.5"; const VERSION = "1.7.0";
var fs = require("fs"); var fs = require("fs");
var Logger = require("./logger.js"); var Logger = require("./logger.js");

25
user.js
View File

@ -31,6 +31,10 @@ var User = function(socket, ip) {
}; };
this.throttle = {}; this.throttle = {};
this.flooded = {}; this.flooded = {};
this.profile = {
image: "",
text: ""
};
this.initCallbacks(); this.initCallbacks();
if(Server.announcement != null) { if(Server.announcement != null) {
@ -322,6 +326,23 @@ User.prototype.initCallbacks = function() {
this.channel.tryVoteskip(this); this.channel.tryVoteskip(this);
} }
}.bind(this)); }.bind(this));
this.socket.on("setProfile", function(data) {
if(!this.name) {
return;
}
data.image = data.image || "";
data.text = data.text || "";
if(data.text.length > 4000) {
data.text = data.text.substring(0, 4000);
}
if(Database.setProfile(this.name, data)) {
this.profile = data;
if(this.channel != null) {
this.channel.broadcastUserUpdate(this);
}
}
}.bind(this));
} }
// Handle administration // Handle administration
@ -415,6 +436,10 @@ User.prototype.login = function(name, pw, session) {
session: row.session_hash session: row.session_hash
}); });
Logger.syslog.log(this.ip + " logged in as " + name); Logger.syslog.log(this.ip + " logged in as " + name);
this.profile = {
image: row.profile_image,
text: row.profile_text
};
var chanrank = (this.channel != null) ? this.channel.getRank(name) var chanrank = (this.channel != null) ? this.channel.getRank(name)
: Rank.Guest; : Rank.Guest;
var rank = (chanrank > row.global_rank) ? chanrank var rank = (chanrank > row.global_rank) ? chanrank

View File

@ -406,6 +406,11 @@ Callbacks = {
} }
} }
div.appendTo($("#userlist")); div.appendTo($("#userlist"));
if(data.name == uname) {
PROFILE.image = data.profile.image;
PROFILE.text = data.profile.text;
}
}, },
updateUser: function(data) { updateUser: function(data) {

View File

@ -36,7 +36,7 @@ var uname = readCookie("sync_uname");
var session = readCookie("sync_session"); var session = readCookie("sync_session");
var PROFILE = { var PROFILE = {
image: "", image: "",
bio: "" text: ""
}; };
function parseBool(x) { function parseBool(x) {

View File

@ -15,6 +15,7 @@ function formatUserlistItem(div, data) {
$(name).removeClass(); $(name).removeClass();
$(name).css("font-style", ""); $(name).css("font-style", "");
$(name).addClass(getNameColor(data.rank)); $(name).addClass(getNameColor(data.rank));
$(div).find(".profile-box").remove();
var profile; var profile;
$(name).mouseenter(function(ev) { $(name).mouseenter(function(ev) {
@ -22,11 +23,14 @@ function formatUserlistItem(div, data) {
.addClass("profile-box") .addClass("profile-box")
.css("top", (ev.pageY + 5) + "px") .css("top", (ev.pageY + 5) + "px")
.css("left", ev.pageX + "px") .css("left", ev.pageX + "px")
.appendTo($("body")); .appendTo(div);
$("<img/>").addClass("profile-image") if(data.profile.image) {
.attr("src", "http://i.imgur.com/P8MIHkc.jpg") $("<img/>").addClass("profile-image")
.appendTo(profile); .attr("src", data.profile.image)
$("<p/>").text("I'm calzoneman, the developer of this site. Feel free to contact me with queries, comments, or praise about the site.").appendTo(profile); .appendTo(profile);
}
$("<strong/>").text(data.name).appendTo(profile);
$("<p/>").text(data.profile.text).appendTo(profile);
}); });
$(name).mousemove(function(ev) { $(name).mousemove(function(ev) {
profile.css("top", (ev.pageY + 5) + "px") profile.css("top", (ev.pageY + 5) + "px")
@ -649,7 +653,7 @@ function onWindowFocus() {
} }
function newPollMenu() { function newPollMenu() {
$("#ytapiplayer").hide(); var vid = $("#ytapiplayer").detach();
var modal = $("<div/>").addClass("modal hide fade") var modal = $("<div/>").addClass("modal hide fade")
.appendTo($("body")); .appendTo($("body"));
var head = $("<div/>").addClass("modal-header") var head = $("<div/>").addClass("modal-header")
@ -708,14 +712,14 @@ function newPollMenu() {
.appendTo(footer) .appendTo(footer)
.click(submit); .click(submit);
modal.on("hidden", function() { modal.on("hidden", function() {
$("#ytapiplayer").show(); vid.appendTo($("#videodiv"));
modal.remove(); modal.remove();
}); });
modal.modal(); modal.modal();
} }
function showLoginFrame() { function showLoginFrame() {
$("#ytapiplayer").hide(); var vid = $("#ytapiplayer").detach();
var modal = $("<div/>").addClass("modal hide fade") var modal = $("<div/>").addClass("modal hide fade")
.appendTo($("body")); .appendTo($("body"));
var head = $("<div/>").addClass("modal-header") var head = $("<div/>").addClass("modal-header")
@ -795,14 +799,14 @@ function showLoginFrame() {
} }
var footer = $("<div/>").addClass("modal-footer").appendTo(modal); var footer = $("<div/>").addClass("modal-footer").appendTo(modal);
modal.on("hidden", function() { modal.on("hidden", function() {
$("#ytapiplayer").show(); vid.appendTo($("#videodiv"));
modal.remove(); modal.remove();
}); });
modal.modal(); modal.modal();
} }
function showUserOpts() { function showUserOpts() {
$("#ytapiplayer").hide(); var vid = $("#ytapiplayer").detach();
var modal = $("<div/>").addClass("modal hide fade") var modal = $("<div/>").addClass("modal hide fade")
.appendTo($("body")); .appendTo($("body"));
var head = $("<div/>").addClass("modal-header") var head = $("<div/>").addClass("modal-header")
@ -888,8 +892,8 @@ function showUserOpts() {
var profbio = $("<textarea/>"); var profbio = $("<textarea/>");
profbio.attr("rows", 5); profbio.attr("rows", 5);
profbio.val(PROFILE.bio); profbio.val(PROFILE.text);
addOption("Profile Bio", profbio); addOption("Profile Text", profbio);
if(RANK >= Rank.Moderator) { if(RANK >= Rank.Moderator) {
$("<hr>").appendTo(form); $("<hr>").appendTo(form);
@ -906,6 +910,10 @@ function showUserOpts() {
.appendTo(footer); .appendTo(footer);
submit.click(function() { submit.click(function() {
socket.emit("setProfile", {
image: profimg.val(),
text: profbio.val()
});
USEROPTS.theme = themeselect.val(); USEROPTS.theme = themeselect.val();
USEROPTS.css = usercss.val(); USEROPTS.css = usercss.val();
USEROPTS.layout = layoutselect.val(); USEROPTS.layout = layoutselect.val();
@ -923,7 +931,7 @@ function showUserOpts() {
}); });
modal.on("hidden", function() { modal.on("hidden", function() {
$("#ytapiplayer").show(); vid.appendTo($("#videodiv"));
modal.remove(); modal.remove();
}); });
modal.modal(); modal.modal();
@ -976,32 +984,6 @@ function applyOpts() {
} }
} }
function showProfileModal(data) {
$("#ytapiplayer").hide();
var modal = $("<div/>").addClass("modal hide fade")
.appendTo($("body"));
var head = $("<div/>").addClass("modal-header")
.appendTo(modal);
$("<button/>").addClass("close")
.attr("data-dismiss", "modal")
.attr("aria-hidden", "true")
.appendTo(head)[0].innerHTML = "&times;";
$("<h3/>").text(data.name).appendTo(head);
var body = $("<div/>").addClass("modal-body").appendTo(modal);
$("<img/>").attr("src", data.image)
.css("width", "80px")
.css("height", "80px")
.appendTo(body)
$("<p/>").addClass("profile-text").appendTo(body).text(data.text);
//var footer = $("<div/>").addClass("modal-footer").appendTo(modal);
modal.on("hidden", function() {
$("#ytapiplayer").show();
modal.remove();
});
modal.modal();
}
function idToURL(data) { function idToURL(data) {
var entry = ""; var entry = "";
switch(data.type) { switch(data.type) {