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

chiefonboarding / ChiefOnboarding / 17803136893

17 Sep 2025 03:44PM UTC coverage: 89.612% (-0.1%) from 89.707%
17803136893

Pull #387

github

web-flow
Merge 561bda08c into 390599d86
Pull Request #387: Implement allauth

6772 of 7557 relevant lines covered (89.61%)

0.9 hits per line

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

39.67
back/admin/integrations/builder_views.py
1
import json
1✔
2

3
from django.contrib.auth import get_user_model
1✔
4
from django.contrib.messages.views import SuccessMessageMixin
1✔
5
from django.http import Http404, HttpResponse, HttpResponseRedirect
1✔
6
from django.shortcuts import get_object_or_404, render
1✔
7
from django.urls import reverse, reverse_lazy
1✔
8
from django.utils.translation import gettext as _
1✔
9
from django.views.generic import View
1✔
10
from django.views.generic.detail import DetailView, SingleObjectMixin
1✔
11
from django.views.generic.edit import CreateView, FormView, UpdateView
1✔
12

13
from admin.integrations.exceptions import (
1✔
14
    DataIsNotJSONError,
15
    FailedPaginatedResponseError,
16
    KeyIsNotInDataError,
17
)
18
from admin.integrations.models import Integration, IntegrationTracker
1✔
19
from admin.integrations.sync_userinfo import SyncUsers
1✔
20
from users.mixins import AdminPermMixin
1✔
21
from users.models import User
1✔
22

23
from .builder_forms import (
1✔
24
    ManifestExecuteForm,
25
    ManifestExistsForm,
26
    ManifestExtractDataForm,
27
    ManifestFormForm,
28
    ManifestHeadersForm,
29
    ManifestInitialDataForm,
30
    ManifestOauthForm,
31
    ManifestRevokeForm,
32
    ManifestUserInfoForm,
33
)
34
from .utils import convert_array_to_object, convert_object_to_array
1✔
35

36

37
class SingleObjectMixinWithObj(SingleObjectMixin):
1✔
38
    def dispatch(self, request, *args, **kwargs):
1✔
39
        self.object = self.get_object()
×
40
        return super().dispatch(request, *args, **kwargs)
×
41

42

43
class RedirectToSelfMixin:
1✔
44
    def get_success_url(self):
1✔
45
        return self.request.path
×
46

47

48
class IntegrationBuilderCreateView(AdminPermMixin, CreateView):
1✔
49
    template_name = "token_create.html"
1✔
50
    model = Integration
1✔
51
    fields = ["name", "manifest_type"]
1✔
52

53
    def form_valid(self, form):
1✔
54
        form.instance.integration = Integration.Type.CUSTOM
×
55
        form.instance.is_active = False
×
56
        form.instance.manifest = {"execute": []}
×
57
        obj = form.save()
×
58
        return HttpResponseRedirect(
×
59
            reverse("integrations:builder-detail", args=[obj.id])
60
        )
61

62
    def get_context_data(self, **kwargs):
1✔
63
        context = super().get_context_data(**kwargs)
×
64
        context["title"] = _("Create new test integration")
×
65
        context["subtitle"] = _("integrations")
×
66
        return context
×
67

68

69
class IntegrationBuilderMakeActiveUpdateView(AdminPermMixin, UpdateView):
1✔
70
    model = Integration
1✔
71
    fields = []
1✔
72
    success_url = reverse_lazy("settings:integrations")
1✔
73

74
    def form_valid(self, form):
1✔
75
        form.instance.is_active = True
×
76
        return super().form_valid(form)
×
77

78

79
class IntegrationBuilderView(AdminPermMixin, DetailView):
1✔
80
    template_name = "manifest_test.html"
1✔
81
    model = Integration
1✔
82
    context_object_name = "integration"
1✔
83

84
    def get_context_data(self, **kwargs):
1✔
85
        context = super().get_context_data(**kwargs)
×
86
        manifest = self.object.manifest
×
87
        for form in manifest.get("form", []):
×
88
            options_source = form.get("options_source", None)
×
89
            if options_source is None:
×
90
                if form.get("url", "") == "":
×
91
                    form["options_source"] = "fixed list"
