Skip to main content

Templates Controller

📖 Overview

Controllers/templates.js powers the reusable template catalogue surfaced in the Forms builder. It allows DashClicks admins to curate starter forms, exposes paginated listings for agency teams, and converts a template into an editable draft. Template authoring is tightly gated by scope (dashclicks.forms.templates) so only HQ teams can mutate shared assets, while agencies may browse/apply templates through the standard forms.templates scope.

🗄️ Collections touched

CollectionPurpose
forms.templatesStores reusable template JSON, category/tag references, and onboarding flags.
formsReceives a new status: 'in_progress' form when useTemplate is invoked.

🔐 Middleware & validation

Routes/templates.js applies the shared stack (verifyAuthorization, verifyAccessAndStatus, validateLimit, validateRequestSchemaV2(validators/templates)) with two notable scope splits:

  • dashclicks.forms.templates – required for POST /forms/templates and PUT /forms/templates/:templateid; reserved for internal staff.
  • forms.templates (optionally with forms parent scope) – grants template listing, category listing, and POST /forms/templates/usetemplate.

validators/templates.js ensures:

  • Path params are valid ObjectIds.
  • Bodies include a templatedata object (shape left open for flexibility).
  • useTemplate payload includes a valid template_id.

🛣️ Route map

MethodPath (internal service)Controller methodNotes
POST/forms/templatessaveTemplatesAdmin-only creation of a template record.
PUT/forms/templates/:templateidupdateTemplatesAdmin-only update of template metadata/content.
POST/forms/templates/usetemplateuseTemplateCopies a template into forms and returns the new draft.
GET/forms/templatesgetTemplatesPaginates through available templates with optional filters.
GET/forms/templates/categoriesgetCategoriesAggregates templates grouped by category (with optional search).
GET/forms/templates/:templateidgetTemplateByIdFetches a single template document.

✨ Controller behaviour

saveTemplates

  • Expects req.body.templatedata and persists it directly to forms.templates.
  • Returns the saved document (Mongoose save() result converted to lean object).
  • The caller is responsible for setting category/tag IDs, is_onboarding_dc, and other metadata.

updateTemplates

  • Path-param :templateid must be a valid ObjectId; the controller builds a lightweight condition { _id: templateid } and calls updateTemplate in the template model.
  • Returns the raw result of findOneAndUpdate, so the UI sees the latest object immediately.

useTemplate

  • Accepts { templatedata: { template_id } }.
  • Loads the source template and strips database-specific fields (_id, timestamps, __v).
  • Forces status: 'in_progress' to avoid publishing on initial clone.
  • Delegates to formsModel.saveForm and returns the newly minted form document.
  • Returns 406 if the template lookup fails, signalling the front-end to refresh its catalogue.

getTemplates

  • Supports query params: page, limit, categories, tags, and search.
  • Applies pagination with skip = (page - 1) * limit.
  • If req.auth.account.main is falsy (i.e., the requester is a sub-account), the controller hides internal onboarding templates:
    • Excludes documents with is_onboarding_dc: true.
    • Filters out names containing (DC), InstaSites, InstaReports, etc., via regex.
  • Category/tag filters accept comma-separated lists and coerce each entry to an ObjectId before matching ($in).
  • Delegates to templatesModel.getAllTemplates, wrapping the result with shared pagination metadata via utilities.generatePagination.

getCategories

  • Shares pagination plumbing with getTemplates.
  • Optional categories filter accepts a comma-separated list (string matching rather than ObjectId).
  • Calls templatesModel.getAllCategories, which groups templates by category and returns { data, count } for the paginator.
  • The controller leaves search filtering to the model (search term passed through unmodified).

getTemplateById

  • Simple wrapper around templatesModel.findTemplate({ _id }).
  • Returns the first entry when an array is produced, otherwise an empty object.

⚠️ Notes & edge cases

  • Scope enforcement – applying templates only requires forms.templates, but creating or updating templates requires the dedicated admin scope. Ensure role assignments mirror this split to avoid exposing internal catalogues.
  • Sub-account catalogue parity – sub-accounts cannot see onboarding templates (is_onboarding_dc) or ones containing certain keywords. If new onboarding templates are introduced, remember to update the regex or add flags appropriately.
  • Template hygieneuseTemplate does not clone createdAt/updatedAt or _id, preventing collisions. It also ensures the resulting form starts as in_progress so the builder can finish configuration before publishing.
💬

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:31 AM