· 9 years ago · Jul 09, 2016, 01:09 PM
1from flask import Flask, render_template, url_for, flash, redirect, request, session, g
2from forms import LoginForm, RegistrationForm, AddAssetForm, EditReservationForm, MakeReservationForm
3import sqlite3, smtplib
4from contextlib import closing
5from flask_login import LoginManager, login_user, logout_user, current_user, login_required, UserMixin
6from datetime import date, timedelta, datetime
7from email.MIMEMultipart import MIMEMultipart
8from email.MIMEText import MIMEText
9from threading import Thread
10from string import capwords
11
12
13
14#Initialization
15app = Flask(__name__)
16
17#Configuration
18
19SECRET_KEY = 'foobar'
20DEBUG = True
21DATABASE = "C:\\Python27\\asset\\asset.db"
22WTF_CSRF_ENABLED = True
23SMTP_SERVER = 'smtp.gmail.com:587'
24ADMIN_EMAIL = 'admin@example.com' #Put admin's email address here.
25
26lm = LoginManager()
27lm.init_app(app)
28
29#Initialization
30app.config.from_object(__name__)
31
32def connect_db():
33 return sqlite3.connect(app.config['DATABASE'])
34
35def create_table(): #To set up database. We need a asset.db file to exist in the main folder.
36 with closing(connect_db()) as conn:
37 with app.open_resource('schema.sql', mode = 'r') as f:
38 conn.cursor().executescript(f.read())
39 conn.commit()
40
41 print('Tables created.')
42
43def fetch_user(username):
44 conn = connect_db()
45 conn.row_factory = sqlite3.Row
46 curs = conn.cursor()
47 curs.execute('select * from user where username = (?) collate nocase', [str(username)])
48 return curs.fetchone()
49
50def fetch_asset(assetname):
51 conn = connect_db()
52 conn.row_factory = sqlite3.Row
53 curs = conn.cursor()
54 curs.execute('select * from asset where assetname = (?) collate nocase', [str(assetname)])
55 return curs.fetchone()
56
57def send_asynch(to_address, message): #Sends email asynchrously.
58 data = MIMEMultipart()
59 from_address = 'noreply.server995@gmail.com'
60 data['From'] = from_address
61 data['To'] = to_address
62 data['Subject'] = message['subject']
63 data.attach(MIMEText(message['body']))
64 server = smtplib.SMTP(app.config['SMTP_SERVER'])
65 server.ehlo()
66 server.starttls()
67 server.ehlo()
68 server.login('noreply.server995', 'assetmanage')
69 try:
70 server.sendmail(from_address, to_address, str(data))
71 except:
72 print('User\'s email is not valid.')
73 return
74 server.quit()
75 print('Delivered mail to %s.' % to_address)
76
77def send_mail(to_address, message):
78 thr = Thread(target = send_asynch, args = [to_address, message])
79 thr.start()
80
81
82class User(UserMixin):
83
84 def __init__(self, username, password, email):
85 self.username = capwords(username)
86 self.password = password
87 self.email = email
88
89 def is_authenticated():
90 return True
91
92 def is_active():
93 return True
94
95 def is_annonymous():
96 return False
97
98 def is_admin():
99 conn = connect_db()
100 conn.row_factory = sqlite3.Row
101 curs = conn.cursor()
102 curs.execute('select isadmin from user where username = (?) collate nocase', [self.username])
103 flag = curs.fetchone()[0]
104 return flag == 1
105
106
107 def get_id(self):
108 conn = connect_db()
109 conn.row_factory = sqlite3.Row
110 curs = conn.cursor()
111 curs.execute('select uid from user where username = (?) collate nocase', [self.username])
112 return unicode(curs.fetchone()[0])
113
114 def get_username(self):
115 return self.username
116
117 def get_email(self):
118 return self.email
119
120 def add_db(self):
121 curs = g.db.cursor()
122 curs.execute('insert into user(username, password, email) values (?, ?, ?)', [self.username, self.password, self.email])
123 g.db.commit()
124
125
126#Views
127
128@app.route('/') #Home page of the user. Shows assets currently reserved by the user.
129@app.route('/index')
130def index():
131 if not (g.user is not None and hasattr(g.user, 'is_authenticated') and g.user.is_authenticated):
132 return redirect(url_for('login'))
133 curs = g.db.cursor()
134 g.db.row_factory = sqlite3.Row
135 curs.execute('select * from asset where isreserved = (?) and owner = (?)', [1, g.user.get_id()])
136 assets = curs.fetchall()
137 return render_template('index.html', assets = assets)
138
139@lm.user_loader
140def load_user(id):
141 conn = connect_db()
142 conn.row_factory = sqlite3.Row
143 curs = conn.cursor()
144 curs.execute('select * from user where uid = (?)', [id])
145 foo = curs.fetchone()
146 if foo is not None:
147 return User(foo[1], foo[2], foo[3])
148 else:
149 return 'User not found.'
150
151@app.route('/login', methods = ['GET', 'POST']) #Log in user.
152def login():
153 if g.user is not None and hasattr(g.user, 'is_authenticated') and g.user.is_authenticated:
154 return redirect(url_for('index'))
155 form = LoginForm()
156 if request.method == 'POST' and form.validate_on_submit():
157 #session['remember_me'] = form.remember_me.data
158 g.username = form.username.data
159 g.password = form.password.data
160 user_db = fetch_user(g.username)
161 if user_db is not None:
162 if g.password == user_db[2]:
163 user = User(user_db[1], user_db[2], user_db[3])
164 login_user(user, remember = form.remember_me.data)
165 #g.user = user
166 flash('Login successful. Welcome %s!' % user_db[1])
167 return redirect(url_for('index'))
168 else:
169 flash('Incorrect password.')
170 return redirect(url_for('login'))
171 else:
172 flash('No such user exists.')
173 return redirect(url_for('login'))
174 return render_template('login.html', title = 'Sign In', form = form)
175
176def check_email(email): #To check if the argument email already exists in the database. Called while registering to ensure emails are not associated with multiple accounts.
177 conn = g.db
178 conn.row_factory = sqlite3.Row
179 curs = conn.cursor()
180 curs.execute('select * from user where email = (?)', [email])
181 return len(curs.fetchall()) != 0
182
183
184@app.route('/register', methods = ['GET', 'POST']) #Create a new user account.
185def register():
186 if g.user is not None and hasattr(g.user, 'is_authenticated') and g.user.is_authenticated:
187 return redirect(url_for('index'))
188 form = RegistrationForm()
189 if request.method == 'POST' and form.validate_on_submit():
190 if fetch_user(form.username.data) is not None:
191 flash('This username already exists. Please choose another one.')
192 return redirect(url_for('register'))
193 elif(check_email(form.email.data)):
194 flash('This email is already associated with an account. Please choose another one.')
195 return redirect(url_for('register'))
196 user = User(username = form.username.data, password = form.password.data, email = form.email.data)
197 user.add_db()
198 message = {'subject': 'Thank you for registering at AssetReservation!',
199 'body': 'Hi %s, you have successfully registered at AssetReservation.' % form.username.data}
200 send_mail(form.email.data, message)
201 flash('Registration successful! You may now login into your account.')
202 return redirect(url_for('login'))
203 return render_template('register.html', title = 'Sign Up', form = form)
204
205@app.route('/logout') #Log out user.
206@login_required
207def logout():
208 logout_user()
209 flash('Logged out.')
210 return redirect(url_for('login'))
211
212@app.route('/addasset', methods = ['GET', 'POST']) #To create a new asset. User can reserve the new asset here itself.
213@login_required
214def add_asset():
215 form = AddAssetForm()
216 if request.method == 'POST' and form.validate_on_submit():
217 if fetch_asset(form.assetname.data) is not None:
218 flash('An asset with that name already exists. Please choose another name.')
219 return redirect(url_for('add_asset'))
220 else:
221 curs = g.db.cursor()
222 if form.reserve_it.data:
223 release_date = str(date.today() + timedelta(days = form.days.data))
224 owner = int(g.user.get_id())
225 curs.execute('insert into asset(assetname, releasedate, owner, isreserved) values (?, ?, ?, ?)', [capwords(form.assetname.data), release_date, owner, 1])
226 message = {'subject': 'An asset has been reserved.',
227 'body': 'User %s has reserved asset %s for %d days' % (g.user.get_username(), form.assetname.data, form.days.data)}
228 send_mail(g.user.get_email(), message)
229 send_mail(app.config['ADMIN_EMAIL'], message)
230 else:
231 curs.execute('insert into asset(assetname) values (?)', [capwords(form.assetname.data)])
232 g.db.commit()
233 flash('Successfully created asset named %s.' % capwords(form.assetname.data))
234 return render_template('add asset.html', form = form)
235 return render_template('add asset.html', form = form)
236
237@app.route('/asset/<asset_name>') #To display asset information.
238def asset(asset_name):
239 asset = fetch_asset(asset_name)
240 if asset is None:
241 flash('Asset not found.')
242 return redirect(url_for('index'))
243 curs = g.db.cursor()
244 g.db.row_factory = sqlite3.Row
245 curs.execute('select username from user where uid = (?)', [asset[3]])
246 owner = str(curs.fetchone()[0])
247 return render_template('asset.html', title = asset_name, asset = asset, owner = owner)
248
249@app.route('/manage') #Manage Assets page where user can reserve new assets and change reservation of current assets.
250@login_required
251def manage():
252 curs = g.db.cursor()
253 g.db.row_factory = sqlite3.Row
254 curs.execute('select * from asset where isreserved = (?) and owner = (?)', [1, g.user.get_id()])
255 users_assets = curs.fetchall()
256 curs.execute('select * from asset where isreserved = (?) and not owner = (?)', [1, g.user.get_id()])
257 others_assets = curs.fetchall()
258 curs.execute('select * from asset where isreserved = 0')
259 free_assets = curs.fetchall()
260 return render_template('manage.html', title = 'Manage Assets', users_assets = users_assets, others_assets = others_assets, free_assets = free_assets)
261
262@app.route('/editreservation/<asset_name>', methods = ['GET', 'POST']) #To edit a current reservation. User can extend reservation or revoke it.
263@login_required
264def edit_reservation(asset_name):
265 asset = fetch_asset(asset_name)
266 if asset is None:
267 flash('Asset not found.')
268 return redirect(url_for('manage'))
269 elif not (asset[4] == 1 and asset[3] == int(g.user.get_id())):
270 flash('You can\'t edit reservation for this asset.')
271 return redirect(url_for('manage'))
272 form = EditReservationForm()
273 if request.method == 'POST' and form.validate_on_submit():
274 revoke = form.revoke_reservation.data
275 curs = g.db.cursor()
276 if revoke:
277 curs.execute('update asset set isreserved = (?) where aid = (?)', [0, asset[0]])
278 g.db.commit()
279 flash('Successfully revoked reservation for asset %s.' % asset[1])
280 return redirect(url_for('manage'))
281 elif form.days.data != 0:
282 release_date = str(datetime.strptime(str(asset[2]), '%Y-%m-%d').date() + timedelta(days = form.days.data))
283 curs.execute('update asset set releasedate = (?) where aid = (?)', [release_date, asset[0]])
284 g.db.commit()
285 flash('Successfully updated asset %s\'s release date to %s' % (asset[1], release_date))
286 return redirect(url_for('manage'))
287 return render_template('edit reservation.html', date = asset[2], form = form)
288
289@app.route('/makereservation/<asset_name>', methods = ['GET', 'POST']) #To make a new reservation.
290@login_required
291def make_reservation(asset_name):
292 asset = fetch_asset(asset_name)
293 if asset is None:
294 flash('Asset not found.')
295 return redirect(url_for('manage'))
296 elif asset[4] == 1:
297 flash('You can\'t reserve this asset.')
298 return redirect(url_for('manage'))
299 form = MakeReservationForm()
300 if request.method == 'POST' and form.validate_on_submit():
301 if form.days.data != 0:
302 curs = g.db.cursor()
303 curs.execute('update asset set isreserved = (?), owner = (?), releasedate = (?) where aid = (?)', [1, int(g.user.get_id()), str(date.today() + timedelta(days = form.days.data)), asset[0]])
304 g.db.commit()
305 message = {'subject': 'An asset has been reserved.',
306 'body': 'User %s has reserved asset %s for %d days' % (g.user.get_username(), asset_name, form.days.data)}
307 send_mail(g.user.get_email(), message)
308 send_mail(app.config['ADMIN_EMAIL'], message)
309 flash('Successfully reserved asset %s for %d days' % (asset[1], form.days.data))
310 return redirect(url_for('manage'))
311 return render_template('make reservation.html', title = 'Make Reservation', asset = asset_name, form = form)
312
313# @app.route('/admin', methods = ['GET', 'POST'])
314# @login_required
315# def admin():
316# if not g.user.is_admin():
317# flash('You need admin priviledges before you can visit this page.')
318# return redirect(url_for('index'))
319# return render_template('admin.html')
320
321
322@app.errorhandler(401)
323def unauthorized_error(error):
324 return render_template('401.html'), 401
325
326@app.before_request
327def before_request():
328 g.db = connect_db()
329 g.user = current_user
330
331@app.teardown_request
332def teardown_request(error):
333 if hasattr(g, 'db'):
334 g.db.close()
335
336
337#Running
338if __name__ == '__main__':
339 app.run()