Source code for core.forms

__package__ = 'archivebox.core'

from django import forms

from ..util import URL_REGEX
from ..parsers import PARSERS
from ..vendor.taggit_utils import edit_string_for_tags, parse_tags

PARSER_CHOICES = [
    (parser_key, parser[0])
    for parser_key, parser in PARSERS.items()
]
DEPTH_CHOICES = (
    ('0', 'depth = 0 (archive just these URLs)'),
    ('1', 'depth = 1 (archive these URLs and all URLs one hop away)'),
)

from ..extractors import get_default_archive_methods

ARCHIVE_METHODS = [
    (name, name)
    for name, _, _ in get_default_archive_methods()
]


class AddLinkForm(forms.Form):
    url = forms.RegexField(label="URLs (one per line)", regex=URL_REGEX, min_length='6', strip=True, widget=forms.Textarea, required=True)
    parser = forms.ChoiceField(label="URLs format", choices=[('auto', 'Auto-detect parser'), *PARSER_CHOICES], initial='auto')
    tag = forms.CharField(label="Tags (comma separated tag1,tag2,tag3)", strip=True, required=False)
    depth = forms.ChoiceField(label="Archive depth", choices=DEPTH_CHOICES, initial='0', widget=forms.RadioSelect(attrs={"class": "depth-selection"}))
    archive_methods = forms.MultipleChoiceField(
        label="Archive methods (select at least 1, otherwise all will be used by default)",
        required=False,
        widget=forms.SelectMultiple,
        choices=ARCHIVE_METHODS,
    )
    # TODO: hook these up to the view and put them 
    # in a collapsible UI section labeled "Advanced"
    #
    # exclude_patterns = forms.CharField(
    #     label="Exclude patterns",
    #     min_length='1',
    #     required=False,
    #     initial=URL_BLACKLIST,
    # )
    # timeout = forms.IntegerField(
    #     initial=TIMEOUT,
    # )
    # overwrite = forms.BooleanField(
    #     label="Overwrite any existing Snapshots",
    #     initial=False,
    # )
    # index_only = forms.BooleanField(
    #     label="Add URLs to index without Snapshotting",
    #     initial=False,
    # )

class TagWidgetMixin:
    def format_value(self, value):
        if value is not None and not isinstance(value, str):
            value = edit_string_for_tags(value)
        return super().format_value(value)

class TagWidget(TagWidgetMixin, forms.TextInput):
    pass

class TagField(forms.CharField):
    widget = TagWidget

    def clean(self, value):
        value = super().clean(value)
        try:
            return parse_tags(value)
        except ValueError:
            raise forms.ValidationError(
                "Please provide a comma-separated list of tags."
            )

    def has_changed(self, initial_value, data_value):
        # Always return False if the field is disabled since self.bound_data
        # always uses the initial value in this case.
        if self.disabled:
            return False

        try:
            data_value = self.clean(data_value)
        except forms.ValidationError:
            pass

        if initial_value is None:
            initial_value = []

        initial_value = [tag.name for tag in initial_value]
        initial_value.sort()

        return initial_value != data_value