Merge branch 'master' into HEAD
This commit is contained in:
commit
0d5dcce74e
4 changed files with 50 additions and 62 deletions
|
@ -1,15 +1,7 @@
|
||||||
import bleach
|
|
||||||
import json
|
|
||||||
import binascii
|
|
||||||
from .extensions import db
|
from .extensions import db
|
||||||
import re
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from sqlalchemy.ext.orderinglist import ordering_list
|
|
||||||
from sqlalchemy.ext.associationproxy import association_proxy
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class JsonType(db.TypeDecorator):
|
class JsonType(db.TypeDecorator):
|
||||||
"""Represents an immutable structure as a json-encoded string.
|
"""Represents an immutable structure as a json-encoded string.
|
||||||
|
@ -29,12 +21,6 @@ class JsonType(db.TypeDecorator):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
users_to_feeds = db.Table(
|
|
||||||
'users_to_feeds', db.Model.metadata,
|
|
||||||
db.Column('user_id', db.Integer, db.ForeignKey('user.id'), index=True),
|
|
||||||
db.Column('feed_id', db.Integer, db.ForeignKey('feed.id'), index=True))
|
|
||||||
|
|
||||||
|
|
||||||
entry_to_reply_context = db.Table(
|
entry_to_reply_context = db.Table(
|
||||||
'entry_to_reply_context', db.Model.metadata,
|
'entry_to_reply_context', db.Model.metadata,
|
||||||
db.Column('entry_id', db.Integer, db.ForeignKey('entry.id'), index=True),
|
db.Column('entry_id', db.Integer, db.ForeignKey('entry.id'), index=True),
|
||||||
|
@ -120,6 +106,15 @@ class Feed(db.Model):
|
||||||
return '<Feed:{},{}>'.format(self.name, self.feed)
|
return '<Feed:{},{}>'.format(self.name, self.feed)
|
||||||
|
|
||||||
|
|
||||||
|
class Subscription(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
users = db.relationship(User, backref='subscriptions')
|
||||||
|
# user-editable name of this subscribed feed
|
||||||
|
name = db.Column(db.String(256))
|
||||||
|
feed = db.relationship(Feed, backref='subscriptions')
|
||||||
|
tags = db.Column(JsonType)
|
||||||
|
|
||||||
|
|
||||||
class Entry(db.Model):
|
class Entry(db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
feed_id = db.Column(db.Integer, db.ForeignKey(Feed.id), index=True)
|
feed_id = db.Column(db.Integer, db.ForeignKey(Feed.id), index=True)
|
||||||
|
@ -137,13 +132,6 @@ class Entry(db.Model):
|
||||||
content_cleaned = db.Column(db.Text)
|
content_cleaned = db.Column(db.Text)
|
||||||
# other properties
|
# other properties
|
||||||
properties = db.Column(JsonType)
|
properties = db.Column(JsonType)
|
||||||
# # association with the InReplyTo objects
|
|
||||||
# irt = db.relationship(
|
|
||||||
# 'InReplyTo', order_by='InReplyTo.list_index',
|
|
||||||
# collection_class=ordering_list('list_index'))
|
|
||||||
# # proxy for just the urls
|
|
||||||
# in_reply_to = association_proxy(
|
|
||||||
# 'irt', 'url', creator=lambda url: InReplyTo(url=url))
|
|
||||||
reply_context = db.relationship(
|
reply_context = db.relationship(
|
||||||
'Entry', secondary='entry_to_reply_context',
|
'Entry', secondary='entry_to_reply_context',
|
||||||
primaryjoin=id == entry_to_reply_context.c.entry_id,
|
primaryjoin=id == entry_to_reply_context.c.entry_id,
|
||||||
|
@ -165,10 +153,3 @@ class Entry(db.Model):
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<Entry:{},{}>'.format(self.title, (self.content or '')[:140])
|
return '<Entry:{},{}>'.format(self.title, (self.content or '')[:140])
|
||||||
|
|
||||||
|
|
||||||
# class InReplyTo(db.Model):
|
|
||||||
# id = db.Column(db.Integer, primary_key=True)
|
|
||||||
# entry_id = db.Column(db.Integer, db.ForeignKey(Entry.id))
|
|
||||||
# url = db.Column(db.String(512))
|
|
||||||
# list_index = db.Column(db.Integer)
|
|
||||||
|
|
|
@ -360,7 +360,7 @@ th {
|
||||||
/* Subtlety of Hue */
|
/* Subtlety of Hue */
|
||||||
body {
|
body {
|
||||||
font: 12pt Helvetica, Arial, sans-serif;
|
font: 12pt Helvetica, Arial, sans-serif;
|
||||||
background: #ECEBF0;
|
background: #ecebf0;
|
||||||
padding-top: 1em; }
|
padding-top: 1em; }
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
@ -392,19 +392,22 @@ ul#navigation {
|
||||||
.pager a {
|
.pager a {
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
background-color: #353129;
|
background-color: #353129;
|
||||||
color: #ECEBF0;
|
color: #ecebf0;
|
||||||
border: 1px solid #ECEBF0;
|
border: 1px solid #ecebf0;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
display: inline-block; }
|
display: inline-block; }
|
||||||
|
|
||||||
article {
|
article {
|
||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
box-shadow: 0 0 2px #687D77;
|
box-shadow: 0 0 2px #687d77;
|
||||||
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: #f3f3f3; }
|
||||||
|
article.reply-context img {
|
||||||
|
max-height: 240px;
|
||||||
|
max-width: 240px; }
|
||||||
article div {
|
article div {
|
||||||
overflow: auto; }
|
overflow: auto; }
|
||||||
article div p:first-child {
|
article div p:first-child {
|
||||||
|
@ -414,17 +417,17 @@ article {
|
||||||
article img, article video {
|
article img, article video {
|
||||||
max-width: 100%; }
|
max-width: 100%; }
|
||||||
article header {
|
article header {
|
||||||
color: #484A47;
|
color: #484a47;
|
||||||
border-bottom: 1px solid #687D77;
|
border-bottom: 1px solid #687d77;
|
||||||
margin-bottom: 0.5em; }
|
margin-bottom: 0.5em; }
|
||||||
article header img {
|
article header img {
|
||||||
max-width: 64px;
|
vertical-align: text-middle;
|
||||||
max-height: 64px;
|
margin: inherit;
|
||||||
min-width: 48px;
|
display: inline;
|
||||||
min-height: 48px;
|
max-width: 1.2em;
|
||||||
margin-left: -85px;
|
max-height: 1.2em;
|
||||||
float: left;
|
min-width: inherit;
|
||||||
border-radius: 4px; }
|
min-height: inherit; }
|
||||||
article footer {
|
article footer {
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
margin-bottom: 0; }
|
margin-bottom: 0; }
|
||||||
|
@ -495,11 +498,11 @@ textarea, input[type="text"], input[type="url"] {
|
||||||
.reply-area .reply-link {
|
.reply-area .reply-link {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 0.2em;
|
padding: 0.2em;
|
||||||
border: 1px solid #687D77;
|
border: 1px solid #687d77;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background-color: #ECEBF0;
|
background-color: #ecebf0;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: #484A47;
|
color: #484a47;
|
||||||
min-width: 50px;
|
min-width: 50px;
|
||||||
text-align: center; }
|
text-align: center; }
|
||||||
|
|
||||||
|
@ -512,5 +515,3 @@ textarea, input[type="text"], input[type="url"] {
|
||||||
max-height: 1.2em;
|
max-height: 1.2em;
|
||||||
min-width: inherit;
|
min-width: inherit;
|
||||||
min-height: inherit; } }
|
min-height: inherit; } }
|
||||||
|
|
||||||
/*# sourceMappingURL=style.css.map */
|
|
||||||
|
|
|
@ -76,6 +76,11 @@ article {
|
||||||
&.reply-context {
|
&.reply-context {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
background-color: #f3f3f3;
|
background-color: #f3f3f3;
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-height: 240px;
|
||||||
|
max-width: 240px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div {
|
div {
|
||||||
|
@ -95,14 +100,15 @@ article {
|
||||||
|
|
||||||
header {
|
header {
|
||||||
img {
|
img {
|
||||||
max-width: 64px;
|
vertical-align: text-middle;
|
||||||
max-height: 64px;
|
margin: inherit;
|
||||||
min-width: 48px;
|
display: inline;
|
||||||
min-height: 48px;
|
max-width: 1.2em;
|
||||||
margin-left: -85px;
|
max-height: 1.2em;
|
||||||
float: left;
|
min-width: inherit;
|
||||||
border-radius: 4px;
|
min-height: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
color: $lunar-green;
|
color: $lunar-green;
|
||||||
border-bottom: 1px solid $sirocco;
|
border-bottom: 1px solid $sirocco;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from redis import StrictRedis
|
|
||||||
from woodwind.models import Feed, Entry
|
|
||||||
from woodwind import util
|
|
||||||
from flask import Config as FlaskConfig
|
from flask import Config as FlaskConfig
|
||||||
|
from redis import StrictRedis
|
||||||
|
from woodwind import util
|
||||||
|
from woodwind.models import Feed, Entry
|
||||||
import bs4
|
import bs4
|
||||||
import datetime
|
import datetime
|
||||||
import feedparser
|
import feedparser
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue