Skip to content

Integrate h captcha into the sensor manufacturer request form#3628

Merged
Baalmart merged 4 commits into
airqo-platform:stagingfrom
BwanikaRobert:Integrate-hCaptcha-into-the-Sensor-Manufacturer-Request-Form
Jun 11, 2026
Merged

Integrate h captcha into the sensor manufacturer request form#3628
Baalmart merged 4 commits into
airqo-platform:stagingfrom
BwanikaRobert:Integrate-hCaptcha-into-the-Sensor-Manufacturer-Request-Form

Conversation

@BwanikaRobert

@BwanikaRobert BwanikaRobert commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Summary of Changes (What does this PR do?)

Adds hCaptcha verification to the public-facing Sensor Manufacturer Request
form (NetworkRequestDialog) to protect the unauthenticated
/api/devices/network-creation-requests endpoint from automated abuse and
spam submissions.

The backend CAPTCHA middleware is already wired — it accepts a captchaToken
field in the POST body and will enforce it once the backend secret key is
activated. This PR completes the frontend integration.

Changes made:

  • schema.ts — added optional captchaToken: z.string().optional() to
    networkRequestSchema to keep the Zod schema aligned with the POST body.
  • network-request-dialog.tsx — integrated HCaptchaWidget following the
    same pattern as the login page:
    • hcaptchaEnabled flag derived from isHCaptchaEnabled() via useMemo
      to conditionally enable all CAPTCHA behaviour at runtime.
    • <HCaptchaWidget> rendered at the bottom of the form only when
      hcaptchaEnabled is true, with onVerify and onExpire handlers.
    • captchaToken only included in the POST body when hcaptchaEnabled
      is true: { ...data, ...(hcaptchaEnabled && { captchaToken }) }.
    • Submit button gated with disabled: isPending || (hcaptchaEnabled && !captchaToken)
      so it remains usable when CAPTCHA is disabled.
    • handleClose resets the widget and clears captchaToken on dialog
      dismiss or cancel.
    • onError also resets the widget and clears captchaToken so the user
      must re-verify before retrying a failed submission.

Dependencies:

  • Requires HCaptchaWidget component (src/vertex/components/ui/hcaptcha-widget.tsx) — already merged.
  • Requires NEXT_PUBLIC_HCAPTCHA_SITE_KEY set in .env.local to render the widget locally.

Status of maturity (all need to be checked before merging):

  • I've tested this locally
  • I consider this code done
  • This change ready to hit production in its current state
  • The title of the PR states what changed and the related issues number (used for the release note).
  • I've included issue number in the "Closes #ISSUE-NUMBER" part of the "What are the relevant tickets?" section to link the issue.
  • I've updated corresponding documentation for the changes in this PR.
  • I have written unit and/or e2e tests for my change(s).

How should this be manually tested?

  1. Add your own hCaptcha site key to .env.local:
    NEXT_PUBLIC_HCAPTCHA_SITE_KEY=your-site-key-here

  2. Run the app locally and navigate to the page that renders NetworkRequestDialog.

  3. Open the Request New Sensor Manufacturer dialog.

  4. Confirm the hCaptcha widget renders at the bottom of the form.

  5. Confirm the Submit Request button is disabled before completing the CAPTCHA.

  6. Complete the CAPTCHA — confirm the Submit button becomes enabled.

  7. Submit the form with valid data — confirm the request succeeds and the dialog closes.

  8. Re-open the dialog — confirm the widget is reset and the Submit button is disabled again.

  9. Trigger a submission error — confirm the widget resets and the Submit button re-disables, requiring re-verification before retrying.

  10. Click Cancel without submitting — confirm the widget resets on close.

  11. Remove NEXT_PUBLIC_HCAPTCHA_SITE_KEY from .env.local and reload — confirm the widget does not render and the Submit button is not blocked.


What are the relevant tickets?

  • Closes#### Summary of Changes (What does this PR do?)

Adds hCaptcha verification to the public-facing Sensor Manufacturer Request
form (NetworkRequestDialog) to protect the unauthenticated
/api/devices/network-creation-requests endpoint from automated abuse and
spam submissions.

