Compare commits

..

No commits in common. "a2de38563860546c21ecc3320806a4b27f287d63" and "29afdd025cb25aacdb670229dae7dcb2d684dffa" have entirely different histories.

13 changed files with 68 additions and 263 deletions

View File

@ -20,25 +20,15 @@ def two_factor_input():
return redirect(url_for('proute.index')) return redirect(url_for('proute.index'))
form = GetTotp() form = GetTotp()
if form.validate_on_submit(): if form.validate_on_submit():
if TOTP( if TOTP(contributor.totp_key).verify(int(form.totp_code.data), valid_window=5):
contributor.totp_key,
).verify(int(form.totp_code.data), valid_window=5):
login_user(contributor, remember=session['remember_me']) login_user(contributor, remember=session['remember_me'])
flash("Congratulations, you are now logged in!") flash("Congratulations, you are now logged in!")
return redirect(url_for('proute.index')) return redirect(url_for('proute.index'))
else: else:
flash("Oops, the pin was wrong") flash("Oops, the pin was wrong")
form.totp_code.data = None form.totp_code.data = None
return render_template( return render_template('two_factor_input.html', form=form, inst="Code was wrong, try again?")
'two_factor_input.html', return render_template('two_factor_input.html', form=form, inst="Enter Auth Code")
form=form,
inst="Code was wrong, try again?",
)
return render_template(
'two_factor_input.html',
form=form,
inst="Enter Auth Code",
)
@auths.route("/login", methods=["GET", "POST"]) @auths.route("/login", methods=["GET", "POST"])
@ -47,14 +37,9 @@ def login():
return redirect(url_for('proute.index')) return redirect(url_for('proute.index'))
form = LoginForm() form = LoginForm()
if form.validate_on_submit(): if form.validate_on_submit():
contributor_by_name = Contributor.query.filter_by( contributor_by_name = Contributor.query.filter_by(name=form.username.data).first()
name=form.username.data, contributor_by_email = Contributor.query.filter_by(email=form.email.data).first()
).first() if contributor_by_name is not None and contributor_by_name.check_password(form.password.data):
contributor_by_email = Contributor.query.filter_by(
email=form.email.data,
).first()
cbn, cbe = contributor_by_name, contributor_by_email
if cbn is not None and cbn.check_password(form.password.data):
if contributor_by_name.use_totp: if contributor_by_name.use_totp:
session['id'] = contributor_by_name.id session['id'] = contributor_by_name.id
session['remember_me'] = form.remember_me.data session['remember_me'] = form.remember_me.data
@ -63,16 +48,13 @@ def login():
login_user(contributor_by_name, remember=form.remember_me.data) login_user(contributor_by_name, remember=form.remember_me.data)
flash("Congratulations, you are now logged in!") flash("Congratulations, you are now logged in!")
return redirect(url_for('proute.index')) return redirect(url_for('proute.index'))
elif cbe is not None and cbe.check_password(form.password.data): elif contributor_by_email is not None and contributor_by_email.check_password(form.password.data):
if contributor_by_email.use_totp: if contributor_by_email.use_totp:
session['id'] = contributor_by_email.id session['id'] = contributor_by_email.id
session['remember_me'] = form.remember_me.data session['remember_me'] = form.remember_me.data
return redirect(url_for('auths.two_factor_input')) return redirect(url_for('auths.two_factor_input'))
else: else:
login_user( login_user(contributor_by_email, remember=form.remember_me.data)
contributor_by_email,
remember=form.remember_me.data,
)
flash("Congratulations, you are now logged in!") flash("Congratulations, you are now logged in!")
return redirect(url_for('proute.index')) return redirect(url_for('proute.index'))
else: else:

View File

