· 6 years ago · Jul 20, 2019, 11:20 AM
1from flask import request, Flask
2from flask_mail import Mail, Message as Fmessage
3from flask_restful import abort, reqparse, Api, Resource
4from cassandra.cluster import Cluster
5from cassandra.query import ordered_dict_factory
6import uuid
7
8app = Flask(__name__)
9
10app.config["MAIL_DEBUG"] = True
11app.config["TESTING"] = False
12app.config["MAIL_SERVER"] = "smtp.gmail.com"
13app.config["MAIL_PORT"] = 465
14app.config["MAIL_USE_SSL"] = True
15app.config["MAIL_USERNAME"] = 'nie@gmail.com' ## CHANGE THIS
16app.config["MAIL_PASSWORD"] = 'password'
17app.config["MAIL_DEFAULT_SENDER"] = 'test@test.pl'
18
19api = Api(app)
20cluster = Cluster()
21mail = Mail(app)
22
23def build_database_scheme(cluster):
24 session = cluster.connect()
25 session.execute('''
26 CREATE KEYSPACE IF NOT EXISTS app
27 WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor' : 1}; ''')
28 session.set_keyspace('app')
29 session.execute('''
30 CREATE TABLE IF NOT EXISTS message (
31 id uuid PRIMARY KEY,
32 email text,
33 title text,
34 content text,
35 magic_number int)
36 WITH default_time_to_live = 300;''')
37 session.execute('''
38 CREATE MATERIALIZED VIEW IF NOT EXISTS message_id_by_magic_number AS
39 SELECT id FROM message
40 WHERE id IS NOT NULL AND magic_number IS NOT NULL
41 PRIMARY KEY (magic_number, id); ''')
42 session.execute('''
43 CREATE MATERIALIZED VIEW IF NOT EXISTS message_by_email AS
44 SELECT * FROM message
45 WHERE id IS NOT NULL AND email IS NOT NULL
46 PRIMARY KEY (email, id); ''')
47
48def get_args_from_post(request, *args, json = True):
49 parser = reqparse.RequestParser()
50
51 for arg in args[0]:
52 arg_type = arg['type'] if 'type' in arg else str
53 arg_location = arg['location'] if 'location' in arg else ('json', 'values')
54 parser.add_argument(arg['name'], type=arg_type, location=arg_location)
55
56 if json:
57 request.get_json(force=True)
58
59 return parser.parse_args()
60
61build_database_scheme(cluster)
62
63class Message(Resource):
64 def post(self):
65 args = get_args_from_post(request, (
66 {'name': 'email'},
67 {'name': 'title'},
68 {'name': 'content'},
69 {'name': 'magic_number', 'type': int}
70 ))
71 session = cluster.connect()
72 session.set_keyspace('app')
73 cql = "INSERT INTO message (id, email, title, content, magic_number) VALUES (%s, %s, %s, %s, %s);"
74 session.execute(cql, (uuid.uuid1(), args['email'], args['title'], args['content'], args['magic_number']))
75 return args
76
77class MessageList(Resource):
78 def get(self, email):
79 cql = "SELECT * FROM message_by_email WHERE email = %s"
80 session = cluster.connect('app')
81 session.row_factory = ordered_dict_factory
82 result = session.execute(cql, (email,))
83
84 messages = []
85
86 for row in result:
87 message = row
88 message['id'] = message['id'].__str__()
89 messages.append(message)
90
91 if messages:
92 return messages
93
94 abort(404, message="There are no messages for email {}".format(email))
95
96class SendingMessage(Resource):
97 def post(self):
98 args = get_args_from_post(request, ({'name' : 'magic_number', 'type': int},))
99 session = cluster.connect('app')
100
101 cql = "SELECT id FROM message_id_by_magic_number WHERE magic_number = %s"
102 session.row_factory = ordered_dict_factory
103 result = session.execute(cql, (args['magic_number'],))
104
105 ids = [row['id'] for row in result]
106 message_lookup_statement = session.prepare("SELECT * FROM message WHERE id = ?")
107 message_delete_statement = session.prepare("DELETE FROM message WHERE id = ?")
108
109 messages = []
110
111 for id in ids:
112 messages.append(session.execute(message_lookup_statement, [id]).one())
113
114 with mail.connect() as connection:
115 for message in messages:
116 msg = Fmessage(recipients=[message['email']],
117 body=message['content'],
118 subject=message['title'])
119 try:
120 connection.send(msg)
121 except:
122 abort(401)
123 else:
124 session.execute(message_delete_statement, [message['id']])
125
126 if messages:
127 return { 'message': 'Emails for magic number {} has been sent'.format(args['magic_number']) }
128 else:
129 return { 'message': 'There is no email to send for given magic number' }
130
131api.add_resource(Message, '/api/message')
132api.add_resource(MessageList, '/api/messages/<email>')
133api.add_resource(SendingMessage, '/api/send')
134
135if __name__ == '__main__':
136 app.run(debug=True)