×
92
                else:
93
                    form["options_source"] = "fetch url"
×
94
        self.object.manifest = manifest
×
95
        self.object.save()
×
96

97
        context["form"] = ManifestFormForm()
×
98
        context["users"] = User.objects.all()
×
99
        context["title"] = _("Integration builder")
×
100
        context["subtitle"] = _("integrations")
×
101
        if self.object.is_sync_users_integration:
×
102
            context["form"] = ManifestHeadersForm(
×
103
                initial={
104
                    "headers": convert_object_to_array(
105
                        self.object.manifest.get("headers", {})
106
                    )
107
                }
108
            )
109
        else:
110
            context["existing_form_items"] = [
×
111
                (ManifestFormForm(initial=form, disabled=True), idx)
112
                for idx, form in enumerate(self.object.manifest.get("form", []))
113
            ]
114
        return context
×
115

116

117
class IntegrationBuilderFormCreateView(
1✔
118
    AdminPermMixin,
119
    SingleObjectMixinWithObj,
120
    RedirectToSelfMixin,
121
    FormView,
122
):
123
    template_name = "manifest_test/form.html"
1✔
124
    model = Integration
1✔
125
    context_object_name = "integration"
1✔
126
    form_class = ManifestFormForm
1✔
127

128
    def form_valid(self, form):
1✔
129
        manifest = self.object.manifest
×
130
        if "form" not in manifest:
×
131
            manifest["form"] = []
×
132
        manifest["form"].append(form.cleaned_data)
×
133
        self.object.manifest = manifest
×
134
        self.object.save()
×
135
        return super().form_valid(form)
×
136

137
    def get_context_data(self, **kwargs):
1✔
138
        context = super().get_context_data(**kwargs)
×
139
        context["existing_form_items"] = [
×
140
            (ManifestFormForm(initial=form, disabled=True), idx)
141
            for idx, form in enumerate(self.object.manifest.get("form", []))
142
        ]
143
        return context
×
144

145

146
class IntegrationBuilderFormUpdateView(
1✔
147
    AdminPermMixin,
148
    SingleObjectMixinWithObj,
149
    RedirectToSelfMixin,
150
    FormView,
151
):
152
    template_name = "manifest_test/_update_form.html"
1✔
153
    model = Integration
1✔
154
    context_object_name = "integration"
1✔
155
    form_class = ManifestFormForm
1✔
156

157
    def get_form_kwargs(self):
1✔
158
        kwargs = super().get_form_kwargs()
×
159
        kwargs["initial"] = self.object.manifest["form"][self.kwargs["index"]]
×
160
        return kwargs
×
161

162
    def form_valid(self, form):
1✔
163
        manifest = self.object.manifest
×
164
        data = form.cleaned_data
×
165
        if len(data.get("items", [])):
×
166
            data["choice_value"] = "key"
×
167
            data["choice_name"] = "value"
×
168

169
        if form.cleaned_data.get("options_source") == "fixed list":
×
170
            form.cleaned_data["url"] = ""
×
171

172
        manifest["form"][self.kwargs["index"]] = form.cleaned_data
×
173
        self.object.manifest = manifest
×
174
        self.object.save()
×
175
        form = self.form_class(
×
176
            initial=self.object.manifest["form"][self.kwargs["index"]], disabled=True
177
        )
178
        return render(
×
179
            self.request,
180
            self.template_name,
181
            {"form": form, "index": self.kwargs["index"], "integration": self.object},
182
        )
183

184
    def get_context_data(self, **kwargs):
1✔
185
        context = super().get_context_data(**kwargs)
×
186
        context["index"] = self.kwargs["index"]
×
187
        return context
×
188

189

190
class IntegrationBuilderFormDeleteView(AdminPermMixin, View):
1✔
191
    def post(self, *args, **kwargs):
1✔
192
        integration = get_object_or_404(Integration, id=self.kwargs["pk"])
×
193
        manifest = integration.manifest
×
194
        del manifest["form"][self.kwargs["index"]]
×
195
        integration.manifest = manifest
×
196
        integration.save()
×
197
        return HttpResponse()
×
198

199

