• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

chiefonboarding / ChiefOnboarding / 18481185920

13 Oct 2025 11:53PM UTC coverage: 89.613% (-0.006%) from 89.619%
18481185920

Pull #572

github

web-flow
Merge f5b8970dc into f01e5ecbf
Pull Request #572: Add permissions based on department

7057 of 7875 relevant lines covered (89.61%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.97
back/admin/integrations/forms.py
1
import json
1✔
2

3
from crispy_forms.helper import FormHelper
1✔
4
from crispy_forms.layout import HTML, Div, Field, Layout
1✔
5
from django import forms
1✔
6
from django.contrib.auth import get_user_model
1✔
7
from django.core.exceptions import ValidationError
1✔
8
from django.utils.safestring import mark_safe
1✔
9
from django.utils.translation import gettext_lazy as _
1✔
10

11
from admin.integrations.models import Integration
1✔
12
from admin.integrations.utils import get_value_from_notation
1✔
13
from admin.sequences.models import IntegrationConfig
1✔
14
from misc.mixins import FilterDepartmentsFieldByUserMixin
1✔
15

16

17
class IntegrationConfigForm(forms.ModelForm):
1✔
18
    def _expected_example(self, form_item):
1✔
19
        def _add_items(form_item):
1✔
20
            items = []
1✔
21
            # Add two example items
22
            for item in range(2):
1✔
23
                items.append(
1✔
24
                    {
25
                        form_item.get("choice_value", "id"): item,
26
                        form_item.get("choice_name", "name"): f"name {item}",
27
                    }
28
                )
29
            return items
1✔
30

31
        inner = form_item.get("data_from", "")
1✔
32
        if inner == "":
1✔
33
            return _add_items(form_item)
1✔
34

35
        # This is pretty ugly, but we are building a json string first
36
        # and then convert it to a real json object to avoid nested loops
37
        notations = inner.split(".")
1✔
38
        stringified_json = "{"
1✔
39
        for idx, notation in enumerate(notations):
1✔
40
            stringified_json += f'"{notation}":'
1✔
41
            if idx + 1 == len(notations):
1✔
42
                stringified_json += json.dumps(_add_items(form_item))
1✔
43
                stringified_json += "}" * len(notations)
1✔
44
            else:
45
                stringified_json += "{"
1✔
46

47
        return json.loads(stringified_json)
1✔
48

49
    def __init__(self, *args, **kwargs):
1✔
50
        super().__init__(*args, **kwargs)
1✔
51
        integration = self.instance
1✔
52
        form = self.instance.manifest.get("form", [])
1✔
53
        self.helper = FormHelper()
1✔
54
        self.helper.form_tag = False
1✔
55
        self.error = None
1✔
56
        for item in form:
1✔
57
            if item["type"] == "input":
1✔
58
                self.fields[item["id"]] = forms.CharField(
1✔
59
                    label=item["name"],
60
                    required=False,
61
                )
62

63
            if item["type"] in ["choice", "multiple_choice"]:
1✔
64
                # If there is a url to fetch the items from then do so
65
                if item.get("url", "") != "":
1✔
66
                    success, response = integration.run_request(item)
1✔
67
                    if not success:
1✔
68
                        self.error = response
×
69
                        return
×
70

71
                    option_data = response.json()
1✔
72
                else:
73
                    # No url, so get the static items
74
                    option_data = item["items"]
1✔
75

76
                # Can we select one or multiple?
77
                if item["type"] == "choice":
1✔
78
                    field = forms.ChoiceField
1✔
79
                else:
80
                    field = forms.MultipleChoiceField
×
81

82
                try:
1✔
83
                    self.fields[item["id"]] = field(
1✔
84
                        label=item["name"],
85
                        widget=(
86
                            forms.CheckboxSelectMultiple
87
                            if item["type"] == "multiple_choice"
88
                            else forms.Select
89
                        ),
90
                        choices=[
91
                            (
92
                                get_value_from_notation(
93
                                    item.get("choice_value", "id"), x
94
                                ),
95
                                get_value_from_notation(
96
                                    item.get("choice_name", "name"), x
97
                                ),
98
                            )
99
                            for x in get_value_from_notation(
100
                                item.get("data_from", ""), option_data
101
                            )
102
                        ],
103
                        required=False,
104
                    )
105
                except Exception:
1✔
106
                    expected = self._expected_example(item)
1✔
107

108
                    self.error = mark_safe(
1✔
109
                        f"Form item ({item['name']}) could not be rendered. Format "
110
                        "was different than expected.<br><h2>Expected format:"
111
                        f"</h2><pre>{json.dumps(expected, indent=4)}</pre><br><h2>"
112
                        "Got from server:</h2><pre>"
113
                        f"{json.dumps(option_data, indent=4)}</pre>"
114
                    )
115
                    break
1✔
116

117
    class Meta:
1✔
118
        model = Integration
1✔
119
        fields = ()
1✔
120

121

122
class ManualIntegrationConfigForm(forms.ModelForm):
1✔
123
    def __init__(self, *args, **kwargs):
1✔
124
        super().__init__(*args, **kwargs)
1✔
125
        self.helper = FormHelper()
1✔
126
        self.helper.form_tag = False
1✔
127

128
        hide_assigned_to = "d-none"
1✔
129
        if (
1✔
130
            self.instance is not None
131
            and self.instance.person_type == IntegrationConfig.PersonType.CUSTOM
132
        ):
133
            hide_assigned_to = ""
×
134

135
        self.helper.layout = Layout(
1✔
136
            HTML(
137
                "<p>"
138
                + _(
139
                    "This is a manual integration, you will have to assign someone "
140
                    "to create/remove it for this person."
141
                )
142
                + "</p>"
143
            ),
144
            Div(
145
                Field("name"),
146
                Field("person_type"),
147
                Div(
148
                    Field("assigned_to"),
149
                    css_class=hide_assigned_to,
150
                ),
151
            ),
152
        )
153

154
    class Meta:
1✔
155
        model = IntegrationConfig
1✔
156
        fields = ("person_type", "assigned_to")
1✔
157

158
    def clean(self):
1✔
159
        cleaned_data = super().clean()
1✔
160
        person_type = cleaned_data.get("person_type", None)
1✔
161
        assigned_to = cleaned_data.get("assigned_to", None)
1✔
162
        if person_type == IntegrationConfig.PersonType.CUSTOM and assigned_to is None:
1✔
163
            raise ValidationError(
1✔
164
                _("You must select someone if you want someone custom")
165
            )
166
        return cleaned_data
1✔
167

168

169
# Credits: https://stackoverflow.com/a/72256767
170
# Removed the sort options
171
class PrettyJSONEncoder(json.JSONEncoder):
1✔
172
    def __init__(self, *args, indent, **kwargs):
1✔
173
        super().__init__(*args, indent=4, **kwargs)
1✔
174

175

176
class IntegrationForm(FilterDepartmentsFieldByUserMixin, forms.ModelForm):
1✔
177
    """Form used to register a new integration through the settings"""
178

179
    manifest = forms.JSONField(encoder=PrettyJSONEncoder, required=False, initial=dict)
1✔
180

181
    class Meta:
1✔
182
        model = Integration
1✔
183
        fields = ("name", "manifest_type", "departments", "manifest")
1✔
184

185
    def __init__(self, *args, **kwargs):
1✔
186
        super().__init__(*args, **kwargs)
1✔
187
        self.fields["manifest_type"].required = True
1✔
188

189
        # make manifest not required when manual user provisioning
190
        if (
1✔
191
            self.data.get("manifest_type", "")
192
            != str(Integration.ManifestType.MANUAL_USER_PROVISIONING)
193
            and self.instance.manifest_type
194
            != Integration.ManifestType.MANUAL_USER_PROVISIONING
195
        ):
196
            self.fields["manifest"].required = True
1✔
197

198
        if self.instance.id:
1✔
199
            # disable manifest_type when updating record
200
            self.fields["manifest_type"].disabled = True
1✔
201

202

203
class IntegrationExtraArgsForm(forms.ModelForm):
1✔
204
    def __init__(self, *args, **kwargs):
1✔
205
        super().__init__(*args, **kwargs)
1✔
206
        initial_data = self.instance.extra_args
1✔
207
        filled_secret_values = self.instance.filled_secret_values
1✔
208
        for item in self.instance.manifest["initial_data_form"]:
1✔
209
            # secret data has been saved, so don't show it again
210
            if item in filled_secret_values:
1✔
211
                continue
1✔
212

213
            self.fields[item["id"]] = forms.CharField(
1✔
214
                label=item["name"], help_text=item["description"]
215
            )
216
            # Check if item was already saved - load data back in form
217
            if item["id"] in initial_data:
1✔
218
                self.fields[item["id"]].initial = initial_data[item["id"]]
1✔
219
            # If field is secret field, then hide it - values are generated on the fly
220
            if "name" in item and item["name"] == "generate":
1✔
221
                self.fields[item["id"]].required = False
1✔
222
                self.fields[item["id"]].widget = forms.HiddenInput()
1✔
223

224
    def save(self):
1✔
225
        integration = self.instance
1✔
226
        integration.extra_args.update(self.cleaned_data)
1✔
227
        integration.save()
1✔
228
        return integration
1✔
229

230
    class Meta:
1✔
231
        model = Integration
1✔
232
        fields = ()
1✔
233

234

235
class IntegrationExtraUserInfoForm(forms.ModelForm):
1✔
236
    def __init__(self, missing_info=None, *args, **kwargs):
1✔
237
        super().__init__(*args, **kwargs)
1✔
238
        if missing_info is None:
1✔
239
            missing_info = self.instance.missing_extra_info
1✔
240

241
        for item in missing_info:
1✔
242
            self.fields[item["id"]] = forms.CharField(
1✔
243
                label=item["name"], help_text=item["description"]
244
            )
245

246
    def save(self):
1✔
247
        user = self.instance
1✔
248
        user.extra_fields |= self.cleaned_data
1✔
249
        user.save()
1✔
250
        return user
1✔
251

252
    class Meta:
1✔
253
        model = get_user_model()
1✔
254
        fields = ()
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc