-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Redesigned most views. Added translations. Separated views and other …
…functionality. Switched to d3 for graphs.
- Loading branch information
Showing
66 changed files
with
3,166 additions
and
1,848 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -114,6 +114,8 @@ venv | |
generated_graphs/ | ||
.directory | ||
remind_* | ||
*.swp | ||
.bash_history | ||
|
||
# IntelliJ and PyCharm | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#!/usr/bin/env bash | ||
# Extract translations to file | ||
pybabel extract -F translations/babel.cf -k lazy_gettext -o translations/messages.pot . | ||
|
||
# Initialize a translation | ||
pybabel init -i translations/messages.pot -d translations -l ee | ||
|
||
# Compile translations | ||
pybabel compile -d translations | ||
|
||
# Update translations | ||
pybabel update -i translations/messages.pot -d translations | ||
|
||
# Update individual translations | ||
pybabel update -i translations/messages.pot -d translations -l en |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
# Background scheduling task | ||
from main import mail | ||
from models.wishlist_model import NoteState | ||
from utility import * | ||
|
||
|
||
def remind_to_add(rate_limit=True): | ||
info("Started sending adding reminders") | ||
now = datetime.datetime.now() | ||
try: | ||
with open("remind_to_add", "r+") as timer_file: | ||
lastexec = timer_file.read() | ||
lastexec = datetime.datetime(*map(int, reversed(lastexec.split("/")))) | ||
|
||
if now - lastexec < datetime.timedelta(days=30): | ||
info(" Adding reminders were rate-limited") | ||
if rate_limit: | ||
return | ||
else: | ||
timer_file.seek(0) | ||
timer_file.write(get_timestamp_string(now)) | ||
except Exception: | ||
info(" Adding reminders rate-limit file was not found") | ||
with open("remind_to_add", "w") as timer_file: | ||
timer_file.write(get_timestamp_string(now)) | ||
|
||
for user in User.query: | ||
if user.last_activity_at: | ||
if now - datetime.datetime(*map(int, user.last_activity_at.split("/"))) < datetime.timedelta(days=15): | ||
continue | ||
|
||
email_to_send = "Tere,\n" | ||
email_to_send += "Tegemist on väikese meeldetuletusega enda nimekirja koostamisele hakata mõtlema\n" | ||
email_to_send += "\n" | ||
email_to_send += "Kirja saavad kõik kasutajad kes ei ole vähemalt 15 päeva sisse loginud\n" | ||
email_to_send += "Jõulurakendus 🎄" | ||
|
||
mail.send_message(subject="Meeldetuletus kinkide kohta", | ||
body=email_to_send, | ||
recipients=[user.email]) | ||
|
||
info(" Finished sending adding reminders") | ||
|
||
|
||
def remind_to_buy(rate_limit=True): | ||
info(" Started sending purchase reminders") | ||
now = datetime.datetime.now() | ||
try: | ||
with open("remind_to_buy", "r+") as timer_file: | ||
lastexec = timer_file.read() | ||
lastexec = datetime.datetime(*map(int, reversed(lastexec.split("/")))) | ||
|
||
if now - lastexec < datetime.timedelta(days=15): | ||
info(" Buying reminders were rate-limited") | ||
if rate_limit: | ||
return | ||
else: | ||
timer_file.seek(0) | ||
timer_file.write(get_timestamp_string(now)) | ||
except Exception: | ||
info(" Reminder to buy timer file was not found") | ||
with open("remind_to_buy", "w") as timer_file: | ||
timer_file.write(get_timestamp_string(now)) | ||
|
||
for user in User.query: | ||
marked_entries = get_person_marked(user.id) | ||
items_to_purchase = [] | ||
for entry in marked_entries: | ||
if entry.status == NoteState.PLANNING_TO_PURCHASE.value["id"] or entry.status == NoteState.MODIFIED.value[ | ||
"id"]: | ||
items_to_purchase.append((entry.item, get_person_name(entry.user_id))) | ||
|
||
if len(items_to_purchase) == 0: | ||
continue | ||
|
||
email_to_send = "Tere,\n" | ||
email_to_send += "Olete märkinud, et plaanite osta allpool loetletud kingitused kuid ei ole vastavate kingituste staatust uuendanud vähemalt viisteist päeva eelnevast meeldetuletusest:\n" | ||
email_to_send += "\n" | ||
email_to_send += "Kingitus | Kellele\n" | ||
for item in items_to_purchase: | ||
email_to_send += "\"" | ||
email_to_send += item[0] | ||
email_to_send += "\" - " | ||
email_to_send += item[1] | ||
email_to_send += "\n" | ||
email_to_send += "\n" | ||
email_to_send += "Palume mitte unustada, ebameeldivad üllatused ei ole need, mida jõuludeks teistele teha soovime\n" | ||
email_to_send += "Jõulurakendus 🎄" | ||
|
||
mail.send_message(subject="Meeldetuletus kinkide kohta", | ||
body=email_to_send, | ||
recipients=[user.email]) | ||
|
||
info(" Finished sending purchase reminders") | ||
|
||
|
||
def get_timestamp_string(now): | ||
return str(now.hour) + "/" + str(now.day) + "/" + str(now.month) + "/" + str(now.year) | ||
|
||
|
||
def remind_about_change(rate_limit=True): | ||
info(" Started sending change reminders") | ||
now = datetime.datetime.now() | ||
try: | ||
with open("remind_about_change", "r+") as timer_file: | ||
lastexec = timer_file.read() | ||
lastexec = datetime.datetime(*map(int, reversed(lastexec.split("/")))) | ||
|
||
if now - lastexec < datetime.timedelta(hours=6): | ||
info(" Changing reminders were rate-limited") | ||
if rate_limit: | ||
return | ||
else: | ||
timer_file.seek(0) | ||
timer_file.write(get_timestamp_string(now)) | ||
except Exception: | ||
info(" Change reminder timer file was not found") | ||
with open("remind_about_change", "w") as timer_file: | ||
timer_file.write(get_timestamp_string(now)) | ||
|
||
for user in User.query: | ||
marked_entries = get_person_marked(user.id) | ||
items_to_purchase = [] | ||
for entry in marked_entries: | ||
if entry.status == NoteState.MODIFIED.value["id"]: | ||
items_to_purchase.append((entry.item, get_person_name(entry.user_id))) | ||
|
||
if len(items_to_purchase) == 0: | ||
continue | ||
|
||
email_to_send = "Tere,\n" | ||
email_to_send += "Viimase päeva jooksul on muudetud allpool loetletud soove, on oluline, et otsustaksite kas soovite ikka kinki osta või vabastate selle teistele:\n" | ||
email_to_send += "\n" | ||
email_to_send += "Kingitus | Kellele\n" | ||
for item in items_to_purchase: | ||
email_to_send += "\"" | ||
email_to_send += item[0] | ||
email_to_send += "\" - " | ||
email_to_send += item[1] | ||
email_to_send += "\n" | ||
email_to_send += "\n" | ||
email_to_send += "Palume päeva jooksul enda otsus uuesti süsteemi sisestada\n" | ||
email_to_send += "Jõulurakendus 🎄" | ||
|
||
mail.send_message(subject="Meeldetuletus kinkide kohta", | ||
body=email_to_send, | ||
recipients=[user.email]) | ||
|
||
info(" Finished sending change reminders") | ||
|
||
|
||
scheduler = BackgroundScheduler(daemon=True) | ||
scheduler.add_job(remind_to_add, | ||
trigger=IntervalTrigger(days=30), | ||
name="Addition reminder", | ||
id="add_reminder", | ||
replace_existing=True) | ||
scheduler.add_job(remind_to_buy, | ||
trigger=IntervalTrigger(days=15), | ||
name="Buying reminder", | ||
id="buy_reminder", | ||
replace_existing=True) | ||
scheduler.add_job(remind_about_change, | ||
trigger=IntervalTrigger(minutes=720), | ||
name="Change reminder", | ||
id="cng_reminder", | ||
replace_existing=True) | ||
|
||
atexit.register(lambda: scheduler.shutdown()) | ||
scheduler.start() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,75 +1,54 @@ | ||
# coding=utf-8 | ||
import logging | ||
|
||
|
||
class Config(object): | ||
"""DEVELOPMENT = | ||
DEBUG = | ||
TESTING = """ | ||
|
||
CSRF_ENABLED = True | ||
WTF_CSRF_ENABLED = True | ||
|
||
SECRET_KEY = "" | ||
SQLALCHEMY_DATABASE_URI = "postgresql://" | ||
ENV = "debug" # TODO: Replace with "production" | ||
FLASK_DEBUG = True # TODO: Disable in production | ||
DEVELOPMENT = True # TODO: Disable in production | ||
DEBUG = True # TODO: Disable in production | ||
TESTING = True # TODO: Disable in production | ||
|
||
CSRF_ENABLED = False # TODO: Enable in production | ||
WTF_CSRF_ENABLED = False # TODO: Enable in production | ||
|
||
SENTRY_URL = "" # TODO: Add sentry URL | ||
SENTRY_USER_ATTRS = ["username", | ||
"id", | ||
"email"] | ||
|
||
AES_KEY = b"yFrstBQ&iKi1OwugdJ?EnIfPWundVBPO" | ||
SECRET_KEY = "" # TODO: Update secret key info | ||
SQLALCHEMY_DATABASE_URI = "" # TODO: Add database URI | ||
SQLALCHEMY_TRACK_MODIFICATIONS = False | ||
MAIL_SERVER = "" | ||
MAIL_SERVER = "localhost" | ||
MAIL_PORT = 25 | ||
MAIL_USE_SSL = False | ||
MAIL_USERNAME = "" | ||
MAIL_PASSWORD = "" | ||
MAIL_DEFAULT_SENDER = ("Name", "[email protected]") | ||
SECURITY_EMAIL_SENDER = ("Name", "[email protected]") | ||
MAIL_SUPPRESS_SEND = False | ||
MAIL_PASSWORD = "" # TODO: Add email server info | ||
MAIL_DEFAULT_SENDER = ("Pretty mailer name", "place@holder") # TODO: Update email sender info | ||
MAIL_SUPPRESS_SEND = True # TODO: Do not suppress send in production | ||
|
||
RECAPTCHA_PUBLIC_KEY = "" | ||
RECAPTCHA_PUBLIC_KEY = "" # TODO: Add captcha keys | ||
RECAPTCHA_PRIVATE_KEY = "" | ||
|
||
SECURITY_PASSWORD_HASH = "" | ||
SECURITY_PASSWORD_SALT = "" | ||
SECURITY_EMAIL_SENDER = ("Pretty mailer name", "place@holder") # TODO: Update email sender info | ||
SECURITY_PASSWORD_HASH = "pbkdf2_sha512" | ||
SECURITY_PASSWORD_SALT = None # TODO: Add salt! | ||
|
||
SECURITY_REGISTERABLE = True | ||
SECURITY_RECOVERABLE = True | ||
SECURITY_CONFIRMABLE = True | ||
SECURITY_CHANGEABLE = True | ||
SECURITY_TRACKABLE = True | ||
SESSION_COOKIE_SECURE = True | ||
REMEMBER_COOKIE_SECURE = True | ||
SESSION_COOKIE_HTTPONLY = True | ||
REMEMBER_COOKIE_HTTPONLY = True | ||
|
||
|
||
class ProductionConfig(Config): | ||
DEBUG = False | ||
TESTING = False | ||
DEVELOPMENT = False | ||
CSRF_ENABLED = True | ||
WTF_CSRF_ENABLED = True | ||
|
||
|
||
class StagingConfig(Config): | ||
DEVELOPMENT = True | ||
DEBUG = True | ||
|
||
|
||
class DevelopmentConfig(Config): | ||
DEVELOPMENT = True | ||
DEBUG = True | ||
|
||
|
||
class TestingConfig(Config): | ||
TESTING = True | ||
|
||
|
||
import os | ||
USER_AFTER_REGISTER_ENDPOINT = "/login" | ||
|
||
from flask import Flask | ||
from flask_mail import Mail | ||
from flask_sqlalchemy import SQLAlchemy | ||
SESSION_COOKIE_SECURE = False # TODO: Enable in production | ||
REMEMBER_COOKIE_SECURE = False # TODO: Enable in production | ||
SESSION_COOKIE_HTTPONLY = False # TODO: Enable in production | ||
REMEMBER_COOKIE_HTTPONLY = False # TODO: Enable in production | ||
|
||
basedir = os.path.abspath(os.path.dirname(__file__)) | ||
app = Flask(__name__) | ||
app.config.from_object("config.DevelopmentConfig") | ||
from werkzeug.contrib.fixers import ProxyFix | ||
LOGLEVEL = logging.DEBUG | ||
|
||
ProxyFix(app, num_proxies=1) | ||
db = SQLAlchemy(app) | ||
mail = Mail(app) | ||
BABEL_DEFAULT_LOCALE = "ee" # TODO: You might want to change this to "en" if you want to default to English |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from flask_security.forms import StringField, Required, RegisterForm, ResetPasswordForm, SendConfirmationForm, \ | ||
ForgotPasswordForm | ||
from flask_wtf import RecaptchaField | ||
|
||
|
||
class ExtendedRegisterForm(RegisterForm): | ||
username = StringField("Eesnimi", [Required()]) # TODO: Translate I think | ||
recaptcha = RecaptchaField("Captcha") | ||
|
||
|
||
class ExtendedResetForm(ResetPasswordForm): | ||
recaptcha = RecaptchaField("Captcha") | ||
|
||
|
||
class ExtendedConfirmationForm(SendConfirmationForm): | ||
recaptcha = RecaptchaField("Captcha") | ||
|
||
|
||
class ExtendedForgotPasswordForm(ForgotPasswordForm): | ||
recaptcha = RecaptchaField("Captcha") |
Oops, something went wrong.