Disable initial email verification.
This commit is contained in:
27
app.py
27
app.py
@@ -397,13 +397,18 @@ def load_logged_in_user():
|
||||
else:
|
||||
g.company = None
|
||||
|
||||
# Check if user is verified
|
||||
if not g.user.is_verified and request.endpoint not in ['verify_email', 'static', 'logout', 'setup_company']:
|
||||
# Allow unverified users to access only verification and static resources
|
||||
if request.endpoint not in ['login', 'register']:
|
||||
flash('Please verify your email address before accessing this page.', 'warning')
|
||||
session.clear()
|
||||
return redirect(url_for('login'))
|
||||
# Check if user has email but not verified
|
||||
if g.user and not g.user.is_verified and g.user.email:
|
||||
# Add a flag for templates to show email verification nag
|
||||
g.show_email_verification_nag = True
|
||||
else:
|
||||
g.show_email_verification_nag = False
|
||||
|
||||
# Check if user has no email at all
|
||||
if g.user and not g.user.email:
|
||||
g.show_email_nag = True
|
||||
else:
|
||||
g.show_email_nag = False
|
||||
else:
|
||||
g.company = None
|
||||
|
||||
@@ -569,8 +574,6 @@ def register():
|
||||
error = None
|
||||
if not username:
|
||||
error = 'Username is required'
|
||||
elif not email:
|
||||
error = 'Email is required'
|
||||
elif not password:
|
||||
error = 'Password is required'
|
||||
elif password != confirm_password:
|
||||
@@ -596,7 +599,7 @@ def register():
|
||||
if company and not error:
|
||||
if User.query.filter_by(username=username, company_id=company.id).first():
|
||||
error = 'Username already exists in this company'
|
||||
elif User.query.filter_by(email=email, company_id=company.id).first():
|
||||
elif email and User.query.filter_by(email=email, company_id=company.id).first():
|
||||
error = 'Email already registered in this company'
|
||||
|
||||
if error is None and company:
|
||||
@@ -690,8 +693,6 @@ def register_freelancer():
|
||||
error = None
|
||||
if not username:
|
||||
error = 'Username is required'
|
||||
elif not email:
|
||||
error = 'Email is required'
|
||||
elif not password:
|
||||
error = 'Password is required'
|
||||
elif password != confirm_password:
|
||||
@@ -708,7 +709,7 @@ def register_freelancer():
|
||||
if not error:
|
||||
if User.query.filter_by(username=username).first():
|
||||
error = 'Username already exists'
|
||||
elif User.query.filter_by(email=email).first():
|
||||
elif email and User.query.filter_by(email=email).first():
|
||||
error = 'Email already registered'
|
||||
|
||||
if error is None:
|
||||
|
||||
@@ -129,7 +129,7 @@ class Project(db.Model):
|
||||
class User(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
username = db.Column(db.String(80), nullable=False)
|
||||
email = db.Column(db.String(120), nullable=False)
|
||||
email = db.Column(db.String(120), nullable=True)
|
||||
password_hash = db.Column(db.String(128))
|
||||
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
||||
|
||||
|
||||
@@ -608,6 +608,96 @@ footer {
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
|
||||
/* Email Nag Banner */
|
||||
.email-nag-banner {
|
||||
background-color: #e3f2fd;
|
||||
border-bottom: 2px solid #1976d2;
|
||||
padding: 0.75rem 1rem;
|
||||
position: relative;
|
||||
animation: slideDown 0.3s ease-out;
|
||||
}
|
||||
|
||||
.email-nag-banner.email-verify {
|
||||
background-color: #fff3cd;
|
||||
border-color: #ffc107;
|
||||
}
|
||||
|
||||
.email-nag-content {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.email-nag-icon {
|
||||
font-size: 1.5rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.email-nag-text {
|
||||
flex: 1;
|
||||
color: #333;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.email-nag-dismiss {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 1rem;
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 1.5rem;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.email-nag-dismiss:hover {
|
||||
background-color: rgba(0,0,0,0.1);
|
||||
color: #333;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
transform: translateY(-100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
transform: translateY(-100%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.email-nag-content {
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
.email-nag-text {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Full width footer when no user (no sidebar) */
|
||||
body:not(.has-user) footer {
|
||||
margin-left: 0;
|
||||
|
||||
@@ -206,6 +206,31 @@
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<!-- Email Nag Screens -->
|
||||
{% if g.show_email_nag %}
|
||||
<div class="email-nag-banner">
|
||||
<div class="email-nag-content">
|
||||
<span class="email-nag-icon">📧</span>
|
||||
<span class="email-nag-text">
|
||||
<strong>Add your email address</strong> to enable account recovery and receive important notifications.
|
||||
</span>
|
||||
<a href="{{ url_for('profile') }}" class="btn btn-sm btn-primary">Add Email</a>
|
||||
<button class="email-nag-dismiss" onclick="dismissEmailNag()" title="Dismiss for this session">×</button>
|
||||
</div>
|
||||
</div>
|
||||
{% elif g.show_email_verification_nag %}
|
||||
<div class="email-nag-banner email-verify">
|
||||
<div class="email-nag-content">
|
||||
<span class="email-nag-icon">✉️</span>
|
||||
<span class="email-nag-text">
|
||||
<strong>Please verify your email address</strong> to ensure you can recover your account if needed.
|
||||
</span>
|
||||
<a href="{{ url_for('profile') }}" class="btn btn-sm btn-warning">Verify Email</a>
|
||||
<button class="email-nag-dismiss" onclick="dismissEmailNag()" title="Dismiss for this session">×</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
@@ -229,6 +254,28 @@
|
||||
<script src="{{ url_for('static', filename='js/password-strength.js') }}"></script>
|
||||
{% if g.user %}
|
||||
<script src="{{ url_for('static', filename='js/user-dropdown.js') }}"></script>
|
||||
<script>
|
||||
function dismissEmailNag() {
|
||||
// Hide the banner with animation
|
||||
const banner = document.querySelector('.email-nag-banner');
|
||||
if (banner) {
|
||||
banner.style.animation = 'slideUp 0.3s ease-out';
|
||||
setTimeout(() => {
|
||||
banner.style.display = 'none';
|
||||
}, 300);
|
||||
}
|
||||
// Store in session storage to not show again this session
|
||||
sessionStorage.setItem('emailNagDismissed', 'true');
|
||||
}
|
||||
|
||||
// Check if already dismissed this session
|
||||
if (sessionStorage.getItem('emailNagDismissed') === 'true') {
|
||||
const banner = document.querySelector('.email-nag-banner');
|
||||
if (banner) {
|
||||
banner.style.display = 'none';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% else %}
|
||||
<script src="{{ url_for('static', filename='js/splash.js') }}"></script>
|
||||
{% endif %}
|
||||
|
||||
@@ -93,7 +93,16 @@
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">Email</span>
|
||||
<span class="info-value">{{ user.email }}</span>
|
||||
<span class="info-value">
|
||||
{% if user.email %}
|
||||
{{ user.email }}
|
||||
{% if not user.is_verified %}
|
||||
<span class="badge badge-warning">Unverified</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="text-muted">Not provided</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">Role</span>
|
||||
@@ -120,10 +129,20 @@
|
||||
<form method="POST" action="{{ url_for('profile') }}" class="profile-form">
|
||||
<div class="form-group">
|
||||
<label for="email">Email Address</label>
|
||||
<input type="email" id="email" name="email" class="form-control" value="{{ user.email }}" required>
|
||||
<small>This email address is used for account verification and notifications.</small>
|
||||
<input type="email" id="email" name="email" class="form-control" value="{{ user.email or '' }}" placeholder="your@email.com">
|
||||
<small>This email address is used for account recovery and notifications.</small>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Update Email</button>
|
||||
{% if user.email and not user.is_verified %}
|
||||
<div class="alert alert-warning">
|
||||
<i>⚠️</i> Your email address is not verified.
|
||||
<a href="{{ url_for('profile') }}" class="btn btn-sm btn-warning">Send Verification Email</a>
|
||||
</div>
|
||||
{% elif not user.email %}
|
||||
<div class="alert alert-info">
|
||||
<i>ℹ️</i> Adding an email address enables account recovery and important notifications.
|
||||
</div>
|
||||
{% endif %}
|
||||
<button type="submit" class="btn btn-primary">{% if user.email %}Update{% else %}Add{% endif %} Email</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -132,7 +151,7 @@
|
||||
<h3>Change Password</h3>
|
||||
<form method="POST" action="{{ url_for('profile') }}" class="password-form">
|
||||
<!-- Hidden email field to maintain current email -->
|
||||
<input type="hidden" name="email" value="{{ user.email }}">
|
||||
<input type="hidden" name="email" value="{{ user.email or '' }}">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="current_password">Current Password</label>
|
||||
|
||||
@@ -47,9 +47,9 @@
|
||||
|
||||
<div class="form-group input-icon">
|
||||
<i>📧</i>
|
||||
<input type="email" id="email" name="email" class="form-control" placeholder="your@email.com" required>
|
||||
<label for="email">Email Address</label>
|
||||
<small class="form-text text-muted">We'll send a verification link to this address</small>
|
||||
<input type="email" id="email" name="email" class="form-control" placeholder="your@email.com (optional)">
|
||||
<label for="email">Email Address (Optional)</label>
|
||||
<small class="form-text text-muted">Recommended for account recovery and notifications</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group input-icon">
|
||||
@@ -80,7 +80,7 @@
|
||||
</div>
|
||||
|
||||
<div class="verification-notice">
|
||||
<p>📨 After registration, you'll need to verify your email address before you can log in.</p>
|
||||
<p>💡 You can register without an email, but we recommend adding one later for account recovery.</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -47,8 +47,9 @@
|
||||
|
||||
<div class="form-group input-icon">
|
||||
<i>📧</i>
|
||||
<input type="email" id="email" name="email" class="form-control" placeholder="your@email.com" required>
|
||||
<label for="email">Email Address</label>
|
||||
<input type="email" id="email" name="email" class="form-control" placeholder="your@email.com (optional)">
|
||||
<label for="email">Email Address (Optional)</label>
|
||||
<small class="form-text text-muted">Recommended for account recovery</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group input-icon">
|
||||
|
||||
Reference in New Issue
Block a user