support excluding feeds from the front page
and some style/UI tweaks
This commit is contained in:
parent
190bb1eb55
commit
bca07e2178
11 changed files with 77 additions and 28 deletions
|
@ -99,7 +99,9 @@ class Subscription(db.Model):
|
||||||
# user-editable name of this subscribed feed
|
# user-editable name of this subscribed feed
|
||||||
name = db.Column(db.String(256))
|
name = db.Column(db.String(256))
|
||||||
tags = db.Column(db.String(256))
|
tags = db.Column(db.String(256))
|
||||||
|
# exclude from the front page
|
||||||
|
exclude = db.Column(db.Boolean, default=False)
|
||||||
|
|
||||||
user = db.relationship(User, backref='subscriptions')
|
user = db.relationship(User, backref='subscriptions')
|
||||||
feed = db.relationship(Feed, backref='subscriptions')
|
feed = db.relationship(Feed, backref='subscriptions')
|
||||||
|
|
||||||
|
|
|
@ -64,15 +64,16 @@ $(function(){
|
||||||
function attachListeners() {
|
function attachListeners() {
|
||||||
$("#older-link").off('click').click(clickOlderLink);
|
$("#older-link").off('click').click(clickOlderLink);
|
||||||
$(".micropub-form button[type='submit']").off('click').click(submitMicropubForm);
|
$(".micropub-form button[type='submit']").off('click').click(submitMicropubForm);
|
||||||
$(".reply-area").hide();
|
$(".reply-area.closed").hide();
|
||||||
|
|
||||||
$("article").off('click').click(function(evt) {
|
$("article").off('click').click(function(evt) {
|
||||||
var $target = $(evt.target);
|
var $target = $(evt.target);
|
||||||
if ($target.closest("form, a, video, audio").length == 0) {
|
if ($target.closest("form, a, video, audio").length == 0) {
|
||||||
|
|
||||||
|
$(".reply-area", this).toggleClass("closed");
|
||||||
$(".reply-area", this).slideToggle(200);
|
$(".reply-area", this).slideToggle(200);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -360,7 +360,8 @@ th {
|
||||||
/* Subtlety of Hue */
|
/* Subtlety of Hue */
|
||||||
body {
|
body {
|
||||||
font: 12pt Helvetica, Arial, sans-serif;
|
font: 12pt Helvetica, Arial, sans-serif;
|
||||||
background: #ecebf0;
|
/*background: $athens-gray;*/
|
||||||
|
background: #f4f4f4;
|
||||||
padding-top: 1em; }
|
padding-top: 1em; }
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
@ -410,12 +411,13 @@ ul#navigation {
|
||||||
|
|
||||||
article {
|
article {
|
||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
box-shadow: 0 0 2px #687d77;
|
/*box-shadow: $box-shadow;
|
||||||
background-color: white;
|
background-color: white;*/
|
||||||
padding: 0.5em; }
|
padding: 0.5em; }
|
||||||
article.reply-context {
|
article.reply-context {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
background-color: #f3f3f3; }
|
background-color: #e0e0e0;
|
||||||
|
color: #555; }
|
||||||
article.reply-context .content img {
|
article.reply-context .content img {
|
||||||
max-height: 240px;
|
max-height: 240px;
|
||||||
max-width: 240px; }
|
max-width: 240px; }
|
||||||
|
|
|
@ -17,7 +17,8 @@ $box-shadow: 0 0 2px $sirocco;
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font: 12pt $body-font;
|
font: 12pt $body-font;
|
||||||
background: $athens-gray;
|
/*background: $athens-gray;*/
|
||||||
|
background: #f4f4f4;
|
||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,13 +87,14 @@ ul#navigation {
|
||||||
|
|
||||||
article {
|
article {
|
||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
box-shadow: $box-shadow;
|
/*box-shadow: $box-shadow;
|
||||||
background-color: white;
|
background-color: white;*/
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
|
|
||||||
&.reply-context {
|
&.reply-context {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
background-color: #f3f3f3;
|
background-color: #e0e0e0;
|
||||||
|
color: #555;
|
||||||
.content img {
|
.content img {
|
||||||
max-height: 240px;
|
max-height: 240px;
|
||||||
max-width: 240px;
|
max-width: 240px;
|
||||||
|
@ -246,10 +248,10 @@ button {
|
||||||
.reply-area {
|
.reply-area {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
height: 4em;
|
height: 4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-link {
|
.reply-link {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
|
@ -18,8 +18,20 @@ $(function() {
|
||||||
}).fail(function failure() {
|
}).fail(function failure() {
|
||||||
$(".save-status", form).html("Save Failed!");
|
$(".save-status", form).html("Save Failed!");
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("form.poll-now").submit(function(evt) {
|
||||||
|
var form = $(this);
|
||||||
|
evt.preventDefault();
|
||||||
|
|
||||||
|
$(".poll-status", form).html("");
|
||||||
|
|
||||||
|
$.post(form.attr('action'), form.serialize(), function success(){
|
||||||
|
$(".poll-status", form).html("Poll Requested.");
|
||||||
|
}).fail(function failure() {
|
||||||
|
$(".poll-status", form).html("Polling Failed!");
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -311,8 +311,13 @@ def notify_feed_updated(app, feed_id, entry_ids):
|
||||||
'subscription': s.id,
|
'subscription': s.id,
|
||||||
'entries': rendered,
|
'entries': rendered,
|
||||||
})
|
})
|
||||||
for topic in ('user:{}'.format(s.user.id),
|
|
||||||
'subsc:{}'.format(s.id)):
|
topics = []
|
||||||
|
if not s.exclude:
|
||||||
|
topics.append('user:{}'.format(s.user.id))
|
||||||
|
topics.append('subsc:{}'.format(s.id))
|
||||||
|
|
||||||
|
for topic in topics:
|
||||||
redis.publish('woodwind_notify:{}'.format(topic), message)
|
redis.publish('woodwind_notify:{}'.format(topic), message)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
| {% for synd in entry.get_property('syndication') %} <a href="{{ synd }}">{{ synd | domain_for_url}}</a>{% endfor %}
|
| {% for synd in entry.get_property('syndication') %} <a href="{{ synd }}">{{ synd | domain_for_url}}</a>{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="reply-area">
|
<div class="reply-area closed">
|
||||||
{% include '_reply.jinja2' with context %}
|
{% include '_reply.jinja2' with context %}
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<link rel="shortcut icon" href="{{ url_for('static', filename='logo.png') }}"/>
|
<link rel="shortcut icon" href="{{ url_for('static', filename='logo.png') }}"/>
|
||||||
<link rel="apple-touch-icon" href="{{ url_for('static', filename='logo.png') }}"/>
|
<link rel="apple-touch-icon" href="{{ url_for('static', filename='logo.png') }}"/>
|
||||||
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css', version='2015-10-07') }}"/>
|
<link rel="stylesheet" href="{{ url_for('static', filename='style.css', version='2015-11-25') }}"/>
|
||||||
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css"/>
|
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css"/>
|
||||||
<script src="//code.jquery.com/jquery-2.1.3.min.js"></script>
|
<script src="//code.jquery.com/jquery-2.1.3.min.js"></script>
|
||||||
<script src="{{ url_for('static', filename='moment.min.js') }}"></script>
|
<script src="{{ url_for('static', filename='moment.min.js') }}"></script>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{% if ws_topic %}
|
{% if ws_topic %}
|
||||||
<script>var WS_TOPIC = "{{ ws_topic }}";</script>
|
<script>var WS_TOPIC = "{{ ws_topic }}";</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<script src="{{url_for('static', filename='feed.js', version='2015-10-08')}}"></script>
|
<script src="{{url_for('static', filename='feed.js', version='2015-11-06')}}"></script>
|
||||||
|
|
||||||
{% if current_user and current_user.settings
|
{% if current_user and current_user.settings
|
||||||
and current_user.settings.get('reply-method') == 'indie-config' %}
|
and current_user.settings.get('reply-method') == 'indie-config' %}
|
||||||
|
|
|
@ -38,6 +38,12 @@
|
||||||
<input type="text" name="tags" value="{{ s.tags or ''}}"/>
|
<input type="text" name="tags" value="{{ s.tags or ''}}"/>
|
||||||
<label>URL</label>
|
<label>URL</label>
|
||||||
<input type="text" name="feed" value="{{ s.feed.feed }}" readonly />
|
<input type="text" name="feed" value="{{ s.feed.feed }}" readonly />
|
||||||
|
|
||||||
|
<label style="display: block; font-weight: normal;">
|
||||||
|
<input type="checkbox" name="exclude" value="true" {% if s.exclude %}checked{% endif %} />
|
||||||
|
Exclude from primary feed
|
||||||
|
</label>
|
||||||
|
|
||||||
<button type="submit">Save Edits</button> <span class="save-status"></span>
|
<button type="submit">Save Edits</button> <span class="save-status"></span>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
@ -63,14 +69,14 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<form action="{{ url_for('.update_feed') }}" method="POST" style="display:inline">
|
<form class="poll-now" action="{{ url_for('.update_feed') }}" method="POST" style="display:inline">
|
||||||
<input type="hidden" name="id" value="{{ s.feed.id }}"/>
|
<input type="hidden" name="id" value="{{ s.feed.id }}"/>
|
||||||
<button type="submit">Poll Now</button>
|
<button type="submit">Poll Now</button> <span class="poll-status"></span>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<form action="{{ url_for('.unsubscribe') }}" method="POST" style="display:inline">
|
<form class="unsubscribe" action="{{ url_for('.unsubscribe') }}" method="POST" style="display:inline">
|
||||||
<input type="hidden" name="id" value="{{ s.id }}"/>
|
<input type="hidden" name="id" value="{{ s.id }}"/>
|
||||||
<button type="submit">Unsubscribe</button>
|
<button type="submit">Unsubscribe</button> <span class="unsubscribe-status"></span>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,8 @@ from . import tasks, util
|
||||||
from .extensions import db, login_mgr, micropub
|
from .extensions import db, login_mgr, micropub
|
||||||
from .models import Feed, Entry, User, Subscription
|
from .models import Feed, Entry, User, Subscription
|
||||||
import flask.ext.login as flask_login
|
import flask.ext.login as flask_login
|
||||||
import binascii
|
|
||||||
|
import base64
|
||||||
import bs4
|
import bs4
|
||||||
import datetime
|
import datetime
|
||||||
import feedparser
|
import feedparser
|
||||||
|
@ -74,6 +75,7 @@ def index():
|
||||||
entry_query = entry_query.filter(
|
entry_query = entry_query.filter(
|
||||||
sqlalchemy.sql.expression.cast(Entry.properties['jam'], sqlalchemy.TEXT) == 'true')
|
sqlalchemy.sql.expression.cast(Entry.properties['jam'], sqlalchemy.TEXT) == 'true')
|
||||||
else:
|
else:
|
||||||
|
entry_query = entry_query.filter(Subscription.exclude == False)
|
||||||
ws_topic = 'user:{}'.format(flask_login.current_user.id)
|
ws_topic = 'user:{}'.format(flask_login.current_user.id)
|
||||||
|
|
||||||
entry_query = entry_query.order_by(Entry.retrieved.desc(),
|
entry_query = entry_query.order_by(Entry.retrieved.desc(),
|
||||||
|
@ -226,6 +228,7 @@ def edit_subscription():
|
||||||
subsc.tags = ' '.join(t.strip() for t in tag_list if t.strip())
|
subsc.tags = ' '.join(t.strip() for t in tag_list if t.strip())
|
||||||
else:
|
else:
|
||||||
subsc.tags = None
|
subsc.tags = None
|
||||||
|
subsc.exclude = flask.request.form.get('exclude') == 'true'
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flask.flash('Edited {}'.format(subsc.name))
|
flask.flash('Edited {}'.format(subsc.name))
|
||||||
|
@ -609,13 +612,29 @@ def add_preview(content):
|
||||||
|
|
||||||
@views.app_template_filter()
|
@views.app_template_filter()
|
||||||
def proxy_image(url):
|
def proxy_image(url):
|
||||||
|
proxy_url = flask.current_app.config.get('IMAGEPROXY_URL')
|
||||||
|
proxy_key = flask.current_app.config.get('IMAGEPROXY_KEY')
|
||||||
|
if proxy_url and proxy_key:
|
||||||
|
sig = base64.urlsafe_b64encode(
|
||||||
|
hmac.new(proxy_key.encode(), url.encode(), hashlib.sha256).digest()
|
||||||
|
).decode()
|
||||||
|
return '/'.join((proxy_url.rstrip('/'), 's' + sig, url))
|
||||||
|
|
||||||
|
pilbox_url = flask.current_app.config.get('PILBOX_URL')
|
||||||
|
pilbox_key = flask.current_app.config.get('PILBOX_KEY')
|
||||||
|
if pilbox_url and pilbox_key:
|
||||||
|
query = urllib.parse.urlencode({'url': url, 'op': 'noop'})
|
||||||
|
sig = hmac.new(pilbox_key.encode(), query.encode(), hashlib.sha1).hexdigest()
|
||||||
|
query += '&sig=' + sig
|
||||||
|
return pilbox_url + '?' + query
|
||||||
|
|
||||||
camo_url = flask.current_app.config.get('CAMO_URL')
|
camo_url = flask.current_app.config.get('CAMO_URL')
|
||||||
camo_key = flask.current_app.config.get('CAMO_KEY')
|
camo_key = flask.current_app.config.get('CAMO_KEY')
|
||||||
if not camo_url or not camo_key:
|
if camo_url and camo_key:
|
||||||
return url
|
digest = hmac.new(camo_key.encode(), url.encode(), hashlib.sha1).hexdigest()
|
||||||
digest = hmac.new(camo_key.encode(), url.encode(), hashlib.sha1).hexdigest()
|
return (urllib.parse.urljoin(camo_url, digest)
|
||||||
return (urllib.parse.urljoin(camo_url, digest)
|
+ '?url=' + urllib.parse.quote_plus(url))
|
||||||
+ '?url=' + urllib.parse.quote_plus(url))
|
return url
|
||||||
|
|
||||||
|
|
||||||
@views.app_template_filter()
|
@views.app_template_filter()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue