Release v1.0.0
Some checks failed
CI / Checks (push) Failing after 13m2s

This commit is contained in:
2025-08-20 21:00:50 +02:00
commit b4338e2769
401 changed files with 23576 additions and 0 deletions

View File

@@ -0,0 +1,215 @@
# -*- coding: utf-8 -*-
from __future__ import annotations
from crispy_forms.bootstrap import FormActions
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit
from django import forms
from django.contrib.auth.forms import (
AuthenticationForm as BaseAuthenticationForm,
PasswordChangeForm as BasePasswordChangeForm,
)
from django.utils.translation import gettext_lazy as _
from .base import Form
class LoginForm(BaseAuthenticationForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.attrs = {
'id': self.__class__.__name__,
'novalidate': '',
}
self.helper.layout = Layout(
'username',
'password',
FormActions(
Submit('submit', _('Log in'), css_class='btn btn-primary'),
template='ui/ui/forms/formactions.html',
css_class='mb-0',
),
)
class ProfileForm(Form):
INCLUDE_CANCEL = False
username = forms.CharField(
label=_('Username'),
disabled=True,
required=False,
)
first_name = forms.CharField(
label=_('First name'),
max_length=150,
required=True,
)
last_name = forms.CharField(
label=_('Last name'),
max_length=150,
required=True,
)
email = forms.EmailField(
label=_('E-mail address'),
required=True,
)
def get_layout_fields(self) -> list[str]:
return [
'username',
'first_name',
'last_name',
'email',
]
class FederatedProfileForm(ProfileForm):
username = forms.CharField(
label=_('Username'),
disabled=True,
required=False,
)
first_name = forms.CharField(
label=_('First name'),
disabled=True,
required=False,
)
last_name = forms.CharField(
label=_('Last name'),
disabled=True,
required=False,
)
email = forms.EmailField(
label=_('E-mail address'),
disabled=True,
required=False,
)
def get_submit_button(self) -> Submit:
return Submit(
'submit',
_('Save'),
css_class='btn btn-primary',
disabled=True,
)
def clean(self) -> dict:
return {}
class PasswordForm(BasePasswordChangeForm):
def get_submit_button(self) -> Submit:
return Submit(
'submit',
_('Save'),
css_class='btn btn-primary',
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-md-3 col-form-label'
self.helper.field_class = 'col-md-9'
self.helper.attrs = {
'id': self.__class__.__name__,
'novalidate': '',
}
self.helper.layout = Layout(
'old_password',
'new_password1',
'new_password2',
FormActions(
self.get_submit_button(),
template='ui/ui/forms/formactions-horizontal.html',
),
)
class FederatedPasswordForm(PasswordForm):
current_password = forms.CharField(
label=_('Old password'),
disabled=True,
required=False,
)
new_password = forms.CharField(
label=_('New password'),
disabled=True,
required=False,
)
new_password_again = forms.CharField(
label=_('New password confirmation'),
disabled=True,
required=False,
)
def get_submit_button(self) -> Submit:
return Submit(
'submit',
_('Save'),
css_class='btn btn-primary disable',
disabled=True,
)
def clean(self) -> dict:
return {}
class SettingsForm(Form):
INCLUDE_CANCEL = False
theme = forms.ChoiceField(
label=_('Theme'),
disabled=True,
required=False,
choices=[
(None, _('Bootstrap')),
('cosmo', _('Cosmo')),
],
show_hidden_initial=True,
)
auto_load_embeds = forms.ChoiceField(
label=_('Auto load embedded content'),
required=False,
choices=[
(None, _('---')),
(True, _('Yes')),
(False, _('No')),
],
help_text=_((
'Auto loading embedded content (e.g. YouTube videos) means that '
'you allow cookies from these sites.'
)),
)
def get_layout_fields(self) -> list[str]:
return [
'theme',
'auto_load_embeds',
]
def get_submit_button(self) -> Submit:
return Submit(
'submit',
_('Save'),
css_class='btn btn-primary',
)
def clean(self) -> dict:
result = super().clean()
theme = result.get('theme', None)
if not theme:
result['theme'] = None
auto_load_embeds = result.get('auto_load_embeds', None)
if not auto_load_embeds:
result['auto_load_embeds'] = None
else:
result['auto_load_embeds'] = (auto_load_embeds == 'True')
return result

View File

@@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
from __future__ import annotations
from crispy_forms.layout import Submit
from django import forms
from django.utils.translation import gettext_lazy as _
from .base import Form
class AssociationForm(Form):
pass
class ConfirmationForm(AssociationForm):
canhazconfirm = forms.CharField(
label='',
required=True,
widget=forms.HiddenInput,
)
title = forms.CharField(
label=_('Title'),
required=False,
disabled=True,
show_hidden_initial=True,
)
url = forms.CharField(
label=_('URL'),
required=False,
disabled=True,
show_hidden_initial=True,
)
def get_layout_fields(self) -> list[str]:
return [
'canhazconfirm',
'title',
'url',
]
def get_submit_button(self) -> Submit:
return Submit('submit', _('Confirm'), css_class='btn btn-primary')
class EditForm(AssociationForm):
url = forms.CharField(
label=_('URL'),
required=False,
disabled=True,
show_hidden_initial=True,
)
target_title = forms.CharField(
label=_('Title'),
required=False,
)
target_description = forms.CharField(
label=_('Description'),
required=False,
widget=forms.Textarea,
)
def get_layout_fields(self) -> list[str]:
return [
'url',
'target_title',
'target_description',
]
def clean(self):
cleaned_data = super().clean()
result = {}
if cleaned_data['target_title']:
result['target_title'] = cleaned_data['target_title']
if cleaned_data['target_description']:
result['target_description'] = cleaned_data['target_description']
return result
class RefreshForm(ConfirmationForm):
def get_submit_button(self) -> Submit:
return Submit('submit', _('Refresh'), css_class='btn btn-warning')
class ArchiveForm(ConfirmationForm):
def get_submit_button(self) -> Submit:
return Submit('submit', _('Archive'), css_class='btn btn-danger')
class DeleteForm(ConfirmationForm):
def get_submit_button(self) -> Submit:
return Submit('submit', _('Delete'), css_class='btn btn-danger')

View File

@@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
from __future__ import annotations
import typing
from crispy_forms.bootstrap import FormActions
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Submit
from django import forms
from django.utils.translation import gettext_lazy as _
from .layout import CancelButton
class Form(forms.Form):
HORIZONTAL = True
INCLUDE_CANCEL = True
def get_layout_fields(self) -> list[str]:
return []
def get_submit_button(self) -> Submit:
return Submit('submit', _('Save'), css_class='btn btn-primary')
def get_extra_actions(self) -> typing.Any:
result = []
if self.INCLUDE_CANCEL is True:
result.append(CancelButton(_('Cancel')))
return result
def get_form_actions_template(self) -> str:
if self.HORIZONTAL is True:
return 'ui/ui/forms/formactions-horizontal.html'
return 'ui/ui/forms/formactions.html'
def get_form_helper_form_class(self) -> str:
if self.HORIZONTAL is True:
return 'form-horizontal'
return ''
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_class = self.get_form_helper_form_class()
self.helper.label_class = 'col-md-3 col-form-label'
self.helper.field_class = 'col-md-9'
self.helper.attrs = {
'id': self.__class__.__name__,
'novalidate': '',
}
self.helper.layout = Layout(
*self.get_layout_fields(),
FormActions(
self.get_submit_button(),
*self.get_extra_actions(),
template=self.get_form_actions_template(),
),
)

View File

@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import annotations
from crispy_forms.layout import Submit
from django import forms
from django.utils.translation import gettext_lazy as _
from .base import Form
class PocketImportForm(Form):
csv = forms.FileField(
label=_('Export CSV'),
required=True,
)
def get_layout_fields(self) -> list[str]:
return ['csv']
def get_submit_button(self) -> Submit:
return Submit('submit', _('Import'), css_class='btn btn-primary')

View File

@@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
from __future__ import annotations
from crispy_forms.utils import TEMPLATE_PACK
from django.template.loader import render_to_string
class CancelButton:
CSS_CLASS = 'btn btn-secondary ui-form-cancel-button'
def __init__(self,
label: str,
*,
css_id: str | None = None,
css_class: str | None = None,
**attributes,
):
self.label = label
self.css_id = css_id
self.css_class = css_class
self.attributes = attributes
def render(self, form, context, template_pack: TEMPLATE_PACK, **kwargs):
final_attributes = {
'class': self.css_class or self.CSS_CLASS,
**self.attributes,
'type': 'button',
'value': self.label,
}
if self.css_id:
final_attributes['id'] = self.css_id
context = {
'attributes': final_attributes,
}
return render_to_string(
'ui/ui/forms/cancel_button.html',
context=context,
)

View File

@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import annotations
from django import forms
from django.core import validators
from django.utils.translation import gettext_lazy as _
from .base import Form
class CreateForm(Form):
url = forms.CharField(
label=_('URL'),
required=True,
validators=[
validators.URLValidator(schemes=['http', 'https']),
],
)
def get_layout_fields(self) -> list[str]:
return ['url']