Answers.Body: <p>Very creative!</p>
  <p>You probably already noticed that since you have no means of authentication, a malicious user could set everyone else's answer to their preferred answer just by trying out every userId in the URL (a process that could be automated very easily with <code>wget</code>).</p>
  <p>To give at least a little bit of protection you could ask them to fill in their email address, and on submit it checks to see if it matches the one you're expecting.</p>
  <p>If you want to do it without the effort of a manual form submission you could include a hashed version of their email address as another URL parameter, and then check that it matches the hashed version you're expecting in the template. See <code>encenc</code> Twig filter for example: <a href="https://craftcms.com/docs/3.x/dev/filters.html#encenc" rel="nofollow noreferrer">https://craftcms.com/docs/3.x/dev/filters.html#encenc</a></p>
  <p>A couple of other warnings here too:</p>
  <ol>
  <li><p>You're basically opening up public write-access to your database here. Your conditional checks in the template mitigate the impact of this at the moment (the DB writes only happen if a user ID exists and with no previously selected answer), so for now at least that's ok, but if you make any changes/additions you need to be careful that you don't accidentally make it so that someone can write a script that infinitely writes to your DB. (You could also add a conditional check that <code>entry</code> exists after attempting to fetch it).</p>
  </li>
  <li><p>When saving confidential data into entries, be careful not to accidentally expose that data in e.g., public sitemaps or internal keyword searches etc. Also be sure to no-index the page so it doesn't get hit by search bots.</p>
  </li>
  </ol>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-06-10T12:53:38.163Z
Answers.Text: Thanks James! Very insightful remarks.
  I've implemented your suggestions to increase security.
  Even installed a fresh craft instance on a subdomain with no public facing pages to separate survey data from the actual site content.
