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)
Example #2
0
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
Example #10
0
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}
Example #11
0
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})