mirror of
https://github.com/discourse/discourse.git
synced 2024-11-26 13:43:36 +08:00
FEATURE: User page refactor
Re-organise user page so it is easier to find interesting info split it into tabs - Introduce notifications and messages tabs - Stop couting stuff for the user page to speed up rendering - Suppress more information when viewing your own profile
This commit is contained in:
parent
c3f08145b8
commit
a8b5192efd
|
@ -0,0 +1,25 @@
|
||||||
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
|
|
||||||
|
export default Ember.Controller.extend({
|
||||||
|
|
||||||
|
pmView: false,
|
||||||
|
|
||||||
|
privateMessagesActive: Em.computed.equal('pmView', 'index'),
|
||||||
|
privateMessagesMineActive: Em.computed.equal('pmView', 'mine'),
|
||||||
|
privateMessagesUnreadActive: Em.computed.equal('pmView', 'unread'),
|
||||||
|
isGroup: Em.computed.equal('pmView', 'groups'),
|
||||||
|
|
||||||
|
|
||||||
|
@computed('model.groups', 'groupFilter', 'pmView')
|
||||||
|
groupPMStats(groups, filter, pmView) {
|
||||||
|
if (groups) {
|
||||||
|
return groups.filter(group => group.has_messages)
|
||||||
|
.map(g => {
|
||||||
|
return {
|
||||||
|
name: g.name,
|
||||||
|
active: (g.name === filter && pmView === "groups")
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -6,7 +6,6 @@ import User from 'discourse/models/user';
|
||||||
|
|
||||||
export default Ember.Controller.extend(CanCheckEmails, {
|
export default Ember.Controller.extend(CanCheckEmails, {
|
||||||
indexStream: false,
|
indexStream: false,
|
||||||
pmView: false,
|
|
||||||
userActionType: null,
|
userActionType: null,
|
||||||
needs: ['user-notifications', 'user-topics-list'],
|
needs: ['user-notifications', 'user-topics-list'],
|
||||||
|
|
||||||
|
@ -28,11 +27,14 @@ export default Ember.Controller.extend(CanCheckEmails, {
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed('viewingSelf', 'currentUser.admin')
|
@computed('viewingSelf', 'currentUser.admin')
|
||||||
canSeePrivateMessages(viewingSelf, isAdmin) {
|
showPrivateMessages(viewingSelf, isAdmin) {
|
||||||
return this.siteSettings.enable_private_messages && (viewingSelf || isAdmin);
|
return this.siteSettings.enable_private_messages && (viewingSelf || isAdmin);
|
||||||
},
|
},
|
||||||
|
|
||||||
canSeeNotificationHistory: Em.computed.alias('canSeePrivateMessages'),
|
@computed('viewingSelf', 'currentUser.admin')
|
||||||
|
canSeeNotificationHistory(viewingSelf, isAdmin) {
|
||||||
|
return viewingSelf || isAdmin;
|
||||||
|
},
|
||||||
|
|
||||||
@computed("content.badge_count")
|
@computed("content.badge_count")
|
||||||
showBadges(badgeCount) {
|
showBadges(badgeCount) {
|
||||||
|
@ -45,6 +47,12 @@ export default Ember.Controller.extend(CanCheckEmails, {
|
||||||
(userActionType === UserAction.TYPES.messages_received);
|
(userActionType === UserAction.TYPES.messages_received);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@computed("indexStream", "userActionType")
|
||||||
|
showActionTypeSummary(indexStream,userActionType, showPMs) {
|
||||||
|
return (indexStream || userActionType) && !showPMs;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
@computed()
|
@computed()
|
||||||
canInviteToForum() {
|
canInviteToForum() {
|
||||||
return User.currentProp('can_invite_to_forum');
|
return User.currentProp('can_invite_to_forum');
|
||||||
|
@ -64,23 +72,6 @@ export default Ember.Controller.extend(CanCheckEmails, {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
privateMessagesActive: Em.computed.equal('pmView', 'index'),
|
|
||||||
privateMessagesMineActive: Em.computed.equal('pmView', 'mine'),
|
|
||||||
privateMessagesUnreadActive: Em.computed.equal('pmView', 'unread'),
|
|
||||||
|
|
||||||
@computed('model.private_messages_stats.groups', 'groupFilter', 'pmView')
|
|
||||||
groupPMStats(stats,filter,pmView) {
|
|
||||||
if (stats) {
|
|
||||||
return stats.map(g => {
|
|
||||||
return {
|
|
||||||
name: g.name,
|
|
||||||
count: g.count,
|
|
||||||
active: (g.name === filter && pmView === 'groups')
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
expandProfile() {
|
expandProfile() {
|
||||||
this.set('forceExpand', true);
|
this.set('forceExpand', true);
|
||||||
|
|
|
@ -3,4 +3,5 @@ export default {
|
||||||
this.controllerFor('user').set('userActionType', userActionType);
|
this.controllerFor('user').set('userActionType', userActionType);
|
||||||
this.controllerFor('user-activity').set('userActionType', userActionType);
|
this.controllerFor('user-activity').set('userActionType', userActionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -199,6 +199,15 @@ const User = RestModel.extend({
|
||||||
ua.action_type === UserAction.TYPES.topics;
|
ua.action_type === UserAction.TYPES.topics;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@computed("groups.@each")
|
||||||
|
displayGroups() {
|
||||||
|
const groups = this.get('groups');
|
||||||
|
const filtered = groups.filter(group => {
|
||||||
|
return !group.automatic || group.name === "moderators";
|
||||||
|
});
|
||||||
|
return filtered.length === 0 ? null : filtered;
|
||||||
|
},
|
||||||
|
|
||||||
// The user's stat count, excluding PMs.
|
// The user's stat count, excluding PMs.
|
||||||
@computed("statsExcludingPms.@each.count")
|
@computed("statsExcludingPms.@each.count")
|
||||||
statsCountNonPM() {
|
statsCountNonPM() {
|
||||||
|
@ -233,8 +242,8 @@ const User = RestModel.extend({
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Em.isEmpty(json.user.custom_groups)) {
|
if (!Em.isEmpty(json.user.groups)) {
|
||||||
json.user.custom_groups = json.user.custom_groups.map(g => Group.create(g));
|
json.user.groups = json.user.groups.map(g => Group.create(g));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json.user.invited_by) {
|
if (json.user.invited_by) {
|
||||||
|
|
|
@ -58,13 +58,20 @@ export default function() {
|
||||||
this.resource('users');
|
this.resource('users');
|
||||||
this.resource('user', { path: '/users/:username' }, function() {
|
this.resource('user', { path: '/users/:username' }, function() {
|
||||||
this.resource('userActivity', { path: '/activity' }, function() {
|
this.resource('userActivity', { path: '/activity' }, function() {
|
||||||
_.map(Discourse.UserAction.TYPES, (id, userAction) => {
|
this.route('topics');
|
||||||
this.route(userAction, { path: userAction.replace('_', '-') });
|
this.route('replies');
|
||||||
});
|
this.route('likesGiven', {path: 'likes-given'});
|
||||||
|
this.route('bookmarks');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.resource('userNotifications', {path: '/notifications'}, function(){
|
||||||
|
this.route('responses');
|
||||||
|
this.route('likesReceived', { path: 'likes-received'});
|
||||||
|
this.route('mentions');
|
||||||
|
this.route('edits');
|
||||||
});
|
});
|
||||||
|
|
||||||
this.route('badges');
|
this.route('badges');
|
||||||
this.route('notifications');
|
|
||||||
this.route('flaggedPosts', { path: '/flagged-posts' });
|
this.route('flaggedPosts', { path: '/flagged-posts' });
|
||||||
this.route('deletedPosts', { path: '/deleted-posts' });
|
this.route('deletedPosts', { path: '/deleted-posts' });
|
||||||
|
|
||||||
|
@ -85,6 +92,7 @@ export default function() {
|
||||||
this.resource('userInvited', { path: '/invited' }, function() {
|
this.resource('userInvited', { path: '/invited' }, function() {
|
||||||
this.route('show', { path: '/:filter' });
|
this.route('show', { path: '/:filter' });
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.route('signup', {path: '/signup'});
|
this.route('signup', {path: '/signup'});
|
||||||
|
|
|
@ -24,7 +24,7 @@ export default (viewName, path) => {
|
||||||
showParticipants: true
|
showParticipants: true
|
||||||
});
|
});
|
||||||
|
|
||||||
this.controllerFor("user").set("pmView", viewName);
|
this.controllerFor("userPrivateMessages").set("pmView", viewName);
|
||||||
this.searchService.set('contextType', 'private_messages');
|
this.searchService.set('contextType', 'private_messages');
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,5 +2,5 @@ import UserActivityStreamRoute from "discourse/routes/user-activity-stream";
|
||||||
import UserAction from "discourse/models/user-action";
|
import UserAction from "discourse/models/user-action";
|
||||||
|
|
||||||
export default UserActivityStreamRoute.extend({
|
export default UserActivityStreamRoute.extend({
|
||||||
userActionType: UserAction.TYPES["replies"]
|
userActionType: UserAction.TYPES["posts"]
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import Draft from 'discourse/models/draft';
|
|
||||||
|
|
||||||
export default Discourse.Route.extend({
|
export default Discourse.Route.extend({
|
||||||
model() {
|
model() {
|
||||||
return this.modelFor("user");
|
return this.modelFor("user");
|
||||||
|
@ -7,21 +5,5 @@ export default Discourse.Route.extend({
|
||||||
|
|
||||||
setupController(controller, user) {
|
setupController(controller, user) {
|
||||||
this.controllerFor("user-activity").set("model", user);
|
this.controllerFor("user-activity").set("model", user);
|
||||||
|
|
||||||
// Bring up a draft
|
|
||||||
const composerController = this.controllerFor("composer");
|
|
||||||
controller.set("model", user);
|
|
||||||
if (this.currentUser) {
|
|
||||||
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
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
export default Discourse.Route.extend({
|
||||||
|
renderTemplate() {
|
||||||
|
this.render("user/notifications-index");
|
||||||
|
}
|
||||||
|
});
|
|
@ -2,5 +2,5 @@ import UserActivityStreamRoute from "discourse/routes/user-activity-stream";
|
||||||
import UserAction from "discourse/models/user-action";
|
import UserAction from "discourse/models/user-action";
|
||||||
|
|
||||||
export default UserActivityStreamRoute.extend({
|
export default UserActivityStreamRoute.extend({
|
||||||
userActionType: UserAction.TYPES["likes_received"]
|
userActionType: UserAction.TYPES["likes_received"],
|
||||||
});
|
});
|
|
@ -2,5 +2,5 @@ import UserActivityStreamRoute from "discourse/routes/user-activity-stream";
|
||||||
import UserAction from "discourse/models/user-action";
|
import UserAction from "discourse/models/user-action";
|
||||||
|
|
||||||
export default UserActivityStreamRoute.extend({
|
export default UserActivityStreamRoute.extend({
|
||||||
userActionType: UserAction.TYPES["posts"]
|
userActionType: UserAction.TYPES["replies"]
|
||||||
});
|
});
|
|
@ -1,6 +1,11 @@
|
||||||
import ViewingActionType from "discourse/mixins/viewing-action-type";
|
import ViewingActionType from "discourse/mixins/viewing-action-type";
|
||||||
|
|
||||||
export default Discourse.Route.extend(ViewingActionType, {
|
export default Discourse.Route.extend(ViewingActionType, {
|
||||||
|
|
||||||
|
renderTemplate() {
|
||||||
|
this.render('user/notifications');
|
||||||
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
didTransition() {
|
didTransition() {
|
||||||
this.controllerFor("user-notifications")._showFooter();
|
this.controllerFor("user-notifications")._showFooter();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import Group from 'discourse/models/group';
|
import Group from 'discourse/models/group';
|
||||||
import createPMRoute from "discourse/routes/build-user-topic-list-route";
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
export default createPMRoute('groups', 'private-messages-groups').extend({
|
export default createPMRoute('groups', 'private-messages-groups').extend({
|
||||||
model(params) {
|
model(params) {
|
||||||
|
@ -13,13 +13,13 @@ export default createPMRoute('groups', 'private-messages-groups').extend({
|
||||||
const groupName = _.last(model.get("filter").split('/'));
|
const groupName = _.last(model.get("filter").split('/'));
|
||||||
Group.findAll().then(groups => {
|
Group.findAll().then(groups => {
|
||||||
const group = _.first(groups.filterBy("name", groupName));
|
const group = _.first(groups.filterBy("name", groupName));
|
||||||
this.controllerFor("user-topics-list").set("group", group);
|
this.controllerFor("user-private-messages").set("group", group);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
setupController(controller, model) {
|
setupController(controller, model) {
|
||||||
this._super.apply(this, arguments);
|
this._super.apply(this, arguments);
|
||||||
const group = _.last(model.get("filter").split('/'));
|
const group = _.last(model.get("filter").split('/'));
|
||||||
this.controllerFor("user").set("groupFilter", group);
|
this.controllerFor("userPrivateMessages").set("groupFilter", group);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
import createPMRoute from "discourse/routes/build-user-topic-list-route";
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
export default createPMRoute('index', 'private-messages');
|
export default createPMRoute('index', 'private-messages');
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
import createPMRoute from "discourse/routes/build-user-topic-list-route";
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
export default createPMRoute('mine', 'private-messages-sent');
|
export default createPMRoute('mine', 'private-messages-sent');
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
import createPMRoute from "discourse/routes/build-user-topic-list-route";
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
export default createPMRoute('unread', 'private-messages-unread');
|
export default createPMRoute('unread', 'private-messages-unread');
|
||||||
|
|
|
@ -1,6 +1,35 @@
|
||||||
import UserActivityRoute from 'discourse/routes/user-activity';
|
import Draft from 'discourse/models/draft';
|
||||||
|
|
||||||
|
export default Discourse.Route.extend({
|
||||||
|
|
||||||
|
renderTemplate() {
|
||||||
|
this.render('user/messages');
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
model() {
|
||||||
|
return this.modelFor("user");
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController(controller, user) {
|
||||||
|
this._super();
|
||||||
|
// Bring up a draft
|
||||||
|
const composerController = this.controllerFor("composer");
|
||||||
|
controller.set("model", user);
|
||||||
|
if (this.currentUser) {
|
||||||
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
export default UserActivityRoute.extend({
|
|
||||||
actions: {
|
actions: {
|
||||||
willTransition: function() {
|
willTransition: function() {
|
||||||
this._super();
|
this._super();
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
export default Discourse.Route.extend({
|
||||||
|
});
|
|
@ -1,11 +1,3 @@
|
||||||
<div class="clearfix">
|
|
||||||
{{#if group}}
|
|
||||||
{{group-notifications-button group=group}}
|
|
||||||
{{/if}}
|
|
||||||
{{#if showNewPM}}
|
|
||||||
{{d-button class="btn-primary pull-right new-private-message" action="composePrivateMessage" icon="envelope" label="user.new_private_message"}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{basic-topic-list topicList=model
|
{{basic-topic-list topicList=model
|
||||||
hideCategory=hideCategory
|
hideCategory=hideCategory
|
||||||
|
|
|
@ -1 +1,42 @@
|
||||||
|
<section class='user-navigation'>
|
||||||
|
<ul class='action-list nav-stacked'>
|
||||||
|
|
||||||
|
<li class='no-glyph'>
|
||||||
|
{{#link-to 'userActivity.index'}}{{i18n 'user.filters.all'}}{{/link-to}}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class='no-glyph'>
|
||||||
|
{{#link-to 'userActivity.topics'}}{{i18n 'user_action_groups.4'}}{{/link-to}}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
{{#link-to 'userActivity.replies'}}
|
||||||
|
<i class="glyph fa fa-reply"></i>{{i18n 'user_action_groups.5'}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
{{#link-to 'userActivity.likesGiven'}}
|
||||||
|
<i class="glyph fa fa-heart"></i>{{i18n 'user_action_groups.1'}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
{{#link-to 'userActivity.bookmarks'}}
|
||||||
|
<i class="glyph fa fa-bookmark"></i>{{i18n 'user_action_groups.3'}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{#if viewingSelf}}
|
||||||
|
<div class='user-archive'>
|
||||||
|
{{d-button action="exportUserArchive" label="user.download_archive" icon="download"}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class='user-right'>
|
||||||
{{outlet}}
|
{{outlet}}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
43
app/assets/javascripts/discourse/templates/user/messages.hbs
Normal file
43
app/assets/javascripts/discourse/templates/user/messages.hbs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<section class='user-navigation'>
|
||||||
|
<ul class='action-list nav-stacked'>
|
||||||
|
<li {{bind-attr class=":noGlyph privateMessagesActive:active"}}>
|
||||||
|
{{#link-to 'userPrivateMessages.index' model}}
|
||||||
|
{{i18n 'user.messages.all'}}
|
||||||
|
{{#if model.hasPMs}}<span class='count'>({{model.private_messages_stats.all}})</span>{{/if}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
<li {{bind-attr class=":noGlyph privateMessagesMineActive:active"}}>
|
||||||
|
{{#link-to 'userPrivateMessages.mine' model}}
|
||||||
|
{{i18n 'user.messages.mine'}}
|
||||||
|
{{#if model.hasStartedPMs}}<span class='count'>({{model.private_messages_stats.mine}})</span>{{/if}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
<li {{bind-attr class=":noGlyph privateMessagesUnreadActive:active"}}>
|
||||||
|
{{#link-to 'userPrivateMessages.unread' model}}
|
||||||
|
{{i18n 'user.messages.unread'}}
|
||||||
|
{{#if model.hasUnreadPMs}}<span class='badge-notification unread-private-messages'>{{model.private_messages_stats.unread}}</span>{{/if}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
{{#each groupPMStats as |group|}}
|
||||||
|
<li class="{{if group.active "active"}}">
|
||||||
|
{{#link-to 'userPrivateMessages.group' group.name}}
|
||||||
|
<i class='glyph fa fa-group'></i>
|
||||||
|
{{group.name}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{d-button class="btn-primary new-private-message" action="composePrivateMessage" icon="envelope" label="user.new_private_message"}}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class='user-right messages'>
|
||||||
|
|
||||||
|
{{#if isGroup}}
|
||||||
|
<div class="clearfix">
|
||||||
|
{{group-notifications-button group=group}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{outlet}}
|
||||||
|
</section>
|
|
@ -0,0 +1,34 @@
|
||||||
|
{{#if model.error}}
|
||||||
|
<div class="item error">
|
||||||
|
{{#if model.forbidden}}
|
||||||
|
{{i18n 'errors.reasons.forbidden'}}
|
||||||
|
{{else}}
|
||||||
|
{{i18n 'errors.desc.unknown'}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if showDismissButton}}
|
||||||
|
<div class='notification-buttons'>
|
||||||
|
<button title="{{i18n 'user.dismiss_notifications_tooltip'}}" id='dismiss-notifications-top' class='btn notifications-read' {{action "resetNew"}}>{{i18n 'user.dismiss_notifications'}}</button>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#each n in model}}
|
||||||
|
<div {{bind-attr class=":item :notification n.read::unread"}}>
|
||||||
|
{{notification-item notification=n}}
|
||||||
|
<span class="time">
|
||||||
|
{{format-date n.created_at leaveAgo="true"}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{#conditional-loading-spinner condition=loading}}
|
||||||
|
{{#unless model.canLoadMore}}
|
||||||
|
{{#if showDismissButton}}
|
||||||
|
<div class='notification-buttons'>
|
||||||
|
<button title="{{i18n 'user.dismiss_notifications_tooltip'}}" id='dismiss-notifications' class='btn notifications-read' {{action "resetNew"}}>{{i18n 'user.dismiss_notifications'}}</button>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{/unless}}
|
||||||
|
{{/conditional-loading-spinner}}
|
|
@ -1,34 +1,25 @@
|
||||||
{{#if model.error}}
|
|
||||||
<div class="item error">
|
|
||||||
{{#if model.forbidden}}
|
|
||||||
{{i18n 'errors.reasons.forbidden'}}
|
|
||||||
{{else}}
|
|
||||||
{{i18n 'errors.desc.unknown'}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if showDismissButton}}
|
<section class='user-navigation'>
|
||||||
<div class='notification-buttons'>
|
<ul class='action-list nav-stacked'>
|
||||||
<button title="{{i18n 'user.dismiss_notifications_tooltip'}}" id='dismiss-notifications-top' class='btn notifications-read' {{action "resetNew"}}>{{i18n 'user.dismiss_notifications'}}</button>
|
<li class='no-glyph'>
|
||||||
</div>
|
{{#link-to 'userNotifications.index'}}{{i18n 'user.filters.all'}}{{/link-to}}
|
||||||
{{/if}}
|
</li>
|
||||||
|
<li>
|
||||||
|
{{#link-to 'userNotifications.responses'}}
|
||||||
|
<i class="glyph fa fa-reply"></i>
|
||||||
|
{{i18n 'user_action_groups.6'}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{#link-to 'userNotifications.likesReceived'}}
|
||||||
|
<i class="glyph fa fa-heart"></i>{{i18n 'user_action_groups.2'}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
<li>{{#link-to 'userNotifications.mentions'}}<i class="glyph fa fa-at"></i>{{i18n 'user_action_groups.7'}}{{/link-to}}</li>
|
||||||
|
<li>{{#link-to 'userNotifications.edits'}}<i class="glyph fa fa-pencil"></i>{{i18n 'user_action_groups.11'}}{{/link-to}}</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
{{#each n in model}}
|
<section class='user-right'>
|
||||||
<div {{bind-attr class=":item :notification n.read::unread"}}>
|
{{outlet}}
|
||||||
{{notification-item notification=n}}
|
</section>
|
||||||
<span class="time">
|
|
||||||
{{format-date n.created_at leaveAgo="true"}}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
{{#conditional-loading-spinner condition=loading}}
|
|
||||||
{{#unless model.canLoadMore}}
|
|
||||||
{{#if showDismissButton}}
|
|
||||||
<div class='notification-buttons'>
|
|
||||||
<button title="{{i18n 'user.dismiss_notifications_tooltip'}}" id='dismiss-notifications' class='btn notifications-read' {{action "resetNew"}}>{{i18n 'user.dismiss_notifications'}}</button>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
{{/unless}}
|
|
||||||
{{/conditional-loading-spinner}}
|
|
||||||
|
|
|
@ -237,15 +237,8 @@
|
||||||
{{category-group categories=model.mutedCategories blacklist=selectedCategories}}
|
{{category-group categories=model.mutedCategories blacklist=selectedCategories}}
|
||||||
</div>
|
</div>
|
||||||
<div class="instructions">{{i18n 'user.muted_categories_instructions'}}</div>
|
<div class="instructions">{{i18n 'user.muted_categories_instructions'}}</div>
|
||||||
</div>
|
<div class="controls category-controls">
|
||||||
|
<a href="{{unbound model.mutedTopicsPath}}">{{i18n 'user.muted_topics_link'}}</a>
|
||||||
<div class="control-group topics">
|
|
||||||
<label class="control-label">{{i18n 'categories.topics'}}</label>
|
|
||||||
{{#if siteSettings.automatically_unpin_topics}}
|
|
||||||
{{preference-checkbox labelKey="user.automatically_unpin_topics" checked=model.automatically_unpin_topics}}
|
|
||||||
{{/if}}
|
|
||||||
<div class="controls topic-controls">
|
|
||||||
<a href="{{unbound model.mutedTopicsPath}}">{{i18n 'user.muted_topics_link'}}</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -258,6 +251,13 @@
|
||||||
<div class="instructions">{{i18n 'user.muted_users_instructions'}}</div>
|
<div class="instructions">{{i18n 'user.muted_users_instructions'}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{#if siteSettings.automatically_unpin_topics}}
|
||||||
|
<div class="control-group topics">
|
||||||
|
<label class="control-label">{{i18n 'categories.topics'}}</label>
|
||||||
|
{{preference-checkbox labelKey="user.automatically_unpin_topics" checked=model.automatically_unpin_topics}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{plugin-outlet "user-custom-controls"}}
|
{{plugin-outlet "user-custom-controls"}}
|
||||||
|
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<div class="container{{if viewingSelf ' viewing-self'}}">
|
<div class="container{{if viewingSelf ' viewing-self'}}">
|
||||||
<section class='user-main'>
|
<section class='user-main'>
|
||||||
<section {{bind-attr class="collapsedInfo :about model.profileBackground:has-background:no-background"}} style={{model.profileBackground}}>
|
<section {{bind-attr class="collapsedInfo :about model.profileBackground:has-background:no-background"}} style={{model.profileBackground}}>
|
||||||
|
{{#unless collapsedInfo}}
|
||||||
<div class='staff-counters'>
|
<div class='staff-counters'>
|
||||||
{{#if model.number_of_flags_given}}
|
{{#if model.number_of_flags_given}}
|
||||||
<div><span class="helpful-flags">{{model.number_of_flags_given}}</span> {{i18n 'user.staff_counters.flags_given'}}</div>
|
<div><span class="helpful-flags">{{model.number_of_flags_given}}</span> {{i18n 'user.staff_counters.flags_given'}}</div>
|
||||||
|
@ -26,6 +27,8 @@
|
||||||
<div><span class="warnings-received">{{model.number_of_warnings}}</span> {{i18n 'user.staff_counters.warnings_received'}}</div>
|
<div><span class="warnings-received">{{model.number_of_warnings}}</span> {{i18n 'user.staff_counters.warnings_received'}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
|
||||||
<div class='profile-image'></div>
|
<div class='profile-image'></div>
|
||||||
<div class='details'>
|
<div class='details'>
|
||||||
<div class='primary'>
|
<div class='primary'>
|
||||||
|
@ -40,18 +43,9 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if viewingSelf}}
|
|
||||||
<li><a {{action "logout"}} href class='btn btn-danger'>{{fa-icon "sign-out"}}{{i18n 'user.log_out'}}</a></li>
|
|
||||||
{{/if}}
|
|
||||||
{{#if currentUser.staff}}
|
{{#if currentUser.staff}}
|
||||||
<li><a href={{model.adminPath}} class="btn">{{fa-icon "wrench"}}{{i18n 'admin.user.show_admin_profile'}}</a></li>
|
<li><a href={{model.adminPath}} class="btn">{{fa-icon "wrench"}}{{i18n 'admin.user.show_admin_profile'}}</a></li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if model.can_edit}}
|
|
||||||
<li>{{#link-to 'preferences' class="btn"}}{{fa-icon "cog"}}{{i18n 'user.preferences'}}{{/link-to}}</li>
|
|
||||||
{{/if}}
|
|
||||||
{{#if canInviteToForum}}
|
|
||||||
<li>{{#link-to 'userInvited' class="btn"}}{{fa-icon "user-plus"}}{{i18n 'user.invited.title'}}{{/link-to}}</li>
|
|
||||||
{{/if}}
|
|
||||||
{{#if collapsedInfo}}
|
{{#if collapsedInfo}}
|
||||||
{{#if viewingSelf}}
|
{{#if viewingSelf}}
|
||||||
<li><a {{action "expandProfile"}} href class="btn">{{fa-icon "angle-double-down"}}{{i18n 'user.expand_profile'}}</a></li>
|
<li><a {{action "expandProfile"}} href class="btn">{{fa-icon "angle-double-down"}}{{i18n 'user.expand_profile'}}</a></li>
|
||||||
|
@ -109,6 +103,8 @@
|
||||||
<div style='clear: both'></div>
|
<div style='clear: both'></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{{#unless collapsedInfo}}
|
||||||
<div class='secondary'>
|
<div class='secondary'>
|
||||||
<dl>
|
<dl>
|
||||||
{{#if model.created_at}}
|
{{#if model.created_at}}
|
||||||
|
@ -135,10 +131,10 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</dd>
|
</dd>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if model.custom_groups}}
|
{{#if model.displayGroups}}
|
||||||
<dt>{{i18n 'groups.title' count=model.custom_groups.length}}</dt>
|
<dt>{{i18n 'groups.title' count=model.displayGroups.length}}</dt>
|
||||||
<dd class='groups'>
|
<dd class='groups'>
|
||||||
{{#each group in model.custom_groups}}
|
{{#each group in model.displayGroups}}
|
||||||
<span>{{#link-to 'group' group class="group-link"}}{{group.name}}{{/link-to}}</span>
|
<span>{{#link-to 'group' group class="group-link"}}{{group.name}}{{/link-to}}</span>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</dd>
|
</dd>
|
||||||
|
@ -149,76 +145,34 @@
|
||||||
</dl>
|
</dl>
|
||||||
{{plugin-outlet "user-profile-secondary"}}
|
{{plugin-outlet "user-profile-secondary"}}
|
||||||
</div>
|
</div>
|
||||||
|
{{/unless}}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class='user-navigation'>
|
<ul class="user-nav">
|
||||||
<ul class='action-list nav-stacked'>
|
<li class='selected'>{{#link-to 'userActivity'}}{{i18n 'user.activity_stream'}}{{/link-to}}</li>
|
||||||
{{activity-filter count=model.statsCountNonPM user=model userActionType=userActionType indexStream=indexStream}}
|
{{#if canSeeNotificationHistory}}
|
||||||
{{#each stat in model.statsExcludingPms}}
|
<li>
|
||||||
{{activity-filter content=stat user=model userActionType=userActionType indexStream=indexStream}}
|
{{#link-to 'userNotifications'}}
|
||||||
{{/each}}
|
{{fa-icon "comment" class="glyph"}}
|
||||||
{{#if showBadges}}
|
{{i18n 'user.notifications'}}
|
||||||
{{#link-to 'user.badges' tagName="li"}}
|
|
||||||
{{#link-to 'user.badges'}}
|
|
||||||
<i class='glyph fa fa-certificate'></i>
|
|
||||||
{{i18n 'badges.title'}}
|
|
||||||
<span class='count'>({{model.badge_count}})</span>
|
|
||||||
{{/link-to}}
|
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
{{/if}}
|
</li>
|
||||||
{{#if canSeeNotificationHistory}}
|
|
||||||
{{#link-to 'user.notifications' tagName="li"}}
|
|
||||||
{{#link-to 'user.notifications'}}
|
|
||||||
{{fa-icon "comment" class="glyph"}}
|
|
||||||
{{i18n 'user.notifications'}}
|
|
||||||
{{/link-to}}
|
|
||||||
{{/link-to}}
|
|
||||||
{{/if}}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{{#if canSeePrivateMessages}}
|
|
||||||
<h3>{{fa-icon "envelope"}} {{i18n 'user.private_messages'}}</h3>
|
|
||||||
<ul class='action-list nav-stacked'>
|
|
||||||
<li {{bind-attr class=":noGlyph privateMessagesActive:active"}}>
|
|
||||||
{{#link-to 'userPrivateMessages.index' model}}
|
|
||||||
{{i18n 'user.messages.all'}}
|
|
||||||
{{#if model.hasPMs}}<span class='count'>({{model.private_messages_stats.all}})</span>{{/if}}
|
|
||||||
{{/link-to}}
|
|
||||||
</li>
|
|
||||||
<li {{bind-attr class=":noGlyph privateMessagesMineActive:active"}}>
|
|
||||||
{{#link-to 'userPrivateMessages.mine' model}}
|
|
||||||
{{i18n 'user.messages.mine'}}
|
|
||||||
{{#if model.hasStartedPMs}}<span class='count'>({{model.private_messages_stats.mine}})</span>{{/if}}
|
|
||||||
{{/link-to}}
|
|
||||||
</li>
|
|
||||||
<li {{bind-attr class=":noGlyph privateMessagesUnreadActive:active"}}>
|
|
||||||
{{#link-to 'userPrivateMessages.unread' model}}
|
|
||||||
{{i18n 'user.messages.unread'}}
|
|
||||||
{{#if model.hasUnreadPMs}}<span class='badge-notification unread-private-messages'>{{model.private_messages_stats.unread}}</span>{{/if}}
|
|
||||||
{{/link-to}}
|
|
||||||
</li>
|
|
||||||
{{#each groupPMStats as |group|}}
|
|
||||||
<li class="{{if group.active "active"}}">
|
|
||||||
{{#link-to 'userPrivateMessages.group' group.name}}
|
|
||||||
<i class='glyph fa fa-group'></i>
|
|
||||||
{{group.name}}
|
|
||||||
<span class='count'>({{group.count}})</span>
|
|
||||||
{{/link-to}}
|
|
||||||
</li>
|
|
||||||
{{/each}}
|
|
||||||
</ul>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
{{#if showPrivateMessages}}
|
||||||
{{#if viewingSelf}}
|
<li>{{#link-to 'userPrivateMessages'}}{{fa-icon "envelope-o"}}{{i18n 'user.private_messages'}}{{/link-to}}</li>
|
||||||
<div class='user-archive'>
|
|
||||||
{{d-button action="exportUserArchive" label="user.download_archive" icon="download"}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</section>
|
{{#if canInviteToForum}}
|
||||||
|
<li>{{#link-to 'userInvited'}}{{fa-icon "user-plus"}}{{i18n 'user.invited.title'}}{{/link-to}}</li>
|
||||||
|
{{/if}}
|
||||||
|
{{#if showBadges}}
|
||||||
|
<li>{{#link-to 'user.badges'}}{{fa-icon "certificate"}}{{i18n 'badges.title'}}{{/link-to}}</li>
|
||||||
|
{{/if}}
|
||||||
|
{{#if model.can_edit}}
|
||||||
|
<li>{{#link-to 'preferences'}}{{fa-icon "cog"}}{{i18n 'user.preferences'}}{{/link-to}}</li>
|
||||||
|
{{/if}}
|
||||||
|
</ul>
|
||||||
|
|
||||||
<section class='user-right'>
|
{{outlet}}
|
||||||
{{outlet}}
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -131,3 +131,34 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-nav {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
li {
|
||||||
|
padding: 0;
|
||||||
|
a {
|
||||||
|
color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 40%));
|
||||||
|
padding: 5px;
|
||||||
|
min-width: 90px;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 3px solid transparent;
|
||||||
|
}
|
||||||
|
a.active, a:hover {
|
||||||
|
color: $primary;
|
||||||
|
border-bottom: 3px solid dark-light-choose(scale-color($primary, $lightness: 20%), scale-color($secondary, $lightness: 20%));
|
||||||
|
}
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
margin: 5px 0px;
|
||||||
|
.fa {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
.fa.fa-comment {
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,13 +65,13 @@
|
||||||
color: $primary;
|
color: $primary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.active > a,
|
.active > a, & li > a.active
|
||||||
{
|
{
|
||||||
color: $secondary;
|
color: $secondary;
|
||||||
background-color: $quaternary;
|
background-color: $quaternary;
|
||||||
}
|
}
|
||||||
|
|
||||||
.active > a::after,
|
.active > a::after, & li > a.active::after
|
||||||
{
|
{
|
||||||
left: 90%;
|
left: 90%;
|
||||||
top: 33%;
|
top: 33%;
|
||||||
|
|
|
@ -231,7 +231,6 @@
|
||||||
background-position: center center;
|
background-position: center center;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 10px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&.group {
|
&.group {
|
||||||
|
@ -642,3 +641,15 @@
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.user-right .group-notification-menu {
|
||||||
|
float: right;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.user-right.messages .topic-list {
|
||||||
|
thead, th.views, td.views {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,10 @@ class UsersController < ApplicationController
|
||||||
|
|
||||||
@user = fetch_user_from_params(include_inactive: current_user.try(:staff?))
|
@user = fetch_user_from_params(include_inactive: current_user.try(:staff?))
|
||||||
user_serializer = UserSerializer.new(@user, scope: guardian, root: 'user')
|
user_serializer = UserSerializer.new(@user, scope: guardian, root: 'user')
|
||||||
if params[:stats].to_s == "false"
|
|
||||||
user_serializer.omit_stats = true
|
# TODO remove this options from serializer
|
||||||
end
|
user_serializer.omit_stats = true
|
||||||
|
|
||||||
topic_id = params[:include_post_count_for].to_i
|
topic_id = params[:include_post_count_for].to_i
|
||||||
if topic_id != 0
|
if topic_id != 0
|
||||||
user_serializer.topic_post_count = {topic_id => Post.where(topic_id: topic_id, user_id: @user.id).count }
|
user_serializer.topic_post_count = {topic_id => Post.where(topic_id: topic_id, user_id: @user.id).count }
|
||||||
|
|
|
@ -141,10 +141,6 @@ class User < ActiveRecord::Base
|
||||||
SiteSetting.min_username_length.to_i..SiteSetting.max_username_length.to_i
|
SiteSetting.min_username_length.to_i..SiteSetting.max_username_length.to_i
|
||||||
end
|
end
|
||||||
|
|
||||||
def custom_groups
|
|
||||||
groups.where(automatic: false, visible: true)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.username_available?(username)
|
def self.username_available?(username)
|
||||||
lower = username.downcase
|
lower = username.downcase
|
||||||
User.where(username_lower: lower).blank? && !SiteSetting.reserved_usernames.split("|").include?(username)
|
User.where(username_lower: lower).blank? && !SiteSetting.reserved_usernames.split("|").include?(username)
|
||||||
|
|
|
@ -11,7 +11,8 @@ class BasicGroupSerializer < ApplicationSerializer
|
||||||
:title,
|
:title,
|
||||||
:grant_trust_level,
|
:grant_trust_level,
|
||||||
:incoming_email,
|
:incoming_email,
|
||||||
:notification_level
|
:notification_level,
|
||||||
|
:has_messages
|
||||||
|
|
||||||
def include_incoming_email?
|
def include_incoming_email?
|
||||||
scope.is_staff?
|
scope.is_staff?
|
||||||
|
|
|
@ -70,7 +70,7 @@ class UserSerializer < BasicUserSerializer
|
||||||
:automatically_unpin_topics
|
:automatically_unpin_topics
|
||||||
|
|
||||||
has_one :invited_by, embed: :object, serializer: BasicUserSerializer
|
has_one :invited_by, embed: :object, serializer: BasicUserSerializer
|
||||||
has_many :custom_groups, embed: :object, serializer: BasicGroupSerializer
|
has_many :groups, embed: :object, serializer: BasicGroupSerializer
|
||||||
has_many :featured_user_badges, embed: :ids, serializer: UserBadgeSerializer, root: :user_badges
|
has_many :featured_user_badges, embed: :ids, serializer: UserBadgeSerializer, root: :user_badges
|
||||||
has_one :card_badge, embed: :object, serializer: BadgeSerializer
|
has_one :card_badge, embed: :object, serializer: BadgeSerializer
|
||||||
|
|
||||||
|
@ -118,6 +118,14 @@ class UserSerializer < BasicUserSerializer
|
||||||
### ATTRIBUTES
|
### ATTRIBUTES
|
||||||
###
|
###
|
||||||
|
|
||||||
|
def groups
|
||||||
|
if scope.is_admin? || object.id == scope.user.try(:id)
|
||||||
|
object.groups
|
||||||
|
else
|
||||||
|
object.groups.where(visible: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def include_email?
|
def include_email?
|
||||||
object.id && object.id == scope.user.try(:id)
|
object.id && object.id == scope.user.try(:id)
|
||||||
end
|
end
|
||||||
|
|
|
@ -378,7 +378,6 @@ en:
|
||||||
"6": "Responses"
|
"6": "Responses"
|
||||||
"7": "Mentions"
|
"7": "Mentions"
|
||||||
"9": "Quotes"
|
"9": "Quotes"
|
||||||
"10": "Starred"
|
|
||||||
"11": "Edits"
|
"11": "Edits"
|
||||||
"12": "Sent Items"
|
"12": "Sent Items"
|
||||||
"13": "Inbox"
|
"13": "Inbox"
|
||||||
|
@ -448,6 +447,7 @@ en:
|
||||||
invited_by: "Invited By"
|
invited_by: "Invited By"
|
||||||
trust_level: "Trust Level"
|
trust_level: "Trust Level"
|
||||||
notifications: "Notifications"
|
notifications: "Notifications"
|
||||||
|
statistics: "Stats"
|
||||||
desktop_notifications:
|
desktop_notifications:
|
||||||
label: "Desktop Notifications"
|
label: "Desktop Notifications"
|
||||||
not_supported: "Notifications are not supported on this browser. Sorry."
|
not_supported: "Notifications are not supported on this browser. Sorry."
|
||||||
|
|
|
@ -305,6 +305,7 @@ Discourse::Application.routes.draw do
|
||||||
get "users/:username/activity/:filter" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT}
|
get "users/:username/activity/:filter" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
get "users/:username/badges" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT}
|
get "users/:username/badges" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
get "users/:username/notifications" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT}
|
get "users/:username/notifications" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
|
get "users/:username/notifications/:filter" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
get "users/:username/pending" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT}
|
get "users/:username/pending" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
delete "users/:username" => "users#destroy", constraints: {username: USERNAME_ROUTE_FORMAT}
|
delete "users/:username" => "users#destroy", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
# The external_id constraint is to allow periods to be used in the value without becoming part of the format. ie: foo.bar.json
|
# The external_id constraint is to allow periods to be used in the value without becoming part of the format. ie: foo.bar.json
|
||||||
|
|
15
db/migrate/20151219045559_add_has_messages_to_groups.rb
Normal file
15
db/migrate/20151219045559_add_has_messages_to_groups.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
class AddHasMessagesToGroups < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
add_column :groups, :has_messages, :boolean, default: false, null: false
|
||||||
|
|
||||||
|
execute <<SQL
|
||||||
|
UPDATE groups g SET has_messages = true
|
||||||
|
WHERE exists(SELECT group_id FROM topic_allowed_groups WHERE group_id = g.id)
|
||||||
|
SQL
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_column :groups, :has_messages
|
||||||
|
end
|
||||||
|
end
|
|
@ -186,6 +186,7 @@ class TopicCreator
|
||||||
check_can_send_permission!(topic, group)
|
check_can_send_permission!(topic, group)
|
||||||
topic.topic_allowed_groups.build(group_id: group.id)
|
topic.topic_allowed_groups.build(group_id: group.id)
|
||||||
len += 1
|
len += 1
|
||||||
|
group.update_columns(:has_messages, true) unless group.has_messages
|
||||||
end
|
end
|
||||||
|
|
||||||
rollback_with!(topic, :target_group_not_found) unless len == names.length
|
rollback_with!(topic, :target_group_not_found) unless len == names.length
|
||||||
|
|
Loading…
Reference in New Issue
Block a user