agentejo / cockpit

Add content management functionality to any site - plug & play / headless / api-first CMS
http://getcockpit.com
MIT License
5.4k stars 523 forks source link

Change the subject of the email - Form module / Cockpit and React JS #1456

Closed MarcTabaries closed 3 years ago

MarcTabaries commented 3 years ago

I'm developing a website with Cockpit and React JS.

In this project, there is a very simple contact form (name, email, message).

I created a form in Cockpit, via the Forms module, and I added a configuration file in Cockpit (config/config.yaml) :

mailer:
  from: no-reply@***.com
  transport: smtp
  host: smtp.ionos.fr
  user: bonjour@***.com
  password: ***
  port: 587
  auth: true
  encryption:

The form module is configured to record data in Cockpit, but also to send me an email as soon as a new record is added (in plain language, as soon as a user clicks on the submit button on the form). That's why I had to create the config/config.yaml file with this informations.

Everything works perfectly. The datas are well recorded in Cockpit and I receive the email.

But I have a problem.

I want to change the subject of the email. For the moment, when I receive an email the subject is : "New form data for: Contact".

In the modules/Forms/bootstrap.php file, line 325... I found this :

$response = $this->app->mailer->mail($frm['email_forward'], $options['subject'] ?? "New form data for: {$formname}", $body, $options);

So, it's in this file that the subject of the email is managed. So, in theory, it's possible to pass an option to modify the subject of the email.

The problem is, I don't see how I should go about sending this information.

I have tried adding the information to the config/config.yaml file but it doesn't work. Like this :

mailer:
  from: no-reply@***.com
  subject: test /* <= I added this information */
  transport: smtp
  host: smtp.ionos.fr
  user: bonjour@***.com
  password: ***
  port: 587
  auth: true
  encryption:

On this page, it's indicated that it's necessary to create a hidden field named "__mailsubject" and with as value the desired subject. The problem is that I'm using React JS (+ axios) and not PHP (no access to : $_REQUEST, $_POST, ...).

Here is the code my React component

import React, { Component } from "react";
import axios from "axios";

class Form extends Component {
  constructor(props) {
    super(props);

    this.onChangeName = this.onChange.bind(this);
    this.onChangeEmail = this.onChange.bind(this);
    this.onChangeMessage = this.onChange.bind(this);
    this.onSubmitForm = this.onSubmitForm.bind(this);
  }

  state = {
    name: '',
    email: '',
    message: ''
  }

  onChange(e) {
    this.setState({ [e.target.name]: e.target.value })
  }

  onSubmitForm(e) {
    e.preventDefault()

    const dataForm = {
      "form": {
        name: this.state.name,
        email: this.state.email,
        message: this.state.message
      }
    };

    axios
      .post('http://dev.site.com/api/forms/submit/contact?token=XXX', dataForm)
      .then((res) => {console.log(res.data)} )
      .catch((error) => {console.log(error)} );

    this.setState({
      name: '', 
      email: '', 
      message: ''
    })
  }

  render() {
    return (
      <>
        <div className="form">
          <div className="title">{this.props.title}</div> 
          <div className="content">
            <form onSubmit={this.onSubmitForm}>
              <label htmlFor="name">Your name :</label>
              <input name="name" value={this.state.name} onChange={this.onChangeName} type="text" />

              <label htmlFor="email">Your email :</label>
              <input name="email" value={this.state.email} onChange={this.onChangeEmail} type="text" />

              <label htmlFor="message">Your message :</label>
              <textarea name="message" value={this.state.message} onChange={this.onChangeMessage}></textarea>

              <input type="submit" value="Submit" />
            </form>
          </div>
        </div>
      </>
    );
  }
}

export default Form;

I tried this. But it doesn't work :

const dataForm = {
  "form": {
    __mailsubject: "test",
    name: this.state.name,
    email: this.state.email,
    message: this.state.message
    }
  };

PS: I will use later Formik and Yup to create and validate the form.

I don't see how I can achieve what I want, other than directly changing the modules/Forms/bootstrap.php file ! But this isn't a good solution because it will give me problems during updates !

The only solution is to use the form templates, like here ?

An idea ?

MarcoDaniels commented 3 years ago

Hi, I already replied this question here on Stack overflow, but here it is:

In order to update the mail subject you need to pass the value as parameter and not as form data.

On your request you should have something like:

axios
  .post('http://dev.site.com/api/forms/submit/contact?token=XXX&__mailsubject=My email subject', dataForm)
  .then((res) => {console.log(res.data)})
  .catch((error) => {console.log(error)})

The code for this can be seen at modules/Forms/Controller/RestApi.php

if ($this->param('__mailsubject')) {
   $options['subject'] = $this->param('__mailsubject');
}

This means it will only check for __mailsubject as a parameter value and not as a form data value.

MarcTabaries commented 3 years ago

Thank you for that answer. It works perfectly.

Indeed, I read this code in Cockpit:

if ($this->param('__mailsubject')) {
   $options['subject'] = $this->param('__mailsubject');
}

But the problem is that I didn't understand that "$this->params" corresponded to the parameters in the URI. I'm stupid !

I think this information should be in the official Cockpit documentation.

Anyway, thank you for your help.