200
class IntegrationBuilderHeadersUpdateView(
1✔
201
    AdminPermMixin,
202
    SingleObjectMixinWithObj,
203
    SuccessMessageMixin,
204
    RedirectToSelfMixin,
205
    FormView,
206
):
207
    template_name = "manifest_test/headers.html"
1✔
208
    form_class = ManifestHeadersForm
1✔
209
    model = Integration
1✔
210
    success_message = _("Headers have been updated")
1✔
211
    context_object_name = "integration"
1✔
212

213
    def get_form_kwargs(self):
1✔
214
        kwargs = super().get_form_kwargs()
×
215
        kwargs["initial"] = {
×
216
            "headers": convert_object_to_array(self.object.manifest.get("headers", {}))
217
        }
218
        return kwargs
×
219

220
    def form_valid(self, form):
1✔
221
        manifest = self.object.manifest
×
222
        manifest["headers"] = convert_array_to_object(form.cleaned_data["headers"])
×
223
        self.object.manifest = manifest
×
224
        self.object.save()
×
225
        return super().form_valid(form)
×
226

227

228
class IntegrationBuilderExistsUpdateView(
1✔
229
    AdminPermMixin,
230
    SingleObjectMixinWithObj,
231
    SuccessMessageMixin,
232
    RedirectToSelfMixin,
233
    FormView,
234
):
235
    template_name = "manifest_test/exists.html"
1✔
236
    form_class = ManifestExistsForm
1✔
237
    model = Integration
1✔
238
    context_object_name = "integration"
1✔
239
    success_message = _("Exists check has been updated")
1✔
240

241
    def get_form_kwargs(self):
1✔
242
        kwargs = super().get_form_kwargs()
×
243
        kwargs["initial"] = self.object.manifest.get("exists", {})
×
244
        return kwargs
×
245

246
    def form_valid(self, form):
1✔
247
        manifest = self.object.manifest
×
248
        manifest["exists"] = form.cleaned_data
×
249
        self.object.manifest = manifest
×
250
        self.object.save()
×
251
        return super().form_valid(form)
×
252

253

254
class IntegrationBuilderRevokeCreateView(
1✔
255
    AdminPermMixin,
256
    RedirectToSelfMixin,
257
    SingleObjectMixinWithObj,
258
    FormView,
259
):
260
    template_name = "manifest_test/revoke.html"
1✔
261
    form_class = ManifestRevokeForm
1✔
262
    model = Integration
1✔
263
    context_object_name = "integration"
1✔
264

265
    def form_valid(self, form):
1✔
266
        manifest = self.object.manifest
×
267
        if "revoke" not in manifest:
×
268
            manifest["revoke"] = []
×
269
        manifest["revoke"].append(form.cleaned_data)
×
270
        self.object.manifest = manifest
×
271
        self.object.save()
×
272
        return super().form_valid(form)
×
273

274
    def get_context_data(self, **kwargs):
1✔
275
        context = super().get_context_data(**kwargs)
×
276
        context["existing_form_items"] = [
×
277
            (ManifestRevokeForm(initial=form, disabled=True), idx)
278
            for idx, form in enumerate(self.object.manifest.get("revoke", []))
279
        ]
280
        return context
×
281

282

283
class IntegrationBuilderRevokeUpdateView(
1✔
284
    AdminPermMixin,
285
    RedirectToSelfMixin,
286
    SingleObjectMixinWithObj,
287
    FormView,
288
):
289
    template_name = "manifest_test/_update_revoke.html"
1✔
290
    form_class = ManifestRevokeForm
1✔
291
    model = Integration
1✔
292
    context_object_name = "integration"
1✔
293

294
    def get_form_kwargs(self):
1✔
295
        kwargs = super().get_form_kwargs()
×
296
        kwargs["initial"] = self.object.manifest["revoke"][self.kwargs["index"]]
×
297
        return kwargs
×
298

299
    def form_valid(self, form):
1✔
300
        manifest = self.object.manifest
×
301
        manifest["revoke"][self.kwargs["index"]] = form.cleaned_data
×
302
        self.object.manifest = manifest
×
303
        self.object.save()
