2

I'm in charge of a full stack D8 (customer requirement) based project. It's mostly a Leaflet's web mapping application. The Leaflet part itself is almost done and it looks beautiful, fast and powerful. I let you know the URL once it gets released to the public.

Ahead comes a sprint ... This is the basic requirement of this phase:

  1. The map is made of several, user switched feature layers.
  2. Some of these layers receives regular updates, for instance: parties in the neighborhood announced witin the last week, two weeks and a month.
  3. The 'parties' entity is stored in several mapserver endpoints (typically a REST service throwing GeoJSON out). Each period (week, two weeks, month) have its own endpoint.
  4. Users (not Drupal users, subscribers only) draw an area in the map and 'subscribe' to the events announced on that area. By 'announced' I mean: points occurring within the user selected area.
  5. At some specific time, my application is going to check the interesting points in the user defined area to send that out to the subscriber.

I forecast lots of challenges here. This is what I came up with to this very moment:

  1. Create a content type with at least an email field and geofield support to store the points of the location area drawn by the user and her email (sort of a 'subscription backend').
  2. Compose a new view to expose these subscriptions in some serialized fashion.
  3. Code a helper script (bash, php, python) that is going to consume this D8 view and get the updated data from the mapserver endpoint.
  4. Using cron and possibly Message Stack (yeah, yeah, I know, still in dev for D8...) to deliver the message for the final recipient.

This is an example of the entire use case:

http://fires.globalforestwatch.org/map/

In the right toolbox, look for the exclamation sign icon. This is the alert function of that map. Draw a line, enter your email and bang!

There are lots of other requirements for this use case (mobile friendly html emails, screenshots of the map with the 'parties' points and previously drawn area overlaid and such), but for know I'm concerned only with the most basic functionality: to store subscribers, their location of interest and how to transform this in some useful data for their mailboxes.

So, what are your thoughts? Anybody out there already faced this task? Any tips?

I don't need code (nor rejects if you wish). Any insights on a elegant way to get things done right? Oh, the less 3rd party modules, the better. Core ones are ok.

EDIT: the new Courier module (D8 only) just came to my attention. It looks like a good contender to Message Stack in the message delivery front.

  • 1
    Thank you for the editing, @Pierre.Vriens. As a newcomer, I'm limited to the number of links. As a non-native English speaker, well... Thank you! – Deny Dias Jun 28 '16 at 19:54
  • Thank you for the thank you, you're welcome! I remember how it was to be new around here, and how you have to get used to all sorts of sometimes bizarre Rules (oeps: rules). Such as that one is not allowed to include a greeting, or just finish a question with a "thank you" (= things called "noise" around here ...). Good luck! – Pierre.Vriens Jun 28 '16 at 20:10
1

I've managed to find a solution for this one by myself. Here's how I did it.

Step 1: New Subscription and Notification

  1. Create a content type for 'alerts'. This content type features fields like: title (composed by first + last name), first name, last name, email address, alert type (party or police, for instance), status (inactive, optin, optout), plain text (no D8 Geofield module required) with two fields to store map bounding boxes, geocode name, geocode ID and subscription key.
  2. I've implemented a UI dialog in the map that interacts with the user (so she inputs a geocode search or a map draw) and the 'headless' D8.
  3. By using the wonderful D8's RESTful Web Services module, that dialog implements code to POST user input data to the alerts content type. This code is smart enough to deal with subscriptions from a geocode search or user draw, as their requirements are a bit different. It also handles form field validation according to certain business rules, takes care of the verification key generation and forwards the request via Ajax to an external, custom made email verification script.
  4. The custom made email verification script (not a D8 module, just plain PHP code with PHPMailer lib) receives the request and resolves the query string sent there. This guy takes care of query string values validation to the very same set of business rules applied to the form. If everything is fine, an email with the requested data is composed and sent to the user by using a secure SMTP. If there are errors in the query string validation (e.g. user is trying to bypass the form or fake someone), it returns with the validation step error code. At this point, the dialog in 3 above redraws itself to let the user know what have just happened (success or error code translated into human readable language).
  5. All fine up to this point, the dialog code in 3 effectively POST the new alert content and email is sent to the user. This email displays The Big Red Button™ saying something like 'Verify Now!' When a user click (or tap) on it, the second step in the process begins...

Step 2: Subscription Validation

Another custom made, plain PHP script (also totally apart of D8) is called by the last user action from the above step. This scripts also counts on D8 RESTfull powers, the amazing (Guzzle PHP HTTP Client) (*3) to perform various actions related to subscription activation. Here they are:

  1. 'Click Here To Verify' call the activation scripts with some query string (e.g. D8 node id and verification key). These are first and foremost validated do the same set of business rules we had before. Looks good? Move on. Fake? Redirect to a nice error page.
  2. A (Guzzle client) (*4) is set with enough options to make it run smooth and secure, '(cookies => true) (*5)' is among then.
  3. A (POST request to login) (*6) is fired. I've created a special user and a role just for D8's API usage. This is to prevent sneakers from the outside. Also, by having a custom made script, I can rest assured the it is always calling on localhost (127.0.0.1), so the Ops guys could set all sort of firewall, proxies and CORS rules to backend protection.
  4. We're in, GET D8's (CSFR token) (*7) for the session.
  5. (GET node content) (*8) and retrieve just the information we need to verify (e.g. status, verification key and such).
  6. Perform validation logic. Fine? Move on. Fake? Redirect to a nice error page.
  7. (PATCH node) (*9) to update the signature status.
  8. (GET logout) (*10) to finish the session, close the Guzzle client by adding header headers => [cookies => true] in this request, and some further cleanup magic.
  9. All set? Redirect user to a nice success page. Something went wrong? Catch exception and redirect to an error page.

During the whole runtime of the script, a specially crafted debug stream and a try/catch carefully listens to any exceptions. When debug is enabled, the page redirection is hold and debug information shows up so the Ops could inspect what is going on behind the scenes.

Well, it doesn't stop there. There are still the optout and the subscription delivery features. However, the above works pretty well as a base for all the remaining steps.

For the sake of completeness to the OP question, the above looks pretty elegant to me (i.e. decoupled, maintainable, secure) and uses no 3rd party D8 modules at all, just the core ones. As a plus, the custom scripts are implement relying on well maintained, open source projects.

For moderators:

Please add the URLs bellow to the places their belong in the text above to as I'm in lack of reputation to do so.

*3 http://guzzlephp.org/
*4 http://docs.guzzlephp.org/en/latest/quickstart.html#making-a-request
*5 http://docs.guzzlephp.org/en/latest/quickstart.html#cookies
*6 http://dropbucket.org/node/6743
*7 https://api.drupal.org/api/drupal/core%21lib%21Drupal.php/function/Drupal%3A%3AcsrfToken/8.1.x
*8 https://www.drupal.org/documentation/modules/rest/get
*9 https://www.drupal.org/documentation/modules/rest/patch
*10 https://www.drupal.org/documentation/modules/rest/javascript

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.