# HG changeset patch
# User Florent Aide, <florent.aide@gmail.com>
# Date 1313666907 -7200
#      Thu Aug 18 13:28:27 2011 +0200
# Node ID 9379d7a911df195e019dff39530b65aaa47ca09c
# Parent  80d3c51f0639807101f182478ffe82e7f1974572
We now have tracking in place in the OpenERP part

diff --git a/__init__.py b/__init__.py
--- a/__init__.py
+++ b/__init__.py
@@ -2,6 +2,7 @@
 ##############################################################################
 #
 #    Email marketing click & read tracker
+#    Copyright (C) 2011 Florent Aide, <florent.aide@gmail.com>
 #    Copyright (C) 2011 XCG Consulting (http://www.xcg-consulting.fr/)
 #
 #    This program is free software: you can redistribute it and/or modify
@@ -19,6 +20,7 @@
 #
 ##############################################################################
 
+import trackitem
 import marketing_campaign_tracker
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/__openerp__.py b/__openerp__.py
--- a/__openerp__.py
+++ b/__openerp__.py
@@ -2,6 +2,7 @@
 ##############################################################################
 #
 #    Email marketing click & read tracker
+#    Copyright (C) 2011 Florent Aide, <florent.aide@gmail.com>
 #    Copyright (C) 2011 XCG Consulting (http://www.xcg-consulting.fr/)
 #
 #    This program is free software: you can redistribute it and/or modify
diff --git a/marketing_campaign_tracker.py b/marketing_campaign_tracker.py
--- a/marketing_campaign_tracker.py
+++ b/marketing_campaign_tracker.py
@@ -2,6 +2,7 @@
 ##############################################################################
 #
 #    Email marketing click & read tracker
+#    Copyright (C) 2011 Florent Aide, <florent.aide@gmail.com>
 #    Copyright (C) 2011 XCG Consulting (http://www.xcg-consulting.fr/)
 #
 #    This program is free software: you can redistribute it and/or modify
@@ -20,6 +21,92 @@
 ##############################################################################
 
 from osv import osv, fields
+import re
+import uuid
+
+simple_text_url_re = re.compile(r'http://[-a-zA-Z0-9_/.]+')
+
+def insert_tracker_in_text(cursor, user, text, tracker_base, pool, activity_id):
+
+    def repl(match_obj):
+        # here we must keep a reference on the uuid in our db for the tracker
+        real_url = match_obj.group(0)
+        uid = str(uuid.uuid4())
+        values = dict(
+            trackitem_uuid = uid,
+            real_url = real_url,
+            campaign_activity_id = activity_id,
+        )
+        trackitem = pool.get('marketing_campaign_tracker.trackitem')
+        # create a trackitem for each URL that is replaced
+        trackitem.create(cursor, user, values, context=None)
+        return "%s/%s" % (tracker_base, uid)
+
+    return simple_text_url_re.sub(repl, text)
+
+
+def insert_tracker_in_html(cr, uid, html, tracker_base, pool, activity_id):
+    return html
+
+class hooked_email_template(osv.osv):
+    """overrides the base email template to hook the URL tracker
+    """
+    _inherit = 'email.template'
+
+    def generate_mail(self, cursor, user, template_id,
+                      record_ids, context=None):
+        """since we cannot override the _generate_mailbox_item_from_template
+        method we hook into the higher level generate mail and are forced to
+        copy over the code in order to add our own... This is some KIND of
+        inheritance :)
+        """
+
+        if context is None:
+            context = {}
+
+        template = self.browse(cursor, user, template_id, context=context)
+
+        if not template:
+            raise Exception("The requested template could not be loaded")
+
+        # CHANGE FROM ORIGINAL METHOD
+        if context.get('use_tracker', False):
+            # here we need to use tracker so let's do it
+            tracker_base = context.get('tracker_base')
+            text = template.def_body_text
+            template.def_body_text = insert_tracker_in_text(
+                cursor, user, text, tracker_base,
+                self.pool, context['activity_id'])
+
+            html = template.def_body_html
+            template.def_body_html = insert_tracker_in_html(
+                cursor, user, html, tracker_base,
+                self.pool, context['activity_id'])
+
+        # END OF CHANGES FROM ORIGINAL METHOD
+
+        result = True
+        mailbox_obj = self.pool.get('email_template.mailbox')
+        for record_id in record_ids:
+            mailbox_id = self._generate_mailbox_item_from_template(
+                cursor, user, template, record_id, context)
+
+            mail = mailbox_obj.browse(cursor, user, mailbox_id, context=context)
+
+            if template.report_template or template.attachment_ids:
+                self.generate_attach_reports(cursor, user, template,
+                                             record_id, mail, context)
+
+            self.pool.get('email_template.mailbox').write(
+                cursor, user, mailbox_id, {'folder':'outbox'}, context=context)
+
+            # TODO : manage return value of all the records
+            result = self.pool.get('email_template.mailbox').send_this_mail(
+                cursor, user, [mailbox_id], context)
+
+        return result
+
+hooked_email_template()
 
 
 class marketing_campaign_activity(osv.osv):