×
304
        form = self.form_class(
×
305
            initial=self.object.manifest["execute"][self.kwargs["index"]], disabled=True
306
        )
307
        return render(
×
308
            self.request,
309
            "manifest_test/revoke_disabled_form.html",
310
            {"form": form, "index": self.kwargs["index"], "integration": self.object},
311
        )
312

313
    def get_context_data(self, **kwargs):
1✔
314
        context = super().get_context_data(**kwargs)
×
315
        context["index"] = self.kwargs["index"]
×
316
        return context
×
317

318

319
class IntegrationBuilderRevokeDeleteView(AdminPermMixin, View):
1✔
320
    def post(self, *args, **kwargs):
1✔
321
        integration = get_object_or_404(Integration, id=self.kwargs["pk"])
×
322
        manifest = integration.manifest
×
323
        del manifest["revoke"][self.kwargs["index"]]
×
324
        integration.manifest = manifest
×
325
        integration.save()
×
326
        return HttpResponse()
×
327

328

329
class IntegrationBuilderInitialDataFormCreateView(
1✔
330
    AdminPermMixin,
331
    RedirectToSelfMixin,
332
    SingleObjectMixinWithObj,
333
    FormView,
334
):
335
    template_name = "manifest_test/initial_data_form.html"
1✔
336
    form_class = ManifestInitialDataForm
1✔
337
    success_message = _("Initial data item has been added")
1✔
338
    model = Integration
1✔
339
    context_object_name = "integration"
1✔
340

341
    def form_valid(self, form):
1✔
342
        manifest = self.object.manifest
×
343
        if "initial_data_form" not in manifest:
×
344
            manifest["initial_data_form"] = []
×
345
        manifest["initial_data_form"].append(form.cleaned_data)
×
346
        self.object.manifest = manifest
×
347
        self.object.save()
×
348
        return super().form_valid(form)
×
349

350
    def get_context_data(self, **kwargs):
1✔
351
        context = super().get_context_data(**kwargs)
×
352
        context["existing_form_items"] = [
×
353
            (ManifestInitialDataForm(initial=form, disabled=True), idx)
354
            for idx, form in enumerate(
355
                self.object.manifest.get("initial_data_form", [])
356
            )
357
        ]
358
        return context
×
359

360

361
class IntegrationBuilderInitialDataFormDeleteView(AdminPermMixin, View):
1✔
362
    def post(self, *args, **kwargs):
1✔
363
        integration = get_object_or_404(Integration, id=self.kwargs["pk"])
×
364
        manifest = integration.manifest
×
365
        # remove value from saved extra args
366
        try:
×
367
            del integration.extra_args[
×
368
                manifest["initial_data_form"][self.kwargs["index"]]["id"]
369
            ]
370
            integration.save()
×
371
        except KeyError:
×
372
            pass
×
373
        del manifest["initial_data_form"][self.kwargs["index"]]
×
374
        integration.manifest = manifest
×
375
        integration.save()
×
376
        return HttpResponse()
×
377

378

379
class IntegrationBuilderUserInfoFormCreateView(
1✔
380
    AdminPermMixin,
381
    RedirectToSelfMixin,
382
    SingleObjectMixinWithObj,
383
    FormView,
384
):
385
    template_name = "manifest_test/user_info_form.html"
1✔
386
    form_class = ManifestUserInfoForm
1✔
387
    success_message = _("User info item has been added")
1✔
388
    model = Integration
1✔
389
    context_object_name = "integration"
1✔
390

391
    def form_valid(self, form):
1✔
392
        manifest = self.object.manifest
×
393
        if "extra_user_info" not in manifest:
×
394
            manifest["extra_user_info"] = []
×
395
        manifest["extra_user_info"].append(form.cleaned_data)
×
396
        self.object.manifest = manifest
×
397
        self.object.save()
×
398
        return super().form_valid(form)
×
399

400
    def get_context_data(self, **kwargs):
1✔
401
        context = super().get_context_data(**kwargs)
×
402
        context["existing_form_items"] = [
×
403
            (ManifestUserInfoForm(initial=form, disabled=True), idx)
404
            for idx, form in enumerate(self.object.manifest.get("extra_user_info", []))
405
        ]
406
        return context
×
407

