Skip to content
This repository was archived by the owner on Aug 30, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions api/feeds/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ def getFeedById(cls, feedId):
def getEntries(cls, pagingKey):
return EntryModel.gql('WHERE pagingKey < :1 ORDER BY pagingKey DESC LIMIT 100', float(pagingKey))

@classmethod
def getAllEntriesByFeed(cls, feed):
return EntryModel.gql('WHERE ANCESTOR IS :1', feed)

@classmethod
def getUnreadEntries(cls, pagingKey):
return EntryModel.gql('WHERE pagingKey < :1 AND read = :2 ORDER BY pagingKey DESC LIMIT 100', float(pagingKey), False)
Expand Down
17 changes: 17 additions & 0 deletions api/feeds/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,23 @@ def post(self, feedId):

self.response.out.write(utils.dumpsJSON(feed.toDict()))

def delete(self, feedId):
self.response.headers['Content-Type'] = 'application/json'

feed = models.FeedManager.getFeedById(feedId)
if not feed:
self.writeNotFound()
return

feeds = models.FeedManager.getAllEntriesByFeed(feed)
if not feeds:
self.writeNotFound()
return

db.delete(feeds)
feed.delete()


class FeedEntryHandler(HandlerBase):
def get(self, feedId, action, pagingKey=None):
self.response.headers['Content-Type'] = 'application/json'
Expand Down
122 changes: 122 additions & 0 deletions webui/sample/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

<style type="text/css">
body { padding-top: 70px; }
table { table-layout: fixed; }
td.break-word { word-wrap:break-word; }
td.floating-item { width: 40px; }
</style>
</head>
<body>
Expand All @@ -38,6 +41,8 @@
<ul class="nav navbar-nav navbar-right">
<li><a data-toggle="modal" href="#addModal">
<span class="glyphicon glyphicon-plus-sign"></span> Add</a></li>
<li><a data-toggle="modal" href="#listModal">
<span class="glyphicon glyphicon-th-list"></span> List</a></li>
<li><a data-toggle="modal" href="#importModal">
<span class="glyphicon glyphicon-upload"></span> Import</a></li>
</ul>
Expand Down Expand Up @@ -81,6 +86,22 @@ <h4 class="modal-title">Add New Feed</h4>
</div>
</div>

<div class="modal fade" id="listModal" tabindex="-1" role="dialog" aria-labelledby="listModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">RSS Feed List</h4>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

<div style="display: none">
<form id="importDummyForm" method="post" action="/api/feeds/import" enctype="multipart/form-data">
<input type="file" id="importDummyFile" name="opml">
Expand Down Expand Up @@ -125,6 +146,7 @@ <h4 class="modal-title">Import Feeds</h4>

<script type="text/javascript">
$(function() {
$('#body').empty();
loadEntries(parseInt(new Date() / 1000));

$('#addModal').on('show.bs.modal', function() {
Expand Down Expand Up @@ -153,6 +175,16 @@ <h4 class="modal-title">Import Feeds</h4>
$('#importModalButton').button('reset');
});

$('#listModal').on('show.bs.modal', function () {
loadFeedsList();
$('#listModalButton').button('reset');
});

$('#listModal').on('hidden.bs.modal', function () {
$('#body').empty();
loadEntries(parseInt(new Date() / 1000));
});

$('#inputOPMLButton').click(function () {
$('#importDummyFile').click();
});
Expand Down Expand Up @@ -210,6 +242,13 @@ <h4 class="modal-title">Import Feeds</h4>
feeds[feed.id] = feed;
}

if (Object.keys(feeds).length === 0) {
footer.empty();
var body = '<div class="alert alert-warning text-center">There is no RSS feed. Please add RSS feed from "Add" menu.</div>';
$('#body').html(body);
return;
}

$.getJSON('/api/feeds/unread/' + pagingKey).done(function(json) {
for(var i in json.entries) {
var entry = json.entries[i];
Expand Down Expand Up @@ -239,6 +278,10 @@ <h4 class="modal-title">Import Feeds</h4>

footer.empty().append(alertBar.append(readMore));
} else {
if (entries.length === 0) {
var body = '<div class="alert alert-info text-center">There is no unread RSS entry</div>';
$('#body').html(body);
}
footer.empty();
}
}).fail(function() {
Expand Down Expand Up @@ -324,6 +367,68 @@ <h4 class="modal-title">Import Feeds</h4>
}
}

function loadFeedsList() {
var def = new $.Deferred();
var body = $('#listModal').find('.modal-body');

body.empty();

$.getJSON('/api/feeds/?').done(function(json) {
var feeds = {};
for(var i in json.feeds) {
var feed = json.feeds[i];
feeds[feed.id] = feed;
}
def.resolve(feeds);
}).fail(function() {
def.reject();
});

def.done(function(feeds) {
if (Object.keys(feeds).length === 0) {
body.html('<div class="alert alert-warning text-center">There is no RSS feed</div>');
return;
}

list = '<div class="panel panel-default"><table class="table table-hover"><tbody>';

buttons = [];
for (feed in feeds) {
buttonId = "deleteFeedButton" + feed;
buttons.push("#" + buttonId);

list += '<tr><td class="break-word"><span class="glyphicon glyphicon-file"></span>';
list += feeds[feed].title;
list += '</td><td class="text-right floating-item"><button id="'
list += buttonId;
list += '" data-id="';
list += feeds[feed].id;
list += '" class="btn btn-xs btn-warning"><span class="glyphicon glyphicon-trash"></span></button></td></tr>';
}
list += '</tbody></table></div>';
body.html(list);

for (button in buttons) {
$(buttons[button]).click(function() {
deleteFeedById($(this).data('id'));
});
}
}).fail(function() {
body.html('<div class="alert alert-danger text-center">Failed to load feeds</div>');
});
}

function deleteFeedById(feedId) {
$.delete('/api/feeds/' + feedId + '/?').done(function(data) {
}).fail(function () {
}).always(function () {
$('#deleteFeedButton').button('reset');
// Wait some time to reflect data changes
$(this).delay(1000).queue(function() {
loadFeedsList();
});
});
}

// hook keyboard input
$(window).keydown(function(event) {
Expand Down Expand Up @@ -378,6 +483,23 @@ <h4 class="modal-title">Import Feeds</h4>

event.preventDefault();
});

jQuery.each(["put", "delete"], function(i, method) {
jQuery[method] = function(url, data, callback, type) {
if (jQuery.isFunction(data)) {
type = type || callback;
callback = data;
data = undefined;
}
return jQuery.ajax({
type: method,
url: url,
data: data,
success: callback,
dataType: type
});
};
});
</script>
</body>
</html>