Fix attendee_types.code uniqueness: per-event not global
Also update generate_type_code() to accept event_id parameter for proper per-event uniqueness checking. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -176,7 +176,20 @@ ENGLISH_TRANSLATIONS = {
|
||||
'welcome': 'Welcome to NetEvents',
|
||||
'connect_with_professionals': 'Connect with professionals at networking events',
|
||||
'register_as_organizer': 'Register as Organizer',
|
||||
'already_have_account': 'Already have an account? Login as:',
|
||||
'already_have_account': 'Already have an account?',
|
||||
'dont_have_account': "Don't have an account?",
|
||||
'click_here': 'Click here',
|
||||
'login_as_organiser': 'login as organiser',
|
||||
'attendee_profile_link': 'Are you an attendee and want to check your personal profile page?',
|
||||
'attendee_profile_url': '/attendee/personal/',
|
||||
'request_profile_link': 'Request Your Personal Page Link',
|
||||
'request_link_description': 'Enter your email address and we will send you a link to access your personal attendee profile page.',
|
||||
'send_link': 'Send Link',
|
||||
'email_sent': 'If that email is registered, we have sent the link.',
|
||||
'email_not_found': 'No attendee found with that email address.',
|
||||
'remember_password': 'Remember your password?',
|
||||
'not_yet_registered': 'Not yet registered?',
|
||||
'register_for_free': 'Register for FREE!',
|
||||
'presenter': 'Presenter',
|
||||
'visitor': 'Visitor',
|
||||
'organiser': 'Organiser',
|
||||
@@ -608,14 +621,14 @@ def generate_staff_code():
|
||||
conn.close()
|
||||
|
||||
|
||||
def generate_type_code():
|
||||
"""Generate a unique 10-character alphanumeric attendee type code."""
|
||||
def generate_type_code(event_id):
|
||||
"""Generate a unique 10-character alphanumeric attendee type code for an event."""
|
||||
chars = string.ascii_uppercase + string.digits
|
||||
while True:
|
||||
code = ''.join(random.choices(chars, k=10))
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT id FROM attendee_types WHERE code = %s", (code,))
|
||||
cursor.execute("SELECT id FROM attendee_types WHERE event_id = %s AND code = %s", (event_id, code))
|
||||
if not cursor.fetchone():
|
||||
cursor.close()
|
||||
conn.close()
|
||||
@@ -2644,7 +2657,7 @@ def manage_attendee_types(event_id):
|
||||
except ValueError:
|
||||
price_value = 0.00
|
||||
|
||||
type_code = generate_type_code()
|
||||
type_code = generate_type_code(event_id)
|
||||
cursor.execute("""
|
||||
INSERT INTO attendee_types (event_id, code, name, price)
|
||||
VALUES (%s, %s, %s, %s)
|
||||
@@ -3820,9 +3833,9 @@ def attendee_profile():
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("""
|
||||
UPDATE attendees SET first_name = %s, last_name = %s, organisation = %s, role = %s, introduction = %s
|
||||
UPDATE attendees SET first_name = %s, last_name = %s, organisation = %s, role = %s, introduction = %s, phone = %s, linkedin = %s
|
||||
WHERE id = %s
|
||||
""", (first_name, last_name, organisation, role, introduction, session['user_id']))
|
||||
""", (first_name, last_name, organisation, role, introduction, request.form.get('phone', '').strip(), request.form.get('linkedin', '').strip(), session['user_id']))
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
@@ -4521,6 +4534,60 @@ def payment_page(code):
|
||||
return render_template('attendee/payment.html', event=event, pending=pending)
|
||||
|
||||
|
||||
@app.route('/attendee/request-link', methods=['GET', 'POST'])
|
||||
def request_attendee_link():
|
||||
"""Page to request a personal page link by email."""
|
||||
if request.method == 'POST':
|
||||
email = request.form.get('email', '').strip()
|
||||
|
||||
if not email:
|
||||
flash('Email is required.')
|
||||
return render_template('attendee/request_link.html')
|
||||
|
||||
try:
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
# Check if attendee exists with this email
|
||||
cursor.execute("SELECT * FROM attendees WHERE email = %s", (email,))
|
||||
attendee = cursor.fetchone()
|
||||
|
||||
if attendee:
|
||||
# Use confirmation_token if available, otherwise attendee_code
|
||||
token = attendee['confirmation_token'] if attendee['confirmation_token'] else attendee['attendee_code']
|
||||
personal_page_url = url_for('attendee_personal_page', token=token, _external=True)
|
||||
|
||||
full_name = f"{attendee['first_name']} {attendee['last_name']}"
|
||||
|
||||
# Get event name
|
||||
cursor.execute("SELECT name FROM events WHERE id = %s", (attendee['event_id'],))
|
||||
event = cursor.fetchone()
|
||||
event_name = event['name'] if event else 'Event'
|
||||
|
||||
# Send email
|
||||
send_attendee_confirmation_email(
|
||||
attendee_email=email,
|
||||
attendee_name=full_name,
|
||||
event_name=event_name,
|
||||
event_date='See your profile',
|
||||
event_location='See your profile',
|
||||
personal_page_url=personal_page_url
|
||||
)
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
# Always show success message for security (don't reveal if email exists)
|
||||
flash(t('email_sent'))
|
||||
return render_template('attendee/request_link.html')
|
||||
|
||||
except Exception as e:
|
||||
flash(f'Error: {e}')
|
||||
return render_template('attendee/request_link.html')
|
||||
|
||||
return render_template('attendee/request_link.html')
|
||||
|
||||
|
||||
@app.route('/attendee/personal/<token>')
|
||||
def attendee_personal_page(token):
|
||||
"""Personal page accessed via confirmation email link."""
|
||||
|
||||
+3
-2
@@ -189,11 +189,12 @@ def create_tables():
|
||||
CREATE TABLE IF NOT EXISTS attendee_types (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
event_id INT NOT NULL,
|
||||
code VARCHAR(10) UNIQUE NOT NULL,
|
||||
code VARCHAR(10) NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
price DECIMAL(10,2) DEFAULT 0.00,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE
|
||||
FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE,
|
||||
UNIQUE KEY unique_type_code_per_event (event_id, code)
|
||||
)
|
||||
"""
|
||||
]
|
||||
|
||||
@@ -156,10 +156,11 @@
|
||||
|--------|------|-------------|
|
||||
| id | INT | PRIMARY KEY AUTO_INCREMENT |
|
||||
| event_id | INT | NOT NULL, FOREIGN KEY → events(id) |
|
||||
| code | VARCHAR(10) | UNIQUE NOT NULL |
|
||||
| code | VARCHAR(10) | NOT NULL |
|
||||
| name | VARCHAR(100) | NOT NULL |
|
||||
| price | DECIMAL(10,2) | DEFAULT 0.00 |
|
||||
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP |
|
||||
| | | UNIQUE KEY (event_id, code) per event |
|
||||
|
||||
## 4. User Types & Roles
|
||||
|
||||
|
||||
Reference in New Issue
Block a user