408

409
class IntegrationBuilderUserInfoFormDeleteView(AdminPermMixin, View):
1✔
410
    def post(self, *args, **kwargs):
1✔
411
        integration = get_object_or_404(Integration, id=self.kwargs["pk"])
×
412
        manifest = integration.manifest
×
413
        del manifest["extra_user_info"][self.kwargs["index"]]
×
414
        integration.manifest = manifest
×
415
        integration.save()
×
416
        return HttpResponse()
×
417

418

419
class IntegrationBuilderExecuteCreateView(
1✔
420
    AdminPermMixin,
421
    RedirectToSelfMixin,
422
    SingleObjectMixinWithObj,
423
    FormView,
424
):
425
    template_name = "manifest_test/execute.html"
1✔
426
    form_class = ManifestExecuteForm
1✔
427
    model = Integration
1✔
428
    context_object_name = "integration"
1✔
429

430
    def form_valid(self, form):
1✔
431
        manifest = self.object.manifest
×
432
        if "execute" not in manifest:
×
433
            manifest["execute"] = []
×
434
        manifest["execute"].append(form.cleaned_data)
×
435
        self.object.manifest = manifest
×
436
        self.object.save()
×
437
        return super().form_valid(form)
×
438

439
    def get_context_data(self, **kwargs):
1✔
440
        context = super().get_context_data(**kwargs)
×
441
        context["existing_form_items"] = [
×
442
            (ManifestExecuteForm(initial=form, disabled=True), idx)
443
            for idx, form in enumerate(self.object.manifest.get("execute", []))
444
        ]
445
        return context
×
446

447

448
class IntegrationBuilderExecuteUpdateView(
1✔
449
    AdminPermMixin,
450
    RedirectToSelfMixin,
451
    SingleObjectMixinWithObj,
452
    FormView,
453
):
454
    template_name = "manifest_test/_update_execute.html"
1✔
455
    form_class = ManifestExecuteForm
1✔
456
    model = Integration
1✔
457
    context_object_name = "integration"
1✔
458

459
    def get_form_kwargs(self):
1✔
460
        kwargs = super().get_form_kwargs()
×
461
        kwargs["initial"] = self.object.manifest["execute"][self.kwargs["index"]]
×
462
        return kwargs
×
463

464
    def form_valid(self, form):
1✔
465
        manifest = self.object.manifest
×
466
        manifest["execute"][self.kwargs["index"]] = form.cleaned_data
×
467
        self.object.manifest = manifest
×
468
        self.object.save()
×
469
        form = self.form_class(
×
470
            initial=self.object.manifest["execute"][self.kwargs["index"]], disabled=True
471
        )
472
        return render(
×
473
            self.request,
474
            "manifest_test/execute_disabled_form.html",
475
            {"form": form, "index": self.kwargs["index"], "integration": self.object},
476
        )
477

478
    def get_context_data(self, **kwargs):
1✔
479
        context = super().get_context_data(**kwargs)
×
480
        context["index"] = self.kwargs["index"]
×
481
        return context
×
482

483

484
class IntegrationBuilderExecuteDeleteView(AdminPermMixin, View):
1✔
485
    def post(self, *args, **kwargs):
1✔
486
        integration = get_object_or_404(Integration, id=self.kwargs["pk"])
×
487
        manifest = integration.manifest
×
488
        del manifest["execute"][self.kwargs["index"]]
×
489
        integration.manifest = manifest
×
490
        integration.save()
×
491
        return HttpResponse()
×
492

493

494
class IntegrationBuilderTestFormView(AdminPermMixin, View):
1✔
495
    def post(self, *args, **kwargs):
1✔
496
        integration = get_object_or_404(Integration, id=self.kwargs["pk"])
×
497
        form = integration.config_form()
×
498
        return render(self.request, "manifest_test/test_form.html", {"form": form})
×
499

500

501
class IntegrationBuilderTestView(AdminPermMixin, View):
1✔
502
    def post(self, *args, **kwargs):
1✔
503
        test_options = ["exists", "revoke", "execute"]
×
504
        test_type = self.kwargs["what"]
×
505
        if self.kwargs["what"] not in test_options:
