Run Black over the whole codebase
This commit is contained in:
parent
cd990e4e2f
commit
2e7d12b3e6
109 changed files with 1539 additions and 1209 deletions
|
@ -8,12 +8,10 @@ class SyndicationInline(admin.TabularInline):
|
|||
|
||||
|
||||
class EntryAdmin(admin.ModelAdmin):
|
||||
date_hierarchy = 'created'
|
||||
list_display = ('title', 'id', 'kind', 'created')
|
||||
list_filter = ('kind',)
|
||||
inlines = (
|
||||
SyndicationInline,
|
||||
)
|
||||
date_hierarchy = "created"
|
||||
list_display = ("title", "id", "kind", "created")
|
||||
list_filter = ("kind",)
|
||||
inlines = (SyndicationInline,)
|
||||
|
||||
|
||||
admin.site.register(Cat)
|
||||
|
|
|
@ -2,4 +2,4 @@ from django.apps import AppConfig
|
|||
|
||||
|
||||
class EntriesConfig(AppConfig):
|
||||
name = 'entries'
|
||||
name = "entries"
|
||||
|
|
|
@ -11,24 +11,24 @@ from .models import Entry
|
|||
def from_url(url: str) -> Entry:
|
||||
domain = Site.objects.get_current().domain
|
||||
if not url:
|
||||
raise error.bad_req('url parameter required')
|
||||
if '//' not in url:
|
||||
url = '//' + url
|
||||
parts = urlparse(url, scheme='https')
|
||||
if parts.scheme not in ('http', 'https') or parts.netloc != domain:
|
||||
raise error.bad_req('url does not point to this site')
|
||||
raise error.bad_req("url parameter required")
|
||||
if "//" not in url:
|
||||
url = "//" + url
|
||||
parts = urlparse(url, scheme="https")
|
||||
if parts.scheme not in ("http", "https") or parts.netloc != domain:
|
||||
raise error.bad_req("url does not point to this site")
|
||||
|
||||
try:
|
||||
match = resolve(parts.path)
|
||||
except Resolver404:
|
||||
raise error.bad_req('url does not point to a valid page on this site')
|
||||
raise error.bad_req("url does not point to a valid page on this site")
|
||||
|
||||
if match.view_name != 'entries:entry':
|
||||
raise error.bad_req('url does not point to an entry on this site')
|
||||
if match.view_name != "entries:entry":
|
||||
raise error.bad_req("url does not point to an entry on this site")
|
||||
|
||||
try:
|
||||
entry = Entry.objects.get(pk=match.kwargs['id'])
|
||||
entry = Entry.objects.get(pk=match.kwargs["id"])
|
||||
except Entry.DoesNotExist:
|
||||
raise error.bad_req('url does not point to an existing entry')
|
||||
raise error.bad_req("url does not point to an existing entry")
|
||||
|
||||
return entry
|
||||
|
|
|
@ -7,16 +7,19 @@ from ronkyuu import webmention
|
|||
@job
|
||||
def ping_hub(*urls):
|
||||
for url in urls:
|
||||
requests.post(settings.PUSH_HUB, data={
|
||||
'hub.mode': 'publish',
|
||||
'hub.url': url,
|
||||
})
|
||||
requests.post(
|
||||
settings.PUSH_HUB,
|
||||
data={
|
||||
"hub.mode": "publish",
|
||||
"hub.url": url,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@job
|
||||
def send_mentions(source, targets=None):
|
||||
if targets is None:
|
||||
targets = webmention.findMentions(source)['refs']
|
||||
targets = webmention.findMentions(source)["refs"]
|
||||
for target in targets:
|
||||
status, endpoint = webmention.discoverEndpoint(target)
|
||||
if endpoint is not None and status == 200:
|
||||
|
|
|
@ -14,62 +14,62 @@ class Entry:
|
|||
return self.index_page()
|
||||
|
||||
def index_page(self, page=0):
|
||||
kwargs = {'kind': self}
|
||||
kwargs = {"kind": self}
|
||||
if page > 1:
|
||||
kwargs['page'] = page
|
||||
return reverse('entries:index', kwargs=kwargs)
|
||||
kwargs["page"] = page
|
||||
return reverse("entries:index", kwargs=kwargs)
|
||||
|
||||
@property
|
||||
def entry(self):
|
||||
return self.plural + '_entry'
|
||||
return self.plural + "_entry"
|
||||
|
||||
@property
|
||||
def atom(self):
|
||||
return reverse('entries:atom_by_kind', kwargs={'kind': self})
|
||||
return reverse("entries:atom_by_kind", kwargs={"kind": self})
|
||||
|
||||
@property
|
||||
def rss(self):
|
||||
return reverse('entries:rss_by_kind', kwargs={'kind': self})
|
||||
return reverse("entries:rss_by_kind", kwargs={"kind": self})
|
||||
|
||||
|
||||
Note = Entry(
|
||||
id='note',
|
||||
icon='fas fa-paper-plane',
|
||||
plural='notes',
|
||||
id="note",
|
||||
icon="fas fa-paper-plane",
|
||||
plural="notes",
|
||||
)
|
||||
|
||||
|
||||
Article = Entry(
|
||||
id='article',
|
||||
icon='fas fa-file-alt',
|
||||
plural='articles',
|
||||
id="article",
|
||||
icon="fas fa-file-alt",
|
||||
plural="articles",
|
||||
slug=True,
|
||||
)
|
||||
|
||||
Photo = Entry(
|
||||
id='photo',
|
||||
icon='fas fa-camera',
|
||||
plural='photos',
|
||||
id="photo",
|
||||
icon="fas fa-camera",
|
||||
plural="photos",
|
||||
)
|
||||
|
||||
Reply = Entry(
|
||||
id='reply',
|
||||
icon='fas fa-comment',
|
||||
plural='replies',
|
||||
id="reply",
|
||||
icon="fas fa-comment",
|
||||
plural="replies",
|
||||
on_home=False,
|
||||
)
|
||||
|
||||
Like = Entry(
|
||||
id='like',
|
||||
icon='fas fa-heart',
|
||||
plural='likes',
|
||||
id="like",
|
||||
icon="fas fa-heart",
|
||||
plural="likes",
|
||||
on_home=False,
|
||||
)
|
||||
|
||||
Repost = Entry(
|
||||
id='repost',
|
||||
icon='fas fa-retweet',
|
||||
plural='reposts',
|
||||
id="repost",
|
||||
icon="fas fa-retweet",
|
||||
plural="reposts",
|
||||
)
|
||||
|
||||
all = (Note, Article, Photo)
|
||||
|
@ -79,7 +79,7 @@ from_plural = {k.plural: k for k in all}
|
|||
|
||||
|
||||
class EntryKindConverter:
|
||||
regex = '|'.join(k.plural for k in all)
|
||||
regex = "|".join(k.plural for k in all)
|
||||
|
||||
def to_python(self, plural):
|
||||
return from_plural[plural]
|
||||
|
|
|
@ -8,7 +8,6 @@ import django.db.models.deletion
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
|
@ -17,20 +16,41 @@ class Migration(migrations.Migration):
|
|||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Entry',
|
||||
name="Entry",
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('kind', models.CharField(choices=[('note', 'Note'), ('article', 'Article')], default='note', max_length=30)),
|
||||
('name', models.CharField(blank=True, max_length=100)),
|
||||
('summary', models.TextField(blank=True)),
|
||||
('content', models.TextField()),
|
||||
('published', models.DateTimeField()),
|
||||
('updated', models.DateTimeField()),
|
||||
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"kind",
|
||||
models.CharField(
|
||||
choices=[("note", "Note"), ("article", "Article")],
|
||||
default="note",
|
||||
max_length=30,
|
||||
),
|
||||
),
|
||||
("name", models.CharField(blank=True, max_length=100)),
|
||||
("summary", models.TextField(blank=True)),
|
||||
("content", models.TextField()),
|
||||
("published", models.DateTimeField()),
|
||||
("updated", models.DateTimeField()),
|
||||
(
|
||||
"author",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'entries',
|
||||
'ordering': ['-published'],
|
||||
"verbose_name_plural": "entries",
|
||||
"ordering": ["-published"],
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -7,23 +7,42 @@ import django.db.models.deletion
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0005_auto_20171023_0158'),
|
||||
('entries', '0001_initial'),
|
||||
("users", "0005_auto_20171023_0158"),
|
||||
("entries", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Syndication',
|
||||
name="Syndication",
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('url', models.CharField(max_length=255)),
|
||||
('entry', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='syndications', to='entries.Entry')),
|
||||
('profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.Profile')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("url", models.CharField(max_length=255)),
|
||||
(
|
||||
"entry",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="syndications",
|
||||
to="entries.Entry",
|
||||
),
|
||||
),
|
||||
(
|
||||
"profile",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE, to="users.Profile"
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'ordering': ['profile'],
|
||||
"ordering": ["profile"],
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,14 +6,13 @@ from django.db import migrations
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('entries', '0002_syndication'),
|
||||
("entries", "0002_syndication"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='entry',
|
||||
name='summary',
|
||||
model_name="entry",
|
||||
name="summary",
|
||||
),
|
||||
]
|
||||
|
|
|
@ -8,20 +8,28 @@ import django.db.models.deletion
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('entries', '0003_remove_entry_summary'),
|
||||
("entries", "0003_remove_entry_summary"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='entry',
|
||||
name='author',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='entries', to=settings.AUTH_USER_MODEL),
|
||||
model_name="entry",
|
||||
name="author",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="entries",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='entry',
|
||||
name='kind',
|
||||
field=models.CharField(choices=[('note', 'note'), ('article', 'article')], db_index=True, default='note', max_length=30),
|
||||
model_name="entry",
|
||||
name="kind",
|
||||
field=models.CharField(
|
||||
choices=[("note", "note"), ("article", "article")],
|
||||
db_index=True,
|
||||
default="note",
|
||||
max_length=30,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,20 +6,24 @@ from django.db import migrations, models
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('entries', '0004_auto_20171027_0846'),
|
||||
("entries", "0004_auto_20171027_0846"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='entry',
|
||||
name='photo',
|
||||
field=models.ImageField(blank=True, upload_to=''),
|
||||
model_name="entry",
|
||||
name="photo",
|
||||
field=models.ImageField(blank=True, upload_to=""),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='entry',
|
||||
name='kind',
|
||||
field=models.CharField(choices=[('note', 'note'), ('article', 'article'), ('photo', 'photo')], db_index=True, default='note', max_length=30),
|
||||
model_name="entry",
|
||||
name="kind",
|
||||
field=models.CharField(
|
||||
choices=[("note", "note"), ("article", "article"), ("photo", "photo")],
|
||||
db_index=True,
|
||||
default="note",
|
||||
max_length=30,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -8,34 +8,41 @@ import model_utils.fields
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('entries', '0005_auto_20171027_1557'),
|
||||
("entries", "0005_auto_20171027_1557"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='entry',
|
||||
options={'ordering': ['-created'], 'verbose_name_plural': 'entries'},
|
||||
name="entry",
|
||||
options={"ordering": ["-created"], "verbose_name_plural": "entries"},
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='entry',
|
||||
old_name='published',
|
||||
new_name='created',
|
||||
model_name="entry",
|
||||
old_name="published",
|
||||
new_name="created",
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='entry',
|
||||
old_name='updated',
|
||||
new_name='modified',
|
||||
model_name="entry",
|
||||
old_name="updated",
|
||||
new_name="modified",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='entry',
|
||||
name='created',
|
||||
field=model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created'),
|
||||
model_name="entry",
|
||||
name="created",
|
||||
field=model_utils.fields.AutoCreatedField(
|
||||
default=django.utils.timezone.now,
|
||||
editable=False,
|
||||
verbose_name="created",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='entry',
|
||||
name='modified',
|
||||
field=model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified'),
|
||||
model_name="entry",
|
||||
name="modified",
|
||||
field=model_utils.fields.AutoLastModifiedField(
|
||||
default=django.utils.timezone.now,
|
||||
editable=False,
|
||||
verbose_name="modified",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,20 +6,31 @@ from django.db import migrations, models
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('entries', '0006_auto_20171102_1200'),
|
||||
("entries", "0006_auto_20171102_1200"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='entry',
|
||||
name='cite',
|
||||
model_name="entry",
|
||||
name="cite",
|
||||
field=models.CharField(blank=True, max_length=255),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='entry',
|
||||
name='kind',
|
||||
field=models.CharField(choices=[('note', 'note'), ('article', 'article'), ('photo', 'photo'), ('reply', 'reply'), ('like', 'like'), ('repost', 'repost')], db_index=True, default='note', max_length=30),
|
||||
model_name="entry",
|
||||
name="kind",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("note", "note"),
|
||||
("article", "article"),
|
||||
("photo", "photo"),
|
||||
("reply", "reply"),
|
||||
("like", "like"),
|
||||
("repost", "repost"),
|
||||
],
|
||||
db_index=True,
|
||||
default="note",
|
||||
max_length=30,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,25 +6,24 @@ from django.db import migrations, models
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('entries', '0007_auto_20171113_0841'),
|
||||
("entries", "0007_auto_20171113_0841"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='entry',
|
||||
old_name='cite',
|
||||
new_name='in_reply_to',
|
||||
model_name="entry",
|
||||
old_name="cite",
|
||||
new_name="in_reply_to",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='entry',
|
||||
name='like_of',
|
||||
model_name="entry",
|
||||
name="like_of",
|
||||
field=models.CharField(blank=True, max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='entry',
|
||||
name='repost_of',
|
||||
model_name="entry",
|
||||
name="repost_of",
|
||||
field=models.CharField(blank=True, max_length=255),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,21 +6,28 @@ from django.db import migrations, models
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('entries', '0008_auto_20171116_2116'),
|
||||
("entries", "0008_auto_20171116_2116"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Tag',
|
||||
name="Tag",
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255, unique=True)),
|
||||
('slug', models.CharField(max_length=255, unique=True)),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=255, unique=True)),
|
||||
("slug", models.CharField(max_length=255, unique=True)),
|
||||
],
|
||||
options={
|
||||
'ordering': ('name',),
|
||||
"ordering": ("name",),
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,15 +6,14 @@ from django.db import migrations, models
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('entries', '0009_tag'),
|
||||
("entries", "0009_tag"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='entry',
|
||||
name='tags',
|
||||
field=models.ManyToManyField(related_name='entries', to='entries.Tag'),
|
||||
model_name="entry",
|
||||
name="tags",
|
||||
field=models.ManyToManyField(related_name="entries", to="entries.Tag"),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -9,17 +9,17 @@ class Migration(migrations.Migration):
|
|||
atomic = False
|
||||
|
||||
dependencies = [
|
||||
('entries', '0010_entry_tags'),
|
||||
("entries", "0010_entry_tags"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameModel(
|
||||
old_name='Tag',
|
||||
new_name='Cat',
|
||||
old_name="Tag",
|
||||
new_name="Cat",
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='entry',
|
||||
old_name='tags',
|
||||
new_name='cats',
|
||||
model_name="entry",
|
||||
old_name="tags",
|
||||
new_name="cats",
|
||||
),
|
||||
]
|
||||
|
|
|
@ -5,25 +5,25 @@ from django.db import migrations
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('entries', '0011_auto_20171120_1108'),
|
||||
("entries", "0011_auto_20171120_1108"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='syndication',
|
||||
options={'ordering': ['domain']},
|
||||
name="syndication",
|
||||
options={"ordering": ["domain"]},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='syndication',
|
||||
name='profile',
|
||||
model_name="syndication",
|
||||
name="profile",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='syndication',
|
||||
name='domain',
|
||||
model_name="syndication",
|
||||
name="domain",
|
||||
field=computed_property.fields.ComputedCharField(
|
||||
compute_from='calc_domain', default='', editable=False, max_length=255),
|
||||
compute_from="calc_domain", default="", editable=False, max_length=255
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
|
|
|
@ -4,24 +4,19 @@ from django.db import migrations, models
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('entries', '0012_auto_20180628_2044'),
|
||||
("entries", "0012_auto_20180628_2044"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='entry',
|
||||
name='kind',
|
||||
model_name="entry",
|
||||
name="kind",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
('note', 'note'),
|
||||
('article', 'article'),
|
||||
('photo', 'photo')
|
||||
],
|
||||
choices=[("note", "note"), ("article", "article"), ("photo", "photo")],
|
||||
db_index=True,
|
||||
default='note',
|
||||
max_length=30
|
||||
default="note",
|
||||
max_length=30,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -17,6 +17,7 @@ from users.models import Site
|
|||
|
||||
from . import kinds
|
||||
from lemoncurry import requests, utils
|
||||
|
||||
ENTRY_KINDS = [(k.id, k.id) for k in kinds.all]
|
||||
|
||||
|
||||
|
@ -32,38 +33,33 @@ class Cat(models.Model):
|
|||
slug = models.CharField(max_length=255, unique=True)
|
||||
|
||||
def __str__(self):
|
||||
return '#' + self.name
|
||||
return "#" + self.name
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
return reverse('entries:cat', args=(self.slug,))
|
||||
return reverse("entries:cat", args=(self.slug,))
|
||||
|
||||
class Meta:
|
||||
ordering = ('name',)
|
||||
ordering = ("name",)
|
||||
|
||||
|
||||
class EntryManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
qs = super(EntryManager, self).get_queryset()
|
||||
return (qs
|
||||
.select_related('author')
|
||||
.prefetch_related('cats', 'syndications'))
|
||||
return qs.select_related("author").prefetch_related("cats", "syndications")
|
||||
|
||||
|
||||
class Entry(ModelMeta, TimeStampedModel):
|
||||
objects = EntryManager()
|
||||
kind = models.CharField(
|
||||
max_length=30,
|
||||
choices=ENTRY_KINDS,
|
||||
db_index=True,
|
||||
default=ENTRY_KINDS[0][0]
|
||||
max_length=30, choices=ENTRY_KINDS, db_index=True, default=ENTRY_KINDS[0][0]
|
||||
)
|
||||
|
||||
name = models.CharField(max_length=100, blank=True)
|
||||
photo = models.ImageField(blank=True)
|
||||
content = models.TextField()
|
||||
|
||||
cats = models.ManyToManyField(Cat, related_name='entries')
|
||||
cats = models.ManyToManyField(Cat, related_name="entries")
|
||||
|
||||
in_reply_to = models.CharField(max_length=255, blank=True)
|
||||
like_of = models.CharField(max_length=255, blank=True)
|
||||
|
@ -71,7 +67,7 @@ class Entry(ModelMeta, TimeStampedModel):
|
|||
|
||||
author = models.ForeignKey(
|
||||
get_user_model(),
|
||||
related_name='entries',
|
||||
related_name="entries",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
|
||||
|
@ -79,10 +75,7 @@ class Entry(ModelMeta, TimeStampedModel):
|
|||
def reply_context(self):
|
||||
if not self.in_reply_to:
|
||||
return None
|
||||
return interpret(
|
||||
requests.mf2(self.in_reply_to).to_dict(),
|
||||
self.in_reply_to
|
||||
)
|
||||
return interpret(requests.mf2(self.in_reply_to).to_dict(), self.in_reply_to)
|
||||
|
||||
@property
|
||||
def published(self):
|
||||
|
@ -93,35 +86,29 @@ class Entry(ModelMeta, TimeStampedModel):
|
|||
return self.modified
|
||||
|
||||
_metadata = {
|
||||
'description': 'excerpt',
|
||||
'image': 'image_url',
|
||||
'twitter_creator': 'twitter_creator',
|
||||
'og_profile_id': 'og_profile_id',
|
||||
"description": "excerpt",
|
||||
"image": "image_url",
|
||||
"twitter_creator": "twitter_creator",
|
||||
"og_profile_id": "og_profile_id",
|
||||
}
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
if self.name:
|
||||
return self.name
|
||||
return shorten(
|
||||
utils.to_plain(self.paragraphs[0]),
|
||||
width=100,
|
||||
placeholder='…'
|
||||
)
|
||||
return shorten(utils.to_plain(self.paragraphs[0]), width=100, placeholder="…")
|
||||
|
||||
@property
|
||||
def excerpt(self):
|
||||
try:
|
||||
return utils.to_plain(self.paragraphs[0 if self.name else 1])
|
||||
except IndexError:
|
||||
return ' '
|
||||
return " "
|
||||
|
||||
@property
|
||||
def paragraphs(self):
|
||||
lines = self.content.splitlines()
|
||||
return [
|
||||
"\n".join(para) for k, para in groupby(lines, key=bool) if k
|
||||
]
|
||||
return ["\n".join(para) for k, para in groupby(lines, key=bool) if k]
|
||||
|
||||
@property
|
||||
def twitter_creator(self):
|
||||
|
@ -136,31 +123,31 @@ class Entry(ModelMeta, TimeStampedModel):
|
|||
return self.photo.url if self.photo else self.author.avatar_url
|
||||
|
||||
def __str__(self):
|
||||
return '{0} {1}: {2}'.format(self.kind, self.id, self.title)
|
||||
return "{0} {1}: {2}".format(self.kind, self.id, self.title)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return self.absolute_url
|
||||
|
||||
@property
|
||||
def absolute_url(self):
|
||||
base = 'https://' + DjangoSite.objects.get_current().domain
|
||||
base = "https://" + DjangoSite.objects.get_current().domain
|
||||
return urljoin(base, self.url)
|
||||
|
||||
@property
|
||||
def affected_urls(self):
|
||||
base = 'https://' + DjangoSite.objects.get_current().domain
|
||||
base = "https://" + DjangoSite.objects.get_current().domain
|
||||
kind = kinds.from_id[self.kind]
|
||||
urls = {
|
||||
self.url,
|
||||
reverse('entries:index', kwargs={'kind': kind}),
|
||||
reverse('entries:atom_by_kind', kwargs={'kind': kind}),
|
||||
reverse('entries:rss_by_kind', kwargs={'kind': kind}),
|
||||
reverse("entries:index", kwargs={"kind": kind}),
|
||||
reverse("entries:atom_by_kind", kwargs={"kind": kind}),
|
||||
reverse("entries:rss_by_kind", kwargs={"kind": kind}),
|
||||
} | {cat.url for cat in self.cats.all()}
|
||||
if kind.on_home:
|
||||
urls |= {
|
||||
reverse('home:index'),
|
||||
reverse('entries:atom'),
|
||||
reverse('entries:rss')
|
||||
reverse("home:index"),
|
||||
reverse("entries:atom"),
|
||||
reverse("entries:rss"),
|
||||
}
|
||||
return {urljoin(base, u) for u in urls}
|
||||
|
||||
|
@ -170,7 +157,7 @@ class Entry(ModelMeta, TimeStampedModel):
|
|||
args = [kind, self.id]
|
||||
if kind.slug:
|
||||
args.append(self.slug)
|
||||
return reverse('entries:entry', args=args)
|
||||
return reverse("entries:entry", args=args)
|
||||
|
||||
@property
|
||||
def short_url(self):
|
||||
|
@ -182,49 +169,48 @@ class Entry(ModelMeta, TimeStampedModel):
|
|||
|
||||
@property
|
||||
def json_ld(self):
|
||||
base = 'https://' + DjangoSite.objects.get_current().domain
|
||||
base = "https://" + DjangoSite.objects.get_current().domain
|
||||
url = urljoin(base, self.url)
|
||||
|
||||
posting = {
|
||||
'@context': 'http://schema.org',
|
||||
'@type': 'BlogPosting',
|
||||
'@id': url,
|
||||
'url': url,
|
||||
'mainEntityOfPage': url,
|
||||
'author': {
|
||||
'@type': 'Person',
|
||||
'url': urljoin(base, self.author.url),
|
||||
'name': self.author.name,
|
||||
"@context": "http://schema.org",
|
||||
"@type": "BlogPosting",
|
||||
"@id": url,
|
||||
"url": url,
|
||||
"mainEntityOfPage": url,
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"url": urljoin(base, self.author.url),
|
||||
"name": self.author.name,
|
||||
},
|
||||
'headline': self.title,
|
||||
'description': self.excerpt,
|
||||
'datePublished': self.created.isoformat(),
|
||||
'dateModified': self.modified.isoformat(),
|
||||
"headline": self.title,
|
||||
"description": self.excerpt,
|
||||
"datePublished": self.created.isoformat(),
|
||||
"dateModified": self.modified.isoformat(),
|
||||
}
|
||||
if self.photo:
|
||||
posting['image'] = (urljoin(base, self.photo.url), )
|
||||
posting["image"] = (urljoin(base, self.photo.url),)
|
||||
return posting
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = 'entries'
|
||||
ordering = ['-created']
|
||||
verbose_name_plural = "entries"
|
||||
ordering = ["-created"]
|
||||
|
||||
|
||||
class Syndication(models.Model):
|
||||
entry = models.ForeignKey(
|
||||
Entry,
|
||||
related_name='syndications',
|
||||
on_delete=models.CASCADE
|
||||
Entry, related_name="syndications", on_delete=models.CASCADE
|
||||
)
|
||||
url = models.CharField(max_length=255)
|
||||
|
||||
domain = ComputedCharField(
|
||||
compute_from='calc_domain', max_length=255,
|
||||
compute_from="calc_domain",
|
||||
max_length=255,
|
||||
)
|
||||
|
||||
def calc_domain(self):
|
||||
domain = urlparse(self.url).netloc
|
||||
if domain.startswith('www.'):
|
||||
if domain.startswith("www."):
|
||||
domain = domain[4:]
|
||||
return domain
|
||||
|
||||
|
@ -234,7 +220,7 @@ class Syndication(models.Model):
|
|||
try:
|
||||
return Site.objects.get(domain=d)
|
||||
except Site.DoesNotExist:
|
||||
return Site(name=d, domain=d, icon='fas fa-newspaper')
|
||||
return Site(name=d, domain=d, icon="fas fa-newspaper")
|
||||
|
||||
class Meta:
|
||||
ordering = ['domain']
|
||||
ordering = ["domain"]
|
||||
|
|
|
@ -3,27 +3,27 @@ import pytest
|
|||
|
||||
@pytest.mark.django_db
|
||||
def test_atom(client):
|
||||
res = client.get('/atom')
|
||||
res = client.get("/atom")
|
||||
assert res.status_code == 200
|
||||
assert res['Content-Type'] == 'application/atom+xml; charset=utf-8'
|
||||
assert res["Content-Type"] == "application/atom+xml; charset=utf-8"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_rss(client):
|
||||
res = client.get('/rss')
|
||||
res = client.get("/rss")
|
||||
assert res.status_code == 200
|
||||
assert res['Content-Type'] == 'application/rss+xml; charset=utf-8'
|
||||
assert res["Content-Type"] == "application/rss+xml; charset=utf-8"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_atom_by_kind(client):
|
||||
res = client.get('/notes/atom')
|
||||
res = client.get("/notes/atom")
|
||||
assert res.status_code == 200
|
||||
assert res['Content-Type'] == 'application/atom+xml; charset=utf-8'
|
||||
assert res["Content-Type"] == "application/atom+xml; charset=utf-8"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_rss_by_kind(client):
|
||||
res = client.get('/notes/rss')
|
||||
res = client.get("/notes/rss")
|
||||
assert res.status_code == 200
|
||||
assert res['Content-Type'] == 'application/rss+xml; charset=utf-8'
|
||||
assert res["Content-Type"] == "application/rss+xml; charset=utf-8"
|
||||
|
|
|
@ -3,47 +3,46 @@ from . import kinds
|
|||
from .views import feeds, lists, perma
|
||||
from lemoncurry import breadcrumbs as crumbs
|
||||
|
||||
register_converter(kinds.EntryKindConverter, 'kind')
|
||||
register_converter(kinds.EntryKindConverter, "kind")
|
||||
|
||||
|
||||
def to_pat(*args):
|
||||
return '^{0}$'.format(''.join(args))
|
||||
return "^{0}$".format("".join(args))
|
||||
|
||||
|
||||
def prefix(route):
|
||||
return app_name + ':' + route
|
||||
return app_name + ":" + route
|
||||
|
||||
|
||||
id = r'/(?P<id>\d+)'
|
||||
kind = r'(?P<kind>{0})'.format('|'.join(k.plural for k in kinds.all))
|
||||
page = r'(?:/page/(?P<page>\d+))?'
|
||||
slug = r'/(?P<slug>[^/]+)'
|
||||
id = r"/(?P<id>\d+)"
|
||||
kind = r"(?P<kind>{0})".format("|".join(k.plural for k in kinds.all))
|
||||
page = r"(?:/page/(?P<page>\d+))?"
|
||||
slug = r"/(?P<slug>[^/]+)"
|
||||
|
||||
slug_opt = '(?:' + slug + ')?'
|
||||
slug_opt = "(?:" + slug + ")?"
|
||||
|
||||
app_name = 'entries'
|
||||
app_name = "entries"
|
||||
urlpatterns = (
|
||||
path('atom', feeds.AtomHomeEntries(), name='atom'),
|
||||
path('rss', feeds.RssHomeEntries(), name='rss'),
|
||||
path('cats/<slug:slug>', lists.by_cat, name='cat'),
|
||||
path('cats/<slug:slug>/page/<int:page>', lists.by_cat, name='cat'),
|
||||
path('<kind:kind>', lists.by_kind, name='index'),
|
||||
path('<kind:kind>/page/<int:page>', lists.by_kind, name='index'),
|
||||
path('<kind:kind>/atom', feeds.AtomByKind(), name='atom_by_kind'),
|
||||
path('<kind:kind>/rss', feeds.RssByKind(), name='rss_by_kind'),
|
||||
|
||||
path('<kind:kind>/<int:id>', perma.entry, name='entry'),
|
||||
path('<kind:kind>/<int:id>/<slug:slug>', perma.entry, name='entry'),
|
||||
path("atom", feeds.AtomHomeEntries(), name="atom"),
|
||||
path("rss", feeds.RssHomeEntries(), name="rss"),
|
||||
path("cats/<slug:slug>", lists.by_cat, name="cat"),
|
||||
path("cats/<slug:slug>/page/<int:page>", lists.by_cat, name="cat"),
|
||||
path("<kind:kind>", lists.by_kind, name="index"),
|
||||
path("<kind:kind>/page/<int:page>", lists.by_kind, name="index"),
|
||||
path("<kind:kind>/atom", feeds.AtomByKind(), name="atom_by_kind"),
|
||||
path("<kind:kind>/rss", feeds.RssByKind(), name="rss_by_kind"),
|
||||
path("<kind:kind>/<int:id>", perma.entry, name="entry"),
|
||||
path("<kind:kind>/<int:id>/<slug:slug>", perma.entry, name="entry"),
|
||||
)
|
||||
|
||||
|
||||
class IndexCrumb(crumbs.Crumb):
|
||||
def __init__(self):
|
||||
super().__init__(prefix('index'), parent='home:index')
|
||||
super().__init__(prefix("index"), parent="home:index")
|
||||
|
||||
@property
|
||||
def kind(self):
|
||||
return self.match.kwargs['kind']
|
||||
return self.match.kwargs["kind"]
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
|
@ -51,9 +50,9 @@ class IndexCrumb(crumbs.Crumb):
|
|||
|
||||
@property
|
||||
def url(self):
|
||||
return reverse(prefix('index'), kwargs={'kind': self.kind})
|
||||
return reverse(prefix("index"), kwargs={"kind": self.kind})
|
||||
|
||||
|
||||
crumbs.add(prefix('cat'), parent='home:index')
|
||||
crumbs.add(prefix("cat"), parent="home:index")
|
||||
crumbs.add(IndexCrumb())
|
||||
crumbs.add(prefix('entry'), parent=prefix('index'))
|
||||
crumbs.add(prefix("entry"), parent=prefix("index"))
|
||||
|
|
|
@ -11,8 +11,8 @@ from ..models import Entry
|
|||
class Atom1FeedWithHub(Atom1Feed):
|
||||
def add_root_elements(self, handler):
|
||||
super().add_root_elements(handler)
|
||||
handler.startElement('link', {'rel': 'hub', 'href': settings.PUSH_HUB})
|
||||
handler.endElement('link')
|
||||
handler.startElement("link", {"rel": "hub", "href": settings.PUSH_HUB})
|
||||
handler.endElement("link")
|
||||
|
||||
|
||||
class EntriesFeed(Feed):
|
||||
|
@ -79,7 +79,7 @@ class RssHomeEntries(EntriesFeed):
|
|||
return Site.objects.get_current().name
|
||||
|
||||
def link(self):
|
||||
return reverse('home:index')
|
||||
return reverse("home:index")
|
||||
|
||||
def description(self):
|
||||
return "content from {0}".format(
|
||||
|
|
|
@ -5,32 +5,32 @@ from ..models import Entry, Cat
|
|||
from ..pagination import paginate
|
||||
|
||||
|
||||
@render_to('entries/index.html')
|
||||
@render_to("entries/index.html")
|
||||
def by_kind(request, kind, page=None):
|
||||
entries = Entry.objects.filter(kind=kind.id)
|
||||
entries = paginate(queryset=entries, reverse=kind.index_page, page=page)
|
||||
|
||||
return {
|
||||
'entries': entries,
|
||||
'atom': kind.atom,
|
||||
'rss': kind.rss,
|
||||
'title': kind.plural,
|
||||
"entries": entries,
|
||||
"atom": kind.atom,
|
||||
"rss": kind.rss,
|
||||
"title": kind.plural,
|
||||
}
|
||||
|
||||
|
||||
@render_to('entries/index.html')
|
||||
@render_to("entries/index.html")
|
||||
def by_cat(request, slug, page=None):
|
||||
def url(page):
|
||||
kwargs = {'slug': slug}
|
||||
kwargs = {"slug": slug}
|
||||
if page > 1:
|
||||
kwargs['page'] = page
|
||||
return reverse('entries:cat', kwargs=kwargs)
|
||||
kwargs["page"] = page
|
||||
return reverse("entries:cat", kwargs=kwargs)
|
||||
|
||||
cat = get_object_or_404(Cat, slug=slug)
|
||||
entries = cat.entries.all()
|
||||
entries = paginate(queryset=entries, reverse=url, page=page)
|
||||
|
||||
return {
|
||||
'entries': entries,
|
||||
'title': '#' + cat.name,
|
||||
"entries": entries,
|
||||
"title": "#" + cat.name,
|
||||
}
|
||||
|
|
|
@ -3,12 +3,12 @@ from django.shortcuts import redirect, get_object_or_404
|
|||
from ..models import Entry
|
||||
|
||||
|
||||
@render_to('entries/entry.html')
|
||||
@render_to("entries/entry.html")
|
||||
def entry(request, kind, id, slug=None):
|
||||
entry = get_object_or_404(Entry, pk=id)
|
||||
if request.path != entry.url:
|
||||
return redirect(entry.url, permanent=True)
|
||||
return {
|
||||
'entry': entry,
|
||||
'title': entry.title,
|
||||
"entry": entry,
|
||||
"title": entry.title,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import multiprocessing
|
||||
|
||||
proc_name = 'lemoncurry'
|
||||
worker_class = 'gevent'
|
||||
proc_name = "lemoncurry"
|
||||
worker_class = "gevent"
|
||||
workers = multiprocessing.cpu_count() * 2 + 1
|
||||
|
|
|
@ -3,10 +3,10 @@ from django.urls import reverse
|
|||
|
||||
|
||||
class HomeSitemap(sitemaps.Sitemap):
|
||||
changefreq = 'daily'
|
||||
changefreq = "daily"
|
||||
|
||||
def items(self):
|
||||
return ('home:index',)
|
||||
return ("home:index",)
|
||||
|
||||
def location(self, item):
|
||||
return reverse(item)
|
||||
|
|
|
@ -2,9 +2,9 @@ from django.urls import path
|
|||
|
||||
from . import views
|
||||
|
||||
app_name = 'home'
|
||||
app_name = "home"
|
||||
urlpatterns = [
|
||||
path('', views.index, name='index'),
|
||||
path('page/<int:page>', views.index, name='index'),
|
||||
path('robots.txt', views.robots, name='robots.txt'),
|
||||
path("", views.index, name="index"),
|
||||
path("page/<int:page>", views.index, name="index"),
|
||||
path("robots.txt", views.robots, name="robots.txt"),
|
||||
]
|
||||
|
|
|
@ -8,34 +8,31 @@ from urllib.parse import urljoin
|
|||
from entries import kinds, pagination
|
||||
from lemoncurry import breadcrumbs, utils
|
||||
|
||||
breadcrumbs.add('home:index', 'home')
|
||||
breadcrumbs.add("home:index", "home")
|
||||
|
||||
|
||||
@render_to('home/index.html')
|
||||
@render_to("home/index.html")
|
||||
def index(request, page=None):
|
||||
def url(page):
|
||||
kwargs = {'page': page} if page != 1 else {}
|
||||
return reverse('home:index', kwargs=kwargs)
|
||||
kwargs = {"page": page} if page != 1 else {}
|
||||
return reverse("home:index", kwargs=kwargs)
|
||||
|
||||
user = request.user
|
||||
if not hasattr(user, 'entries'):
|
||||
if not hasattr(user, "entries"):
|
||||
user = get_object_or_404(User, pk=1)
|
||||
|
||||
entries = user. |