diff --git a/app.py b/app.py index 5d6f525..593c773 100644 --- a/app.py +++ b/app.py @@ -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/') def attendee_personal_page(token): """Personal page accessed via confirmation email link.""" diff --git a/init_db.py b/init_db.py index 2621f4a..718f3aa 100644 --- a/init_db.py +++ b/init_db.py @@ -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) ) """ ] diff --git a/spec.md b/spec.md index 57046f9..daf809b 100644 --- a/spec.md +++ b/spec.md @@ -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