Changes made:

  • schema.ts — added optional captchaToken: z.string().optional() to
    networkRequestSchema to keep the Zod schema aligned with the POST body.
  • network-request-dialog.tsx — integrated HCaptchaWidget following the
    same pattern as the login page:
    • hcaptchaEnabled flag derived from isHCaptchaEnabled() via useMemo
      to conditionally enable all CAPTCHA behaviour at runtime.
    • <HCaptchaWidget> rendered at the bottom of the form only when
      hcaptchaEnabled is true, with onVerify and onExpire handlers.
    • captchaToken only included in the POST body when hcaptchaEnabled
      is true: { ...data, ...(hcaptchaEnabled && { captchaToken }) }.
    • Submit button gated with disabled: isPending || (hcaptchaEnabled && !captchaToken)
      so it remains usable when CAPTCHA is disabled.
    • handleClose resets the widget and clears captchaToken on dialog
      dismiss or cancel.
    • onError also resets the widget and clears captchaToken so the user
      must re-verify before retrying a failed submission.

Status of maturity (all need to be checked before merging):


How should this be manually tested?

  1. Add your own hCaptcha site key to .env.local:
    NEXT_PUBLIC_HCAPTCHA_SITE_KEY=your-site-key-here

  2. Run the app locally and navigate to the page that renders NetworkRequestDialog.

  3. Open the Request New Sensor Manufacturer dialog.

  4. Confirm the hCaptcha widget renders at the bottom of the form.

  5. Confirm the Submit Request button is disabled before completing the CAPTCHA.

  6. Complete the CAPTCHA — confirm the Submit button becomes enabled.

  7. Submit the form with valid data — confirm the request succeeds and the dialog closes.

  8. Re-open the dialog — confirm the widget is reset and the Submit button is disabled again.

  9. Trigger a submission error — confirm the widget resets and the Submit button re-disables, requiring re-verification before retrying.

  10. Click Cancel without submitting — confirm the widget resets on close.

  11. Remove NEXT_PUBLIC_HCAPTCHA_SITE_KEY from .env.local and reload — confirm the widget does not render and the Submit button is not blocked.


What are the relevant tickets?

Screenshots (optional)

hp1 hp2 hp3

Summary by CodeRabbit

  • New Features

    • hCaptcha verification step added to the Sensor Manufacturer Request form; submit button disabled until verification is complete
  • Improvements

    • Shipping label printing errors now display as in-app banner messages instead of browser alerts
  • Documentation

    • Changelog updated with Version 2.0.3 release information documenting new hCaptcha integration

Copilot AI review requested due to automatic review settings June 11, 2026 05:30
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@BwanikaRobert, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 24 minutes. Learn how PR review limits work.

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ca62c9ab-cfc8-4c97-8856-5f873b9fca9b

📥 Commits

Reviewing files that changed from the base of the PR and between cd9b652 and 07e15b5.

📒 Files selected for processing (3)
  • src/vertex/app/changelog.md
  • src/vertex/components/features/networks/network-request-dialog.tsx
  • src/vertex/components/features/networks/schema.ts
📝 Walkthrough

Walkthrough

The PR adds hCaptcha bot protection to the Sensor Manufacturer Request form by integrating a verification widget, gating submission on token acquisition, and managing token state across errors and dialog close. A separate change migrates error reporting in ShippingLabelPrintModal from alert() to in-app banners.

Changes

hCaptcha Integration in NetworkRequestDialog

Layer / File(s) Summary
Schema contract update
src/vertex/components/features/networks/schema.ts
Adds optional captchaToken string field to networkRequestSchema, aligning the form's validation with the POST body expected by the backend.
Component setup and state management
src/vertex/components/features/networks/network-request-dialog.tsx
Imports HCaptchaWidget, HCaptchaWidgetHandle, and isHCaptchaEnabled; initializes captchaToken state, a ref for widget reset, and a memoized hcaptchaEnabled flag. Extends the POST payload to conditionally include captchaToken when enabled.
Form UI with widget and submission gating
src/vertex/components/features/networks/network-request-dialog.tsx
Renders HCaptchaWidget conditionally and wires onVerify/onExpire callbacks to set/clear the token. Disables the primary action button when hCaptcha is enabled but no token exists, preventing submission until verification completes.
State lifecycle on error and dialog close
src/vertex/components/features/networks/network-request-dialog.tsx
Clears the captcha token and resets the widget on mutation errors and when closing the dialog, ensuring clean state across interactions.
Release notes
src/vertex/app/changelog.md
Documents Version 2.0.3 (June 11, 2026) with hCaptcha integration details, affected files, and implementation summary.