@ -8,23 +8,13 @@ from threading import Thread
def send_password_reset_email(contributor, external_url): def send_password_reset_email(contributor, external_url):
token = contributor.get_reset_password_token() token = contributor.get_reset_password_token()
send_email( send_email('Photo App Reset Your Password',
'Photo App Reset Your Password', sender=current_app.config['MAIL_ADMINS'][0],
sender=current_app.config['MAIL_ADMINS'][0], recipients=[contributor.email],
recipients=[contributor.email], text_body=render_template('email/reset_password_email_text.txt',
text_body=render_template( contributor=contributor, token=token, external_url=external_url),
'email/reset_password_email_text.txt', html_body=render_template('email/reset_password_email_html.html',
contributor=contributor, contributor=contributor, token=token, external_url=external_url))
token=token,
external_url=external_url,
),
html_body=render_template(
'email/reset_password_email_html.html',
contributor=contributor,
token=token,
external_url=external_url,
),
)
def send_async_email(app, msg): def send_async_email(app, msg):
@ -36,7 +26,4 @@ def send_email(subject, sender, recipients, text_body, html_body):
msg = Message(subject, sender=sender, recipients=recipients) msg = Message(subject, sender=sender, recipients=recipients)
msg.body = text_body msg.body = text_body
msg.html = html_body msg.html = html_body
Thread( Thread(target=send_async_email, args=(current_app._get_current_object(), msg)).start()
target=send_async_email,
args=(current_app._get_current_object(), msg),
).start()

View File

@ -26,11 +26,7 @@ def change_password():
else: else:
flash("Error Invalid Password") flash("Error Invalid Password")
return(redirect(url_for('prof.change_password'))) return(redirect(url_for('prof.change_password')))
return render_template( return render_template('change_password.html', title='Change Password', form=form)
'change_password.html',
title='Change Password',
form=form,
)
@prof.route("/edit-profile", methods=["GET", "POST"]) @prof.route("/edit-profile", methods=["GET", "POST"])

View File

@ -17,15 +17,9 @@ def register():
return redirect(url_for('proute.index')) return redirect(url_for('proute.index'))
form = RegistrationForm() form = RegistrationForm()
if form.validate_on_submit(): if form.validate_on_submit():
my_sql = "SELECT setval('contributor_id_seq', " db.engine.execute("SELECT setval('contributor_id_seq', (SELECT MAX(id) FROM contributor))")
my_sql += "(SELECT MAX(id) FROM contributor))"
db.engine.execute(my_sql)
db.session.commit() db.session.commit()
contributor = Contributor( contributor = Contributor(name=form.username.data, num_photos=0, email=form.email.data)
name=form.username.data,
num_photos=0,
email=form.email.data,
)
contributor.set_password(form.password.data) contributor.set_password(form.password.data)
db.session.add(contributor) db.session.add(contributor)
db.session.commit() db.session.commit()

View File

@ -1,8 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from flask import ( from flask import Blueprint, redirect, url_for, flash, render_template, current_app
Blueprint, redirect, url_for, flash, render_template, current_app
)
from flask_login import current_user from flask_login import current_user
from app.models import Contributor from app.models import Contributor
from app.forms import ResetPasswordForm, ResetPasswordRequestForm from app.forms import ResetPasswordForm, ResetPasswordRequestForm
@ -27,11 +25,7 @@ def reset_password(token):
db.session.commit() db.session.commit()
flash('Your password has been reset.') flash('Your password has been reset.')
return redirect(url_for('auths.login')) return redirect(url_for('auths.login'))
return render_template( return render_template('reset_password.html', title="New Password?", form=form)
'reset_password.html',
title="New Password?",
form=form,
)
@pwd.route('/reset-password-request', methods=['GET', 'POST']) @pwd.route('/reset-password-request', methods=['GET', 'POST'])
@ -41,23 +35,12 @@ def reset_password_request():
else: else:
form = ResetPasswordRequestForm() form = ResetPasswordRequestForm()
if form.validate_on_submit(): if form.validate_on_submit():
contributor = Contributor.query.filter_by( contributor = Contributor.query.filter_by(email=form.email.data).first()
email=form.email.data,
).first()
if contributor: if contributor:
send_password_reset_email( send_password_reset_email(contributor, current_app.config['EXTERNAL_URL'])
contributor, flash('Check your email for the instructions to reset your password')
current_app.config['EXTERNAL_URL'],
)
my_flash = 'Check your email for the instructions '
my_flash += 'to reset your password'
flash(my_flash)
return redirect(url_for('auths.login')) return redirect(url_for('auths.login'))
else: else:
flash('Sorry, invalid email') flash('Sorry, invalid email')
return redirect(url_for('auths.login')) return redirect(url_for('auths.login'))
return render_template( return render_template('reset_password_request.html', title='Reset Password', form=form)
'reset_password_request.html',
title='Reset Password',
form=form,
)

