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',
|
'welcome': 'Welcome to NetEvents',
|
||||||
'connect_with_professionals': 'Connect with professionals at networking events',
|
'connect_with_professionals': 'Connect with professionals at networking events',
|
||||||
'register_as_organizer': 'Register as Organizer',
|
'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',
|
'presenter': 'Presenter',
|
||||||
'visitor': 'Visitor',
|
'visitor': 'Visitor',
|
||||||
'organiser': 'Organiser',
|
'organiser': 'Organiser',
|
||||||
@@ -608,14 +621,14 @@ def generate_staff_code():
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def generate_type_code():
|
def generate_type_code(event_id):
|
||||||
"""Generate a unique 10-character alphanumeric attendee type code."""
|
"""Generate a unique 10-character alphanumeric attendee type code for an event."""
|
||||||
chars = string.ascii_uppercase + string.digits
|
chars = string.ascii_uppercase + string.digits
|
||||||
while True:
|
while True:
|
||||||
code = ''.join(random.choices(chars, k=10))
|
code = ''.join(random.choices(chars, k=10))
|
||||||
conn = get_db_connection()
|
conn = get_db_connection()
|
||||||
cursor = conn.cursor()
|
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():
|
if not cursor.fetchone():
|
||||||
cursor.close()
|
cursor.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
@@ -2644,7 +2657,7 @@ def manage_attendee_types(event_id):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
price_value = 0.00
|
price_value = 0.00
|
||||||
|
|
||||||
type_code = generate_type_code()
|
type_code = generate_type_code(event_id)
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
INSERT INTO attendee_types (event_id, code, name, price)
|
INSERT INTO attendee_types (event_id, code, name, price)
|
||||||
VALUES (%s, %s, %s, %s)
|
VALUES (%s, %s, %s, %s)
|
||||||
@@ -3820,9 +3833,9 @@ def attendee_profile():
|
|||||||
conn = get_db_connection()
|
conn = get_db_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("""
|
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
|
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()
|
conn.commit()
|
||||||
cursor.close()
|
cursor.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
@@ -4521,6 +4534,60 @@ def payment_page(code):
|
|||||||
return render_template('attendee/payment.html', event=event, pending=pending)
|
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>')
|
@app.route('/attendee/personal/<token>')
|
||||||
def attendee_personal_page(token):
|
def attendee_personal_page(token):
|
||||||
"""Personal page accessed via confirmation email link."""
|
"""Personal page accessed via confirmation email link."""
|
||||||
|
|||||||
+3
-2
@@ -189,11 +189,12 @@ def create_tables():
|
|||||||
CREATE TABLE IF NOT EXISTS attendee_types (
|
CREATE TABLE IF NOT EXISTS attendee_types (
|
||||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
event_id INT NOT NULL,
|
event_id INT NOT NULL,
|
||||||
code VARCHAR(10) UNIQUE NOT NULL,
|
code VARCHAR(10) NOT NULL,
|
||||||
name VARCHAR(100) NOT NULL,
|
name VARCHAR(100) NOT NULL,
|
||||||
price DECIMAL(10,2) DEFAULT 0.00,
|
price DECIMAL(10,2) DEFAULT 0.00,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
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 |
|
| id | INT | PRIMARY KEY AUTO_INCREMENT |
|
||||||
| event_id | INT | NOT NULL, FOREIGN KEY → events(id) |
|
| 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 |
|
| name | VARCHAR(100) | NOT NULL |
|
||||||
| price | DECIMAL(10,2) | DEFAULT 0.00 |
|
| price | DECIMAL(10,2) | DEFAULT 0.00 |
|
||||||
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP |
|
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP |
|
||||||
|
| | | UNIQUE KEY (event_id, code) per event |
|
||||||
|
|
||||||
## 4. User Types & Roles
|
## 4. User Types & Roles
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user