def getNotifications(): if 'appid' in request.form: long_id = request.form['appid'] appid = modules.getModel(models.App, appid = request.form.get('appid')).id elif 'LATrackingID' in request.cookies: long_id = request.cookies.get('LATrackingID') appid = modules.getModel(models.App, appid = request.cookies.get('LATrackingID')).id else: return jsonify(**{}) _emails = {d.id:d.subject for d in db.session.query(models.Email).filter_by(app_id = appid).all()} _links = {d.id: d.text for d in db.session.query(models.Link).filter_by(app_id = appid).all()} emails = db.session.query(models.Visit).filter(models.Visit.email_id.in_(_emails.keys())).filter_by(notified=False).all() links = db.session.query(models.Visit).filter(models.Visit.link_id.in_(_links.keys())).filter_by(notified=False).all() n_e, n_l = [], [] for e in emails: d = {} d['state'] = e.state d['subject'] = _emails[e.email_id] d['country'] = e.country d['minutes_ago'] = int((datetime.utcnow() - e.date).total_seconds()/60) n_e.append(d) for l in links: d = {} d['state'] = l.state d['text'] = _links[l.link_id] d['country'] = l.country d['minutes_ago'] = int((datetime.utcnow() - l.date).total_seconds()/60) n_l.append(d) return jsonify(links=n_l, emails=n_e, appid=long_id)
def sendEmailFromController(email_dict): if 'appid' not in email_dict: return {'success':False, 'reason':'need tracking_id'} appid = email_dict['appid'] app = modules.getModel(models.App, appid = email_dict.get('appid')) if not app or not app.user.is_verified: return {'success':False, 'reason':'bad app id'} html = email_dict.get('html', '') try: if db.session.query(models.Email).filter_by(subject=email_dict['subject'], html = html, from_address=app.google_email, to_address=email_dict['to_address']).first(): return {'success':False, 'reason':'duplicate email alert'} except Exception as ee: pass if html: links = [] soup = bs(html) d = {'appid':appid} for i in ['text', 'html', 'cc_address', 'bcc_address', 'to_address', 'from_address', 'subject']: if i in email_dict: d[i] = email_dict[i] e = _makeDBEmail(d) for a in soup.find_all('a'): if a.get('href') and 'latracking.com/r/' not in a['href'].lower() and 'mailto:' not in a['href'].lower() and 'tel:' not in a['href'].lower(): cleaned = _makeDBLink(e['email_id'], a.text, a['href'], appid) if cleaned['success']: links.append({'url':a.get('href'), 'text':a.text, 'cleaned':cleaned}) a['href'] = cleaned['latracking_url'] new_tag = soup.new_tag("img", src=e['tracking_link'], style="height: 1px; width:1px; display: none !important;") soup.append(new_tag) html = str(soup) access_token = appGoogleAPI(app) threadID = None if email_dict.get('threadID'): tt = modules.getModel(models.Thread, unique_thread_id=email_dict.get('threadID')) threadID = tt.unique_thread_id response = googleAPI.sendEmail(email = app.google_email, access_token = access_token, to_address = d['to_address'], subject = d.get('subject', ''), bcc_address = d.get('bcc_address', ''), html = html, text = email_dict.get('text', ''), threadID = threadID) email = db.session.query(models.Email).filter_by(id=e['email_id']).first() email.google_message_id = response['id'] email.from_address = app.google_email thread_created = False while not thread_created: random_thread = 'tt'+''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(9)) thread, thread_created = modules.get_or_create(models.Thread, threadid=random_thread, unique_thread_id = response['threadId'], origin='google', app_id = app.id, defaults = {'first_made':datetime.now()}) if ('demi' in app.google_email or 'kylie' in app.google_email) and ('sinan' in email_dict['to_address'] or 'jamasen' in email_dict['to_address']): thread.latracking_reply = True email.google_thread_id = response['threadId'] if email_dict.get('replied_to'): email.replied_to = email_dict.get('replied_to') email.thread_id = thread.id if email_dict.get('threadID'): email.google_thread_id = email_dict['threadID'] email.thread_id = tt.id if 'legion_cadence_id' in email_dict: email.legion_cadence_id = int(email_dict['legion_cadence_id']) if 'legion_template_id' in email_dict: email.legion_template_id = int(email_dict['legion_template_id']) email.date_sent = datetime.utcnow() db.session.commit() return {'success':True, 'links':links, 'cleaned_html':str(soup), 'email':e, 'threadid':random_thread}
def checkApp(): try: a = modules.getModel(models.App, appid=request.form.get('appid')) except Exception as eee: print eee, "checkapp error" return jsonify(success=False) return jsonify(success=True, is_valid=a.google_access_token is not None)
def verify(v): u = modules.getModel(models.User, login_check = v) if u: u.is_verified = True db.session.commit() login_user(u, remember=True, force=True, fresh=False) return jsonify(**{})
def emailOpen(e): d = {} if request.cookies.get('LATrackingID'): a = modules.getModel(models.App, appid = request.cookies.get('LATrackingID')) d['app_id'] = a.id d['private_ip'] = request.environ.get('REMOTE_ADDR') d['public_ip'] = request.environ.get('HTTP_X_FORWARDED_FOR') d['full_url'] = request.environ.get('HTTP_REFERER', '').strip().lower() email = db.session.query(models.Email).filter_by(emailid=e).first() if email: d['email_id'] = email.id else: return jsonify(**{'status':'failure', 'description':'no such email found'}) if d['public_ip']: g = geocoder.ip(d['public_ip']) d['lat'], d['lng'] = g.latlng d['city'] = g.city d['country'] = g.country d['state'] = g.state d['user_agent'] = request.environ.get('HTTP_USER_AGENT') if d['user_agent']: user_agent = parse(d['user_agent']) d['browser'] = user_agent.browser.family d['is_bot'], d['is_mobile'], d['is_tablet'], d['is_pc'] = user_agent.is_bot, user_agent.is_mobile, user_agent.is_tablet, user_agent.is_pc p = models.Visit(**d) p.date = datetime.now() db.session.add(p) db.session.commit() return jsonify(success=True, description='successfully tracked email')
def _redirect(l): d = {} d['private_ip'] = request.environ.get('REMOTE_ADDR') d['public_ip'] = request.environ.get('HTTP_X_FORWARDED_FOR') d['full_url'] = request.environ.get('HTTP_REFERER', '').strip().lower() if request.cookies.get('LATrackingID'): a = modules.getModel(models.App, appid = request.cookies.get('LATrackingID')) d['app_id'] = a.id link = db.session.query(models.Link).filter_by(linkid=l).first() if link: red_url = link.url d['link_id'] = link.id error = 'successfully tracked link' else: return jsonify(**{'status':'failure', 'description':'no such link found'}) if d['public_ip']: g = geocoder.ip(d['public_ip']) d['lat'], d['lng'] = g.latlng d['city'] = g.city d['country'] = g.country d['state'] = g.state d['user_agent'] = request.environ.get('HTTP_USER_AGENT') if d['user_agent']: user_agent = parse(d['user_agent']) d['browser'] = user_agent.browser.family d['is_bot'], d['is_mobile'], d['is_tablet'], d['is_pc'] = user_agent.is_bot, user_agent.is_mobile, user_agent.is_tablet, user_agent.is_pc p = models.Visit(**d) p.date = datetime.now() db.session.add(p) db.session.commit() return redirect(red_url, code=302)
def cadenceInfo(): try: a = modules.getModel(models.App, appid=request.form.get('appid')).id except Exception as e: return jsonify() dates = {} utc_now = datetime.utcnow() now = datetime.utcnow()+timedelta(hours=int(request.form.get('offset', -8))) cadence_ids = request.form.get('cadence_ids', '').split(',') emails_orm = db.session.query(models.Email).with_entities(models.Email.id, models.Email.date_sent).filter(models.Email.legion_cadence_id.in_(cadence_ids)).all() emails = [(e.id, e.date_sent) for e in emails_orm if e.id and e.date_sent] for e in emails: date_formatted = datetime.strftime(e[1], '%m/%d/%Y') if date_formatted not in dates: dates[date_formatted] = [] dates[date_formatted].append(e[0]) ids = [a[0] for a in emails] num_emails = float(len(ids)) all_opens = db.session.query(models.Visit).filter(models.Visit.email_id.in_(ids)).all() most_recent_opens = [('open', s.email.to_address, ((utc_now-s.date).seconds), ((utc_now-s.date).seconds/60), ((utc_now-s.date).seconds/3600), s.email.subject) for s in sorted(all_opens, key = lambda x:x.date)[-10:]][::-1] all_opens = {a.email_id:1 for a in all_opens} all_links = db.session.query(models.Link).filter(models.Link.email_id.in_(ids)).all() link_ids = [l.id for l in all_links] all_clicks = db.session.query(models.Visit).filter(models.Visit.link_id.in_(link_ids)).all() most_recent_clicks = [('click', s.link.email.to_address, ((utc_now-s.date).seconds), ((utc_now-s.date).seconds/60), ((utc_now-s.date).seconds/3600), s.link.email.subject) for s in sorted(all_clicks, key = lambda x:x.date)[-10:]][::-1] all_clicks = {a.link.email_id:1 for a in all_clicks} all_replies = db.session.query(models.Email).filter(and_(models.Email.replied_to.in_(ids), models.Email.bounce==False)) most_recent_replies = [('reply', s.from_address, ((utc_now-s.date_sent).seconds), ((utc_now-s.date_sent).seconds/60), ((utc_now-s.date_sent).seconds/3600), s.subject) for s in sorted(all_replies, key = lambda x:x.date_sent)[-10:]][::-1] all_replies = {e.replied_to:1 for e in all_replies} stats = {'dates': {}} for day in modules.date_range(now-timedelta(days=7), now): _day = datetime.strftime(day, '%m/%d/%Y') if _day not in dates: stats['dates'][_day] = {'sent':0, 'opens':0, 'replies':0, 'clicks':0} continue stats['dates'][_day] = { 'sent':len(dates[_day]), 'opens':sum([all_opens.get(a, 0) for a in dates[_day]]), 'replies':sum([all_replies.get(a, 0) for a in dates[_day]]), 'clicks':sum([all_clicks.get(a, 0) for a in dates[_day]]), } stats['dates'] = [(x, stats['dates'][x]) for x in sorted(stats['dates'])] stats['most_recent_replies'] = most_recent_replies stats['most_recent_clicks'] = most_recent_clicks stats['most_recent_opens'] = most_recent_opens return jsonify(stats)
def getInfoOnEmail(): if 'appid' not in request.form or 'email' not in request.form: return jsonify(success=False, reason='appid not in POST') email_id = request.form.get('email', '') a = db.session.query(models.App).filter_by(appid=request.form['appid']).first() if not a: return jsonify(success=False, reason='no such app found') a = a.id email = modules.getModel(models.Email, emailid = email_id) to_return = {} if email.google_message_id: #is a google message to_return['thread'] = _getStatsOnGoogleThread(email.thread.unique_thread_id) return jsonify(success=True, threads = to_return)
def _getStatsOnGoogleThread(threadId): thread = modules.getModel(models.Thread, unique_thread_id=threadId) messages_in_thread = thread.emails num_messages = len(messages_in_thread) from_addresses = list(set([e.from_address for e in messages_in_thread if e.from_address])) has_bounce = sum([e.bounce for e in messages_in_thread if e.from_address]) > 0 to_addresses = list(set([e.to_address for e in messages_in_thread if e.to_address])) to_return = {'type':'google', 'unique_thread_id':threadId, 'messages':sorted(map(cleanEmail,messages_in_thread), key=lambda x:x['date_sent']), 'has_bounce':has_bounce, 'num_messages':num_messages, 'from_addresses':from_addresses, 'to_addresses':to_addresses} to_return['all_parties_replied'] = thread.all_parties_replied to_return['date_of_first_message'] = to_return['messages'][0]['date_sent'] to_return['bounced_emails'] = [e.bounced_email for e in messages_in_thread if e.bounced_email] try: to_return['date_of_last_open'] = reduce(lambda x, y:x+y, [m['last_few_opens'] for m in to_return['messages']])[-1]['date'] except: to_return['date_of_last_open'] = None return to_return
def _makeDBEmail(form_dict): app = modules.getModel(models.App, appid=form_dict['appid']) if app: d = {} created = False d['app_id'] = app.id while not created: random_email = 'ee'+''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(9)) for i in ['google_message_id', 'google_thread_id', 'date_sent', 'text', 'html', 'cc_address', 'bcc_address', 'to_address', 'from_address', 'subject']: if i in form_dict: d[i] = form_dict[i] if i == 'text': d['makeshift_sentiment'] = googleAPI.MakeshiftSentiment(d[i]) elif i == 'html': d['makeshift_sentiment'] = googleAPI.MakeshiftSentiment(bs(d[i]).text) e, created = modules.get_or_create(models.Email, emailid=random_email, **d) return {'success':True, 'email_id':e.id, 'emailid':random_email, 'tracking_link':'https://www.latracking.com/e/'+random_email} return {'success':False}
def _makeDBLink(email_id, text, url, appid): r = re.match(website_re, url) if '.' not in r.group(4): return {'success': False, 'reason': 'not a valid url'} if not r.group(1): u = 'http://' else: u = r.group(1) u+=r.group(3)+r.group(4) if r.group(5): u += '/'+r.group(5) app = modules.getModel(models.App, appid=appid) if app: created = False while not created: random_link = 'll'+''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(9)) l, created = modules.get_or_create(models.Link, linkid=random_link, defaults = {'app_id':app.id, 'email_id':email_id, 'url':u, 'text': text}) return {'success':True, 'link_id':random_link, 'url':u, 'latracking_url':'https://www.latracking.com/r/'+random_link} return {'success':False}
def test(): if request.method == 'POST': if 'delete' in request.form: a = modules.get_or_create(models.App, appid=request.form['delete'])[0] db.session.delete(a) db.session.commit() elif 'site_to_track' in request.form: base = request.form['site_to_track'].replace('https://','').replace('http://','').replace('www.','').replace('/','').lower().strip() w, w_c = modules.get_or_create(models.Website, base=base) a = modules.getModel(models.App, website = w) if a: flash('Someone already owns this website!', 'error') else: a = models.App(appid = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(20)), user = current_user, website = w) db.session.add(a) db.session.commit() redirect('/test') apps = db.session.query(models.App).filter_by(user_id = current_user.id).all() return render_template('test.html', apps = apps)
def insert(): error = 'tracked visit. Nothing more to see here' status = 'success' try: d = {} d['private_ip'] = request.environ.get('REMOTE_ADDR') d['public_ip'] = request.environ.get('HTTP_X_FORWARDED_FOR') d['full_url'] = request.environ.get('HTTP_REFERER', '').strip().lower() if 'appid' in request.form: if 'event' in request.form: d['visit_id'] = db.session.query(models.Visit).filter_by(full_url=d['full_url'], public_ip=d['public_ip'], private_ip=d['private_ip']).order_by('-id').first().id d['event_type'] = request.form['event_type'].lower() d['element_id'] = request.form['element_id'].lower() d['element_type'] = request.form['element_type'].lower() d['element_tag'] = request.form['element_tag'].lower() if 'public_ip' in d: del d['public_ip'] if 'private_ip' in d: del d['private_ip'] if 'full_url' in d: del d['full_url'] e = models.Event(**d) e.date = datetime.now() db.session.add(e) db.session.commit() return jsonify(**{'status':'success', 'description':'event recorded'}) app = modules.getModel(models.App, appid = request.form['appid']) if not app: return jsonify(**{'status':'failure', 'description':'no app found with that id'}) if app.website.base not in d['full_url']: return jsonify(**{'status':'failure', 'description':'app is for a different website'}) ur = d['full_url'].replace('https://','').replace('http://','').replace('www.','').lower().strip() if '/' not in ur: ur += '/' base, d['after'] = ur[:ur.index('/')], ur[ur.index('/')+1:] d['website_id'] = app.website.id if len(d['after']) <= 1: d['after'] = None elif d['after'][-1] == '/': d['after'] = d['after'][:-1] if '?' in ur: if d['after']: d['after'] = d['after'].split('?')[0] d['gets'] = ur.split('?')[1] if len(d['gets']) <= 1: d['gets'] = None d['secure'] = 'https://' in d['full_url'] else: return jsonify(**{'status':'failure', 'description':'no recognized action taken'}) if d['public_ip']: g = geocoder.ip(d['public_ip']) d['lat'], d['lng'] = g.latlng d['city'] = g.city d['country'] = g.country d['state'] = g.state d['user_agent'] = request.environ.get('HTTP_USER_AGENT') if d['user_agent']: user_agent = parse(d['user_agent']) d['browser'] = user_agent.browser.family d['is_bot'], d['is_mobile'], d['is_tablet'], d['is_pc'] = user_agent.is_bot, user_agent.is_mobile, user_agent.is_tablet, user_agent.is_pc p = models.Visit(**d) p.date = datetime.now() db.session.add(p) db.session.commit() except Exception as e: error = repr(e) status = 'failure' return jsonify(**{'status':status, 'description':error})