View File

@ -32,12 +32,7 @@ def enable_totp():
else: else:
flash("TOTP Code didn't validate, rescan and try again") flash("TOTP Code didn't validate, rescan and try again")
return(redirect(url_for('prof.edit_profile'))) return(redirect(url_for('prof.edit_profile')))
return render_template( return render_template('qr.html', qr=qr, form=form, title="Aunthentication Code")
'qr.html',
qr=qr,
form=form,
title="Aunthentication Code",
)
def get_totp_qr(contributor): def get_totp_qr(contributor):
@ -45,9 +40,7 @@ def get_totp_qr(contributor):
contributor.totp_key = pyotp.random_base32() contributor.totp_key = pyotp.random_base32()
db.session.commit() db.session.commit()
totp_uri = pyotp.totp.TOTP( totp_uri = pyotp.totp.TOTP(contributor.totp_key).provisioning_uri(name=contributor.email, issuer_name='Photo App')
contributor.totp_key,
).provisioning_uri(name=contributor.email, issuer_name='Photo App')
img = qrcode.make(totp_uri, image_factory=qrcode.image.svg.SvgPathImage) img = qrcode.make(totp_uri, image_factory=qrcode.image.svg.SvgPathImage)
f = BytesIO() f = BytesIO()
img.save(f) img.save(f)

View File

