mirror of
https://github.com/DarrenOfficial/dpaste.git
synced 2024-11-15 16:12:51 +11:00
First pass of Type Annotations
This commit is contained in:
parent
08f7d9c27f
commit
cf3ad14795
12 changed files with 204 additions and 123 deletions
|
@ -1,4 +1,7 @@
|
|||
from typing import Dict, List, Optional, Tuple, Type, Union
|
||||
|
||||
from django.apps import AppConfig, apps
|
||||
from django.core.handlers.wsgi import WSGIRequest
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
@ -118,7 +121,7 @@ class dpasteAppConfig(AppConfig):
|
|||
PLAIN_CODE_SYMBOL = "_code"
|
||||
|
||||
@property
|
||||
def TEXT_FORMATTER(self):
|
||||
def TEXT_FORMATTER(self,) -> List[Tuple[str, str, Type[object]]]:
|
||||
"""
|
||||
Choices list with all "Text" lexer. Prepend keys with an underscore
|
||||
so they don't accidentally clash with a Pygments Lexer name.
|
||||
|
@ -130,6 +133,8 @@ class dpasteAppConfig(AppConfig):
|
|||
Lexer Highlight Class)
|
||||
|
||||
If the Highlight Class is not given, PygmentsHighlighter is used.
|
||||
|
||||
@FIXME: Make `Type[object]` use the Type[Highlighter] class.
|
||||
"""
|
||||
from dpaste.highlight import (
|
||||
PlainTextHighlighter,
|
||||
|
@ -144,7 +149,9 @@ class dpasteAppConfig(AppConfig):
|
|||
]
|
||||
|
||||
@property
|
||||
def CODE_FORMATTER(self):
|
||||
def CODE_FORMATTER(
|
||||
self,
|
||||
) -> List[Union[Tuple[str, str, Type[object]], Tuple[str, str]]]:
|
||||
"""
|
||||
Choices list with all "Code" Lexer. Each list
|
||||
contains a lexer tuple of:
|
||||
|
@ -621,7 +628,7 @@ class dpasteAppConfig(AppConfig):
|
|||
CACHE_TIMEOUT = 60 * 10
|
||||
|
||||
@staticmethod
|
||||
def get_base_url(request=None):
|
||||
def get_base_url(request: Optional[WSGIRequest] = None) -> str:
|
||||
"""
|
||||
String. The full qualified hostname and path to the dpaste instance.
|
||||
This is used to generate a link in the API response. If the "Sites"
|
||||
|
@ -637,7 +644,7 @@ class dpasteAppConfig(AppConfig):
|
|||
return "https://dpaste-base-url.example.org"
|
||||
|
||||
@property
|
||||
def extra_template_context(self):
|
||||
def extra_template_context(self) -> Dict[str, str]:
|
||||
"""
|
||||
Returns a dictionary with context variables which are passed to
|
||||
all Template Views.
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, Optional, Tuple, Type, Union
|
||||
|
||||
from django import forms
|
||||
from django.apps import apps
|
||||
from django.core.handlers.wsgi import WSGIRequest
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .highlight import LEXER_CHOICES, LEXER_DEFAULT, LEXER_KEYS
|
||||
|
@ -10,7 +12,9 @@ from .models import Snippet
|
|||
config = apps.get_app_config("dpaste")
|
||||
|
||||
|
||||
def get_expire_values(expires):
|
||||
def get_expire_values(
|
||||
expires: str,
|
||||
) -> Union[Tuple[None, int], Tuple[datetime, int]]:
|
||||
if expires == "never":
|
||||
expire_type = Snippet.EXPIRE_KEEP
|
||||
expires = None
|
||||
|
@ -20,9 +24,7 @@ def get_expire_values(expires):
|
|||
else:
|
||||
expire_type = Snippet.EXPIRE_TIME
|
||||
expires = expires and expires or config.EXPIRE_DEFAULT
|
||||
expires = datetime.datetime.now() + datetime.timedelta(
|
||||
seconds=int(expires)
|
||||
)
|
||||
expires = datetime.now() + timedelta(seconds=int(expires))
|
||||
return expires, expire_type
|
||||
|
||||
|
||||
|
@ -59,7 +61,7 @@ class SnippetForm(forms.ModelForm):
|
|||
model = Snippet
|
||||
fields = ("content", "lexer", "rtl")
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
def __init__(self, request: WSGIRequest, *args, **kwargs) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
self.request = request
|
||||
|
||||
|
@ -72,13 +74,13 @@ class SnippetForm(forms.ModelForm):
|
|||
if "l" in request.GET and request.GET["l"] in LEXER_KEYS:
|
||||
self.fields["lexer"].initial = request.GET["l"]
|
||||
|
||||
def clean_content(self):
|
||||
def clean_content(self) -> str:
|
||||
content = self.cleaned_data.get("content", "")
|
||||
if not content.strip():
|
||||
raise forms.ValidationError(_("This field is required."))
|
||||
return content
|
||||
|
||||
def clean_expires(self):
|
||||
def clean_expires(self) -> Optional[datetime]:
|
||||
"""
|
||||
Extract the 'expire_type' from the choice of expire choices.
|
||||
"""
|
||||
|
@ -87,7 +89,7 @@ class SnippetForm(forms.ModelForm):
|
|||
self.cleaned_data["expire_type"] = expire_type
|
||||
return expires
|
||||
|
||||
def clean(self):
|
||||
def clean(self) -> Dict[str, Optional[Union[Type[object], None]]]:
|
||||
"""
|
||||
The `title` field is a hidden honeypot field. If its filled,
|
||||
this is likely spam.
|
||||
|
@ -96,7 +98,9 @@ class SnippetForm(forms.ModelForm):
|
|||
raise forms.ValidationError("This snippet was identified as Spam.")
|
||||
return self.cleaned_data
|
||||
|
||||
def save(self, parent=None, *args, **kwargs):
|
||||
def save(
|
||||
self, parent: Optional[Snippet] = None, *args, **kwargs
|
||||
) -> Snippet:
|
||||
# Set parent snippet
|
||||
self.instance.parent = parent
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
from io import StringIO
|
||||
from logging import getLogger
|
||||
from typing import Any, Iterator, Optional, Type
|
||||
|
||||
from django.apps import apps
|
||||
from django.template.defaultfilters import escape, linebreaksbr
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.safestring import SafeString, mark_safe
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from pygments import highlight
|
||||
from pygments.formatters.html import HtmlFormatter
|
||||
|
@ -34,7 +36,13 @@ class Highlighter(object):
|
|||
return l[1]
|
||||
return fallback
|
||||
|
||||
def render(self, code_string, lexer_name, direction=None, **kwargs):
|
||||
def render(
|
||||
self,
|
||||
code_string: str,
|
||||
lexer_name: str,
|
||||
direction: Optional[str] = None,
|
||||
**kwargs
|
||||
) -> SafeString:
|
||||
highlighted_string = self.highlight(code_string, lexer_name=lexer_name)
|
||||
context = {
|
||||
"highlighted": highlighted_string,
|
||||
|
@ -52,7 +60,7 @@ class PlainTextHighlighter(Highlighter):
|
|||
|
||||
template_name = "dpaste/highlight/text.html"
|
||||
|
||||
def highlight(self, code_string, **kwargs):
|
||||
def highlight(self, code_string: str, **kwargs) -> SafeString:
|
||||
return linebreaksbr(code_string)
|
||||
|
||||
|
||||
|
@ -99,7 +107,7 @@ class RestructuredTextHighlighter(PlainTextHighlighter):
|
|||
},
|
||||
}
|
||||
|
||||
def highlight(self, code_string, **kwargs):
|
||||
def highlight(self, code_string: str, **kwargs) -> SafeString:
|
||||
from docutils.core import publish_parts
|
||||
|
||||
self.publish_args["source"] = code_string
|
||||
|
@ -113,10 +121,10 @@ class RestructuredTextHighlighter(PlainTextHighlighter):
|
|||
class NakedHtmlFormatter(HtmlFormatter):
|
||||
"""Pygments HTML formatter with no further HTML tags."""
|
||||
|
||||
def wrap(self, source, outfile):
|
||||
def wrap(self, source: Iterator[Any], outfile: StringIO) -> Iterator[Any]:
|
||||
return self._wrap_code(source)
|
||||
|
||||
def _wrap_code(self, source):
|
||||
def _wrap_code(self, source: Iterator[Any]) -> None:
|
||||
yield from source
|
||||
|
||||
|
||||
|
@ -125,7 +133,7 @@ class PlainCodeHighlighter(Highlighter):
|
|||
Plain Code. No highlighting but Pygments like span tags around each line.
|
||||
"""
|
||||
|
||||
def highlight(self, code_string, **kwargs):
|
||||
def highlight(self, code_string: str, **kwargs) -> str:
|
||||
return "\n".join(
|
||||
[
|
||||
'<span class="plain">{}</span>'.format(escape(l) or "​")
|
||||
|
@ -144,7 +152,7 @@ class PygmentsHighlighter(Highlighter):
|
|||
lexer = None
|
||||
lexer_fallback = PythonLexer()
|
||||
|
||||
def highlight(self, code_string, lexer_name):
|
||||
def highlight(self, code_string: str, lexer_name: str) -> str:
|
||||
if not self.lexer:
|
||||
try:
|
||||
self.lexer = get_lexer_by_name(lexer_name)
|
||||
|
@ -155,18 +163,7 @@ class PygmentsHighlighter(Highlighter):
|
|||
return highlight(code_string, self.lexer, self.formatter)
|
||||
|
||||
|
||||
class SolidityHighlighter(PygmentsHighlighter):
|
||||
"""Solidity Specific Highlighter. This uses a 3rd party Pygments lexer."""
|
||||
|
||||
def __init__(self):
|
||||
# SolidityLexer does not necessarily need to be installed
|
||||
# since its imported here and not used later.
|
||||
from pygments_lexer_solidity import SolidityLexer
|
||||
|
||||
self.lexer = SolidityLexer()
|
||||
|
||||
|
||||
def get_highlighter_class(lexer_name):
|
||||
def get_highlighter_class(lexer_name: str) -> Type[Highlighter]:
|
||||
"""
|
||||
Get Highlighter for lexer name.
|
||||
|
||||
|
|
|
@ -5,31 +5,78 @@ from django.db import models, migrations
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Snippet',
|
||||
name="Snippet",
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('secret_id', models.CharField(max_length=255, unique=True, null=True, verbose_name='Secret ID', blank=True)),
|
||||
('content', models.TextField(verbose_name='Content')),
|
||||
('lexer', models.CharField(default=b'python', max_length=30, verbose_name='Lexer')),
|
||||
('published', models.DateTimeField(auto_now_add=True, verbose_name='Published')),
|
||||
('expire_type', models.PositiveSmallIntegerField(default=1, verbose_name='Expire Type', choices=[(1, 'Expire by timestamp'), (2, 'Keep Forever'), (3, 'One-Time snippet')])),
|
||||
('expires', models.DateTimeField(null=True, verbose_name='Expires', blank=True)),
|
||||
('view_count', models.PositiveIntegerField(default=0, verbose_name='View count')),
|
||||
('lft', models.PositiveIntegerField(editable=False, db_index=True)),
|
||||
('rght', models.PositiveIntegerField(editable=False, db_index=True)),
|
||||
('tree_id', models.PositiveIntegerField(editable=False, db_index=True)),
|
||||
('level', models.PositiveIntegerField(editable=False, db_index=True)),
|
||||
('parent', models.ForeignKey(related_name='children', blank=True, to='dpaste.Snippet', null=True, on_delete=models.CASCADE)),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
verbose_name="ID",
|
||||
serialize=False,
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"secret_id",
|
||||
models.CharField(
|
||||
max_length=255,
|
||||
unique=True,
|
||||
null=True,
|
||||
verbose_name="Secret ID",
|
||||
blank=True,
|
||||
),
|
||||
),
|
||||
("content", models.TextField(verbose_name="Content")),
|
||||
(
|
||||
"lexer",
|
||||
models.CharField(
|
||||
default=b"python", max_length=30, verbose_name="Lexer"
|
||||
),
|
||||
),
|
||||
(
|
||||
"published",
|
||||
models.DateTimeField(auto_now_add=True, verbose_name="Published"),
|
||||
),
|
||||
(
|
||||
"expire_type",
|
||||
models.PositiveSmallIntegerField(
|
||||
default=1,
|
||||
verbose_name="Expire Type",
|
||||
choices=[
|
||||
(1, "Expire by timestamp"),
|
||||
(2, "Keep Forever"),
|
||||
(3, "One-Time snippet"),
|
||||
],
|
||||
options={
|
||||
'ordering': ('-published',),
|
||||
'db_table': 'dpaste_snippet',
|
||||
},
|
||||
),
|
||||
),
|
||||
(
|
||||
"expires",
|
||||
models.DateTimeField(null=True, verbose_name="Expires", blank=True),
|
||||
),
|
||||
(
|
||||
"view_count",
|
||||
models.PositiveIntegerField(default=0, verbose_name="View count"),
|
||||
),
|
||||
("lft", models.PositiveIntegerField(editable=False, db_index=True)),
|
||||
("rght", models.PositiveIntegerField(editable=False, db_index=True)),
|
||||
("tree_id", models.PositiveIntegerField(editable=False, db_index=True)),
|
||||
("level", models.PositiveIntegerField(editable=False, db_index=True)),
|
||||
(
|
||||
"parent",
|
||||
models.ForeignKey(
|
||||
related_name="children",
|
||||
blank=True,
|
||||
to="dpaste.Snippet",
|
||||
null=True,
|
||||
on_delete=models.CASCADE,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={"ordering": ("-published",), "db_table": "dpaste_snippet",},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -7,24 +7,12 @@ from django.db import migrations
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dpaste', '0001_initial'),
|
||||
("dpaste", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='snippet',
|
||||
name='level',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='snippet',
|
||||
name='lft',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='snippet',
|
||||
name='rght',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='snippet',
|
||||
name='tree_id',
|
||||
),
|
||||
migrations.RemoveField(model_name="snippet", name="level",),
|
||||
migrations.RemoveField(model_name="snippet", name="lft",),
|
||||
migrations.RemoveField(model_name="snippet", name="rght",),
|
||||
migrations.RemoveField(model_name="snippet", name="tree_id",),
|
||||
]
|
||||
|
|
|
@ -7,14 +7,14 @@ from django.db import migrations, models
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dpaste', '0002_auto_20170119_1038'),
|
||||
("dpaste", "0002_auto_20170119_1038"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='snippet',
|
||||
name='highlighted',
|
||||
field=models.TextField(default='', verbose_name='Highlighted Content'),
|
||||
model_name="snippet",
|
||||
name="highlighted",
|
||||
field=models.TextField(default="", verbose_name="Highlighted Content"),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
|
|
|
@ -7,13 +7,15 @@ from django.db import migrations, models
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dpaste', '0003_snippet_highlighted'),
|
||||
("dpaste", "0003_snippet_highlighted"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='snippet',
|
||||
name='lexer',
|
||||
field=models.CharField(default='python', max_length=30, verbose_name='Lexer'),
|
||||
model_name="snippet",
|
||||
name="lexer",
|
||||
field=models.CharField(
|
||||
default="python", max_length=30, verbose_name="Lexer"
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,12 +6,9 @@ from django.db import migrations
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dpaste', '0004_auto_20180107_1603'),
|
||||
("dpaste", "0004_auto_20180107_1603"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='snippet',
|
||||
name='highlighted',
|
||||
),
|
||||
migrations.RemoveField(model_name="snippet", name="highlighted",),
|
||||
]
|
||||
|
|
|
@ -7,13 +7,20 @@ import django.db.models.deletion
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dpaste', '0005_remove_snippet_highlighted'),
|
||||
("dpaste", "0005_remove_snippet_highlighted"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='snippet',
|
||||
name='parent',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='dpaste.Snippet', verbose_name='Parent Snippet'),
|
||||
model_name="snippet",
|
||||
name="parent",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="children",
|
||||
to="dpaste.Snippet",
|
||||
verbose_name="Parent Snippet",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,13 +6,13 @@ from django.db import migrations, models
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dpaste', '0006_auto_20180622_1051'),
|
||||
("dpaste", "0006_auto_20180622_1051"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='snippet',
|
||||
name='rtl',
|
||||
field=models.BooleanField(default=False, verbose_name='Right-to-left'),
|
||||
model_name="snippet",
|
||||
name="rtl",
|
||||
field=models.BooleanField(default=False, verbose_name="Right-to-left"),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -4,6 +4,7 @@ from random import SystemRandom
|
|||
from django.apps import apps
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.safestring import SafeString
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from dpaste import highlight
|
||||
|
@ -13,7 +14,7 @@ logger = getLogger(__file__)
|
|||
R = SystemRandom()
|
||||
|
||||
|
||||
def generate_secret_id(length):
|
||||
def generate_secret_id(length: int) -> str:
|
||||
if length > config.SLUG_LENGTH:
|
||||
logger.warning(
|
||||
"Slug creation triggered a duplicate, "
|
||||
|
@ -75,18 +76,18 @@ class Snippet(models.Model):
|
|||
ordering = ("-published",)
|
||||
db_table = "dpaste_snippet"
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return self.secret_id
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
def save(self, *args, **kwargs) -> None:
|
||||
if not self.secret_id:
|
||||
self.secret_id = generate_secret_id(length=config.SLUG_LENGTH)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def get_absolute_url(self):
|
||||
def get_absolute_url(self) -> str:
|
||||
return reverse("snippet_details", kwargs={"snippet_id": self.secret_id})
|
||||
|
||||
def highlight(self):
|
||||
def highlight(self) -> SafeString:
|
||||
HighlighterClass = highlight.get_highlighter_class(self.lexer)
|
||||
return HighlighterClass().render(
|
||||
code_string=self.content,
|
||||
|
@ -95,12 +96,12 @@ class Snippet(models.Model):
|
|||
)
|
||||
|
||||
@property
|
||||
def lexer_name(self):
|
||||
def lexer_name(self) -> str:
|
||||
"""Display name for this lexer."""
|
||||
return highlight.Highlighter.get_lexer_display_name(self.lexer)
|
||||
|
||||
@property
|
||||
def remaining_views(self):
|
||||
def remaining_views(self) -> int:
|
||||
if self.expire_type == self.EXPIRE_ONETIME:
|
||||
remaining = config.ONETIME_LIMIT - self.view_count
|
||||
return remaining > 0 and remaining or 0
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import datetime
|
||||
import difflib
|
||||
import json
|
||||
from typing import Any, Dict, Optional, Union
|
||||
|
||||
from django.apps import apps
|
||||
from django.core.handlers.wsgi import WSGIRequest
|
||||
from django.db.models.query import QuerySet
|
||||
from django.http import (
|
||||
Http404,
|
||||
HttpResponse,
|
||||
|
@ -11,9 +14,11 @@ from django.http import (
|
|||
HttpResponseRedirect,
|
||||
)
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
from django.template.response import TemplateResponse
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.cache import add_never_cache_headers, patch_cache_control
|
||||
from django.utils.datastructures import MultiValueDict
|
||||
from django.utils.http import http_date
|
||||
from django.utils.translation import ugettext
|
||||
from django.views.generic import FormView
|
||||
|
@ -23,6 +28,7 @@ from pygments.lexers import get_lexer_for_filename
|
|||
from pygments.util import ClassNotFound
|
||||
|
||||
from dpaste import highlight
|
||||
from dpaste.apps import dpasteAppConfig
|
||||
from dpaste.forms import SnippetForm, get_expire_values
|
||||
from dpaste.highlight import PygmentsHighlighter
|
||||
from dpaste.models import Snippet
|
||||
|
@ -43,22 +49,26 @@ class SnippetView(FormView):
|
|||
form_class = SnippetForm
|
||||
template_name = "dpaste/new.html"
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
def get(self, request: WSGIRequest, *args, **kwargs) -> TemplateResponse:
|
||||
response = super().get(request, *args, **kwargs)
|
||||
if config.CACHE_HEADER:
|
||||
patch_cache_control(response, max_age=config.CACHE_TIMEOUT)
|
||||
return response
|
||||
|
||||
def get_form_kwargs(self):
|
||||
def get_form_kwargs(
|
||||
self,
|
||||
) -> Dict[str, Optional[Union[MultiValueDict, WSGIRequest]]]:
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs.update({"request": self.request})
|
||||
return kwargs
|
||||
|
||||
def form_valid(self, form):
|
||||
def form_valid(self, form: SnippetForm) -> HttpResponseRedirect:
|
||||
snippet = form.save()
|
||||
return HttpResponseRedirect(snippet.get_absolute_url())
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
def get_context_data(
|
||||
self, **kwargs
|
||||
) -> Dict[str, Union[SnippetForm, "SnippetView", str]]:
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx.update(config.extra_template_context)
|
||||
return ctx
|
||||
|
@ -76,7 +86,9 @@ class SnippetDetailView(DetailView, FormView):
|
|||
slug_url_kwarg = "snippet_id"
|
||||
slug_field = "secret_id"
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
def post(
|
||||
self, request: WSGIRequest, *args, **kwargs
|
||||
) -> Union[HttpResponseRedirect, TemplateResponse]:
|
||||
"""
|
||||
Delete a snippet. This is allowed by anybody as long as he knows the
|
||||
snippet id. I got too many manual requests to do this, mostly for legal
|
||||
|
@ -95,7 +107,7 @@ class SnippetDetailView(DetailView, FormView):
|
|||
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
def get(self, request: WSGIRequest, *args, **kwargs) -> HttpResponse:
|
||||
snippet = self.get_object()
|
||||
|
||||
# One-Time snippet get deleted if the view count matches our limit
|
||||
|
@ -126,7 +138,7 @@ class SnippetDetailView(DetailView, FormView):
|
|||
|
||||
return response
|
||||
|
||||
def get_initial(self):
|
||||
def get_initial(self) -> Dict[str, Union[str, bool]]:
|
||||
snippet = self.get_object()
|
||||
return {
|
||||
"content": snippet.content,
|
||||
|
@ -134,16 +146,23 @@ class SnippetDetailView(DetailView, FormView):
|
|||
"rtl": snippet.rtl,
|
||||
}
|
||||
|
||||
def get_form_kwargs(self):
|
||||
def get_form_kwargs(
|
||||
self,
|
||||
) -> Dict[
|
||||
str,
|
||||
Optional[
|
||||
Union[Dict[str, Union[str, bool]], MultiValueDict, WSGIRequest]
|
||||
],
|
||||
]:
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs.update({"request": self.request})
|
||||
return kwargs
|
||||
|
||||
def form_valid(self, form):
|
||||
def form_valid(self, form: SnippetForm) -> HttpResponseRedirect:
|
||||
snippet = form.save(parent=self.get_object())
|
||||
return HttpResponseRedirect(snippet.get_absolute_url())
|
||||
|
||||
def get_snippet_diff(self):
|
||||
def get_snippet_diff(self) -> None:
|
||||
snippet = self.get_object()
|
||||
|
||||
if not snippet.parent_id:
|
||||
|
@ -165,7 +184,7 @@ class SnippetDetailView(DetailView, FormView):
|
|||
# Remove blank lines
|
||||
return highlighted
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
def get_context_data(self, **kwargs) -> Dict[str, Any]:
|
||||
self.object = self.get_object()
|
||||
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
|
@ -187,26 +206,30 @@ class SnippetRawView(SnippetDetailView):
|
|||
|
||||
template_name = "dpaste/raw.html"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
def dispatch(self, request: WSGIRequest, *args, **kwargs) -> HttpResponse:
|
||||
if not config.RAW_MODE_ENABLED:
|
||||
return HttpResponseForbidden(
|
||||
ugettext("This dpaste installation has Raw view mode disabled.")
|
||||
)
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def render_plain_text(self, context, **response_kwargs):
|
||||
def render_plain_text(
|
||||
self, context: dpasteAppConfig, **response_kwargs
|
||||
) -> HttpResponse:
|
||||
snippet = self.get_object()
|
||||
response = HttpResponse(snippet.content)
|
||||
response["Content-Type"] = "text/plain;charset=UTF-8"
|
||||
response["X-Content-Type-Options"] = "nosniff"
|
||||
return response
|
||||
|
||||
def render_to_response(self, context, **response_kwargs):
|
||||
def render_to_response(
|
||||
self, context: Dict[str, Any], **response_kwargs
|
||||
) -> HttpResponse:
|
||||
if config.RAW_MODE_PLAIN_TEXT:
|
||||
return self.render_plain_text(config, **response_kwargs)
|
||||
return super().render_to_response(context, **response_kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
def get_context_data(self, **kwargs) -> Dict[str, Any]:
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx.update(config.extra_template_context)
|
||||
return ctx
|
||||
|
@ -220,16 +243,18 @@ class SnippetHistory(TemplateView):
|
|||
|
||||
template_name = "dpaste/history.html"
|
||||
|
||||
def get_user_snippets(self):
|
||||
def get_user_snippets(self) -> QuerySet:
|
||||
snippet_id_list = self.request.session.get("snippet_list", [])
|
||||
return Snippet.objects.filter(pk__in=snippet_id_list)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
def get(self, request: WSGIRequest, *args, **kwargs) -> TemplateResponse:
|
||||
response = super().get(request, *args, **kwargs)
|
||||
add_never_cache_headers(response)
|
||||
return response
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
def post(
|
||||
self, request: WSGIRequest, *args, **kwargs
|
||||
) -> HttpResponseRedirect:
|
||||
"""
|
||||
Delete all user snippets at once.
|
||||
"""
|
||||
|
@ -240,7 +265,9 @@ class SnippetHistory(TemplateView):
|
|||
url = "{0}#".format(reverse("snippet_history"))
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
def get_context_data(
|
||||
self, **kwargs
|
||||
) -> Dict[str, Union["SnippetHistory", QuerySet, str]]:
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx.update({"snippet_list": self.get_user_snippets()})
|
||||
ctx.update(config.extra_template_context)
|
||||
|
@ -257,14 +284,14 @@ class APIView(View):
|
|||
API View
|
||||
"""
|
||||
|
||||
def _format_default(self, s):
|
||||
def _format_default(self, s: Snippet) -> str:
|
||||
"""
|
||||
The default response is the snippet URL wrapped in quotes.
|
||||
"""
|
||||
base_url = config.get_base_url(request=self.request)
|
||||
return f'"{base_url}{s.get_absolute_url()}"'
|
||||
|
||||
def _format_url(self, s):
|
||||
def _format_url(self, s: Snippet) -> str:
|
||||
"""
|
||||
The `url` format returns the snippet URL,
|
||||
no quotes, but a linebreak at the end.
|
||||
|
@ -272,7 +299,7 @@ class APIView(View):
|
|||
base_url = config.get_base_url(request=self.request)
|
||||
return f"{base_url}{s.get_absolute_url()}\n"
|
||||
|
||||
def _format_json(self, s):
|
||||
def _format_json(self, s: Snippet) -> str:
|
||||
"""
|
||||
The `json` format export.
|
||||
"""
|
||||
|
@ -285,7 +312,7 @@ class APIView(View):
|
|||
}
|
||||
)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
def post(self, request: WSGIRequest, *args, **kwargs) -> HttpResponse:
|
||||
content = request.POST.get("content", "")
|
||||
lexer = request.POST.get("lexer", highlight.LEXER_DEFAULT).strip()
|
||||
filename = request.POST.get("filename", "").strip()
|
||||
|
@ -357,7 +384,11 @@ class APIView(View):
|
|||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
def page_not_found(request, exception=None, template_name="dpaste/404.html"):
|
||||
def page_not_found(
|
||||
request: WSGIRequest,
|
||||
exception: Optional[Http404] = None,
|
||||
template_name: str = "dpaste/404.html",
|
||||
) -> HttpResponse:
|
||||
context = {}
|
||||
context.update(config.extra_template_context)
|
||||
response = render(request, template_name, context, status=404)
|
||||
|
|
Loading…
Reference in a new issue