Versionen im Vergleich

Schlüssel

  • Diese Zeile wurde hinzugefügt.
  • Diese Zeile wurde entfernt.
  • Formatierung wurde geändert.
Hinweis

WIP

Beispiel-App im gitext ablegen, dann die essentiellen Teile hier hereinkopieren.

Goal: Send a Newsletter that is based on a Mailing Template but also contains content that is dynamically gathered and rendered with CSE.https://gitext.pinuts.de/

Info

You can download the whole Kickstarter-based sample application from our GitLab repository: um-public/tutorial-dynamic-newsletter-content

...

Start a new Kickstarter project

Codeblock
languagebash
umkickstarter -n de.pinuts.tutorial
cd umkickstarter
# Copy your partner license file to env/devel/cmsbs-conf/cmsbs.license
gradle setup run

Create Newsletter Template

Login to http://localhost:8080/cmsbs as admin / admin and create a new Newsletter Template named offerlist-nl with the following HTML body:

Codeblock
Dear {firstname},

your top offers for today:

{withcse:renderOfferList:}

Implement RenderEntryCallback

Implement a new RenderEntryCall method that will be called by the withcse directive from within the Newsletter Template just created.

This method should return true to indicate that the string in this.value should be rendered into the newsletter body.

cmsbs-conf/cse/plugins/de.pinuts.tutorial/callback/RenderEntryCallback.es6:

Codeblock
languagejs
/// <reference path="../../../.vscode.js"/>

import faker from "@de.pinuts.demodata/shared/faker.es6";

function renderOffers(offers) {
    return `<ul>${offers.map(renderOffer).join('')}</ul>`;
}

function renderOffer(offer) {
    return (
    `<li style="margin-bottom: 8px">
        <strong>${Strings.encodeXml(offer.productName)}</strong><br/>
        ${Strings.encodeXml(offer.price)}
    </li>`);
}

function fakeOffers() {
    const offers = [];
    const num = faker.random.number({min: 0, max: 5});

    for (let idx = 0; idx < num; idx++) {
        offers.push({
            productName: faker.commerce.productName(),
            price: faker.commerce.price(10, 100, 2, '€')
        });
    }

    return offers;
}


RenderEntryCallback.prototype.renderOfferList = function() {
    const offers = fakeOffers();

    this.templateContext.doSend = offers.length > 0;
     this.value = renderOffers(offers);

    return true;
}

Install DemoData plugin

To generate some random content we use the DemoData plugin. Include the dependency into your build.gradle file and run gradle setup run once more:

Codeblock
languagegroovy
...
dependencies {
    runtime('de.pinuts.cmsbs:UM:7.34.1')
    runtime('de.pinuts.cmsbs:TestDriver2:2.0.6')
    runtime('de.pinuts.cmsbs:DemoData:1.0.4')
}
...

Send Newsletter manually

Now manually create a List named offerlist and some Entries with email addresses that are subscribed to that list.

Send a Newsletter manually based on the template created earlier.

Goto Tools / Mail Log to verify that emails have been sent and actually do contain the dynamically generated content.

Send Newsletter programmatically

If you also want to start sending the above Newsletter programmatically – i.e. by a Cronjob – you can create an EventFile and trigger sending with the following code snippet.

cmsbs-conf/cse/plugins/de.pinuts.tutorial/shared/SendOfferListNewsletter.es6:

Codeblock
languagejs
/// <reference path="../../../.vscode.js"/>

const MAILING_TEMPLATE_NAME = 'offerlist-nl';
const CHANNEL_NAME = 'offerlist';
const NEWSLETTER_TAG = 'offerlist';

function createEventFile() {
    return `<event archive="true">
        <destination>
            <channel>${Strings.encodeXml(CHANNEL_NAME)}</channel>
        </destination>
        <data>
            <message>${Strings.encodeXml(MAILING_TEMPLATE_NAME)}</message>
            <email archiveOutgoingEmails="false" obeyPreferHtml="false" sendBothParts="false" trackingMode="Off"></email>
        </data>
        <tag>${Strings.encodeXml(NEWSLETTER_TAG)}</tag>
    </event>`;
}

export function run() {
    UM.println('Preparing newsletter...');

    const eventFile = createEventFile();
    UM.newsletterArchive.send(eventFile);
}

de.pinuts.tutorial.sendNewsletter = run;

Codeblock
languagejs
/// <reference path="../../../.vscode.js"/>

function createEventFile(channelName, mailingTemplateId, content) {
    return `<event archive="true">
        <destination>
            <channel>${channelName}</channel>
        </destination>
        <global special="content" trim="true">
            ${Strings.encodeXml(content)}
        </global>
        <data>
            <message>${mailingTemplateId}</message>
            <email archiveOutgoingEmails="false" obeyPreferHtml="false" sendBothParts="false" trackingMode="Off"></email>
        </data>
        <tag>${NEWSLETTER_TAG}</tag>
    </event>`;
}

function renderOfferList(offers) {
    return `<ul>${offers.map(renderOffer).join('')}</ul>`;
}

function renderOffer(offer) {
    const companyPlace = [];
    if (offer.company) companyPlace.push(Strings.encodeXml(offer.company));
    if (offer.city) companyPlace.push(Strings.encodeXml(offer.city));

    return (
    `<li style="margin-bottom: 8px">
        <strong>${Strings.encodeXml(offer.title)}</strong><br/>
        ${companyPlace.join(', ')}
    </li>`
    );
}

export function run() {
        const channelName = NEWSLETTER_LIST_NAME_PREFIX + portal;
        const mailingTemplateId = MAILING_TEMPLATE_ID_PREFIX + portal;

        const offers = JobOffer.list({
            status: 'p',
            portal,
            orderBy: 'jobofferFirstPublishedAt desc',
            max: 35,
            publishedAfter: getLastSendDate()
        });

        if (offers.length > 0) {
            UM.println(`Bereite Newsletter für Portal '${portal}' vor: ${offers.length} Angebote.`);

            const content = renderOfferList(offers);
            const eventFile = createEventFile(channelName, mailingTemplateId, content);

            UM.newsletterArchive.send(eventFile);
        } else {
            UM.println(`Keine Angebote in Portal '${portal}'.`);
        }
}

RenderEntryCallback:

...

languagejs

...

Having done that you can create a CSE: Call Cronjob to periodically call de.pinuts.tutorial.sendNewsletter().