@ -2,9 +2,7 @@
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import ( from wtforms.validators import DataRequired, Email, Optional, Regexp, ValidationError, EqualTo, Length
DataRequired, Email, Optional, Regexp, ValidationError, EqualTo, Length
)
from flask_wtf.file import FileField, FileAllowed, FileRequired from flask_wtf.file import FileField, FileAllowed, FileRequired
from app.models import Contributor, EmailWhiteList from app.models import Contributor, EmailWhiteList
from zxcvbn import zxcvbn from zxcvbn import zxcvbn
@ -15,38 +13,17 @@ class ConfirmPhotoDelete(FlaskForm):
class GetTotp(FlaskForm): class GetTotp(FlaskForm):
totp_code = StringField( totp_code = StringField('6-Digit Code?', validators=[DataRequired(), Length(min=6, max=6, message="6 Digits")], render_kw={'autofocus': True})
'6-Digit Code?',
validators=[DataRequired(), Length(min=6, max=6, message="6 Digits")],
render_kw={'autofocus': True},
)
submit = SubmitField('OK') submit = SubmitField('OK')
class ConfirmTotp(FlaskForm): class ConfirmTotp(FlaskForm):
totp_code = StringField( totp_code = StringField('6-Digit Code?', validators=[DataRequired(), Length(min=6, max=6, message="Rescan And Try Again")], render_kw={'autofocus': True})
'6-Digit Code?',
validators=[
DataRequired(),
Length(min=6, max=6, message="Rescan And Try Again"),
],
render_kw={'autofocus': True},
)
submit = SubmitField('Enable 2FA') submit = SubmitField('Enable 2FA')
class EditProfile(FlaskForm): class EditProfile(FlaskForm):
username = StringField( username = StringField('Username', validators=[DataRequired(), Regexp('^[a-zA-Z0-9]+$', message='letters and digits only (no spaces)')], render_kw={'autofocus': True})
'Username',
validators=[
DataRequired(),
Regexp(
'^[a-zA-Z0-9]+$',
message='letters and digits only (no spaces)',
),
],
render_kw={'autofocus': True},
)
email = StringField('Email', validators=[Optional(), Email()]) email = StringField('Email', validators=[Optional(), Email()])
password = PasswordField('Confirm Password', validators=[DataRequired()]) password = PasswordField('Confirm Password', validators=[DataRequired()])
submit = SubmitField('Update Name/Email') submit = SubmitField('Update Name/Email')
@ -67,10 +44,7 @@ class EditProfile(FlaskForm):
class LoginForm(FlaskForm): class LoginForm(FlaskForm):
username = StringField( username = StringField('Username', validators=[Optional()], render_kw={'autofocus': True})
'Username',
validators=[Optional()], render_kw={'autofocus': True},
)
email = StringField('Email', validators=[Optional(), Email()]) email = StringField('Email', validators=[Optional(), Email()])
password = PasswordField('Password', validators=[DataRequired()]) password = PasswordField('Password', validators=[DataRequired()])
remember_me = BooleanField('Remember Me') remember_me = BooleanField('Remember Me')
@ -78,15 +52,8 @@ class LoginForm(FlaskForm):
class ResetPasswordForm(FlaskForm): class ResetPasswordForm(FlaskForm):
password = PasswordField( password = PasswordField('Password', validators=[DataRequired(), Length(min=15, )], render_kw={'autofocus': True})
'Password', password2 = PasswordField('Repeat Password', validators=[DataRequired(), EqualTo('password')])
validators=[DataRequired(), Length(min=15, )],
render_kw={'autofocus': True},
)
password2 = PasswordField(
'Repeat Password',
validators=[DataRequired(), EqualTo('password')],
)
submit = SubmitField('Request Password Reset') submit = SubmitField('Request Password Reset')
def validate_password(self, password): def validate_password(self, password):
@ -95,26 +62,10 @@ class ResetPasswordForm(FlaskForm):
class RegistrationForm(FlaskForm): class RegistrationForm(FlaskForm):
username = StringField( username = StringField('Username', validators=[DataRequired(), Regexp('^[a-zA-Z0-9]+$', message='letters and digits only (no spaces)')], render_kw={'autofocus': True})
'Username',
validators=[
DataRequired(),
Regexp(
'^[a-zA-Z0-9]+$',
message='letters and digits only (no spaces)',
),
],
render_kw={'autofocus': True},
)
email = StringField('Email', validators=[DataRequired(), Email()]) email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField( password = PasswordField('Password', validators=[DataRequired(), Length(min=15, )])
'Password', password2 = PasswordField('Repeat Password', validators=[DataRequired(), EqualTo('password')])
validators=[DataRequired(), Length(min=15, )],
)
password2 = PasswordField(
'Repeat Password',
validators=[DataRequired(), EqualTo('password')],
)
submit = SubmitField('Register') submit = SubmitField('Register')
def validate_password(self, password): def validate_password(self, password):
@ -127,9 +78,7 @@ class RegistrationForm(FlaskForm):
raise ValidationError('Please use a different username.') raise ValidationError('Please use a different username.')
def validate_email(self, email): def validate_email(self, email):
white_listed_user = EmailWhiteList.query.filter_by( white_listed_user = EmailWhiteList.query.filter_by(email=email.data).first()
email=email.data,
).first()
if white_listed_user is None: if white_listed_user is None:
raise ValidationError('This email address is not authorized.') raise ValidationError('This email address is not authorized.')
user = Contributor.query.filter_by(email=email.data).first() user = Contributor.query.filter_by(email=email.data).first()
@ -138,28 +87,14 @@ class RegistrationForm(FlaskForm):
class ResetPasswordRequestForm(FlaskForm): class ResetPasswordRequestForm(FlaskForm):
email = StringField( email = StringField('Email', validators=[DataRequired(), Email()], render_kw={'autofocus': True})
'Email',
validators=[DataRequired(), Email()],
render_kw={'autofocus': True},
)
submit = SubmitField('Request Password Reset') submit = SubmitField('Request Password Reset')
class ChangePassword(FlaskForm): class ChangePassword(FlaskForm):
password = PasswordField( password = PasswordField('Confirm Password', validators=[DataRequired()], render_kw={'autofocus': True})
'Confirm Password', new_password = PasswordField('New Password', validators=[DataRequired(), Length(min=15, )])
validators=[DataRequired()], new_password2 = PasswordField('Repeat New Password', validators=[DataRequired(), EqualTo('new_password')])
render_kw={'autofocus': True},
)
new_password = PasswordField(
'New Password',
validators=[DataRequired(), Length(min=15, )],
)
new_password2 = PasswordField(
'Repeat New Password',
validators=[DataRequired(), EqualTo('new_password')],
)
submit = SubmitField('Save') submit = SubmitField('Save')
def validate_password(self, password): def validate_password(self, password):

