Repository: mr-teslaa/valentine-ai
Branch: main
Commit: 6c0ab822390f
Files: 49
Total size: 137.0 KB
Directory structure:
gitextract_nl_bb119/
├── .github/
│ └── workflows/
│ └── deploy.yml
├── .gitignore
├── application/
│ ├── CohereAI/
│ │ ├── GenerateBlog.py
│ │ └── Utils.py
│ ├── __init__.py
│ ├── auth/
│ │ ├── __init__.py
│ │ ├── forms.py
│ │ └── views.py
│ ├── config.py
│ ├── models.py
│ ├── public/
│ │ ├── __init__.py
│ │ └── views.py
│ ├── static/
│ │ └── assets/
│ │ ├── css/
│ │ │ └── custom.css
│ │ ├── js/
│ │ │ ├── clock.js
│ │ │ └── theme.js
│ │ └── vendor/
│ │ └── prismjs/
│ │ ├── plugins/
│ │ │ ├── line-numbers/
│ │ │ │ └── prism-line-numbers.css
│ │ │ └── toolbar/
│ │ │ └── prism-toolbar.css
│ │ └── themes/
│ │ └── prism.css
│ ├── superadmin/
│ │ ├── __init__.py
│ │ ├── forms.py
│ │ └── views.py
│ ├── templates/
│ │ ├── auth/
│ │ │ ├── activation_link_email.html
│ │ │ ├── forgetpassword.html
│ │ │ ├── join.html
│ │ │ ├── login.html
│ │ │ ├── password_reset_link_email.html
│ │ │ └── reset_token.html
│ │ ├── helpers/
│ │ │ ├── _global_footer.html
│ │ │ ├── _nav_top_landing.html
│ │ │ └── _side_navbar_dashboard.html
│ │ ├── layout/
│ │ │ └── root.html
│ │ ├── public/
│ │ │ ├── landing.html
│ │ │ └── letter.html
│ │ └── user/
│ │ ├── account.html
│ │ ├── account_update_password.html
│ │ ├── dashboard.html
│ │ ├── letter_sent.html
│ │ ├── letters.html
│ │ └── send_letter_email.html
│ ├── user/
│ │ ├── __init__.py
│ │ ├── forms.py
│ │ └── views.py
│ └── utils/
│ ├── CutomAuth.py
│ ├── Location.py
│ ├── SendEmail.py
│ ├── Utils.py
│ └── __init__.py
├── requirements.txt
└── run.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/deploy.yml
================================================
on:
push:
branches:
- main
name: 🚀 Deploy website on push
jobs:
web-deploy:
name: 🎉 Deploy
runs-on: ubuntu-latest
steps:
- name: 🚚 Get latest code
uses: actions/checkout@v2
- name: 📂 Sync files
uses: SamKirkland/FTP-Deploy-Action@4.3.0
with:
server: ${{ secrets.ftp_server }}
username: ${{ secrets.ftp_username }}
password: ${{ secrets.ftp_password }}
================================================
FILE: .gitignore
================================================
# Created by https://www.toptal.com/developers/gitignore/api/flask
# Edit at https://www.toptal.com/developers/gitignore?templates=flask
migrations/
__pycache__/
application/__pycache__/
application/public/__pycache__/
*/*/__pycache__/
*/*/*/__pycache__/
*/*/*/*/__pycache__/
*/*/*/*/*/__pycache__/
.idea/
venv/
env/
.code/
.vscode/
.pytest_cache/
tempCodeRunnerFile.py
### Flask ###
instance/*
!instance/.gitignore
.webassets-cache
.env
### Flask.Python Stack ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# End of https://www.toptal.com/developers/gitignore/api/flask
================================================
FILE: application/CohereAI/GenerateBlog.py
================================================
import os
import time
import cohere
from dotenv import find_dotenv, load_dotenv
load_dotenv(find_dotenv())
# Cohere AI API setup
co = cohere.Client(os.getenv('API_KEY'))
def max_likely(prediction):
output = prediction.generations[0].text
return output
# Generate blog posts for each keyword
def generate_letter(gender):
letter_generate = co.generate(
model='command',
prompt= "You are a poet, you are known for your unique romantic, flirting words and today is valentines day. Write one very short sentence within 65 character romantic, loving, caring message for my " + gender,
max_tokens=70,
temperature=0.9,
stop_sequences=["---"]
)
letter = max_likely(letter_generate)
return letter
================================================
FILE: application/CohereAI/Utils.py
================================================
import uuid
def linkid():
link = uuid.uuid4().hex[:8]
return link
================================================
FILE: application/__init__.py
================================================
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
from flask_migrate import Migrate
from flask_moment import Moment
from application.config import Config
from flask_mail import Mail
db = SQLAlchemy()
bcrypt = Bcrypt()
login_manager = LoginManager()
migrate = Migrate()
moment = Moment()
mail = Mail()
login_manager.login_view = 'auth.login'
login_manager.login_message_category = 'info'
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
bcrypt.init_app(app)
login_manager.init_app(app)
moment.init_app(app)
migrate.init_app(app, db)
mail.init_app(app)
from application.models import User
from application.models import Visitor
from application.auth.views import auth
app.register_blueprint(auth)
from application.public.views import public
app.register_blueprint(public)
from application.superadmin.views import superadmin
app.register_blueprint(superadmin)
from application.user.views import user
app.register_blueprint(user)
return app
================================================
FILE: application/auth/__init__.py
================================================
================================================
FILE: application/auth/forms.py
================================================
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms import PasswordField
from wtforms import IntegerField
from wtforms import SubmitField
from wtforms import BooleanField
from wtforms import TextAreaField
from wtforms import SelectField
from wtforms import DateField
from flask_wtf.file import FileField
from flask_wtf.file import FileAllowed
from wtforms.validators import DataRequired
from wtforms.validators import NumberRange
from wtforms.validators import Optional
from wtforms.validators import Length
from wtforms.validators import Email
from wtforms.validators import EqualTo
from wtforms.validators import ValidationError
from flask_login import current_user
from application.models import User
class RegistrationForm(FlaskForm):
name = StringField(
'Your Name',
validators = [
DataRequired(),
Length(2, 50)
]
)
phone = StringField(
'Phone',
validators=[
DataRequired(),
Length(min=5, max=15, message='Phone number must be between 5 and 15.')
]
)
email = StringField(
'E-mail',
validators = [
DataRequired(),
Email()
]
)
password = PasswordField(
'Password',
validators = [ DataRequired() ]
)
confirm_password = PasswordField(
'Confirm Password',
validators = [
DataRequired(),
EqualTo('password')
]
)
submit = SubmitField('Join Now')
def validate_phone(self, phone):
user_phone = User.query.filter_by(phone=phone.data).first()
if user_phone:
raise ValidationError('This Phone is alredy registerd. Please choose a different one.')
def validate_email(self, email):
user_email = User.query.filter_by(email=email.data).first()
if user_email:
raise ValidationError('That email is taken/already registered. Please choose a different one.')
class LoginForm(FlaskForm):
phone = StringField(
'Phone',
validators=[
DataRequired(),
Length(min=5, max=15, message='Phone number must be between 5 and 15.')
]
)
password = PasswordField(
'Password',
validators = [DataRequired()]
)
remember = BooleanField('Remember Me')
submit = SubmitField('Login')
# UPDATE PASSWORD FORM
class UpdatePasswordForm(FlaskForm):
currentPassword = PasswordField(
'Current Password',
validators=[ DataRequired() ]
)
newPassword = PasswordField(
'New Password',
# validators=[ DataRequired() ]
)
confirmnewPassword = PasswordField(
'Confirm New Password',
# validators=[ DataRequired() ]
)
submit = SubmitField('Save')
# FORGET PASSWORD FORM
class ForgetPasswordForm(FlaskForm):
email = StringField(
'Email',
validators = [
Email()
]
)
submit = SubmitField('Get Password Reset Link')
# CHANGE PASSWORD TOKEN
class ResetPasswordForm(FlaskForm):
password = PasswordField(
'Password',
validators=[ DataRequired() ]
)
confirm_password = PasswordField(
'Confirm Password',
validators = [
DataRequired(),
EqualTo('password')
]
)
submit = SubmitField('Reset Password')
================================================
FILE: application/auth/views.py
================================================
# importing basic flask module
from flask import Blueprint
from flask import redirect
from flask import render_template
from flask import request
from flask import url_for
from flask import flash
from flask import abort
from flask import jsonify
from flask import make_response
from flask import current_app
# importing module from flask login
from flask_login import current_user
from flask_login import login_required
from flask_login import login_user
from flask_login import logout_user
from application import db
from application import bcrypt
from application.models import User
from application.auth.forms import LoginForm
from application.auth.forms import RegistrationForm
from application.auth.forms import UpdatePasswordForm
from application.auth.forms import ForgetPasswordForm
from application.auth.forms import ResetPasswordForm
from application.utils.SendEmail import send_reset_email
auth = Blueprint('auth', __name__)
# @auth.route('/join/admin/', methods=['GET', 'POST'])
# def join_superadmin():
# current_ip = request.remote_addr
# if current_user.is_authenticated:
# current_user.ip = current_ip
# db.session.commit()
# return redirect(url_for('user.dashboard'))
# form = RegistrationForm()
# if form.validate_on_submit():
# hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
# if form.middle_name.data:
# user = User(
# first_name=form.first_name.data.strip(),
# middle_name=form.middle_name.data.strip(),
# last_name=form.last_name.data.strip(),
# phone=form.phone.data,
# password=hashed_password,
# email=form.email.data.strip(), address=form.address.data.strip(),
# user_role='superadmin', is_active=True
# )
# else:
# user = User(
# first_name=form.first_name.data.strip(),
# last_name=form.last_name.data.strip(),
# phone=form.phone.data,
# password=hashed_password,
# email=form.email.data.strip(), address=form.address.data.strip(),
# user_role='superadmin', is_active=True
# )
# db.session.add(user)
# db.session.commit()
# send_activation_email(user)
# send_admin_contact_alert_email(user)
# flash('Check your email, we have sent you a confirmation link to activate your account', 'info')
# return redirect(url_for('auth.login'))
# return render_template('auth/join.html', form=form)
# NEW USER JOIN PAGE
@auth.route('/join/', methods=['GET', 'POST'])
def join():
current_ip = request.remote_addr
if current_user.is_authenticated:
current_user.ip = current_ip
db.session.commit()
return redirect(url_for('user.dashboard'))
form = RegistrationForm()
if form.validate_on_submit():
hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
user = User(
name=form.name.data.strip(),
phone=form.phone.data,
password=hashed_password,
email=form.email.data.strip(),
user_role='user',
is_active=True
)
db.session.add(user)
db.session.commit()
flash('Account created successfully', 'info')
return redirect(url_for('auth.login'))
return render_template('auth/join.html', form=form)
# Activate account route
@auth.route('/activate/<token>')
def activate(token):
# Activate a user's account
user = User.query.filter_by(activation_token=token, is_active=False).first()
if user:
user_verified = user.verify_reset_token(token)
if user_verified:
user.is_active = True
db.session.commit()
flash('Your account has been activated! You are now able to log in ✅', 'success')
return redirect(url_for('auth.login'))
else:
flash('The activation link is invalid or has expired.', 'warning')
return redirect(url_for('auth.join'))
# USER LOGIN PAGE
@auth.route('/login/', methods=['GET', 'POST'])
def login():
form = LoginForm()
current_ip = request.remote_addr
if current_user.is_authenticated:
current_user.ip = current_ip
db.session.commit()
return redirect(url_for('user.dashboard'))
if form.validate_on_submit():
user = User.query.filter_by(phone=form.phone.data).first_or_404()
if user and user.is_active and bcrypt.check_password_hash(user.password, form.password.data):
login_user(user, remember=form.remember.data)
next_page = request.args.get('next')
flash('✅ Login success', 'success')
return redirect(next_page) if next_page else redirect(url_for('user.dashboard'))
elif user and not user.is_active:
flash('⚠️ Please check your email and activate your account, untill you can not login', 'info')
else:
flash('⚠️ Login Unsuccessful. Please check phone number and password', 'danger')
return render_template('auth/login.html', form=form)
# USER LOGOUT
@auth.route("/logout/")
@login_required
def logout():
logout_user()
flash('Logout successfully ✅', 'success')
return redirect(url_for('auth.login'))
# RESET PASSWORD FOR USER
@auth.route('/user/resetpassword/', methods=['GET', 'POST'])
@login_required
def user_resetpassword():
form = UpdatePasswordForm()
if form.validate_on_submit():
newpass = form.newPassword.data
confirmpass = form.confirmnewPassword.data
currentpass_hash = bcrypt.check_password_hash(current_user.password, form.currentPassword.data)
if currentpass_hash and newpass==confirmpass:
hashed_password = bcrypt.generate_password_hash(newpass).decode('utf-8')
current_user.password = hashed_password
db.session.commit()
flash('Your password has been updated!', 'success')
return redirect(url_for('user.dashboard'))
else:
flash('Password Not Matched', 'danger')
return redirect(url_for('user.user_resetpassword'))
return render_template('user/change_password.html', title='Change Password', form=form)
# VERIFY USER EMAIL IS REGISTERED IN OUR SYSTEM
@auth.route('/password/recover/', methods=['GET', 'POST'])
def forgetpassword():
form = ForgetPasswordForm()
if current_user.is_authenticated:
return redirect(url_for('user.dashboard'))
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
send_reset_email(user)
flash('If you have an account with this email, an email has been sent with instructions to reset your password.', 'info')
return redirect(url_for('auth.login'))
return render_template('auth/forgetpassword.html', title='Reset Password', form=form)
# PASSWORD RESET TOKEN
@auth.route("/reset-password/<token>", methods=['GET', 'POST'])
def reset_token(token):
if current_user.is_authenticated:
return redirect(url_for('user.index'))
user = User.verify_reset_token(token)
if user is None:
flash('That is an invalid or expired token', 'warning')
return redirect(url_for('user.reset_request'))
form = ResetPasswordForm()
if form.validate_on_submit():
hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
user.password = hashed_password
db.session.commit()
flash('Your password has been updated! You are now able to log in', 'success')
return redirect(url_for('auth.login'))
return render_template('auth/reset_token.html', title='Reset Password', form=form)
================================================
FILE: application/config.py
================================================
import os
from dotenv import find_dotenv, load_dotenv
load_dotenv(find_dotenv())
production=True
# production=False
class Config:
SECRET_KEY='248fb9a5bdffa13c0bc136504ebf75c2'
if production is True:
SQLALCHEMY_DATABASE_URI=os.getenv('SQLALCHEMY_DATABASE_URI')
else:
SQLALCHEMY_DATABASE_URI='sqlite:///valentine.db'
# SQLALCHEMY_TRACK_MODIFICATIONS=True
MAIL_SERVER = os.getenv('SMTP_SERVER')
MAIL_DEFAULT_SENDER = 'amazonkdp@binomatrix.com'
MAIL_PORT = 465
MAIL_USE_SSL = True
MAIL_USERNAME = os.getenv('EMAIL_USERNAME')
MAIL_PASSWORD = os.getenv('EMAIL_PASSWORD')
================================================
FILE: application/models.py
================================================
import secrets
# importing necessary module
from datetime import datetime
from flask import current_app
# importing dataase
from application import db
# importing login manager
from application import login_manager
from flask_login import UserMixin
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
# making sure that the user is logged in
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class User(db.Model, UserMixin):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(300))
phone = db.Column(db.String(15), unique=True)
email = db.Column(db.String(120), unique=True)
img = db.Column(db.String(500), default='default.jpg')
password = db.Column(db.String(800), nullable=False)
address = db.Column(db.String(900))
user_role = db.Column(db.String(60), default="user")
letter_sender = db.relationship('Letter', backref='sender', lazy=True)
join_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
ip = db.Column(db.String(60))
# ACCOUNT ACTIVATION
activation_token = db.Column(db.String(500), unique=True)
is_active = db.Column(db.Boolean(), default=False)
# GENERATE ACTIVATION TOKEN
def generate_activation_token(self, expires_sec=3600):
s = Serializer(current_app.config['SECRET_KEY'], expires_sec)
return s.dumps({'user_id': self.id}).decode('utf-8')
# GENERATING PASSWORD RESET TOKEN
def get_reset_token(self, expires_sec=1800):
s = Serializer(current_app.config['SECRET_KEY'], expires_sec)
return s.dumps({'user_id': self.id}).decode('utf-8')
# verify the token if the token has exprired or invalid
@staticmethod
def verify_reset_token(token):
s = Serializer(current_app.config['SECRET_KEY'])
try:
user_id = s.loads(token)['user_id']
except:
return None
return User.query.get(user_id)
# verify the token if the token has exprired or invalid
@staticmethod
def verify_activation_token(token):
s = Serializer(current_app.config['SECRET_KEY'])
try:
user_id = s.loads(token)['user_id']
except:
return None
return User.query.get(user_id)
class Letter(db.Model):
id = db.Column(db.Integer, primary_key=True)
receiver_name = db.Column(db.String(100), nullable=False)
email=db.Column(db.String(100), nullable=False)
gender=db.Column(db.String(100), nullable=False)
message=db.Column(db.String(900))
link=db.Column(db.String(100), unique=True)
is_hidden = db.Column(db.Boolean(), default=False)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
sender_id = db.Column(db.Integer, db.ForeignKey('user.id'))
class Visitor(db.Model):
id = db.Column(db.Integer, primary_key=True)
ip = db.Column(db.String(100), nullable=False)
first_name=db.Column(db.String(100))
middle_name=db.Column(db.String(100))
last_name=db.Column(db.String(100))
email=db.Column(db.String(100))
phone=db.Column(db.String(100))
message=db.Column(db.String(100))
date_visit = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
================================================
FILE: application/public/__init__.py
================================================
================================================
FILE: application/public/views.py
================================================
# importing basic flask module
from flask import Blueprint
from flask import redirect
from flask import render_template
from flask import request
from flask import url_for
from flask import flash
from flask import abort
from flask import jsonify
from flask import make_response
from flask import current_app
from datetime import date
from datetime import datetime
from application import db
from application.models import User
from application.models import Letter
from application.models import Visitor
from application.utils.Location import getLocation
public = Blueprint('public', __name__)
# LANDING PAGE
@public.route('/')
def index():
# GETTING IP OF USER
ip_request = request.remote_addr
# GET TODAY
today = datetime.utcnow().date()
# GET VISITORS
visitor = Visitor.query.filter_by(ip=ip_request).filter(Visitor.date_visit.like(f'{today}%')).first()
if visitor:
# visitor has already visited today, don't count as a new visit
pass
else:
visitor = Visitor(ip=ip_request)
db.session.add(visitor)
db.session.commit()
return render_template(
'public/landing.html'
)
# LETTER PAGE
@public.route('/letter/<string:link>/')
def letter(link):
letter = Letter.query.filter_by(link=link).order_by(Letter.created_at.desc()).first_or_404()
return render_template('public/letter.html', letter=letter)
================================================
FILE: application/static/assets/css/custom.css
================================================
/* ================ CLOCK ================ */
.clock-container h4,
.clock-container h5,
.clock-container p {
margin-bottom: 0;
color: #fff !important;
}
.clock-container .clock {
color: var(--bs-white);
text-align: center;
position: fixed;
bottom: 0;
padding: 0.2rem 1.5rem;
margin: 0.5rem;
border-radius: 16px;
background-color: var(--bs-light);
z-index: 1025;
}
.clock-container .clock h4,
.clock-container .clock h5 {
color: var(--bs-white);
}
.clock-container .clock-right {
right: 0;
background: linear-gradient(131deg, rgb(252, 171, 1), rgb(254, 33, 79) 100%);
}
.clock-container .clock-left {
left: 0;
background: linear-gradient(117deg, rgb(30, 42, 120), rgb(255, 46, 76) 100%);
}
/* ================ TEXT ================ */
.text__justify {
text-align: justify;
}
/* ================ END TEXT ================ */
================================================
FILE: application/static/assets/js/clock.js
================================================
function updateClock1() {
let date = new Date();
let nyWeekday = date.toLocaleString("en-US", {
timeZone: "America/New_York",
weekday: "long",
});
let nyTime = date.toLocaleString("en-US", {
timeZone: "America/New_York",
hour: "numeric",
minute: "numeric",
second: "numeric",
hour12: true,
});
document.getElementById("nyWeekday").innerHTML = nyWeekday;
document.getElementById("nytime").innerHTML = nyTime;
}
function updateClock2() {
let date = new Date();
let bdWeekday = date.toLocaleString("en-US", {
timeZone: "Asia/Dhaka",
weekday: "long",
});
let bdTime = date.toLocaleString("en-US", {
timeZone: "Asia/Dhaka",
hour: "numeric",
minute: "numeric",
second: "numeric",
hour12: true,
});
document.getElementById("bdWeekday").innerHTML = bdWeekday;
document.getElementById("bdtime").innerHTML = bdTime;
}
setInterval(updateClock1, 1000);
setInterval(updateClock2, 1000);
================================================
FILE: application/static/assets/js/theme.js
================================================
function _typeof(e) {
return (_typeof =
"function" == typeof Symbol && "symbol" == typeof Symbol.iterator
? function (e) {
return typeof e;
}
: function (e) {
return e &&
"function" == typeof Symbol &&
e.constructor === Symbol &&
e !== Symbol.prototype
? "symbol"
: typeof e;
})(e);
}
function ownKeys(t, e) {
var r,
a = Object.keys(t);
return (
Object.getOwnPropertySymbols &&
((r = Object.getOwnPropertySymbols(t)),
e &&
(r = r.filter(function (e) {
return Object.getOwnPropertyDescriptor(t, e).enumerable;
})),
a.push.apply(a, r)),
a
);
}
function _objectSpread(t) {
for (var e = 1; e < arguments.length; e++) {
var r = null != arguments[e] ? arguments[e] : {};
e % 2
? ownKeys(Object(r), !0).forEach(function (e) {
_defineProperty(t, e, r[e]);
})
: Object.getOwnPropertyDescriptors
? Object.defineProperties(t, Object.getOwnPropertyDescriptors(r))
: ownKeys(Object(r)).forEach(function (e) {
Object.defineProperty(
t,
e,
Object.getOwnPropertyDescriptor(r, e)
);
});
}
return t;
}
function _defineProperty(e, t, r) {
return (
(t = _toPropertyKey(t)) in e
? Object.defineProperty(e, t, {
value: r,
enumerable: !0,
configurable: !0,
writable: !0,
})
: (e[t] = r),
e
);
}
function _toPropertyKey(e) {
e = _toPrimitive(e, "string");
return "symbol" === _typeof(e) ? e : String(e);
}
function _toPrimitive(e, t) {
if ("object" !== _typeof(e) || null === e) return e;
var r = e[Symbol.toPrimitive];
if (void 0 === r) return ("string" === t ? String : Number)(e);
t = r.call(e, t || "default");
if ("object" !== _typeof(t)) return t;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
/**
* Silicon | Multipurpose Bootstrap 5 Template & UI Kit
* Copyright 2023 Createx Studio
* Theme core scripts
*
* @author Createx Studio
* @version 1.5.0
*/
!(function () {
"use strict";
var t, e, r, a, n, o;
null !== (e = document.querySelector('[data-bs-toggle="mode"]')) &&
((t = e.querySelector(".form-check-input")),
"dark" === mode
? (root.classList.add("dark-mode"), (t.checked = !0))
: (root.classList.remove("dark-mode"), (t.checked = !1)),
e.addEventListener("click", function (e) {
t.checked
? (root.classList.add("dark-mode"),
window.localStorage.setItem("mode", "dark"))
: (root.classList.remove("dark-mode"),
window.localStorage.setItem("mode", "light"));
})),
null != (a = document.querySelector(".navbar-sticky")) &&
((e = a.classList),
(r = a.offsetHeight),
e.contains("position-absolute")
? window.addEventListener("scroll", function (e) {
500 < e.currentTarget.pageYOffset
? a.classList.add("navbar-stuck")
: a.classList.remove("navbar-stuck");
})
: window.addEventListener("scroll", function (e) {
500 < e.currentTarget.pageYOffset
? ((document.body.style.paddingTop = r + "px"),
a.classList.add("navbar-stuck"))
: ((document.body.style.paddingTop = ""),
a.classList.remove("navbar-stuck"));
})),
new SmoothScroll("[data-scroll]", {
speed: 800,
speedAsDuration: !0,
offset: function (e, t) {
return t.dataset.scrollOffset || 40;
},
header: "[data-scroll-header]",
updateURL: !1,
}),
null != (o = document.querySelector(".btn-scroll-top")) &&
((n = parseInt(600, 10)),
window.addEventListener("scroll", function (e) {
e.currentTarget.pageYOffset > n
? o.classList.add("show")
: o.classList.remove("show");
})),
(function () {
for (
var e = document.querySelectorAll(".password-toggle"), r = 0;
r < e.length;
r++
)
!(function () {
var t = e[r].querySelector(".form-control");
e[r].querySelector(".password-toggle-btn").addEventListener(
"click",
function (e) {
"checkbox" === e.target.type &&
(e.target.checked
? (t.type = "text")
: (t.type = "password"));
},
!1
);
})();
})(),
null !== document.querySelector(".rellax") &&
new Rellax(".rellax", { horizontal: !0 }),
(function () {
for (
var e = document.querySelectorAll(".parallax"), t = 0;
t < e.length;
t++
)
new Parallax(e[t]);
})(),
(function (e, t, r) {
for (var a = 0; a < e.length; a++) t.call(r, a, e[a]);
})(document.querySelectorAll(".swiper"), function (e, t) {
var r;
(r =
null != t.dataset.swiperOptions
? JSON.parse(t.dataset.swiperOptions)
: r).pager &&
(a = {
pagination: {
el: ".pagination .list-unstyled",
clickable: !0,
bulletActiveClass: "active",
bulletClass: "page-item",
renderBullet: function (e, t) {
return (
'<li class="' +
t +
'"><a href="#" class="page-link btn-icon btn-sm">' +
(e + 1) +
"</a></li>"
);
},
},
});
var a = _objectSpread(_objectSpread({}, r), a),
a = new Swiper(t, a);
r.tabs &&
a.on("activeIndexChange", function (e) {
var t = document.querySelector(
e.slides[e.activeIndex].dataset.swiperTab
);
document
.querySelector(
e.slides[e.previousIndex].dataset.swiperTab
)
.classList.remove("active"),
t.classList.add("active");
});
}),
(function () {
var e = document.querySelectorAll(".gallery");
if (e.length)
for (var t = 0; t < e.length; t++) {
var r = !!e[t].dataset.thumbnails,
a = !!e[t].dataset.video,
n = [lgZoom, lgFullscreen],
a = a ? [lgVideo] : [],
r = r ? [lgThumbnail] : [],
r = [].concat(n, a, r);
lightGallery(e[t], {
selector: ".gallery-item",
plugins: r,
licenseKey: "D4194FDD-48924833-A54AECA3-D6F8E646",
download: !1,
autoplayVideoOnSlide: !0,
zoomFromOrigin: !1,
youtubePlayerParams: {
modestbranding: 1,
showinfo: 0,
rel: 0,
},
vimeoPlayerParams: {
byline: 0,
portrait: 0,
color: "6366f1",
},
});
}
})(),
(function () {
for (
var n = document.querySelectorAll(".range-slider"), o = 0;
o < n.length;
o++
)
!(function () {
var e = n[o].querySelector(".range-slider-ui"),
r = n[o].querySelector(".range-slider-value-min"),
a = n[o].querySelector(".range-slider-value-max"),
t = {
dataStartMin: parseInt(n[o].dataset.startMin, 10),
dataStartMax: parseInt(n[o].dataset.startMax, 10),
dataMin: parseInt(n[o].dataset.min, 10),
dataMax: parseInt(n[o].dataset.max, 10),
dataStep: parseInt(n[o].dataset.step, 10),
dataPips: n[o].dataset.pips,
};
noUiSlider.create(e, {
start: t.dataStartMax
? [t.dataStartMin, t.dataStartMax]
: [t.dataStartMin],
connect: !!t.dataStartMax || "lower",
step: t.dataStep,
pips: !!t.dataPips && { mode: "count", values: 5 },
tooltips: !0,
range: { min: t.dataMin, max: t.dataMax },
format: {
to: function (e) {
return "$" + parseInt(e, 10);
},
from: function (e) {
return Number(e);
},
},
}),
e.noUiSlider.on("update", function (e, t) {
e = (e = e[t]).replace(/\D/g, "");
t
? a && (a.value = Math.round(e))
: r && (r.value = Math.round(e));
}),
r &&
r.addEventListener("change", function () {
e.noUiSlider.set([this.value, null]);
}),
a &&
a.addEventListener("change", function () {
e.noUiSlider.set([null, this.value]);
});
})();
})(),
window.addEventListener(
"load",
function () {
var e = document.getElementsByClassName("needs-validation");
Array.prototype.filter.call(e, function (t) {
t.addEventListener(
"submit",
function (e) {
!1 === t.checkValidity() &&
(e.preventDefault(), e.stopPropagation()),
t.classList.add("was-validated");
},
!1
);
});
},
!1
),
(function () {
var a = document.querySelectorAll("[data-format]");
if (0 !== a.length)
for (var n = 0; n < a.length; n++)
!(function () {
var e,
t = a[n],
r = t.parentNode.querySelector(".credit-card-icon");
null != t.dataset.format &&
(e = JSON.parse(t.dataset.format)),
r
? new Cleave(
t,
_objectSpread(
_objectSpread({}, e),
{},
{
onCreditCardTypeChanged:
function (e) {
r.className =
"credit-card-icon " +
e;
},
}
)
)
: new Cleave(t, e);
})();
})(),
[].slice
.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
.map(function (e) {
return new bootstrap.Tooltip(e, { trigger: "hover" });
}),
[].slice
.call(document.querySelectorAll('[data-bs-toggle="popover"]'))
.map(function (e) {
return new bootstrap.Popover(e);
}),
[].slice.call(document.querySelectorAll(".toast")).map(function (e) {
return new bootstrap.Toast(e);
}),
(function () {
var e = document.querySelectorAll('[data-bs-toggle="video"]');
if (e.length)
for (var t = 0; t < e.length; t++)
lightGallery(e[t], {
selector: "this",
plugins: [lgVideo],
licenseKey: "D4194FDD-48924833-A54AECA3-D6F8E646",
download: !1,
youtubePlayerParams: {
modestbranding: 1,
showinfo: 0,
rel: 0,
},
vimeoPlayerParams: {
byline: 0,
portrait: 0,
color: "6366f1",
},
});
})(),
(function () {
var e = document.querySelectorAll(".price-switch-wrapper");
if (!(e.length <= 0))
for (var t = 0; t < e.length; t++)
e[t]
.querySelector('[data-bs-toggle="price"]')
.addEventListener("change", function (e) {
for (
var t = e.currentTarget.querySelector(
'input[type="checkbox"]'
),
r = e.currentTarget
.closest(".price-switch-wrapper")
.querySelectorAll(
"[data-monthly-price]"
),
a = e.currentTarget
.closest(".price-switch-wrapper")
.querySelectorAll(
"[data-annual-price]"
),
n = 0;
n < r.length;
n++
)
1 == t.checked
? r[n].classList.add("d-none")
: r[n].classList.remove("d-none");
for (var o = 0; o < r.length; o++)
1 == t.checked
? a[o].classList.remove("d-none")
: a[o].classList.add("d-none");
});
})(),
(function () {
var n,
r = document.querySelectorAll(".masonry-grid");
if (null !== r)
for (var o = 0; o < r.length; o++) {
var e = (function () {
(n = new Shuffle(r[o], {
itemSelector: ".masonry-grid-item",
sizer: ".masonry-grid-item",
})),
imagesLoaded(r[o]).on("progress", function () {
n.layout();
});
var a = r[o].closest(".masonry-filterable");
if (null === a) return { v: void 0 };
for (
var e = a.querySelectorAll(
".masonry-filters [data-group]"
),
t = 0;
t < e.length;
t++
)
e[t].addEventListener("click", function (e) {
var t = a.querySelector(
".masonry-filters .active"
),
r = this.dataset.group;
null !== t && t.classList.remove("active"),
this.classList.add("active"),
n.filter(r),
e.preventDefault();
});
})();
if ("object" === _typeof(e)) return e.v;
}
})(),
(function () {
var e = document.querySelectorAll(".subscription-form");
if (null !== e) {
for (var l = 0; l < e.length; l++)
!(function () {
var t = e[l].querySelector('button[type="submit"]'),
r = t.innerHTML,
a = e[l].querySelector(".form-control"),
n = e[l].querySelector(
".subscription-form-antispam"
),
o = e[l].querySelector(".subscription-status");
e[l].addEventListener("submit", function (e) {
e && e.preventDefault(),
"" === n.value && i(this, t, a, r, o);
});
})();
var i = function (e, t, r, a, n) {
t.innerHTML = "Sending...";
var o = e.action.replace("/post?", "/post-json?"),
e = "&" + r.name + "=" + encodeURIComponent(r.value),
l = document.createElement("script");
(l.src = o + "&c=callback" + e),
document.body.appendChild(l);
var i = "callback";
window[i] = function (e) {
delete window[i],
document.body.removeChild(l),
(t.innerHTML = a),
"success" == e.result
? (r.classList.remove("is-invalid"),
r.classList.add("is-valid"),
n.classList.remove("status-error"),
n.classList.add("status-success"),
(n.innerHTML = e.msg),
setTimeout(function () {
r.classList.remove("is-valid"),
(n.innerHTML = ""),
n.classList.remove(
"status-success"
);
}, 6e3))
: (r.classList.remove("is-valid"),
r.classList.add("is-invalid"),
n.classList.remove("status-success"),
n.classList.add("status-error"),
(n.innerHTML = e.msg.substring(4)),
setTimeout(function () {
r.classList.remove("is-invalid"),
(n.innerHTML = ""),
n.classList.remove("status-error");
}, 6e3));
};
};
}
})(),
document.querySelectorAll(".animation-on-hover").forEach(function (e) {
e.addEventListener("mouseover", function () {
e.querySelectorAll("lottie-player").forEach(function (e) {
e.setDirection(1), e.play();
});
}),
e.addEventListener("mouseleave", function () {
e.querySelectorAll("lottie-player").forEach(function (e) {
e.setDirection(-1), e.play();
});
});
}),
(function () {
var v = document.querySelectorAll(".audio-player");
if (0 !== v.length)
for (
var e = function () {
var t = v[y],
r = t.querySelector("audio"),
e = t.querySelector(".ap-play-button"),
a = t.querySelector(".ap-seek-slider"),
n = t.querySelector(".ap-volume-slider"),
o = t.querySelector(".ap-duration"),
l = t.querySelector(".ap-current-time"),
i = "play",
s = null;
e.addEventListener("click", function (e) {
i =
"play" === i
? (e.currentTarget.classList.add(
"ap-pause"
),
r.play(),
requestAnimationFrame(m),
"pause")
: (e.currentTarget.classList.remove(
"ap-pause"
),
r.pause(),
cancelAnimationFrame(s),
"play");
});
function c(e) {
e === a
? t.style.setProperty(
"--seek-before-width",
(e.value / e.max) * 100 + "%"
)
: t.style.setProperty(
"--volume-before-width",
(e.value / e.max) * 100 + "%"
);
}
a.addEventListener("input", function (e) {
c(e.target);
}),
n.addEventListener("input", function (e) {
c(e.target);
});
function u(e) {
var t = Math.floor(e / 60),
e = (
(e = Math.floor(e % 60)) < 10 ? "0" : ""
).concat(e);
return "".concat(t, ":").concat(e);
}
function d() {
o.textContent = u(r.duration);
}
function p() {
a.max = Math.floor(r.duration);
}
function f() {
var e = Math.floor(
r.buffered.end(r.buffered.length - 1)
);
t.style.setProperty(
"--buffered-width",
"".concat((e / a.max) * 100, "%")
);
}
var m = function e() {
(a.value = Math.floor(r.currentTime)),
(l.textContent = u(a.value)),
t.style.setProperty(
"--seek-before-width",
"".concat((a.value / a.max) * 100, "%")
),
(s = requestAnimationFrame(e));
};
0 < r.readyState
? (d(), p(), f())
: r.addEventListener(
"loadedmetadata",
function () {
d(), p(), f();
}
),
r.addEventListener("progress", f),
a.addEventListener("input", function () {
(l.textContent = u(a.value)),
r.paused || cancelAnimationFrame(s);
}),
a.addEventListener("change", function () {
(r.currentTime = a.value),
r.paused || requestAnimationFrame(m);
}),
n.addEventListener("input", function (e) {
e = e.target.value;
r.volume = e / 100;
});
},
y = 0;
y < v.length;
y++
)
e();
})();
})();
================================================
FILE: application/static/assets/vendor/prismjs/plugins/line-numbers/prism-line-numbers.css
================================================
pre[class*="language-"].line-numbers {
position: relative;
padding-left: 3.8em;
counter-reset: linenumber;
}
pre[class*="language-"].line-numbers > code {
position: relative;
white-space: inherit;
}
.line-numbers .line-numbers-rows {
position: absolute;
pointer-events: none;
top: 0;
font-size: 100%;
left: -3.8em;
width: 3em; /* works for line-numbers below 1000 lines */
letter-spacing: -1px;
border-right: 1px solid #999;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.line-numbers-rows > span {
display: block;
counter-increment: linenumber;
}
.line-numbers-rows > span:before {
content: counter(linenumber);
color: #999;
display: block;
padding-right: 0.8em;
text-align: right;
}
================================================
FILE: application/static/assets/vendor/prismjs/plugins/toolbar/prism-toolbar.css
================================================
div.code-toolbar {
position: relative;
}
div.code-toolbar > .toolbar {
position: absolute;
z-index: 10;
top: .3em;
right: .2em;
transition: opacity 0.3s ease-in-out;
opacity: 0;
}
div.code-toolbar:hover > .toolbar {
opacity: 1;
}
/* Separate line b/c rules are thrown out if selector is invalid.
IE11 and old Edge versions don't support :focus-within. */
div.code-toolbar:focus-within > .toolbar {
opacity: 1;
}
div.code-toolbar > .toolbar > .toolbar-item {
display: inline-block;
}
div.code-toolbar > .toolbar > .toolbar-item > a {
cursor: pointer;
}
div.code-toolbar > .toolbar > .toolbar-item > button {
background: none;
border: 0;
color: inherit;
font: inherit;
line-height: normal;
overflow: visible;
padding: 0;
-webkit-user-select: none; /* for button */
-moz-user-select: none;
-ms-user-select: none;
}
div.code-toolbar > .toolbar > .toolbar-item > a,
div.code-toolbar > .toolbar > .toolbar-item > button,
div.code-toolbar > .toolbar > .toolbar-item > span {
color: #bbb;
font-size: .8em;
padding: 0 .5em;
background: #f5f2f0;
background: rgba(224, 224, 224, 0.2);
box-shadow: 0 2px 0 0 rgba(0,0,0,0.2);
border-radius: .5em;
}
div.code-toolbar > .toolbar > .toolbar-item > a:hover,
div.code-toolbar > .toolbar > .toolbar-item > a:focus,
div.code-toolbar > .toolbar > .toolbar-item > button:hover,
div.code-toolbar > .toolbar > .toolbar-item > button:focus,
div.code-toolbar > .toolbar > .toolbar-item > span:hover,
div.code-toolbar > .toolbar > .toolbar-item > span:focus {
color: inherit;
text-decoration: none;
}
================================================
FILE: application/static/assets/vendor/prismjs/themes/prism.css
================================================
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.token.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
/* This background color was intended by the author of this theme. */
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
================================================
FILE: application/superadmin/__init__.py
================================================
================================================
FILE: application/superadmin/forms.py
================================================
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms import PasswordField
from wtforms import IntegerField
from wtforms import SubmitField
from wtforms import BooleanField
from wtforms import TextAreaField
from wtforms import SelectField
from wtforms import DateField
from flask_wtf.file import FileField
from flask_wtf.file import FileAllowed
from wtforms.validators import DataRequired
from wtforms.validators import Optional
from wtforms.validators import NumberRange
from wtforms.validators import Length
from wtforms.validators import Email
from wtforms.validators import EqualTo
from wtforms.validators import ValidationError
from flask_login import current_user
from application.models import User
# FUNDS ANALYTICS DATE RANGE
# class FundsAnalyticsDateRangeForm(FlaskForm):
# submit = SubmitField('Submit')
================================================
FILE: application/superadmin/views.py
================================================
import os
from datetime import datetime
# importing basic flask module
from flask import Blueprint
from flask import redirect
from flask import render_template
from flask import request
from flask import url_for
from flask import flash
from flask import abort
from flask import jsonify
from flask import make_response
from flask import current_app
from sqlalchemy import func
# importing module from flask login
from flask_login import current_user
from flask_login import login_required
from flask_login import login_user
from flask_login import logout_user
from application import db
from application import bcrypt
# from application.superadmin.forms import aksjdlkf
from application.models import User
from application.utils.Utils import applicationID
from application.utils.CutomAuth import superadmin_required
superadmin = Blueprint('superadmin', __name__)
# USER PROFILE
@superadmin.route('/superadmin/dashboard/', methods=['GET', 'POST'])
@login_required
@superadmin_required
def superadmin_dashboard():
return render_template(
'superadmin/dashboard.html',
title='Admin Dashboard',
)
================================================
FILE: application/templates/auth/activation_link_email.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Reset Your Password</title>
<link rel="stylesheet" href="{{ url_for('static', filename='assets/css/theme.min.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='assets/css/custom.css') }}" />
</head>
<body style="font-family: sans-serif; margin: 1rem 0.5rem; background-color: #6366f1; text-align: center;">
<div style="background-color: #fff; padding: 0.5rem;">
<table>
<tbody>
<tr>
<td>
<a href="https://rabeyabaten.com/" style="text-decoration: none;">
<img src="https://rabeyabaten.com/static/assets/images/logo.jpg" width="80"
alt="Rabeya Baten Foundation">
</a>
</td>
<td>
<a href="https://rabeyabaten.com/" style="text-decoration: none;">
<span style="margin-left: 10px; font-size: 1.5rem; color: #000; font-weight: 700;">
Rabeya Baten Foundation
</span>
</a>
</td>
</tr>
</tbody>
</table>
<p style="text-align: left; margin-top: 20px;">
As Salamu Alaikum, Thank you for registering with the Rabeya Baten Foundation. This email confirms that we have received your registration and the information provided by you.
</p>
<p style="margin-top: 50px; margin-bottom: 50px; text-align: center;">
<a href="{{ activation_link }}"
style="background: #6366f1; padding: 15px 40px; color: #fff; border-radius: 0.35rem; text-decoration: none;">
Activate your account
</a>
</p>
<p style="text-align: left;">
If you are unable to click the link, please copy and paste it into your browser's address bar.
<br>
<a href="{{ activation_link }}"> {{ activation_link }} </a>
</p>
<br>
<p style="text-align: left;">
Your account has been created successfully, and you can now access our website and start exploring our services.
If you have any questions or need further assistance, please contact us at
<a href="mailto:rabeyabatenfoundation@gmail.com">rabeyabatenfoundation@gmail.com</a>.
</p>
<p style="text-align: left;">
Zazak Allahu Khairan and Thank you for joining our community and supporting our mission to make a positive impact on society.
</p>
<p style="text-align: left;">
Best Regards,<br>
Rabeya Baten Foundation Team
</p>
<address style="text-align: left; background-color: #dfe6e9; color: #000; padding: 2rem;">
<small>
Mobile: +8801765-914159 <br>
Address: Rabeya Monjil, Padmapukur Par, Saiyadpur,<br>
Post Office: Duttapara. Thana: Chandraganj,<br>
District: Lakshmipur, Country: Bangladesh.<br>
Email: rabeyabatenfoundation@gmail.com<br>
YouTube: <a href="https://www.youtube.com/@RabeyaBatenFoundation">@RabeyaBatenFoundation</a>
<br>
Facebook: <a href="https://www.facebook.com/rabeyabatenfoundation">@rabeyabatenfoundation</a>
<br><br>
</small>
</address>
</div>
</body>
</html>
================================================
FILE: application/templates/auth/forgetpassword.html
================================================
{% extends 'layout/root.html' %}
{% block nav %}
{% include 'helpers/_nav_top_landing.html' %}
{% endblock %}
{% block body %}
<main style="margin-top: 100px">
<section class="position-relative pt-5 pb-5">
<div class="container d-flex flex-wrap justify-content-center justify-content-xl-start h-100">
<div class="w-100 align-self-end pt-1 pt-md-4 pb-4" style="max-width: 526px;">
<h1 class="text-center text-xl-start">
Forget your password?
</h1>
<form method="POST" action="" class="needs-validation mb-2" novalidate="">
{{ form.hidden_tag() }}
<div class="position-relative my-4">
{{ form.email.label(class="form-label fs-base") }}
{{ form.email(
class="form-control form-control-lg",
placeholder="Email"
) }}
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.email.errors %}
{% for error in form.email.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter valid Email!</span>
{% endif %}
</div>
</div>
{{ form.submit(class="btn btn-primary shadow-primary btn-lg w-100") }}
</form>
</div>
<!-- Background -->
<div class="position-absolute top-0 end-0 w-50 h-100 bg-position-center bg-repeat-0 bg-size-cover d-none d-xl-block"
style="background-image: url(https://silicon.createx.studio/assets/img/account/signin-bg.jpg);"></div>
</div>
</section>
</main>
{% endblock %}
{% block footer %}
{% include 'helpers/_global_footer.html' %}
{% endblock %}
================================================
FILE: application/templates/auth/join.html
================================================
{% extends 'layout/root.html' %}
{% block nav %}
{% include 'helpers/_nav_top_landing.html' %}
{% endblock %}
{% block body %}
<main style="margin-top: 20px">
<section class="position-relative pt-5 pb-5">
<!-- Sign in form -->
<div class="container d-flex flex-wrap justify-content-center justify-content-xl-start h-100">
<div class="w-100 align-self-end pt-1 pt-md-4 pb-4" style="max-width: 826px;">
<h1 class="text-center text-xl-start">Create Account</h1>
<p class="text-center text-xl-start pb-3 mb-3">Already have an account?<a
href="{{ url_for('auth.login') }}"> Login here.</a></p>
<!-- FORM VALIDATION ERROR -->
{% for field in [form.name, form.phone, form.email, form.password, form.confirm_password] %}
{% if field.errors %}
<div class="row my-1">
<div class="col-12">
<div class="toast align-items-center bg-danger fade show" role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide="flase" style="width: 100%">
<div class="toast-body">
{% for error in field.errors %}
<sapn class="text-white mb-0">{{ field.label }}: {{ error }}</sapn>
{% endfor %}
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
<form action="" method="POST" class="needs-validation my-2" novalidate="">
{{ form.hidden_tag() }}
<div class="row">
<!-- START - NAME -->
<div class="col-12">
<div class="position-relative mb-4">
{{ form.name.label(class="form-label fs-base") }}
{{ form.name(
class="form-control form-control-lg",
placeholder="Your Name"
) }}
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.name.errors %}
{% for error in form.name.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter a valid first name!</span>
{% endif %}
</div>
</div>
</div>
<!-- END - NAME -->
</div>
<div class="row">
<div class="col-md-6">
<div class="position-relative mb-4">
{{ form.email.label(class="form-label fs-base") }}
{{ form.email(
class="form-control form-control-lg",
placeholder="Email"
) }}
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.email.errors %}
{% for error in form.email.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter a valid Email!</span>
{% endif %}
</div>
</div>
</div>
<div class="col-md-6">
<div class="position-relative mb-4">
{{ form.phone.label(class="form-label fs-base") }}
{{ form.phone(
class="form-control form-control-lg",
placeholder="Phone number"
) }}
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.phone.errors %}
{% for error in form.phone.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter a valid phone number!</span>
{% endif %}
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="mb-4">
{{ form.password.label(class="form-label fs-base") }}
<div class="password-toggle">
{{ form.password(
class="form-control form-control-lg",
placeholder="Password"
) }}
<label class="password-toggle-btn" aria-label="Show/hide password">
<input class="password-toggle-check" type="checkbox">
<span class="password-toggle-indicator"></span>
</label>
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.password.errors %}
{% for error in form.password.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter a valid password!</span>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="mb-4">
{{ form.confirm_password.label(class="form-label fs-base") }}
<div class="password-toggle">
{{ form.confirm_password(
class="form-control form-control-lg",
placeholder="Confirm Password"
) }}
<label class="password-toggle-btn" aria-label="Show/hide password">
<input class="password-toggle-check" type="checkbox">
<span class="password-toggle-indicator"></span>
</label>
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.confirm_password.errors %}
{% for error in form.confirm_password.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter a valid password!</span>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{{ form.submit(class="btn btn-primary shadow-primary btn-lg w-100") }}
</form>
<!-- <h6 class="text-center mb-4">Or sign in with your social network</h6>
<div class="row row-cols-1 row-cols-sm-2">
<div class="col mb-3">
<a href="#" class="btn btn-icon btn-secondary btn-google btn-lg w-100">
<i class="bx bxl-google fs-xl me-2"></i>
Google
</a>
</div>
<div class="col mb-3">
<a href="#" class="btn btn-icon btn-secondary btn-facebook btn-lg w-100">
<i class="bx bxl-facebook fs-xl me-2"></i>
Facebook
</a>
</div>
</div> -->
</div>
</div>
<!-- Background -->
<div class="position-absolute top-0 end-0 w-33 h-100 bg-position-center bg-repeat-0 bg-size-cover d-none d-xl-block"
style="background-image: url(https://silicon.createx.studio/assets/img/account/signin-bg.jpg);"></div>
</section>
</main>
{% endblock %}
{% block footer %}
{% include 'helpers/_global_footer.html' %}
{% endblock %}
================================================
FILE: application/templates/auth/login.html
================================================
{% extends 'layout/root.html' %}
{% block nav %}
{% include 'helpers/_nav_top_landing.html' %}
{% endblock %}
{% block body %}
<main style="margin-top: 20px">
<section class="position-relative pt-5 pb-5">
<!-- Sign in form -->
<div class="container d-flex flex-wrap justify-content-center justify-content-xl-start h-100">
<div class="w-100 align-self-end pt-1 pt-md-4 pb-4" style="max-width: 526px;">
<h1 class="text-center text-xl-start">Welcome Back</h1>
<p class="text-center text-xl-start pb-3 mb-3">Don’t have an account yet? <a
href="{{ url_for('auth.join') }}">Register here.</a></p>
<!-- FORM VALIDATION ERROR -->
{% for field in [form.phone, form.password] %}
{% if field.errors %}
<div class="row my-1">
<div class="col-12">
<div class="toast align-items-center bg-danger fade show" role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide="flase" style="width: 100%">
<div class="toast-body">
{% for error in field.errors %}
<sapn class="text-white mb-0">{{ field.label }}: {{ error }}</sapn>
{% endfor %}
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
<form action="" method="POST" class="needs-validation mb-2" novalidate="">
{{ form.hidden_tag() }}
<div class="position-relative mb-4">
{{ form.phone.label(class="form-label fs-base") }}
{{ form.phone(
class="form-control form-control-lg",
placeholder="Phone number"
) }}
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.phone.errors %}
{% for error in form.phone.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter valid phone number!</span>
{% endif %}
</div>
</div>
<div class="mb-4">
{{ form.password.label(class="form-label fs-base") }}
<div class="password-toggle">
{{ form.password(
class="form-control form-control-lg",
placeholder="Password"
) }}
<label class="password-toggle-btn" aria-label="Show/hide password">
<input class="password-toggle-check" type="checkbox">
<span class="password-toggle-indicator"></span>
</label>
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.password.errors %}
{% for error in form.password.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter a valid password</span>
{% endif %}
</div>
</div>
</div>
<div class="mb-4">
<div class="form-check">
{{ form.remember(class="form-check-input") }}
{{ form.remember.label(class="form-check-label fs-base") }}
</div>
</div>
{{ form.submit(class="btn btn-primary shadow-primary btn-lg w-100") }}
</form>
<a href="{{ url_for('auth.forgetpassword') }}" class="btn btn-link btn-lg w-100">Forgot your password?</a>
<!-- <h6 class="text-center mb-4">Or sign in with your social network</h6>
<div class="row row-cols-1 row-cols-sm-2">
<div class="col mb-3">
<a href="#" class="btn btn-icon btn-secondary btn-google btn-lg w-100">
<i class="bx bxl-google fs-xl me-2"></i>
Google
</a>
</div>
<div class="col mb-3">
<a href="#" class="btn btn-icon btn-secondary btn-facebook btn-lg w-100">
<i class="bx bxl-facebook fs-xl me-2"></i>
Facebook
</a>
</div>
</div> -->
</div>
</div>
<!-- Background -->
<div class="position-absolute top-0 end-0 w-50 h-100 bg-position-center bg-repeat-0 bg-size-cover d-none d-xl-block"
style="background-image: url(https://silicon.createx.studio/assets/img/account/signin-bg.jpg);"></div>
</section>
</main>
{% endblock %}
{% block footer %}
{% include 'helpers/_global_footer.html' %}
{% endblock %}
================================================
FILE: application/templates/auth/password_reset_link_email.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Reset Your Password</title>
<link rel="stylesheet" href="{{ url_for('static', filename='assets/css/theme.min.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='assets/css/custom.css') }}" />
</head>
<body style="font-family: sans-serif; margin: 1rem 3rem; background-color: #6366f1;">
<div style="background-color: #fff; padding: 2rem;">
<table>
<tbody>
<tr>
<!-- <td>
<a href="https://rabeyabaten.com/" style="text-decoration: none;">
<img src="https://rabeyabaten.com/static/assets/images/logo.jpg" width="80"
alt="Rabeya Baten Foundation">
</a>
</td> -->
<td>
<a href="#" style="text-decoration: none;">
<span style="margin-left: 10px; font-size: 1.5rem; color: #000; font-weight: 700;">
ValentineAI
</span>
</a>
</td>
</tr>
</tbody>
</table>
<p style="text-align: left; margin-top: 20px">
We received a request to reset the password for your account with the Valentine application.
To reset your password, please click on the link below
</p>
<p style="margin-top: 50px; margin-bottom: 50px; text-align: center;">
<a href="{{ password_reset_link }}"
style="background: #6366f1; padding: 15px 40px; color: #fff; border-radius: 0.35rem; text-decoration: none;">
Reset your Password
</a>
</p>
<p style="text-align: left;">
If you are unable to click the link, please copy and paste it into your browser's address bar.
<br>
<p style="margin-top: 30px; margin-bottom: 20px;">
<a href="{{ password_reset_link }}"> {{ password_reset_link }} </a>
</p>
<br>
<p style="text-align: left;">
Please note that this link is only valid for the next 24 hours. If you do not reset your password within this time frame, you will need to submit a new request.
</p>
<p style="text-align: left;">
If you have any questions or need further assistance, please contact us at
<a href="mailto:sayhi@hossainfoysal.com">sayhi@hossainfoysal.com</a>.
<br>
If you did not make this request then simply ignore this email and no changes will be made.
</p>
<p style="text-align: left;">
Best Regards,<br>
Valentine AI
</p>
<address style="text-align: left; background-color: #dfe6e9; color: #000; padding: 2rem;">
<small>
It's a fun project. Made by <a href="http://hossainfoysal.com" target="_new">HossainFoysal.com</a>
<br>
Hosted on <a href="http://binomatrix.com" target="_new">BinoMatrix</a>. Fastest growing software company in Bangladesh.
</small>
</address>
</div>
</body>
</html>
================================================
FILE: application/templates/auth/reset_token.html
================================================
{% extends 'layout/root.html' %}
{% block nav %}
{% include 'helpers/_nav_top_landing.html' %}
{% endblock %}
{% block body %}
<main style="margin-top: 100px">
<section class="position-relative pt-5 pb-5">
<!-- Sign in form -->
<div class="container d-flex flex-wrap justify-content-center justify-content-xl-start h-100">
<div class="w-100 align-self-end pt-1 pt-md-4 pb-4" style="max-width: 526px;">
<h1 class="text-center text-xl-start">Type new password</h1>
<!-- FORM VALIDATION ERROR -->
{% for field in [form.password, form.confirm_password] %}
{% if field.errors %}
<div class="row my-1">
<div class="col-12">
<div class="toast align-items-center bg-danger fade show" role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide="flase" style="width: 100%">
<div class="toast-body">
{% for error in field.errors %}
<sapn class="text-white mb-0">{{ field.label }}: {{ error }}</sapn>
{% endfor %}
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
<form method="POST" action="" class="login__register" id="login-in">
{{ form.hidden_tag() }}
<div class="row">
<div class="col-sm-12">
<div class="mb-4">
{{ form.password.label(class="form-label fs-base") }}
<div class="password-toggle">
{{ form.password(
class="form-control form-control-lg",
placeholder="Password"
) }}
<label class="password-toggle-btn" aria-label="Show/hide password">
<input class="password-toggle-check" type="checkbox">
<span class="password-toggle-indicator"></span>
</label>
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.password.errors %}
{% for error in form.password.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter a valid password!</span>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="mb-4">
{{ form.confirm_password.label(class="form-label fs-base") }}
<div class="password-toggle">
{{ form.confirm_password(
class="form-control form-control-lg",
placeholder="Confirm Password"
) }}
<label class="password-toggle-btn" aria-label="Show/hide password">
<input class="password-toggle-check" type="checkbox">
<span class="password-toggle-indicator"></span>
</label>
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.confirm_password.errors %}
{% for error in form.confirm_password.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter a valid password!</span>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{{ form.submit(class="btn btn-primary shadow-primary btn-lg w-100") }}
</form>
</div>
</div>
<!-- Background -->
<div class="position-absolute top-0 end-0 w-50 h-100 bg-position-center bg-repeat-0 bg-size-cover d-none d-xl-block"
style="background-image: url(https://silicon.createx.studio/assets/img/account/signin-bg.jpg);"></div>
</section>
</main>
{% endblock %}
{% block footer %}
{% include 'helpers/_global_footer.html' %}
{% endblock %}
================================================
FILE: application/templates/helpers/_global_footer.html
================================================
<!-- ============== START - FOOTER ============== -->
<footer class="footer bg-dark pt-5 pb-4 pb-lg-5">
<div class="container dark-mode pt-lg-4">
<div class="row pb-5">
<div class="col-md-4">
<div class="navbar-brand text-gradient-primary p-0 me-0 mb-3 mb-lg-4">
Contact us
</div>
<ul class="nav flex-column pb-lg-1 mb-lg-3">
<li class="nav-item">
<p class="nav-link d-inline-block px-0 pt-1 pb-2">
It's a fun project. Made by <a href="http://hossainfoysal.com" target="_new">HossainFoysal.com</a>
</p>
</li>
<li class="nav-item">
<p class="nav-link d-inline-block px-0 pt-1 pb-2">
Hosted on <a href="http://binomatrix.com" target="_new">BinoMatrix</a>. Fastest growing software company in Bangladesh.
</p>
</li>
</ul>
</div>
<div class="col-md-8 pt-4 pt-md-1 pt-lg-0">
<div class="row">
<div class="col-md-5">
<h6 class="navbar-brand fs-md mb-2 text-gradient-primary">
Sitemap
</h6>
<div class="d-block">
<ul class="nav flex-column pb-lg-1 mb-lg-3">
<li class="nav-item">
<a href="/" class="nav-link d-inline-block px-0 pt-1 pb-2">
Home
</a>
</li>
<!-- <li class="nav-item">
<a href="#" class="nav-link d-inline-block px-0 pt-1 pb-2">
Contact
</a>
</li> -->
</ul>
</div>
</div>
<div class="col-md-7">
<h4 class="text-gradient-primary">
Developed by
</h4>
<a href="http://hossainfoysal.com" target="_new" class="fs-lg nav-link">Hossain Foysal</a>
<p class="fs-md mb-0">Full-Stack Software Engineer</p>
<a href="tel:+8801884020619" class="nav-link">Mobile: +8801884020619</aj>
<a href="http://hossainfoysal.com" target="_new">
<img style="border-radius: 20px"
src="https://hossainfoysal.com/static/img/social-media-banner-hossainfoysal.com.jpg"
alt="Hossain Foysal - Full Stack Web Developer, app developer, cybersecurity researcher " />
</a>
</div>
</div>
</div>
</div>
<p class="nav d-block fs-xs text-center pb-5 pb-lg-0 mb-5 mb-lg-0">
© All rights reserved by ValentineAI. Hosted with 💙 by
<a class="nav-link d-inline-block p-0" href="https://binomatrix.com/" target="_blank">BinoMatrix.com</a>
</p>
</div>
</footer>
<!-- ============== END - FOOTER ============== -->
================================================
FILE: application/templates/helpers/_nav_top_landing.html
================================================
<header class="header navbar bg-light navbar-expand-lg position-absolute navbar-sticky shadow-sm navbar-stuck">
<nav class="container px-3">
<a href="/" class="navbar-brand">
<!-- <img src="{{ url_for('static', filename='assets/images/logo.jpg') }}"
width="80"
alt="Rabeya Baten Foundation Logo"> -->
<span class="d-none d-sm-block">ValentineAI</span>
</a>
<button class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarCollapse1"
aria-expanded="false">
<span class="navbar-toggler-icon"></span>
</button>
<div id="navbarCollapse1" class="collapse navbar-collapse">
<hr class="d-lg-none mt-3 mb-2">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a href="{{ url_for('public.index') }}" class="nav-link">Home</a>
</li>
<!-- <li class="nav-item">
<a href="#" class="nav-link">Contact Us</a>
</li> -->
</ul>
{% if current_user.is_authenticated %}
<a href="{{ url_for('user.dashboard') }}"
class="btn btn-primary btn-sm fs-sm rounded ms-2 my-3 my-lg-0">Dashboard</a>
<a href="{{ url_for('auth.logout') }}"
class="btn btn-danger btn-sm fs-sm rounded ms-2 my-3 my-lg-0">Logout</a>
{% else %}
<a href="{{ url_for('auth.join') }}"
class="btn btn-primary btn-sm fs-sm rounded my-3 my-lg-0">Join Us</a>
<a href="{{ url_for('auth.login') }}"
class="btn btn-outline-primary btn-sm fs-sm rounded ms-2 my-3 my-lg-0">Login</a>
{% endif %}
</div>
</nav>
</header>
================================================
FILE: application/templates/helpers/_side_navbar_dashboard.html
================================================
<aside class="col-lg-3 col-md-4 border-end pb-5 mt-n5">
<div class="position-sticky top-0">
<div class="text-center py-5">
<div class="d-table position-relative mx-auto mt-2 mt-lg-4 pt-5 mb-3">
<!-- <img src="{{ url_for('static', filename='assets/images/profile/' + current_user.img) }}"
class="d-block rounded-circle"
width="120"
alt="John Doe"> -->
<div style="height: 120px;
width: 120px" class="bg-primary d-block rounded-circle"></div>
</div>
<h2 class="h5 mb-1">{{ current_user.name | title }}</h2>
<p class="mb-4">Address: {{ current_user.address | title }}</p>
<button type="button" class="btn btn-secondary w-100 d-md-none mt-n2 mb-3" data-bs-toggle="collapse"
data-bs-target="#account-menu">
<i class="bx bxs-user-detail fs-xl me-2"></i>
Account menu
<i class="bx bx-chevron-down fs-lg ms-1"></i>
</button>
<div id="account-menu" class="list-group list-group-flush collapse d-md-block">
<a href="{{ url_for("user.dashboard") }}"
class="list-group-item list-group-item-action d-flex align-items-center">
<i class="bx bxs-dashboard fs-xl opacity-60 me-2"></i>
Dashboard
</a>
<a href="{{ url_for("user.letters") }}"
class="list-group-item list-group-item-action d-flex align-items-center">
<i class="bx bxs-envelope fs-xl opacity-60 me-2"></i>
All Letters
</a>
<a href="{{ url_for("user.account") }}"
class="list-group-item list-group-item-action d-flex align-items-center">
<i class="bx bx-cog fs-xl opacity-60 me-2"></i>
Account
</a>
<a href="{{ url_for("user.account_password") }}"
class="list-group-item list-group-item-action d-flex align-items-center">
<i class="bx bx-lock-alt fs-xl opacity-60 me-2"></i>
Password
</a>
<a href="{{ url_for("auth.logout") }}"
class="list-group-item list-group-item-action d-flex align-items-center">
<i class="bx bx-log-out fs-xl opacity-60 me-2"></i>
Logout
</a>
</div>
</div>
</div>
</aside>
================================================
FILE: application/templates/layout/root.html
================================================
<!DOCTYPE html>
<html>
<head>
<title>
{% if title %}
{{ title }} | Valentines Letter Sender
{% else %}
Valentines Letter Sender
{% endif %}
</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<link rel="icon" href="images/favicon.ico" type="image/x-icon" />
<link rel="stylesheet" type="text/css"
href="//fonts.googleapis.com/css2?family=DM+Serif+Display&family=Roboto:wght@300;400;700&display=swap" />
<link href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css" rel="stylesheet" />
<!-- Vendor Styles -->
<link rel='stylesheet' href='https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css'>
<link rel="stylesheet" href="{{ url_for('static', filename='assets/vendor/swiper/swiper-bundle.min.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='assets/vendor/prismjs/themes/prism.css') }}" />
<link rel="stylesheet"
href="{{ url_for('static', filename='assets/vendor/prismjs/plugins/toolbar/prism-toolbar.css') }}" />
<link rel="stylesheet"
href="{{ url_for('static', filename='assets/vendor/prismjs/plugins/line-numbers/prism-line-numbers.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='assets/css/theme.min.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='assets/css/custom.css') }}" />
{% block head %}
{% endblock %}
<!-- Theme mode -->
<script>
let mode = window.localStorage.getItem('mode'),
root = document.getElementsByTagName('html')[0];
if (mode !== null && mode === 'dark') {
root.classList.add('dark-mode');
} else {
root.classList.remove('dark-mode');
}
</script>
{{ moment.include_moment() }}
</head>
<body>
<!-- ============== START NAVIGATION SECTION ============== -->
{% block nav %}
{% endblock %}
<!-- ============== END NAVIGATION SECTION ============== -->
<!-- bs-toast toast toast-ex animate__animated my-2 fade bg-primary animate__slideInRight show -->
<!-- ============== START FLASH MESSAGE ============== -->
{% with messages=get_flashed_messages(with_categories=true)%}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }} alert-dismissible fade show" role="alert"
style="margin-bottom: 0; position: absolute; top: 7rem; z-index: 1500;">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endif %}
{% endwith %}
<!-- ============== END FLASH MESSAGE ============== -->
<!-- ============== START BODY SECTION ============== -->
{% block body %}
{% endblock %}
<!-- ============== END BODY SECTION ============== -->
<!-- ============== START FOOTER SECTION ============== -->
{% block footer %}
{% endblock %}
<!-- ============== END FOOTER SECTION ============== -->
<script>
const numberWithCommas = (x) => {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
</script>
<!-- Vendor Scripts -->
<script
src="{{ url_for('static', filename='assets/vendor/bootstrap/dist/js/bootstrap.bundle.min.js') }}"></script>
<script
src="{{ url_for('static', filename='assets/vendor/smooth-scroll/dist/smooth-scroll.polyfills.min.js') }}"></script>
<script src="{{ url_for('static', filename='assets/vendor/swiper/swiper-bundle.min.js') }}"></script>
<script src="{{ url_for('static', filename='assets/vendor/prismjs/components/prism-core.min.js') }}"></script>
<script src="{{ url_for('static', filename='assets/vendor/prismjs/components/prism-markup.min.js') }}"></script>
<script src="{{ url_for('static', filename='assets/vendor/prismjs/components/prism-clike.min.js') }}"></script>
<script
src="{{ url_for('static', filename='assets/vendor/prismjs/plugins/toolbar/prism-toolbar.min.js') }}"></script>
<script
src="{{ url_for('static', filename='assets/vendor/prismjs/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js') }}"></script>
<script
src="{{ url_for('static', filename='assets/vendor/prismjs/plugins/line-numbers/prism-line-numbers.min.js') }}"></script>
{% block script %}
{% endblock %}
<!-- Main Theme Script -->
<script src="{{ url_for('static', filename='assets/js/theme.js') }}"></script>
</body>
</html>
================================================
FILE: application/templates/public/landing.html
================================================
{% extends 'layout/root.html' %}
{% block nav %}
{% include 'helpers/_nav_top_landing.html' %}
{% endblock %}
{% block body %}
<section class="jarallax bg-dark min-vh-100" data-jarallax="" data-speed="0.4" data-bs-theme="dark">
<span class="position-absolute top-0 start-0 w-100 h-100"
style="background: radial-gradient(116.18% 118% at 50% 100%, rgba(99, 102, 241, 0.1) 0%, rgba(218, 70, 239, 0.05) 41.83%, rgba(241, 244, 253, 0.07) 82.52%);"></span>
<div class="min-vh-100 d-flex flex-column py-5">
<div class="container position-relative text-center zindex-5 pt-4 pt-md-5 pb-5 mt-auto">
<div class="row mt-5">
<div class="col-xl-10 mx-auto">
<h1 class="display-1 mb-md-4 pb-3 text-light">Send your loved person a letter digitally 💌</h1>
<p class="text-light mx-auto mb-md-4 mb-3 pb-xl-2 pb-md-0 pb-sm-2 fs-3" style="max-width: 36.5rem;">
Powered by ValentineAI
<br>
Hosted on <a href="http://binomatrix.com" target="_new">BinoMatrix</a>
</p>
<a href="{{ url_for('auth.join') }}" class="btn btn-lg btn-primary shadow-primary">Write your
valentine letter</a>
</div>
</div>
</div>
</div>
<div id="jarallax-container-0" class="jarallax-container"
style="position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; overflow: hidden; z-index: -100; clip-path: polygon(0px 0px, 100% 0px, 100% 100%, 0px 100%);">
<div class="jarallax-img"
style="background-image: url({{ url_for("static", filename="assets/images/hero-bg.png") }}); object-fit: cover; object-position: 50% 50%; max-width: none; position: fixed; top: 0px; left: 0px; overflow: hidden; pointer-events: none; transform-style: preserve-3d; backface-visibility: hidden; margin-top: -4.63125px; transform: translate3d(0px, 4.63125px, 0px);"
data-jarallax-original-styles="background-image: url({{ url_for("static", filename="assets/images/hero-bg.png") }});">
</div>
</div>
</section>
{% endblock %}
{% block footer %}
{% include 'helpers/_global_footer.html' %}
{% endblock %}
================================================
FILE: application/templates/public/letter.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Letter</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Pacifico&display=swap');
body {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: #ff758f;
}
.valentines-day-card {
position: relative;
width: 400px;
height: 300px;
background-color: #ff8fa3;
overflow: hidden;
border: 10px solid white;
border-radius: 10px;
box-shadow: 0 0 100px rgba(0, 0, 0, .4);
}
.valentines-day-card:before {
content: "";
position: absolute;
background-color: #ffb3c1;
width: 100px;
height: 100px;
border-radius: 50%;
top: 140px;
left: -25px;
box-shadow: 60px 20px #ffb3c1, 130px 10px #ffb3c1, 190px 20px #ffb3c1, 260px -5px #ffb3c1, 340px 20px #ffb3c1;
}
.valentines-day-card:after {
content: "";
position: absolute;
background-color: #ffccd5;
width: 100px;
height: 100px;
border-radius: 50%;
top: 160px;
left: -40px;
box-shadow: 50px 20px #ffccd5, 120px 40px #ffccd5, 200px 15px #ffccd5, 260px 30px #ffccd5, 330px 30px #ffccd5, 380px 10px #ffccd5;
}
.clouds {
position: absolute;
width: 100px;
height: 100px;
border-radius: 50%;
background-color: #fff0f3;
z-index: 5;
top: 210px;
left: -20px;
box-shadow: 55px 30px #fff0f3, 125px 10px #fff0f3, 175px 20px #fff0f3, 250px 10px #fff0f3, 320px 5px #fff0f3, 380px 10px #fff0f3;
}
.hearts {
position: absolute;
z-index: 2;
}
.heartOne {
position: absolute;
left: 100px;
top: 250px;
animation: up 4s linear forwards 1s;
}
.heartTwo {
position: absolute;
left: 270px;
top: 230px;
animation: up 5s linear forwards 1.8s;
}
.heartThree {
position: absolute;
left: 85px;
top: 415px;
animation: up 5s linear forwards 3s;
}
.heartFour {
position: absolute;
left: 320px;
top: 380px;
animation: upTwo 9s linear infinite 3.5s;
}
.heartFive {
position: absolute;
left: 150px;
top: 400px;
animation: upTwo 13s linear infinite 4.5s;
}
.right-side:before,
.right-side:after {
position: absolute;
content: "";
transform-origin: left;
animation: move 1s ease infinite;
}
.right-side:before {
border-radius: 50% 50% 50% 0;
width: 21px;
height: 20px;
background-color: #c9184a;
left: -0.26px;
}
.right-side:after {
height: 0;
width: 0;
border-bottom: 10px solid transparent;
border-left: 15px solid #c9184a;
top: 19px;
left: -0.26px;
}
@keyframes move {
0%,
100% {
transform: rotateY(0);
}
50% {
transform: rotateY(-45deg);
}
}
.left-side:before,
.left-side:after {
position: absolute;
content: "";
transform-origin: right;
animation: move 1s ease infinite;
}
.left-side:before {
border-radius: 50% 50% 0 50%;
width: 20px;
height: 20px;
left: -20.7px;
background-color: #ff4d6d;
}
.left-side:after {
height: 0;
width: 0;
left: -15px;
border-bottom: 10px solid transparent;
border-right: 15px solid #ff4d6d;
top: 19px;
}
@keyframes up {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-200px);
}
}
@keyframes upTwo {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-450px);
}
}
.text {
position: absolute;
color: #800f2f;
font-size: 30px;
font-family: 'Pacifico', cursive;
line-height: 1;
text-align: center;
width: 380px;
left: 10px;
z-index: 3;
top: 280px;
animation: up 1s ease forwards;
transition: .2s;
}
.hover {
color: white;
font-family: 'Pacifico', cursive;
text-align: center;
}
.text:hover span {
display: none;
}
.text:hover:before {
content: "{{ letter.message }}";
font-size: 25px;
}
</style>
</head>
<body>
<div class="happy-valentines">
<div class="valentines-day-card">
<div class="clouds"></div>
<div class="hearts">
<div class="heartOne">
<div class="left-side"></div>
<div class="right-side"></div>
</div>
<div class="heartTwo">
<div class="left-side"></div>
<div class="right-side"></div>
</div>
<div class="heartThree">
<div class="left-side"></div>
<div class="right-side"></div>
</div>
<div class="heartFour">
<div class="left-side"></div>
<div class="right-side"></div>
</div>
<div class="heartFive">
<div class="left-side"></div>
<div class="right-side"></div>
</div>
</div>
<div class="text"><span>Happy Valentine's Day!</br> {{ letter.receiver_name }}</div>
</div>
{% if letter.is_hidden %}
<p class="hover">- Your well wisher -</p>
{% else %}
<p class="hover">- Your {{ letter.sender.name }} -</p>
{% endif %}
</div>
</body>
</html>
================================================
FILE: application/templates/user/account.html
================================================
{% extends 'layout/root.html' %}
{% block nav %}
{% include 'helpers/_nav_top_landing.html' %}
{% endblock %}
{% block body %}
<main style="margin-top: 100px">
<section class="container">
<div class="row">
<!-- Sidebar (User info + Account menu) -->
{% include 'helpers/_side_navbar_dashboard.html' %}
<!-- Account details -->
<div class="col-md-9 pb-5 mb-2 mb-lg-4 mt-3 mt-md-0">
<div class="ps-md-3 ps-lg-0 mt-md-2 py-md-4">
<h1 class="h2 pt-xl-1 pb-3">Profile Details</h1>
{% for field in [form.name, form.email, form.phone] %}
{% if field.errors %}
<div class="row my-1">
<div class="col-12">
<div class="toast align-items-center bg-danger fade show" role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide="flase" style="width: 100%">
<div class="toast-body">
{% for error in field.errors %}
<sapn class="text-white mb-0">{{ field.label }}: {{ error }}</sapn>
{% endfor %}
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
<!-- Basic info -->
<h2 class="h5 text-primary mb-4">Edit info</h2>
<form action="" method="POST" class="needs-validation my-2" novalidate="">
{{ form.hidden_tag() }}
<!-- === START - NAME CONTAINER === -->
<div class="row">
<!-- START - NAME -->
<div class="col-12">
<div class="position-relative mb-4">
{{ form.name.label(class="form-label fs-base") }}
{{ form.name(
class="form-control form-control-lg",
placeholder="Your First Name"
) }}
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.name.errors %}
{% for error in form.name.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter a valid name!</span>
{% endif %}
</div>
</div>
</div>
<!-- END - NAME -->
</div>
<!-- END - FIRST NAME, MIDDLE NAME, LAST NAME CONTAINER -->
<!-- === START - EMAIL, PHONE, ADDRESS CONTAINER === -->
<div class="row">
<!-- START - EMAIL -->
<div class="col-12">
<div class="position-relative mb-4">
{{ form.email.label(class="form-label fs-base") }}
{{ form.email(
class="form-control form-control-lg",
placeholder="Email"
) }}
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.email.errors %}
{% for error in form.email.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter a valid Email!</span>
{% endif %}
</div>
</div>
</div>
<!-- END - EMAIL -->
<!-- START - PHONE -->
<div class="col-12">
<div class="position-relative mb-4">
{{ form.phone.label(class="form-label fs-base") }}
{{ form.phone(
class="form-control form-control-lg",
placeholder="Phone number"
) }}
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.phone.errors %}
{% for error in form.phone.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter a valid phone number!</span>
{% endif %}
</div>
</div>
</div>
<!-- END - PHONE -->
</div>
<!-- === END - EMAIL, PHONE, ADDRESS CONTAINER === -->
{{ form.submit(class="btn btn-primary shadow-primary btn-lg w-100") }}
</form>
<!-- Delete account -->
<!-- <h2 class="h5 text-primary pt-1 pt-lg-3 mt-4">Delete account</h2>
<p>When you delete your account, your public profile will be deactivated immediately. If you change your
mind before the 14 days are up, sign in with your email and password, and we’ll send you a link to
reactivate your account.</p>
<button type="button" class="btn btn-danger">Yes, I want to delete my
account</button> -->
</div>
</div>
</div>
</section>
</main>
{% endblock %}
{% block footer %}
{% include 'helpers/_global_footer.html' %}
{% endblock %}
================================================
FILE: application/templates/user/account_update_password.html
================================================
{% extends 'layout/root.html' %}
{% block nav %}
{% include 'helpers/_nav_top_landing.html' %}
{% endblock %}
{% block body %}
<main style="margin-top: 100px">
<section class="container">
<div class="row">
<!-- Sidebar (User info + Account menu) -->
{% include 'helpers/_side_navbar_dashboard.html' %}
<!-- Account details -->
<div class="col-md-9 pb-5 mb-2 mb-lg-4 mt-3 mt-md-0">
<div class="ps-md-3 ps-lg-0 mt-md-2 py-md-4">
<h1 class="h2 pt-xl-1 pb-3">Account Password</h1>
{% for field in [form.current_password, form.confirm_password, form.new_password] %}
{% if field.errors %}
<div class="row my-1">
<div class="col-12">
<div class="toast align-items-center bg-danger fade show" role="alert" aria-live="assertive"
aria-atomic="true" data-bs-autohide="flase" style="width: 100%">
<div class="toast-body">
{% for error in field.errors %}
<sapn class="text-white mb-0">{{ field.label }}: {{ error }}</sapn>
{% endfor %}
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
<!-- Basic info -->
<h2 class="h5 text-primary mb-4">Update Password</h2>
<form action="" method="POST" class="needs-validation my-2" novalidate="">
{{ form.hidden_tag() }}
<div class="row">
<div class="col-sm-12">
<div class="mb-4">
{{ form.current_password.label(class="form-label fs-base") }}
<div class="password-toggle">
{{ form.current_password(
class="form-control form-control-lg",
placeholder="Current Password"
) }}
<label class="password-toggle-btn" aria-label="Show/hide password">
<input class="password-toggle-check" type="checkbox">
<span class="password-toggle-indicator"></span>
</label>
<div class="invalid-feedback position-absolute start-0 top-100">
<span>Please enter a valid password!</span>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="mb-4">
{{ form.new_password.label(class="form-label fs-base") }}
<div class="password-toggle">
{{ form.new_password(
class="form-control form-control-lg",
placeholder="New Password"
) }}
<label class="password-toggle-btn" aria-label="Show/hide password">
<input class="password-toggle-check" type="checkbox">
<span class="password-toggle-indicator"></span>
</label>
<div class="invalid-feedback position-absolute start-0 top-100">
<span>Please enter a valid password!</span>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="mb-4">
{{ form.confirm_password.label(class="form-label fs-base") }}
<div class="password-toggle">
{{ form.confirm_password(
class="form-control form-control-lg",
placeholder="Confirm New Password"
) }}
<label class="password-toggle-btn" aria-label="Show/hide password">
<input class="password-toggle-check" type="checkbox">
<span class="password-toggle-indicator"></span>
</label>
<div class="invalid-feedback position-absolute start-0 top-100">
<span>Please enter a valid password!</span>
</div>
</div>
</div>
</div>
</div>
{{ form.submit(class="btn btn-primary shadow-primary btn-lg w-100") }}
</form>
</div>
</div>
</div>
</section>
</main>
{% endblock %}
{% block footer %}
{% include 'helpers/_global_footer.html' %}
{% endblock %}
================================================
FILE: application/templates/user/dashboard.html
================================================
{% extends 'layout/root.html' %}
{% block nav %}
{% include 'helpers/_nav_top_landing.html' %}
{% endblock %}
{% block body %}
<main style="margin-top: 100px">
<section class="container">
<div class="row">
<!-- Sidebar (User info + Account menu) -->
{% include 'helpers/_side_navbar_dashboard.html' %}
<div class="col-md-9 pb-5 mb-2 mb-lg-4 mt-n3 mt-md-0">
<h2>
Send a letter to your loving person 💌
</h2>
<!-- FORM VALIDATION ERROR -->
{% for field in [form.name, form.email, form.gender, form.letter] %}
{% if field.errors %}
<div class="row my-1">
<div class="col-12">
<div class="toast align-items-center bg-danger fade show" role="alert" aria-live="assertive" aria-atomic="true" data-bs-autohide="flase" style="width: 100%">
<div class="toast-body">
{% for error in field.errors %}
<sapn class="text-white mb-0">{{ field.label }}: {{ error }}</sapn>
{% endfor %}
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
<form action="" method="POST" class="needs-validation mb-2 position-relative" novalidate="">
<!-- LOADING SPINNER -->
<div id="spinner" class="w-100 text-center d-none">
<div class="spinner-border mt-5" style="width: 3.5rem; height: 3.5rem;" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p>Loading..</p>
</div>
<div id="formel">
{{ form.hidden_tag() }}
<div class="position-relative mb-4">
{{ form.name.label(class="form-label fs-base") }}
{{ form.name(
class="form-control form-control-lg",
placeholder=""
) }}
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.name.errors %}
{% for error in form.name.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter valid name!</span>
{% endif %}
</div>
</div>
<div class="mb-4">
{{ form.email.label(class="form-label fs-base") }}
{{ form.email(
class="form-control form-control-lg",
placeholder=""
) }}
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.email.errors %}
{% for error in form.email.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter valid email!</span>
{% endif %}
</div>
</div>
<div class="mb-4">
{{ form.gender.label(class="form-label fs-base") }}
{{ form.gender(
class="form-select form-select-lg",
placeholder=""
) }}
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.gender.errors %}
{% for error in form.gender.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Select a valid gender!</span>
{% endif %}
</div>
</div>
<div class="position-relative mb-4">
{{ form.letter.label(class="form-label fs-base") }}
{{ form.letter(
class="form-control form-control-lg",
placeholder="",
style="height: 120px",
) }}
<div class="invalid-feedback position-absolute start-0 top-100">
{% if form.letter.errors %}
{% for error in form.letter.errors %}
<span>{{ error }}</span>
{% endfor %}
{% else %}
<span>Please enter a valid letter!</span>
{% endif %}
</div>
</div>
<div class="mb-4">
<div class="form-check">
{{ form.is_hidden(class="form-check-input") }}
{{ form.is_hidden.label(class="form-check-label") }}
</div>
</div>
{{ form.submit(class="btn btn-primary shadow-primary btn-lg w-100") }}
</div>
</form>
</div>
</div>
</section>
</main>
<!-- <script>
let genderel = document.getElementById("gender");
let form = document.querySelector('#formel');
let spinner = document.querySelector('#spinner');
let submit = document.querySelector('submit');
genderel.addEventListener('change', () => {
form.classList.add('d-none');
spinner.classList.remove('d-none');
let gender = document.getElementById("gender").value;
fetch(`${window.origin}/dashboard/letter/regenerate/`, {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
gender
}),
}).then((response) => {
if (response.status !== 200) {
console.log(`Something went wrong! Reload the page. Status: ${response.status}`);
return;
}
response.json().then((data) => {
spinner.classList.add('d-none');
form.classList.remove('d-none');
console.log(data)
})
});
});
</script> -->
{% endblock %}
{% block footer %}
{% include 'helpers/_global_footer.html' %}
{% endblock %}
================================================
FILE: application/templates/user/letter_sent.html
================================================
{% extends 'layout/root.html' %}
{% block nav %}
{% include 'helpers/_nav_top_landing.html' %}
{% endblock %}
{% block body %}
<main style="margin-top: 100px">
<section class="container">
<div class="row">
<!-- Sidebar (User info + Account menu) -->
{% include 'helpers/_side_navbar_dashboard.html' %}
<div class="col-md-9 pb-5 mb-2 mb-lg-4 mt-n3 mt-md-0">
<h2>
💌 Message sent to your love 💝 ✈️
</h2>
<input type="text" id="loveLetterLink" class="form-control form-control-lg" value="" readonly>
<button id="clipboardEl" class="btn btn-primary mt-3">
<i class='bx bx-copy fs-lg me-2'></i>
Copy link
</button>
<a href="{{ url_for('user.letters') }}" class="btn btn-dark mt-3 ms-2">
View all letters
</a>
</div>
</div>
</section>
</main>
<script>
let clipboardEl = document.querySelector('#clipboardEl');
let loveLetterLink = document.querySelector('#loveLetterLink');
loveLetterLink.value = `${window.origin}/letter/{{ letter.link }}/`
//Copy password to clipboard
clipboardEl.addEventListener('click', () => {
const textarea = document.createElement('textarea') ;
const letterLink = loveLetterLink.value;
if (!letterLink){
return '' ;
}
textarea.value = letterLink;
document.body.appendChild(textarea) ;
textarea.select() ;
document.execCommand('copy') ;
textarea.remove();
//Make an alert when password is copied
alert('Link copied to clipboard') ;
});
</script>
{% endblock %}
{% block footer %}
{% include 'helpers/_global_footer.html' %}
{% endblock %}
================================================
FILE: application/templates/user/letters.html
================================================
{% extends 'layout/root.html' %}
{% block nav %}
{% include 'helpers/_nav_top_landing.html' %}
{% endblock %}
{% block body %}
<main style="margin-top: 100px">
<section class="container">
<div class="row">
<!-- Sidebar (User info + Account menu) -->
{% include 'helpers/_side_navbar_dashboard.html' %}
<div class="col-md-9 pb-5 mb-2 mb-lg-4 mt-n3 mt-md-0">
<h2>
💌 Letters you have sent
</h2>
<!-- Light bordered table -->
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th scope="col" style="width: 5%">#</th>
<th scope="col">Receiver</th>
<th scope="col">Email</th>
<th scope="col">Gender</th>
<th scope="col" style="width: 40%">Message</th>
<th scope="col" style="width: 10%">Action</th>
</tr>
</thead>
<tbody>
{% for letter in letters.items %}
<tr>
<th scope="row">{{ loop.index }}</th>
<td>{{ letter.receiver_name | title }}</td>
<td>{{ letter.email }}</td>
<td>{{ letter.gender | title }}</td>
<td>{{ letter.message }}</td>
<td>
<a href="{{ url_for('public.letter', link=letter.link) }}" class="btn btn-success">
View Letter
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Pagination: Basic example -->
<nav aria-label="Page navigation example">
<ul class="pagination">
{% if letters.has_prev %}
<li class="page-item">
<a href="{{ url_for('user.letters', page=letters.prev_num) }}" class="page-link">
<i class="bx bx-chevron-left ms-n1 me-1"></i>
Prev
</a>
</li>
{% endif %}
<!-- START - Iterate through the pagination -->
{% for page_num in letters.iter_pages(left_edge=0, left_current=2, right_current=3, right_edge=0) %}
{% if page_num %}
{% if letters.page == page_num %}
<li class="page-item active d-none d-sm-block" aria-current="page">
<a class="page-link" href="{{ url_for('user.letters', page=page_num) }}">
{{ page_num }}
<span class="visually-hidden">(current)</span>
</a>
</li>
{% else %}
<li class="page-item d-none d-sm-block">
<a href="{{ url_for('user.letters', page=page_num) }}" class="page-link">
{{ page_num }}
</a>
</li>
{% endif %}
{% endif %}
{% endfor %}
<!-- END - Iterate through the pagination -->
{% if letters.has_next %}
<li class="page-item">
<a href="{{ url_for('user.letters', page=letters.next_num) }}" class="page-link">
Next
<i class="bx bx-chevron-right me-n1 ms-1"></i>
</a>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
</section>
</main>
{% endblock %}
{% block footer %}
{% include 'helpers/_global_footer.html' %}
{% endblock %}
================================================
FILE: application/templates/user/send_letter_email.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>💌 You received a letter to read - ValentineAI</title>
<link rel="stylesheet" href="{{ url_for('static', filename='assets/css/theme.min.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='assets/css/custom.css') }}" />
</head>
<body style="font-family: sans-serif; margin: 1rem 3rem; background-color: #6366f1;">
<div style="background-color: #fff; padding: 2rem;">
<table>
<tbody>
<tr>
<!-- <td>
<a href="https://rabeyabaten.com/" style="text-decoration: none;">
<img src="https://rabeyabaten.com/static/assets/images/logo.jpg" width="80"
alt="Rabeya Baten Foundation">
</a>
</td> -->
<td>
<a href="#" style="text-decoration: none;">
<span style="margin-left: 10px; font-size: 1.5rem; color: #000; font-weight: 700;">
ValentineAI
</span>
</a>
</td>
</tr>
</tbody>
</table>
<p style="text-align: left; margin-top: 20px">
You have received a new letter from your loved person who really want to surprise you. Check his messages below
</p>
<p style="margin-top: 50px; margin-bottom: 50px; text-align: center;">
<a href="{{ letter_link }}"
style="background: #6366f1; padding: 15px 40px; color: #fff; border-radius: 0.35rem; text-decoration: none;">
💌 Read the message
</a>
</p>
<p style="text-align: left;">
If you are unable to click the link, please copy and paste it into your browser's address bar.
<br>
<p style="margin-top: 30px; margin-bottom: 20px;">
<a href="{{ letter_link }}"> {{ letter_link }} </a>
</p>
<br>
<p style="text-align: left;">
If you have any questions, please contact us at
<a href="mailto:sayhi@hossainfoysal.com">sayhi@hossainfoysal.com</a>. We would love to help answer your question.
</p>
<p style="text-align: left;">
Best Regards,<br>
Valentine AI
</p>
<address style="text-align: left; background-color: #dfe6e9; color: #000; padding: 2rem;">
<small>
It's a fun project. Made by <a href="http://hossainfoysal.com" target="_new">HossainFoysal.com</a>
<br>
Hosted on <a href="http://binomatrix.com" target="_new">BinoMatrix</a>. Fastest growing software company in Bangladesh.
</small>
</address>
</div>
</body>
</html>
================================================
FILE: application/user/__init__.py
================================================
================================================
FILE: application/user/forms.py
================================================
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms import PasswordField
from wtforms import IntegerField
from wtforms import SubmitField
from wtforms import BooleanField
from wtforms import TextAreaField
from wtforms import SelectField
from wtforms import DateField
from flask_wtf.file import FileField
from flask_wtf.file import FileAllowed
from wtforms.validators import DataRequired
from wtforms.validators import Optional
from wtforms.validators import NumberRange
from wtforms.validators import Length
from wtforms.validators import Email
from wtforms.validators import EqualTo
from wtforms.validators import ValidationError
from flask_login import current_user
from application.models import User
# LETTER FORM
class LetterForm(FlaskForm):
name = StringField(
'Receiver Name',
validators = [
DataRequired(),
Length(2, 50)
]
)
email = StringField(
'Receiver Email',
validators = [
DataRequired(),
Email()
]
)
gender = SelectField(
'To your',
choices = [
('girlfriend', 'Girlfriend'),
('boyfriend', 'Boyfriend')
]
)
letter = TextAreaField(
'Your message',
validators = [
DataRequired(),
Length(10, 100)
]
)
is_hidden = BooleanField(
'No, I don\'t want to display my name',
validators = [DataRequired()]
)
submit = SubmitField('Send your surprise message')
# UPDATE PROFILE FORM
class UpdateProfileForm(FlaskForm):
name = StringField(
'Your Name',
validators = [
DataRequired(),
Length(2, 50)
]
)
email = StringField(
'E-mail',
validators = [
DataRequired(),
Email()
]
)
phone = StringField(
'Phone',
validators=[
DataRequired(),
]
)
picture = FileField(
'Update Profile Picture',
validators = [
FileAllowed(['jpg','jpeg','png'])
]
)
address = StringField(
'Address',
validators = [
DataRequired(),
Length(min=5, max=50)
]
)
submit = SubmitField('Save')
def validate_phone(self, phone):
if phone.data and phone.data != current_user.phone:
user_phone = User.query.filter_by(phone=phone.data).first()
if user_phone:
raise ValidationError('This phone number is already registered. Please choose a different one.')
def validate_email(self, email):
if email.data and email.data != current_user.email:
user_email = User.query.filter_by(email=email.data).first()
if user_email:
raise ValidationError('That email is already registered. Please choose a different one.')
# UPDATE PASSWORD
class UpdatePasswordForm(FlaskForm):
current_password = PasswordField(
'Current Password'
)
new_password = PasswordField(
'New Password'
)
confirm_password = PasswordField(
'Confirm New Password',
validators = [
DataRequired(),
EqualTo('new_password')
]
)
submit = SubmitField('Save')
================================================
FILE: application/user/views.py
================================================
import os
# importing basic flask module
from flask import Blueprint
from flask import redirect
from flask import render_template
from flask import request
from flask import url_for
from flask import flash
from flask import abort
from flask import jsonify
from flask import make_response
from flask import current_app
# importing module from flask login
from flask_login import current_user
from flask_login import login_required
from flask_login import login_user
from flask_login import logout_user
from application import db
from application import bcrypt
from application.user.forms import UpdateProfileForm
from application.user.forms import UpdatePasswordForm
from application.user.forms import LetterForm
from application.models import User
from application.models import Letter
from application.CohereAI.Utils import linkid
from application.utils.SendEmail import send_letter_email
# from application.CohereAI.GenerateBlog import generate_letter
user = Blueprint('user', __name__)
# USER PROFILE
@user.route('/dashboard/', methods=['GET', 'POST'])
@login_required
def dashboard():
if current_user.user_role == 'superadmin':
return redirect(url_for('superadmin.dashboard'))
# letter = generate_letter(gender='girlfriend')
form = LetterForm()
if form.validate_on_submit():
letter_link = linkid()
letter = Letter(
receiver_name=form.name.data.strip(),
email=form.email.data.strip(),
gender=form.gender.data,
message=form.letter.data.strip(),
link=letter_link,
is_hidden=form.is_hidden.data,
sender=current_user
)
db.session.add(letter)
db.session.commit()
send_letter_email(letter)
flash('Message generated', 'success')
return redirect(url_for('user.letter_sent'))
# if request.method == 'GET':
# form.letter.data = letter
return render_template(
'user/dashboard.html',
title='Dashboard',
form=form
)
# USER PROFILE
# @user.route('/dashboard/letter/regenerate/', methods=['GET', 'POST'])
# @login_required
# def regenerate_message():
# data = request.get_json()
# gender = data['gender']
# letter = generate_letter(gender)
# res = make_response(jsonify(letter), 200)
# return res
# USER LETTERS
@user.route('/dashboard/letter/sent/', methods=['GET', 'POST'])
@login_required
def letter_sent():
letter = Letter.query.order_by(Letter.created_at.desc()).first_or_404()
return render_template('user/letter_sent.html', letter=letter)
# USER PROFILE
@user.route('/dashboard/letters/', methods=['GET', 'POST'])
@login_required
def letters():
page = request.args.get('page', 1, type=int)
letters = Letter.query.order_by(Letter.created_at.desc()).paginate(page=page, per_page=10)
return render_template('user/letters.html', letters=letters)
# USER PROFILE
@user.route('/dashboard/account/', methods=['GET', 'POST'])
@login_required
def account():
form = UpdateProfileForm()
if form.validate_on_submit():
# if form.picture.data:
# picture_file = save_profile(form.picture.data)
# current_user.image_file = picture_file
current_user.name = form.name.data.strip()
current_user.phone = form.phone.data
current_user.email = form.email.data
db.session.commit()
flash('Your account has been updated!', 'success')
return redirect(url_for('user.dashboard'))
if request.method == 'GET':
form.name.data = current_user.name
form.email.data = current_user.email
form.phone.data = current_user.phone
# image_file = url_for('static', filename='profile/' + current_user.img)
return render_template('user/account.html', title='Profile', form=form)
# USER PROFILE
@user.route('/dashboard/account/password/', methods=['GET', 'POST'])
@login_required
def account_password():
form = UpdatePasswordForm()
if form.validate_on_submit():
# Get form data
new_password = form.new_password.data
confirm_new_password = form.confirm_password.data
current_password = form.current_password.data
# Check if current password is correct
current_password_hash = bcrypt.check_password_hash(current_user.password, current_password)
if current_password_hash and new_password == confirm_new_password:
# Hash and set new password
hashed_password = bcrypt.generate_password_hash(new_password).decode('utf-8')
current_user.password = hashed_password
db.session.commit()
elif current_password_hash and new_password != confirm_new_password:
flash('New Password and Confirm Password Doesn\'t Matched ⚠️', 'danger')
return redirect(url_for('dashboard.user_profile_edit'))
elif current_password and current_password_hash == False:
flash('Your current password is incorrect', 'danger')
return redirect(url_for('user.account_password'))
db.session.commit()
return redirect(url_for('user.dashboard'))
return render_template('user/account_update_password.html', title='Password', form=form)
================================================
FILE: application/utils/CutomAuth.py
================================================
from functools import wraps
from flask import abort
from flask_login import current_user
def superadmin_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not current_user.is_authenticated or current_user.user_role not in ["superadmin"]:
abort(404) # Or redirect to an unauthorized page
return f(*args, **kwargs)
return decorated_function
================================================
FILE: application/utils/Location.py
================================================
import requests
def getLocation(ip_address):
url = 'https://get.geojs.io/v1/ip/geo/'+ip_address+'.json'
geo_request = requests.get(url)
geo_data = geo_request.json()
return geo_data
================================================
FILE: application/utils/SendEmail.py
================================================
# importing necessary module
import os
import random
import string
from flask import url_for
from flask import render_template
from flask import current_app
from flask import request
from flask_mail import Message
from application import db
from application import bcrypt
from application import mail
from application.utils.Location import getLocation
# Create an email message with an activation link
# def send_activation_email(user):
# token = generate_otp()
# user.activation_token = bcrypt.generate_password_hash(token).decode('utf-8')
# db.session.commit()
# activation_link = url_for('auth.activate_account', token=user.activation_token, _external=True)
# msg = Message('Activate Your Account',
# sender=current_app.config['MAIL_DEFAULT_SENDER'],
# recipients=[user.email])
# msg.html = render_template('auth/activation_email.html', activation_link=activation_link)
# mail.send(msg)
# def send_activation_email(user):
# otp = generate_otp()
# print(f'====== GET THE OTP -> {otp}')
# token = bcrypt.generate_password_hash(otp).decode('utf-8')
# print(f'====== GET THE TOKEN -> {token}')
# user.activation_token = token
# print(f'====== GET THE user activation token -> {user.activation_token}')
# db.session.commit()
# activation_link = url_for('auth.activate_account', token=token, _external=True)
# msg = Message('Activate Your Account',
# sender=current_app.config['MAIL_DEFAULT_SENDER'],
# recipients=[user.email])
# msg.html = render_template('auth/activation_email.html', activation_link=activation_link)
# mail.send(msg)
# ===================================
# SEND ACCOUNT ACTIVATION EMAIL
# ===================================
# def send_activation_email(user):
# token = user.generate_activation_token()
# user.activation_token = token
# db.session.commit()
# activation_url = url_for('auth.activate', token=token, _external=True)
# msg = Message('Activate Your Account - Rabeya Baten Foundation',
# sender=current_app.config['MAIL_DEFAULT_SENDER'],
# recipients=[user.email])
# msg.html = render_template('auth/activation_link_email.html', activation_link=activation_url)
# mail.send(msg)
# ===================================
# SEND PASSWORD RESET EMAIL
# ===================================
def send_reset_email(user):
token = user.get_reset_token()
reset_link = url_for('auth.reset_token', token=token, _external=True)
msg = Message('Password Reset Request - Valentine',
sender=current_app.config['MAIL_DEFAULT_SENDER'],
recipients=[user.email])
msg.html = render_template('auth/password_reset_link_email.html', password_reset_link=reset_link)
mail.send(msg)
# ===================================
# SEND EMAIL TO RECEIVER
# ===================================
def send_letter_email(letter):
letter_link = url_for('public.letter', link=letter.link, _external=True)
msg = Message('💌 You received a letter to read - ValentineAI',
sender=current_app.config['MAIL_DEFAULT_SENDER'],
recipients=[letter.email])
msg.html = render_template('user/send_letter_email.html', letter_link=letter_link)
mail.send(msg)
================================================
FILE: application/utils/Utils.py
================================================
import os
import uuid
import secrets
import datetime
def applicationID():
now = datetime.datetime.now()
timestamp = now.strftime("%Y%m%d%H%M%S")
return timestamp + str(uuid.uuid4().int)[:10]
================================================
FILE: application/utils/__init__.py
================================================
================================================
FILE: requirements.txt
================================================
alembic==1.7.7
bcrypt==3.2.2
blinker==1.4
certifi==2022.5.18.1
cffi==1.15.0
charset-normalizer==2.0.12
click==8.0.1
colorama==0.4.4
cssbeautifier==1.14.7
dnspython==2.1.0
EditorConfig==0.12.3
email-validator==1.1.3
Faker==18.9.0
Flask==2.0.1
Flask-Admin==1.6.0
Flask-Bcrypt==0.7.1
Flask-CKEditor==0.4.6
Flask-Login==0.5.0
Flask-Mail==0.9.1
Flask-Migrate==3.1.0
Flask-Moment==1.0.5
Flask-SQLAlchemy==2.5.1
Flask-WTF==0.15.1
greenlet==1.1.1
html-tag-names==0.1.2
html-void-elements==0.1.0
idna==3.2
itsdangerous==2.0.1
Jinja2==3.0.1
jsbeautifier==1.14.7
Mako==1.2.0
MarkupSafe==2.0.1
mysqlclient==2.1.0
packaging==23.1
pathspec==0.11.1
Pillow==8.3.1
pycparser==2.20
python-dateutil==2.8.2
python-dotenv==0.21.1
python-slugify==8.0.1
PyYAML==6.0
regex==2023.5.5
requests==2.27.1
six==1.16.0
SQLAlchemy==1.4.23
text-unidecode==1.3
tomli==2.0.1
tqdm==4.65.0
urllib3==1.26.9
Werkzeug==2.0.1
WTForms==2.3.3
================================================
FILE: run.py
================================================
from application import create_app
app = create_app()
# production = False
production = True
if production is False:
if __name__ == '__main__':
app.run(debug=True)
else:
if __name__ == '__main__':
app.run()
gitextract_nl_bb119/ ├── .github/ │ └── workflows/ │ └── deploy.yml ├── .gitignore ├── application/ │ ├── CohereAI/ │ │ ├── GenerateBlog.py │ │ └── Utils.py │ ├── __init__.py │ ├── auth/ │ │ ├── __init__.py │ │ ├── forms.py │ │ └── views.py │ ├── config.py │ ├── models.py │ ├── public/ │ │ ├── __init__.py │ │ └── views.py │ ├── static/ │ │ └── assets/ │ │ ├── css/ │ │ │ └── custom.css │ │ ├── js/ │ │ │ ├── clock.js │ │ │ └── theme.js │ │ └── vendor/ │ │ └── prismjs/ │ │ ├── plugins/ │ │ │ ├── line-numbers/ │ │ │ │ └── prism-line-numbers.css │ │ │ └── toolbar/ │ │ │ └── prism-toolbar.css │ │ └── themes/ │ │ └── prism.css │ ├── superadmin/ │ │ ├── __init__.py │ │ ├── forms.py │ │ └── views.py │ ├── templates/ │ │ ├── auth/ │ │ │ ├── activation_link_email.html │ │ │ ├── forgetpassword.html │ │ │ ├── join.html │ │ │ ├── login.html │ │ │ ├── password_reset_link_email.html │ │ │ └── reset_token.html │ │ ├── helpers/ │ │ │ ├── _global_footer.html │ │ │ ├── _nav_top_landing.html │ │ │ └── _side_navbar_dashboard.html │ │ ├── layout/ │ │ │ └── root.html │ │ ├── public/ │ │ │ ├── landing.html │ │ │ └── letter.html │ │ └── user/ │ │ ├── account.html │ │ ├── account_update_password.html │ │ ├── dashboard.html │ │ ├── letter_sent.html │ │ ├── letters.html │ │ └── send_letter_email.html │ ├── user/ │ │ ├── __init__.py │ │ ├── forms.py │ │ └── views.py │ └── utils/ │ ├── CutomAuth.py │ ├── Location.py │ ├── SendEmail.py │ ├── Utils.py │ └── __init__.py ├── requirements.txt └── run.py
SYMBOL INDEX (58 symbols across 17 files)
FILE: application/CohereAI/GenerateBlog.py
function max_likely (line 11) | def max_likely(prediction):
function generate_letter (line 16) | def generate_letter(gender):
FILE: application/CohereAI/Utils.py
function linkid (line 3) | def linkid():
FILE: application/__init__.py
function create_app (line 22) | def create_app(config_class=Config):
FILE: application/auth/forms.py
class RegistrationForm (line 26) | class RegistrationForm(FlaskForm):
method validate_phone (line 66) | def validate_phone(self, phone):
method validate_email (line 71) | def validate_email(self, email):
class LoginForm (line 78) | class LoginForm(FlaskForm):
class UpdatePasswordForm (line 98) | class UpdatePasswordForm(FlaskForm):
class ForgetPasswordForm (line 118) | class ForgetPasswordForm(FlaskForm):
class ResetPasswordForm (line 130) | class ResetPasswordForm(FlaskForm):
FILE: application/auth/views.py
function join (line 71) | def join():
function activate (line 99) | def activate(token):
function login (line 116) | def login():
function logout (line 141) | def logout():
function user_resetpassword (line 150) | def user_resetpassword():
function forgetpassword (line 170) | def forgetpassword():
function reset_token (line 185) | def reset_token(token):
FILE: application/config.py
class Config (line 9) | class Config:
FILE: application/models.py
function load_user (line 18) | def load_user(user_id):
class User (line 21) | class User(db.Model, UserMixin):
method generate_activation_token (line 39) | def generate_activation_token(self, expires_sec=3600):
method get_reset_token (line 44) | def get_reset_token(self, expires_sec=1800):
method verify_reset_token (line 50) | def verify_reset_token(token):
method verify_activation_token (line 60) | def verify_activation_token(token):
class Letter (line 69) | class Letter(db.Model):
class Visitor (line 81) | class Visitor(db.Model):
FILE: application/public/views.py
function index (line 28) | def index():
function letter (line 53) | def letter(link):
FILE: application/static/assets/js/clock.js
function updateClock1 (line 1) | function updateClock1() {
function updateClock2 (line 18) | function updateClock2() {
FILE: application/static/assets/js/theme.js
function _typeof (line 1) | function _typeof(e) {
function ownKeys (line 16) | function ownKeys(t, e) {
function _objectSpread (line 30) | function _objectSpread(t) {
function _defineProperty (line 49) | function _defineProperty(e, t, r) {
function _toPropertyKey (line 62) | function _toPropertyKey(e) {
function _toPrimitive (line 66) | function _toPrimitive(e, t) {
function c (line 531) | function c(e) {
function u (line 548) | function u(e) {
function d (line 555) | function d() {
function p (line 558) | function p() {
function f (line 561) | function f() {
FILE: application/superadmin/views.py
function superadmin_dashboard (line 36) | def superadmin_dashboard():
FILE: application/user/forms.py
class LetterForm (line 29) | class LetterForm(FlaskForm):
class UpdateProfileForm (line 71) | class UpdateProfileForm(FlaskForm):
method validate_phone (line 113) | def validate_phone(self, phone):
method validate_email (line 119) | def validate_email(self, email):
class UpdatePasswordForm (line 127) | class UpdatePasswordForm(FlaskForm):
FILE: application/user/views.py
function dashboard (line 39) | def dashboard():
function letter_sent (line 93) | def letter_sent():
function letters (line 101) | def letters():
function account (line 110) | def account():
function account_password (line 134) | def account_password():
FILE: application/utils/CutomAuth.py
function superadmin_required (line 5) | def superadmin_required(f):
FILE: application/utils/Location.py
function getLocation (line 3) | def getLocation(ip_address):
FILE: application/utils/SendEmail.py
function send_reset_email (line 62) | def send_reset_email(user):
function send_letter_email (line 75) | def send_letter_email(letter):
FILE: application/utils/Utils.py
function applicationID (line 6) | def applicationID():
Condensed preview — 49 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (155K chars).
[
{
"path": ".github/workflows/deploy.yml",
"chars": 524,
"preview": "on:\n push:\n branches:\n - main\nname: 🚀 Deploy website on push\njobs:\n web-deploy:\n name: 🎉 "
},
{
"path": ".gitignore",
"chars": 3590,
"preview": "# Created by https://www.toptal.com/developers/gitignore/api/flask\n# Edit at https://www.toptal.com/developers/gitignore"
},
{
"path": "application/CohereAI/GenerateBlog.py",
"chars": 792,
"preview": "import os\nimport time\nimport cohere\nfrom dotenv import find_dotenv, load_dotenv\n\nload_dotenv(find_dotenv())\n\n# Cohere AI"
},
{
"path": "application/CohereAI/Utils.py",
"chars": 74,
"preview": "import uuid\n\ndef linkid():\n link = uuid.uuid4().hex[:8]\n return link"
},
{
"path": "application/__init__.py",
"chars": 1177,
"preview": "from flask import Flask\nfrom flask_sqlalchemy import SQLAlchemy\nfrom flask_bcrypt import Bcrypt\nfrom flask_login import "
},
{
"path": "application/auth/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "application/auth/forms.py",
"chars": 3454,
"preview": "from flask_wtf import FlaskForm\n\nfrom wtforms import StringField\nfrom wtforms import PasswordField\nfrom wtforms import I"
},
{
"path": "application/auth/views.py",
"chars": 7849,
"preview": "# importing basic flask module\nfrom flask import Blueprint\nfrom flask import redirect\nfrom flask import render_templat"
},
{
"path": "application/config.py",
"chars": 625,
"preview": "import os\nfrom dotenv import find_dotenv, load_dotenv\n\nload_dotenv(find_dotenv())\n\nproduction=True \n# production=False\n\n"
},
{
"path": "application/models.py",
"chars": 3304,
"preview": "import secrets\n# importing necessary module\nfrom datetime import datetime\nfrom flask import current_app\n\n# importin"
},
{
"path": "application/public/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "application/public/views.py",
"chars": 1407,
"preview": "# importing basic flask module\nfrom flask import Blueprint\nfrom flask import redirect\nfrom flask import render_templat"
},
{
"path": "application/static/assets/css/custom.css",
"chars": 897,
"preview": "/* ================ CLOCK ================ */\n.clock-container h4,\n.clock-container h5,\n.clock-container p {\n margin-"
},
{
"path": "application/static/assets/js/clock.js",
"chars": 918,
"preview": "function updateClock1() {\n\tlet date = new Date();\n\tlet nyWeekday = date.toLocaleString(\"en-US\", {\n\t\ttimeZone: \"America/N"
},
{
"path": "application/static/assets/js/theme.js",
"chars": 16973,
"preview": "function _typeof(e) {\n\treturn (_typeof =\n\t\t\"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator\n\t\t\t? functi"
},
{
"path": "application/static/assets/vendor/prismjs/plugins/line-numbers/prism-line-numbers.css",
"chars": 782,
"preview": "pre[class*=\"language-\"].line-numbers {\n\tposition: relative;\n\tpadding-left: 3.8em;\n\tcounter-reset: linenumber;\n}\n\npre[cla"
},
{
"path": "application/static/assets/vendor/prismjs/plugins/toolbar/prism-toolbar.css",
"chars": 1565,
"preview": "div.code-toolbar {\n\tposition: relative;\n}\n\ndiv.code-toolbar > .toolbar {\n\tposition: absolute;\n\tz-index: 10;\n\ttop: .3em;\n"
},
{
"path": "application/static/assets/vendor/prismjs/themes/prism.css",
"chars": 2335,
"preview": "/**\n * prism.js default theme for JavaScript, CSS and HTML\n * Based on dabblet (http://dabblet.com)\n * @author Lea Verou"
},
{
"path": "application/superadmin/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "application/superadmin/forms.py",
"chars": 849,
"preview": "from flask_wtf import FlaskForm\n\nfrom wtforms import StringField\nfrom wtforms import PasswordField\nfrom wtforms import I"
},
{
"path": "application/superadmin/views.py",
"chars": 1127,
"preview": "import os\nfrom datetime import datetime\n# importing basic flask module\nfrom flask import Blueprint\nfrom flask import r"
},
{
"path": "application/templates/auth/activation_link_email.html",
"chars": 3396,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE="
},
{
"path": "application/templates/auth/forgetpassword.html",
"chars": 2078,
"preview": "{% extends 'layout/root.html' %}\n\n{% block nav %}\n{% include 'helpers/_nav_top_landing.html' %}\n{% endblock %}\n\n{% block"
},
{
"path": "application/templates/auth/join.html",
"chars": 9654,
"preview": "{% extends 'layout/root.html' %}\n\n{% block nav %}\n{% include 'helpers/_nav_top_landing.html' %}\n{% endblock %}\n\n{% block"
},
{
"path": "application/templates/auth/login.html",
"chars": 5609,
"preview": "{% extends 'layout/root.html' %}\n\n{% block nav %}\n{% include 'helpers/_nav_top_landing.html' %}\n{% endblock %}\n\n{% block"
},
{
"path": "application/templates/auth/password_reset_link_email.html",
"chars": 2887,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"UTF-8\">\n\t\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\""
},
{
"path": "application/templates/auth/reset_token.html",
"chars": 5316,
"preview": "{% extends 'layout/root.html' %}\n\n{% block nav %}\n{% include 'helpers/_nav_top_landing.html' %}\n{% endblock %}\n\n{% block"
},
{
"path": "application/templates/helpers/_global_footer.html",
"chars": 3432,
"preview": "<!-- ============== START - FOOTER ============== -->\n<footer class=\"footer bg-dark pt-5 pb-4 pb-lg-5\">\n <div class=\""
},
{
"path": "application/templates/helpers/_nav_top_landing.html",
"chars": 1893,
"preview": "<header class=\"header navbar bg-light navbar-expand-lg position-absolute navbar-sticky shadow-sm navbar-stuck\">\n <na"
},
{
"path": "application/templates/helpers/_side_navbar_dashboard.html",
"chars": 2561,
"preview": "<aside class=\"col-lg-3 col-md-4 border-end pb-5 mt-n5\">\n <div class=\"position-sticky top-0\">\n <div class=\"text"
},
{
"path": "application/templates/layout/root.html",
"chars": 4409,
"preview": "<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<title>\n\t\t\t{% if title %}\n\t\t\t{{ title }} | Valentines Letter Sender\n\t\t\t{% else %}\n\t\t\tVa"
},
{
"path": "application/templates/public/landing.html",
"chars": 2026,
"preview": "{% extends 'layout/root.html' %}\n\n{% block nav %}\n{% include 'helpers/_nav_top_landing.html' %}\n{% endblock %}\n\n{% block"
},
{
"path": "application/templates/public/letter.html",
"chars": 5167,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"UTF-8\">\n\t\t<meta name=\"viewport\" content=\"width=device-width, i"
},
{
"path": "application/templates/user/account.html",
"chars": 6710,
"preview": "{% extends 'layout/root.html' %}\n\n{% block nav %}\n{% include 'helpers/_nav_top_landing.html' %}\n{% endblock %}\n\n{% block"
},
{
"path": "application/templates/user/account_update_password.html",
"chars": 6044,
"preview": "{% extends 'layout/root.html' %}\n\n{% block nav %}\n{% include 'helpers/_nav_top_landing.html' %}\n{% endblock %}\n\n{% block"
},
{
"path": "application/templates/user/dashboard.html",
"chars": 8105,
"preview": "{% extends 'layout/root.html' %}\n{% block nav %}\n {% include 'helpers/_nav_top_landing.html' %}\n{% endblock %}\n{% blo"
},
{
"path": "application/templates/user/letter_sent.html",
"chars": 1786,
"preview": "{% extends 'layout/root.html' %}\n{% block nav %}\n{% include 'helpers/_nav_top_landing.html' %}\n{% endblock %}\n{% block b"
},
{
"path": "application/templates/user/letters.html",
"chars": 4475,
"preview": "{% extends 'layout/root.html' %}\n{% block nav %}\n{% include 'helpers/_nav_top_landing.html' %}\n{% endblock %}\n{% block b"
},
{
"path": "application/templates/user/send_letter_email.html",
"chars": 2553,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"UTF-8\">\n\t\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\""
},
{
"path": "application/user/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "application/user/forms.py",
"chars": 3339,
"preview": "from flask_wtf import FlaskForm\n\nfrom wtforms import StringField\nfrom wtforms import PasswordField\nfrom wtforms import I"
},
{
"path": "application/user/views.py",
"chars": 5286,
"preview": "import os\n\n# importing basic flask module\nfrom flask import Blueprint\nfrom flask import redirect\nfrom flask import ren"
},
{
"path": "application/utils/CutomAuth.py",
"chars": 396,
"preview": "from functools import wraps\nfrom flask import abort\nfrom flask_login import current_user\n\ndef superadmin_required(f):\n "
},
{
"path": "application/utils/Location.py",
"chars": 200,
"preview": "import requests\n\ndef getLocation(ip_address):\n url = 'https://get.geojs.io/v1/ip/geo/'+ip_address+'.json'\n\n geo_re"
},
{
"path": "application/utils/SendEmail.py",
"chars": 3360,
"preview": "# importing necessary module\nimport os\nimport random\nimport string\nfrom flask import url_for\nfrom flask import render_"
},
{
"path": "application/utils/Utils.py",
"chars": 203,
"preview": "import os\nimport uuid\nimport secrets\nimport datetime\n\ndef applicationID():\n now = datetime.datetime.now()\n timesta"
},
{
"path": "application/utils/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "requirements.txt",
"chars": 899,
"preview": "alembic==1.7.7\nbcrypt==3.2.2\nblinker==1.4\ncertifi==2022.5.18.1\ncffi==1.15.0\ncharset-normalizer==2.0.12\nclick==8.0.1\ncolo"
},
{
"path": "run.py",
"chars": 233,
"preview": "from application import create_app\n\napp = create_app()\n\n# production = False\nproduction = True\n\nif production is False:\n"
}
]
About this extraction
This page contains the full source code of the mr-teslaa/valentine-ai GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 49 files (137.0 KB), approximately 33.0k tokens, and a symbol index with 58 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.