Banner Error Handling in ShippingLabelPrintModal

Layer / File(s) Summary
Banner-based error reporting
src/vertex/components/features/shipping/ShippingLabelPrintModal.tsx
Imports and uses the useBanner hook to display scoped error banners when pop-ups are blocked or QR image URLs are invalid, replacing browser alert() calls. Strengthens the isValidDataUrl type guard to accept unknown and validate more strictly.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • airqo-platform/AirQo-frontend#3529: Sets up the shared HCaptchaWidget component and isHCaptchaEnabled() environment helper that this PR consumes for the NetworkRequestDialog integration.
  • airqo-platform/AirQo-frontend#3558: Also modifies NetworkRequestDialog's error and success handling paths, which overlap with the captcha reset and banner migration work in this PR.

Suggested labels

ready for review

Suggested reviewers

  • Baalmart
  • OchiengPaul442
  • Codebmk

Poem

🤖 A token arrives, the bot keeps away,
Click verify once, then submit your say.
When errors arise or you change your mind,
The captcha resets, leaves no trace behind.
And alerts bow down to banners so bright,
User experience takes flight! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Changes to ShippingLabelPrintModal.tsx are out of scope—issue #3485 specifies only network-request-dialog.tsx, schema.ts, and changelog.md should change. Remove ShippingLabelPrintModal.tsx modifications; they are unrelated to hCaptcha integration in the Sensor Manufacturer Request form and should be addressed in a separate PR.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Integrate h captcha into the sensor manufacturer request form' directly and clearly summarizes the main change—adding hCaptcha protection to the public network request form.
Linked Issues check ✅ Passed All coding requirements from issue #3485 are met: captchaToken added to schema, HCaptchaWidget integrated with proper state management, token included in POST body, submit button gated on verification, and CAPTCHA reset on dialog close. Changelog entry documenting the changes is also included.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • JIRA integration encountered authorization issues. Please disconnect and reconnect the integration in the CodeRabbit UI.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds hCaptcha support to the Network Request dialog (schema + UI + submission gating) and replaces alert() calls in the shipping label print flow with scoped banners, with a corresponding changelog entry.

Changes:

  • Add optional captchaToken to the network request Zod schema and include token in POST body when hCaptcha is enabled
  • Integrate HCaptchaWidget into NetworkRequestDialog, gating submission and resetting token/widget on close + error
  • Replace print-modal alert() messages with showBanner errors and update changelog

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

File Description
src/vertex/components/features/shipping/ShippingLabelPrintModal.tsx Switches pop-up/invalid-URL feedback from alert() to banner notifications
src/vertex/components/features/networks/schema.ts Extends request schema to optionally accept captchaToken
src/vertex/components/features/networks/network-request-dialog.tsx Adds hCaptcha widget, token state, submit gating, and reset behavior
src/vertex/app/changelog.md Documents hCaptcha integration release notes

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


