From 8fe2e576dca7ceae4456af125af4a607a423e9bb Mon Sep 17 00:00:00 2001 From: Jeremy Edberg Date: Wed, 10 Sep 2008 16:54:08 -0700 Subject: [PATCH] adding a reporting module --- r2/r2/lib/utils/reporting.py | 166 +++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 r2/r2/lib/utils/reporting.py diff --git a/r2/r2/lib/utils/reporting.py b/r2/r2/lib/utils/reporting.py new file mode 100644 index 000000000..d7907b0c2 --- /dev/null +++ b/r2/r2/lib/utils/reporting.py @@ -0,0 +1,166 @@ +import sqlalchemy as sa +import datetime as dt +import time +import smtplib + +from r2.lib.utils import timeago +from r2.lib.db import tdb_sql +from r2.models.mail_queue import Email + +class Report(object): + """Class for creating reports based on reddit data""" + def __init__(self, period=None, date=None): + """Sets up the date storage.""" + self.period = period + self.date = date + + def append_date_clause(self, table, select, all_time=None): + """Create the date portion of a where clause based on the time + period specified.""" + if all_time: + return select + if self.period and not self.date: + select.append_whereclause(table.c.date > timeago(self.period)) + if self.date: + seconds = 24 * 60 * 60 + wheredate = dt.datetime.strptime(self.date,"%Y%m%d") + select.append_whereclause(table.c.date >= wheredate) + select.append_whereclause((table.c.date < wheredate + + dt.timedelta(0, seconds))) + return select + + def total_things(self, table_name, spam=None, all_time=None): + """Return totals based on items in the thing tables.""" + t = tdb_sql.types_name[table_name]['thing_table'] + s = sa.select([sa.func.count(t.c.thing_id)]) + if spam: + s.append_whereclause(t.c.spam==spam) + s.append_whereclause(t.c.deleted=='f') + s = self.append_date_clause(t, s, all_time=all_time) + + return s.execute().fetchone()[0] + + def total_relation(self, table_name, key, value=None, all_time=None): + """Return totals based on relationship data.""" + rel_table = tdb_sql.rel_types_name['%s_account_link' % table_name].rel_table + t1, t2 = rel_table[0], rel_table[3] + + s = sa.select([sa.func.count(t1.c.date)], + sa.and_(t1.c.rel_id == t2.c.thing_id, t2.c.key == key)) + if value: + s.append_whereclause(t2.c.value == value) + s = self.append_date_clause(t1, s, all_time=all_time) + return s.execute().fetchone()[0] + + def email_stats(self, table_name, all_time=None): + """Calculate stats based on the email tables.""" + t = getattr(Email.handler, '%s_table' % table_name) + s = sa.select([sa.func.count(t.c.kind)]) + s = self.append_date_clause(t, s, all_time=all_time) + return s.execute().fetchone()[0] + + def css_stats(self, val, all_time=None): + """Create stats related to custom css and headers.""" + t = tdb_sql.types_name['subreddit'].data_table[0] + s = sa.select([sa.func.count(t.c.key)], t.c.key == val) + return s.execute().fetchone()[0] + + +class TextReport(object): + """Class for building text based reports""" + def __init__(self, period, date): + self.r = Report(period=period, date=date) + self.rep = '' + self.period = period + self.date = date + if period: + self.phrase = "in the last" + self.time = period + if date: + self.phrase = "on" + self.time = self.pretty_date(date) + + def _thing_stats(self, thing, all_time=None): + """return a header and a list of thing stats""" + header = "%ss created " % thing + if all_time: + header += "since the beginning:" + else: + header += "%s %s:" % (self.phrase, self.time) + columns = ['all', 'spam', 'non-spam'] + data = [str(self.r.total_things(thing, all_time=all_time)), + str(self.r.total_things(thing, spam="t", all_time=all_time)), + str(self.r.total_things(thing, spam="f", all_time=all_time))] + return [[header], columns, data] + + def pretty_date(self, date): + """Makes a pretty date from a date""" + return time.strftime("%a, %b %d, %Y", time.strptime(date,"%Y%m%d")) + + def process_things(self, things, all_time=None): + """builds a report for a list of things""" + ret = '' + for thing in things: + (header, columns, data) = self._thing_stats(thing, all_time=all_time) + ret += '\n'.join(['\t'.join(header), '\t'.join(columns), '\t'.join(data)]) + ret += '\n' + return ret + + def process_relation(self, name, table_name, key, value, all_time=None): + """build a report for a relation""" + ret = ("%d\tTotal %s %s %s\n" % + (self.r.total_relation(table_name, key, value=value, all_time=all_time), + name, self.phrase, self.time)) + return ret + + def process_other(self, type, name, table_name, all_time=None): + """build other types of reports""" + if type == 'email': + f = self.r.email_stats + if type == 'css': + f = self.r.css_stats + ret = ("%d\tTotal %s %s %s\n" % + (f(table_name, all_time=all_time), name, self.phrase, self.time)) + return ret + + def build(self, show_all_time=True): + """build a complete text report""" + rep = 'Subject: reddit stats %s %s\n\n' % (self.phrase, self.time) + + rep += self.process_things(['account','subreddit','link','message','comment']) + + rep += "\n" + rep += self.process_relation('valid votes', 'vote', 'valid_thing', 't') + rep += self.process_relation('organic votes', 'vote', 'organic', 't') + rep += self.process_relation('votes', 'vote', 'valid_thing', None) + rep += self.process_relation('reports', 'report', 'amount', None) + + rep += self.process_other('email', 'share emails sent', 'track') + rep += self.process_other('email', 'share emails rejected', 'reject') + + if show_all_time: + rep += self.process_other('css', 'subreddits with custom css', + 'stylesheet_hash', all_time=True) + rep += self.process_other('css', 'subreddits with a custom header', + 'header', all_time=True) + rep += "\n" + rep += self.process_things(['account','subreddit','link','message','comment'], + all_time=True) + + return rep + +def yesterday(): + """return yesterday's date""" + return "%04d%02d%02d" % time.localtime(time.time() - 60*60*24)[0:3] + +def run(period=None, date=None, show_all_time=True, + sender=None, recipients=None, smtpserver=None): + if not date and not period: + date = yesterday() + session = smtplib.SMTP(smtpserver) + report = TextReport(period, date).build(show_all_time=show_all_time) + if sender: + report = "To: %s\n" % ', '.join(recipients) + report + smtpresult = session.sendmail(sender, recipients, report) + else: + print report