View File

@ -64,20 +64,12 @@ class Contributor(UserMixin, db.Model):
return '<Contributor {}>'.format(self.name) return '<Contributor {}>'.format(self.name)
def get_reset_password_token(self, expires_in=1800): def get_reset_password_token(self, expires_in=1800):
return jwt.encode( return jwt.encode({'reset_password': self.id, 'exp': time() + expires_in}, current_app.config['SECRET_KEY'], algorithm='HS256').decode('utf-8')
{'reset_password': self.id, 'exp': time() + expires_in},
current_app.config['SECRET_KEY'],
algorithm='HS256',
).decode('utf-8')
@staticmethod @staticmethod
def verify_reset_password_token(token): def verify_reset_password_token(token):
try: try:
id = jwt.decode( id = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=['HS256'])['reset_password']
token,
current_app.config['SECRET_KEY'],
algorithms=['HS256'],
)['reset_password']
except BaseException as error: except BaseException as error:
print('An exception occurred: {}'.format(error)) print('An exception occurred: {}'.format(error))
return Contributor.query.get(id) return Contributor.query.get(id)

View File

@ -1,9 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from flask import ( from flask import Blueprint, request, redirect, url_for, render_template, current_app, send_file
Blueprint, request, redirect, url_for,
render_template, current_app, send_file,
)
from flask_login import current_user from flask_login import current_user
from app.models import Photo from app.models import Photo
from app.forms import ConfirmPhotoDelete from app.forms import ConfirmPhotoDelete
@ -20,10 +17,7 @@ def download():
if current_user.is_authenticated: if current_user.is_authenticated:
f = request.args['file'] f = request.args['file']
try: try:
return send_file( return send_file('/var/lib/photo_app/photos/{}'.format(f), attachment_filename=f)
'/var/lib/photo_app/photos/{}'.format(f),
attachment_filename=f,
)
except Exception as e: except Exception as e:
return str(e) return str(e)
@ -33,14 +27,11 @@ def delete():
photo = Photo.query.get(request.args['photo_id']) photo = Photo.query.get(request.args['photo_id'])
if photo is None: if photo is None:
return(redirect(url_for('proute.index'))) return(redirect(url_for('proute.index')))
cu = current_user if not current_user.is_authenticated or photo.contributor_id != current_user.id:
if not cu.is_authenticated or photo.contributor_id != cu.id:
return(redirect(url_for('proute.index'))) return(redirect(url_for('proute.index')))
form = ConfirmPhotoDelete() form = ConfirmPhotoDelete()
if request.method == 'POST' and form.validate_on_submit(): if request.method == 'POST' and form.validate_on_submit():
return( return(redirect(url_for('p_route.photo', photo_id=delete_photo(photo))))
redirect(url_for('p_route.photo', photo_id=delete_photo(photo))),
)
return(render_template( return(render_template(
'delete_photo.html', 'delete_photo.html',
title="Delete Photo?", title="Delete Photo?",
@ -58,19 +49,11 @@ def delete_photo(photo):
password=current_app.config['DATABASE_PASSWORD'] password=current_app.config['DATABASE_PASSWORD']
) )
cur = conn.cursor() cur = conn.cursor()
cur.execute( cur.execute("SELECT count(id) FROM photo WHERE contributor_id=%s AND id>%s", (photo.contributor_id, photo.id))
"SELECT count(id) FROM photo WHERE contributor_id=%s AND id>%s",
(photo.contributor_id, photo.id),
)
if cur.fetchone()[0] == 0: if cur.fetchone()[0] == 0:
cur.execute( cur.execute("SELECT id FROM photo WHERE contributor_id=%s ORDER BY id", (photo.contributor_id, ))
"SELECT id FROM photo WHERE contributor_id=%s ORDER BY id",
(photo.contributor_id, ),
)
else: else:
my_statement = "SELECT id FROM photo WHERE contributor_id=%s " cur.execute("SELECT id FROM photo WHERE contributor_id=%s AND id>%s ORDER BY id", (photo.contributor_id, photo.id))
my_statement += "AND id>%s ORDER BY id"
cur.execute(my_statement, (photo.contributor_id, photo.id))
next_photo_id = cur.fetchone()[0] next_photo_id = cur.fetchone()[0]
os.chdir(current_app.config['PHOTO_SAVE_PATH']) os.chdir(current_app.config['PHOTO_SAVE_PATH'])
if os.path.exists('raw_' + photo.photo_name): if os.path.exists('raw_' + photo.photo_name):

View File

@ -2,9 +2,7 @@
from flask import current_app from flask import current_app
from flask_login import current_user from flask_login import current_user
from flask import ( from flask import Blueprint, render_template, redirect, url_for, flash, request, abort
Blueprint, render_template, redirect, url_for, flash, request, abort
)
from app.forms import UploadPhotoForm from app.forms import UploadPhotoForm
from .scripts.process_uploaded_photo import process_uploaded_photo from .scripts.process_uploaded_photo import process_uploaded_photo
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
@ -25,20 +23,10 @@ def photo_upload():
if filename != '': if filename != '':
import os import os
file_ext = os.path.splitext(filename)[1] file_ext = os.path.splitext(filename)[1]
fe = file_ext if file_ext not in ['.jpg', '.png'] or file_ext != validate_image(f.stream):
if fe not in ['.jpg', '.png'] or fe != validate_image(f.stream):
abort(400) abort(400)
f.save( f.save(os.path.join(current_app.config['PHOTO_SAVE_PATH'], 'raw_' + filename))
os.path.join( photo_id = process_uploaded_photo(filename, current_user, current_app.config)
current_app.config['PHOTO_SAVE_PATH'],
'raw_' + filename,
),
)
photo_id = process_uploaded_photo(
filename,
current_user,
current_app.config,
)
print(photo_id) print(photo_id)
flash("Thanks for the new photo!") flash("Thanks for the new photo!")
return(redirect(url_for('p_route.photo', photo_id=photo_id))) return(redirect(url_for('p_route.photo', photo_id=photo_id)))

View File

@ -34,35 +34,19 @@ def find_next_previous(photo):
password=current_app.config['DATABASE_PASSWORD'] password=current_app.config['DATABASE_PASSWORD']
) )
cur = conn.cursor() cur = conn.cursor()
cur.execute( cur.execute("SELECT count(id) FROM photo WHERE contributor_id=%s AND id > %s", (photo.contributor_id, photo.id))
"SELECT count(id) FROM photo WHERE contributor_id=%s AND id > %s",
(photo.contributor_id, photo.id),
)
count = cur.fetchone()[0] count = cur.fetchone()[0]
if count == 0: if count == 0:
cur.execute( cur.execute("SELECT id FROM photo WHERE contributor_id=%s ORDER BY id", (photo.contributor_id, ))
"SELECT id FROM photo WHERE contributor_id=%s ORDER BY id",
(photo.contributor_id, ),
)
else: else:
my_sql = "SELECT id FROM photo WHERE contributor_id=%s " cur.execute("SELECT id FROM photo WHERE contributor_id=%s AND id > %s ORDER BY id", (photo.contributor_id, photo.id))
my_sql += "AND id > %s ORDER BY id"
cur.execute(my_sql, (photo.contributor_id, photo.id))
photo.next_photo_id = cur.fetchone()[0] photo.next_photo_id = cur.fetchone()[0]
cur.execute( cur.execute("SELECT count(id) FROM photo WHERE contributor_id=%s AND id < %s", (photo.contributor_id, photo.id))
"SELECT count(id) FROM photo WHERE contributor_id=%s AND id < %s",
(photo.contributor_id, photo.id),
)
count = cur.fetchone()[0] count = cur.fetchone()[0]
if count == 0: if count == 0:
cur.execute( cur.execute("SELECT id FROM photo WHERE contributor_id=%s ORDER BY id DESC", (photo.contributor_id, ))
"SELECT id FROM photo WHERE contributor_id=%s ORDER BY id DESC",
(photo.contributor_id, ),
)
else: else:
my_sql = "SELECT id FROM photo WHERE contributor_id=%s " cur.execute("SELECT id FROM photo WHERE contributor_id=%s AND id < %s ORDER BY id DESC", (photo.contributor_id, photo.id))
my_sql += "AND id < %s ORDER BY id DESC"
cur.execute(my_sql, (photo.contributor_id, photo.id))
photo.previous_photo_id = cur.fetchone()[0] photo.previous_photo_id = cur.fetchone()[0]
conn.close() conn.close()
@ -74,17 +58,11 @@ def calc_additional_data(photo):
else: else:
photo.SizeOnDisc = str(round(photo.photo_raw_size / 1024, 1)) + 'K' photo.SizeOnDisc = str(round(photo.photo_raw_size / 1024, 1)) + 'K'
if photo.photo_1280_size >= 1048576: if photo.photo_1280_size >= 1048576:
photo.SizeOnDisc1280 = str( photo.SizeOnDisc1280 = str(round(photo.photo_1280_size / 1048576, 1)) + 'M'
round(photo.photo_1280_size / 1048576, 1),
) + 'M'
else: else:
photo.SizeOnDisc1280 = str( photo.SizeOnDisc1280 = str(round(photo.photo_1280_size / 1024, 1)) + 'K'
round(photo.photo_1280_size / 1024, 1),
) + 'K'
if photo.photo_480_size >= 1048576: if photo.photo_480_size >= 1048576:
photo.SizeOnDisc480 = str( photo.SizeOnDisc480 = str(round(photo.photo_480_size / 1048576, 1)) + 'M'
round(photo.photo_480_size / 1048576, 1),
) + 'M'
else: else:
photo.SizeOnDisc480 = str(round(photo.photo_480_size / 1024, 1)) + 'K' photo.SizeOnDisc480 = str(round(photo.photo_480_size / 1024, 1)) + 'K'
if photo.GPSAltitude is not None: if photo.GPSAltitude is not None:
@ -93,8 +71,6 @@ def calc_additional_data(photo):
photo.GPSAltitudeFeet = None photo.GPSAltitudeFeet = None
if photo.GPSLatitude is not None and photo.GPSLongitude is not None: if photo.GPSLatitude is not None and photo.GPSLongitude is not None:
photo.LatLong = "{},{}".format(photo.GPSLatitude, photo.GPSLongitude) photo.LatLong = "{},{}".format(photo.GPSLatitude, photo.GPSLongitude)
my_map_url = "https://www.google.com/" photo.MapUrl = "https://www.google.com/maps/search/?api=1&query={}".format(photo.LatLong)
my_map_url += "maps/search/?api=1&query={}".format(photo.LatLong)
photo.MapUrl = my_map_url
else: else:
photo.LatLong, photo.MapUrl = None, None photo.LatLong, photo.MapUrl = None, None