const handlePrint = () => {
// Generate HTML for the new window
const printWindow = window.open('', '_blank');

const handlePrint = () => {
// Generate HTML for the new window
const printWindow = window.open('', '_blank');
Comment on lines 33 to 37
const invalidLabels = labels.filter(label => !isValidDataUrl(label.qr_code_image));
if (invalidLabels.length > 0) {
alert('Some QR code images have invalid URLs');
showBanner({ severity: 'error', message: 'Some QR code images have invalid URLs', scoped: true });
return;
}
const { showBannerWithDelay } = useBannerWithDelay();
const [captchaToken, setCaptchaToken] = useState("");
const captchaRef = useRef<HCaptchaWidgetHandle>(null);
const hcaptchaEnabled = useMemo(() => isHCaptchaEnabled(), []);
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
body: JSON.stringify({ ...data, ...(hcaptchaEnabled && { captchaToken }) }),
Comment on lines +24 to +30
<details>
<summary><strong>Files Updated (2)</strong></summary>

- `src/vertex/components/features/networks/network-request-dialog.tsx` [MODIFIED]
- `src/vertex/components/features/networks/schema.ts` [MODIFIED]

</details>
@github-actions

Copy link
Copy Markdown
Contributor

New azure docs changes available for preview here

@github-actions

Copy link
Copy Markdown
Contributor

New azure website changes available for preview here

@github-actions

Copy link
Copy Markdown
Contributor

New azure analytics_platform changes available for preview here

@github-actions

Copy link
Copy Markdown
Contributor

New azure vertex changes available for preview here

@BwanikaRobert
BwanikaRobert force-pushed the Integrate-hCaptcha-into-the-Sensor-Manufacturer-Request-Form branch from cd9b652 to 6efa4d2 Compare June 11, 2026 05:49
@github-actions

Copy link
Copy Markdown
Contributor

New azure website changes available for preview here

@github-actions

Copy link
Copy Markdown
Contributor

New azure docs changes available for preview here

@github-actions

Copy link
Copy Markdown
Contributor

New azure analytics_platform changes available for preview here

@github-actions

Copy link
Copy Markdown
Contributor

New azure vertex changes available for preview here

Copilot AI review requested due to automatic review settings June 11, 2026 05:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

captchaRef.current?.reset();
}, [form, onOpenChange]);

const onSubmit = (values: NetworkRequestValues) => {
Comment on lines +28 to +30
const [captchaToken, setCaptchaToken] = useState("");
const captchaRef = useRef<HCaptchaWidgetHandle>(null);
const hcaptchaEnabled = useMemo(() => isHCaptchaEnabled(), []);
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
body: JSON.stringify({ ...data, ...(hcaptchaEnabled && { captchaToken }) }),
Comment on lines 49 to 51
queryClient.invalidateQueries({ queryKey: ["network-requests"] });
showBannerWithDelay({ severity: 'success', message: resp.message || "Your request for a new Sensor Manufacturer has been submitted successfully!", scoped: true });
},

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot We have two modals here on success the first modal will close and it will leave the second modal open.

Comment on lines +24 to +30
<details>
<summary><strong>Files Updated (2)</strong></summary>

- `src/vertex/components/features/networks/network-request-dialog.tsx` [MODIFIED]
- `src/vertex/components/features/networks/schema.ts` [MODIFIED]

</details>
@github-actions

Copy link
Copy Markdown
Contributor

New azure docs changes available for preview here

@github-actions

Copy link
Copy Markdown
Contributor

New azure website changes available for preview here

@github-actions

Copy link
Copy Markdown
Contributor

New azure analytics_platform changes available for preview here

@github-actions

Copy link
Copy Markdown
Contributor

New azure vertex changes available for preview here

@github-actions

Copy link
Copy Markdown
Contributor

New azure website changes available for preview here

@github-actions

Copy link
Copy Markdown
Contributor

New azure docs changes available for preview here

@github-actions

Copy link
Copy Markdown
Contributor

New azure analytics_platform changes available for preview here

@github-actions

Copy link
Copy Markdown
Contributor

New azure vertex changes available for preview here

@Codebmk Codebmk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks @BwanikaRobert

@Baalmart

Copy link
Copy Markdown
Collaborator

Hi @Codebmk , I have realised that this PR is triggering multiple deploy previews for almost all projects and yet it should be triggerig for just one project. We need to investigate this.

@Baalmart
Baalmart merged commit adfdff5 into airqo-platform:staging Jun 11, 2026
24 of 25 checks passed
@Baalmart Baalmart mentioned this pull request Jun 11, 2026
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Vertex: Feature] Integrate hCaptcha into the Sensor Manufacturer Request Form

4 participants