mirror of
https://github.com/discourse/discourse.git
synced 2025-03-06 11:19:51 +00:00
Upgrade Notifications to fix deprecations and use store
This commit is contained in:
parent
aab9706b7a
commit
0b65c88003
@ -1,22 +1,55 @@
|
|||||||
|
const INVITED_TYPE = 8;
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
tagName: 'li',
|
tagName: 'li',
|
||||||
classNameBindings: ['notification.read', 'notification.is_warning'],
|
classNameBindings: ['notification.read', 'notification.is_warning'],
|
||||||
|
|
||||||
|
scope: function() {
|
||||||
|
return "notifications." + this.site.get("notificationLookup")[this.get("notification.notification_type")];
|
||||||
|
}.property("notification.notification_type"),
|
||||||
|
|
||||||
|
url: function() {
|
||||||
|
const it = this.get('notification');
|
||||||
|
const badgeId = it.get("data.badge_id");
|
||||||
|
if (badgeId) {
|
||||||
|
const badgeName = it.get("data.badge_name");
|
||||||
|
return Discourse.getURL('/badges/' + badgeId + '/' + badgeName.replace(/[^A-Za-z0-9_]+/g, '-').toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
const topicId = it.get('topic_id');
|
||||||
|
if (topicId) {
|
||||||
|
return Discourse.Utilities.postUrl(it.get("slug"), topicId, it.get("post_number"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it.get('notification_type') === INVITED_TYPE) {
|
||||||
|
return Discourse.getURL('/my/invited');
|
||||||
|
}
|
||||||
|
}.property("notification.data.{badge_id,badge_name}", "model.slug", "model.topic_id", "model.post_number"),
|
||||||
|
|
||||||
|
description: function() {
|
||||||
|
const badgeName = this.get("notification.data.badge_name");
|
||||||
|
if (badgeName) { return Handlebars.Utils.escapeExpression(badgeName); }
|
||||||
|
|
||||||
|
const title = this.get('notification.data.topic_title');
|
||||||
|
return Ember.isEmpty(title) ? "" : Handlebars.Utils.escapeExpression(title);
|
||||||
|
}.property("notification.data.{badge_name,topic_title}"),
|
||||||
|
|
||||||
_markRead: function(){
|
_markRead: function(){
|
||||||
var self = this;
|
this.$('a').click(() => {
|
||||||
this.$('a').click(function(){
|
this.set('notification.read', true);
|
||||||
self.set('notification.read', true);
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}.on('didInsertElement'),
|
}.on('didInsertElement'),
|
||||||
|
|
||||||
render: function(buffer) {
|
render(buffer) {
|
||||||
var notification = this.get('notification'),
|
const notification = this.get('notification');
|
||||||
text = I18n.t(this.get('scope'), Em.getProperties(notification, 'description', 'username'));
|
const description = this.get('description');
|
||||||
|
const username = notification.get('data.display_username');
|
||||||
|
const text = I18n.t(this.get('scope'), {description, username});
|
||||||
|
|
||||||
var url = notification.get('url');
|
const url = this.get('url');
|
||||||
if (url) {
|
if (url) {
|
||||||
buffer.push('<a href="' + notification.get('url') + '">' + text + '</a>');
|
buffer.push('<a href="' + url + '">' + text + '</a>');
|
||||||
} else {
|
} else {
|
||||||
buffer.push(text);
|
buffer.push(text);
|
||||||
}
|
}
|
||||||
|
@ -41,10 +41,11 @@ const HeaderController = DiscourseController.extend({
|
|||||||
if (self.get("loadingNotifications")) { return; }
|
if (self.get("loadingNotifications")) { return; }
|
||||||
|
|
||||||
self.set("loadingNotifications", true);
|
self.set("loadingNotifications", true);
|
||||||
Discourse.NotificationContainer.loadRecent().then(function(result) {
|
|
||||||
|
this.store.find('notification', {recent: true}).then(function(notifications) {
|
||||||
self.setProperties({
|
self.setProperties({
|
||||||
'currentUser.unread_notifications': 0,
|
'currentUser.unread_notifications': 0,
|
||||||
notifications: result
|
notifications
|
||||||
});
|
});
|
||||||
}).catch(function() {
|
}).catch(function() {
|
||||||
self.setProperties({
|
self.setProperties({
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
import ObjectController from 'discourse/controllers/object';
|
|
||||||
|
|
||||||
const INVITED_TYPE = 8;
|
|
||||||
|
|
||||||
export default ObjectController.extend({
|
|
||||||
|
|
||||||
notificationUrl: function(it) {
|
|
||||||
var badgeId = it.get("data.badge_id");
|
|
||||||
if (badgeId) {
|
|
||||||
var badgeName = it.get("data.badge_name");
|
|
||||||
return Discourse.getURL('/badges/' + badgeId + '/' + badgeName.replace(/[^A-Za-z0-9_]+/g, '-').toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
var topicId = it.get('topic_id');
|
|
||||||
if (topicId) {
|
|
||||||
return Discourse.Utilities.postUrl(it.get("slug"), topicId, it.get("post_number"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it.get('notification_type') === INVITED_TYPE) {
|
|
||||||
return Discourse.getURL('/my/invited');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
scope: function() {
|
|
||||||
return "notifications." + this.site.get("notificationLookup")[this.get("notification_type")];
|
|
||||||
}.property("notification_type"),
|
|
||||||
|
|
||||||
username: Em.computed.alias("data.display_username"),
|
|
||||||
|
|
||||||
url: function() {
|
|
||||||
return this.notificationUrl(this);
|
|
||||||
}.property("data.{badge_id,badge_name}", "slug", "topic_id", "post_number"),
|
|
||||||
|
|
||||||
description: function() {
|
|
||||||
const badgeName = this.get("data.badge_name");
|
|
||||||
if (badgeName) { return Handlebars.Utils.escapeExpression(badgeName); }
|
|
||||||
return this.blank("data.topic_title") ? "" : Handlebars.Utils.escapeExpression(this.get("data.topic_title"));
|
|
||||||
}.property("data.{badge_name,topic_title}")
|
|
||||||
|
|
||||||
});
|
|
@ -1,43 +1,21 @@
|
|||||||
|
|
||||||
export default Ember.ArrayController.extend({
|
export default Ember.ArrayController.extend({
|
||||||
needs: ['user-notifications', 'application'],
|
needs: ['application'],
|
||||||
loading: false,
|
|
||||||
|
|
||||||
_showFooter: function() {
|
_showFooter: function() {
|
||||||
this.set("controllers.application.showFooter", !this.get("canLoadMore"));
|
this.set("controllers.application.showFooter", !this.get("model.canLoadMore"));
|
||||||
}.observes("canLoadMore"),
|
}.observes("model.canLoadMore"),
|
||||||
|
|
||||||
showDismissButton: function() {
|
showDismissButton: Ember.computed.gt('user.total_unread_notifications', 0),
|
||||||
return this.get('user').total_unread_notifications > 0;
|
|
||||||
}.property('user'),
|
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
resetNew: function() {
|
resetNew: function() {
|
||||||
var self = this;
|
Discourse.ajax('/notifications/mark-read', { method: 'PUT' }).then(() => {
|
||||||
Discourse.NotificationContainer.resetNew().then(function() {
|
this.setEach('read', true);
|
||||||
self.get('controllers.user-notifications').setEach('read', true);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
loadMore: function() {
|
loadMore: function() {
|
||||||
if (this.get('canLoadMore') && !this.get('loading')) {
|
this.get('model').loadMore();
|
||||||
this.set('loading', true);
|
|
||||||
var self = this;
|
|
||||||
Discourse.NotificationContainer.loadHistory(
|
|
||||||
self.get('model.lastObject.created_at'),
|
|
||||||
self.get('user.username')).then(function(result) {
|
|
||||||
self.set('loading', false);
|
|
||||||
var notifications = result.get('content');
|
|
||||||
self.pushObjects(notifications);
|
|
||||||
// Stop trying if it's the end
|
|
||||||
if (notifications && (notifications.length === 0 || notifications.length < 60)) {
|
|
||||||
self.set('canLoadMore', false);
|
|
||||||
}
|
|
||||||
}).catch(function(error) {
|
|
||||||
self.set('loading', false);
|
|
||||||
Em.Logger.error(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -38,13 +38,13 @@ export default {
|
|||||||
app.register('session:main', Session.current(), { instantiate: false });
|
app.register('session:main', Session.current(), { instantiate: false });
|
||||||
injectAll(app, 'session');
|
injectAll(app, 'session');
|
||||||
|
|
||||||
|
app.register('store:main', Store);
|
||||||
|
inject(app, 'store', 'route', 'controller');
|
||||||
|
|
||||||
app.register('current-user:main', Discourse.User.current(), { instantiate: false });
|
app.register('current-user:main', Discourse.User.current(), { instantiate: false });
|
||||||
inject(app, 'currentUser', 'component', 'route', 'controller');
|
inject(app, 'currentUser', 'component', 'route', 'controller');
|
||||||
|
|
||||||
app.register('message-bus:main', window.MessageBus, { instantiate: false });
|
app.register('message-bus:main', window.MessageBus, { instantiate: false });
|
||||||
inject(app, 'messageBus', 'route', 'controller', 'view');
|
inject(app, 'messageBus', 'route', 'controller', 'view');
|
||||||
|
|
||||||
app.register('store:main', Store);
|
|
||||||
inject(app, 'store', 'route', 'controller');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,22 +1,15 @@
|
|||||||
/**
|
// Provides the ability to load more items for a view which is scrolled to the bottom.
|
||||||
Provides the ability to load more items for a view which is scrolled to the bottom.
|
|
||||||
**/
|
|
||||||
|
|
||||||
export default Em.Mixin.create(Ember.ViewTargetActionSupport, Discourse.Scrolling, {
|
export default Em.Mixin.create(Ember.ViewTargetActionSupport, Discourse.Scrolling, {
|
||||||
|
|
||||||
scrolled: function() {
|
scrolled: function() {
|
||||||
var eyeline = this.get('eyeline');
|
const eyeline = this.get('eyeline');
|
||||||
if (eyeline) { eyeline.update(); }
|
if (eyeline) { eyeline.update(); }
|
||||||
},
|
},
|
||||||
|
|
||||||
_bindEyeline: function() {
|
_bindEyeline: function() {
|
||||||
var eyeline = new Discourse.Eyeline(this.get('eyelineSelector') + ":last");
|
const eyeline = new Discourse.Eyeline(this.get('eyelineSelector') + ":last");
|
||||||
this.set('eyeline', eyeline);
|
this.set('eyeline', eyeline);
|
||||||
|
eyeline.on('sawBottom', () => this.send('loadMore'));
|
||||||
var self = this;
|
|
||||||
eyeline.on('sawBottom', function() {
|
|
||||||
self.send('loadMore');
|
|
||||||
});
|
|
||||||
this.bindScrolling();
|
this.bindScrolling();
|
||||||
}.on('didInsertElement'),
|
}.on('didInsertElement'),
|
||||||
|
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
Discourse.NotificationContainer = Ember.ArrayProxy.extend({
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
Discourse.NotificationContainer.reopenClass({
|
|
||||||
|
|
||||||
createFromJson: function(json_array) {
|
|
||||||
return Discourse.NotificationContainer.create({content: json_array});
|
|
||||||
},
|
|
||||||
|
|
||||||
createFromError: function(error) {
|
|
||||||
return Discourse.NotificationContainer.create({
|
|
||||||
content: [],
|
|
||||||
error: true,
|
|
||||||
forbidden: error.status === 403
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
loadRecent: function() {
|
|
||||||
// TODO - add .json (breaks tests atm)
|
|
||||||
return Discourse.ajax('/notifications').then(function(result) {
|
|
||||||
return Discourse.NotificationContainer.createFromJson(result);
|
|
||||||
}).catch(function(error) {
|
|
||||||
// TODO HeaderController can't handle a createFromError
|
|
||||||
// just throw for now
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
loadHistory: function(beforeDate, username) {
|
|
||||||
var url = '/notifications/history.json',
|
|
||||||
params = [
|
|
||||||
beforeDate ? ('before=' + beforeDate) : null,
|
|
||||||
username ? ('user=' + username) : null
|
|
||||||
];
|
|
||||||
|
|
||||||
// Remove nulls
|
|
||||||
params = params.filter(function(param) { return !!param; });
|
|
||||||
// Build URL
|
|
||||||
params.forEach(function(param, idx) {
|
|
||||||
url = url + (idx === 0 ? '?' : '&') + param;
|
|
||||||
});
|
|
||||||
|
|
||||||
return Discourse.ajax(url).then(function(result) {
|
|
||||||
return Discourse.NotificationContainer.createFromJson(result);
|
|
||||||
}).catch(function(error) {
|
|
||||||
return Discourse.NotificationContainer.createFromError(error);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
resetNew: function() {
|
|
||||||
return Discourse.ajax("/notifications/reset-new", {type: 'PUT'});
|
|
||||||
}
|
|
||||||
});
|
|
@ -4,6 +4,10 @@ export default Ember.ArrayProxy.extend({
|
|||||||
totalRows: 0,
|
totalRows: 0,
|
||||||
refreshing: false,
|
refreshing: false,
|
||||||
|
|
||||||
|
canLoadMore: function() {
|
||||||
|
return this.get('length') < this.get('totalRows');
|
||||||
|
}.property('totalRows', 'length'),
|
||||||
|
|
||||||
loadMore() {
|
loadMore() {
|
||||||
const loadMoreUrl = this.get('loadMoreUrl');
|
const loadMoreUrl = this.get('loadMoreUrl');
|
||||||
if (!loadMoreUrl) { return; }
|
if (!loadMoreUrl) { return; }
|
||||||
|
@ -434,16 +434,13 @@ User.reopenClass(Discourse.Singleton, {
|
|||||||
return user.findDetails(options);
|
return user.findDetails(options);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
// TODO: Use app.register and junk Discourse.Singleton
|
||||||
The current singleton will retrieve its attributes from the `PreloadStore`
|
|
||||||
if it exists. Otherwise, no instance is created.
|
|
||||||
|
|
||||||
@method createCurrent
|
|
||||||
@returns {Discourse.User} the user, if logged in.
|
|
||||||
**/
|
|
||||||
createCurrent: function() {
|
createCurrent: function() {
|
||||||
var userJson = PreloadStore.get('currentUser');
|
var userJson = PreloadStore.get('currentUser');
|
||||||
if (userJson) { return Discourse.User.create(userJson); }
|
if (userJson) {
|
||||||
|
const store = Discourse.__container__.lookup('store:main');
|
||||||
|
return store.createRecord('user', userJson);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,31 +1,22 @@
|
|||||||
import ShowFooter from "discourse/mixins/show-footer";
|
import ShowFooter from "discourse/mixins/show-footer";
|
||||||
|
import ViewingActionType from "discourse/mixins/viewing-action-type";
|
||||||
|
|
||||||
export default Discourse.Route.extend(ShowFooter, {
|
export default Discourse.Route.extend(ShowFooter, ViewingActionType, {
|
||||||
actions: {
|
actions: {
|
||||||
didTransition: function() {
|
didTransition() {
|
||||||
this.controllerFor("user_notifications")._showFooter();
|
this.controllerFor("user-notifications")._showFooter();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
model: function() {
|
model() {
|
||||||
var user = this.modelFor('user');
|
var user = this.modelFor('user');
|
||||||
return Discourse.NotificationContainer.loadHistory(undefined, user.get('username'));
|
return this.store.find('notification', {username: user.get('username')});
|
||||||
},
|
},
|
||||||
|
|
||||||
setupController: function(controller, model) {
|
setupController(controller, model) {
|
||||||
controller.set('model', model);
|
controller.set('model', model);
|
||||||
controller.set('user', this.modelFor('user'));
|
controller.set('user', this.modelFor('user'));
|
||||||
|
this.viewingActionType(-1);
|
||||||
if (this.controllerFor('user_activity').get('content')) {
|
|
||||||
this.controllerFor('user_activity').set('userActionType', -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// properly initialize "canLoadMore"
|
|
||||||
controller.set("canLoadMore", model.get("length") === 60);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderTemplate: function() {
|
|
||||||
this.render('user-notification-history', {into: 'user'});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
{{#conditional-loading-spinner condition=loadingNotifications}}
|
{{#conditional-loading-spinner condition=loadingNotifications}}
|
||||||
{{#if content}}
|
{{#if content}}
|
||||||
<ul>
|
<ul>
|
||||||
{{#each n in model itemController="notification"}}
|
{{#each n in model}}
|
||||||
{{notification-item notification=n scope=n.scope}}
|
{{notification-item notification=n}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
<li class="read last">
|
<li class="read last">
|
||||||
<a href="{{unbound myNotificationsUrl}}">{{i18n 'notifications.more'}}…</a>
|
<a href="{{unbound myNotificationsUrl}}">{{i18n 'notifications.more'}}…</a>
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#each n in model itemController="notification"}}
|
{{#each n in model}}
|
||||||
<div {{bind-attr class=":item :notification n.read::unread"}}>
|
<div {{bind-attr class=":item :notification n.read::unread"}}>
|
||||||
{{notification-item notification=n scope=n.scope}}
|
{{notification-item notification=n}}
|
||||||
<span class="time">
|
<span class="time">
|
||||||
{{format-date n.created_at leaveAgo="true"}}
|
{{format-date n.created_at leaveAgo="true"}}
|
||||||
</span>
|
</span>
|
||||||
@ -24,7 +24,7 @@
|
|||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
{{#conditional-loading-spinner condition=loading}}
|
{{#conditional-loading-spinner condition=loading}}
|
||||||
{{#unless canLoadMore}}
|
{{#unless model.canLoadMore}}
|
||||||
{{#if showDismissButton}}
|
{{#if showDismissButton}}
|
||||||
<div class='notification-buttons'>
|
<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>
|
<button title="{{i18n 'user.dismiss_notifications_tooltip'}}" id='dismiss-notifications' class='btn notifications-read' {{action "resetNew"}}>{{i18n 'user.dismiss_notifications'}}</button>
|
||||||
|
@ -2,6 +2,5 @@ import LoadMore from "discourse/mixins/load-more";
|
|||||||
|
|
||||||
export default Ember.View.extend(LoadMore, {
|
export default Ember.View.extend(LoadMore, {
|
||||||
eyelineSelector: '.user-stream .notification',
|
eyelineSelector: '.user-stream .notification',
|
||||||
classNames: ['user-stream', 'notification-history'],
|
classNames: ['user-stream', 'notification-history']
|
||||||
templateName: 'user/notifications'
|
|
||||||
});
|
});
|
@ -1,56 +1,51 @@
|
|||||||
|
require_dependency 'notification_serializer'
|
||||||
|
|
||||||
class NotificationsController < ApplicationController
|
class NotificationsController < ApplicationController
|
||||||
|
|
||||||
before_filter :ensure_logged_in
|
before_filter :ensure_logged_in
|
||||||
|
|
||||||
def recent
|
def index
|
||||||
notifications = Notification.recent_report(current_user, 10)
|
user = current_user
|
||||||
|
if params[:recent].present?
|
||||||
|
notifications = Notification.recent_report(current_user, 10)
|
||||||
|
|
||||||
if notifications.present?
|
if notifications.present?
|
||||||
# ordering can be off due to PMs
|
# ordering can be off due to PMs
|
||||||
max_id = notifications.map(&:id).max
|
max_id = notifications.map(&:id).max
|
||||||
current_user.saw_notification_id(max_id) unless params.has_key?(:silent)
|
current_user.saw_notification_id(max_id) unless params.has_key?(:silent)
|
||||||
|
end
|
||||||
|
current_user.reload
|
||||||
|
current_user.publish_notifications_state
|
||||||
|
|
||||||
|
render_serialized(notifications, NotificationSerializer, root: :notifications)
|
||||||
|
else
|
||||||
|
offset = params[:offset].to_i
|
||||||
|
user = User.find_by_username(params[:username].to_s) if params[:username]
|
||||||
|
|
||||||
|
guardian.ensure_can_see_notifications!(user)
|
||||||
|
|
||||||
|
notifications = Notification.where(user_id: user.id)
|
||||||
|
.visible
|
||||||
|
.includes(:topic)
|
||||||
|
.order(created_at: :desc)
|
||||||
|
|
||||||
|
total_rows = notifications.dup.count
|
||||||
|
notifications = notifications.offset(offset).limit(60)
|
||||||
|
render_json_dump(notifications: serialize_data(notifications, NotificationSerializer),
|
||||||
|
total_rows_notifications: total_rows,
|
||||||
|
load_more_notifications: notifications_path(username: user.username, offset: offset + 60))
|
||||||
end
|
end
|
||||||
current_user.reload
|
|
||||||
current_user.publish_notifications_state
|
|
||||||
|
|
||||||
render_serialized(notifications, NotificationSerializer)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def history
|
def mark_read
|
||||||
params.permit(:before, :user)
|
Notification.where(user_id: current_user.id).includes(:topic).where(read: false).update_all(read: true)
|
||||||
params[:before] ||= 1.day.from_now
|
|
||||||
|
|
||||||
user = current_user
|
|
||||||
user = User.find_by_username(params[:user].to_s) if params[:user]
|
|
||||||
|
|
||||||
unless guardian.can_see_notifications?(user)
|
|
||||||
return render json: {errors: [I18n.t('js.errors.reasons.forbidden')]}, status: 403
|
|
||||||
end
|
|
||||||
|
|
||||||
notifications = Notification.where(user_id: user.id)
|
|
||||||
.visible
|
|
||||||
.includes(:topic)
|
|
||||||
.limit(60)
|
|
||||||
.where('created_at < ?', params[:before])
|
|
||||||
.order(created_at: :desc)
|
|
||||||
|
|
||||||
render_serialized(notifications, NotificationSerializer)
|
|
||||||
end
|
|
||||||
|
|
||||||
def reset_new
|
|
||||||
params.permit(:user)
|
|
||||||
|
|
||||||
user = current_user
|
|
||||||
if params[:user]
|
|
||||||
user = User.find_by_username(params[:user].to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
Notification.where(user_id: user.id).includes(:topic).where(read: false).update_all(read: true)
|
|
||||||
|
|
||||||
current_user.saw_notification_id(Notification.recent_report(current_user, 1).max)
|
current_user.saw_notification_id(Notification.recent_report(current_user, 1).max)
|
||||||
current_user.reload
|
current_user.reload
|
||||||
current_user.publish_notifications_state
|
current_user.publish_notifications_state
|
||||||
|
|
||||||
render nothing: true
|
render json: success_json
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
class NotificationSerializer < ApplicationSerializer
|
class NotificationSerializer < ApplicationSerializer
|
||||||
|
|
||||||
attributes :notification_type,
|
attributes :id,
|
||||||
|
:notification_type,
|
||||||
:read,
|
:read,
|
||||||
:created_at,
|
:created_at,
|
||||||
:post_number,
|
:post_number,
|
||||||
|
@ -329,9 +329,8 @@ Discourse::Application.routes.draw do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
get "notifications" => "notifications#recent"
|
get 'notifications' => 'notifications#index'
|
||||||
get "notifications/history" => "notifications#history"
|
put 'notifications/mark-read' => 'notifications#mark_read'
|
||||||
put "notifications/reset-new" => 'notifications#reset_new'
|
|
||||||
|
|
||||||
match "/auth/:provider/callback", to: "users/omniauth_callbacks#complete", via: [:get, :post]
|
match "/auth/:provider/callback", to: "users/omniauth_callbacks#complete", via: [:get, :post]
|
||||||
match "/auth/failure", to: "users/omniauth_callbacks#failure", via: [:get, :post]
|
match "/auth/failure", to: "users/omniauth_callbacks#failure", via: [:get, :post]
|
||||||
|
@ -6,17 +6,17 @@ describe NotificationsController do
|
|||||||
let!(:user) { log_in }
|
let!(:user) { log_in }
|
||||||
|
|
||||||
it 'should succeed for recent' do
|
it 'should succeed for recent' do
|
||||||
xhr :get, :recent
|
xhr :get, :index, recent: true
|
||||||
expect(response).to be_success
|
expect(response).to be_success
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should succeed for history' do
|
it 'should succeed for history' do
|
||||||
xhr :get, :history
|
xhr :get, :index
|
||||||
expect(response).to be_success
|
expect(response).to be_success
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should succeed for history' do
|
it 'should succeed' do
|
||||||
xhr :get, :reset_new
|
xhr :put, :mark_read
|
||||||
expect(response).to be_success
|
expect(response).to be_success
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ describe NotificationsController do
|
|||||||
notification = Fabricate(:notification, user: user)
|
notification = Fabricate(:notification, user: user)
|
||||||
expect(user.reload.unread_notifications).to eq(1)
|
expect(user.reload.unread_notifications).to eq(1)
|
||||||
expect(user.reload.total_unread_notifications).to eq(1)
|
expect(user.reload.total_unread_notifications).to eq(1)
|
||||||
xhr :get, :recent
|
xhr :get, :index, recent: true
|
||||||
expect(user.reload.unread_notifications).to eq(0)
|
expect(user.reload.unread_notifications).to eq(0)
|
||||||
expect(user.reload.total_unread_notifications).to eq(1)
|
expect(user.reload.total_unread_notifications).to eq(1)
|
||||||
end
|
end
|
||||||
@ -33,7 +33,7 @@ describe NotificationsController do
|
|||||||
notification = Fabricate(:notification, user: user)
|
notification = Fabricate(:notification, user: user)
|
||||||
expect(user.reload.unread_notifications).to eq(1)
|
expect(user.reload.unread_notifications).to eq(1)
|
||||||
expect(user.reload.total_unread_notifications).to eq(1)
|
expect(user.reload.total_unread_notifications).to eq(1)
|
||||||
xhr :get, :recent, silent: true
|
xhr :get, :index, recent: true, silent: true
|
||||||
expect(user.reload.unread_notifications).to eq(1)
|
expect(user.reload.unread_notifications).to eq(1)
|
||||||
expect(user.reload.total_unread_notifications).to eq(1)
|
expect(user.reload.total_unread_notifications).to eq(1)
|
||||||
end
|
end
|
||||||
@ -42,7 +42,7 @@ describe NotificationsController do
|
|||||||
notification = Fabricate(:notification, user: user)
|
notification = Fabricate(:notification, user: user)
|
||||||
expect(user.reload.unread_notifications).to eq(1)
|
expect(user.reload.unread_notifications).to eq(1)
|
||||||
expect(user.reload.total_unread_notifications).to eq(1)
|
expect(user.reload.total_unread_notifications).to eq(1)
|
||||||
xhr :put, :reset_new
|
xhr :put, :mark_read
|
||||||
user.reload
|
user.reload
|
||||||
expect(user.reload.unread_notifications).to eq(0)
|
expect(user.reload.unread_notifications).to eq(0)
|
||||||
expect(user.reload.total_unread_notifications).to eq(0)
|
expect(user.reload.total_unread_notifications).to eq(0)
|
||||||
@ -51,7 +51,7 @@ describe NotificationsController do
|
|||||||
|
|
||||||
context 'when not logged in' do
|
context 'when not logged in' do
|
||||||
it 'should raise an error' do
|
it 'should raise an error' do
|
||||||
expect { xhr :get, :recent }.to raise_error(Discourse::NotLoggedIn)
|
expect { xhr :get, :index, recent: true }.to raise_error(Discourse::NotLoggedIn)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
moduleFor("controller:header", "controller:header", {
|
|
||||||
needs: ['controller:application']
|
|
||||||
});
|
|
||||||
|
|
||||||
test("showNotifications action", function() {
|
|
||||||
let resolveRequestWith;
|
|
||||||
const request = new Ember.RSVP.Promise(function(resolve) {
|
|
||||||
resolveRequestWith = resolve;
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentUser = Discourse.User.create({ unread_notifications: 1});
|
|
||||||
const controller = this.subject({ currentUser: currentUser });
|
|
||||||
const viewSpy = { showDropdownBySelector: sinon.spy() };
|
|
||||||
|
|
||||||
sandbox.stub(Discourse, "ajax").withArgs("/notifications").returns(request);
|
|
||||||
|
|
||||||
Ember.run(function() {
|
|
||||||
controller.send("showNotifications", viewSpy);
|
|
||||||
});
|
|
||||||
|
|
||||||
equal(controller.get("notifications"), null, "notifications are null before data has finished loading");
|
|
||||||
equal(currentUser.get("unread_notifications"), 1, "current user's unread notifications count is not zeroed before data has finished loading");
|
|
||||||
ok(viewSpy.showDropdownBySelector.calledWith("#user-notifications"), "dropdown with loading glyph is shown before data has finished loading");
|
|
||||||
|
|
||||||
Ember.run(function() {
|
|
||||||
resolveRequestWith(["notification"]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Can't use deepEquals because controller.get("notifications") is an ArrayProxy, not an Array
|
|
||||||
ok(controller.get("notifications").indexOf("notification") !== -1, "notification is in the controller");
|
|
||||||
equal(currentUser.get("unread_notifications"), 0, "current user's unread notifications count is zeroed after data has finished loading");
|
|
||||||
ok(viewSpy.showDropdownBySelector.calledWith("#user-notifications"), "dropdown with notifications is shown after data has finished loading");
|
|
||||||
});
|
|
@ -1,56 +0,0 @@
|
|||||||
import Site from 'discourse/models/site';
|
|
||||||
|
|
||||||
function buildFixture() {
|
|
||||||
return {
|
|
||||||
notification_type: 1, //mentioned
|
|
||||||
post_number: 1,
|
|
||||||
topic_id: 1234,
|
|
||||||
slug: "a-slug",
|
|
||||||
data: {
|
|
||||||
topic_title: "some title",
|
|
||||||
display_username: "velesin"
|
|
||||||
},
|
|
||||||
site: Site.current()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
moduleFor("controller:notification");
|
|
||||||
|
|
||||||
test("scope property is correct", function() {
|
|
||||||
const controller = this.subject(buildFixture());
|
|
||||||
equal(controller.get("scope"), "notifications.mentioned");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("username property is correct", function() {
|
|
||||||
const controller = this.subject(buildFixture());
|
|
||||||
equal(controller.get("username"), "velesin");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("description property returns badge name when there is one", function() {
|
|
||||||
const fixtureWithBadgeName = _.extend({}, buildFixture(), { data: { badge_name: "badge" } });
|
|
||||||
const controller = this.subject(fixtureWithBadgeName);
|
|
||||||
equal(controller.get("description"), "badge");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("description property returns empty string when there is no topic title", function() {
|
|
||||||
const fixtureWithEmptyTopicTitle = _.extend({}, buildFixture(), { data: { topic_title: "" } });
|
|
||||||
const controller = this.subject(fixtureWithEmptyTopicTitle);
|
|
||||||
equal(controller.get("description"), "");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("description property returns topic title", function() {
|
|
||||||
const fixtureWithTopicTitle = _.extend({}, buildFixture(), { data: { topic_title: "topic" } });
|
|
||||||
const controller = this.subject(fixtureWithTopicTitle);
|
|
||||||
equal(controller.get("description"), "topic");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("url property returns badge's url when there is a badge", function() {
|
|
||||||
const fixtureWithBadge = _.extend({}, buildFixture(), { data: { badge_id: 1, badge_name: "Badge Name"} });
|
|
||||||
const controller = this.subject(fixtureWithBadge);
|
|
||||||
equal(controller.get("url"), "/badges/1/badge-name");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("url property returns topic's url when there is a topic", function() {
|
|
||||||
const controller = this.subject(buildFixture());
|
|
||||||
equal(controller.get("url"), "/t/a-slug/1234");
|
|
||||||
});
|
|
@ -1,2 +1,2 @@
|
|||||||
/*jshint maxlen:10000000 */
|
/*jshint maxlen:10000000 */
|
||||||
export default {"/notifications": [ { notification_type: 2, read: true, post_number: 2, topic_id: 1234, slug: "a-slug", data: { topic_title: "some title", display_username: "velesin" } } ] };
|
export default {"/notifications": {notifications: [ { id: 123, notification_type: 2, read: true, post_number: 2, topic_id: 1234, slug: "a-slug", data: { topic_title: "some title", display_username: "velesin" } } ] }};
|
||||||
|
@ -36,7 +36,7 @@ test('updating simultaneously', function() {
|
|||||||
expect(2);
|
expect(2);
|
||||||
|
|
||||||
const store = createStore();
|
const store = createStore();
|
||||||
store.find('widget', 123).then(function(widget) {
|
return store.find('widget', 123).then(function(widget) {
|
||||||
|
|
||||||
const firstPromise = widget.update({ name: 'new name' });
|
const firstPromise = widget.update({ name: 'new name' });
|
||||||
const secondPromise = widget.update({ name: 'new name' });
|
const secondPromise = widget.update({ name: 'new name' });
|
||||||
@ -90,7 +90,7 @@ test('creating simultaneously', function() {
|
|||||||
|
|
||||||
test('destroyRecord', function() {
|
test('destroyRecord', function() {
|
||||||
const store = createStore();
|
const store = createStore();
|
||||||
store.find('widget', 123).then(function(widget) {
|
return store.find('widget', 123).then(function(widget) {
|
||||||
widget.destroyRecord().then(function(result) {
|
widget.destroyRecord().then(function(result) {
|
||||||
ok(result);
|
ok(result);
|
||||||
});
|
});
|
||||||
|
@ -20,6 +20,7 @@ test('pagination support', function() {
|
|||||||
equal(rs.get('totalRows'), 4);
|
equal(rs.get('totalRows'), 4);
|
||||||
ok(rs.get('loadMoreUrl'), 'has a url to load more');
|
ok(rs.get('loadMoreUrl'), 'has a url to load more');
|
||||||
ok(!rs.get('loadingMore'), 'it is not loading more');
|
ok(!rs.get('loadingMore'), 'it is not loading more');
|
||||||
|
ok(rs.get('canLoadMore'));
|
||||||
|
|
||||||
const promise = rs.loadMore();
|
const promise = rs.loadMore();
|
||||||
|
|
||||||
@ -28,6 +29,7 @@ test('pagination support', function() {
|
|||||||
ok(!rs.get('loadingMore'), 'it finished loading more');
|
ok(!rs.get('loadingMore'), 'it finished loading more');
|
||||||
equal(rs.get('length'), 4);
|
equal(rs.get('length'), 4);
|
||||||
ok(!rs.get('loadMoreUrl'));
|
ok(!rs.get('loadMoreUrl'));
|
||||||
|
ok(!rs.get('canLoadMore'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user