mirror of
https://github.com/discourse/discourse.git
synced 2025-03-09 14:34:35 +00:00
Each user activity filter has its own URL now.
This commit is contained in:
parent
3238e0caa4
commit
19f3a8d640
@ -4,7 +4,7 @@
|
||||
<div class='field'>{{i18n user.username.title}}</div>
|
||||
<div class='value'>{{username}}</div>
|
||||
<div class='controls'>
|
||||
{{#linkTo 'user.activity' content class="btn"}}
|
||||
{{#linkTo 'userActivity' class="btn"}}
|
||||
<i class='icon icon-user'></i>
|
||||
{{i18n admin.user.show_public_profile}}
|
||||
{{/linkTo}}
|
||||
|
@ -28,6 +28,26 @@ Discourse.computed = {
|
||||
}).property(p1, p2);
|
||||
},
|
||||
|
||||
/**
|
||||
Returns i18n version of a string based on a property.
|
||||
|
||||
@method i18n
|
||||
@params {String} properties* to format
|
||||
@params {String} format the i18n format string
|
||||
@return {Function} computedProperty function
|
||||
**/
|
||||
i18n: function() {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
var format = args.pop();
|
||||
var computed = Ember.computed(function() {
|
||||
var context = this;
|
||||
return I18n.t(format.fmt.apply(format, args.map(function (a) {
|
||||
return context.get(a);
|
||||
})));
|
||||
});
|
||||
return computed.property.apply(computed, args);
|
||||
},
|
||||
|
||||
/**
|
||||
Uses an Ember String `fmt` call to format a string. See:
|
||||
http://emberjs.com/api/classes/Ember.String.html#method_fmt
|
||||
@ -71,4 +91,5 @@ Discourse.computed = {
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
@ -1,3 +1,37 @@
|
||||
Discourse.UserActivityRoute = Discourse.Route.extend({
|
||||
renderTemplate: function() {
|
||||
this.render('user_activity', {into: 'user', outlet: 'userOutlet' });
|
||||
},
|
||||
|
||||
model: function() {
|
||||
return this.modelFor('user');
|
||||
}
|
||||
});
|
||||
|
||||
Discourse.UserActivityIndexRoute = Discourse.Route.extend({
|
||||
model: function() {
|
||||
return this.modelFor('user').findStream();
|
||||
},
|
||||
|
||||
setupController: function(controller, model) {
|
||||
this.controllerFor('userActivity').set('stream', model);
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(Discourse.UserAction.TYPES).forEach(function (userAction) {
|
||||
Discourse["UserActivity" + userAction.classify() + "Route"] = Discourse.UserActivityIndexRoute.extend({
|
||||
model: function() {
|
||||
return this.modelFor('user').findStream(Discourse.UserAction.TYPES[userAction]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Discourse.UserIndexRoute = Discourse.Route.extend({
|
||||
redirect: function() {
|
||||
this.transitionTo('userActivity.index');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
This controller supports all actions on a user's activity stream
|
||||
|
||||
@ -6,7 +40,7 @@
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.UserActivityController = Discourse.ObjectController.extend({
|
||||
Discourse.UserActivityController = Discourse.Controller.extend({
|
||||
needs: ['composer'],
|
||||
|
||||
kickOffPrivateMessage: (function() {
|
||||
|
@ -1,3 +1,68 @@
|
||||
/**
|
||||
Base route for showing private messages
|
||||
|
||||
@class UserPrivateMessagesRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.UserPrivateMessagesRoute = Discourse.Route.extend({
|
||||
renderTemplate: function() {
|
||||
this.render('user_private_messages', {into: 'user', outlet: 'userOutlet' });
|
||||
},
|
||||
|
||||
model: function() {
|
||||
return this.modelFor('user');
|
||||
},
|
||||
|
||||
setupController: function(controller, user) {
|
||||
var composerController = this.controllerFor('composer');
|
||||
controller.set('model', user);
|
||||
Discourse.Draft.get('new_private_message').then(function(data) {
|
||||
if (data.draft) {
|
||||
composerController.open({
|
||||
draft: data.draft,
|
||||
draftKey: 'new_private_message',
|
||||
ignoreIfChanged: true,
|
||||
draftSequence: data.draft_sequence
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Default private messages route
|
||||
|
||||
@class UserPrivateMessagesIndexRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.UserPrivateMessagesIndexRoute = Discourse.Route.extend({
|
||||
model: function() {
|
||||
return this.modelFor('user').findStream(Discourse.UserAction.TYPES.messages_received);
|
||||
},
|
||||
|
||||
setupController: function(controller, model) {
|
||||
this.controllerFor('userPrivateMessages').set('stream', model);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
Private messages sent route
|
||||
|
||||
@class UserPrivateMessagesSentRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.UserPrivateMessagesSentRoute = Discourse.UserPrivateMessagesIndexRoute.extend({
|
||||
model: function() {
|
||||
return this.modelFor('user').findStream(Discourse.UserAction.TYPES.messages_sent);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
This controller handles actions related to a user's private messages.
|
||||
|
||||
|
@ -270,8 +270,12 @@ Discourse.User = Discourse.Model.extend({
|
||||
},
|
||||
|
||||
findStream: function(filter) {
|
||||
if (Discourse.UserAction.statGroups[filter]) {
|
||||
filter = Discourse.UserAction.statGroups[filter].join(",");
|
||||
|
||||
// When filtering for replies, include mentions and quotes too
|
||||
if (filter === Discourse.UserAction.TYPES.replies) {
|
||||
filter = [Discourse.UserAction.TYPES.replies,
|
||||
Discourse.UserAction.TYPES.mentions,
|
||||
Discourse.UserAction.TYPES.quotes].join(",");
|
||||
}
|
||||
|
||||
var stream = Discourse.UserStream.create({
|
||||
@ -351,7 +355,7 @@ Discourse.User.reopenClass({
|
||||
groupStats: function(stats) {
|
||||
var responses = Discourse.UserActionStat.create({
|
||||
count: 0,
|
||||
action_type: Discourse.UserAction.RESPONSE
|
||||
action_type: Discourse.UserAction.TYPES.replies
|
||||
});
|
||||
|
||||
stats.filterProperty('isResponse').forEach(function (stat) {
|
||||
@ -363,7 +367,7 @@ Discourse.User.reopenClass({
|
||||
|
||||
var insertAt = 1;
|
||||
result.forEach(function(item, index){
|
||||
if(item.action_type === Discourse.UserAction.NEW_TOPIC || item.action_type === Discourse.UserAction.POST){
|
||||
if(item.action_type === Discourse.UserAction.TYPES.topics || item.action_type === Discourse.UserAction.TYPES.posts){
|
||||
insertAt = index + 1;
|
||||
}
|
||||
});
|
||||
|
@ -6,82 +6,100 @@
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
|
||||
var UserActionTypes = {
|
||||
likes_given: 1,
|
||||
likes_received: 2,
|
||||
bookmarks: 3,
|
||||
topics: 4,
|
||||
posts: 5,
|
||||
replies: 6,
|
||||
mentions: 7,
|
||||
quotes: 9,
|
||||
favorites: 10,
|
||||
edits: 11,
|
||||
messages_sent: 12,
|
||||
messages_received: 13
|
||||
};
|
||||
|
||||
var InvertedActionTypes = {};
|
||||
_.each(UserActionTypes, function (k, v) {
|
||||
InvertedActionTypes[k] = v;
|
||||
});
|
||||
|
||||
Discourse.UserAction = Discourse.Model.extend({
|
||||
|
||||
descriptionHtml: function() {
|
||||
var action = this.get('action_type');
|
||||
var ua = Discourse.UserAction;
|
||||
var actions = [ua.LIKE, ua.WAS_LIKED, ua.STAR, ua.EDIT, ua.BOOKMARK, ua.GOT_PRIVATE_MESSAGE, ua.NEW_PRIVATE_MESSAGE];
|
||||
var icon = "";
|
||||
var sentence = "";
|
||||
var sameUser = (this.get('username') === Discourse.User.current('username'));
|
||||
/**
|
||||
Return an i18n key we will use for the description text of a user action.
|
||||
|
||||
if (action === null || actions.indexOf(action) >= 0) {
|
||||
@property descriptionKey
|
||||
**/
|
||||
descriptionKey: function() {
|
||||
var action = this.get('action_type');
|
||||
if (action === null || Discourse.UserAction.TO_SHOW.indexOf(action) >= 0) {
|
||||
if (this.get('isPM')) {
|
||||
icon = '<i class="icon icon-envelope" title="{{i18n user.stream.private_message}}"></i>';
|
||||
if (sameUser) {
|
||||
sentence = I18n.t('user_action.sent_by_you', { userUrl: this.get('userUrl') });
|
||||
} else {
|
||||
sentence = I18n.t('user_action.sent_by_user', { user: this.get('name'), userUrl: this.get('userUrl') });
|
||||
}
|
||||
return this.get('sameUser') ? 'sent_by_you' : 'sent_by_user';
|
||||
} else {
|
||||
if (sameUser) {
|
||||
sentence = I18n.t('user_action.posted_by_you', { userUrl: this.get('userUrl') });
|
||||
} else {
|
||||
sentence = I18n.t('user_action.posted_by_user', { user: this.get('name'), userUrl: this.get('userUrl') });
|
||||
}
|
||||
return this.get('sameUser') ? 'posted_by_you' : 'posted_by_user';
|
||||
}
|
||||
} else if (action === ua.NEW_TOPIC) {
|
||||
if (sameUser) {
|
||||
sentence = I18n.t('user_action.you_posted_topic', { userUrl: this.get('userUrl'), topicUrl: this.get('replyUrl') });
|
||||
} else {
|
||||
sentence = I18n.t('user_action.user_posted_topic', { user: this.get('name'), userUrl: this.get('userUrl'), topicUrl: this.get('replyUrl') });
|
||||
}
|
||||
} else if (action === ua.POST || action === ua.RESPONSE) {
|
||||
if (this.get('reply_to_post_number')) {
|
||||
if (sameUser) {
|
||||
sentence = I18n.t('user_action.you_replied_to_post', { post_number: '#' + this.get('reply_to_post_number'),
|
||||
userUrl: this.get('userUrl'), postUrl: this.get('postUrl') });
|
||||
} else {
|
||||
sentence = I18n.t('user_action.user_replied_to_post', { user: this.get('name'),
|
||||
post_number: '#' + this.get('reply_to_post_number'), userUrl: this.get('userUrl'), postUrl: this.get('postUrl') });
|
||||
}
|
||||
} else {
|
||||
if (sameUser) {
|
||||
sentence = I18n.t('user_action.you_replied_to_topic', { userUrl: this.get('userUrl'),
|
||||
topicUrl: this.get('replyUrl') });
|
||||
} else {
|
||||
sentence = I18n.t('user_action.user_replied_to_topic', { user: this.get('name'),
|
||||
userUrl: this.get('userUrl'), topicUrl: this.get('replyUrl') });
|
||||
}
|
||||
}
|
||||
} else if (action === ua.MENTION) {
|
||||
if (sameUser) {
|
||||
sentence = I18n.t('user_action.you_mentioned_user', { user: this.get('target_name'),
|
||||
user1Url: this.get('userUrl'), user2Url: this.get('targetUserUrl') });
|
||||
} else {
|
||||
if (this.get('target_username') === Discourse.User.current('username')) {
|
||||
sentence = I18n.t('user_action.user_mentioned_you', { user: this.get('name'),
|
||||
user1Url: this.get('userUrl'), user2Url: this.get('targetUserUrl') });
|
||||
} else {
|
||||
sentence = I18n.t('user_action.user_mentioned_user', { user: this.get('name'),
|
||||
another_user: this.get('target_name'), user1Url: this.get('userUrl'), user2Url: this.get('targetUserUrl') });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
||||
return new Handlebars.SafeString(icon + " " + sentence);
|
||||
}.property(),
|
||||
if (this.get('topicType')) {
|
||||
return this.get('sameUser') ? 'you_posted_topic' : 'user_posted_topic';
|
||||
}
|
||||
|
||||
targetUserUrl: function() {
|
||||
return Discourse.Utilities.userUrl(this.get('target_username'));
|
||||
}.property(),
|
||||
if (this.get('postReplyType')) {
|
||||
if (this.get('reply_to_post_number')) {
|
||||
return this.get('sameUser') ? 'you_replied_to_post' : 'user_replied_to_post';
|
||||
} else {
|
||||
return this.get('sameUser') ? 'you_replied_to_topic' : 'user_replied_to_topic';
|
||||
}
|
||||
}
|
||||
|
||||
userUrl: function() {
|
||||
return Discourse.Utilities.userUrl(this.get('username'));
|
||||
}.property(),
|
||||
if (this.get('mentionType')) {
|
||||
if (this.get('sameUser')) {
|
||||
return 'you_mentioned_user';
|
||||
} else {
|
||||
return this.get('targetUser') ? 'user_mentioned_you' : 'user_mentioned_user';
|
||||
}
|
||||
}
|
||||
}.property('action_type'),
|
||||
|
||||
/**
|
||||
Returns the HTML representation of a user action's description, complete with icon.
|
||||
|
||||
@property descriptionHtml
|
||||
**/
|
||||
descriptionHtml: function() {
|
||||
var descriptionKey = this.get('descriptionKey');
|
||||
if (!descriptionKey) { return; }
|
||||
|
||||
var icon = this.get('isPM') ? '<i class="icon icon-envelope" title="{{i18n user.stream.private_message}}"></i>' : '';
|
||||
|
||||
return new Handlebars.SafeString(icon + " " + I18n.t("user_action." + descriptionKey, {
|
||||
userUrl: this.get('userUrl'),
|
||||
replyUrl: this.get('replyUrl'),
|
||||
postUrl: this.get('postUrl'),
|
||||
topicUrl: this.get('replyUrl'),
|
||||
user: this.get('name'),
|
||||
post_number: '#' + this.get('reply_to_post_number'),
|
||||
user1Url: this.get('userUrl'),
|
||||
user2Url: this.get('targetUserUrl'),
|
||||
another_user: this.get('target_name')
|
||||
}));
|
||||
|
||||
}.property('descriptionKey'),
|
||||
|
||||
sameUser: function() {
|
||||
return this.get('username') === Discourse.User.current('username');
|
||||
}.property('username'),
|
||||
|
||||
targetUser: function() {
|
||||
return this.get('target_username') === Discourse.User.current('username');
|
||||
}.property('target_username'),
|
||||
|
||||
targetUserUrl: Discourse.computed.url('target_username', '/users/%@'),
|
||||
userUrl: Discourse.computed.url('username', '/users/%@'),
|
||||
|
||||
postUrl: function() {
|
||||
return Discourse.Utilities.postUrl(this.get('slug'), this.get('topic_id'), this.get('post_number'));
|
||||
@ -91,15 +109,14 @@ Discourse.UserAction = Discourse.Model.extend({
|
||||
return Discourse.Utilities.postUrl(this.get('slug'), this.get('topic_id'), this.get('reply_to_post_number'));
|
||||
}.property(),
|
||||
|
||||
isPM: function() {
|
||||
var a = this.get('action_type');
|
||||
return a === Discourse.UserAction.NEW_PRIVATE_MESSAGE || a === Discourse.UserAction.GOT_PRIVATE_MESSAGE;
|
||||
}.property(),
|
||||
|
||||
isPostAction: function() {
|
||||
var a = this.get('action_type');
|
||||
return a === Discourse.UserAction.RESPONSE || a === Discourse.UserAction.POST || a === Discourse.UserAction.NEW_TOPIC;
|
||||
}.property(),
|
||||
replyType: Em.computed.equal('action_type', UserActionTypes.replies),
|
||||
postType: Em.computed.equal('action_type', UserActionTypes.posts),
|
||||
topicType: Em.computed.equal('action_type', UserActionTypes.topics),
|
||||
messageSentType: Em.computed.equal('action_type', UserActionTypes.messages_sent),
|
||||
messageReceivedType: Em.computed.equal('action_type', UserActionTypes.messages_received),
|
||||
mentionType: Em.computed.equal('action_type', UserActionTypes.mentions),
|
||||
isPM: Em.computed.or('messageSentType', 'messageReceivedType'),
|
||||
postReplyType: Em.computed.or('postType', 'replyType'),
|
||||
|
||||
addChild: function(action) {
|
||||
var groups = this.get("childGroups");
|
||||
@ -113,17 +130,16 @@ Discourse.UserAction = Discourse.Model.extend({
|
||||
}
|
||||
this.set("childGroups", groups);
|
||||
|
||||
var ua = Discourse.UserAction;
|
||||
var bucket = (function() {
|
||||
switch (action.action_type) {
|
||||
case ua.LIKE:
|
||||
case ua.WAS_LIKED:
|
||||
case UserActionTypes.likes_given:
|
||||
case UserActionTypes.likes_received:
|
||||
return "likes";
|
||||
case ua.STAR:
|
||||
case UserActionTypes.favorites:
|
||||
return "stars";
|
||||
case ua.EDIT:
|
||||
case UserActionTypes.edits:
|
||||
return "edits";
|
||||
case ua.BOOKMARK:
|
||||
case UserActionTypes.bookmarks:
|
||||
return "bookmarks";
|
||||
}
|
||||
})();
|
||||
@ -145,28 +161,29 @@ Discourse.UserAction = Discourse.Model.extend({
|
||||
}.property("childGroups"),
|
||||
|
||||
switchToActing: function() {
|
||||
this.set('username', this.get('acting_username'));
|
||||
this.set('avatar_template', this.get('acting_avatar_template'));
|
||||
this.set('name', this.get('acting_name'));
|
||||
this.setProperties({
|
||||
username: this.get('acting_username'),
|
||||
avatar_template: this.get('acting_avatar_template'),
|
||||
name: this.get('acting_name')
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Discourse.UserAction.reopenClass({
|
||||
collapseStream: function(stream) {
|
||||
var collapse, collapsed, pos, uniq;
|
||||
collapse = [this.LIKE, this.WAS_LIKED, this.STAR, this.EDIT, this.BOOKMARK];
|
||||
uniq = {};
|
||||
collapsed = Em.A();
|
||||
pos = 0;
|
||||
_.each(stream, function(item) {
|
||||
var current, found, key;
|
||||
key = "" + item.topic_id + "-" + item.post_number;
|
||||
found = uniq[key];
|
||||
var uniq = {},
|
||||
collapsed = Em.A(),
|
||||
pos = 0;
|
||||
|
||||
stream.forEach(function(item) {
|
||||
var key = "" + item.topic_id + "-" + item.post_number;
|
||||
var found = uniq[key];
|
||||
if (found === void 0) {
|
||||
if (collapse.indexOf(item.action_type) >= 0) {
|
||||
|
||||
var current;
|
||||
if (Discourse.UserAction.TO_COLLAPSE.indexOf(item.action_type) >= 0) {
|
||||
current = Discourse.UserAction.create(item);
|
||||
current.set('action_type', null);
|
||||
current.set('description', null);
|
||||
current.setProperties({action_type: null, description: null});
|
||||
item.switchToActing();
|
||||
current.addChild(item);
|
||||
} else {
|
||||
@ -176,39 +193,37 @@ Discourse.UserAction.reopenClass({
|
||||
collapsed[pos] = current;
|
||||
pos += 1;
|
||||
} else {
|
||||
if (collapse.indexOf(item.action_type) >= 0) {
|
||||
if (Discourse.UserAction.TO_COLLAPSE.indexOf(item.action_type) >= 0) {
|
||||
item.switchToActing();
|
||||
return collapsed[found].addChild(item);
|
||||
collapsed[found].addChild(item);
|
||||
} else {
|
||||
collapsed[found].set('action_type', item.get('action_type'));
|
||||
return collapsed[found].set('description', item.get('description'));
|
||||
collapsed[found].setProperties(item.getProperties('action_type', 'description'));
|
||||
}
|
||||
}
|
||||
});
|
||||
return collapsed;
|
||||
},
|
||||
|
||||
// in future we should be sending this through from the server
|
||||
LIKE: 1,
|
||||
WAS_LIKED: 2,
|
||||
BOOKMARK: 3,
|
||||
NEW_TOPIC: 4,
|
||||
POST: 5,
|
||||
RESPONSE: 6,
|
||||
MENTION: 7,
|
||||
QUOTE: 9,
|
||||
STAR: 10,
|
||||
EDIT: 11,
|
||||
NEW_PRIVATE_MESSAGE: 12,
|
||||
GOT_PRIVATE_MESSAGE: 13
|
||||
});
|
||||
TYPES: UserActionTypes,
|
||||
TYPES_INVERTED: InvertedActionTypes,
|
||||
|
||||
TO_COLLAPSE: [UserActionTypes.likes_given,
|
||||
UserActionTypes.likes_received,
|
||||
UserActionTypes.favorites,
|
||||
UserActionTypes.edits,
|
||||
UserActionTypes.bookmarks],
|
||||
|
||||
TO_SHOW: [
|
||||
UserActionTypes.likes_given,
|
||||
UserActionTypes.likes_received,
|
||||
UserActionTypes.favorites,
|
||||
UserActionTypes.edits,
|
||||
UserActionTypes.bookmarks,
|
||||
UserActionTypes.messages_sent,
|
||||
UserActionTypes.messages_received
|
||||
]
|
||||
|
||||
Discourse.UserAction.reopenClass({
|
||||
statGroups: (function() {
|
||||
var g = {};
|
||||
g[Discourse.UserAction.RESPONSE] = [Discourse.UserAction.RESPONSE, Discourse.UserAction.MENTION, Discourse.UserAction.QUOTE];
|
||||
return g;
|
||||
})()
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
@ -10,19 +10,17 @@ Discourse.UserActionStat = Discourse.Model.extend({
|
||||
|
||||
isPM: function() {
|
||||
var actionType = this.get('action_type');
|
||||
return actionType === Discourse.UserAction.NEW_PRIVATE_MESSAGE ||
|
||||
actionType === Discourse.UserAction.GOT_PRIVATE_MESSAGE;
|
||||
return actionType === Discourse.UserAction.TYPES.messages_sent ||
|
||||
actionType === Discourse.UserAction.TYPES.messages_received;
|
||||
}.property('action_type'),
|
||||
|
||||
description: function() {
|
||||
return I18n.t('user_action_groups.' + this.get('action_type'));
|
||||
}.property('description'),
|
||||
description: Discourse.computed.i18n('action_type', 'user_action_groups.%@'),
|
||||
|
||||
isResponse: function() {
|
||||
var actionType = this.get('action_type');
|
||||
return actionType === Discourse.UserAction.RESPONSE ||
|
||||
actionType === Discourse.UserAction.MENTION ||
|
||||
actionType === Discourse.UserAction.QUOTE;
|
||||
return actionType === Discourse.UserAction.TYPES.replies ||
|
||||
actionType === Discourse.UserAction.TYPES.mentions ||
|
||||
actionType === Discourse.UserAction.TYPES.quotes;
|
||||
}.property('action_type')
|
||||
|
||||
});
|
||||
|
@ -40,12 +40,24 @@ Discourse.Route.buildRoutes(function() {
|
||||
|
||||
// User routes
|
||||
this.resource('user', { path: '/users/:username' }, function() {
|
||||
this.route('activity', { path: '/' });
|
||||
this.route('index', { path: '/'} );
|
||||
|
||||
this.resource('userActivity', { path: '/activity' }, function() {
|
||||
var resource = this;
|
||||
Object.keys(Discourse.UserAction.TYPES).forEach(function (userAction) {
|
||||
resource.route(userAction, { path: userAction.replace("_", "-") });
|
||||
});
|
||||
});
|
||||
|
||||
this.resource('userPrivateMessages', { path: '/private-messages' }, function() {
|
||||
this.route('sent', {path: '/messages-sent'});
|
||||
});
|
||||
|
||||
this.resource('preferences', { path: '/preferences' }, function() {
|
||||
this.route('username', { path: '/username' });
|
||||
this.route('email', { path: '/email' });
|
||||
});
|
||||
this.route('privateMessages', { path: '/private-messages' });
|
||||
|
||||
this.route('invited', { path: 'invited' });
|
||||
});
|
||||
});
|
||||
|
@ -11,7 +11,7 @@ Discourse.RestrictedUserRoute = Discourse.Route.extend({
|
||||
afterModel: function() {
|
||||
var user = this.modelFor('user');
|
||||
if (!user.get('can_edit')) {
|
||||
this.transitionTo('user.activity', user);
|
||||
this.transitionTo('userActivity');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,21 +0,0 @@
|
||||
/**
|
||||
This route handles shows a user's activity
|
||||
|
||||
@class UserActivityRoute
|
||||
@extends Discourse.Route
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.UserActivityRoute = Discourse.Route.extend({
|
||||
|
||||
model: function() {
|
||||
return this.modelFor('user').findStream();
|
||||
},
|
||||
|
||||
renderTemplate: function() {
|
||||
this.render({ into: 'user', outlet: 'userOutlet' });
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
@ -1,37 +0,0 @@
|
||||
/**
|
||||
This route displays a user's private messages.
|
||||
|
||||
@class UserPrivateMessagesRoute
|
||||
@extends Discourse.RestrictedUserRoute
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
Discourse.UserPrivateMessagesRoute = Discourse.RestrictedUserRoute.extend({
|
||||
|
||||
model: function() {
|
||||
return this.modelFor('user').findStream(Discourse.UserAction.GOT_PRIVATE_MESSAGE);
|
||||
},
|
||||
|
||||
renderTemplate: function() {
|
||||
this.render({ into: 'user', outlet: 'userOutlet' });
|
||||
},
|
||||
|
||||
setupController: function(controller, stream) {
|
||||
var composerController = this.controllerFor('composer');
|
||||
controller.set('model', stream);
|
||||
Discourse.Draft.get('new_private_message').then(function(data) {
|
||||
if (data.draft) {
|
||||
composerController.open({
|
||||
draft: data.draft,
|
||||
draftKey: 'new_private_message',
|
||||
ignoreIfChanged: true,
|
||||
draftSequence: data.draft_sequence
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
@ -85,7 +85,7 @@
|
||||
</li>
|
||||
<li class='current-user'>
|
||||
{{#if currentUser}}
|
||||
{{#titledLinkTo 'user.activity' currentUser titleKey="current_user" class="icon"}}{{avatar currentUser imageSize="medium" }}{{/titledLinkTo}}
|
||||
{{#titledLinkTo 'user' currentUser titleKey="current_user" class="icon"}}{{avatar currentUser imageSize="medium" }}{{/titledLinkTo}}
|
||||
{{else}}
|
||||
<div class="icon not-logged-in-avatar" {{action showLogin}}><i class='icon-user'></i></div>
|
||||
{{/if}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{{#with user}}
|
||||
{{#with model}}
|
||||
<div id='user-info'>
|
||||
<nav class='buttons'>
|
||||
{{#if can_edit}}
|
||||
@ -15,9 +15,9 @@
|
||||
<div class='clearfix'></div>
|
||||
|
||||
<ul class='action-list nav-stacked side-nav'>
|
||||
{{activityFilter count=statsCountNonPM}}
|
||||
{{#each statsExcludingPms}}
|
||||
{{activityFilter content=this}}
|
||||
{{activityFilter count=statsCountNonPM user=this}}
|
||||
{{#each stat in statsExcludingPms}}
|
||||
{{activityFilter content=stat user=model}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
<div class='show'>
|
||||
@ -35,7 +35,7 @@
|
||||
<dt>{{i18n user.last_seen}}:</dt><dd>{{date last_seen_at}}</dd>
|
||||
{{/if}}
|
||||
{{#if invited_by}}
|
||||
<dt>{{i18n user.invited_by}}:</dt><dd>{{#linkTo 'user.activity' invited_by}}{{invited_by.username}}{{/linkTo}}</dd>
|
||||
<dt>{{i18n user.invited_by}}:</dt><dd>{{#linkTo 'userActivity' invited_by}}{{invited_by.username}}{{/linkTo}}</dd>
|
||||
{{/if}}
|
||||
{{#if email}}
|
||||
<dt>{{i18n user.email.title}}:</dt><dd {{bindAttr title="email"}}>{{email}}</dd>
|
||||
@ -53,4 +53,4 @@
|
||||
</div>
|
||||
{{/with}}
|
||||
|
||||
{{userStream stream=model}}
|
||||
{{userStream stream=stream}}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div id='user-info'>
|
||||
{{#with user}}
|
||||
{{#with model}}
|
||||
<nav class='buttons'>
|
||||
{{#if can_edit}}
|
||||
{{#linkTo "preferences" class="btn"}}{{i18n user.edit}}{{/linkTo}}
|
||||
@ -15,11 +15,12 @@
|
||||
<div class='clearfix'></div>
|
||||
|
||||
<ul class='action-list nav-stacked side-nav'>
|
||||
{{#each statsPmsOnly}}
|
||||
{{activityFilter content=this}}
|
||||
{{#each stat in statsPmsOnly}}
|
||||
{{activityFilter content=stat user=model}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/with}}
|
||||
</div>
|
||||
{{userStream stream=model}}
|
||||
|
||||
{{userStream stream=stream}}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div id='user-stream'>
|
||||
{{#each view.stream.content}}
|
||||
<div {{bindAttr class=":item hidden:hidden deleted:deleted"}}>
|
||||
<div {{bindAttr class=":item hidden deleted"}}>
|
||||
<div class='clearfix info'>
|
||||
<a href="{{unbound userUrl}}" class='avatar-link'><div class='avatar-wrapper'>{{avatar this imageSize="large" extraClasses="actor" ignoreTitle="true"}}</div></a>
|
||||
<span class='time'>{{date path="created_at" leaveAgo="true"}}</span>
|
||||
|
@ -12,11 +12,11 @@
|
||||
{{/if}}
|
||||
<ul class="nav nav-pills">
|
||||
<li>
|
||||
{{#linkTo 'user.activity'}}{{i18n user.activity_stream}}{{/linkTo}}
|
||||
{{#linkTo 'userActivity'}}{{i18n user.activity_stream}}{{/linkTo}}
|
||||
</li>
|
||||
{{#if canSeePrivateMessages}}
|
||||
<li>
|
||||
{{#linkTo "user.privateMessages"}}{{i18n user.private_messages}}{{/linkTo}}
|
||||
{{#linkTo 'userPrivateMessages'}}{{i18n user.private_messages}}{{/linkTo}}
|
||||
</li>
|
||||
{{/if}}
|
||||
<li>
|
||||
|
@ -30,7 +30,6 @@ Discourse.ActionsHistoryView = Discourse.View.extend({
|
||||
if (c.get('usersExpanded')) {
|
||||
var postUrl;
|
||||
c.get('users').forEach(function(u) {
|
||||
console.log(u);
|
||||
iconsHtml += "<a href=\"" + Discourse.getURL("/users/") + (u.get('username_lower')) + "\">";
|
||||
if (u.post_url) {
|
||||
postUrl = postUrl || u.post_url;
|
||||
|
@ -10,9 +10,8 @@ Discourse.ActivityFilterView = Discourse.View.extend({
|
||||
tagName: 'li',
|
||||
classNameBindings: ['active', 'noGlyph'],
|
||||
|
||||
stream: Em.computed.alias('controller.content'),
|
||||
stream: Em.computed.alias('controller.stream'),
|
||||
shouldRerender: Discourse.View.renderIfChanged('count'),
|
||||
|
||||
noGlyph: Em.computed.empty('icon'),
|
||||
|
||||
active: function() {
|
||||
@ -24,62 +23,57 @@ Discourse.ActivityFilterView = Discourse.View.extend({
|
||||
}
|
||||
}.property('stream.filter', 'content.action_type'),
|
||||
|
||||
activityCount: function() {
|
||||
return this.get('content.count') || this.get('count');
|
||||
}.property('content.count', 'count'),
|
||||
|
||||
typeKey: function() {
|
||||
|
||||
var actionType = this.get('content.action_type');
|
||||
if (actionType === Discourse.UserAction.TYPES.messages_received) { return ""; }
|
||||
|
||||
var result = Discourse.UserAction.TYPES_INVERTED[actionType];
|
||||
if (!result) { return ""; }
|
||||
|
||||
// We like our URLS to have hyphens, not underscores
|
||||
return "/" + result.replace("_", "-");
|
||||
}.property('content.action_type'),
|
||||
|
||||
url: function() {
|
||||
var section = this.get('content.isPM') ? "/private-messages" : "/activity";
|
||||
return "/users/" + this.get('user.username_lower') + section + this.get('typeKey');
|
||||
}.property('typeKey'),
|
||||
|
||||
description: function() {
|
||||
return this.get('content.description') || I18n.t("user.filters.all");
|
||||
}.property('content.description'),
|
||||
|
||||
render: function(buffer) {
|
||||
var content = this.get("content");
|
||||
var count, description;
|
||||
|
||||
if (content) {
|
||||
count = Em.get(content, "count");
|
||||
description = Em.get(content, "description");
|
||||
} else {
|
||||
count = this.get("count");
|
||||
description = I18n.t("user.filters.all");
|
||||
}
|
||||
|
||||
buffer.push("<a href='" + this.get('url') + "'>");
|
||||
var icon = this.get('icon');
|
||||
|
||||
buffer.push("<a href='#'>");
|
||||
if(icon) {
|
||||
if (icon) {
|
||||
buffer.push("<i class='glyph icon icon-" + icon + "'></i> ");
|
||||
}
|
||||
|
||||
buffer.push(description +
|
||||
" <span class='count'>(" + count + ")</span>");
|
||||
|
||||
|
||||
buffer.push(this.get('description') + " <span class='count'>(" + this.get('activityCount') + ")</span>");
|
||||
buffer.push("<span class='icon-chevron-right'></span></a>");
|
||||
|
||||
},
|
||||
|
||||
icon: function(){
|
||||
var action_type = parseInt(this.get("content.action_type"),10);
|
||||
var icon;
|
||||
|
||||
switch(action_type){
|
||||
case Discourse.UserAction.WAS_LIKED:
|
||||
icon = "heart";
|
||||
break;
|
||||
case Discourse.UserAction.BOOKMARK:
|
||||
icon = "bookmark";
|
||||
break;
|
||||
case Discourse.UserAction.EDIT:
|
||||
icon = "pencil";
|
||||
break;
|
||||
case Discourse.UserAction.RESPONSE:
|
||||
icon = "reply";
|
||||
break;
|
||||
case Discourse.UserAction.STAR:
|
||||
icon = "star";
|
||||
break;
|
||||
switch(parseInt(this.get('content.action_type'),10)) {
|
||||
case Discourse.UserAction.TYPES.likes_received:
|
||||
return "heart";
|
||||
case Discourse.UserAction.TYPES.bookmarks:
|
||||
return "bookmark";
|
||||
case Discourse.UserAction.TYPES.edits:
|
||||
return "pencil";
|
||||
case Discourse.UserAction.TYPES.replies:
|
||||
return "reply";
|
||||
case Discourse.UserAction.TYPES.favorites:
|
||||
return "star";
|
||||
}
|
||||
}.property("content.action_type")
|
||||
|
||||
return icon;
|
||||
}.property("content.action_type"),
|
||||
|
||||
click: function() {
|
||||
this.set('stream.filter', this.get('content.action_type'));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
Discourse.View.registerHelper('activityFilter', Discourse.ActivityFilterView);
|
||||
|
@ -18,12 +18,12 @@ Discourse.UserPrivateMessagesView = Discourse.View.extend({
|
||||
|
||||
inbox: function(evt) {
|
||||
this.selectCurrent(evt);
|
||||
return this.set('controller.filter', Discourse.UserAction.GOT_PRIVATE_MESSAGE);
|
||||
return this.set('controller.filter', Discourse.UserAction.TYPES.messages_received);
|
||||
},
|
||||
|
||||
sentMessages: function(evt) {
|
||||
this.selectCurrent(evt);
|
||||
return this.set('controller.filter', Discourse.UserAction.NEW_PRIVATE_MESSAGE);
|
||||
return this.set('controller.filter', Discourse.UserAction.TYPES.messages_sent);
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -11,15 +11,17 @@
|
||||
|
||||
// Stuff we need to load first
|
||||
//= require_tree ./discourse/mixins
|
||||
//= require ./discourse/components/computed
|
||||
//= require ./discourse/views/view
|
||||
//= require ./discourse/components/debounce
|
||||
//= require ./discourse/models/model
|
||||
//= require ./discourse/models/user_action
|
||||
//= require ./discourse/controllers/controller
|
||||
//= require ./discourse/controllers/object_controller
|
||||
//= require ./discourse/views/modal/modal_body_view
|
||||
//= require ./discourse/views/combobox_view
|
||||
//= require ./discourse/views/buttons/button_view
|
||||
//= require ./discourse/views/buttons/dropdown_button_view
|
||||
//= require ./discourse/models/model
|
||||
//= require ./discourse/routes/discourse_route
|
||||
//= require ./discourse/routes/discourse_restricted_user_route
|
||||
|
||||
|
@ -119,6 +119,7 @@ Discourse::Application.routes.draw do
|
||||
|
||||
get 'user_preferences' => 'users#user_preferences_redirect'
|
||||
get 'users/:username/private-messages' => 'user_actions#private_messages', constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||
get 'users/:username/private-messages/:filter' => 'user_actions#private_messages', constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||
get 'users/:username' => 'users#show', constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||
put 'users/:username' => 'users#update', constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||
get 'users/:username/preferences' => 'users#preferences', constraints: {username: USERNAME_ROUTE_FORMAT}, as: :email_preferences
|
||||
@ -129,6 +130,8 @@ Discourse::Application.routes.draw do
|
||||
get 'users/:username/avatar(/:size)' => 'users#avatar', constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||
get 'users/:username/invited' => 'users#invited', constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||
post 'users/:username/send_activation_email' => 'users#send_activation_email', constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||
get 'users/:username/activity' => 'users#show', constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||
get 'users/:username/activity/:filter' => 'users#show', constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||
|
||||
resources :uploads
|
||||
|
||||
|
@ -6,7 +6,14 @@ task 'integration:create_fixtures' => :environment do
|
||||
fixtures = {
|
||||
list: ["/latest.json", "/categories.json", "/category/bug.json"],
|
||||
topic: ["/t/280.json"],
|
||||
user: ["/users/eviltrout.json", "/user_actions.json?offset=0&username=eviltrout"],
|
||||
user: ["/users/eviltrout.json",
|
||||
"/user_actions.json?offset=0&username=eviltrout",
|
||||
"/user_actions.json?offset=0&username=eviltrout&filter=4",
|
||||
"/user_actions.json?offset=0&username=eviltrout&filter=5",
|
||||
"/user_actions.json?offset=0&username=eviltrout&filter=6,7,9",
|
||||
"/user_actions.json?offset=0&username=eviltrout&filter=1",
|
||||
"/user_actions.json?offset=0&username=eviltrout&filter=2",
|
||||
"/user_actions.json?offset=0&username=eviltrout&filter=11"],
|
||||
static: ["/faq", '/tos', '/privacy']
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,6 @@ test("fmt", function() {
|
||||
test("url without a prefix", function() {
|
||||
var t = testClass.create({ username: 'eviltrout' });
|
||||
equal(t.get('userUrl'), "/users/eviltrout");
|
||||
|
||||
});
|
||||
|
||||
test("url with a prefix", function() {
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,12 +1,21 @@
|
||||
integration("User");
|
||||
|
||||
test("Profile", function() {
|
||||
test("Activity Streams", function() {
|
||||
expect(14);
|
||||
|
||||
visit("/users/eviltrout").then(function() {
|
||||
expect(2);
|
||||
var streamTest = function(url) {
|
||||
visit(url).then(function() {
|
||||
ok(exists(".user-heading"), "The heading is rendered");
|
||||
ok(exists("#user-stream"), "The stream is rendered");
|
||||
});
|
||||
};
|
||||
|
||||
ok(exists(".user-heading"), "The heading is rendered");
|
||||
ok(exists("#user-stream"), "The stream is rendered");
|
||||
});
|
||||
streamTest("/users/eviltrout");
|
||||
streamTest("/users/eviltrout/activity/topics");
|
||||
streamTest("/users/eviltrout/activity/posts");
|
||||
streamTest("/users/eviltrout/activity/replies");
|
||||
streamTest("/users/eviltrout/activity/likes-given");
|
||||
streamTest("/users/eviltrout/activity/likes-received");
|
||||
streamTest("/users/eviltrout/activity/edits");
|
||||
|
||||
});
|
||||
|
@ -3,17 +3,17 @@ module("Discourse.UserAction");
|
||||
test("collapsing likes", function () {
|
||||
var actions = Discourse.UserAction.collapseStream([
|
||||
Discourse.UserAction.create({
|
||||
action_type: Discourse.UserAction.LIKE,
|
||||
action_type: Discourse.UserAction.TYPES.likes_given,
|
||||
topic_id: 1,
|
||||
user_id: 1,
|
||||
post_number: 1
|
||||
}), Discourse.UserAction.create({
|
||||
action_type: Discourse.UserAction.EDIT,
|
||||
action_type: Discourse.UserAction.TYPES.edits,
|
||||
topic_id: 2,
|
||||
user_id: 1,
|
||||
post_number: 1
|
||||
}), Discourse.UserAction.create({
|
||||
action_type: Discourse.UserAction.LIKE,
|
||||
action_type: Discourse.UserAction.TYPES.likes_given,
|
||||
topic_id: 1,
|
||||
user_id: 2,
|
||||
post_number: 1
|
||||
|
Loading…
x
Reference in New Issue
Block a user