Answers.UserDisplayName: MetaMachine
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-06-09T09:06:19.167Z
Answers.LastActivityDate: 2022-06-09T09:21:08.200Z
Answers.LastEditDate: 2022-06-09T09:21:08.200Z
Answers.UserDisplayName: James Smith
Body: <p>I need to send a simple (one-off) survey to users and capture their answer in the most unobstructive way. It's one question with a yes/no answer.</p>
  <p>Setting up mailchimp(or other service) seems overkill, so I figured I can just use craft.</p>
  <p>Would there be any downsides/potential problems doing it this way.</p>
  <ol>
  <li><p>I create a new section and import (with feedme) each email as an
  entry, I also assign a unique id to each email.
  <a href="https://i.sstatic.net/B4pUH.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/B4pUH.png" alt="enter image description here" /></a></p>
  </li>
  <li><p>Then, I would send an email with yes / no buttons that have a link
  with the answer as a query string, like this
  <code>https://www.domain.com/survey?userid=456&amp;answer=no</code> or</p>
  <p><code>https://www.domain.com/survey?userid=456&amp;answer=yes</code></p>
  </li>
  <li><p>The entry template has this code that updates the answer field upon visiting the page using the <a href="https://craft-docs.netlify.app/docs/3.x/dev/functions.html#configure" rel="nofollow noreferrer">configure function</a>.</p>
  </li>
  </ol>
  <pre><code>{# set the custom user id from the querystring #}
  {% set userId = craft.app.request.getParam('userid') %}
  
  {# set the answer from the querystring #}
  {% set answer = craft.app.request.getParam('answer') %}
      
  {% if userId is not null %}
    {% set entry = craft.entries
        .section('survey')
        .surveyUserId(userId)
        .one() %}
      
      {# Check if the answer field is empty #}
      {% if entry.surveyAnswer is empty %}
      
        {% if answer == 'yes' %}
          {% do configure(entry, { surveyAnswer: 'Yes' }) %}
          {% do craft.app.elements.saveElement(entry) %}
        {% endif %}
      
        {% if answer == 'no' %}
          {% do configure(entry, { surveyAnswer: 'No' }) %}
          {% do craft.app.elements.saveElement(entry) %}
        {% endif %}
                          
      {% else %}
        It seems you've already submitted your answer.
      {% endif %}
      
  {% else %}
      No user id defined
  {% endif %}
  </code></pre>
  
Tags: <frontend><saveentry>
Title: Saving entry on page visit using craft 'configure' function
ThreadText: # Saving entry on page visit using craft 'configure' function
  
  (Asked by: username_0 on 2022-06-09)
  
  I need to send a simple (one-off) survey to users and capture their answer in the most unobstructive way. It's one question with a yes/no answer.
  
  Setting up mailchimp(or other service) seems overkill, so I figured I can just use craft.
  
  Would there be any downsides/potential problems doing it this way.
  
  1. I create a new section and import (with feedme) each email as an
     entry, I also assign a unique id to each email.
     [![enter image description here](https://i.sstatic.net/B4pUH.png)](https://i.sstatic.net/B4pUH.png)
  2. Then, I would send an email with yes / no buttons that have a link
     with the answer as a query string, like this
     `https://www.domain.com/survey?userid=456&answer=no` or
  
     `https://www.domain.com/survey?userid=456&answer=yes`
  3. The entry template has this code that updates the answer field upon visiting the page using the [configure function](https://craft-docs.netlify.app/docs/3.x/dev/functions.html#configure).
  
  ```
  {# set the custom user id from the querystring #}
  {% set userId = craft.app.request.getParam('userid') %}
  
  {# set the answer from the querystring #}
  {% set answer = craft.app.request.getParam('answer') %}
      
  {% if userId is not null %}
    {% set entry = craft.entries
        .section('survey')
        .surveyUserId(userId)
        .one() %}
      
      {# Check if the answer field is empty #}
      {% if entry.surveyAnswer is empty %}
      
        {% if answer == 'yes' %}
          {% do configure(entry, { surveyAnswer: 'Yes' }) %}
          {% do craft.app.elements.saveElement(entry) %}
        {% endif %}
      
        {% if answer == 'no' %}
          {% do configure(entry, { surveyAnswer: 'No' }) %}
          {% do craft.app.elements.saveElement(entry) %}
        {% endif %}
                          
      {% else %}
        It seems you've already submitted your answer.
      {% endif %}
      
  {% else %}
      No user id defined
  {% endif %}
  
  ```
  
  **Tags:** frontend, saveentry
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2022-06-09. Score: 1 | Accepted answer
  
  Very creative!
  
  You probably already noticed that since you have no means of authentication, a malicious user could set everyone else's answer to their preferred answer just by trying out every userId in the URL (a process that could be automated very easily with `wget`).
  
  To give at least a little bit of protection you could ask them to fill in their email address, and on submit it checks to see if it matches the one you're expecting.
  
  If you want to do it without the effort of a manual form submission you could include a hashed version of their email address as another URL parameter, and then check that it matches the hashed version you're expecting in the template. See `encenc` Twig filter for example: <https://craftcms.com/docs/3.x/dev/filters.html#encenc>
  
  A couple of other warnings here too:
  
  1. You're basically opening up public write-access to your database here. Your conditional checks in the template mitigate the impact of this at the moment (the DB writes only happen if a user ID exists and with no previously selected answer), so for now at least that's ok, but if you make any changes/additions you need to be careful that you don't accidentally make it so that someone can write a script that infinitely writes to your DB. (You could also add a conditional check that `entry` exists after attempting to fetch it).
  2. When saving confidential data into entries, be careful not to accidentally expose that data in e.g., public sitemaps or internal keyword searches etc. Also be sure to no-index the page so it doesn't get hit by search bots.
  
  > **Comments:**
  > **username_0**: Thanks username_1! Very insightful remarks. I've implemented your suggestions to increase security. Even installed a fresh craft instance on a subdomain with no public facing pages to separate survey data from the actual site content.  
  
  ---
  
  