×
506
            raise Http404
×
507

508
        integration = get_object_or_404(Integration, id=self.kwargs["pk"])
×
509
        extra_fields = json.loads(self.request.POST.get("extra_values", "{}"))
×
510

511
        try:
×
512
            user = get_user_model().objects.get(id=self.request.POST.get("user", -1))
×
513
            user.extra_fields |= convert_array_to_object(extra_fields)
×
514
        except (get_user_model().DoesNotExist, ValueError):
×
515
            return render(
×
516
                self.request,
517
                "manifest_test/test_execute.html",
518
                {"error": "no user selected"},
519
            )
520
        if test_type == "exists":
×
521
            result = integration.user_exists(user, save_result=False)
×
522
        elif test_type == "execute":
×
523
            result = integration.execute(user)
×
524
        elif test_type == "revoke":
×
525
            result = integration.revoke_user(user)
×
526

527
        tracker = IntegrationTracker.objects.filter(
×
528
            integration=integration, for_user=user
529
        ).last()
530

531
        return render(
×
532
            self.request,
533
            "manifest_test/test_execute.html",
534
            {"result": result, "integration": integration, "tracker": tracker},
535
        )
536

537

538
class IntegrationBuilderSyncTestView(AdminPermMixin, View):
1✔
539
    def post(self, *args, **kwargs):
1✔
540
        integration = get_object_or_404(Integration, id=self.kwargs["pk"])
×
541

542
        error = None
×
543
        users = []
×
544
        try:
×
545
            # we are passing in the user who is requesting it, but we likely don't need
546
            # them.
547
            users = SyncUsers(integration).get_import_user_candidates()
×
548
        except (
×
549
            KeyIsNotInDataError,
550
            FailedPaginatedResponseError,
551
            DataIsNotJSONError,
552
        ) as e:
553
            error = e
×
554

555
        tracker = IntegrationTracker.objects.filter(integration=integration).last()
×
556

557
        return render(
×
558
            self.request,
559
            "manifest_test/test_sync.html",
560
            {
561
                "integration": integration,
562
                "tracker": tracker,
563
                "users": users,
564
                "error": error,
565
            },
566
        )
567

568

569
class IntegrationBuilderOauthUpdateView(
1✔
570
    AdminPermMixin,
571
    SingleObjectMixinWithObj,
572
    SuccessMessageMixin,
573
    RedirectToSelfMixin,
574
    FormView,
575
):
576
    template_name = "manifest_test/oauth.html"
1✔
577
    form_class = ManifestOauthForm
1✔
578
    model = Integration
1✔
579
    success_message = _("Oauth has been updated")
1✔
580
    context_object_name = "integration"
1✔
581

582
    def get_form_kwargs(self):
1✔
583
        kwargs = super().get_form_kwargs()
×
584
        kwargs["initial"] = {"oauth": self.object.manifest.get("oauth", {})}
×
585
        return kwargs
×
586

587
    def form_valid(self, form):
1✔
588
        manifest = self.object.manifest
×
589
        manifest["oauth"] = form.cleaned_data["oauth"]
×
590
        self.object.manifest = manifest
×
591
        self.object.save()
×
592
        return super().form_valid(form)
×
593

594

595
class IntegrationBuilderExtractDataUpdateView(
1✔
596
    AdminPermMixin,
597
    SingleObjectMixinWithObj,
598
    SuccessMessageMixin,
599
    RedirectToSelfMixin,
600
    FormView,
601
):
602
    template_name = "manifest_test/extract_data.html"
1✔
603
    form_class = ManifestExtractDataForm
1✔
604
    model = Integration
1✔
605
    success_message = _("Extract data has been updated")
1✔
606
    context_object_name = "integration"
1✔
607

608
    def get_form_kwargs(self):
1✔
609
        kwargs = super().get_form_kwargs()
×
610
        kwargs["initial"] = self.object.manifest
×
611
        return kwargs
×
612

613
    def form_valid(self, form):
1✔
614
        manifest = self.object.manifest
×
615
        manifest |= form.cleaned_data
×
616
        self.object.manifest = manifest
×
617
        self.object.save()
×
618
        return super().form_valid(form)
×
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