Compare commits
2 Commits
9bc908233e
...
04c9110a9c
Author | SHA1 | Date |
---|---|---|
Vivian Lim | 04c9110a9c | |
Vivian Lim | 87ace86369 |
|
@ -0,0 +1,53 @@
|
|||
import config
|
||||
import MySQLdb
|
||||
|
||||
|
||||
db = MySQLdb.connect(user=config.MYSQL_USER, passwd=config.MYSQL_PASSWD, db=config.MYSQL_DB)
|
||||
def logmsg(msg, to, sentby):
|
||||
c = db.cursor()
|
||||
try:
|
||||
c.execute("""INSERT INTO sendlog (msg, sent_by) VALUES (%s, %s)""", (msg, sentby))
|
||||
sendlogid = c.lastrowid
|
||||
|
||||
for recipient in to:
|
||||
c.execute("""INSERT INTO sendlog_to (id, recipient) VALUES (%s, %s)""", (sendlogid, recipient))
|
||||
db.commit()
|
||||
except:
|
||||
print "um error"
|
||||
db.rollback()
|
||||
|
||||
def getloggedmsgs(lastOut):
|
||||
c = db.cursor(MySQLdb.cursors.DictCursor)
|
||||
c.execute("""SELECT sendlog.*, users.name AS sent_by_name FROM sendlog INNER JOIN users ON sendlog.sent_by = users.uid WHERE sendlog.id > %s ORDER BY id DESC""", (lastOut,))
|
||||
rows = c.fetchall()
|
||||
for r in rows:
|
||||
c.execute("""SELECT people.id, people.name FROM sendlog_to INNER JOIN people ON sendlog_to.recipient = people.id WHERE sendlog_to.id = %s """, (r['id'],))
|
||||
r['to'] = c.fetchall()
|
||||
db.commit()
|
||||
return rows
|
||||
|
||||
def loginboundmsg(inmsg):
|
||||
c = db.cursor()
|
||||
try:
|
||||
# check if this sender is known to us.
|
||||
shortfrom = inmsg['From'][2:] # also check for another form of number where +1 is omitted
|
||||
c.execute("""SELECT id FROM people WHERE people.phonenum = %s or people.phonenum = %s LIMIT 1""", (inmsg['From'], shortfrom))
|
||||
row = c.fetchone()
|
||||
sender_id = -1 # default to this if unknown...
|
||||
if row: # found? great, update sender_id.
|
||||
sender_id = row[0]
|
||||
|
||||
c.execute("""INSERT INTO inbound_msgs (`From`, SmsMessageSid, AccountSid, Body, SmsStatus, from_known_person) VALUES (%s, %s, %s, %s, %s, %s)""", (inmsg['From'], inmsg['SmsMessageSid'], inmsg['AccountSid'], inmsg['Body'], inmsg['SmsStatus'], sender_id))
|
||||
db.commit()
|
||||
except:
|
||||
print "um error"
|
||||
print c._last_executed
|
||||
db.rollback()
|
||||
|
||||
def getinboundmsgs(lastIn):
|
||||
c = db.cursor(MySQLdb.cursors.DictCursor)
|
||||
c.execute("""SELECT inbound_msgs.id, inbound_msgs.from, inbound_msgs.body, people.id as pid, people.name FROM `inbound_msgs` LEFT JOIN people ON inbound_msgs.from_known_person = people.id WHERE inbound_msgs.id > %s ORDER BY inbound_msgs.id DESC""", (lastIn,))
|
||||
print c._last_executed
|
||||
rows = c.fetchall()
|
||||
db.commit()
|
||||
return rows
|
|
@ -8,7 +8,8 @@ class LibAddrBook:
|
|||
self.db = MySQLdb.connect(user=config.MYSQL_USER, passwd=config.MYSQL_PASSWD, db=config.MYSQL_DB)
|
||||
def get_everyone(self):
|
||||
c = self.db.cursor()
|
||||
c.execute("""SELECT * from people""")
|
||||
c.execute("""SELECT * from people ORDER BY people.name ASC""")
|
||||
self.db.commit()
|
||||
ppl = []
|
||||
nums = []
|
||||
for row in c.fetchall():
|
||||
|
@ -21,6 +22,7 @@ class LibAddrBook:
|
|||
def get_groups(self):
|
||||
c = self.db.cursor()
|
||||
c.execute("""SELECT * from groups""")
|
||||
self.db.commit()
|
||||
groups = []
|
||||
for row in c.fetchall():
|
||||
groups.append({'gid': row[0], 'name': row[1]})
|
||||
|
@ -28,10 +30,12 @@ class LibAddrBook:
|
|||
|
||||
# todo: make sure ids is actually a list of numbers?
|
||||
def get_nums_with_ids(self, ids):
|
||||
if len(ids) == 0: return []
|
||||
c = self.db.cursor()
|
||||
idlist = ', '.join('{}'.format(x) for x in ids)
|
||||
print idlist
|
||||
c.execute("""SELECT * from people WHERE id IN ({})""".format(idlist))
|
||||
self.db.commit()
|
||||
nums = []
|
||||
for row in c.fetchall():
|
||||
nums.append(row[PHONE_NUM_COL])
|
||||
|
@ -48,5 +52,17 @@ class LibAddrBook:
|
|||
grouplist = ', '.join('{}'.format(x) for x in groups)
|
||||
print grouplist
|
||||
c.execute("""SELECT people.id from people INNER JOIN memberships ON people.id = memberships.person_id WHERE memberships.group_id IN ({})""".format(grouplist))
|
||||
self.db.commit()
|
||||
ids = [r[0] for r in c.fetchall()]
|
||||
return ids
|
||||
|
||||
def add_person(self, name, num):
|
||||
c = self.db.cursor()
|
||||
try:
|
||||
c.execute("""INSERT INTO people (name, phonenum) VALUES (%s, %s)""", (name, num))
|
||||
self.db.commit()
|
||||
return True
|
||||
except:
|
||||
print "error adding user"
|
||||
self.db.rollback()
|
||||
return False
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
from flask import Flask, jsonify, render_template, request, json, redirect, url_for
|
||||
#from libsmscast import LibSMSCast
|
||||
from mocksmscast import LibSMSCast
|
||||
from libaddrbook import LibAddrBook
|
||||
from flask.ext.login import login_user, logout_user, current_user, login_required, LoginManager
|
||||
import user
|
||||
import dbmsgs
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = 'abcdgfkfdhgslkjh' # lol
|
||||
|
@ -22,12 +24,23 @@ def send():
|
|||
to = [int(x) for x in json.loads(tostr)]
|
||||
print to
|
||||
|
||||
dbmsgs.logmsg(msg, to, current_user.uid)
|
||||
|
||||
dest = addr.get_nums_with_ids(to)
|
||||
print dest
|
||||
howmany = len(dest)
|
||||
client.send(dest, msg)
|
||||
return jsonify(result="sent {} to {} numbers(s)".format(msg, howmany))
|
||||
|
||||
@app.route('/_get_updates')
|
||||
@login_required
|
||||
def get_updates():
|
||||
lastOut = request.args.get('lastOut')
|
||||
if not lastOut: lastOut = 0
|
||||
lastIn = request.args.get('lastIn')
|
||||
if not lastIn: lastIn = 0
|
||||
return jsonify(msgs=dbmsgs.getloggedmsgs(lastOut), inbound=dbmsgs.getinboundmsgs(lastIn))
|
||||
|
||||
@app.route('/_get_people_in_groups')
|
||||
@login_required
|
||||
def get_people_in_groups():
|
||||
|
@ -51,11 +64,36 @@ def get_groups():
|
|||
groups = addr.get_groups()
|
||||
return jsonify(groups=groups)
|
||||
|
||||
@app.route('/addperson', methods=["GET","POST"])
|
||||
@login_required
|
||||
def add_person():
|
||||
statustext = ""
|
||||
if request.method == "POST":
|
||||
addr = LibAddrBook()
|
||||
name = request.form['name']
|
||||
num = request.form['num']
|
||||
state = addr.add_person(name, num)
|
||||
if not state: # failure
|
||||
statustext = "Failed to add person {}".format(name)
|
||||
else: # success
|
||||
statustext = "Successfully added person {}".format(name)
|
||||
return render_template('addperson.html', statustext=statustext)
|
||||
|
||||
|
||||
@app.route('/')
|
||||
@login_required
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
|
||||
@app.route("/_twilio_new_sms", methods=["POST"])
|
||||
def twilio_new_sms():
|
||||
if request.method == "POST":
|
||||
dbmsgs.loginboundmsg(request.form)
|
||||
return "(y)"
|
||||
#print request.form;
|
||||
return "(n)"
|
||||
|
||||
|
||||
@app.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
if current_user.is_authenticated() and current_user.is_active():
|
||||
|
@ -68,7 +106,7 @@ def login():
|
|||
# do login because username and password have been specified
|
||||
uid = user.authenticate(username, password)
|
||||
if uid != None:
|
||||
login_user(user.get(uid))
|
||||
login_user(user.get(uid), remember=True)
|
||||
return redirect(url_for('index'))
|
||||
return render_template('login.html')
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<p>add person</p>
|
||||
<p style="font-weight:bold">{{ statustext }}</p>
|
||||
<form name="addperson" action="/addperson" method="post">
|
||||
<p>name: <input type="text" name="name" autofocus /></p>
|
||||
<p>phone #: <input type="text" name="num" /></p>
|
||||
<p><input type="submit" value="Add" /></p>
|
||||
</form>
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block body %}
|
||||
<script type="text/javascript">
|
||||
window.SMSCAST = {};
|
||||
SMSCAST.largestMsgIdSeen = 0;
|
||||
SMSCAST.largestReceivedMsgIdSeen = 0;
|
||||
$(function() {
|
||||
$( document ).ready(function() {
|
||||
// doc ready. load users
|
||||
|
@ -8,7 +11,7 @@
|
|||
var people = data.people;
|
||||
for(var i=0; i<people.length; ++i){
|
||||
var p = people[i];
|
||||
$( "#people" ).append("<span class=\"person\" id=\"p_" + p.id + "\" person_id=\"" + p.id + "\">" + p.name + "</span>");
|
||||
$( "#people" ).append("<a href='#' class=\"person\" id=\"p_" + p.id + "\" person_id=\"" + p.id + "\">" + p.name + "</a>");
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -17,26 +20,44 @@
|
|||
var groups = data.groups;
|
||||
for(var i=0; i<groups.length; ++i){
|
||||
var g = groups[i];
|
||||
$( "#groups" ).append("<span class=\"group\" id=\"g_" + g.gid + "\" group_id=\"" + g.gid + "\">" + g.name + "</span>");
|
||||
$( "#groups" ).append("<a href='#' class=\"group\" id=\"g_" + g.gid + "\" group_id=\"" + g.gid + "\">" + g.name + "</a>");
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
loadUpdates(); // start getting live updates
|
||||
|
||||
});
|
||||
|
||||
var send = function() {
|
||||
var message = $('input[name="msg"]').val();
|
||||
if(message.length == 0) {
|
||||
$("#result").text("No message has been entered in the text field!");
|
||||
return false;
|
||||
}
|
||||
|
||||
var list = getSelectedPeople();
|
||||
if(list.length == 0){
|
||||
$("#result").text("No recipients have been selected!");
|
||||
return false;
|
||||
}
|
||||
$.getJSON($SCRIPT_ROOT + '/send', {
|
||||
msg: $('input[name="msg"]').val(),
|
||||
msg: message,
|
||||
to: JSON.stringify(list)
|
||||
}, function(data) {
|
||||
$("#result").text(data.result);
|
||||
});
|
||||
$('input[name="msg"]').val(''); // clear text field
|
||||
return false;
|
||||
}
|
||||
|
||||
$('a#send').bind('click', send);
|
||||
$('a#msgsend').bind('click', send);
|
||||
$('#msgfield').keypress(function (e) {
|
||||
if(e.which == 13) {
|
||||
send();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
$('#people').on('click', '.person', function(event) {
|
||||
var target = $(this);
|
||||
|
@ -70,7 +91,6 @@
|
|||
var id = people[i];
|
||||
$("#people > #p_" + id).addClass('selected');
|
||||
}
|
||||
$("#result").text(data.result);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
@ -92,28 +112,179 @@
|
|||
return(list);
|
||||
}
|
||||
|
||||
function loadUpdates(){
|
||||
$.getJSON($SCRIPT_ROOT + '/_get_updates', {
|
||||
lastOut:SMSCAST.largestMsgIdSeen,
|
||||
lastIn:SMSCAST.largestReceivedMsgIdSeen
|
||||
},
|
||||
function(data) {
|
||||
updateSentMessages(data.msgs);
|
||||
updateReceivedMessages(data.inbound);
|
||||
});
|
||||
setTimeout(loadUpdates, 5000);
|
||||
}
|
||||
function updateSentMessages(msgs){
|
||||
for(var i=msgs.length-1; i>=0; --i){
|
||||
if(msgs[i].id > SMSCAST.largestMsgIdSeen){ // only add messages more recent
|
||||
$( "#msgs" ).prepend(getMessageHtml(msgs[i]));
|
||||
}
|
||||
}
|
||||
if(msgs.length > 0){ // if this payload had any messages, keep track of the largest seen id.
|
||||
SMSCAST.largestMsgIdSeen = msgs[0].id;
|
||||
}
|
||||
|
||||
}
|
||||
function getMessageHtml(msg){
|
||||
var to = msg.to;
|
||||
var tolist = "";
|
||||
for(var i=0; i<to.length; ++i){
|
||||
tolist = tolist + to[i].name;
|
||||
if(i < to.length - 1){ // separate names with commas
|
||||
tolist = tolist + ", ";
|
||||
}
|
||||
}
|
||||
|
||||
return "<div class='msg outbound' id='" + msg.id + "'>" +
|
||||
"<div class='msg_text'>" + msg.msg + "</div>" +
|
||||
"<div class='msg_info'>sent by " + msg.sent_by_name + " at " + msg.when + "</div>" +
|
||||
"<div class='msg_info'>to " + tolist + "</div>" +
|
||||
"</div>";
|
||||
}
|
||||
function updateReceivedMessages(msgs){
|
||||
for(var i=msgs.length-1; i>=0; --i){
|
||||
if(msgs[i].id > SMSCAST.largestReceivedMsgIdSeen){ // only add messages more recent
|
||||
$( "#inmsgs" ).prepend(getReceivedMessageHtml(msgs[i]));
|
||||
}
|
||||
}
|
||||
if(msgs.length > 0){ // if this payload had any messages, keep track of the largest seen id.
|
||||
SMSCAST.largestReceivedMsgIdSeen = msgs[0].id;
|
||||
}
|
||||
}
|
||||
function getReceivedMessageHtml(msg){
|
||||
var str = "<div class='msg inbound' id='" + msg.id + "'>" +
|
||||
"<div class='msg_text'>" + msg.body + "</div>";
|
||||
if(msg.name){
|
||||
str = str + "<div class='msg_info'>from " + msg.name + "</div>";
|
||||
}
|
||||
else {
|
||||
str = str + "<div class='msg_info'>from " + msg.from + "</div>";
|
||||
}
|
||||
return str + "</div>";
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
*
|
||||
{
|
||||
font-family: "Myriad Pro", Arial;
|
||||
}
|
||||
.person, .group{
|
||||
border: 2px solid;
|
||||
display: inline-block;
|
||||
color: #222222;
|
||||
border: 2px solid #47aef5;
|
||||
border-radius: 10px;
|
||||
background-color: #bbb;
|
||||
background-color: #eee;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
padding: 5px;
|
||||
text-decoration: none;
|
||||
}
|
||||
.selected{
|
||||
background-color: #3c3;
|
||||
background-color: #47aef5;
|
||||
color: #fff;
|
||||
}
|
||||
.column{
|
||||
float:left;
|
||||
width:30%;
|
||||
min-width:400px;
|
||||
border: 2px solid black;
|
||||
margin: 2px;
|
||||
padding: 8px;
|
||||
height: 80%;
|
||||
overflow-y:scroll;
|
||||
}
|
||||
#content, html, body
|
||||
{
|
||||
height: 98%;
|
||||
background-color: #eefdff;
|
||||
}
|
||||
.column
|
||||
{
|
||||
background-color: #fffbcf;
|
||||
}
|
||||
#msgfield
|
||||
{
|
||||
font-size: xx-large;
|
||||
width: 80%;
|
||||
height: 1.5em;
|
||||
}
|
||||
#msgsend
|
||||
{
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
text-align: center;
|
||||
width: 10%;
|
||||
height: 1.5em;
|
||||
font-size: x-large;
|
||||
color: #fff;
|
||||
border: 2px solid #47aef5;
|
||||
border-radius: 10px;
|
||||
background-color: #47aef5;
|
||||
margin: 2px;
|
||||
padding: 5px;
|
||||
text-decoration: none;
|
||||
}
|
||||
#result
|
||||
{
|
||||
font-size: large;
|
||||
}
|
||||
.msg
|
||||
{
|
||||
border: 2px solid #e78e2b;
|
||||
border-radius: 5px;
|
||||
background-color: #ffca8a;
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
}
|
||||
.msg .msg_text
|
||||
{
|
||||
font-size: larger;
|
||||
font-weight: bold;
|
||||
}
|
||||
.msg .msg_info
|
||||
{
|
||||
font-size: smaller;
|
||||
padding-left: 1em;
|
||||
}
|
||||
a
|
||||
{
|
||||
font-color: 47aef5;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<div class="header">
|
||||
<p style="float:right">logged in as {{ current_user.name }} <a href="logout">log out</a></p>
|
||||
<h1>smscast</h1>
|
||||
<p><input type="text" name="msg"><a href="#" id="send">send</a></p>
|
||||
<p><span id="result">res</span></p>
|
||||
</div>
|
||||
<div id="send" class="column">
|
||||
<p style="msgarea"><input type="text" name="msg" id="msgfield"><a href="#" id="msgsend">Send!</a></p>
|
||||
<p><span id="result">Select recipients below and enter a message to broadcast in the box above.</span></p>
|
||||
<h2>groups</h2>
|
||||
<p id="groups"></p>
|
||||
<h2>people</h2>
|
||||
<p id="people"></p>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h2>sent messages</h2>
|
||||
<div id="msgs"></div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h2>received messages</h2>
|
||||
<div id="inmsgs"></div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<p>log in</p>
|
||||
<form name="login" action="/login" method="post">
|
||||
<p>Username: <input type="text" name="username" autofocus /></p>
|
||||
<p>Password: <input type="password" name="password" /></p>
|
||||
|
|
2
user.py
2
user.py
|
@ -10,6 +10,7 @@ class User:
|
|||
c = self.db.cursor()
|
||||
c.execute("""SELECT name FROM users WHERE uid = %s""", (uid,))
|
||||
self.name = c.fetchall()[0][0]
|
||||
self.db.commit()
|
||||
|
||||
def is_authenticated(self):
|
||||
return True # stub
|
||||
|
@ -33,6 +34,7 @@ def authenticate(username, password):
|
|||
|
||||
# get salt for the user
|
||||
c.execute("""SELECT salt, password, uid FROM users WHERE name = %s """ , (username,))
|
||||
db.commit()
|
||||
print "getting salt for {}".format(username)
|
||||
if(c.rowcount == 0): return None
|
||||
row = c.fetchall()[0]
|
||||
|
|
Loading…
Reference in New Issue