@@ -43,9 +130,16 @@
     # override the _process_wi_email to replace all the URLs in the template
     # body by our tracker URL and store the corresponding keys in database
     def _process_wi_email(self, cr, uid, activity, workitem, context=None):
-        print "*"*35
-        print "Processing workitem for email!"
-        print "*"*35
+        if context is None:
+            context = {}
+
+        context['use_tracker'] = activity.use_tracker
+
+        if activity.use_tracker:
+            # TODO: get it from the tracker reference on the activity and remove trailing / if any
+            context['tracker_base'] = 'http://localhost:9965'
+            context['activity_id'] = activity.id
+
         return self.pool.get('email.template').generate_mail(cr, uid,
                                             activity.email_template_id.id,
                                             [workitem.res_id], context=context)
diff --git a/trackitem.py b/trackitem.py
new file mode 100644
--- /dev/null
+++ b/trackitem.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    Email marketing click & read tracker
+#    Copyright (C) 2011 Florent Aide, <florent.aide@gmail.com>
+#    Copyright (C) 2011 XCG Consulting (http://www.xcg-consulting.fr/)
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from osv import osv, fields
+import time
+
+class trackitem(osv.osv):
+    """a trackitem is a simple link between a real URL and a UUID URL that
+    was sent in an email. When the person clicks on the UUID URL the tracker
+    server will hit the database with the UUID to try and find the real URL
+    and then redirect the visitor to the real URL he wants to see.
+    During this process the tracker will be responsible to create trackvisit
+    objects associated with the relevant trackitem.
+
+    A trackitem is also directly linked to a campaign activity in order to be
+    easily able to analyze by campaign the click/read ratios
+    """
+    _name = 'marketing_campaign_tracker.trackitem'
+
+    _columns = {
+        'trackitem_uuid': fields.char("uuid", size=36, required=True, select=1),
+        'real_url': fields.char("Real URL", size=500),
+        # we only need the activity because an activity obj has a campaign_id
+        # attribute referencing the campaign it belongs to.
+        'campaign_activity_id': fields.many2one(
+            'marketing.campaign.activity',
+            'Marketing Campaign Activity',
+        ),
+    }
+
+trackitem()
+
+class trackvisit(osv.osv):
+    """a trackvisit is a small timestamp associated to a trackitem
+    Basically each time a client clicks on a tracked URL and gets redirected
+    by the tracker a trackvisit will be recorded for the action. This opens-up
+    interesting trails of who clicks/views our marketing emails and how many
+    times, when, from where...
+    """
+
+    _name = 'marketing_campaign_tracker.trackvisit'
+
+    _columns = {
+        # keep a reference to our parent
+        'trackitem_id': fields.many2one(
+            'marketing_campaign_tracker.trackitem',
+            'Track Item',
+            ),
+        'visit_time': fields.datetime('Visit time', required=True),
+    }
+
+    _defaults = dict(
+        # format the datetime for PG backend storage in a timestamp
+        visit_time = lambda *a: time.strftime("%Y-%m-%d %H:%M:%S.000000"),
+    )
+
+trackvisit()