View File

@ -33,9 +33,7 @@ def get_photo_list(contributor_id):
password=current_app.config['DATABASE_PASSWORD'] password=current_app.config['DATABASE_PASSWORD']
) )
cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
my_sql = "SELECT photo_name,id FROM photo WHERE contributor_id=%s " cur.execute("SELECT photo_name,id FROM photo WHERE contributor_id=%s ORDER BY timestamp,\"DateTimeOriginal\" DESC", (contributor_id, ))
my_sql += "ORDER BY timestamp,\"DateTimeOriginal\" DESC"
cur.execute(my_sql, (contributor_id, ))
photos = cur.fetchall() photos = cur.fetchall()
conn.close() conn.close()
return photos return photos

View File

@ -24,10 +24,8 @@ class SENDXMPPHandler(Handler):
self.logging_xmpp_use_tls = logging_xmpp_use_tls self.logging_xmpp_use_tls = logging_xmpp_use_tls
''' '''
This works on Debian 10 with flask running under This works on Debian 10 with flask running under gunicorn3 as a systemd service, hack as necessary
gunicorn3 as a systemd service, hack as necessary echo '<message>' | /usr/bin/sendxmpp -t -u <sender> -j <server> -p <password> <recipient@example.com>
echo '<message>' | /usr/bin/sendxmpp -t -u <sender> \
-j <server> -p <password> <recipient@example.com>
''' '''
def emit(self, record): def emit(self, record):
try: try: