2013-02-22 15:41:12 -05:00
|
|
|
/**
|
|
|
|
A data model representing a user on Discourse
|
2013-02-20 13:15:50 -05:00
|
|
|
|
2013-02-22 15:41:12 -05:00
|
|
|
@class User
|
|
|
|
@extends Discourse.Model
|
|
|
|
@namespace Discourse
|
|
|
|
@module Discourse
|
|
|
|
**/
|
|
|
|
Discourse.User = Discourse.Model.extend({
|
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
Large version of this user's avatar.
|
|
|
|
|
|
|
|
@property avatarLarge
|
|
|
|
@type {String}
|
|
|
|
**/
|
2013-02-22 15:41:12 -05:00
|
|
|
avatarLarge: (function() {
|
|
|
|
return Discourse.Utilities.avatarUrl(this.get('username'), 'large', this.get('avatar_template'));
|
|
|
|
}).property('username'),
|
|
|
|
|
2013-03-14 14:45:29 -04:00
|
|
|
/**
|
2013-03-13 16:43:16 -04:00
|
|
|
Small version of this user's avatar.
|
|
|
|
|
|
|
|
@property avatarSmall
|
|
|
|
@type {String}
|
|
|
|
**/
|
2013-02-22 15:41:12 -05:00
|
|
|
avatarSmall: (function() {
|
2013-04-18 03:22:59 -04:00
|
|
|
return Discourse.Utilities.avatarUrl(this.get('username'), 'small', this.get('avatar_template'));
|
2013-02-22 15:41:12 -05:00
|
|
|
}).property('username'),
|
|
|
|
|
2013-05-24 12:21:53 -04:00
|
|
|
searchContext: function() {
|
|
|
|
return ({ type: 'user', id: this.get('username_lower') });
|
|
|
|
}.property('username_lower'),
|
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
This user's website.
|
|
|
|
|
|
|
|
@property websiteName
|
|
|
|
@type {String}
|
|
|
|
**/
|
2013-04-18 03:22:59 -04:00
|
|
|
websiteName: function() {
|
2013-02-22 15:41:12 -05:00
|
|
|
return this.get('website').split("/")[2];
|
2013-04-18 03:22:59 -04:00
|
|
|
}.property('website'),
|
|
|
|
|
|
|
|
hasWebsite: function() {
|
|
|
|
return this.present('website');
|
|
|
|
}.property('website'),
|
2013-02-22 15:41:12 -05:00
|
|
|
|
2013-05-02 03:40:44 -04:00
|
|
|
statusIcon: function() {
|
|
|
|
var desc;
|
|
|
|
if(this.get('admin')) {
|
2013-05-07 10:58:41 -04:00
|
|
|
desc = Em.String.i18n('user.admin', {user: this.get("name")});
|
2013-05-02 03:40:44 -04:00
|
|
|
return '<i class="icon icon-trophy" title="' + desc + '" alt="' + desc + '"></i>';
|
|
|
|
}
|
|
|
|
if(this.get('moderator')){
|
2013-05-07 10:58:41 -04:00
|
|
|
desc = Em.String.i18n('user.moderator', {user: this.get("name")});
|
2013-05-02 03:40:44 -04:00
|
|
|
return '<i class="icon icon-magic" title="' + desc + '" alt="' + desc + '"></i>';
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}.property('admin','moderator'),
|
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
Path to this user.
|
|
|
|
|
|
|
|
@property path
|
|
|
|
@type {String}
|
|
|
|
**/
|
2013-05-07 13:30:12 -04:00
|
|
|
path: function() {
|
2013-03-14 08:01:52 -04:00
|
|
|
return Discourse.getURL("/users/") + (this.get('username_lower'));
|
2013-05-07 13:30:12 -04:00
|
|
|
}.property('username'),
|
2013-03-14 08:01:52 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
Path to this user's administration
|
|
|
|
|
|
|
|
@property adminPath
|
|
|
|
@type {String}
|
|
|
|
**/
|
2013-05-07 13:30:12 -04:00
|
|
|
adminPath: function() {
|
2013-03-14 08:01:52 -04:00
|
|
|
return Discourse.getURL("/admin/users/") + (this.get('username_lower'));
|
2013-05-07 13:30:12 -04:00
|
|
|
}.property('username'),
|
2013-02-22 15:41:12 -05:00
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
This user's username in lowercase.
|
|
|
|
|
|
|
|
@property username_lower
|
|
|
|
@type {String}
|
|
|
|
**/
|
2013-05-07 13:30:12 -04:00
|
|
|
username_lower: function() {
|
2013-02-22 15:41:12 -05:00
|
|
|
return this.get('username').toLowerCase();
|
2013-05-07 13:30:12 -04:00
|
|
|
}.property('username'),
|
2013-02-22 15:41:12 -05:00
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
This user's trust level.
|
|
|
|
|
|
|
|
@property trustLevel
|
|
|
|
@type {Integer}
|
|
|
|
**/
|
2013-05-07 13:30:12 -04:00
|
|
|
trustLevel: function() {
|
2013-05-24 11:22:17 -04:00
|
|
|
return Discourse.Site.instance().get('trust_levels').findProperty('id', this.get('trust_level'));
|
2013-05-07 13:30:12 -04:00
|
|
|
}.property('trust_level'),
|
2013-02-22 15:41:12 -05:00
|
|
|
|
2013-03-14 14:45:29 -04:00
|
|
|
/**
|
2013-03-13 16:43:16 -04:00
|
|
|
Changes this user's username.
|
|
|
|
|
|
|
|
@method changeUsername
|
|
|
|
@param {String} newUsername The user's new username
|
|
|
|
@returns Result of ajax call
|
|
|
|
**/
|
2013-02-22 15:41:12 -05:00
|
|
|
changeUsername: function(newUsername) {
|
2013-05-07 13:30:12 -04:00
|
|
|
return Discourse.ajax("/users/" + (this.get('username_lower')) + "/preferences/username", {
|
2013-02-22 15:41:12 -05:00
|
|
|
type: 'PUT',
|
2013-05-07 13:30:12 -04:00
|
|
|
data: { new_username: newUsername }
|
2013-02-22 15:41:12 -05:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
Changes this user's email address.
|
|
|
|
|
|
|
|
@method changeEmail
|
|
|
|
@param {String} email The user's new email address\
|
|
|
|
@returns Result of ajax call
|
|
|
|
**/
|
2013-02-22 15:41:12 -05:00
|
|
|
changeEmail: function(email) {
|
2013-05-07 13:30:12 -04:00
|
|
|
return Discourse.ajax("/users/" + (this.get('username_lower')) + "/preferences/email", {
|
2013-02-22 15:41:12 -05:00
|
|
|
type: 'PUT',
|
2013-05-07 13:30:12 -04:00
|
|
|
data: { email: email }
|
2013-02-22 15:41:12 -05:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
Returns a copy of this user.
|
|
|
|
|
|
|
|
@method copy
|
|
|
|
@returns {User}
|
|
|
|
**/
|
|
|
|
copy: function() {
|
2013-02-22 15:41:12 -05:00
|
|
|
return Discourse.User.create(this.getProperties(Ember.keys(this)));
|
|
|
|
},
|
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
Save's this user's properties over AJAX via a PUT request.
|
|
|
|
|
|
|
|
@method save
|
2013-04-08 15:04:40 -04:00
|
|
|
@returns {Promise} the result of the operation
|
2013-03-13 16:43:16 -04:00
|
|
|
**/
|
2013-04-08 15:04:40 -04:00
|
|
|
save: function() {
|
|
|
|
var user = this;
|
2013-05-07 13:30:12 -04:00
|
|
|
return Discourse.ajax("/users/" + this.get('username').toLowerCase(), {
|
2013-02-22 15:41:12 -05:00
|
|
|
data: this.getProperties('auto_track_topics_after_msecs',
|
|
|
|
'bio_raw',
|
|
|
|
'website',
|
|
|
|
'name',
|
|
|
|
'email_digests',
|
|
|
|
'email_direct',
|
|
|
|
'email_private_messages',
|
|
|
|
'digest_after_days',
|
2013-03-13 16:43:16 -04:00
|
|
|
'new_topic_duration_minutes',
|
2013-03-12 23:06:58 -04:00
|
|
|
'external_links_in_new_tab',
|
|
|
|
'enable_quoting'),
|
2013-05-07 10:58:41 -04:00
|
|
|
type: 'PUT'
|
|
|
|
}).then(function(data) {
|
|
|
|
user.set('bio_excerpt',data.user.bio_excerpt);
|
2013-04-08 15:04:40 -04:00
|
|
|
Discourse.set('currentUser.enable_quoting', user.get('enable_quoting'));
|
|
|
|
Discourse.set('currentUser.external_links_in_new_tab', user.get('external_links_in_new_tab'));
|
2013-02-22 15:41:12 -05:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
Changes the password and calls the callback function on AJAX.complete.
|
|
|
|
|
|
|
|
@method changePassword
|
2013-04-08 15:04:40 -04:00
|
|
|
@returns {Promise} the result of the change password operation
|
2013-03-13 16:43:16 -04:00
|
|
|
**/
|
2013-04-08 15:04:40 -04:00
|
|
|
changePassword: function() {
|
2013-05-07 13:30:12 -04:00
|
|
|
return Discourse.ajax("/session/forgot_password", {
|
2013-02-22 15:41:12 -05:00
|
|
|
dataType: 'json',
|
|
|
|
data: {
|
2013-04-25 20:06:31 -04:00
|
|
|
login: this.get('username')
|
2013-02-22 15:41:12 -05:00
|
|
|
},
|
2013-04-08 15:04:40 -04:00
|
|
|
type: 'POST'
|
2013-02-22 15:41:12 -05:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
Loads a single user action by id.
|
|
|
|
|
|
|
|
@method loadUserAction
|
|
|
|
@param {Integer} id The id of the user action being loaded
|
|
|
|
@returns A stream of the user's actions containing the action of id
|
|
|
|
**/
|
2013-02-22 15:41:12 -05:00
|
|
|
loadUserAction: function(id) {
|
2013-04-08 15:04:40 -04:00
|
|
|
var user = this;
|
|
|
|
var stream = this.get('stream');
|
2013-05-07 13:30:12 -04:00
|
|
|
return Discourse.ajax("/user_actions/" + id + ".json", { cache: 'false' }).then(function(result) {
|
2013-04-08 15:04:40 -04:00
|
|
|
if (result) {
|
|
|
|
if ((user.get('streamFilter') || result.action_type) !== result.action_type) return;
|
2013-05-22 11:20:16 -04:00
|
|
|
var action = Discourse.UserAction.collapseStream([Discourse.UserAction.create(result)]);
|
|
|
|
stream.set('itemsLoaded', user.get('itemsLoaded') + 1);
|
|
|
|
stream.insertAt(0, action[0]);
|
2013-02-20 13:15:50 -05:00
|
|
|
}
|
2013-02-22 15:41:12 -05:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
The user's stat count, excluding PMs.
|
|
|
|
|
|
|
|
@property statsCountNonPM
|
|
|
|
@type {Integer}
|
|
|
|
**/
|
2013-05-20 16:52:37 -04:00
|
|
|
statsCountNonPM: function() {
|
|
|
|
if (this.blank('statsExcludingPms')) return 0;
|
|
|
|
return this.get('statsExcludingPms').getEach('count').reduce(function (accum, val) {
|
|
|
|
return accum + val;
|
2013-02-22 15:41:12 -05:00
|
|
|
});
|
2013-05-20 16:52:37 -04:00
|
|
|
}.property('statsExcludingPms.@each.count'),
|
2013-02-22 15:41:12 -05:00
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
The user's stats, excluding PMs.
|
|
|
|
|
|
|
|
@property statsExcludingPms
|
|
|
|
@type {Array}
|
|
|
|
**/
|
2013-05-20 16:52:37 -04:00
|
|
|
statsExcludingPms: function() {
|
|
|
|
if (this.blank('stats')) return [];
|
|
|
|
return this.get('stats').rejectProperty('isPM');
|
|
|
|
}.property('stats.@each.isPM'),
|
2013-02-22 15:41:12 -05:00
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
This user's stats, only including PMs.
|
|
|
|
|
|
|
|
@property statsPmsOnly
|
|
|
|
@type {Array}
|
|
|
|
**/
|
2013-05-20 16:52:37 -04:00
|
|
|
statsPmsOnly: function() {
|
|
|
|
if (this.blank('stats')) return [];
|
|
|
|
return this.get('stats').filterProperty('isPM');
|
|
|
|
}.property('stats.@each.isPM'),
|
2013-04-11 20:07:46 -04:00
|
|
|
|
2013-04-04 12:59:44 -04:00
|
|
|
|
2013-05-22 11:20:16 -04:00
|
|
|
findDetails: function() {
|
2013-04-04 12:59:44 -04:00
|
|
|
var user = this;
|
2013-05-22 11:20:16 -04:00
|
|
|
return PreloadStore.getAndRemove("user_" + user.get('username'), function() {
|
|
|
|
return Discourse.ajax("/users/" + user.get('username') + '.json');
|
2013-04-04 12:59:44 -04:00
|
|
|
}).then(function (json) {
|
|
|
|
json.user.stats = Discourse.User.groupStats(json.user.stats.map(function(s) {
|
2013-05-20 16:52:37 -04:00
|
|
|
if (s.count) s.count = parseInt(s.count, 10);
|
|
|
|
return Discourse.UserActionStat.create(s);
|
2013-04-04 12:59:44 -04:00
|
|
|
}));
|
|
|
|
|
|
|
|
user.setProperties(json.user);
|
2013-05-20 16:52:37 -04:00
|
|
|
return user;
|
2013-04-04 12:59:44 -04:00
|
|
|
});
|
2013-05-22 11:20:16 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
findStream: function(filter) {
|
|
|
|
if (Discourse.UserAction.statGroups[filter]) {
|
|
|
|
filter = Discourse.UserAction.statGroups[filter].join(",");
|
|
|
|
}
|
|
|
|
|
|
|
|
var stream = Discourse.UserStream.create({
|
2013-05-25 14:08:09 -04:00
|
|
|
itemsLoaded: 0,
|
2013-05-22 11:20:16 -04:00
|
|
|
content: [],
|
|
|
|
filter: filter,
|
|
|
|
user: this
|
|
|
|
});
|
|
|
|
|
|
|
|
stream.findItems();
|
|
|
|
return stream;
|
2013-04-04 12:59:44 -04:00
|
|
|
}
|
|
|
|
|
2013-02-22 15:41:12 -05:00
|
|
|
});
|
2013-02-20 13:15:50 -05:00
|
|
|
|
2013-02-22 15:41:12 -05:00
|
|
|
Discourse.User.reopenClass({
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
Checks if given username is valid for this email address
|
2013-02-22 15:41:12 -05:00
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
@method checkUsername
|
|
|
|
@param {String} username A username to check
|
|
|
|
@param {String} email An email address to check
|
|
|
|
**/
|
2013-02-22 15:41:12 -05:00
|
|
|
checkUsername: function(username, email) {
|
2013-05-07 13:30:12 -04:00
|
|
|
return Discourse.ajax('/users/check_username', {
|
|
|
|
data: { username: username, email: email }
|
2013-02-22 15:41:12 -05:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
Groups the user's statistics
|
|
|
|
|
|
|
|
@method groupStats
|
|
|
|
@param {Array} Given stats
|
|
|
|
@returns {Object}
|
|
|
|
**/
|
2013-02-22 15:41:12 -05:00
|
|
|
groupStats: function(stats) {
|
2013-05-20 16:52:37 -04:00
|
|
|
var responses = Discourse.UserActionStat.create({
|
|
|
|
count: 0,
|
|
|
|
action_type: Discourse.UserAction.RESPONSE
|
2013-02-22 15:41:12 -05:00
|
|
|
});
|
2013-05-20 16:52:37 -04:00
|
|
|
|
|
|
|
stats.filterProperty('isResponse').forEach(function (stat) {
|
|
|
|
responses.set('count', responses.get('count') + stat.get('count'));
|
2013-02-22 15:41:12 -05:00
|
|
|
});
|
2013-05-20 16:52:37 -04:00
|
|
|
|
|
|
|
var result = Em.A();
|
|
|
|
result.pushObject(responses);
|
|
|
|
result.pushObjects(stats.rejectProperty('isResponse'));
|
|
|
|
return(result);
|
2013-02-22 15:41:12 -05:00
|
|
|
},
|
2013-02-20 13:15:50 -05:00
|
|
|
|
2013-03-13 16:43:16 -04:00
|
|
|
/**
|
|
|
|
Creates a new account over POST
|
|
|
|
|
|
|
|
@method createAccount
|
|
|
|
@param {String} name This user's name
|
|
|
|
@param {String} email This user's email
|
|
|
|
@param {String} password This user's password
|
|
|
|
@param {String} passwordConfirm This user's confirmed password
|
|
|
|
@param {String} challenge
|
|
|
|
@returns Result of ajax call
|
|
|
|
**/
|
2013-02-22 15:41:12 -05:00
|
|
|
createAccount: function(name, email, password, username, passwordConfirm, challenge) {
|
2013-05-07 13:30:12 -04:00
|
|
|
return Discourse.ajax("/users", {
|
2013-02-22 15:41:12 -05:00
|
|
|
data: {
|
|
|
|
name: name,
|
|
|
|
email: email,
|
|
|
|
password: password,
|
|
|
|
username: username,
|
|
|
|
password_confirmation: passwordConfirm,
|
|
|
|
challenge: challenge
|
|
|
|
},
|
|
|
|
type: 'POST'
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|