Skip to content

fix: sql function get_mining_source_credentials_for_user#2850

Merged
malek10xdev merged 21 commits into
mainfrom
google-contact-sync-advanced
Jun 20, 2026
Merged

fix: sql function get_mining_source_credentials_for_user#2850
malek10xdev merged 21 commits into
mainfrom
google-contact-sync-advanced

Conversation

@malek10xdev

@malek10xdev malek10xdev commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Resolves #2850 and fixes 6 bugs discovered during QA demo + 2 follow-up bugs from continued testing.

Summary

DB Migration

  • supabase/migrations/20260619000000_delete_user_data_auth_uid.sql — new private.delete_user_data() function (parameterless, SECURITY DEFINER, uses auth.uid()) that delegates contact cleanup to private.delete_contacts(NULL, TRUE) and cleans all other user-owned tables. Preserves private.email_status as a shared enrichment cache.

Edge Function

  • supabase/functions/delete-user/index.ts — now calls delete_user_data() via the authenticated user client (not admin) and keeps admin only for auth.admin.deleteUser().
  • supabase/functions/_shared/mailing/email.ts — guards sendEmail when SMTP is not configured (local dev).
  • supabase/functions/email-campaigns/deno.lock removed — local Supabase Edge Runtime doesn't support lockfile v5.

Frontend Fixes

  • PassiveMiningDialog.vue — uses store refs for defaults, guards watcher with oldVal to prevent overwriting user toggle changes.
  • ContactInformationSidebar.vuetoRaw(contact.value) before passing to cache, safety guards in skipDialog/allTags/watch(show).
  • stores/contacts.tsJSON.parse(JSON.stringify(...)) deep-clone in updateContactsCache, try/catch in syncContactsList and realtime callback.
  • stores/filters.ts + filters-defaults.ts — new emailMissing toggle filter for "phone without email" contacts.
  • MiningTable.vue — new ToggleSwitch for the email-missing filter with i18n.

Test plan

  • deno test for delete-user edge function (5 tests pass)
  • Frontend lint passes
  • Local manual QA: delete user returns 200; passive mining toggle reflects user choice; no edge-function lockfile/SMTP errors
  • QA deploy verification

Out of scope (handled separately)

  • Frontend form "empty for a second" flicker during save (mitigated with computed guards; full fix tracked separately)
  • Proxy object could not be cloned loop (mitigated with JSON deep-clone)

Add config JSONB column to private.mining_sources for per-source settings.
Backend supports miningSource.id lookup with fallback to email.
Edge functions read config flags and pass them through the pipeline.
Frontend adds toggles in PassiveMiningDialog and sources.vue.
i18n labels in en/fr.

Partially resolves #2818
- Remove spurious async on PgMiningSources.getSourceById stub (DeepSource JS-0116)
- Update startMiningSchema to accept miningSource.id as optional alternative to email
- Wire Zod validate() middleware into all mining routes
- Install hpp middleware for HTTP Parameter Pollution defense
- Guard req.query.userId against array pollution in auth middleware
- Run prettier on mining.schema.ts (was failing CI check)
- Add express-rate-limit to mining POST routes (CodeQL flagged db-access without rate limiting)
@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown

Coverage Report

Passed

Commit: d52ba0b

Summary

Name Stmts Branch Funcs Lines
🟡 Total 44.6% 42.1% 51.4% 44.9%
All files
Name Stmts Branch Funcs Lines
🔴 backend/src/controllers/mining.controller.ts 0% 0% 0% 0%
🟢 backend/src/services/extractors/engines/GoogleContactsExtractor.ts 94.7% 93.3% 100% 97.2%
No coverage changes
Name Stmts Branch Funcs Lines
🔴 backend/src/controllers/mining.controller.ts 0% 0% 0% 0%
🟢 backend/src/services/extractors/engines/GoogleContactsExtractor.ts 94.7% 93.3% 100% 97.2%

Generated by Test Coverage Reporter for commit d52ba0b

When a contact has telephone: [] instead of telephone: null, the
NOT_EMPTY filter incorrectly shows the contact as having a phone
number. The contacts_view database view returns empty arrays
instead of null for contacts without phone numbers.

Added Array.isArray(value) && value.length === 0 check to treat
empty arrays as empty.
Closing modal before the API call left users with no feedback while
deletion was in progress. Now the modal stays open (with loading state)
during the request and closes only on success.
@malek10xdev

Copy link
Copy Markdown
Collaborator Author

Ready for review. This PR now includes:

delete-user fix:

  • New private.delete_user_data() migration using auth.uid() + SECURITY DEFINER
  • Edge function calls RPC as authenticated user
  • Tests pass (5/5)

Passive mining toggle fix:

  • Google Contacts toggle now correctly sends false when disabled (was sending true)
  • Initialized from store refs instead of hardcoded defaults
  • Watcher guarded with oldVal to prevent overwriting user edits

Local dev edge function fixes:

  • Removed incompatible email-campaigns/deno.lock (v5 not supported by local runtime)
  • Added SMTP guard in sendEmail to skip when SMTP_HOST is unset/example

Other frontend fixes in this PR:

  • Proxy cloning error in contacts cache (JSON deep-clone)
  • New filter: phone without email
  • Sidebar template safety guards

@malek10xdev malek10xdev merged commit 783048c into main Jun 20, 2026
15 checks passed
@malek10xdev malek10xdev deleted the google-contact-sync-advanced branch June 20, 2026 00:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant