mirror of
https://github.com/viq/NewsBlur.git
synced 2025-04-13 09:38:09 +00:00
Notifications now save their filter and type. Also updates the UI.
This commit is contained in:
parent
201b024261
commit
fd4db68f7b
9 changed files with 221 additions and 63 deletions
|
@ -22,6 +22,7 @@ class MUserFeedNotification(mongo.Document):
|
|||
user_id = mongo.IntField()
|
||||
feed_id = mongo.IntField()
|
||||
frequency = mongoengine_fields.IntEnumField(NotificationFrequency)
|
||||
is_focus = mongo.BooleanField()
|
||||
last_notification_date = mongo.DateTimeField(default=datetime.datetime.now)
|
||||
is_email = mongo.BooleanField()
|
||||
is_web = mongo.BooleanField()
|
||||
|
@ -58,12 +59,14 @@ class MUserFeedNotification(mongo.Document):
|
|||
|
||||
for feed in notifications:
|
||||
notifications_by_feed[feed.feed_id] = {
|
||||
'notifications': [],
|
||||
'notification_freq': feed.frequency
|
||||
'notification_types': [],
|
||||
'notification_filter': "focus" if feed.is_focus else "unread",
|
||||
}
|
||||
if feed.is_email: notifications_by_feed[feed.feed_id]['notifications'].append('email')
|
||||
if feed.is_web: notifications_by_feed[feed.feed_id]['notifications'].append('web')
|
||||
if feed.is_ios: notifications_by_feed[feed.feed_id]['notifications'].append('ios')
|
||||
if feed.is_android: notifications_by_feed[feed.feed_id]['notifications'].append('android')
|
||||
if feed.is_email: notifications_by_feed[feed.feed_id]['notification_types'].append('email')
|
||||
if feed.is_web: notifications_by_feed[feed.feed_id]['notification_types'].append('web')
|
||||
if feed.is_ios: notifications_by_feed[feed.feed_id]['notification_types'].append('ios')
|
||||
if feed.is_android: notifications_by_feed[feed.feed_id]['notification_types'].append('android')
|
||||
|
||||
return notifications_by_feed
|
||||
return notifications_by_feed
|
||||
|
||||
|
|
@ -3,5 +3,6 @@ from apps.notifications import views
|
|||
from oauth2_provider import views as op_views
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^/?$', views.notifications_by_feed, name='notifications-by-feed'),
|
||||
url(r'^$', views.notifications_by_feed, name='notifications-by-feed'),
|
||||
url(r'^feed/?$', views.set_notifications_for_feed, name='set-notifications-for-feed'),
|
||||
)
|
|
@ -10,4 +10,38 @@ def notifications_by_feed(request):
|
|||
user = get_user(request)
|
||||
notifications_by_feed = MUserFeedNotification.feeds_for_user(user.pk)
|
||||
|
||||
return notifications_by_feed
|
||||
return notifications_by_feed
|
||||
|
||||
@ajax_login_required
|
||||
@json.json_view
|
||||
def set_notifications_for_feed(request):
|
||||
user = get_user(request)
|
||||
feed_id = request.POST['feed_id']
|
||||
notification_types = request.POST.getlist('notification_types')
|
||||
notification_filter = request.POST.get('notification_filter')
|
||||
|
||||
try:
|
||||
notification = MUserFeedNotification.objects.get(user_id=user.pk, feed_id=feed_id)
|
||||
except MUserFeedNotification.DoesNotExist:
|
||||
params = {
|
||||
"user_id": user.pk,
|
||||
"feed_id": feed_id,
|
||||
}
|
||||
notification = MUserFeedNotification.objects.create(**params)
|
||||
|
||||
notification.is_focus = bool(notification_filter == "focus")
|
||||
notification.is_email = bool('email' in notification_types)
|
||||
notification.is_ios = bool('ios' in notification_types)
|
||||
notification.is_android = bool('android' in notification_types)
|
||||
notification.is_web = bool('web' in notification_types)
|
||||
notification.save()
|
||||
|
||||
if (not notification.is_email and
|
||||
not notification.is_ios and
|
||||
not notification.is_android and
|
||||
not notification.is_web):
|
||||
notification.delete()
|
||||
|
||||
notifications_by_feed = MUserFeedNotification.feeds_for_user(user.pk)
|
||||
|
||||
return {"notifications_by_feed": notifications_by_feed}
|
||||
|
|
|
@ -8821,6 +8821,10 @@ form.opml_import_form input {
|
|||
/* = Notifications Modal = */
|
||||
/* ======================= */
|
||||
|
||||
.NB-modal-notifications .NB-modal-title .NB-icon {
|
||||
background: transparent url('/media/embed/icons/circular/menu_icn_notifications_128.png');
|
||||
background-size: 28px;
|
||||
}
|
||||
.NB-modal.NB-modal-notifications .NB-fieldset {
|
||||
border-bottom: none;
|
||||
width: 100%;
|
||||
|
@ -8836,21 +8840,54 @@ form.opml_import_form input {
|
|||
float: left;
|
||||
overflow: hidden;
|
||||
}
|
||||
.NB-modal-notifications .NB-modal-section-site {
|
||||
margin: 12px 0 0;
|
||||
}
|
||||
|
||||
.NB-feed-notification {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid #F0F0F0;
|
||||
}
|
||||
.NB-feed-notification .NB-feed-notification-filter {
|
||||
float: right;
|
||||
margin: 0 12px;
|
||||
.NB-feed-notification:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.NB-feed-notification .NB-feed-title {
|
||||
font-size: 12px;
|
||||
padding: 0 260px 0 24px;
|
||||
}
|
||||
.NB-feed-notification .NB-feed-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 0;
|
||||
}
|
||||
.NB-feed-notification .NB-feed-frequency-icon {
|
||||
float: left;
|
||||
margin: 0 7px 0 0;
|
||||
clear: left;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 4px 7px 0 0;
|
||||
}
|
||||
.NB-feed-notification .NB-feed-frequency {
|
||||
float: left;
|
||||
color: #A0A0A0;
|
||||
font-size: 10px;
|
||||
margin: 2px 0 0 0;
|
||||
}
|
||||
|
||||
.NB-feed-notification .NB-feed-notification-controls {
|
||||
position: relative;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
.NB-feed-notification .NB-feed-notification-filter {
|
||||
float: right;
|
||||
margin: 0 12px;
|
||||
}
|
||||
.NB-feed-notification .NB-feed-notification-filter .NB-unread-icon,
|
||||
.NB-feed-notification .NB-feed-notification-filter .NB-focus-icon {
|
||||
|
@ -8867,21 +8904,24 @@ form.opml_import_form input {
|
|||
background-size: 8px;
|
||||
}
|
||||
.NB-feed-notification .segmented-control {
|
||||
margin-top: -2px;
|
||||
margin-bottom: 2px;
|
||||
margin: 0 0 4px 0;
|
||||
}
|
||||
.NB-feed-notification .segmented-control li {
|
||||
padding: 2px 6px;
|
||||
font-size: 10px;
|
||||
min-width: 36px;
|
||||
}
|
||||
.NB-feed-notification .NB-feed-notifications {
|
||||
.NB-feed-notification .segmented-control li:not(.NB-active) {
|
||||
color: #A0A0A0;
|
||||
}
|
||||
.NB-feed-notification .NB-feed-notification-types {
|
||||
float: right;
|
||||
clear: right;
|
||||
}
|
||||
.NB-modal-notifications .NB-modal-section-site {
|
||||
margin: 12px 0 0;
|
||||
.NB-feed-notification .NB-feed-notification-filter-focus {
|
||||
width: 82px;
|
||||
}
|
||||
|
||||
|
||||
/* ===================== */
|
||||
/* = Feedchooser Modal = */
|
||||
/* ===================== */
|
||||
|
|
|
@ -1482,6 +1482,18 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({
|
|||
}
|
||||
},
|
||||
|
||||
set_notifications_for_feed: function(feed, callback) {
|
||||
if (NEWSBLUR.Globals.is_authenticated) {
|
||||
this.make_request('/notifications/feed/', {
|
||||
'feed_id': feed.id,
|
||||
'notification_types': feed.get('notification_types'),
|
||||
'notification_filter': feed.get('notification_filter')
|
||||
}, callback);
|
||||
} else {
|
||||
if ($.isFunction(callback)) callback();
|
||||
}
|
||||
},
|
||||
|
||||
send_story_email: function(data, callback, error_callback) {
|
||||
if (NEWSBLUR.Globals.is_authenticated) {
|
||||
this.make_request('/reader/send_story_email', data, callback, error_callback, {'timeout': 6000});
|
||||
|
|
|
@ -271,6 +271,8 @@ NEWSBLUR.Collections.Feeds = Backbone.Collection.extend({
|
|||
this.bind('change', this.detect_active_feed);
|
||||
},
|
||||
|
||||
comparator: 'feed_title',
|
||||
|
||||
// ===========
|
||||
// = Actions =
|
||||
// ===========
|
||||
|
|
|
@ -34,9 +34,13 @@ _.extend(NEWSBLUR.ReaderNotifications.prototype, {
|
|||
var frequency = this.feed.get('notification_frequency');
|
||||
var notifications = this.feed.get('notifications');
|
||||
|
||||
if (this.feed) {
|
||||
NEWSBLUR.Modal.prototype.initialize_feed.call(this, feed_id);
|
||||
}
|
||||
NEWSBLUR.Modal.prototype.initialize_feed.call(this, feed_id);
|
||||
|
||||
var $site = $(".NB-modal-section-site", this.$modal);
|
||||
$site.html(this.make_feed_notification(this.feed));
|
||||
|
||||
var $all = $(".NB-modal-section-all", this.$modal);
|
||||
$all.html(this.make_feed_notifications());
|
||||
|
||||
this.resize();
|
||||
},
|
||||
|
@ -68,7 +72,12 @@ _.extend(NEWSBLUR.ReaderNotifications.prototype, {
|
|||
this.make_feed_chooser()
|
||||
])),
|
||||
$.make('div', { className: 'NB-modal-loading' }),
|
||||
$.make('h2', { className: 'NB-modal-title' }, 'Notifications'),
|
||||
$.make('h2', { className: 'NB-modal-title' }, [
|
||||
$.make('div', { className: 'NB-modal-loading' }),
|
||||
$.make('div', { className: 'NB-icon' }),
|
||||
'Notificatons',
|
||||
$.make('div', { className: 'NB-icon-dropdown' })
|
||||
]),
|
||||
(this.feed && $.make('div', { className: 'NB-fieldset NB-modal-submit' }, [
|
||||
$.make('fieldset', [
|
||||
$.make('legend', 'Site Notifications'),
|
||||
|
@ -80,7 +89,7 @@ _.extend(NEWSBLUR.ReaderNotifications.prototype, {
|
|||
$.make('div', { className: 'NB-fieldset NB-modal-submit' }, [
|
||||
$.make('fieldset', [
|
||||
$.make('legend', 'All Notifications'),
|
||||
$.make('div', { className: 'NB-modal-section'}, [
|
||||
$.make('div', { className: 'NB-modal-section NB-modal-section-all'}, [
|
||||
this.make_feed_notifications()
|
||||
])
|
||||
])
|
||||
|
@ -104,13 +113,15 @@ _.extend(NEWSBLUR.ReaderNotifications.prototype, {
|
|||
},
|
||||
|
||||
make_feed_notifications: function() {
|
||||
var notifications = this.model.get_feeds().filter(function(feed) {
|
||||
return feed.get('notifications');
|
||||
var site_feed_id = this.model.id;
|
||||
var notifications = this.model.get_feeds().select(function(feed) {
|
||||
return feed.get('notification_types') && feed.id != site_feed_id;
|
||||
});
|
||||
var $feeds = [];
|
||||
|
||||
notifications.sort(function(a, b) { return a.get('feed_title') < b.get('feed_title'); });
|
||||
for (var feed in notifications) {
|
||||
$feeds.push(this.make_feed_notification(feed));
|
||||
$feeds.push(this.make_feed_notification(notifications[feed]));
|
||||
}
|
||||
|
||||
return $feeds;
|
||||
|
|
|
@ -1,62 +1,72 @@
|
|||
NEWSBLUR.Views.FeedNotificationView = Backbone.View.extend({
|
||||
|
||||
events: {
|
||||
"click .NB-feed-notifications-email" : "toggle_email",
|
||||
"click .NB-feed-notifications-ios" : "toggle_ios",
|
||||
"click .NB-feed-notifications-android" : "toggle_android",
|
||||
"click .NB-feed-notifications-web" : "toggle_web"
|
||||
"click .NB-feed-notification-filter-unread": "toggle_unread",
|
||||
"click .NB-feed-notification-filter-focus" : "toggle_focus",
|
||||
"click .NB-feed-notification-email" : "toggle_email",
|
||||
"click .NB-feed-notification-ios" : "toggle_ios",
|
||||
"click .NB-feed-notification-android" : "toggle_android",
|
||||
"click .NB-feed-notification-web" : "toggle_web"
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
initialize: function(m) {
|
||||
console.log(['feed notificaiton', this.model, m]);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var feed = this.model;
|
||||
var $feed = $(_.template('<div class="NB-feed-notification <% if (selected) { %>selected<% } %>">\
|
||||
<ul class="segmented-control NB-feed-notifications">\
|
||||
<li class="NB-feed-notifications-option NB-feed-notifications-email">Email</li>\
|
||||
<li class="NB-feed-notifications-option NB-feed-notifications-web">Web</li>\
|
||||
<li class="NB-feed-notifications-option NB-feed-notifications-ios">iOS</li>\
|
||||
<li class="NB-feed-notifications-option NB-feed-notifications-android">Android</li>\
|
||||
</ul>\
|
||||
<ul class="segmented-control NB-feed-notification-filter">\
|
||||
<li class="NB-feed-notification-filter-unread NB-active">\
|
||||
<div class="NB-unread-icon"></div>\
|
||||
Unread stories\
|
||||
</li>\
|
||||
<li class="NB-feed-notification-filter-focus">\
|
||||
<div class="NB-focus-icon"></div>\
|
||||
Focus\
|
||||
</li>\
|
||||
</ul>\
|
||||
<div class="NB-feed-notification-controls">\
|
||||
<ul class="segmented-control NB-feed-notification-filter">\
|
||||
<li class="NB-feed-notification-filter-unread <% if (!is_focus) { %>NB-active<% } %>">\
|
||||
<div class="NB-unread-icon"></div>\
|
||||
Unread stories\
|
||||
</li>\
|
||||
<li class="NB-feed-notification-filter-focus <% if (is_focus) { %>NB-active<% } %>">\
|
||||
<div class="NB-focus-icon"></div>\
|
||||
Focus\
|
||||
</li>\
|
||||
</ul>\
|
||||
<ul class="segmented-control NB-feed-notification-types">\
|
||||
<li class="NB-feed-notification-option NB-feed-notification-email <% if (is_email) { %>NB-active<% } %>">Email</li>\
|
||||
<li class="NB-feed-notification-option NB-feed-notification-web <% if (is_web) { %>NB-active<% } %>">Web</li>\
|
||||
<li class="NB-feed-notification-option NB-feed-notification-ios <% if (is_ios) { %>NB-active<% } %>">iOS</li>\
|
||||
<li class="NB-feed-notification-option NB-feed-notification-android <% if (is_android) { %>NB-active<% } %>">Android</li>\
|
||||
</ul>\
|
||||
</div>\
|
||||
<img class="NB-feed-icon" src="<%= $.favicon(feed) %>">\
|
||||
<div class="NB-feed-title"><%= feed.get("feed_title") %></div>\
|
||||
<div class="NB-feed-frequency-icon"></div>\
|
||||
<div class="NB-feed-frequency"><%= frequency %></div>\
|
||||
</div>\
|
||||
', {
|
||||
feed : feed,
|
||||
selected : this.options.selected,
|
||||
frequency_count : this.frequency_count()
|
||||
frequency : feed && this.frequency(feed.get('average_stories_per_month')),
|
||||
frequency_count : this.frequency_count(),
|
||||
is_email : _.contains(feed.get('notification_types'), 'email'),
|
||||
is_ios : _.contains(feed.get('notification_types'), 'ios'),
|
||||
is_android : _.contains(feed.get('notification_types'), 'android'),
|
||||
is_web : _.contains(feed.get('notification_types'), 'web'),
|
||||
is_focus : feed.get('notification_filter') == 'focus'
|
||||
}));
|
||||
|
||||
// <div class="NB-feed-notification-frequency">\
|
||||
// <select name="notifications_frequency">\
|
||||
// <option value="0">Immediately</option>\
|
||||
// <option value="1">Max once an hour</option>\
|
||||
// <option value="1">Max once every six hours</option>\
|
||||
// <option value="1">Max once every twelve hours</option>\
|
||||
// <option value="1">Max once a day</option>\
|
||||
// </select>\
|
||||
// </div>\
|
||||
// <div class="NB-feed-notification-frequency-count">\
|
||||
// <%= frequency_count %> a day\
|
||||
// </div>\
|
||||
|
||||
this.$el.replaceWith($feed);
|
||||
this.setElement($feed);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
frequency: function(count) {
|
||||
if (count == 0) {
|
||||
return "No stories published last month";
|
||||
} else if (count < 30) {
|
||||
return Inflector.pluralize("story", count, true) + " per month";
|
||||
} else if (count >= 30) {
|
||||
return Inflector.pluralize("story", Math.round(count / 30.0), true) + " per day";
|
||||
}
|
||||
},
|
||||
|
||||
frequency_count: function() {
|
||||
var freq = this.model.get('notification_frequency');
|
||||
var story_count = this.model.get('stories_per_month') / 30.0;
|
||||
|
@ -76,7 +86,52 @@ NEWSBLUR.Views.FeedNotificationView = Backbone.View.extend({
|
|||
// ==========
|
||||
|
||||
toggle_email: function() {
|
||||
this.toggle_type('email');
|
||||
},
|
||||
|
||||
toggle_ios: function() {
|
||||
this.toggle_type('ios');
|
||||
},
|
||||
|
||||
toggle_android: function() {
|
||||
this.toggle_type('android');
|
||||
},
|
||||
|
||||
toggle_web: function() {
|
||||
this.toggle_type('web');
|
||||
},
|
||||
|
||||
toggle_type: function(type) {
|
||||
var notification_types = this.model.get('notification_types') || [];
|
||||
var is_type = _.contains(notification_types, type);
|
||||
if (is_type) {
|
||||
notification_types.splice(notification_types.indexOf(type), 1);
|
||||
} else {
|
||||
notification_types.push(type);
|
||||
}
|
||||
this.model.set('notification_types', notification_types);
|
||||
|
||||
this.save();
|
||||
},
|
||||
|
||||
toggle_focus: function() {
|
||||
this.model.set('notification_filter', 'focus');
|
||||
|
||||
this.save();
|
||||
},
|
||||
|
||||
toggle_unread: function() {
|
||||
this.model.set('notification_filter', 'unread');
|
||||
|
||||
this.save();
|
||||
},
|
||||
|
||||
save: function() {
|
||||
NEWSBLUR.assets.set_notifications_for_feed(this.model, function() {
|
||||
|
||||
});
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
});
|
2
urls.py
2
urls.py
|
@ -30,7 +30,7 @@ urlpatterns = patterns('',
|
|||
(r'^import/', include('apps.feed_import.urls')),
|
||||
(r'^api/', include('apps.api.urls')),
|
||||
(r'^recommendations/', include('apps.recommendations.urls')),
|
||||
(r'^notifications/?', include('apps.notifications.urls')),
|
||||
(r'^notifications/?', include('apps.notifications.urls')),
|
||||
(r'^statistics/', include('apps.statistics.urls')),
|
||||
(r'^social/', include('apps.social.urls')),
|
||||
(r'^oauth/', include('apps.oauth.urls')),
|
||||
|
|
Loading…
Add table
Reference in a new issue