diff --git a/.gitignore b/.gitignore index 92624863..828494f8 100644 --- a/.gitignore +++ b/.gitignore @@ -158,4 +158,4 @@ dmypy.json # Cython debug symbols cython_debug/ -# End of https://www.toptal.com/developers/gitignore/api/python,jupyternotebooks +# End of https://www.toptal.com/developers/gitignore/api/python,jupyternotebooks \ No newline at end of file diff --git a/docs/campaigns/exporting_campaigns.rst b/docs/campaigns/exporting_campaigns.rst new file mode 100644 index 00000000..c26e57ee --- /dev/null +++ b/docs/campaigns/exporting_campaigns.rst @@ -0,0 +1,123 @@ +.. vale off + +Exporting Campaigns +################### + +.. vale on + +Before importing or exporting data, as a safety precaution take a backup of your database so that you can restore data if required. Speak to the administrator of your domain to be able to do this as it requires specific technical knowledge. + +.. important:: + Both the import and the export features are only available in Mautic 7.0 and later versions. + +Supported data types +-------------------- + +When you select a Campaign, the export feature extracts all Campaign data and entities and any dependencies the Campaign needs to function. This includes: + + - Dynamic Content + - Assets + - Custom Fields + - Other related dependencies + +The export command: + + - Detect use of Plugins and Custom Fields + - Include the data to support these dependencies + +.. important:: + The importing instance needs the same Custom Fields and Plugins to be present. + +.. vale off + +How exporting Campaigns works +***************************** + +.. vale on + +Whether exporting via the UI, the command line or using the API, the Export feature +follows the same process. + + - Checks that the User has adequate permissions to export + - Supports exporting multiple Campaigns simultaneously + - Exports data in a structured JSON format + - Exports Assets into a separate folder in their original format + - Zips the resulting collection of files for easy transfer across systems + +Export methods +************** + +You can use the Export feature in three ways: + +UI-based export +--------------- + +Manual export through Mautic Campaigns dashboard: + +# Go to the Campaigns menu +# Select the Campaign you want to Export +# Select the Export option from the dropdown menu located next to the item selection + +CLI-based export +---------------- + +Use the following commands: + +.. code-block:: bash + + bin/console mautic:entity:export --entity=campaign --id=1 --zip-file --path=path/to-file + +* `entity` defines the type of entity to Export, in this case `campaign` +* `id` defines the id of the Campaign to Export. Look at the URL to find the ID when you view or edit the Campaign - the ID appears in the URL for example, ``/s/campaigns/view/123`` where 123 is the ID +* `zip-file` creates a zip file of the Campaign and its dependencies +* `path` specifies the directory to save the exported file. + +.. code-block:: bash + + bin/console mautic:entity:export --entity=campaign --id=1 --json-file + +* Creates only a JSON file and ignores any additional resources + +API-based export +---------------- + +You can export Campaigns programmatically using the Mautic API. You need to authenticate for the API request. using the API credentials stored in Mautic's settings. For more detail on how to authenticate, see the :doc:`Mautic API documentation authentication/authentication.html`. + +Curl example +************ + +.. code-block:: bash + + curl --location 'https://{your-mautic-domain}/api/campaigns/export/1' \ + --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ + --data '' + +Python example +************** + +.. code-block:: python + + import requests + + # API Endpoint + campaign_id = 1 + url = f'https://example.com/api/campaigns/export/{campaign_id}' + + # Authentication + headers = { + 'Authorization': 'Bearer YOUR_ACCESS_TOKEN' + } + + # Send export request + response = requests.get(url, headers=headers) + + # Handle response + if response.status_code == 200: + export_file = response.content + # Save or process the exported campaign + +.. important:: + - Replace `example.com` with your actual Mautic instance domain + - Replace `YOUR_ACCESS_TOKEN` with a valid authentication token + - The API uses a GET request to export a specific Campaign by ID + - Ensure you have the necessary API permissions diff --git a/docs/campaigns/images/activate-campaign.png b/docs/campaigns/images/activate-campaign.png new file mode 100644 index 00000000..064b5de2 Binary files /dev/null and b/docs/campaigns/images/activate-campaign.png differ diff --git a/docs/campaigns/images/campaign-sample.json b/docs/campaigns/images/campaign-sample.json new file mode 100644 index 00000000..e8a54b30 --- /dev/null +++ b/docs/campaigns/images/campaign-sample.json @@ -0,0 +1,573 @@ +[ + { + "campaign": [ + { + "id": 3, + "name": "Sample campaign file", + "description": "", + "is_published": false, + "canvas_settings": { + "nodes": [ + { + "id": 5, + "positionX": "379", + "positionY": "159" + }, + { + "id": 7, + "positionX": "772", + "positionY": "155" + }, + { + "id": 8, + "positionX": "73", + "positionY": "158" + }, + { + "id": 9, + "positionX": "506", + "positionY": "408" + }, + { + "id": 6, + "positionX": "213", + "positionY": "263" + }, + { + "id": "lists", + "positionX": "653", + "positionY": "53" + }, + { + "id": "forms", + "positionX": "947", + "positionY": "51" + } + ], + "connections": [ + { + "sourceId": "lists", + "targetId": 5, + "anchors": { + "source": "leadsource", + "target": "top" + } + }, + { + "sourceId": 5, + "targetId": 6, + "anchors": { + "source": "yes", + "target": "top" + } + }, + { + "sourceId": "lists", + "targetId": 7, + "anchors": { + "source": "leadsource", + "target": "top" + } + }, + { + "sourceId": "lists", + "targetId": 8, + "anchors": { + "source": "leadsource", + "target": "top" + } + }, + { + "sourceId": "lists", + "targetId": 9, + "anchors": { + "source": "leadsource", + "target": "top" + } + }, + { + "sourceId": "lists", + "targetId": "forms", + "anchors": { + "source": "leadsourceright", + "target": "leadsourceleft" + } + } + ] + }, + "uuid": "b4ddc4d7-149e-4a81-9141-0e03c598627a" + } + ], + "campaign_event": [ + { + "id": 5, + "campaign_id": 3, + "name": "Downloads asset", + "description": "", + "type": "asset.download", + "event_type": "decision", + "event_order": 1, + "properties": { + "canvasSettings": { + "droppedX": "313", + "droppedY": "158" + }, + "name": "", + "anchor": "leadsource", + "properties": { + "assets": [ + 2 + ] + }, + "type": "asset.download", + "eventType": "decision", + "anchorEventType": "source", + "campaignId": "3", + "_token": "0.oKNciNUEGsLHNnAw81-PkskwW94qK_8ClWqMXITDlz4.k5ZuwZo1VY6kZz5jvS-4-bNUD4h5ToVr3wHOa-OHp2mQ0xHfozNsiPIAGw", + "buttons": { + "save": "" + }, + "triggerDate": null, + "assets": [ + 2 + ] + }, + "trigger_interval": 0, + "trigger_interval_unit": "", + "trigger_mode": "", + "triggerDate": null, + "channel": "asset", + "channel_id": 2, + "parent_id": null, + "uuid": "2ea825c4-6086-4ec8-b355-44f7355d4bc0" + }, + { + "id": 7, + "campaign_id": 3, + "name": "Request dynamic content", + "description": "", + "type": "dwc.decision", + "event_type": "decision", + "event_order": 1, + "properties": { + "canvasSettings": { + "droppedX": "553", + "droppedY": "158" + }, + "name": "", + "anchor": "leadsource", + "properties": { + "dwc_slot_name": "test", + "dynamicContent": 1 + }, + "type": "dwc.decision", + "eventType": "decision", + "anchorEventType": "source", + "campaignId": "3", + "_token": "04feb2c5a9.SYXSFiT87s-Zw_AIqYLsKEyHuLu3w2dVy9oma5rraFw.GsjjfWq5r6LBgrl-2NO-ay7_7PmOkh8ls7QeIN2xKR0Yt4g7c5KPqfyklw", + "buttons": { + "save": "" + }, + "triggerDate": null, + "dwc_slot_name": "test", + "dynamicContent": 1 + }, + "trigger_interval": 0, + "trigger_interval_unit": "", + "trigger_mode": "", + "triggerDate": null, + "channel": "dynamicContent", + "channel_id": 1, + "parent_id": null, + "uuid": "21ec254c-68d5-4675-aae0-4d698676a9ce" + }, + { + "id": 8, + "campaign_id": 3, + "name": "Visits a page", + "description": "", + "type": "page.pagehit", + "event_type": "decision", + "event_order": 1, + "properties": { + "canvasSettings": { + "droppedX": "73", + "droppedY": "158" + }, + "name": "", + "anchor": "leadsource", + "properties": { + "pages": [ + 1 + ], + "url": "", + "referer": "" + }, + "type": "page.pagehit", + "eventType": "decision", + "anchorEventType": "source", + "campaignId": "3", + "_token": "5f8ffc233728216b01c925d3b1.-S7eUs8NTLUMFt8d0pR5J8yCaeCdnLbL4RAthmMKL8U.qmPvOYFIDdhUV5Zro8UrZK76PaKkzc67mX4VzSRQboSoHIR_mGMt02lxuA", + "buttons": { + "save": "" + }, + "triggerDate": null, + "pages": [ + 1 + ], + "url": null, + "referer": null + }, + "trigger_interval": 0, + "trigger_interval_unit": "", + "trigger_mode": "", + "triggerDate": null, + "channel": "page", + "channel_id": 1, + "parent_id": null, + "uuid": "2a29709f-0cf7-435e-afab-aff130965789" + }, + { + "id": 9, + "campaign_id": 3, + "name": "test", + "description": "", + "type": "lead.points", + "event_type": "condition", + "event_order": 1, + "properties": { + "canvasSettings": { + "droppedX": "10", + "droppedY": "263" + }, + "name": "test", + "triggerMode": "immediate", + "triggerDate": null, + "triggerInterval": "1", + "triggerIntervalUnit": "d", + "triggerHour": "", + "triggerRestrictedStartHour": "", + "triggerRestrictedStopHour": "", + "triggerWindow": "0", + "anchor": "leadsource", + "properties": { + "operator": "=", + "score": "1111", + "group": "1" + }, + "type": "lead.points", + "eventType": "condition", + "anchorEventType": "source", + "campaignId": "3", + "_token": "91d612e76a6bf.bDrd_GtYJSCQAa8oNqzeGhljlPlKZ9gy66WBo3Qer08.P3fslyUdZE3IQOZeR_2MWXsbwLtzNqBCk8u56DNE7g49CIfRPDZERvVmyA", + "buttons": { + "save": "" + }, + "operator": "=", + "score": 1111, + "group": 1 + }, + "trigger_interval": 1, + "trigger_interval_unit": "d", + "trigger_mode": "immediate", + "triggerDate": null, + "channel": "", + "channel_id": 0, + "parent_id": null, + "uuid": "bc70df3e-7d49-4d12-b6ad-992f1e3205a4" + }, + { + "id": 6, + "campaign_id": 3, + "name": "test", + "description": "", + "type": "email.send", + "event_type": "action", + "event_order": 2, + "properties": { + "canvasSettings": { + "droppedX": "213", + "droppedY": "263" + }, + "name": "test", + "triggerMode": "immediate", + "triggerDate": null, + "triggerInterval": "1", + "triggerIntervalUnit": "d", + "triggerHour": "", + "triggerRestrictedStartHour": "", + "triggerRestrictedStopHour": "", + "triggerWindow": "0", + "anchor": "yes", + "properties": { + "email": 1, + "email_type": "marketing", + "priority": "2", + "attempts": "3" + }, + "type": "email.send", + "eventType": "action", + "anchorEventType": "decision", + "campaignId": "3", + "_token": "fa386d8.ZuglYE5nMxIig26ZT_ooaIBQV5jFhTurjLKYxG0W_dM.NaUUCwAicn96wifvPqt6K-IoA9r81EPb9NygjypMvJI32n9NGQlSdEfkCQ", + "buttons": { + "save": "" + }, + "email": 1, + "email_type": "marketing", + "priority": 2, + "attempts": 3 + }, + "trigger_interval": 1, + "trigger_interval_unit": "d", + "trigger_mode": "immediate", + "triggerDate": null, + "channel": "email", + "channel_id": 1, + "parent_id": 5, + "uuid": "63077b6b-800b-4ed1-88ca-3267e3012947" + } + ], + "asset": [ + { + "id": 2, + "is_published": true, + "title": "stesetste", + "description": null, + "alias": "stesetste", + "storage_location": "local", + "path": "e2ac32c7d50379f5df60cc43d1e7181fa5e94ab9.png", + "remote_path": null, + "original_file_name": "icon_128x128.png", + "lang": "en", + "publish_up": null, + "publish_down": null, + "extension": "png", + "mime": "image\/png", + "size": 10, + "disallow": true, + "uuid": "21a5c18a-3c34-4871-92c1-b698eb5ac80f" + } + ], + "dynamicContent": [ + { + "id": 1, + "translation_parent_id": null, + "variant_parent_id": null, + "is_published": true, + "name": "test", + "description": null, + "publish_up": null, + "publish_down": null, + "content": null, + "utm_tags": { + "utmSource": null, + "utmMedium": null, + "utmCampaign": null, + "utmContent": null + }, + "lang": "en", + "variant_settings": [], + "variant_start_date": null, + "filters": [], + "is_campaign_based": true, + "slot_name": "", + "uuid": "107ac8a2-ec01-4ea9-88e8-80d24e2a63bc" + } + ], + "page": [ + { + "id": 1, + "is_published": true, + "title": "test page", + "alias": "test-page", + "template": "blank", + "custom_html": "\r\n \r\n {pagetitle}<\/title>\r\n <meta name=\"description\" content=\"{pagemetadescription}\" \/>\r\n \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n <\/head><body><div data-section-wrapper=\"1\"><center><table data-section=\"1\" width=\"600\" cellpadding=\"0\" cellspacing=\"0\" id=\"iuuk\"><tbody><tr><td><div data-slot-container=\"1\" id=\"i70n\"><div data-slot=\"text\"><br \/><h2>Hello there!<\/h2><br \/>\r\n We haven't heard from you for a while...\r\n <br \/><br \/><br \/><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/center><\/div><style>#iuuk{width:600;}#i70n{min-height:30px;}<\/style><\/body><\/html>", + "content": [], + "publish_up": null, + "publish_down": null, + "hits": 0, + "unique_hits": 0, + "variant_hits": 0, + "revision": 6, + "meta_description": null, + "head_script": null, + "footer_script": null, + "redirect_type": null, + "redirect_url": null, + "is_preference_center": false, + "no_index": false, + "lang": "en", + "variant_settings": [], + "uuid": "401fbafc-707e-44d8-87c2-3f823f17546b" + } + ], + "pointGroup": [ + { + "id": 1, + "name": "test", + "description": null, + "is_published": true, + "uuid": "895c3582-99d7-4174-bb2b-e33a38324882" + } + ], + "email": [ + { + "id": 1, + "translation_parent_id": null, + "variant_parent_id": null, + "unsubscribeform_id": null, + "preference_center_id": null, + "is_published": true, + "name": "test email 1", + "description": null, + "subject": "test", + "preheader_text": null, + "from_name": null, + "use_owner_as_mailer": false, + "template": "mautic_code_mode", + "content": [], + "utm_tags": { + "utmSource": null, + "utmMedium": null, + "utmCampaign": null, + "utmContent": null + }, + "plain_text": null, + "custom_html": "<!doctype html>\r\n<html lang=\"und\" dir=\"auto\" xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\" xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:o=\"urn:schemas-microsoft-com:office:office\">\r\n\r\n<head>\r\n <title><\/title>\r\n <!--[if !mso]><!-->\r\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\r\n <!--<![endif]-->\r\n <meta http-equiv=\"Content-Type\" content=\"text\/html; charset=UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\r\n <style type=\"text\/css\">\r\n #outlook a {\r\n padding: 0;\r\n }\r\n\r\n body {\r\n margin: 0;\r\n padding: 0;\r\n -webkit-text-size-adjust: 100%;\r\n -ms-text-size-adjust: 100%;\r\n }\r\n\r\n table,\r\n td {\r\n border-collapse: collapse;\r\n mso-table-lspace: 0pt;\r\n mso-table-rspace: 0pt;\r\n }\r\n\r\n img {\r\n border: 0;\r\n height: auto;\r\n line-height: 100%;\r\n outline: none;\r\n text-decoration: none;\r\n -ms-interpolation-mode: bicubic;\r\n }\r\n\r\n p {\r\n display: block;\r\n margin: 13px 0;\r\n }\r\n <\/style>\r\n <!--[if mso]>\r\n <noscript>\r\n <xml>\r\n <o:OfficeDocumentSettings>\r\n <o:AllowPNG\/>\r\n <o:PixelsPerInch>96<\/o:PixelsPerInch>\r\n <\/o:OfficeDocumentSettings>\r\n <\/xml>\r\n <\/noscript>\r\n <![endif]-->\r\n <!--[if lte mso 11]>\r\n <style type=\"text\/css\">\r\n .mj-outlook-group-fix { width:100% !important; }\r\n <\/style>\r\n <![endif]-->\r\n <!--[if !mso]><!-->\r\n <link href=\"https:\/\/fonts.googleapis.com\/css?family=Open+Sans:300,400,500,700\" rel=\"stylesheet\" type=\"text\/css\">\r\n <link href=\"https:\/\/fonts.googleapis.com\/css?family=Ubuntu:300,400,500,700\" rel=\"stylesheet\" type=\"text\/css\">\r\n <style type=\"text\/css\">\r\n @import url(https:\/\/fonts.googleapis.com\/css?family=Open+Sans:300,400,500,700);\r\n @import url(https:\/\/fonts.googleapis.com\/css?family=Ubuntu:300,400,500,700);\r\n <\/style>\r\n <!--<![endif]-->\r\n <style type=\"text\/css\">\r\n @media only screen and (min-width:480px) {\r\n .mj-column-px-550 {\r\n width: 550px !important;\r\n max-width: 550px;\r\n }\r\n }\r\n <\/style>\r\n <style media=\"screen and (min-width:480px)\">\r\n .moz-text-html .mj-column-px-550 {\r\n width: 550px !important;\r\n max-width: 550px;\r\n }\r\n <\/style>\r\n <!-- CSS-STYLE -->\r\n<\/head>\r\n\r\n<body style=\"word-spacing:normal;\">\r\n <div style lang=\"und\" dir=\"auto\">\r\n <!--[if mso | IE]><table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"\" role=\"presentation\" style=\"width:600px;\" width=\"600\" bgcolor=\"#ffffff\" ><tr><td style=\"line-height:0px;font-size:0px;mso-line-height-rule:exactly;\"><![endif]-->\r\n <div style=\"background:#ffffff;background-color:#ffffff;margin:0px auto;max-width:600px;\">\r\n <table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"background:#ffffff;background-color:#ffffff;width:100%;\">\r\n <tbody>\r\n <tr>\r\n <td style=\"direction:ltr;font-size:0px;padding:20px 0;text-align:center;\">\r\n <!--[if mso | IE]><table role=\"presentation\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr><td class=\"\" style=\"vertical-align:top;width:550px;\" ><![endif]-->\r\n <div class=\"mj-column-px-550 mj-outlook-group-fix\" style=\"font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;\">\r\n <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"vertical-align:top;\" width=\"100%\">\r\n <tbody>\r\n <tr>\r\n <td style=\"font-size:0px;word-break:break-word;\">\r\n <div style=\"height:20px;line-height:20px;\"> <\/div>\r\n <\/td>\r\n <\/tr>\r\n <tr>\r\n <td style=\"font-size:0px;word-break:break-word;\">\r\n <div style=\"height:20px;line-height:20px;\"> <\/div>\r\n <\/td>\r\n <\/tr>\r\n <tr>\r\n <td align=\"left\" style=\"font-size:0px;padding:10px 25px;word-break:break-word;\">\r\n <div style=\"font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:28px;font-weight:700;line-height:1;text-align:left;color:#000000;\">\r\n <p style=\"padding: 0; line-height: 1.4em; font-family: 'Open Sans', Helvetica, Arial, sans-serif; margin: 0;\">Hello World! <\/p>\r\n <\/div>\r\n <\/td>\r\n <\/tr>\r\n <tr>\r\n <td align=\"left\" style=\"font-size:0px;padding:10px 25px;word-break:break-word;\">\r\n <div style=\"font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:14px;line-height:1;text-align:left;color:#000000;\">\r\n <p style=\"padding: 0; line-height: 1.4em; font-family: 'Open Sans', Helvetica, Arial, sans-serif; margin: 0;\">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquid officia consequatur placeat reprehenderit excepturi, tempore, id quos quaerat ab fuga. <\/p>\r\n <p style=\"padding: 0; line-height: 1.4em; font-family: 'Open Sans', Helvetica, Arial, sans-serif; margin: 0;\">\r\n <br data-cke-filler=\"true\">\r\n <\/p>\r\n <p style=\"padding: 0; line-height: 1.4em; font-family: 'Open Sans', Helvetica, Arial, sans-serif; margin: 0;\">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore, voluptate. <\/p>\r\n <p style=\"padding: 0; line-height: 1.4em; font-family: 'Open Sans', Helvetica, Arial, sans-serif; margin: 0;\">\r\n <br data-cke-filler=\"true\">\r\n <\/p>\r\n <p style=\"padding: 0; line-height: 1.4em; font-family: 'Open Sans', Helvetica, Arial, sans-serif; margin: 0;\">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dignissimos alias rerum nemo ducimus modi perspiciatis. <\/p>\r\n <\/div>\r\n <\/td>\r\n <\/tr>\r\n <tr>\r\n <td style=\"font-size:0px;word-break:break-word;\">\r\n <div style=\"height:20px;line-height:20px;\"> <\/div>\r\n <\/td>\r\n <\/tr>\r\n <tr>\r\n <td align=\"left\" style=\"font-size:0px;padding:10px 25px;word-break:break-word;\">\r\n <div style=\"font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:11px;line-height:1;text-align:left;color:#6d6d6d;\">\r\n <p style=\"padding: 0; line-height: 1.4em; font-family: 'Open Sans', Helvetica, Arial, sans-serif; margin: 0;\">{unsubscribe_text} | {webview_text}<\/p>\r\n <\/div>\r\n <\/td>\r\n <\/tr>\r\n <tr>\r\n <td style=\"font-size:0px;word-break:break-word;\">\r\n <div style=\"height:20px;line-height:20px;\"> <\/div>\r\n <\/td>\r\n <\/tr>\r\n <tr>\r\n <td style=\"font-size:0px;word-break:break-word;\">\r\n <div style=\"height:20px;line-height:20px;\"> <\/div>\r\n <\/td>\r\n <\/tr>\r\n <\/tbody>\r\n <\/table>\r\n <\/div>\r\n <!--[if mso | IE]><\/td><\/tr><\/table><![endif]-->\r\n <\/td>\r\n <\/tr>\r\n <\/tbody>\r\n <\/table>\r\n <\/div>\r\n <!--[if mso | IE]><\/td><\/tr><\/table><![endif]-->\r\n <\/div>\r\n<\/body>\r\n\r\n<\/html>", + "email_type": "template", + "publish_up": null, + "publish_down": null, + "revision": 5, + "lang": "en", + "variant_settings": [], + "variant_start_date": null, + "dynamic_content": [ + { + "tokenName": "Dynamic Content 1", + "content": "Default Dynamic Content", + "filters": [ + { + "content": null, + "filters": [] + } + ] + } + ], + "headers": [], + "public_preview": false, + "uuid": "e9315582-087e-42f1-a9c5-3af468fd522c" + } + ], + "lists": [ + { + "id": 1, + "name": "Test Seg", + "is_published": true, + "description": null, + "alias": "test-seg", + "public_name": "Test Seg", + "filters": [], + "is_global": true, + "is_preference_center": false, + "uuid": "d697157e-9ae3-4600-aa2e-4a2a5a6e36e0" + } + ], + "forms": [ + { + "id": 1, + "name": "test form", + "is_published": true, + "description": null, + "alias": "test_form", + "lang": null, + "cached_html": "\n<style type=\"text\/css\" scoped>\n .mauticform_wrapper { max-width: 600px; margin: 10px auto; }\n .mauticform-innerform {}\n .mauticform-post-success {}\n .mauticform-name { font-weight: bold; font-size: 1.5em; margin-bottom: 3px; }\n .mauticform-description { margin-top: 2px; margin-bottom: 10px; }\n .mauticform-error { margin-bottom: 10px; color: red; }\n .mauticform-message { margin-bottom: 10px; color: green; }\n .mauticform-row { display: block; margin-bottom: 20px; }\n .mauticform-label { font-size: 1.1em; display: block; font-weight: bold; margin-bottom: 5px; }\n .mauticform-row.mauticform-required .mauticform-label:after { color: #e32; content: \" *\"; display: inline; }\n .mauticform-helpmessage { display: block; font-size: 0.9em; margin-bottom: 3px; }\n .mauticform-errormsg { display: block; color: red; margin-top: 2px; }\n .mauticform-selectbox, .mauticform-input, .mauticform-textarea { width: 100%; padding: 0.5em 0.5em; border: 1px solid #CCC; background: #fff; box-shadow: 0px 0px 0px #fff inset; border-radius: 4px; box-sizing: border-box; }\n .mauticform-checkboxgrp-row {}\n .mauticform-checkboxgrp-label { font-weight: normal; }\n .mauticform-checkboxgrp-checkbox {}\n .mauticform-radiogrp-row {}\n .mauticform-radiogrp-label { font-weight: normal; }\n .mauticform-radiogrp-radio {}\n .mauticform-button-wrapper .mauticform-button.btn-ghost, .mauticform-pagebreak-wrapper .mauticform-pagebreak.btn-ghost { color: #5d6c7c;background-color: #ffffff;border-color: #dddddd;}\n .mauticform-button-wrapper .mauticform-button, .mauticform-pagebreak-wrapper .mauticform-pagebreak { display: inline-block;margin-bottom: 0;font-weight: 600;text-align: center;vertical-align: middle;cursor: pointer;background-image: none;border: 1px solid transparent;white-space: nowrap;padding: 6px 12px;font-size: 13px;line-height: 1.3856;border-radius: 3px;-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;}\n .mauticform-button-wrapper .mauticform-button.btn-ghost[disabled], .mauticform-pagebreak-wrapper .mauticform-pagebreak.btn-ghost[disabled] { background-color: #ffffff; border-color: #dddddd; opacity: 0.75; cursor: not-allowed; }\n .mauticform-pagebreak-wrapper .mauticform-button-wrapper { display: inline; }\n\n \/* Make fields display inline when using width classes *\/\n .mauticform-page-wrapper {\n display: flex;\n flex-wrap: wrap;\n width: 100%;\n margin: 0 -10px;\n }\n\n \/* Ensure field containers respect width classes *\/\n .mauticform-row {\n box-sizing: border-box;\n padding: 0 10px;\n margin-bottom: 15px;\n }\n\n \/* Responsive adjustment for mobile *\/\n @media (max-width: 767px) {\n .mauticform-three-quarters-width,\n .mauticform-two-thirds-width,\n .mauticform-half-width,\n .mauticform-one-third-width,\n .mauticform-one-quarter-width {\n width: 100%;\n }\n }\n\n \/**\n * @see https:\/\/github.com\/TarekRaafat\/autoComplete.js\/blob\/master\/dist\/css\/autoComplete.02.css.\n *\/\n .autoComplete_wrapper {position: relative;}\n .autoComplete_wrapper > input::placeholder {transition: all 0.3s ease;}\n .autoComplete_wrapper > ul {position: absolute;max-height: 226px;overflow-y: scroll;top: 100%;left: 0;right: 0;padding: 0;margin: 0.5rem 0 0 0;border-radius: 4px;background-color: #fff;border: 1px solid rgba(33, 33, 33, 0.1);z-index: 1000;outline: none;}\n .autoComplete_wrapper > ul > li {padding: 10px 20px;list-style: none;text-align: left;font-size: 16px;color: #212121;transition: all 0.1s ease-in-out;border-radius: 3px;background-color: rgba(255, 255, 255, 1);white-space: nowrap;overflow: hidden;text-overflow: ellipsis;transition: all 0.2s ease;}\n .autoComplete_wrapper > ul > li > span {float: right;}\n .autoComplete_wrapper > ul > li::selection {color: rgba(#ffffff, 0);background-color: rgba(#ffffff, 0);}\n .autoComplete_wrapper > ul > li:hover {cursor: pointer;background-color: rgba(123, 123, 123, 0.1);}\n .autoComplete_wrapper > ul > li mark {background-color: transparent;font-weight: bold;}\n .autoComplete_wrapper > ul > li mark::selection {background-color: rgba(#ffffff, 0);}\n .autoComplete_wrapper > ul > li[aria-selected=\"true\"] {background-color: rgba(123, 123, 123, 0.1);}\n @media only screen and (max-width: 600px) {\n .autoComplete_wrapper > input {width: 18rem;}\n }\n<\/style>\n\n<style type=\"text\/css\" scoped>\n .mauticform-field-hidden { display:none }\n<\/style>\n<div id=\"mauticform_wrapper_testform\" class=\"mauticform_wrapper\">\n <form autocomplete=\"false\" role=\"form\" method=\"post\" action=\"https:\/\/mautic.ddev.site\/form\/submit?formId=1\" id=\"mauticform_testform\" data-mautic-form=\"testform\" enctype=\"multipart\/form-data\" ><div class=\"mauticform-error\" id=\"mauticform_testform_error\"><\/div>\n <div class=\"mauticform-message\" id=\"mauticform_testform_message\"><\/div><div class=\"mauticform-innerform\">\n <div class=\"mauticform-page-wrapper mauticform-page-1\" data-mautic-form-page=\"1\" >\n \n \n \n \n \n\n<div id=\"mauticform_testform_submit\"class=\"mauticform-row mauticform-button-wrapper mauticform-field-1\"style=\"width: 100%\">\n <button class=\"btn btn-ghost mauticform-button\"name=\"mauticform[submit]\"value=\"1\"id=\"mauticform_input_testform_submit\"type=\"submit\">Submit<\/button>\n<\/div>\n <\/div><\/div><input type=\"hidden\" name=\"mauticform[formId]\" id=\"mauticform_testform_id\" value=\"1\"\/>\n <input type=\"hidden\" name=\"mauticform[return]\" id=\"mauticform_testform_return\" value=\"\"\/>\n <input type=\"hidden\" name=\"mauticform[formName]\" id=\"mauticform_testform_name\" value=\"testform\"\/>\n \n <\/form>\n<\/div>\n", + "post_action": "return", + "template": null, + "form_type": "campaign", + "render_style": true, + "post_action_property": null, + "form_attr": null, + "uuid": "c98d1a1b-1a12-4931-bb4d-3583394cd573" + } + ], + "form_fields": [ + { + "id": 1, + "uuid": "74f101ad-94b6-4013-bd7d-9dbba719637a", + "label": "Submit", + "show_label": true, + "alias": "submit", + "type": "button", + "is_custom": false, + "custom_parameters": [], + "default_value": null, + "is_required": false, + "validation_message": null, + "help_message": null, + "field_order": 1, + "properties": [], + "validation": [], + "parent_id": null, + "conditions": [], + "label_attr": null, + "input_attr": "class=\"btn btn-ghost\"", + "container_attr": null, + "save_result": true, + "is_auto_fill": false, + "show_when_value_exists": null, + "show_after_x_submissions": null, + "mapped_object": null, + "mapped_field": null, + "form": 1 + } + ], + "dependencies": [ + { + "campaign_event": [ + { + "campaign": 3, + "campaign_event": 5, + "asset": 2 + }, + { + "campaign": 3, + "campaign_event": 7, + "dynamicContent": 1 + }, + { + "campaign": 3, + "campaign_event": 8, + "page": 1 + }, + { + "campaign": 3, + "campaign_event": 9, + "pointGroup": 1 + }, + { + "campaign": 3, + "campaign_event": 6, + "email": 1 + } + ], + "lists": [ + { + "campaign": 3, + "lists": 1 + } + ], + "forms": [ + { + "forms": 1, + "form_fields": 1 + }, + { + "campaign": 3, + "forms": 1 + } + ] + } + ] + } +] diff --git a/docs/campaigns/importing_campaigns.rst b/docs/campaigns/importing_campaigns.rst new file mode 100644 index 00000000..75835fe8 --- /dev/null +++ b/docs/campaigns/importing_campaigns.rst @@ -0,0 +1,173 @@ +.. vale off + +Importing Campaigns +################### + +.. vale on + +The Import feature allows you to add pre-configured Campaigns to your Mautic instance using zip files containing all the relevant data to construct a Campaign. + +Import process +-------------- + +Step-by-step import +******************* + +1. **Log into your Mautic account** + Navigate to the main dashboard and authenticate. + +2. **Access Campaigns Section** + Click on the Campaigns menu to view existing Campaigns. + +3. **Open Import Options** + - Click the cog icon in the top-right corner + - Select **Import** from the dropdown menu + +4. **Select Campaign File** + On the import screen: + + - Choose the Campaign zip file you wish to import + - **Recommended:** use a ZIP file created from the Mautic export function + - Ensures inclusion of Campaign data, external Assets, and Dynamic Content + +.. important:: + The user interface only supports importing ZIP files. You can use both the command line and API endpoints to import correctly structured JSON files. + +Import mechanics +**************** + +During the import process, Mautic performs a comprehensive analysis of the data to import: + +- Checks that the logged in User has the correct permissions to import +- Identifies required entities for the Campaign to function +- Validates if a Campaign template depends on an external Plugin: + + * The import function verifies Plugin installation + * When a required Plugin is missing: + + - The import process halts + - Prompts the User to install the necessary Plugin before continuing + +- Validates for potential ID conflicts in imported entities +- Where conflicts exist, provides options to: + + * Update existing entities, allowing Administrators to update existing Campaigns + * Create new entities, using a new ID + +- **Automatic Data Mapping** + * Mautic intelligently maps imported data to the correct locations + * Creates any necessary dependent entities automatically + +- **Campaign Activation** + * After successful import, the Campaign remains inactive by default, so that you stay in control + * Navigate to the Campaigns list to activate imported Campaigns + +.. tip:: + To activate the imported Campaign: + + 1. Go to the Campaigns section + 2. Locate the newly imported Campaign using the toggle next to the Campaign name |activate_toggle|. + + 3. Toggle the Campaign status to "Active" + + .. |activate_toggle| image:: images/activate-campaign.png + :alt: Activate Campaign toggle + +Importing via the command line +------------------------------ + +You can import Campaigns using the Mautic command-line console: + +.. code-block:: bash + + bin/console mautic:entity:import \ + --entity=campaign \ + --file=/tmp/entity_data.zip \ + --user=<user_id> + +Command parameters +****************** + +- ``--entity=campaign`` + * Specifies the type of entity being imported + * In this case, importing a Campaign + +- ``--file=/tmp/entity_data.zip`` + * Path to the ZIP file containing the Campaign data + * Must be a valid export file created from a Mautic export + +- ``--user=<user_id>`` + * ID of the user performing the import, which is logged against the audit trail + * Ensures proper access and permissions for the import process + +.. important:: + - Ensure the ZIP file is a valid Mautic Campaign export + - The specified User must have appropriate import permissions + - Verify the path is correct before running the command + +Importing using the Mautic API +------------------------------ + +You can Import Campaigns programmatically using the Mautic API: + +Curl example with ZIP file +************************** + +.. code-block:: bash + + curl -X POST 'https://example.com/api/campaigns/import' \ + -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ + -H 'Content-Type: multipart/form-data' \ + -F 'file=@/path/to/campaign_export.zip' + +Python example with JSON data +***************************** + +.. code-block:: python + + import requests + + # API Endpoint + url = 'https://example.com/api/campaigns/import' + + # Authentication + headers = { + 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', + 'Content-Type': 'application/json' + } + + # Campaign import data + payload = { + 'name': 'Imported Campaign', + 'description': 'Campaign imported via API', + # Add other campaign details as needed + } + + # Send import request + response = requests.post(url, headers=headers, json=payload) + + # Handle response + if response.status_code == 200: + imported_campaign = response.json() + print("Campaign imported successfully") + +API import methods +****************** + +Mautic supports two primary methods of API-based Campaign import: + +1. **ZIP File Import** + - Use ``multipart/form-data`` content type + - Upload the complete Campaign export ZIP file + - Includes all Campaign assets and dependencies from the ZIP file + +2. **JSON Data Import** + - Use ``application/json`` content type + - Send Campaign details directly in the request body + - Useful for creating new Campaigns or updating existing Campaigns + +.. important:: + - Replace ``example.com`` with your actual Mautic instance domain + - Ensure you have a valid access token by accessing the API Credentials section within Mautic's settings. + - The imported Campaign must comply with Mautic's Campaign structure + - Verify import permissions and data integrity diff --git a/docs/configuration/command_line_interface.rst b/docs/configuration/command_line_interface.rst index 5e3a4429..eb4835d0 100644 --- a/docs/configuration/command_line_interface.rst +++ b/docs/configuration/command_line_interface.rst @@ -115,14 +115,21 @@ These are the commands you may need to use in relation to your Mautic instance. - * - ``mautic:email:fetch`` - Fetch and process monitored Email. - - + + * - ``mautic:entity:import --entity=campaign file=path-to-file/entity_data.zip`` + - Imports campaign and dependent entities to Mautic from a ZIP file. See :doc:`/campaigns/importing-campaigns`. + + * - ``mautic:entity:export --entity=campaign --id=1 path=path/to-file`` + - Exports campaign and dependent entities from Mautic to a ZIP file. See :doc:`/campaigns/exporting-campaigns`. + * - ``messenger:consume email`` - Processes mail queue - - * - ``mautic:fields:analse`` + * - ``mautic:fields:analyse`` - Analyze Custom Fields table and return table or file with results. See :doc:`/contacts/custom_fields`. - * - ``mautic:import`` + - Imports Contacts from a CSV file - If the CSV import is configured to run in background then this command will pick up the pending import jobs and imports the data from CSV files to Mautic. - * - ``mautic:integration:fetchleads`` diff --git a/docs/index.rst b/docs/index.rst index df81ac67..36315db9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -94,6 +94,8 @@ There are different types of documentation available to help you navigate your w campaigns/creating_campaigns campaigns/campaign_builder campaigns/managing_campaigns + campaigns/exporting_campaigns + campaigns/importing_campaigns campaigns/troubleshooting_campaigns .. toctree::