def _load_graph(self, info_cache): rpc = self.rpc visits = info_cache['visits'] creds = info_cache['credentials'] messages_count = rpc( 'db/table/count', 'messages', query_filter={'campaign_id': self.config['campaign_id']}) messages_not_opened = rpc('db/table/count', 'messages', query_filter={ 'campaign_id': self.config['campaign_id'], 'opened': None }) bars = [] bars.append(messages_count) bars.append(messages_count - messages_not_opened) bars.append(len(visits)) bars.append(len(unique(visits, key=lambda visit: visit.message_id))) if len(creds): bars.append(len(creds)) bars.append(len(unique(creds, key=lambda cred: cred.message_id))) yticklabels = ('Messages', 'Opened', 'Visits', 'Unique\nVisits', 'Credentials', 'Unique\nCredentials') self.graph_bar(bars, len(yticklabels), yticklabels[:len(bars)]) return
def _load_graph(self, info_cache): rpc = self.rpc messages_count = rpc( 'db/table/count', 'messages', query_filter={'campaign_id': self.config['campaign_id']}) if not messages_count: self._graph_null_pie('No Messages Sent') return visits_count = len( unique(info_cache['visits'], key=lambda visit: visit.message_id)) credentials_count = len( unique(info_cache['credentials'], key=lambda cred: cred.message_id)) if not credentials_count <= visits_count <= messages_count: raise ValueError( 'credential visit and message counts are inconsistent') labels = ['Without Visit', 'With Visit', 'With Credentials'] sizes = [] sizes.append( (float(messages_count - visits_count) / float(messages_count)) * 100) sizes.append( (float(visits_count - credentials_count) / float(messages_count)) * 100) sizes.append((float(credentials_count) / float(messages_count)) * 100) if not credentials_count: labels.pop() sizes.pop() if not visits_count: labels.pop() sizes.pop() self.graph_pie(sizes, legend_labels=labels) return
def _load_graph(self, info_cache): rpc = self.parent.rpc messages_count = rpc('campaign/messages/count', self.config['campaign_id']) if not messages_count: self._graph_null_pie('No Messages Sent') return visits_count = len(unique(info_cache['visits'], key=lambda visit: visit.message_id)) credentials_count = len(unique(info_cache['credentials'], key=lambda cred: cred.message_id)) assert credentials_count <= visits_count <= messages_count labels = ['Without Visit', 'With Visit', 'With Credentials'] sizes = [] sizes.append((float(messages_count - visits_count) / float(messages_count)) * 100) sizes.append((float(visits_count - credentials_count) / float(messages_count)) * 100) sizes.append((float(credentials_count) / float(messages_count)) * 100) colors = ['yellowgreen', 'gold', 'indianred'] explode = [0.1, 0, 0] if not credentials_count: labels.pop() sizes.pop() colors.pop() explode.pop() if not visits_count: labels.pop() sizes.pop() colors.pop() explode.pop() ax = self.axes[0] ax.pie(sizes, explode=explode, labels=labels, labeldistance=1.05, colors=colors, autopct='%1.1f%%', shadow=True, startangle=45) ax.axis('equal') return
def _load_graph(self, info_cache): rpc = self.rpc messages_count = rpc('db/table/count', 'messages', query_filter={'campaign_id': self.config['campaign_id']}) if not messages_count: self._graph_null_pie('No Messages Sent') return visits_count = len(unique(info_cache['visits'], key=lambda visit: visit.message_id)) credentials_count = len(unique(info_cache['credentials'], key=lambda cred: cred.message_id)) assert credentials_count <= visits_count <= messages_count labels = ['Without Visit', 'With Visit', 'With Credentials'] sizes = [] sizes.append((float(messages_count - visits_count) / float(messages_count)) * 100) sizes.append((float(visits_count - credentials_count) / float(messages_count)) * 100) sizes.append((float(credentials_count) / float(messages_count)) * 100) colors = ['yellowgreen', 'gold', 'indianred'] explode = [0.1, 0, 0] if not credentials_count: labels.pop() sizes.pop() colors.pop() explode.pop() if not visits_count: labels.pop() sizes.pop() colors.pop() explode.pop() ax = self.axes[0] ax.pie(sizes, explode=explode, labels=tuple("{0:.1f}%".format(s) for s in sizes), labeldistance=1.15, colors=colors, shadow=True, startangle=45) ax.axis('equal') self.add_legend_patch(zip(colors, labels), fontsize='x-small') return
def _campaign_stats(self, campaign): rpc = self.rpc messages = list(rpc.remote_table('messages', query_filter={'campaign_id': campaign.id})) visits = list(rpc.remote_table('visits', query_filter={'campaign_id': campaign.id})) credentials = list(rpc.remote_table('credentials', query_filter={'campaign_id': campaign.id})) stats = { 'created': campaign.created, 'expiration': campaign.expiration, 'reject_after_credentials': campaign.reject_after_credentials, 'id': campaign.id, 'name': generate_hash(campaign.name), 'messages': { 'total': len(messages), 'unique': { 'by_target': len(unique(messages, key=lambda message: message.target_email)), } }, 'visits': { 'total': len(visits), 'unique': { 'by_message': len(unique(visits, key=lambda visit: visit.message_id)), } }, 'credentials': { 'total': len(credentials), 'unique': { 'by_message': len(unique(credentials, key=lambda credential: credential.message_id)), 'by_visit': len(unique(credentials, key=lambda credential: credential.visit_id)) } } } return stats
def _load_graph(self, info_cache): messages = info_cache['messages'] messages_count = messages['total'] if not messages_count: self._graph_null_pie('No Messages Sent') return visits_count = len( unique(info_cache['visits']['edges'], key=lambda visit: visit['node']['messageId'])) credentials_count = len( unique(info_cache['credentials']['edges'], key=lambda cred: cred['node']['messageId'])) if not credentials_count <= visits_count <= messages_count: raise ValueError( 'credential visit and message counts are inconsistent') labels = ['Without Visit', 'With Visit', 'With Credentials'] sizes = [] sizes.append( (float(messages_count - visits_count) / float(messages_count)) * 100) sizes.append( (float(visits_count - credentials_count) / float(messages_count)) * 100) sizes.append((float(credentials_count) / float(messages_count)) * 100) if not credentials_count: labels.pop() sizes.pop() if not visits_count: labels.pop() sizes.pop() self.graph_pie(sizes, legend_labels=labels) return
def _load_graph(self, info_cache): messages = info_cache['messages']['edges'] messages = [ message['node'] for message in messages if message['node']['companyDepartment'] is not None ] if not messages: self._graph_null_bar('') return messages = dict((message['id'], message) for message in messages) visits = info_cache['visits']['edges'] visits = [ visit['node'] for visit in visits if visit['node']['messageId'] in messages ] visits = unique(visits, key=lambda visit: visit['messageId']) visits = dict((visit['id'], visit) for visit in visits) creds = info_cache['credentials']['edges'] creds = [ cred['node'] for cred in creds if cred['node']['messageId'] in messages ] creds = unique(creds, key=lambda cred: cred['messageId']) creds = dict((cred['id'], cred) for cred in creds) department_messages = collections.Counter() department_messages.update(message['companyDepartment']['name'] for message in messages.values()) department_visits = collections.Counter() department_visits.update( messages[visit['messageId']]['companyDepartment']['name'] for visit in visits.values()) department_credentials = collections.Counter() department_credentials.update( messages[cred['messageId']]['companyDepartment']['name'] for cred in creds.values()) bars = [] department_names = tuple(department_messages.keys()) for department_name in department_names: dep_messages = float(department_messages[department_name]) dep_creds = float(department_credentials.get( department_name, 0)) / dep_messages * 100 dep_visits = (float(department_visits.get(department_name, 0)) / dep_messages * 100) - dep_creds bars.append( (dep_creds, dep_visits, (100.0 - (dep_creds + dep_visits)))) bar_colors = (self.get_color('map_marker1', ColorHexCode.RED), self.get_color('map_marker2', ColorHexCode.YELLOW), self.get_color('bar_bg', ColorHexCode.GRAY)) self.graph_bar_stacked(bars, bar_colors, department_names) self.add_legend_patch(tuple( zip(bar_colors[:2], ('With Credentials', 'Without Credentials'))), fontsize=10) return
def _load_graph(self, info_cache): messages = info_cache['messages']['edges'] messages = [message['node'] for message in messages if message['node']['companyDepartment'] is not None] if not messages: self._graph_null_bar('') return messages = dict((message['id'], message) for message in messages) visits = info_cache['visits']['edges'] visits = [visit['node'] for visit in visits if visit['node']['messageId'] in messages] visits = unique(visits, key=lambda visit: visit['messageId']) visits = dict((visit['id'], visit) for visit in visits) creds = info_cache['credentials']['edges'] creds = [cred['node'] for cred in creds if cred['node']['messageId'] in messages] creds = unique(creds, key=lambda cred: cred['messageId']) creds = dict((cred['id'], cred) for cred in creds) department_messages = collections.Counter() department_messages.update(message['companyDepartment']['name'] for message in messages.values()) department_visits = collections.Counter() department_visits.update(messages[visit['messageId']]['companyDepartment']['name'] for visit in visits.values()) department_credentials = collections.Counter() department_credentials.update(messages[cred['messageId']]['companyDepartment']['name'] for cred in creds.values()) bars = [] department_names = tuple(department_messages.keys()) for department_name in department_names: dep_messages = float(department_messages[department_name]) dep_creds = float(department_credentials.get(department_name, 0)) / dep_messages * 100 dep_visits = (float(department_visits.get(department_name, 0)) / dep_messages * 100) - dep_creds bars.append(( dep_creds, dep_visits, (100.0 - (dep_creds + dep_visits)) )) bar_colors = ( self.get_color('map_marker1', ColorHexCode.RED), self.get_color('map_marker2', ColorHexCode.YELLOW), self.get_color('bar_bg', ColorHexCode.GRAY) ) self.graph_bar_stacked( bars, bar_colors, department_names ) self.add_legend_patch(tuple(zip(bar_colors[:2], ('With Credentials', 'Without Credentials'))), fontsize=10) return
def _load_graph(self, info_cache): rpc = self.rpc visits = info_cache['visits'] creds = info_cache['credentials'] bars = [] bars.append(rpc('db/table/count', 'messages', query_filter={'campaign_id': self.config['campaign_id']})) bars.append(len(visits)) bars.append(len(unique(visits, key=lambda visit: visit.message_id))) if len(creds): bars.append(len(creds)) bars.append(len(unique(creds, key=lambda cred: cred.message_id))) yticklabels = ('Messages', 'Visits', 'Unique\nVisits', 'Credentials', 'Unique\nCredentials') self.graph_bar(bars, len(yticklabels), yticklabels[:len(bars)]) return
def _load_graph(self, info_cache): rpc = self.parent.rpc visits = info_cache['visits'] creds = info_cache['credentials'] bars = [] bars.append(rpc('campaign/messages/count', self.config['campaign_id'])) bars.append(len(visits)) bars.append(len(unique(visits, key=lambda visit: visit.message_id))) if len(creds): bars.append(len(creds)) bars.append(len(unique(creds, key=lambda cred: cred.message_id))) xticklabels = ('Messages', 'Visits', 'Unique\nVisits', 'Credentials', 'Unique\nCredentials')[:len(bars)] bars = self.graph_bar(bars, xticklabels=xticklabels, ylabel='Grand Total') return
def _campaign_stats(self, campaign): rpc = self.rpc messages = list( rpc.remote_table('messages', query_filter={'campaign_id': campaign.id})) visits = list( rpc.remote_table('visits', query_filter={'campaign_id': campaign.id})) credentials = list( rpc.remote_table('credentials', query_filter={'campaign_id': campaign.id})) stats = { 'created': campaign.created, 'expiration': campaign.expiration, 'reject_after_credentials': campaign.reject_after_credentials, 'id': campaign.id, 'name': generate_hash(campaign.name), 'messages': { 'total': len(messages), 'unique': { 'by_target': len( unique(messages, key=lambda message: message.target_email)), } }, 'visits': { 'total': len(visits), 'unique': { 'by_message': len(unique(visits, key=lambda visit: visit.message_id)), } }, 'credentials': { 'total': len(credentials), 'unique': { 'by_message': len( unique(credentials, key=lambda credential: credential.message_id)), 'by_visit': len( unique(credentials, key=lambda credential: credential.visit_id)) } } } return stats
def _load_graph(self, info_cache): visits = unique(info_cache['visits'], key=lambda visit: visit.message_id) cred_ips = set(cred.message_id for cred in info_cache['credentials']) cred_ips = set([visit.visitor_ip for visit in visits if visit.message_id in cred_ips]) ax = self.axes[0] bm = mpl_toolkits.basemap.Basemap(resolution='c', ax=ax, **self.basemap_args) if self.draw_states: bm.drawstates() bm.drawcoastlines() bm.drawcountries() bm.fillcontinents(color=MPL_COLOR_LAND, lake_color=MPL_COLOR_WATER) bm.drawparallels((-60, -30, 0, 30, 60), labels=(1, 1, 0, 0)) bm.drawmeridians((0, 90, 180, 270), labels=(0, 0, 0, 1)) bm.drawmapboundary(fill_color=MPL_COLOR_WATER) if not visits: return ctr = collections.Counter() ctr.update([visit.visitor_ip for visit in visits]) base_markersize = self.markersize_scale base_markersize = max(base_markersize, 3.05) base_markersize = min(base_markersize, 9) self._plot_visitor_map_points(bm, ctr, base_markersize, cred_ips) self.add_legend_patch(((self.mpl_color_with_creds, 'With Credentials'), (self.mpl_color_without_creds, 'Without Credentials'))) return
def _load_graph(self, info_cache): departments = info_cache['company_departments'] departments = dict((department.id, department.name) for department in departments) messages = info_cache['messages'] message_departments = dict((message.id, departments[message.company_department_id]) for message in messages if message.company_department_id is not None) if not len(message_departments): self._graph_null_bar('') return messages = [message for message in messages if message.id in message_departments] visits = info_cache['visits'] visits = [visit for visit in visits if visit.message_id in message_departments] visits = unique(visits, key=lambda visit: visit.message_id) department_visits = collections.Counter() department_visits.update(message_departments[visit.message_id] for visit in visits) department_totals = collections.Counter() department_totals.update(message_departments[message.id] for message in messages) department_scores = dict((department, (department_visits[department] / total) * 100) for department, total in department_totals.items()) department_scores = sorted(department_scores.items(), key=lambda x: (x[1], x[0]), reverse=True) department_scores = collections.OrderedDict(department_scores) yticklabels, bars = zip(*department_scores.items()) self.graph_bar(bars, len(yticklabels), yticklabels) return
def _load_graph(self, info_cache): visits = info_cache['visits']['edges'] creds = info_cache['credentials']['edges'] messages = info_cache['messages'] messages_count = messages['total'] messages_opened = [message['node'] for message in messages['edges'] if message['node']['opened'] is not None] bars = [] bars.append(messages_count) bars.append(len(messages_opened)) bars.append(len(visits)) bars.append(len(unique(visits, key=lambda visit: visit['node']['messageId']))) if len(creds): bars.append(len(creds)) bars.append(len(unique(creds, key=lambda cred: cred['node']['messageId']))) yticklabels = ('Messages', 'Opened', 'Visits', 'Unique\nVisits', 'Credentials', 'Unique\nCredentials') self.graph_bar(bars, yticklabels[:len(bars)]) return
def _load_graph(self, info_cache): rpc = self.rpc messages_count = rpc('db/table/count', 'messages', query_filter={'campaign_id': self.config['campaign_id']}) if not messages_count: self._graph_null_pie('No Messages Sent') return visits_count = len(unique(info_cache['visits'], key=lambda visit: visit.message_id)) credentials_count = len(unique(info_cache['credentials'], key=lambda cred: cred.message_id)) assert credentials_count <= visits_count <= messages_count labels = ['Without Visit', 'With Visit', 'With Credentials'] sizes = [] sizes.append((float(messages_count - visits_count) / float(messages_count)) * 100) sizes.append((float(visits_count - credentials_count) / float(messages_count)) * 100) sizes.append((float(credentials_count) / float(messages_count)) * 100) if not credentials_count: labels.pop() sizes.pop() if not visits_count: labels.pop() sizes.pop() self.graph_pie(sizes, legend_labels=labels) return
def _load_graph(self, info_cache): messages = info_cache['messages'] messages_count = messages['total'] if not messages_count: self._graph_null_pie('No Messages Sent') return visits_count = len(unique(info_cache['visits']['edges'], key=lambda visit: visit['node']['messageId'])) credentials_count = len(unique(info_cache['credentials']['edges'], key=lambda cred: cred['node']['messageId'])) if not credentials_count <= visits_count <= messages_count: raise ValueError('credential visit and message counts are inconsistent') labels = ['Without Visit', 'With Visit', 'With Credentials'] sizes = [] sizes.append((float(messages_count - visits_count) / float(messages_count)) * 100) sizes.append((float(visits_count - credentials_count) / float(messages_count)) * 100) sizes.append((float(credentials_count) / float(messages_count)) * 100) if not credentials_count: labels.pop() sizes.pop() if not visits_count: labels.pop() sizes.pop() self.graph_pie(sizes, legend_labels=labels) return
def _load_graph(self, info_cache): visits = info_cache['visits']['edges'] creds = info_cache['credentials']['edges'] messages = info_cache['messages'] messages_count = messages['total'] messages_opened = [ message['node'] for message in messages['edges'] if message['node']['opened'] is not None ] bars = [] bars.append(messages_count) bars.append(len(messages_opened)) bars.append(len(visits)) bars.append( len(unique(visits, key=lambda visit: visit['node']['messageId']))) if len(creds): bars.append(len(creds)) bars.append( len(unique(creds, key=lambda cred: cred['node']['messageId']))) yticklabels = ('Messages', 'Opened', 'Visits', 'Unique\nVisits', 'Credentials', 'Unique\nCredentials') self.graph_bar(bars, yticklabels[:len(bars)]) return
def _load_graph(self, info_cache): campaign_id = self.config['campaign_id'] departments = info_cache['companyDepartments'] departments = dict( (department['node']['id'], department['node']['name']) for department in departments['edges']) messages = info_cache['messages'] message_departments = dict( (message['node']['id'], departments.get(str(message['node'].get('companyDepartmentId')))) for message in messages['edges'] if message['node']['companyDepartmentId'] is not None) if not len(message_departments): self._graph_null_bar('') return messages = [ message['node'] for message in messages['edges'] if message['node']['id'] in message_departments ] visits = info_cache['visits'] visits = [ visit['node'] for visit in visits['edges'] if visit['node']['messageId'] in message_departments ] visits = unique(visits, key=lambda visit: visit['messageId']) department_visits = collections.Counter() department_visits.update(message_departments[visit['messageId']] for visit in visits) department_totals = collections.Counter() department_totals.update(message_departments[message['id']] for message in messages) department_scores = dict( (department, (float(department_visits[department]) / float(total)) * 100) for department, total in department_totals.items()) department_scores = sorted(department_scores.items(), key=lambda x: (x[1], x[0]), reverse=True) department_scores = collections.OrderedDict(department_scores) yticklabels, bars = zip(*department_scores.items()) self.graph_bar(bars, len(yticklabels), yticklabels) return
def _load_graph(self, info_cache): visits = unique(info_cache['visits']['edges'], key=lambda visit: visit['node']['messageId']) cred_ips = set(cred['node']['messageId'] for cred in info_cache['credentials']['edges']) cred_ips = set([ visit['node']['visitorIp'] for visit in visits if visit['node']['messageId'] in cred_ips ]) color_fg = self.get_color('fg', ColorHexCode.BLACK) color_land = self.get_color('map_land', ColorHexCode.GRAY) color_water = self.get_color('map_water', ColorHexCode.WHITE) ax = self.axes[0] bm = mpl_toolkits.basemap.Basemap(resolution='c', ax=ax, **self.basemap_args) if self.draw_states: bm.drawstates() bm.drawcoastlines() bm.drawcountries() bm.fillcontinents(color=color_land, lake_color=color_water) parallels = bm.drawparallels((-60, -30, 0, 30, 60), labels=(1, 1, 0, 0)) self._map_set_line_color(parallels, color_fg) meridians = bm.drawmeridians((0, 90, 180, 270), labels=(0, 0, 0, 1)) self._map_set_line_color(meridians, color_fg) bm.drawmapboundary(fill_color=color_water, linewidth=0) if not visits: return ctr = collections.Counter() ctr.update([visit['node']['visitorIp'] for visit in visits]) base_markersize = self.markersize_scale base_markersize = max(base_markersize, 3.05) base_markersize = min(base_markersize, 9) self._plot_visitor_map_points(bm, ctr, base_markersize, cred_ips) self.add_legend_patch( ((self.color_with_creds, 'With Credentials'), (self.color_without_creds, 'Without Credentials'))) return
def _load_graph(self, info_cache): visits = unique(info_cache['visits'], key=lambda visit: visit.message_id) cred_ips = set(cred.message_id for cred in info_cache['credentials']) cred_ips = set([visit.visitor_ip for visit in visits if visit.message_id in cred_ips]) color_fg = self.get_color('fg', ColorHexCode.BLACK) color_land = self.get_color('map_land', ColorHexCode.GRAY) color_water = self.get_color('map_water', ColorHexCode.WHITE) ax = self.axes[0] bm = mpl_toolkits.basemap.Basemap(resolution='c', ax=ax, **self.basemap_args) if self.draw_states: bm.drawstates() bm.drawcoastlines() bm.drawcountries() bm.fillcontinents(color=color_land, lake_color=color_water) parallels = bm.drawparallels( (-60, -30, 0, 30, 60), labels=(1, 1, 0, 0) ) self._map_set_line_color(parallels, color_fg) meridians = bm.drawmeridians( (0, 90, 180, 270), labels=(0, 0, 0, 1) ) self._map_set_line_color(meridians, color_fg) bm.drawmapboundary( fill_color=color_water, linewidth=0 ) if not visits: return ctr = collections.Counter() ctr.update([visit.visitor_ip for visit in visits]) base_markersize = self.markersize_scale base_markersize = max(base_markersize, 3.05) base_markersize = min(base_markersize, 9) self._plot_visitor_map_points(bm, ctr, base_markersize, cred_ips) self.add_legend_patch(((self.color_with_creds, 'With Credentials'), (self.color_without_creds, 'Without Credentials'))) return