File: forms.py

package info (click to toggle)
freedombox 26.2
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 82,976 kB
  • sloc: python: 48,504; javascript: 1,736; xml: 481; makefile: 290; sh: 167; php: 32
file content (156 lines) | stat: -rw-r--r-- 4,971 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# SPDX-License-Identifier: AGPL-3.0-or-later
"""
Django form for configuring Gitweb.
"""

import re
from urllib.parse import urlparse

from django import forms
from django.core.exceptions import ValidationError
from django.core.validators import URLValidator
from django.utils.translation import gettext_lazy as _

from plinth.modules import gitweb

from . import privileged


def _get_branches(repo):
    """Get all the branches in the repository."""
    branch_data = privileged.get_branches(repo)
    default_branch = branch_data['default_branch']
    branches = branch_data['branches']

    if default_branch not in branches:
        branches.insert(0, default_branch)

    return [(branch, branch) for branch in branches]


def get_name_from_url(url):
    """Get a repository name from URL"""
    return urlparse(url).path.split('/')[-1]


def is_repo_url(url):
    """Check if URL is valid."""
    try:
        RepositoryValidator(input_should_be='url')(url)
    except ValidationError:
        return False

    return True


class RepositoryValidator:
    input_should_be = 'name'

    def __init__(self, input_should_be=None):
        if input_should_be is not None:
            self.input_should_be = input_should_be

    def __call__(self, value):
        """Validate that the input is a correct repository name or URL"""
        if self.input_should_be in ('url', 'url_or_name'):
            try:
                URLValidator(schemes=['http', 'https'],
                             message=_('Invalid repository URL.'))(value)
            except ValidationError:
                if self.input_should_be == 'url':
                    raise
            else:
                value = get_name_from_url(value)

        if (not re.match(r'^[a-zA-Z0-9-._]+$', value)) \
                or value.startswith(('-', '.')) \
                or value.endswith('.git.git'):
            raise ValidationError(_('Invalid repository name.'), 'invalid')


class CreateRepoForm(forms.Form):
    """Form to create and edit a new repository."""

    name = forms.CharField(
        label=_(
            'Name of a new repository or URL to import an existing repository.'
        ), strip=True,
        validators=[RepositoryValidator(input_should_be='url_or_name')],
        widget=forms.TextInput(attrs={'autocomplete': 'off'}))

    description = forms.CharField(
        label=_('Description of the repository'), strip=True, required=False,
        help_text=_('Optional, for displaying on Gitweb.'))

    owner = forms.CharField(label=_('Repository\'s owner name'), strip=True,
                            required=False,
                            help_text=_('Optional, for displaying on Gitweb.'))

    is_private = forms.BooleanField(
        label=_('Private repository'), required=False,
        help_text=_('Allow only authorized users to access this repository.'))

    def __init__(self, *args, **kwargs):
        """Initialize the form with extra request argument."""
        super().__init__(*args, **kwargs)
        self.fields['name'].widget.attrs.update({'autofocus': 'autofocus'})

    def clean_name(self):
        """Check if the name is valid."""
        name = self.cleaned_data['name']

        repo_name = name
        if is_repo_url(name):
            repo_name = get_name_from_url(name)

        if repo_name.endswith('.git'):
            repo_name = repo_name[:-4]

        for repo in gitweb.get_repo_list():
            if repo_name == repo['name']:
                raise ValidationError(
                    _('A repository with this name already exists.'))

        if is_repo_url(name):
            if not privileged.repo_exists(name):
                raise ValidationError('Remote repository is not available.')

        return name


class EditRepoForm(CreateRepoForm):
    """Form to create and edit a new repository."""

    name = forms.CharField(
        label=_('Name of the repository'),
        strip=True,
        validators=[RepositoryValidator()],
        help_text=_(
            'An alpha-numeric string that uniquely identifies a repository.'),
    )

    default_branch = forms.ChoiceField(
        label=_('Default branch'),
        help_text=_('Gitweb displays this as a default branch.'))

    def __init__(self, *args, **kwargs):
        """Initialize the form with extra request argument."""
        super().__init__(*args, **kwargs)
        branches = _get_branches(self.initial['name'])
        self.fields['default_branch'].choices = branches

    def clean_name(self):
        """Check if the name is valid."""
        name = self.cleaned_data['name']
        if 'name' in self.initial and name == self.initial['name']:
            return name

        if name.endswith('.git'):
            name = name[:-4]

        for repo in gitweb.get_repo_list():
            if name == repo['name']:
                raise ValidationError(
                    _('A repository with this name already exists.'))

        return name