Compare commits
2 Commits
69f208fb8b
...
1b0e30ff9e
Author | SHA1 | Date | |
---|---|---|---|
1b0e30ff9e | |||
2538c7ea7f |
59
admin.py
59
admin.py
@ -646,19 +646,55 @@ def register_administerable(cls):
|
||||
# for each model (otherwise the last view function definitions would
|
||||
# get registered to all routes).
|
||||
|
||||
@auth
|
||||
@rendering.page(title_show=False)
|
||||
def view_listing():
|
||||
Commentable = Administerable.__class_descendants__['Commentable'] # avoids circular dependency
|
||||
|
||||
menu = rendering.Menu(
|
||||
f'{cls._lowerclass}-listing-actions',
|
||||
[{
|
||||
'endpoint': f'admin.{cls._lowerclass}_create',
|
||||
'label': 'Create new',
|
||||
}]
|
||||
)
|
||||
if issubclass(cls, Commentable):
|
||||
|
||||
return rendering.Listing(cls.select(), title=cls.__name__, mode='admin-teaser', menu=menu)
|
||||
@auth
|
||||
@rendering.page(title_show=False)
|
||||
def view_listing(offset=0):
|
||||
|
||||
menu = rendering.Menu(
|
||||
f'{cls._lowerclass}-listing-actions',
|
||||
[{
|
||||
'endpoint': f'admin.{cls._lowerclass}_create',
|
||||
'label': 'Create new',
|
||||
}]
|
||||
)
|
||||
|
||||
return rendering.Listing(cls.select().order_by(cls.created.desc(), cls.name, cls.id.desc()), title=cls.__name__, mode='teaser', menu=menu, endpoint=f'admin.{cls._lowerclass}_listing', offset=offset)
|
||||
|
||||
elif issubclass(cls, Named):
|
||||
|
||||
@auth
|
||||
@rendering.page(title_show=False)
|
||||
def view_listing(offset=0):
|
||||
|
||||
menu = rendering.Menu(
|
||||
f'{cls._lowerclass}-listing-actions',
|
||||
[{
|
||||
'endpoint': f'admin.{cls._lowerclass}_create',
|
||||
'label': 'Create new',
|
||||
}]
|
||||
)
|
||||
|
||||
return rendering.Listing(cls.select().order_by(cls.name, cls.id.desc()), title=cls.__name__, mode='teaser', menu=menu, endpoint=f'admin.{cls._lowerclass}_listing', offset=offset)
|
||||
|
||||
else:
|
||||
|
||||
@auth
|
||||
@rendering.page(title_show=False)
|
||||
def view_listing(offset=0):
|
||||
|
||||
menu = rendering.Menu(
|
||||
f'{cls._lowerclass}-listing-actions',
|
||||
[{
|
||||
'endpoint': f'admin.{cls._lowerclass}_create',
|
||||
'label': 'Create new',
|
||||
}]
|
||||
)
|
||||
|
||||
return rendering.Listing(cls.select().order_by(cls.id.desc()), title=cls.__name__, mode='teaser', menu=menu, endpoint=f'admin.{cls._lowerclass}_listing', offset=offset)
|
||||
|
||||
@auth
|
||||
def view_create(*args, **kwargs):
|
||||
@ -682,6 +718,7 @@ def register_administerable(cls):
|
||||
return cls.view(*args, **kwargs)
|
||||
|
||||
app.admin.add_url_rule(f'/{cls._lowerclass}/', f'{cls._lowerclass}_listing', view_listing)
|
||||
app.admin.add_url_rule(f'/{cls._lowerclass}/+<int:offset>/', f'{cls._lowerclass}_listing', view_listing)
|
||||
|
||||
app.admin.add_url_rule(f'/{cls._lowerclass}/create/', f'{cls._lowerclass}_create', view_create, methods=['GET', 'POST'])
|
||||
if issubclass(cls, Named):
|
||||
|
@ -135,7 +135,6 @@ class Application(flask.Flask, MenuMixin, BlockMixin):
|
||||
# public routes
|
||||
@rendering.page(title_show=False)
|
||||
def listing(offset=0):
|
||||
# TODO: Menu?
|
||||
return rendering.Listing(cls.list(), title=cls.__name__, endpoint=f'{cls._lowerclass}_listing', offset=offset)
|
||||
|
||||
@rendering.page(format='atom')
|
||||
|
18
main.py
18
main.py
@ -122,6 +122,20 @@ def menu_footer():
|
||||
'endpoint': 'the_button',
|
||||
'label': 'The Button',
|
||||
},
|
||||
{
|
||||
'endpoint': 'view_page',
|
||||
'params': {
|
||||
'path': '/donate',
|
||||
},
|
||||
'label': 'Donate',
|
||||
},
|
||||
{
|
||||
'endpoint': 'view_page',
|
||||
'params': {
|
||||
'path': '/hire',
|
||||
},
|
||||
'label': 'Hire',
|
||||
},
|
||||
]
|
||||
|
||||
return rendering.Menu('secondary', items)
|
||||
@ -540,10 +554,10 @@ class ScoredLink(admin.Administerable):
|
||||
last_scrape = peewee.DateTimeField(null=True, default=None)
|
||||
|
||||
explanation_external_site_count = markdown.SafeMarkdownString("""
|
||||
How many **third-party sites** the linked content loads data from.
|
||||
How many **third-party sites** the linked page loads data from.
|
||||
|
||||
This is relevant to your privacy because each of those third-party sites
|
||||
gets – at the very least – to see that you visited the linked content.
|
||||
gets – at the very least – to see that you visited this page.
|
||||
|
||||
*Lower* is better, **0** is *ideal*.""")
|
||||
|
||||
|
55
tagging.py
55
tagging.py
@ -1,3 +1,6 @@
|
||||
# builtins
|
||||
import functools
|
||||
|
||||
# third-party
|
||||
import werkzeug
|
||||
import flask
|
||||
@ -13,12 +16,40 @@ import markdown
|
||||
import form
|
||||
import admin
|
||||
|
||||
@app.expose('/tag/')
|
||||
class Tag(admin.Named):
|
||||
|
||||
title = markdown.SafeMarkdownCharField(null=False, verbose_name='Title')
|
||||
text = markdown.MarkdownTextField()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
self.listing_offset = 0
|
||||
|
||||
@classmethod
|
||||
def view(cls, mode='full', offset=0, **kwargs):
|
||||
|
||||
if mode != 'full':
|
||||
return super().view(mode=mode, **kwargs)
|
||||
|
||||
# NOTE: copied over from Named.view, added setting of listing_offset
|
||||
# TODO: there should be a more generalized solution for this.
|
||||
# decorated `wrapped` functions should be moved into the
|
||||
# classes themselves, so they can be easily overriden
|
||||
|
||||
@rendering.page(mode=mode, title_show=False) # show title in own template, gives better flexibility
|
||||
def wrapped(**kw):
|
||||
|
||||
instance = cls.load(kw['name'])
|
||||
instance.listing_offset = offset
|
||||
|
||||
if not instance.access(mode):
|
||||
flask.abort(404)
|
||||
|
||||
return instance
|
||||
|
||||
return wrapped(**kwargs)
|
||||
|
||||
@werkzeug.utils.cached_property
|
||||
def listing(self):
|
||||
|
||||
@ -60,7 +91,7 @@ class Tag(admin.Named):
|
||||
|
||||
stmt = stmt.order_by(stmt.c.created.desc(), stmt.c.name.asc())
|
||||
|
||||
return rendering.Listing(stmt.dicts(), item_constructor=taggable_constructor)
|
||||
return rendering.Listing(stmt.dicts(), offset=self.listing_offset, endpoint='tag_full', endpoint_params={'name': self.name}, item_constructor=taggable_constructor)
|
||||
|
||||
class TagCollectionForm(admin.AutoForm):
|
||||
|
||||
@ -277,3 +308,23 @@ def taggable_constructor(item):
|
||||
|
||||
taggable = Taggable.__class_descendants__[ item['type'] ]
|
||||
return taggable.load(item['name'])
|
||||
|
||||
# Fake @app.expose, but with extra offset for tag_full
|
||||
|
||||
@rendering.page(title_show=False)
|
||||
def tag_listing(offset=0):
|
||||
|
||||
return rendering.Listing(Tag.list(), title='Tag', endpoint='tag_listing', offset=offset)
|
||||
|
||||
@rendering.page(format='atom')
|
||||
def tag_feed():
|
||||
return rendering.Listing(Tag.list(), title=cls.__name__)
|
||||
|
||||
tag_full = functools.partial(Tag.view, mode='full')
|
||||
|
||||
app.add_url_rule('/tag/', 'tag_listing', tag_listing)
|
||||
app.add_url_rule('/tag/+<int:offset>/', 'tag_listing', tag_listing)
|
||||
app.add_url_rule('/feed/tag', 'tag_feed', tag_feed)
|
||||
app.add_url_rule('/tag/<string:name>/', 'tag_full', tag_full)
|
||||
app.add_url_rule('/tag/<string:name>/+<int:offset>/', 'tag_full', tag_full)
|
||||
app.models_exposed['Tag'] = Tag
|
||||
|
@ -1114,6 +1114,11 @@ article.renderable > .content > h6 {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
article.renderable.mode-full > footer .meta {
|
||||
max-width: var(--distance-typographic-width);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
article.administerable > .content section {
|
||||
background: hsla(0 0 5 / 90%);
|
||||
backdrop-filter: blur(8px);
|
||||
@ -1180,7 +1185,7 @@ article.audio audio {
|
||||
background: #444;
|
||||
}
|
||||
|
||||
article.image .description {
|
||||
article.image.mode-inline .description {
|
||||
position: absolute;
|
||||
left: 50vw;
|
||||
translate: -50% -100%;
|
||||
|
@ -10,6 +10,14 @@
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block meta_header %}
|
||||
|
||||
<span class="created">{{ content.created|prettydate }}</span>
|
||||
|
||||
{{ super() }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
|
||||
{{ super() }}
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
{% block header %}
|
||||
|
||||
{{ super() }}
|
||||
|
||||
{% if mode == 'full' %}
|
||||
|
||||
{% if content.lead_image_id %}
|
||||
@ -18,6 +16,8 @@
|
||||
|
||||
{% endif %}
|
||||
|
||||
{{ super() }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
@ -3,7 +3,13 @@
|
||||
|
||||
{% if self.header()|trim %}
|
||||
<header>
|
||||
{% block header %}{% endblock %}
|
||||
{% block header %}
|
||||
{% if self.meta_header() %}
|
||||
<div class="meta">
|
||||
{% block meta_header %}{% endblock %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</header>
|
||||
{% endif %}
|
||||
|
||||
@ -22,9 +28,9 @@
|
||||
{% if self.footer()|trim %}
|
||||
<footer>
|
||||
{% block footer %}
|
||||
{% if self.meta()|trim %}
|
||||
{% if self.meta_footer()|trim %}
|
||||
<div class="meta">
|
||||
{% block meta %}{% endblock %}
|
||||
{% block meta_footer %}{% endblock %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{% extends 'default/templates/renderable/administerable.html' %}
|
||||
|
||||
{% block meta %}
|
||||
{% block meta_footer %}
|
||||
|
||||
{{ super() }}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user