updates
This commit is contained in:
2
Backend/seeders/__init__.py
Normal file
2
Backend/seeders/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# Seeders package
|
||||
|
||||
BIN
Backend/seeders/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
Backend/seeders/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
Backend/seeders/__pycache__/banner_seeder.cpython-312.pyc
Normal file
BIN
Backend/seeders/__pycache__/banner_seeder.cpython-312.pyc
Normal file
Binary file not shown.
BIN
Backend/seeders/__pycache__/homepage_seeder.cpython-312.pyc
Normal file
BIN
Backend/seeders/__pycache__/homepage_seeder.cpython-312.pyc
Normal file
Binary file not shown.
BIN
Backend/seeders/__pycache__/user_seeder.cpython-312.pyc
Normal file
BIN
Backend/seeders/__pycache__/user_seeder.cpython-312.pyc
Normal file
Binary file not shown.
318
Backend/seeders/about_seeder.py
Normal file
318
Backend/seeders/about_seeder.py
Normal file
@@ -0,0 +1,318 @@
|
||||
"""
|
||||
About Page Seeder
|
||||
Seeds the database with comprehensive about page content
|
||||
All images are from Unsplash (free stock photos)
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
|
||||
# Add parent directory to path to allow importing from src
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal
|
||||
from src.shared.config.logging_config import get_logger
|
||||
from src.content.models.page_content import PageContent, PageType
|
||||
|
||||
# Import all models to ensure relationships are loaded
|
||||
from src.models import *
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_about_page_data():
|
||||
"""Generate comprehensive about page data with Unsplash images"""
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
return {
|
||||
'page_type': PageType.ABOUT,
|
||||
'title': 'About Our Hotel',
|
||||
'subtitle': 'A Legacy of Luxury and Exceptional Service',
|
||||
'description': 'Discover our rich heritage spanning three decades. We have been crafting exceptional experiences for discerning travelers worldwide, blending timeless elegance with modern amenities.',
|
||||
'content': '<p>For over three decades, we have been at the forefront of luxury hospitality, creating unforgettable experiences for our guests. Our commitment to excellence, attention to detail, and passion for service has made us a destination of choice for travelers seeking the finest in accommodation, dining, and personalized service.</p>',
|
||||
'meta_title': 'About Us | Luxury Hotel & Resort - Our Story, Mission & Vision',
|
||||
'meta_description': 'Learn about our luxury hotel\'s rich heritage, mission, vision, and commitment to exceptional hospitality. Discover our story spanning three decades of excellence.',
|
||||
'meta_keywords': 'about us, hotel history, luxury hospitality, hotel mission, hotel vision, hotel story, luxury hotel',
|
||||
'og_title': 'About Our Luxury Hotel - A Legacy of Excellence',
|
||||
'og_description': 'Discover our rich heritage spanning three decades. We have been crafting exceptional experiences for discerning travelers worldwide.',
|
||||
'og_image': 'https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?w=1200&h=630&fit=crop',
|
||||
'canonical_url': 'https://luxuryhotel.com/about',
|
||||
'hero_title': 'Our Story',
|
||||
'hero_subtitle': 'Three Decades of Excellence in Luxury Hospitality',
|
||||
'hero_image': 'https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?w=1920&h=1080&fit=crop',
|
||||
'hero_video_url': None,
|
||||
'hero_video_poster': None,
|
||||
'about_hero_image': 'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1400&h=900&fit=crop',
|
||||
'story_content': '<p>Founded in 1993, our hotel began as a vision to create a sanctuary of luxury and sophistication in the heart of the city. What started as a small boutique property has grown into an internationally recognized destination, consistently ranked among the world\'s finest hotels.</p><p>Over the years, we have welcomed countless guests, from world leaders and celebrities to families celebrating special moments. Each guest has contributed to our story, and we are honored to have been part of their journeys.</p><p>Our commitment to excellence has never wavered. We continuously invest in our facilities, train our staff to the highest standards, and innovate to exceed expectations. Today, we stand as a testament to what is possible when passion meets dedication.</p>',
|
||||
'mission': '<p>Our mission is to provide unparalleled luxury experiences that exceed expectations. We are committed to creating memorable moments for every guest through exceptional service, world-class amenities, and attention to every detail. We strive to be the benchmark of excellence in hospitality, where every interaction reflects our dedication to perfection.</p>',
|
||||
'vision': '<p>Our vision is to be the world\'s most respected luxury hotel brand, recognized for our unwavering commitment to excellence, innovation, and sustainable luxury. We envision a future where our guests feel truly at home, where our team members are proud ambassadors of our values, and where our community benefits from our presence and commitment to responsible hospitality.</p>',
|
||||
'values': json.dumps([
|
||||
{
|
||||
'icon': 'heart',
|
||||
'title': 'Excellence',
|
||||
'description': 'We strive for perfection in every detail, ensuring your experience exceeds expectations. Excellence is not a goal but a standard we maintain in everything we do.'
|
||||
},
|
||||
{
|
||||
'icon': 'users',
|
||||
'title': 'Hospitality',
|
||||
'description': 'Our dedicated team provides warm, personalized service to make you feel at home. We believe true hospitality comes from the heart and is reflected in every interaction.'
|
||||
},
|
||||
{
|
||||
'icon': 'leaf',
|
||||
'title': 'Sustainability',
|
||||
'description': 'Committed to eco-friendly practices for a better future and a delightful stay. We balance luxury with responsibility, ensuring our operations protect the environment for future generations.'
|
||||
},
|
||||
{
|
||||
'icon': 'award',
|
||||
'title': 'Quality',
|
||||
'description': 'We maintain the highest standards in service, amenities, and guest satisfaction. Quality is embedded in our culture and evident in every aspect of your stay.'
|
||||
},
|
||||
{
|
||||
'icon': 'handshake',
|
||||
'title': 'Integrity',
|
||||
'description': 'We conduct our business with honesty, transparency, and ethical practices. Trust is the foundation of our relationships with guests, partners, and our community.'
|
||||
},
|
||||
{
|
||||
'icon': 'lightbulb',
|
||||
'title': 'Innovation',
|
||||
'description': 'We embrace new technologies and creative solutions to enhance your experience. Innovation drives us to continuously improve and stay ahead of industry trends.'
|
||||
}
|
||||
]),
|
||||
'team': json.dumps([
|
||||
{
|
||||
'name': 'Sarah Johnson',
|
||||
'position': 'General Manager',
|
||||
'bio': 'With over 20 years of experience in luxury hospitality, Sarah leads our team with passion and dedication. Her commitment to excellence has been instrumental in our success.',
|
||||
'image': 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=400&h=400&fit=crop&crop=face',
|
||||
'social': {
|
||||
'linkedin': 'https://linkedin.com/in/sarahjohnson',
|
||||
'twitter': 'https://twitter.com/sarahjohnson'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Michael Chen',
|
||||
'position': 'Executive Chef',
|
||||
'bio': 'Award-winning chef with a passion for creating culinary masterpieces. Michael brings innovative flavors and techniques to our restaurants, delighting guests with every dish.',
|
||||
'image': 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400&h=400&fit=crop&crop=face',
|
||||
'social': {
|
||||
'linkedin': 'https://linkedin.com/in/michaelchen',
|
||||
'instagram': 'https://instagram.com/chefmichael'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Emily Rodriguez',
|
||||
'position': 'Director of Guest Services',
|
||||
'bio': 'Emily ensures every guest receives personalized attention and exceptional service. Her warm personality and attention to detail make her a favorite among our guests.',
|
||||
'image': 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=400&h=400&fit=crop&crop=face',
|
||||
'social': {
|
||||
'linkedin': 'https://linkedin.com/in/emilyrodriguez'
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'David Thompson',
|
||||
'position': 'Spa Director',
|
||||
'bio': 'With expertise in wellness and holistic healing, David has created a world-class spa experience. His innovative treatments and serene environment provide guests with ultimate relaxation.',
|
||||
'image': 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=400&h=400&fit=crop&crop=face',
|
||||
'social': {
|
||||
'linkedin': 'https://linkedin.com/in/davidthompson'
|
||||
}
|
||||
}
|
||||
]),
|
||||
'timeline': json.dumps([
|
||||
{
|
||||
'year': '1993',
|
||||
'title': 'Foundation',
|
||||
'description': 'Hotel founded with a vision to create a luxury destination. Opened with 50 rooms and a commitment to exceptional service.',
|
||||
'image': 'https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?w=800&h=600&fit=crop'
|
||||
},
|
||||
{
|
||||
'year': '2000',
|
||||
'title': 'First Expansion',
|
||||
'description': 'Expanded to 150 rooms and added our first fine dining restaurant. Received our first five-star rating from international travel guides.',
|
||||
'image': 'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=800&h=600&fit=crop'
|
||||
},
|
||||
{
|
||||
'year': '2008',
|
||||
'title': 'Spa & Wellness Center',
|
||||
'description': 'Opened our world-class spa and wellness center, introducing holistic wellness programs and luxury treatments.',
|
||||
'image': 'https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=800&h=600&fit=crop'
|
||||
},
|
||||
{
|
||||
'year': '2015',
|
||||
'title': 'Major Renovation',
|
||||
'description': 'Completed a comprehensive renovation, modernizing all rooms and public spaces while preserving our classic elegance.',
|
||||
'image': 'https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=800&h=600&fit=crop'
|
||||
},
|
||||
{
|
||||
'year': '2020',
|
||||
'title': 'Sustainability Initiative',
|
||||
'description': 'Launched our comprehensive sustainability program, achieving carbon neutrality and implementing eco-friendly practices throughout the property.',
|
||||
'image': 'https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=800&h=600&fit=crop'
|
||||
},
|
||||
{
|
||||
'year': '2023',
|
||||
'title': 'Award Recognition',
|
||||
'description': 'Received "Best Luxury Hotel" award and maintained our five-star rating. Celebrated 30 years of excellence in hospitality.',
|
||||
'image': 'https://images.unsplash.com/photo-1579621970563-ebec7560ff3e?w=800&h=600&fit=crop'
|
||||
}
|
||||
]),
|
||||
'achievements': json.dumps([
|
||||
{
|
||||
'icon': 'trophy',
|
||||
'title': 'Best Luxury Hotel 2023',
|
||||
'description': 'Awarded by International Hospitality Association',
|
||||
'year': '2023',
|
||||
'image': 'https://images.unsplash.com/photo-1579621970563-ebec7560ff3e?w=400&h=400&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'star',
|
||||
'title': 'Five-Star Rating',
|
||||
'description': 'Consistently rated five-star by global travel guides',
|
||||
'year': '2020-2023',
|
||||
'image': 'https://images.unsplash.com/photo-1579621970563-ebec7560ff3e?w=400&h=400&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'medal',
|
||||
'title': 'Excellence in Service',
|
||||
'description': 'Recognized for outstanding customer service and guest satisfaction',
|
||||
'year': '2022',
|
||||
'image': 'https://images.unsplash.com/photo-1579621970563-ebec7560ff3e?w=400&h=400&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'leaf',
|
||||
'title': 'Green Hotel Certification',
|
||||
'description': 'Certified for sustainable practices and environmental responsibility',
|
||||
'year': '2021',
|
||||
'image': 'https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=400&h=400&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'users',
|
||||
'title': 'Guest Choice Award',
|
||||
'description': 'Voted favorite luxury hotel by guests worldwide',
|
||||
'year': '2023',
|
||||
'image': 'https://images.unsplash.com/photo-1579621970563-ebec7560ff3e?w=400&h=400&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'award',
|
||||
'title': 'Culinary Excellence',
|
||||
'description': 'Restaurant awarded Michelin star for exceptional cuisine',
|
||||
'year': '2022',
|
||||
'image': 'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=400&h=400&fit=crop'
|
||||
}
|
||||
]),
|
||||
'stats': json.dumps([
|
||||
{'number': '50000+', 'label': 'Happy Guests', 'icon': 'users'},
|
||||
{'number': '30+', 'label': 'Years of Excellence', 'icon': 'calendar'},
|
||||
{'number': '150+', 'label': 'Awards Won', 'icon': 'award'},
|
||||
{'number': '98%', 'label': 'Guest Satisfaction', 'icon': 'star'},
|
||||
{'number': '200+', 'label': 'Team Members', 'icon': 'users'},
|
||||
{'number': '115', 'label': 'Luxury Rooms', 'icon': 'home'}
|
||||
]),
|
||||
'stats_section_title': 'Our Achievements in Numbers',
|
||||
'stats_section_subtitle': 'A legacy built on excellence and guest satisfaction',
|
||||
'testimonials': json.dumps([
|
||||
{
|
||||
'name': 'James Wilson',
|
||||
'title': 'VIP Guest',
|
||||
'quote': 'The level of luxury and attention to detail is simply extraordinary. This hotel understands what true hospitality means.',
|
||||
'rating': 5,
|
||||
'image': 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=200&h=200&fit=crop&crop=face'
|
||||
},
|
||||
{
|
||||
'name': 'Sophia Lee',
|
||||
'title': 'Travel Blogger',
|
||||
'quote': 'Every aspect of my stay was flawless. The service, the amenities, the ambiance - truly a five-star experience.',
|
||||
'rating': 5,
|
||||
'image': 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=200&h=200&fit=crop&crop=face'
|
||||
},
|
||||
{
|
||||
'name': 'David Chen',
|
||||
'title': 'CEO, Global Corp',
|
||||
'quote': 'An impeccable hotel with outstanding service. This is what luxury hospitality should be - perfect in every way.',
|
||||
'rating': 5,
|
||||
'image': 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=200&h=200&fit=crop&crop=face'
|
||||
},
|
||||
{
|
||||
'name': 'Maria Garcia',
|
||||
'title': 'Frequent Guest',
|
||||
'quote': 'I\'ve stayed at many luxury hotels, but this one stands out. The personal attention and genuine care for guests is remarkable.',
|
||||
'rating': 5,
|
||||
'image': 'https://images.unsplash.com/photo-1544005313-94ddf0286df2?w=200&h=200&fit=crop&crop=face'
|
||||
}
|
||||
]),
|
||||
'testimonials_section_title': 'What Our Guests Say',
|
||||
'testimonials_section_subtitle': 'Stories from our valued guests',
|
||||
'gallery_images': json.dumps([
|
||||
'https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=1200&h=800&fit=crop'
|
||||
]),
|
||||
'gallery_section_title': 'Our Photo Gallery',
|
||||
'gallery_section_subtitle': 'A glimpse into our world of luxury',
|
||||
'contact_info': json.dumps({
|
||||
'phone': '+1 (555) 123-4567',
|
||||
'email': 'info@luxuryhotel.com',
|
||||
'address': '123 Luxury Avenue, Premium City, PC 12345'
|
||||
}),
|
||||
'social_links': json.dumps({
|
||||
'facebook': 'https://facebook.com/luxuryhotel',
|
||||
'twitter': 'https://twitter.com/luxuryhotel',
|
||||
'instagram': 'https://instagram.com/luxuryhotel',
|
||||
'linkedin': 'https://linkedin.com/company/luxuryhotel',
|
||||
'youtube': 'https://youtube.com/luxuryhotel'
|
||||
}),
|
||||
'is_active': True,
|
||||
'created_at': now,
|
||||
'updated_at': now
|
||||
}
|
||||
|
||||
|
||||
def seed_about_page(db: Session):
|
||||
"""Seed about page content into the database"""
|
||||
try:
|
||||
about_data = get_about_page_data()
|
||||
|
||||
# Check if about page content already exists
|
||||
existing_content = db.query(PageContent).filter(PageContent.page_type == PageType.ABOUT).first()
|
||||
|
||||
if existing_content:
|
||||
logger.info('Updating existing about page content...')
|
||||
for key, value in about_data.items():
|
||||
if key not in ['id', 'page_type', 'created_at']: # Don't update primary key or creation date
|
||||
setattr(existing_content, key, value)
|
||||
existing_content.updated_at = datetime.now(timezone.utc)
|
||||
else:
|
||||
logger.info('Creating new about page content...')
|
||||
about_page = PageContent(**about_data)
|
||||
db.add(about_page)
|
||||
|
||||
db.commit()
|
||||
logger.info('About page content seeded successfully!')
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error seeding about page: {str(e)}', exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
seed_about_page(db)
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed about page: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
200
Backend/seeders/accessibility_seeder.py
Normal file
200
Backend/seeders/accessibility_seeder.py
Normal file
@@ -0,0 +1,200 @@
|
||||
"""
|
||||
Accessibility Page Seeder
|
||||
Seeds the database with comprehensive accessibility information
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
|
||||
# Add parent directory to path to allow importing from src
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal
|
||||
from src.shared.config.logging_config import get_logger
|
||||
from src.content.models.page_content import PageContent, PageType
|
||||
|
||||
# Import all models to ensure relationships are loaded
|
||||
from src.models import *
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_accessibility_page_data():
|
||||
"""Generate comprehensive accessibility page data"""
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
return {
|
||||
'page_type': PageType.ACCESSIBILITY,
|
||||
'title': 'Accessibility',
|
||||
'subtitle': 'Committed to Accessibility for All',
|
||||
'description': 'We are committed to providing accessible facilities and services for all our guests. Learn about our accessibility features and accommodations.',
|
||||
'content': """
|
||||
<h2>Our Commitment to Accessibility</h2>
|
||||
<p>At Luxury Hotel & Resort, we are committed to ensuring that our facilities and services are accessible to all guests, including those with disabilities. We strive to comply with the Americans with Disabilities Act (ADA) and continuously work to improve accessibility throughout our property.</p>
|
||||
|
||||
<h2>Accessible Accommodations</h2>
|
||||
<h3>Accessible Guest Rooms</h3>
|
||||
<p>We offer several accessible guest rooms designed to meet ADA requirements, featuring:</p>
|
||||
<ul>
|
||||
<li>Wider doorways (minimum 32 inches)</li>
|
||||
<li>Roll-in showers or accessible bathtubs with grab bars</li>
|
||||
<li>Lowered light switches and thermostats</li>
|
||||
<li>Visual door knockers and phone alerts</li>
|
||||
<li>Accessible vanities and bathroom fixtures</li>
|
||||
<li>Closed-captioned televisions</li>
|
||||
<li>Accessible closet rods and shelves</li>
|
||||
</ul>
|
||||
|
||||
<h3>Room Features</h3>
|
||||
<ul>
|
||||
<li>Hearing-impaired kits available upon request</li>
|
||||
<li>Visual smoke detectors</li>
|
||||
<li>TTY/TDD devices available</li>
|
||||
<li>Accessible furniture and seating</li>
|
||||
</ul>
|
||||
|
||||
<h2>Public Areas & Facilities</h2>
|
||||
<h3>Entrance & Lobby</h3>
|
||||
<ul>
|
||||
<li>Wheelchair-accessible main entrance</li>
|
||||
<li>Automatic doors at main entrance</li>
|
||||
<li>Accessible front desk with lowered counter</li>
|
||||
<li>Accessible seating areas in lobby</li>
|
||||
</ul>
|
||||
|
||||
<h3>Dining Facilities</h3>
|
||||
<ul>
|
||||
<li>Accessible dining areas in all restaurants</li>
|
||||
<li>Accessible tables and seating</li>
|
||||
<li>Menus available in large print or braille upon request</li>
|
||||
<li>Staff trained to assist guests with disabilities</li>
|
||||
</ul>
|
||||
|
||||
<h3>Recreation & Fitness</h3>
|
||||
<ul>
|
||||
<li>Accessible fitness center with adaptive equipment</li>
|
||||
<li>Accessible pool area with pool lift (available upon request)</li>
|
||||
<li>Accessible spa facilities</li>
|
||||
</ul>
|
||||
|
||||
<h3>Meeting & Event Spaces</h3>
|
||||
<ul>
|
||||
<li>Accessible meeting rooms</li>
|
||||
<li>Accessible restrooms in meeting areas</li>
|
||||
<li>Assistive listening devices available</li>
|
||||
<li>Sign language interpreters available with advance notice</li>
|
||||
</ul>
|
||||
|
||||
<h2>Parking & Transportation</h2>
|
||||
<ul>
|
||||
<li>Accessible parking spaces near main entrance</li>
|
||||
<li>Van-accessible parking spaces</li>
|
||||
<li>Accessible valet service</li>
|
||||
<li>Accessible transportation available upon request</li>
|
||||
</ul>
|
||||
|
||||
<h2>Service Animals</h2>
|
||||
<p>Service animals are welcome throughout our property. We comply with all applicable laws regarding service animals and do not charge additional fees for service animals.</p>
|
||||
|
||||
<h2>Assistive Devices & Services</h2>
|
||||
<h3>Available Upon Request</h3>
|
||||
<ul>
|
||||
<li>TTY/TDD devices</li>
|
||||
<li>Visual door knockers</li>
|
||||
<li>Hearing-impaired kits</li>
|
||||
<li>Closed-captioned televisions</li>
|
||||
<li>Large print menus and materials</li>
|
||||
<li>Braille materials (available for select items)</li>
|
||||
<li>Assistive listening devices for meetings</li>
|
||||
<li>Sign language interpreters (with advance notice)</li>
|
||||
</ul>
|
||||
|
||||
<h2>Website Accessibility</h2>
|
||||
<p>We are committed to making our website accessible to all users. Our website is designed to comply with WCAG 2.1 Level AA standards. If you encounter any accessibility barriers on our website, please contact us so we can address the issue.</p>
|
||||
|
||||
<h2>Communication</h2>
|
||||
<p>Our staff is trained to communicate effectively with guests who have disabilities. We can provide information in alternative formats upon request, including:</p>
|
||||
<ul>
|
||||
<li>Large print materials</li>
|
||||
<li>Written materials</li>
|
||||
<li>Assistance with reading menus or other materials</li>
|
||||
</ul>
|
||||
|
||||
<h2>Accessibility Concerns & Feedback</h2>
|
||||
<p>We welcome feedback from our guests regarding accessibility. If you have any concerns or suggestions for improvement, please contact us:</p>
|
||||
<ul>
|
||||
<li><strong>Email:</strong> accessibility@luxuryhotel.com</li>
|
||||
<li><strong>Phone:</strong> +1 (555) 123-4567</li>
|
||||
<li><strong>TTY/TDD:</strong> +1 (555) 123-4568</li>
|
||||
<li><strong>Address:</strong> 123 Luxury Avenue, Premium City, PC 12345, United States</li>
|
||||
</ul>
|
||||
|
||||
<h2>Reservations</h2>
|
||||
<p>When making a reservation, please inform us of any specific accessibility needs so we can ensure your room and services meet your requirements. Our reservations team is available 24/7 to assist you.</p>
|
||||
<ul>
|
||||
<li><strong>Reservations Phone:</strong> +1 (555) 123-4567</li>
|
||||
<li><strong>Reservations Email:</strong> reservations@luxuryhotel.com</li>
|
||||
</ul>
|
||||
|
||||
<h2>Ongoing Improvements</h2>
|
||||
<p>We are continuously working to improve accessibility throughout our property. We regularly review and update our facilities and services to better serve all our guests. If you have suggestions for improvements, we would love to hear from you.</p>
|
||||
|
||||
<p><em>Last Updated: {}</em></p>
|
||||
""".format(now.strftime('%B %d, %Y')),
|
||||
'meta_title': 'Accessibility | Luxury Hotel & Resort - Accessible Facilities',
|
||||
'meta_description': 'Learn about our accessible facilities and services. We are committed to providing accessible accommodations for all guests.',
|
||||
'meta_keywords': 'accessibility, ADA, accessible hotel, wheelchair accessible, disability accommodations, accessible rooms',
|
||||
'og_title': 'Accessibility - Luxury Hotel & Resort',
|
||||
'og_description': 'Committed to accessibility for all. Learn about our accessible facilities and services.',
|
||||
'og_image': 'https://images.unsplash.com/photo-1556761175-5973dc0f32e7?w=1200&h=630&fit=crop',
|
||||
'canonical_url': 'https://luxuryhotel.com/accessibility',
|
||||
'is_active': True,
|
||||
'created_at': now,
|
||||
'updated_at': now
|
||||
}
|
||||
|
||||
|
||||
def seed_accessibility_page(db: Session):
|
||||
"""Seed accessibility page content into the database"""
|
||||
try:
|
||||
accessibility_data = get_accessibility_page_data()
|
||||
|
||||
# Check if accessibility page content already exists
|
||||
existing_content = db.query(PageContent).filter(PageContent.page_type == PageType.ACCESSIBILITY).first()
|
||||
|
||||
if existing_content:
|
||||
logger.info('Updating existing accessibility page content...')
|
||||
for key, value in accessibility_data.items():
|
||||
if key not in ['id', 'page_type', 'created_at']:
|
||||
setattr(existing_content, key, value)
|
||||
existing_content.updated_at = datetime.now(timezone.utc)
|
||||
else:
|
||||
logger.info('Creating new accessibility page content...')
|
||||
accessibility_page = PageContent(**accessibility_data)
|
||||
db.add(accessibility_page)
|
||||
|
||||
db.commit()
|
||||
logger.info('Accessibility page content seeded successfully!')
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error seeding accessibility page: {str(e)}', exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
seed_accessibility_page(db)
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed accessibility page: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
315
Backend/seeders/banner_seeder.py
Normal file
315
Backend/seeders/banner_seeder.py
Normal file
@@ -0,0 +1,315 @@
|
||||
"""
|
||||
Banner Seeder
|
||||
Seeds the database with comprehensive banners for different positions
|
||||
All images are from Unsplash (free stock photos)
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
# Add parent directory to path to import modules
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal
|
||||
from src.content.models.banner import Banner
|
||||
from src.shared.config.logging_config import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_banner_data():
|
||||
"""Generate comprehensive banner data with Unsplash images"""
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
future_date = now + timedelta(days=365) # Banners active for 1 year
|
||||
|
||||
banners = [
|
||||
# Home Page Banners
|
||||
{
|
||||
'title': 'Welcome to Luxury',
|
||||
'description': 'Experience unparalleled elegance and world-class service at our award-winning hotel. Discover sophisticated rooms, exceptional dining, and modern amenities.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/rooms',
|
||||
'position': 'home',
|
||||
'display_order': 1,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
{
|
||||
'title': 'Special Summer Offer',
|
||||
'description': 'Book now and save up to 30% on your summer getaway! Perfect for families, couples, and solo travelers. Limited time offer.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/book',
|
||||
'position': 'home',
|
||||
'display_order': 2,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
{
|
||||
'title': 'Fine Dining Experience',
|
||||
'description': 'Savor exquisite cuisine at our Michelin-starred restaurants. Enjoy international flavors, local specialties, and expertly curated wine pairings.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/services',
|
||||
'position': 'home',
|
||||
'display_order': 3,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
{
|
||||
'title': 'Luxury Spa & Wellness',
|
||||
'description': 'Rejuvenate at our world-class spa with personalized treatments, therapeutic massages, steam rooms, saunas, and yoga classes.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/services',
|
||||
'position': 'home',
|
||||
'display_order': 4,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
{
|
||||
'title': 'Business Events & Conferences',
|
||||
'description': 'Host your corporate event in our state-of-the-art facilities. Versatile spaces for intimate meetings to large conferences with cutting-edge technology.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1497366216548-37526070297c?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/contact',
|
||||
'position': 'home',
|
||||
'display_order': 5,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
|
||||
# Rooms Page Banners
|
||||
{
|
||||
'title': 'Luxurious Suites',
|
||||
'description': 'Elegantly designed suites with spacious layouts, separate living areas, marble bathrooms, and private balconies with panoramic views. Smart room controls and premium amenities included.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/rooms',
|
||||
'position': 'rooms',
|
||||
'display_order': 1,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
{
|
||||
'title': 'Presidential Suite',
|
||||
'description': 'Ultimate luxury in our exclusive 2,000+ sq ft suite. Features grand living room, formal dining, fully equipped kitchen, private terrace, and personal butler service. Perfect for VIP guests.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1596394516093-501ba68a0ba6?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/rooms',
|
||||
'position': 'rooms',
|
||||
'display_order': 2,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
{
|
||||
'title': 'Ocean View Rooms',
|
||||
'description': 'Breathtaking ocean views from private balconies. Spacious rooms with floor-to-ceiling windows, coastal decor, and premium furnishings. Perfect for romantic getaways.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/rooms',
|
||||
'position': 'rooms',
|
||||
'display_order': 3,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
|
||||
# About Page Banners
|
||||
{
|
||||
'title': 'Our Story',
|
||||
'description': 'Discover our rich heritage spanning three decades. Founded to redefine luxury hospitality, we\'ve grown into an internationally recognized destination with timeless elegance.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/about',
|
||||
'position': 'about',
|
||||
'display_order': 1,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
{
|
||||
'title': 'Award-Winning Service',
|
||||
'description': 'Recognized globally for exceptional hospitality with prestigious awards including five-star ratings and "Best Luxury Hotel" honors. Our trained team delivers service beyond expectations.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1579621970563-ebec7560ff3e?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/about',
|
||||
'position': 'about',
|
||||
'display_order': 2,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
|
||||
# Contact Page Banner
|
||||
{
|
||||
'title': 'Get in Touch',
|
||||
'description': 'Our friendly team is available 24/7 for reservations, inquiries, and special requests. Reach us by phone, email, or visit our front desk. Concierge assistance available.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1556761175-5973dc0f32e7?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/contact',
|
||||
'position': 'contact',
|
||||
'display_order': 1,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
|
||||
# Services Page Banners
|
||||
{
|
||||
'title': 'Premium Services',
|
||||
'description': 'Enjoy personalized butler service, private airport transfers, VIP lounge access, and priority reservations. Business center, city tours, and special occasion planning available.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1441986300917-64674bd600d8?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/services',
|
||||
'position': 'services',
|
||||
'display_order': 1,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
{
|
||||
'title': '24/7 Concierge Service',
|
||||
'description': 'Our dedicated concierge team is available around the clock. We assist with restaurant reservations, event tickets, transportation, exclusive experiences, and special occasions.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1556761175-5973dc0f32e7?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/services',
|
||||
'position': 'services',
|
||||
'display_order': 2,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
|
||||
# Promotional Banners (can be used across pages)
|
||||
{
|
||||
'title': 'Early Bird Special',
|
||||
'description': 'Book 30 days in advance and save 20%! Perfect for travelers who plan ahead. Applies to all room types. Terms and conditions apply.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/book',
|
||||
'position': 'home',
|
||||
'display_order': 6,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
{
|
||||
'title': 'Weekend Getaway Package',
|
||||
'description': 'All-inclusive weekend package with luxurious accommodation, daily breakfast, and full spa access. Late checkout included. Available Friday through Sunday.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/book',
|
||||
'position': 'home',
|
||||
'display_order': 7,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
{
|
||||
'title': 'Honeymoon Package',
|
||||
'description': 'Romantic honeymoon package includes luxurious suite, breakfast in bed, candlelit dinner with champagne, couples spa treatments, and special amenities.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1611892440504-42a792e24d32?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/book',
|
||||
'position': 'home',
|
||||
'display_order': 8,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
|
||||
# Footer/General Banners
|
||||
{
|
||||
'title': 'Join Our Loyalty Program',
|
||||
'description': 'Earn points with every stay. Redeem for free nights, upgrades, dining credits, and spa treatments. Multiple tier levels from Silver to Platinum. Join free today!',
|
||||
'image_url': 'https://images.unsplash.com/photo-1519389950473-47ba0277781c?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/loyalty',
|
||||
'position': 'home',
|
||||
'display_order': 9,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
},
|
||||
{
|
||||
'title': 'Gift Cards Available',
|
||||
'description': 'Give the gift of luxury with our hotel gift cards. Perfect for any occasion. Usable for accommodations, dining, spa, and all services. Never expire. Purchase online or at front desk.',
|
||||
'image_url': 'https://images.unsplash.com/photo-1606761568499-6d2451b23c66?w=1920&h=1080&fit=crop',
|
||||
'link_url': '/gift-cards',
|
||||
'position': 'home',
|
||||
'display_order': 10,
|
||||
'is_active': True,
|
||||
'start_date': now,
|
||||
'end_date': future_date
|
||||
}
|
||||
]
|
||||
|
||||
return banners
|
||||
|
||||
|
||||
def seed_banners(db: Session, clear_existing: bool = False):
|
||||
"""Seed banners into the database"""
|
||||
try:
|
||||
if clear_existing:
|
||||
logger.info('Clearing existing banners...')
|
||||
db.query(Banner).delete()
|
||||
db.commit()
|
||||
|
||||
banners_data = get_banner_data()
|
||||
created_count = 0
|
||||
updated_count = 0
|
||||
|
||||
for banner_data in banners_data:
|
||||
# Check if banner with same title and position already exists
|
||||
existing = db.query(Banner).filter(
|
||||
Banner.title == banner_data['title'],
|
||||
Banner.position == banner_data['position']
|
||||
).first()
|
||||
|
||||
if existing:
|
||||
logger.info(f'Updating existing banner: {banner_data["title"]} ({banner_data["position"]})')
|
||||
# Update existing banner
|
||||
for key, value in banner_data.items():
|
||||
setattr(existing, key, value)
|
||||
existing.updated_at = datetime.now(timezone.utc)
|
||||
updated_count += 1
|
||||
else:
|
||||
logger.info(f'Creating new banner: {banner_data["title"]} ({banner_data["position"]})')
|
||||
# Create new banner
|
||||
banner = Banner(**banner_data)
|
||||
db.add(banner)
|
||||
created_count += 1
|
||||
|
||||
db.commit()
|
||||
logger.info(f'Banner seeding completed! Created: {created_count}, Updated: {updated_count}')
|
||||
return created_count, updated_count
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f'Error seeding banners: {str(e)}', exc_info=True)
|
||||
db.rollback()
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function to run the seeder"""
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Seed banners into the database')
|
||||
parser.add_argument(
|
||||
'--clear',
|
||||
action='store_true',
|
||||
help='Clear existing banners before seeding'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
logger.info('Starting banner seeder...')
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
created, updated = seed_banners(db, clear_existing=args.clear)
|
||||
logger.info(f'Banner seeder completed successfully! Created: {created}, Updated: {updated}')
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed banners: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
320
Backend/seeders/blog_seeder.py
Normal file
320
Backend/seeders/blog_seeder.py
Normal file
@@ -0,0 +1,320 @@
|
||||
"""
|
||||
Blog Seeder
|
||||
Seeds the database with blog posts
|
||||
All images are from Unsplash (free stock photos)
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
import re
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
# Add parent directory to path to import modules
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal
|
||||
from src.shared.config.logging_config import get_logger
|
||||
from src.content.models.blog import BlogPost
|
||||
from src.auth.models.user import User
|
||||
|
||||
# Import all models to ensure relationships are loaded correctly
|
||||
from src.models import *
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def slugify(text):
|
||||
"""Convert text to URL-friendly slug"""
|
||||
text = text.lower()
|
||||
text = re.sub(r'[^\w\s-]', '', text)
|
||||
text = re.sub(r'[-\s]+', '-', text)
|
||||
return text.strip('-')
|
||||
|
||||
|
||||
def get_blog_posts_data(author_id: int):
|
||||
"""Generate comprehensive blog posts data with Unsplash images"""
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
posts = [
|
||||
{
|
||||
'title': '10 Tips for Planning the Perfect Luxury Hotel Stay',
|
||||
'slug': '10-tips-planning-perfect-luxury-hotel-stay',
|
||||
'excerpt': 'Discover expert tips to make your luxury hotel experience unforgettable. From booking strategies to maximizing amenities, we share insider secrets.',
|
||||
'content': '''<p>Planning a luxury hotel stay requires attention to detail and insider knowledge. Whether you're celebrating a special occasion or simply treating yourself, these tips will help you make the most of your experience.</p>
|
||||
|
||||
<h2>1. Book in Advance</h2>
|
||||
<p>Luxury hotels often offer early bird discounts and better room availability when you book well in advance. Planning ahead also gives you access to special packages and upgrades.</p>
|
||||
|
||||
<h2>2. Communicate Your Preferences</h2>
|
||||
<p>Don't hesitate to communicate your preferences when booking. Whether you prefer a high floor, specific room amenities, or have dietary restrictions, hotels are happy to accommodate.</p>
|
||||
|
||||
<h2>3. Join Loyalty Programs</h2>
|
||||
<p>Most luxury hotels offer loyalty programs with exclusive benefits. Join before your stay to earn points, receive member rates, and enjoy perks like late checkout.</p>
|
||||
|
||||
<h2>4. Explore Hotel Amenities</h2>
|
||||
<p>Take advantage of all the hotel has to offer - from spa treatments to fine dining. Many luxury hotels have world-class facilities that are worth experiencing.</p>
|
||||
|
||||
<h2>5. Use Concierge Services</h2>
|
||||
<p>The concierge team is your gateway to the best local experiences. They can secure restaurant reservations, arrange transportation, and provide insider recommendations.</p>
|
||||
|
||||
<h2>6. Check for Special Packages</h2>
|
||||
<p>Look for special packages that bundle accommodations with dining, spa, or local experiences. These often provide better value than booking separately.</p>
|
||||
|
||||
<h2>7. Review Cancellation Policies</h2>
|
||||
<p>Understand the cancellation and modification policies before booking. Flexible rates may cost more but provide peace of mind.</p>
|
||||
|
||||
<h2>8. Pack Appropriately</h2>
|
||||
<p>While luxury hotels provide many amenities, bringing appropriate attire for dining and activities ensures you're prepared for all experiences.</p>
|
||||
|
||||
<h2>9. Arrive Early or Late</h2>
|
||||
<p>If possible, arrive early or late to avoid peak check-in times. This often results in better service and sometimes room upgrades if available.</p>
|
||||
|
||||
<h2>10. Leave Reviews</h2>
|
||||
<p>Share your experience through reviews. Hotels value feedback and often reward guests who provide detailed, constructive reviews.</p>
|
||||
|
||||
<p>Remember, a luxury hotel stay is about creating memories. Take your time, enjoy every moment, and don't hesitate to ask for what will make your stay perfect.</p>''',
|
||||
'featured_image': 'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1200&h=800&fit=crop',
|
||||
'author_id': author_id,
|
||||
'published_at': now - timedelta(days=5),
|
||||
'is_published': True,
|
||||
'tags': json.dumps(['travel tips', 'luxury travel', 'hotel guide', 'vacation planning']),
|
||||
'meta_title': '10 Tips for Planning the Perfect Luxury Hotel Stay | Travel Guide',
|
||||
'meta_description': 'Expert tips for planning an unforgettable luxury hotel stay. Learn booking strategies, how to maximize amenities, and insider secrets.',
|
||||
'meta_keywords': 'luxury hotel tips, hotel booking guide, travel planning, luxury travel advice',
|
||||
'sections': None
|
||||
},
|
||||
{
|
||||
'title': 'The Art of Fine Dining: A Culinary Journey at Our Hotel',
|
||||
'slug': 'art-fine-dining-culinary-journey',
|
||||
'excerpt': 'Explore our award-winning restaurants and discover the culinary philosophy behind our Michelin-starred dining experiences.',
|
||||
'content': '''<p>Fine dining is an art form that combines exceptional ingredients, masterful technique, and impeccable service. At our hotel, we've created culinary experiences that celebrate both tradition and innovation.</p>
|
||||
|
||||
<h2>Our Culinary Philosophy</h2>
|
||||
<p>Our chefs believe in using the finest locally sourced ingredients, supporting sustainable practices, and creating dishes that tell a story. Each plate is a masterpiece, carefully crafted to delight all senses.</p>
|
||||
|
||||
<h2>Signature Dishes</h2>
|
||||
<p>From our signature truffle risotto to our perfectly aged wagyu beef, every dish on our menu has been thoughtfully created. Our tasting menus offer a journey through flavors, textures, and culinary traditions.</p>
|
||||
|
||||
<h2>Wine Pairing Excellence</h2>
|
||||
<p>Our sommeliers curate wine pairings that enhance every dish. With an extensive cellar featuring rare vintages and hidden gems, we ensure the perfect complement to your meal.</p>
|
||||
|
||||
<h2>Private Dining Experiences</h2>
|
||||
<p>For special occasions, our private dining rooms offer intimate settings with personalized menus. Our chefs work closely with guests to create unforgettable culinary experiences.</p>
|
||||
|
||||
<p>Join us for a culinary journey that celebrates the art of fine dining and creates memories that last a lifetime.</p>''',
|
||||
'featured_image': 'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=1200&h=800&fit=crop',
|
||||
'author_id': author_id,
|
||||
'published_at': now - timedelta(days=10),
|
||||
'is_published': True,
|
||||
'tags': json.dumps(['fine dining', 'culinary', 'restaurant', 'gourmet']),
|
||||
'meta_title': 'The Art of Fine Dining | Culinary Excellence',
|
||||
'meta_description': 'Discover our award-winning restaurants and Michelin-starred dining experiences. Explore our culinary philosophy and signature dishes.',
|
||||
'meta_keywords': 'fine dining, Michelin restaurant, gourmet cuisine, culinary experience',
|
||||
'sections': None
|
||||
},
|
||||
{
|
||||
'title': 'Wellness and Relaxation: Your Guide to Our Spa & Wellness Center',
|
||||
'slug': 'wellness-relaxation-spa-wellness-center-guide',
|
||||
'excerpt': 'Discover our world-class spa and wellness center. Learn about our treatments, wellness programs, and how to achieve ultimate relaxation.',
|
||||
'content': '''<p>In today's fast-paced world, taking time for wellness and relaxation is essential. Our spa and wellness center offers a sanctuary where you can rejuvenate your mind, body, and spirit.</p>
|
||||
|
||||
<h2>Our Wellness Philosophy</h2>
|
||||
<p>We believe in holistic wellness that addresses physical, mental, and emotional well-being. Our treatments combine traditional techniques with modern innovations to provide comprehensive care.</p>
|
||||
|
||||
<h2>Signature Treatments</h2>
|
||||
<p>From our signature deep tissue massages to rejuvenating facials, each treatment is customized to your needs. Our expert therapists use premium products and time-tested techniques.</p>
|
||||
|
||||
<h2>Wellness Programs</h2>
|
||||
<p>Beyond individual treatments, we offer comprehensive wellness programs including yoga classes, meditation sessions, and personalized fitness consultations.</p>
|
||||
|
||||
<h2>The Spa Environment</h2>
|
||||
<p>Our spa facilities include steam rooms, saunas, relaxation lounges, and private treatment rooms. Every detail is designed to create a serene, peaceful atmosphere.</p>
|
||||
|
||||
<h2>Couples Experiences</h2>
|
||||
<p>Share the relaxation experience with our couples treatments. Perfect for romantic getaways or celebrating special moments together.</p>
|
||||
|
||||
<p>Whether you're seeking stress relief, muscle recovery, or simply a moment of tranquility, our spa and wellness center provides the perfect escape.</p>''',
|
||||
'featured_image': 'https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=1200&h=800&fit=crop',
|
||||
'author_id': author_id,
|
||||
'published_at': now - timedelta(days=15),
|
||||
'is_published': True,
|
||||
'tags': json.dumps(['spa', 'wellness', 'relaxation', 'self-care']),
|
||||
'meta_title': 'Wellness and Relaxation Guide | Spa & Wellness Center',
|
||||
'meta_description': 'Discover our world-class spa and wellness center. Learn about treatments, wellness programs, and how to achieve ultimate relaxation.',
|
||||
'meta_keywords': 'spa, wellness, relaxation, massage, hotel spa',
|
||||
'sections': None
|
||||
},
|
||||
{
|
||||
'title': 'Sustainable Luxury: Our Commitment to Environmental Responsibility',
|
||||
'slug': 'sustainable-luxury-environmental-responsibility',
|
||||
'excerpt': 'Learn about our sustainability initiatives and how we balance luxury with environmental responsibility. Discover our green practices and commitment to the planet.',
|
||||
'content': '''<p>Luxury and sustainability are not mutually exclusive. At our hotel, we've proven that you can enjoy world-class amenities while protecting the environment for future generations.</p>
|
||||
|
||||
<h2>Our Sustainability Mission</h2>
|
||||
<p>We're committed to reducing our environmental footprint through innovative practices, renewable energy, and responsible sourcing. Our goal is carbon neutrality while maintaining the highest standards of luxury.</p>
|
||||
|
||||
<h2>Green Building Practices</h2>
|
||||
<p>Our facilities incorporate energy-efficient systems, water conservation measures, and sustainable materials. We continuously invest in technologies that reduce our environmental impact.</p>
|
||||
|
||||
<h2>Local and Sustainable Sourcing</h2>
|
||||
<p>We prioritize local suppliers and sustainable ingredients in our restaurants. This not only reduces our carbon footprint but also supports local communities and ensures the freshest quality.</p>
|
||||
|
||||
<h2>Waste Reduction</h2>
|
||||
<p>Through comprehensive recycling programs, composting, and waste reduction initiatives, we've significantly decreased our waste output. Single-use plastics have been eliminated throughout the property.</p>
|
||||
|
||||
<h2>Guest Participation</h2>
|
||||
<p>We invite guests to join us in our sustainability efforts through optional programs like towel reuse, energy conservation, and supporting local conservation projects.</p>
|
||||
|
||||
<p>Together, we can enjoy luxury experiences while protecting our planet. Every small action contributes to a more sustainable future.</p>''',
|
||||
'featured_image': 'https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=1200&h=800&fit=crop',
|
||||
'author_id': author_id,
|
||||
'published_at': now - timedelta(days=20),
|
||||
'is_published': True,
|
||||
'tags': json.dumps(['sustainability', 'environment', 'green hotel', 'eco-friendly']),
|
||||
'meta_title': 'Sustainable Luxury | Environmental Responsibility',
|
||||
'meta_description': 'Learn about our sustainability initiatives and how we balance luxury with environmental responsibility. Discover our green practices.',
|
||||
'meta_keywords': 'sustainable luxury, green hotel, environmental responsibility, eco-friendly',
|
||||
'sections': None
|
||||
},
|
||||
{
|
||||
'title': 'Celebrating 30 Years of Excellence in Hospitality',
|
||||
'slug': 'celebrating-30-years-excellence-hospitality',
|
||||
'excerpt': 'Join us as we celebrate three decades of providing exceptional hospitality. Learn about our journey, milestones, and vision for the future.',
|
||||
'content': '''<p>This year marks a significant milestone - 30 years of excellence in hospitality. From our humble beginnings to becoming an internationally recognized destination, our journey has been remarkable.</p>
|
||||
|
||||
<h2>Our Beginnings</h2>
|
||||
<p>Founded in 1993, we started with a simple vision: to create a sanctuary of luxury and sophistication. What began as a small boutique property has grown into a world-class destination.</p>
|
||||
|
||||
<h2>Key Milestones</h2>
|
||||
<p>Over three decades, we've achieved numerous milestones - from our first five-star rating to receiving international awards. Each achievement represents our commitment to excellence.</p>
|
||||
|
||||
<h2>Our Team</h2>
|
||||
<p>None of this would be possible without our dedicated team. Their passion, professionalism, and commitment to service excellence have been the foundation of our success.</p>
|
||||
|
||||
<h2>Looking Forward</h2>
|
||||
<p>As we celebrate this milestone, we're also looking to the future. We continue to innovate, invest in our facilities, and enhance our services to exceed guest expectations.</p>
|
||||
|
||||
<h2>Thank You</h2>
|
||||
<p>To all our guests, partners, and team members - thank you for being part of our journey. Here's to the next 30 years of creating unforgettable experiences.</p>
|
||||
|
||||
<p>Join us in celebrating this special anniversary with special packages and events throughout the year.</p>''',
|
||||
'featured_image': 'https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?w=1200&h=800&fit=crop',
|
||||
'author_id': author_id,
|
||||
'published_at': now - timedelta(days=25),
|
||||
'is_published': True,
|
||||
'tags': json.dumps(['anniversary', 'hotel history', 'milestone', 'celebration']),
|
||||
'meta_title': 'Celebrating 30 Years of Excellence | Hotel Anniversary',
|
||||
'meta_description': 'Join us as we celebrate three decades of providing exceptional hospitality. Learn about our journey, milestones, and vision for the future.',
|
||||
'meta_keywords': 'hotel anniversary, 30 years, hospitality excellence, milestone',
|
||||
'sections': None
|
||||
},
|
||||
{
|
||||
'title': 'The Ultimate Business Traveler\'s Guide to Our Hotel',
|
||||
'slug': 'ultimate-business-traveler-guide',
|
||||
'excerpt': 'Discover how our hotel caters to business travelers with state-of-the-art facilities, convenient services, and amenities designed for productivity and comfort.',
|
||||
'content': '''<p>Business travel doesn't have to mean sacrificing comfort or productivity. Our hotel is designed specifically to meet the needs of modern business travelers.</p>
|
||||
|
||||
<h2>Business Facilities</h2>
|
||||
<p>Our fully equipped business center provides everything you need - from high-speed internet to meeting rooms with state-of-the-art AV equipment. Work seamlessly from anywhere in the hotel.</p>
|
||||
|
||||
<h2>Convenient Services</h2>
|
||||
<p>Express check-in and checkout, 24/7 concierge service, and flexible meeting arrangements ensure your business needs are met efficiently. We understand that time is valuable.</p>
|
||||
|
||||
<h2>Comfortable Accommodations</h2>
|
||||
<p>Our rooms feature dedicated workspaces, ergonomic furniture, and premium amenities. After a long day of meetings, relax in comfort and recharge for tomorrow.</p>
|
||||
|
||||
<h2>Networking Opportunities</h2>
|
||||
<p>Our restaurants and lounges provide perfect settings for business networking. Whether hosting clients or connecting with colleagues, we provide the ideal atmosphere.</p>
|
||||
|
||||
<h2>Wellness for Business Travelers</h2>
|
||||
<p>Maintain your wellness routine with our fitness center, spa services, and healthy dining options. We help you stay balanced even when traveling for business.</p>
|
||||
|
||||
<p>Experience business travel redefined - where productivity meets luxury, and comfort enhances performance.</p>''',
|
||||
'featured_image': 'https://images.unsplash.com/photo-1497366216548-37526070297c?w=1200&h=800&fit=crop',
|
||||
'author_id': author_id,
|
||||
'published_at': now - timedelta(days=30),
|
||||
'is_published': True,
|
||||
'tags': json.dumps(['business travel', 'corporate', 'productivity', 'meetings']),
|
||||
'meta_title': 'Business Traveler\'s Guide | Corporate Accommodation',
|
||||
'meta_description': 'Discover how our hotel caters to business travelers with state-of-the-art facilities, convenient services, and productivity-focused amenities.',
|
||||
'meta_keywords': 'business travel, corporate hotel, business facilities, meeting rooms',
|
||||
'sections': None
|
||||
}
|
||||
]
|
||||
|
||||
return posts
|
||||
|
||||
|
||||
def seed_blog_posts(db: Session, clear_existing: bool = False):
|
||||
"""Seed blog posts into the database"""
|
||||
try:
|
||||
# Get admin user as author
|
||||
admin_user = db.query(User).filter(User.email == 'admin@hotel.com').first()
|
||||
if not admin_user:
|
||||
logger.error('Admin user not found. Please run user seeder first.')
|
||||
raise ValueError('Admin user not found. Please run user seeder first.')
|
||||
|
||||
if clear_existing:
|
||||
logger.info('Clearing existing blog posts...')
|
||||
db.query(BlogPost).delete()
|
||||
db.commit()
|
||||
logger.info('Existing blog posts cleared.')
|
||||
|
||||
posts_data = get_blog_posts_data(admin_user.id)
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
created_count = 0
|
||||
updated_count = 0
|
||||
|
||||
for post_data in posts_data:
|
||||
# Generate slug if not provided
|
||||
if not post_data.get('slug'):
|
||||
post_data['slug'] = slugify(post_data['title'])
|
||||
|
||||
existing = db.query(BlogPost).filter(BlogPost.slug == post_data['slug']).first()
|
||||
|
||||
if existing:
|
||||
logger.debug(f"Blog post '{post_data['title']}' already exists. Updating...")
|
||||
for key, value in post_data.items():
|
||||
setattr(existing, key, value)
|
||||
existing.updated_at = now
|
||||
updated_count += 1
|
||||
else:
|
||||
logger.debug(f"Creating blog post: {post_data['title']}")
|
||||
post = BlogPost(**post_data)
|
||||
db.add(post)
|
||||
created_count += 1
|
||||
|
||||
db.commit()
|
||||
logger.info(f'Successfully seeded blog posts! Created: {created_count}, Updated: {updated_count}, Total: {len(posts_data)}')
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error seeding blog posts: {str(e)}', exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Seed blog posts')
|
||||
parser.add_argument(
|
||||
'--clear',
|
||||
action='store_true',
|
||||
help='Clear existing blog posts before seeding'
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
seed_blog_posts(db, clear_existing=args.clear)
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed blog posts: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
221
Backend/seeders/cancellation_seeder.py
Normal file
221
Backend/seeders/cancellation_seeder.py
Normal file
@@ -0,0 +1,221 @@
|
||||
"""
|
||||
Cancellation Policy Page Seeder
|
||||
Seeds the database with comprehensive cancellation policy content
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
|
||||
# Add parent directory to path to allow importing from src
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal
|
||||
from src.shared.config.logging_config import get_logger
|
||||
from src.content.models.page_content import PageContent, PageType
|
||||
|
||||
# Import all models to ensure relationships are loaded
|
||||
from src.models import *
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_cancellation_page_data():
|
||||
"""Generate comprehensive cancellation policy page data"""
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
return {
|
||||
'page_type': PageType.CANCELLATION,
|
||||
'title': 'Cancellation Policy',
|
||||
'subtitle': 'Reservation Cancellation Terms and Conditions',
|
||||
'description': 'Learn about our cancellation policy, including cancellation deadlines, fees, and procedures for different rate types.',
|
||||
'content': """
|
||||
<h2>1. Overview</h2>
|
||||
<p>This Cancellation Policy outlines the terms and conditions for cancelling reservations at Luxury Hotel & Resort. Cancellation terms vary by rate type and are clearly stated at the time of booking. Please review this policy carefully before making a reservation.</p>
|
||||
|
||||
<h2>2. Standard Cancellation Policy</h2>
|
||||
<h3>2.1 Flexible Rate</h3>
|
||||
<p>For reservations made with our Flexible Rate:</p>
|
||||
<ul>
|
||||
<li><strong>Free Cancellation:</strong> Cancellations made 24-48 hours before the scheduled check-in date and time are free of charge</li>
|
||||
<li><strong>Late Cancellation:</strong> Cancellations made less than 24 hours before check-in will incur a charge equal to one night's room rate plus taxes</li>
|
||||
<li><strong>No-Show:</strong> Failure to arrive on the scheduled check-in date will result in a charge for the entire reservation</li>
|
||||
</ul>
|
||||
|
||||
<h3>2.2 Non-Refundable Rate</h3>
|
||||
<p>For reservations made with our Non-Refundable Rate:</p>
|
||||
<ul>
|
||||
<li>These rates offer the best value but are non-refundable</li>
|
||||
<li>Cancellations or modifications are not permitted</li>
|
||||
<li>In exceptional circumstances, we may offer a credit for future stays (subject to management approval)</li>
|
||||
<li>No-shows will be charged the full reservation amount</li>
|
||||
</ul>
|
||||
|
||||
<h3>2.3 Advance Purchase Rate</h3>
|
||||
<p>For Advance Purchase rates:</p>
|
||||
<ul>
|
||||
<li>Full payment is required at the time of booking</li>
|
||||
<li>Cancellations made 7 days or more before check-in: Full refund minus a processing fee</li>
|
||||
<li>Cancellations made less than 7 days before check-in: No refund</li>
|
||||
</ul>
|
||||
|
||||
<h2>3. Special Packages and Promotions</h2>
|
||||
<p>Cancellation terms for special packages, promotions, and seasonal offers may differ from standard rates. Specific cancellation terms will be clearly stated at the time of booking and in your confirmation email.</p>
|
||||
|
||||
<h2>4. Group Bookings</h2>
|
||||
<p>For group bookings (typically 10 or more rooms):</p>
|
||||
<ul>
|
||||
<li>Cancellation terms are specified in the group booking contract</li>
|
||||
<li>Generally, cancellations must be made 30-60 days in advance to avoid penalties</li>
|
||||
<li>Individual room cancellations within a group may be subject to different terms</li>
|
||||
<li>Please refer to your group booking agreement for specific terms</li>
|
||||
</ul>
|
||||
|
||||
<h2>5. Event and Meeting Bookings</h2>
|
||||
<p>Cancellation policies for event and meeting space bookings are detailed in your event contract. Generally:</p>
|
||||
<ul>
|
||||
<li>Cancellations made 30+ days in advance: Full refund or credit</li>
|
||||
<li>Cancellations made 14-30 days in advance: 50% refund or credit</li>
|
||||
<li>Cancellations made less than 14 days in advance: No refund</li>
|
||||
</ul>
|
||||
|
||||
<h2>6. How to Cancel</h2>
|
||||
<h3>6.1 Online Cancellation</h3>
|
||||
<p>You can cancel your reservation online through:</p>
|
||||
<ul>
|
||||
<li>Your booking confirmation email (click "Manage Reservation")</li>
|
||||
<li>Our website's "Manage Booking" section</li>
|
||||
<li>Your account dashboard (if you have an account)</li>
|
||||
</ul>
|
||||
|
||||
<h3>6.2 Phone Cancellation</h3>
|
||||
<p>Call our reservations team:</p>
|
||||
<ul>
|
||||
<li><strong>Phone:</strong> +1 (555) 123-4567</li>
|
||||
<li><strong>Hours:</strong> 24/7</li>
|
||||
<li>Please have your confirmation number ready</li>
|
||||
</ul>
|
||||
|
||||
<h3>6.3 Email Cancellation</h3>
|
||||
<p>Send an email to:</p>
|
||||
<ul>
|
||||
<li><strong>Email:</strong> reservations@luxuryhotel.com</li>
|
||||
<li>Include your confirmation number and guest name</li>
|
||||
<li>Allow 24-48 hours for email processing</li>
|
||||
</ul>
|
||||
|
||||
<h2>7. Cancellation Confirmation</h2>
|
||||
<p>Upon successful cancellation, you will receive a cancellation confirmation email. Please retain this confirmation for your records. If you do not receive a confirmation, please contact us to verify that your cancellation was processed.</p>
|
||||
|
||||
<h2>8. Refunds</h2>
|
||||
<p>Refunds for eligible cancellations will be processed to the original payment method within 5-10 business days. The time it takes for the refund to appear in your account depends on your financial institution. For more information, please refer to our Refund Policy.</p>
|
||||
|
||||
<h2>9. Modifications vs. Cancellations</h2>
|
||||
<h3>9.1 Date Changes</h3>
|
||||
<p>Modifying your reservation dates may be treated as a cancellation and rebooking, subject to availability and current rates. Please contact us to discuss modification options.</p>
|
||||
|
||||
<h3>9.2 Room Type Changes</h3>
|
||||
<p>Changes to room type are subject to availability and rate differences. Additional charges may apply if the new room type has a higher rate.</p>
|
||||
|
||||
<h2>10. Force Majeure</h2>
|
||||
<p>In cases of force majeure events (natural disasters, pandemics, government restrictions, travel bans, etc.), we will work with you to provide flexible cancellation options, including:</p>
|
||||
<ul>
|
||||
<li>Full refunds</li>
|
||||
<li>Rescheduling without penalty</li>
|
||||
<li>Credit for future stays</li>
|
||||
</ul>
|
||||
<p>Each situation is evaluated individually. Please contact us as soon as possible if you are affected by a force majeure event.</p>
|
||||
|
||||
<h2>11. Third-Party Bookings</h2>
|
||||
<p>If you made your reservation through a third-party booking site (such as Expedia, Booking.com, etc.), you must cancel through that third party according to their cancellation policies. We cannot directly cancel third-party bookings.</p>
|
||||
|
||||
<h2>12. No-Show Policy</h2>
|
||||
<p>If you do not arrive on your scheduled check-in date and have not cancelled your reservation:</p>
|
||||
<ul>
|
||||
<li>Your reservation will be considered a "no-show"</li>
|
||||
<li>You will be charged according to your rate's cancellation policy</li>
|
||||
<li>Remaining nights may be released for resale</li>
|
||||
<li>No refunds are provided for no-show reservations</li>
|
||||
</ul>
|
||||
|
||||
<h2>13. Early Departure</h2>
|
||||
<p>If you check out earlier than your scheduled departure date:</p>
|
||||
<ul>
|
||||
<li>You may be eligible for a partial refund for unused nights</li>
|
||||
<li>Early departure refunds are not guaranteed and are evaluated on a case-by-case basis</li>
|
||||
<li>Please notify the front desk at least 24 hours before your early departure</li>
|
||||
<li>Refunds are subject to the terms of your original reservation</li>
|
||||
</ul>
|
||||
|
||||
<h2>14. Special Circumstances</h2>
|
||||
<p>We understand that unexpected circumstances may arise. In cases of medical emergencies, family emergencies, or other extenuating circumstances, please contact us immediately. We will review your situation and may offer flexible cancellation options on a case-by-case basis.</p>
|
||||
|
||||
<h2>15. Contact Information</h2>
|
||||
<p>For cancellation requests or questions about our cancellation policy, please contact us:</p>
|
||||
<ul>
|
||||
<li><strong>Reservations Phone:</strong> +1 (555) 123-4567 (24/7)</li>
|
||||
<li><strong>Reservations Email:</strong> reservations@luxuryhotel.com</li>
|
||||
<li><strong>Address:</strong> 123 Luxury Avenue, Premium City, PC 12345, United States</li>
|
||||
</ul>
|
||||
|
||||
<h2>16. Policy Updates</h2>
|
||||
<p>We reserve the right to update this Cancellation Policy at any time. Changes will be posted on this page with an updated "Last Updated" date. The cancellation terms that apply to your reservation are those in effect at the time you made your booking.</p>
|
||||
|
||||
<p><em>Last Updated: {}</em></p>
|
||||
""".format(now.strftime('%B %d, %Y')),
|
||||
'meta_title': 'Cancellation Policy | Luxury Hotel & Resort',
|
||||
'meta_description': 'Learn about our cancellation policy, including cancellation deadlines, fees, and procedures for different rate types.',
|
||||
'meta_keywords': 'cancellation policy, hotel cancellation, booking cancellation, cancel reservation, cancellation terms',
|
||||
'og_title': 'Cancellation Policy - Luxury Hotel & Resort',
|
||||
'og_description': 'Reservation cancellation terms and conditions. Learn how to cancel your booking and applicable fees.',
|
||||
'og_image': 'https://images.unsplash.com/photo-1556761175-5973dc0f32e7?w=1200&h=630&fit=crop',
|
||||
'canonical_url': 'https://luxuryhotel.com/cancellation',
|
||||
'is_active': True,
|
||||
'created_at': now,
|
||||
'updated_at': now
|
||||
}
|
||||
|
||||
|
||||
def seed_cancellation_page(db: Session):
|
||||
"""Seed cancellation policy page content into the database"""
|
||||
try:
|
||||
cancellation_data = get_cancellation_page_data()
|
||||
|
||||
# Check if cancellation page content already exists
|
||||
existing_content = db.query(PageContent).filter(PageContent.page_type == PageType.CANCELLATION).first()
|
||||
|
||||
if existing_content:
|
||||
logger.info('Updating existing cancellation policy page content...')
|
||||
for key, value in cancellation_data.items():
|
||||
if key not in ['id', 'page_type', 'created_at']:
|
||||
setattr(existing_content, key, value)
|
||||
existing_content.updated_at = datetime.now(timezone.utc)
|
||||
else:
|
||||
logger.info('Creating new cancellation policy page content...')
|
||||
cancellation_page = PageContent(**cancellation_data)
|
||||
db.add(cancellation_page)
|
||||
|
||||
db.commit()
|
||||
logger.info('Cancellation policy page content seeded successfully!')
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error seeding cancellation policy page: {str(e)}', exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
seed_cancellation_page(db)
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed cancellation policy page: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
167
Backend/seeders/contact_seeder.py
Normal file
167
Backend/seeders/contact_seeder.py
Normal file
@@ -0,0 +1,167 @@
|
||||
"""
|
||||
Contact Page Seeder
|
||||
Seeds the database with comprehensive contact page content
|
||||
All images are from Unsplash (free stock photos)
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
|
||||
# Add parent directory to path to allow importing from src
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal
|
||||
from src.shared.config.logging_config import get_logger
|
||||
from src.content.models.page_content import PageContent, PageType
|
||||
|
||||
# Import all models to ensure relationships are loaded
|
||||
from src.models import *
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_contact_page_data():
|
||||
"""Generate comprehensive contact page data with Unsplash images"""
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
return {
|
||||
'page_type': PageType.CONTACT,
|
||||
'title': 'Contact Us',
|
||||
'subtitle': 'We\'re Here to Help - Get in Touch',
|
||||
'description': 'Have questions or need assistance? Our friendly team is available 24/7 to help with reservations, inquiries, and special requests. Reach out to us through any of the methods below.',
|
||||
'content': '<p>We value your feedback and are here to assist you with any questions or requests. Whether you\'re planning a stay, have a question about our services, or need assistance during your visit, our team is ready to help.</p>',
|
||||
'meta_title': 'Contact Us | Luxury Hotel & Resort - Get in Touch',
|
||||
'meta_description': 'Contact our luxury hotel for reservations, inquiries, or assistance. Our friendly team is available 24/7. Phone, email, and location information.',
|
||||
'meta_keywords': 'contact us, hotel contact, reservations, customer service, hotel phone number, hotel email',
|
||||
'og_title': 'Contact Us - Luxury Hotel & Resort',
|
||||
'og_description': 'Have questions or need assistance? Our friendly team is available 24/7 to help with reservations, inquiries, and special requests.',
|
||||
'og_image': 'https://images.unsplash.com/photo-1556761175-5973dc0f32e7?w=1200&h=630&fit=crop',
|
||||
'canonical_url': 'https://luxuryhotel.com/contact',
|
||||
'hero_title': 'Get in Touch',
|
||||
'hero_subtitle': 'We\'re Here to Help You',
|
||||
'hero_image': 'https://images.unsplash.com/photo-1556761175-5973dc0f32e7?w=1920&h=1080&fit=crop',
|
||||
'hero_video_url': None,
|
||||
'hero_video_poster': None,
|
||||
'contact_info': json.dumps({
|
||||
'phone': '+1 (555) 123-4567',
|
||||
'toll_free': '+1 (800) 123-4567',
|
||||
'email': 'info@luxuryhotel.com',
|
||||
'reservations_email': 'reservations@luxuryhotel.com',
|
||||
'address': '123 Luxury Avenue, Premium City, PC 12345',
|
||||
'address_line2': 'United States',
|
||||
'business_hours': {
|
||||
'front_desk': '24/7',
|
||||
'concierge': '24/7',
|
||||
'reservations': 'Monday - Sunday: 8:00 AM - 10:00 PM',
|
||||
'restaurant': 'Breakfast: 7:00 AM - 11:00 AM, Lunch: 12:00 PM - 3:00 PM, Dinner: 6:00 PM - 11:00 PM',
|
||||
'spa': 'Monday - Sunday: 9:00 AM - 9:00 PM'
|
||||
}
|
||||
}),
|
||||
'map_url': 'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3022.184132576!2d-73.98811768459418!3d40.75889597932681!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x89c25855c6480299%3A0x55194ec5a1ae072e!2sTimes%20Square!5e0!3m2!1sen!2sus!4v1234567890123!5m2!1sen!2sus',
|
||||
'social_links': json.dumps({
|
||||
'facebook': 'https://facebook.com/luxuryhotel',
|
||||
'twitter': 'https://twitter.com/luxuryhotel',
|
||||
'instagram': 'https://instagram.com/luxuryhotel',
|
||||
'linkedin': 'https://linkedin.com/company/luxuryhotel',
|
||||
'youtube': 'https://youtube.com/luxuryhotel',
|
||||
'pinterest': 'https://pinterest.com/luxuryhotel'
|
||||
}),
|
||||
'testimonials': json.dumps([
|
||||
{
|
||||
'name': 'Sarah Johnson',
|
||||
'title': 'Guest',
|
||||
'quote': 'The customer service team was incredibly helpful and responsive. They answered all my questions and made my booking process seamless.',
|
||||
'rating': 5,
|
||||
'image': 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=200&h=200&fit=crop&crop=face'
|
||||
},
|
||||
{
|
||||
'name': 'Michael Chen',
|
||||
'title': 'Business Traveler',
|
||||
'quote': 'The concierge team went above and beyond to help with my business needs. Their attention to detail and professionalism is outstanding.',
|
||||
'rating': 5,
|
||||
'image': 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=200&h=200&fit=crop&crop=face'
|
||||
}
|
||||
]),
|
||||
'testimonials_section_title': 'What Our Guests Say About Our Service',
|
||||
'testimonials_section_subtitle': 'Real feedback from our valued guests',
|
||||
'features': json.dumps([
|
||||
{
|
||||
'icon': 'phone',
|
||||
'title': '24/7 Support',
|
||||
'description': 'Our team is available around the clock to assist you with any questions or requests.'
|
||||
},
|
||||
{
|
||||
'icon': 'clock',
|
||||
'title': 'Quick Response',
|
||||
'description': 'We respond to all inquiries within 24 hours, often much sooner.'
|
||||
},
|
||||
{
|
||||
'icon': 'users',
|
||||
'title': 'Expert Team',
|
||||
'description': 'Our knowledgeable staff is trained to provide exceptional service and assistance.'
|
||||
},
|
||||
{
|
||||
'icon': 'globe',
|
||||
'title': 'Multiple Languages',
|
||||
'description': 'We speak your language. Our team is fluent in multiple languages to serve international guests.'
|
||||
}
|
||||
]),
|
||||
'features_section_title': 'Why Contact Us',
|
||||
'features_section_subtitle': 'We\'re committed to providing exceptional service',
|
||||
'gallery_images': json.dumps([
|
||||
'https://images.unsplash.com/photo-1556761175-5973dc0f32e7?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?w=1200&h=800&fit=crop'
|
||||
]),
|
||||
'gallery_section_title': 'Visit Our Hotel',
|
||||
'gallery_section_subtitle': 'Experience our luxury facilities',
|
||||
'is_active': True,
|
||||
'created_at': now,
|
||||
'updated_at': now
|
||||
}
|
||||
|
||||
|
||||
def seed_contact_page(db: Session):
|
||||
"""Seed contact page content into the database"""
|
||||
try:
|
||||
contact_data = get_contact_page_data()
|
||||
|
||||
# Check if contact page content already exists
|
||||
existing_content = db.query(PageContent).filter(PageContent.page_type == PageType.CONTACT).first()
|
||||
|
||||
if existing_content:
|
||||
logger.info('Updating existing contact page content...')
|
||||
for key, value in contact_data.items():
|
||||
if key not in ['id', 'page_type', 'created_at']: # Don't update primary key or creation date
|
||||
setattr(existing_content, key, value)
|
||||
existing_content.updated_at = datetime.now(timezone.utc)
|
||||
else:
|
||||
logger.info('Creating new contact page content...')
|
||||
contact_page = PageContent(**contact_data)
|
||||
db.add(contact_page)
|
||||
|
||||
db.commit()
|
||||
logger.info('Contact page content seeded successfully!')
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error seeding contact page: {str(e)}', exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
seed_contact_page(db)
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed contact page: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
192
Backend/seeders/faq_seeder.py
Normal file
192
Backend/seeders/faq_seeder.py
Normal file
@@ -0,0 +1,192 @@
|
||||
"""
|
||||
FAQ Page Seeder
|
||||
Seeds the database with comprehensive FAQ content
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
|
||||
# Add parent directory to path to allow importing from src
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal
|
||||
from src.shared.config.logging_config import get_logger
|
||||
from src.content.models.page_content import PageContent, PageType
|
||||
|
||||
# Import all models to ensure relationships are loaded
|
||||
from src.models import *
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_faq_page_data():
|
||||
"""Generate comprehensive FAQ page data"""
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
return {
|
||||
'page_type': PageType.FAQ,
|
||||
'title': 'Frequently Asked Questions',
|
||||
'subtitle': 'Find Answers to Common Questions',
|
||||
'description': 'Get answers to the most frequently asked questions about our hotel, reservations, services, and policies.',
|
||||
'content': """
|
||||
<h2>General Questions</h2>
|
||||
|
||||
<h3>What are your check-in and check-out times?</h3>
|
||||
<p>Check-in time is 3:00 PM, and check-out time is 11:00 AM. Early check-in and late check-out may be available upon request, subject to availability and additional charges.</p>
|
||||
|
||||
<h3>Do you offer airport transportation?</h3>
|
||||
<p>Yes, we offer airport transfer services. Please contact our concierge team at least 24 hours in advance to arrange transportation. Additional charges may apply.</p>
|
||||
|
||||
<h3>Is parking available?</h3>
|
||||
<p>Yes, we offer complimentary valet parking for all hotel guests. Self-parking is also available at an additional charge.</p>
|
||||
|
||||
<h3>Do you have a fitness center?</h3>
|
||||
<p>Yes, our state-of-the-art fitness center is open 24/7 and is complimentary for all hotel guests. We also offer personal training sessions upon request.</p>
|
||||
|
||||
<h3>Is Wi-Fi available?</h3>
|
||||
<p>Yes, complimentary high-speed Wi-Fi is available throughout the hotel, including all guest rooms and public areas.</p>
|
||||
|
||||
<h2>Reservations & Booking</h2>
|
||||
|
||||
<h3>How do I make a reservation?</h3>
|
||||
<p>You can make a reservation through our website, by calling our reservations team at +1 (555) 123-4567, or by emailing reservations@luxuryhotel.com.</p>
|
||||
|
||||
<h3>Can I modify or cancel my reservation?</h3>
|
||||
<p>Yes, you can modify or cancel your reservation through our website or by contacting our reservations team. Please refer to our cancellation policy for details on refunds and fees.</p>
|
||||
|
||||
<h3>What payment methods do you accept?</h3>
|
||||
<p>We accept all major credit cards (Visa, MasterCard, American Express, Discover), debit cards, and bank transfers. Cash payments are also accepted at check-in.</p>
|
||||
|
||||
<h3>Do you require a deposit?</h3>
|
||||
<p>A credit card is required to guarantee your reservation. A deposit may be required for certain room types or during peak seasons. Details will be provided at the time of booking.</p>
|
||||
|
||||
<h3>Can I book for someone else?</h3>
|
||||
<p>Yes, you can make a reservation for another guest. Please provide the guest's name and contact information at the time of booking, and ensure they have a valid ID for check-in.</p>
|
||||
|
||||
<h2>Rooms & Accommodations</h2>
|
||||
|
||||
<h3>What amenities are included in the rooms?</h3>
|
||||
<p>All rooms include complimentary Wi-Fi, flat-screen TV, minibar, coffee maker, in-room safe, air conditioning, and luxury toiletries. Suites include additional amenities such as separate living areas and premium services.</p>
|
||||
|
||||
<h3>Do you have connecting rooms?</h3>
|
||||
<p>Yes, we have connecting rooms available. Please request connecting rooms at the time of booking, and we will do our best to accommodate your request based on availability.</p>
|
||||
|
||||
<h3>Are rooms accessible for guests with disabilities?</h3>
|
||||
<p>Yes, we have accessible rooms designed to meet ADA requirements. Please inform us of any specific accessibility needs when making your reservation.</p>
|
||||
|
||||
<h3>Can I request a specific room or floor?</h3>
|
||||
<p>Yes, you can request a specific room or floor preference. While we cannot guarantee specific rooms, we will do our best to honor your request based on availability.</p>
|
||||
|
||||
<h3>Do you allow pets?</h3>
|
||||
<p>We welcome service animals. For pets, please contact us in advance as pet-friendly rooms are limited and additional charges may apply.</p>
|
||||
|
||||
<h2>Services & Amenities</h2>
|
||||
|
||||
<h3>Do you have a spa?</h3>
|
||||
<p>Yes, we have a world-class spa offering a variety of treatments. Advance reservations are recommended. Please contact our spa directly to book treatments.</p>
|
||||
|
||||
<h3>Are there restaurants on-site?</h3>
|
||||
<p>Yes, we have multiple dining options including fine dining, casual restaurants, and room service available 24/7. Our restaurants feature award-winning cuisine and extensive wine selections.</p>
|
||||
|
||||
<h3>Do you offer room service?</h3>
|
||||
<p>Yes, room service is available 24 hours a day. Our extensive menu includes breakfast, lunch, dinner, and late-night options.</p>
|
||||
|
||||
<h3>Is there a business center?</h3>
|
||||
<p>Yes, our business center is equipped with computers, printers, and meeting facilities. It is available 24/7 for all guests.</p>
|
||||
|
||||
<h3>Do you have meeting and event facilities?</h3>
|
||||
<p>Yes, we have versatile meeting and event spaces suitable for conferences, weddings, and other special occasions. Please contact our events team for more information.</p>
|
||||
|
||||
<h2>Policies & Procedures</h2>
|
||||
|
||||
<h3>What is your cancellation policy?</h3>
|
||||
<p>Cancellation policies vary by rate type and booking. Generally, cancellations made 24-48 hours before check-in are free. Please refer to your booking confirmation for specific cancellation terms.</p>
|
||||
|
||||
<h3>What is your smoking policy?</h3>
|
||||
<p>Our hotel is 100% non-smoking. Smoking is not permitted in any guest rooms or indoor public areas. Designated outdoor smoking areas are available.</p>
|
||||
|
||||
<h3>What is the minimum age to check in?</h3>
|
||||
<p>Guests must be at least 18 years old to check in. Guests under 18 must be accompanied by an adult.</p>
|
||||
|
||||
<h3>Do you have a lost and found?</h3>
|
||||
<p>Yes, we maintain a lost and found department. If you have lost an item, please contact our front desk immediately. We will make every effort to locate and return your belongings.</p>
|
||||
|
||||
<h2>Special Requests</h2>
|
||||
|
||||
<h3>Can I request early check-in or late check-out?</h3>
|
||||
<p>Early check-in and late check-out are subject to availability. Please contact us in advance, and we will do our best to accommodate your request. Additional charges may apply.</p>
|
||||
|
||||
<h3>Do you accommodate special dietary requirements?</h3>
|
||||
<p>Yes, we can accommodate various dietary requirements including vegetarian, vegan, gluten-free, and allergies. Please inform us of any dietary restrictions when making your reservation or dining reservation.</p>
|
||||
|
||||
<h3>Can you help arrange special occasions?</h3>
|
||||
<p>Absolutely! Our concierge team can help arrange special occasions such as anniversaries, birthdays, or proposals. Please contact us in advance to discuss your needs.</p>
|
||||
|
||||
<h2>Contact & Support</h2>
|
||||
|
||||
<h3>How can I contact the hotel?</h3>
|
||||
<p>You can reach us by phone at +1 (555) 123-4567, email at info@luxuryhotel.com, or through our website's contact form. Our front desk is available 24/7.</p>
|
||||
|
||||
<h3>Do you have a loyalty program?</h3>
|
||||
<p>Yes, we offer a loyalty program with exclusive benefits including room upgrades, late check-out, and special rates. Membership is free. Please visit our website or contact us for more information.</p>
|
||||
|
||||
<h3>Can I leave feedback about my stay?</h3>
|
||||
<p>We value your feedback! You can leave a review on our website, through our post-stay survey, or by contacting our guest relations team directly.</p>
|
||||
""",
|
||||
'meta_title': 'FAQ | Frequently Asked Questions - Luxury Hotel & Resort',
|
||||
'meta_description': 'Find answers to frequently asked questions about reservations, rooms, services, and policies at Luxury Hotel & Resort.',
|
||||
'meta_keywords': 'FAQ, frequently asked questions, hotel questions, booking questions, hotel policies, hotel information',
|
||||
'og_title': 'FAQ - Luxury Hotel & Resort',
|
||||
'og_description': 'Find answers to common questions about our hotel, reservations, and services.',
|
||||
'og_image': 'https://images.unsplash.com/photo-1556761175-5973dc0f32e7?w=1200&h=630&fit=crop',
|
||||
'canonical_url': 'https://luxuryhotel.com/faq',
|
||||
'is_active': True,
|
||||
'created_at': now,
|
||||
'updated_at': now
|
||||
}
|
||||
|
||||
|
||||
def seed_faq_page(db: Session):
|
||||
"""Seed FAQ page content into the database"""
|
||||
try:
|
||||
faq_data = get_faq_page_data()
|
||||
|
||||
# Check if FAQ page content already exists
|
||||
existing_content = db.query(PageContent).filter(PageContent.page_type == PageType.FAQ).first()
|
||||
|
||||
if existing_content:
|
||||
logger.info('Updating existing FAQ page content...')
|
||||
for key, value in faq_data.items():
|
||||
if key not in ['id', 'page_type', 'created_at']:
|
||||
setattr(existing_content, key, value)
|
||||
existing_content.updated_at = datetime.now(timezone.utc)
|
||||
else:
|
||||
logger.info('Creating new FAQ page content...')
|
||||
faq_page = PageContent(**faq_data)
|
||||
db.add(faq_page)
|
||||
|
||||
db.commit()
|
||||
logger.info('FAQ page content seeded successfully!')
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error seeding FAQ page: {str(e)}', exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
seed_faq_page(db)
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed FAQ page: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
173
Backend/seeders/footer_seeder.py
Normal file
173
Backend/seeders/footer_seeder.py
Normal file
@@ -0,0 +1,173 @@
|
||||
"""
|
||||
Footer Page Seeder
|
||||
Seeds the database with comprehensive footer content
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
|
||||
# Add parent directory to path to allow importing from src
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal
|
||||
from src.shared.config.logging_config import get_logger
|
||||
from src.content.models.page_content import PageContent, PageType
|
||||
|
||||
# Import all models to ensure relationships are loaded
|
||||
from src.models import *
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_footer_page_data():
|
||||
"""Generate comprehensive footer page data"""
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
return {
|
||||
'page_type': PageType.FOOTER,
|
||||
'title': 'Luxury Hotel & Resort',
|
||||
'subtitle': 'Experience Unparalleled Elegance and Comfort',
|
||||
'description': 'Your premier destination for luxury hospitality. Experience world-class service, exquisite accommodations, and unforgettable moments.',
|
||||
'content': '<p>For over three decades, we have been crafting exceptional experiences for discerning travelers worldwide. Our commitment to excellence and attention to detail sets us apart.</p>',
|
||||
'social_links': json.dumps({
|
||||
'facebook': 'https://facebook.com/luxuryhotel',
|
||||
'twitter': 'https://twitter.com/luxuryhotel',
|
||||
'instagram': 'https://instagram.com/luxuryhotel',
|
||||
'linkedin': 'https://linkedin.com/company/luxuryhotel',
|
||||
'youtube': 'https://youtube.com/luxuryhotel',
|
||||
'pinterest': 'https://pinterest.com/luxuryhotel'
|
||||
}),
|
||||
'footer_links': json.dumps({
|
||||
'quick_links': [
|
||||
{'label': 'Home', 'url': '/'},
|
||||
{'label': 'About Us', 'url': '/about'},
|
||||
{'label': 'Rooms & Suites', 'url': '/rooms'},
|
||||
{'label': 'Services', 'url': '/services'},
|
||||
{'label': 'Contact', 'url': '/contact'},
|
||||
{'label': 'Blog', 'url': '/blog'}
|
||||
],
|
||||
'accommodations': [
|
||||
{'label': 'Standard Rooms', 'url': '/rooms?type=standard'},
|
||||
{'label': 'Deluxe Rooms', 'url': '/rooms?type=deluxe'},
|
||||
{'label': 'Executive Suites', 'url': '/rooms?type=executive'},
|
||||
{'label': 'Presidential Suites', 'url': '/rooms?type=presidential'},
|
||||
{'label': 'Ocean View Rooms', 'url': '/rooms?type=ocean-view'},
|
||||
{'label': 'Family Rooms', 'url': '/rooms?type=family'}
|
||||
],
|
||||
'services': [
|
||||
{'label': 'Spa & Wellness', 'url': '/services?category=spa'},
|
||||
{'label': 'Fine Dining', 'url': '/services?category=dining'},
|
||||
{'label': 'Concierge', 'url': '/services?category=concierge'},
|
||||
{'label': 'Business Center', 'url': '/services?category=business'},
|
||||
{'label': 'Event Planning', 'url': '/services?category=events'},
|
||||
{'label': 'Transportation', 'url': '/services?category=transportation'}
|
||||
],
|
||||
'information': [
|
||||
{'label': 'About Us', 'url': '/about'},
|
||||
{'label': 'Our Story', 'url': '/about#story'},
|
||||
{'label': 'Awards & Recognition', 'url': '/about#awards'},
|
||||
{'label': 'Careers', 'url': '/careers'},
|
||||
{'label': 'Press & Media', 'url': '/press'},
|
||||
{'label': 'Blog', 'url': '/blog'}
|
||||
],
|
||||
'support_links': [
|
||||
{'label': 'Contact Us', 'url': '/contact'},
|
||||
{'label': 'FAQ', 'url': '/faq'},
|
||||
{'label': 'Booking Help', 'url': '/help'},
|
||||
{'label': 'Cancellation Policy', 'url': '/cancellation'},
|
||||
{'label': 'Privacy Policy', 'url': '/privacy'},
|
||||
{'label': 'Terms & Conditions', 'url': '/terms'},
|
||||
{'label': 'Refund Policy', 'url': '/refunds'},
|
||||
{'label': 'Accessibility', 'url': '/accessibility'}
|
||||
]
|
||||
}),
|
||||
'badges': json.dumps([
|
||||
{
|
||||
'icon': 'award',
|
||||
'text': '5-Star Rated',
|
||||
'description': 'Consistently rated five-star by global travel guides'
|
||||
},
|
||||
{
|
||||
'icon': 'trophy',
|
||||
'text': 'Award Winning',
|
||||
'description': 'Best Luxury Hotel 2023'
|
||||
},
|
||||
{
|
||||
'icon': 'shield',
|
||||
'text': 'Secure Booking',
|
||||
'description': 'Your data and payments are protected'
|
||||
},
|
||||
{
|
||||
'icon': 'star',
|
||||
'text': '98% Satisfaction',
|
||||
'description': 'Guest satisfaction rating'
|
||||
},
|
||||
{
|
||||
'icon': 'leaf',
|
||||
'text': 'Eco-Friendly',
|
||||
'description': 'Certified green hotel'
|
||||
},
|
||||
{
|
||||
'icon': 'check-circle',
|
||||
'text': 'Best Price Guarantee',
|
||||
'description': 'We guarantee the best rates'
|
||||
}
|
||||
]),
|
||||
'copyright_text': f'© {datetime.now(timezone.utc).year} Luxury Hotel & Resort. All rights reserved.',
|
||||
'contact_info': json.dumps({
|
||||
'phone': '+1 (555) 123-4567',
|
||||
'toll_free': '+1 (800) 123-4567',
|
||||
'email': 'info@luxuryhotel.com',
|
||||
'reservations_email': 'reservations@luxuryhotel.com',
|
||||
'address': '123 Luxury Avenue, Premium City, PC 12345, United States'
|
||||
}),
|
||||
'is_active': True,
|
||||
'created_at': now,
|
||||
'updated_at': now
|
||||
}
|
||||
|
||||
|
||||
def seed_footer_page(db: Session):
|
||||
"""Seed footer page content into the database"""
|
||||
try:
|
||||
footer_data = get_footer_page_data()
|
||||
|
||||
# Check if footer page content already exists
|
||||
existing_content = db.query(PageContent).filter(PageContent.page_type == PageType.FOOTER).first()
|
||||
|
||||
if existing_content:
|
||||
logger.info('Updating existing footer page content...')
|
||||
for key, value in footer_data.items():
|
||||
if key not in ['id', 'page_type', 'created_at']: # Don't update primary key or creation date
|
||||
setattr(existing_content, key, value)
|
||||
existing_content.updated_at = datetime.now(timezone.utc)
|
||||
else:
|
||||
logger.info('Creating new footer page content...')
|
||||
footer_page = PageContent(**footer_data)
|
||||
db.add(footer_page)
|
||||
|
||||
db.commit()
|
||||
logger.info('Footer page content seeded successfully!')
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error seeding footer page: {str(e)}', exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
seed_footer_page(db)
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed footer page: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
596
Backend/seeders/homepage_seeder.py
Normal file
596
Backend/seeders/homepage_seeder.py
Normal file
@@ -0,0 +1,596 @@
|
||||
"""
|
||||
Homepage Seeder
|
||||
Seeds the homepage with comprehensive content including images from Unsplash
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
|
||||
# Add parent directory to path to import modules
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal, engine
|
||||
from src.content.models.page_content import PageContent, PageType
|
||||
from src.shared.config.logging_config import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_homepage_data():
|
||||
"""Generate comprehensive homepage data with Unsplash images"""
|
||||
|
||||
# Using Unsplash Source API for images (free, no API key needed)
|
||||
# Format: https://source.unsplash.com/{width}x{height}/?{keywords}
|
||||
|
||||
return {
|
||||
'page_type': PageType.HOME,
|
||||
'title': 'Luxury Hotel & Resort',
|
||||
'subtitle': 'Experience Unparalleled Elegance and Comfort',
|
||||
'description': 'Welcome to our world-class luxury hotel where exceptional service meets breathtaking elegance. Discover a sanctuary of sophistication and comfort.',
|
||||
'content': '<p>Experience the pinnacle of luxury hospitality at our award-winning hotel. Nestled in a prime location, we offer world-class amenities, exquisite dining, and unparalleled service that creates unforgettable memories.</p>',
|
||||
|
||||
# SEO Meta Tags
|
||||
'meta_title': 'Luxury Hotel & Resort | Premium Accommodation & World-Class Service',
|
||||
'meta_description': 'Discover luxury accommodation with world-class amenities, fine dining, and exceptional service. Book your stay at our award-winning hotel today.',
|
||||
'meta_keywords': 'luxury hotel, resort, premium accommodation, fine dining, spa, business hotel, vacation, travel',
|
||||
'og_title': 'Luxury Hotel & Resort - Experience Unparalleled Elegance',
|
||||
'og_description': 'Welcome to our world-class luxury hotel where exceptional service meets breathtaking elegance.',
|
||||
'og_image': 'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1200&h=630&fit=crop',
|
||||
'canonical_url': 'https://luxuryhotel.com',
|
||||
|
||||
# Hero Section
|
||||
'hero_title': 'Welcome to Luxury Redefined',
|
||||
'hero_subtitle': 'Where Every Moment Becomes a Memory',
|
||||
'hero_image': 'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1920&h=1080&fit=crop',
|
||||
'hero_video_url': None,
|
||||
'hero_video_poster': None,
|
||||
|
||||
# Story Content
|
||||
'story_content': '<p>For over three decades, we have been crafting exceptional experiences for our guests. Our commitment to excellence, attention to detail, and passion for hospitality has made us a destination of choice for discerning travelers worldwide.</p>',
|
||||
|
||||
# Values Section
|
||||
'values': json.dumps([
|
||||
{
|
||||
'icon': 'heart',
|
||||
'title': 'Excellence',
|
||||
'description': 'We strive for perfection in every detail, ensuring your experience exceeds expectations.'
|
||||
},
|
||||
{
|
||||
'icon': 'shield',
|
||||
'title': 'Trust',
|
||||
'description': 'Your comfort and security are our top priorities, backed by years of trusted service.'
|
||||
},
|
||||
{
|
||||
'icon': 'users',
|
||||
'title': 'Hospitality',
|
||||
'description': 'Our dedicated team is committed to making your stay memorable and delightful.'
|
||||
},
|
||||
{
|
||||
'icon': 'award',
|
||||
'title': 'Quality',
|
||||
'description': 'We maintain the highest standards in service, amenities, and guest satisfaction.'
|
||||
}
|
||||
]),
|
||||
|
||||
# Features Section
|
||||
'features_section_title': 'Why Choose Us',
|
||||
'features_section_subtitle': 'Discover what makes us the perfect choice for your stay',
|
||||
'features': json.dumps([
|
||||
{
|
||||
'icon': 'wifi',
|
||||
'title': 'Free High-Speed WiFi',
|
||||
'description': 'Stay connected with complimentary high-speed internet throughout the property.',
|
||||
'image': 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=800&h=600&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'utensils',
|
||||
'title': 'Fine Dining',
|
||||
'description': 'Savor exquisite cuisine at our award-winning restaurants and bars.',
|
||||
'image': 'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=800&h=600&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'spa',
|
||||
'title': 'Luxury Spa',
|
||||
'description': 'Rejuvenate your mind and body at our world-class spa and wellness center.',
|
||||
'image': 'https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=800&h=600&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'dumbbell',
|
||||
'title': 'Fitness Center',
|
||||
'description': 'Maintain your workout routine in our state-of-the-art fitness facility.',
|
||||
'image': 'https://images.unsplash.com/photo-1534438327276-14e5300c3a48?w=800&h=600&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'swimming-pool',
|
||||
'title': 'Swimming Pool',
|
||||
'description': 'Relax and unwind in our stunning outdoor and indoor pools.',
|
||||
'image': 'https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=800&h=600&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'car',
|
||||
'title': 'Valet Parking',
|
||||
'description': 'Complimentary valet parking service for all our guests.',
|
||||
'image': 'https://images.unsplash.com/photo-1502877338535-766e1452684a?w=800&h=600&fit=crop'
|
||||
}
|
||||
]),
|
||||
|
||||
# About Preview Section
|
||||
'about_preview_title': 'Our Story',
|
||||
'about_preview_subtitle': 'A Legacy of Excellence',
|
||||
'about_preview_content': '<p>Since our founding, we have been dedicated to providing exceptional hospitality experiences. Our commitment to excellence, combined with our passion for service, has established us as a leader in the luxury hospitality industry.</p>',
|
||||
'about_preview_image': 'https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?w=1200&h=800&fit=crop',
|
||||
|
||||
# Stats Section
|
||||
'stats_section_title': 'Our Achievements',
|
||||
'stats_section_subtitle': 'Numbers that speak for themselves',
|
||||
'stats': json.dumps([
|
||||
{
|
||||
'number': '50000+',
|
||||
'label': 'Happy Guests',
|
||||
'icon': 'users'
|
||||
},
|
||||
{
|
||||
'number': '30+',
|
||||
'label': 'Years of Excellence',
|
||||
'icon': 'calendar'
|
||||
},
|
||||
{
|
||||
'number': '150+',
|
||||
'label': 'Awards Won',
|
||||
'icon': 'award'
|
||||
},
|
||||
{
|
||||
'number': '98%',
|
||||
'label': 'Guest Satisfaction',
|
||||
'icon': 'star'
|
||||
}
|
||||
]),
|
||||
|
||||
# Rooms Section
|
||||
'rooms_section_title': 'Luxurious Accommodations',
|
||||
'rooms_section_subtitle': 'Elegant rooms and suites designed for your comfort',
|
||||
'rooms_section_button_text': 'View All Rooms',
|
||||
'rooms_section_button_link': '/rooms',
|
||||
'rooms_section_enabled': True,
|
||||
|
||||
# Luxury Services Section
|
||||
'luxury_services_section_title': 'Premium Services',
|
||||
'luxury_services_section_subtitle': 'Indulge in our exclusive offerings',
|
||||
'services_section_button_text': 'Explore Services',
|
||||
'services_section_button_link': '/services',
|
||||
'services_section_limit': 6,
|
||||
'luxury_services': json.dumps([
|
||||
{
|
||||
'icon': 'concierge',
|
||||
'title': '24/7 Concierge',
|
||||
'description': 'Our dedicated concierge team is available around the clock to assist with any request.',
|
||||
'image': 'https://images.unsplash.com/photo-1556761175-5973dc0f32e7?w=600&h=400&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'plane',
|
||||
'title': 'Airport Transfer',
|
||||
'description': 'Complimentary airport transfer service for a seamless arrival experience.',
|
||||
'image': 'https://images.unsplash.com/photo-1449824913935-59a10b8d2000?w=600&h=400&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'briefcase',
|
||||
'title': 'Business Center',
|
||||
'description': 'Fully equipped business center with meeting rooms and conference facilities.',
|
||||
'image': 'https://images.unsplash.com/photo-1497366216548-37526070297c?w=600&h=400&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'wine',
|
||||
'title': 'Wine Cellar',
|
||||
'description': 'Explore our extensive collection of fine wines from around the world.',
|
||||
'image': 'https://images.unsplash.com/photo-1510812431401-41d2bd2722f3?w=600&h=400&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'music',
|
||||
'title': 'Live Entertainment',
|
||||
'description': 'Enjoy live music and entertainment in our elegant lounge areas.',
|
||||
'image': 'https://images.unsplash.com/photo-1493225457124-a3eb161ffa5f?w=600&h=400&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'gift',
|
||||
'title': 'Gift Shop',
|
||||
'description': 'Browse our curated selection of luxury gifts and souvenirs.',
|
||||
'image': 'https://images.unsplash.com/photo-1441986300917-64674bd600d8?w=600&h=400&fit=crop'
|
||||
}
|
||||
]),
|
||||
|
||||
# Luxury Experiences Section
|
||||
'luxury_experiences_section_title': 'Unique Experiences',
|
||||
'luxury_experiences_section_subtitle': 'Create unforgettable memories with our curated experiences',
|
||||
'luxury_experiences': json.dumps([
|
||||
{
|
||||
'icon': 'sunset',
|
||||
'title': 'Sunset Rooftop Dining',
|
||||
'description': 'Dine under the stars with panoramic city views and gourmet cuisine.',
|
||||
'image': 'https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=800&h=600&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'compass',
|
||||
'title': 'City Tours',
|
||||
'description': 'Explore the city with our guided tours showcasing local culture and landmarks.',
|
||||
'image': 'https://images.unsplash.com/photo-1488646953014-85cb44e25828?w=800&h=600&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'camera',
|
||||
'title': 'Photography Sessions',
|
||||
'description': 'Capture your special moments with our professional photography services.',
|
||||
'image': 'https://images.unsplash.com/photo-1516035069371-29a1b244cc32?w=800&h=600&fit=crop'
|
||||
}
|
||||
]),
|
||||
|
||||
# Amenities Section
|
||||
'amenities_section_title': 'World-Class Amenities',
|
||||
'amenities_section_subtitle': 'Everything you need for a perfect stay',
|
||||
'amenities': json.dumps([
|
||||
{
|
||||
'icon': 'wifi',
|
||||
'title': 'Free WiFi',
|
||||
'description': 'High-speed internet access throughout the property'
|
||||
},
|
||||
{
|
||||
'icon': 'tv',
|
||||
'title': 'Smart TV',
|
||||
'description': 'Streaming services and premium channels in every room'
|
||||
},
|
||||
{
|
||||
'icon': 'coffee',
|
||||
'title': 'Coffee Maker',
|
||||
'description': 'Premium coffee and tea making facilities'
|
||||
},
|
||||
{
|
||||
'icon': 'snowflake',
|
||||
'title': 'Climate Control',
|
||||
'description': 'Individual temperature control in all rooms'
|
||||
},
|
||||
{
|
||||
'icon': 'lock',
|
||||
'title': 'Safe',
|
||||
'description': 'In-room safe for your valuables'
|
||||
},
|
||||
{
|
||||
'icon': 'shirt',
|
||||
'title': 'Laundry Service',
|
||||
'description': 'Professional laundry and dry cleaning services'
|
||||
}
|
||||
]),
|
||||
|
||||
# Testimonials Section
|
||||
'testimonials_section_title': 'What Our Guests Say',
|
||||
'testimonials_section_subtitle': 'Real experiences from real guests',
|
||||
'testimonials': json.dumps([
|
||||
{
|
||||
'name': 'Sarah Johnson',
|
||||
'title': 'Business Traveler',
|
||||
'quote': 'The service was exceptional and the rooms were immaculate. This hotel exceeded all my expectations.',
|
||||
'rating': 5,
|
||||
'image': 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=200&h=200&fit=crop&crop=face'
|
||||
},
|
||||
{
|
||||
'name': 'Michael Chen',
|
||||
'title': 'Honeymooner',
|
||||
'quote': 'Our honeymoon was made perfect by the attentive staff and beautiful accommodations. Truly unforgettable!',
|
||||
'rating': 5,
|
||||
'image': 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=200&h=200&fit=crop&crop=face'
|
||||
},
|
||||
{
|
||||
'name': 'Emily Rodriguez',
|
||||
'title': 'Family Vacation',
|
||||
'quote': 'Perfect for families! The kids loved the pool and the staff was so accommodating. We will definitely return.',
|
||||
'rating': 5,
|
||||
'image': 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=200&h=200&fit=crop&crop=face'
|
||||
},
|
||||
{
|
||||
'name': 'David Thompson',
|
||||
'title': 'Luxury Traveler',
|
||||
'quote': 'The attention to detail and level of service is unmatched. This is what luxury hospitality should be.',
|
||||
'rating': 5,
|
||||
'image': 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=200&h=200&fit=crop&crop=face'
|
||||
}
|
||||
]),
|
||||
|
||||
# Gallery Section
|
||||
'gallery_section_title': 'Photo Gallery',
|
||||
'gallery_section_subtitle': 'A glimpse into our world of luxury',
|
||||
'gallery_images': json.dumps([
|
||||
'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1542314831-068cd1dbfeeb?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1611892440504-42a792e24d32?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1578683010236-d716f9a3f461?w=1200&h=800&fit=crop'
|
||||
]),
|
||||
|
||||
# Luxury Section
|
||||
'luxury_section_title': 'Luxury Redefined',
|
||||
'luxury_section_subtitle': 'Experience the epitome of elegance and sophistication',
|
||||
'luxury_section_image': 'https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1400&h=900&fit=crop',
|
||||
'luxury_features': json.dumps([
|
||||
{
|
||||
'icon': 'crown',
|
||||
'title': 'Royal Treatment',
|
||||
'description': 'Experience service fit for royalty with our personalized attention to every detail.'
|
||||
},
|
||||
{
|
||||
'icon': 'gem',
|
||||
'title': 'Premium Quality',
|
||||
'description': 'Only the finest materials and furnishings grace our elegant spaces.'
|
||||
},
|
||||
{
|
||||
'icon': 'sparkles',
|
||||
'title': 'Exclusive Access',
|
||||
'description': 'Enjoy exclusive access to private lounges and premium facilities.'
|
||||
}
|
||||
]),
|
||||
|
||||
# Luxury Gallery Section
|
||||
'luxury_gallery_section_title': 'Luxury Gallery',
|
||||
'luxury_gallery_section_subtitle': 'Discover our world of refined elegance',
|
||||
'luxury_gallery': json.dumps([
|
||||
'https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1596394516093-501ba68a0ba6?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop'
|
||||
]),
|
||||
|
||||
# Luxury Testimonials Section
|
||||
'luxury_testimonials_section_title': 'Guest Experiences',
|
||||
'luxury_testimonials_section_subtitle': 'Stories from our valued guests',
|
||||
'luxury_testimonials': json.dumps([
|
||||
{
|
||||
'name': 'James Wilson',
|
||||
'title': 'VIP Guest',
|
||||
'quote': 'The level of luxury and attention to detail is simply extraordinary. This is hospitality at its finest.',
|
||||
'image': 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=200&h=200&fit=crop&crop=face'
|
||||
},
|
||||
{
|
||||
'name': 'Maria Garcia',
|
||||
'title': 'Celebrity Guest',
|
||||
'quote': 'Privacy, elegance, and impeccable service. This hotel understands true luxury.',
|
||||
'image': 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=200&h=200&fit=crop&crop=face'
|
||||
}
|
||||
]),
|
||||
|
||||
# Awards Section
|
||||
'awards_section_title': 'Awards & Recognition',
|
||||
'awards_section_subtitle': 'Recognized for excellence in hospitality',
|
||||
'awards': json.dumps([
|
||||
{
|
||||
'icon': 'trophy',
|
||||
'title': 'Best Luxury Hotel 2023',
|
||||
'description': 'Awarded by International Hospitality Association',
|
||||
'year': '2023',
|
||||
'image': 'https://images.unsplash.com/photo-1606761568499-6d2451b23c66?w=400&h=400&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'star',
|
||||
'title': '5-Star Rating',
|
||||
'description': 'Consistently rated 5 stars by leading travel organizations',
|
||||
'year': '2023',
|
||||
'image': 'https://images.unsplash.com/photo-1519389950473-47ba0277781c?w=400&h=400&fit=crop'
|
||||
},
|
||||
{
|
||||
'icon': 'award',
|
||||
'title': 'Excellence in Service',
|
||||
'description': 'Recognized for outstanding customer service and guest satisfaction',
|
||||
'year': '2022',
|
||||
'image': 'https://images.unsplash.com/photo-1579621970563-ebec7560ff3e?w=400&h=400&fit=crop'
|
||||
}
|
||||
]),
|
||||
|
||||
# Partners Section
|
||||
'partners_section_title': 'Our Partners',
|
||||
'partners_section_subtitle': 'Trusted by leading brands and organizations',
|
||||
'partners': json.dumps([
|
||||
{
|
||||
'name': 'Travel Partner',
|
||||
'logo': 'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=200&h=100&fit=crop',
|
||||
'url': '#'
|
||||
},
|
||||
{
|
||||
'name': 'Luxury Brand',
|
||||
'logo': 'https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?w=200&h=100&fit=crop',
|
||||
'url': '#'
|
||||
},
|
||||
{
|
||||
'name': 'Hospitality Group',
|
||||
'logo': 'https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=200&h=100&fit=crop',
|
||||
'url': '#'
|
||||
}
|
||||
]),
|
||||
|
||||
# CTA Section
|
||||
'cta_title': 'Ready to Experience Luxury?',
|
||||
'cta_subtitle': 'Book your stay today and discover why we are the preferred choice for discerning travelers',
|
||||
'cta_button_text': 'Book Now',
|
||||
'cta_button_link': '/book',
|
||||
'cta_image': 'https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1400&h=700&fit=crop',
|
||||
|
||||
# Newsletter Section
|
||||
'newsletter_section_title': 'Stay Connected',
|
||||
'newsletter_section_subtitle': 'Subscribe to our newsletter for exclusive offers and updates',
|
||||
'newsletter_placeholder': 'Enter your email address',
|
||||
'newsletter_button_text': 'Subscribe',
|
||||
'newsletter_enabled': True,
|
||||
|
||||
# Trust Badges Section
|
||||
'trust_badges_section_title': 'Why Trust Us',
|
||||
'trust_badges_section_subtitle': 'Your peace of mind is our priority',
|
||||
'trust_badges_enabled': True,
|
||||
'trust_badges': json.dumps([
|
||||
{
|
||||
'icon': 'shield-check',
|
||||
'title': 'Secure Booking',
|
||||
'description': 'Your data and payments are protected with industry-leading security'
|
||||
},
|
||||
{
|
||||
'icon': 'clock',
|
||||
'title': '24/7 Support',
|
||||
'description': 'Round-the-clock customer support for all your needs'
|
||||
},
|
||||
{
|
||||
'icon': 'undo',
|
||||
'title': 'Flexible Cancellation',
|
||||
'description': 'Free cancellation up to 24 hours before check-in'
|
||||
},
|
||||
{
|
||||
'icon': 'check-circle',
|
||||
'title': 'Best Price Guarantee',
|
||||
'description': 'We guarantee the best rates for your stay'
|
||||
}
|
||||
]),
|
||||
|
||||
# Promotions Section
|
||||
'promotions_section_title': 'Special Offers',
|
||||
'promotions_section_subtitle': 'Exclusive deals and packages for our guests',
|
||||
'promotions_enabled': True,
|
||||
'promotions': json.dumps([
|
||||
{
|
||||
'title': 'Early Bird Special',
|
||||
'description': 'Book 30 days in advance and save 20%',
|
||||
'discount': '20% OFF',
|
||||
'image': 'https://images.unsplash.com/photo-1566073771259-6a8506099945?w=800&h=600&fit=crop',
|
||||
'link': '/promotions/early-bird'
|
||||
},
|
||||
{
|
||||
'title': 'Weekend Getaway',
|
||||
'description': 'Perfect weekend escape with complimentary breakfast',
|
||||
'discount': '15% OFF',
|
||||
'image': 'https://images.unsplash.com/photo-1520250497591-112f2f40a3f4?w=800&h=600&fit=crop',
|
||||
'link': '/promotions/weekend'
|
||||
},
|
||||
{
|
||||
'title': 'Honeymoon Package',
|
||||
'description': 'Romantic getaway with special amenities and services',
|
||||
'discount': '25% OFF',
|
||||
'image': 'https://images.unsplash.com/photo-1571896349842-33c89424de2d?w=800&h=600&fit=crop',
|
||||
'link': '/promotions/honeymoon'
|
||||
}
|
||||
]),
|
||||
|
||||
# Blog Section
|
||||
'blog_section_title': 'Latest News & Updates',
|
||||
'blog_section_subtitle': 'Stay informed with our latest articles and hotel news',
|
||||
'blog_posts_limit': 3,
|
||||
'blog_enabled': True,
|
||||
|
||||
# Sections Enabled
|
||||
'sections_enabled': json.dumps({
|
||||
'hero': True,
|
||||
'features': True,
|
||||
'about_preview': True,
|
||||
'stats': True,
|
||||
'rooms': True,
|
||||
'services': True,
|
||||
'experiences': True,
|
||||
'amenities': True,
|
||||
'testimonials': True,
|
||||
'gallery': True,
|
||||
'luxury': True,
|
||||
'awards': True,
|
||||
'partners': True,
|
||||
'cta': True,
|
||||
'newsletter': True,
|
||||
'trust_badges': True,
|
||||
'promotions': True,
|
||||
'blog': True
|
||||
}),
|
||||
|
||||
# Badges
|
||||
'badges': json.dumps([
|
||||
{
|
||||
'text': '5-Star Rated',
|
||||
'icon': 'star'
|
||||
},
|
||||
{
|
||||
'text': 'Award Winning',
|
||||
'icon': 'award'
|
||||
},
|
||||
{
|
||||
'text': 'Eco-Friendly',
|
||||
'icon': 'leaf'
|
||||
}
|
||||
]),
|
||||
|
||||
# Social Links
|
||||
'social_links': json.dumps({
|
||||
'facebook': 'https://facebook.com/luxuryhotel',
|
||||
'twitter': 'https://twitter.com/luxuryhotel',
|
||||
'instagram': 'https://instagram.com/luxuryhotel',
|
||||
'linkedin': 'https://linkedin.com/company/luxuryhotel',
|
||||
'youtube': 'https://youtube.com/luxuryhotel'
|
||||
}),
|
||||
|
||||
# Contact Info
|
||||
'contact_info': json.dumps({
|
||||
'phone': '+1 (555) 123-4567',
|
||||
'email': 'info@luxuryhotel.com',
|
||||
'address': '123 Luxury Avenue, Premium City, PC 12345'
|
||||
}),
|
||||
|
||||
# Active Status
|
||||
'is_active': True,
|
||||
'created_at': datetime.now(timezone.utc),
|
||||
'updated_at': datetime.now(timezone.utc)
|
||||
}
|
||||
|
||||
|
||||
def seed_homepage(db: Session):
|
||||
"""Seed the homepage content"""
|
||||
try:
|
||||
# Check if homepage already exists
|
||||
existing = db.query(PageContent).filter(PageContent.page_type == PageType.HOME).first()
|
||||
|
||||
if existing:
|
||||
logger.info('Homepage content already exists. Updating...')
|
||||
# Update existing content
|
||||
data = get_homepage_data()
|
||||
for key, value in data.items():
|
||||
if key != 'page_type': # Don't update page_type
|
||||
setattr(existing, key, value)
|
||||
existing.updated_at = datetime.now(timezone.utc)
|
||||
db.commit()
|
||||
logger.info('Homepage content updated successfully!')
|
||||
return existing
|
||||
else:
|
||||
logger.info('Creating new homepage content...')
|
||||
# Create new content
|
||||
data = get_homepage_data()
|
||||
homepage = PageContent(**data)
|
||||
db.add(homepage)
|
||||
db.commit()
|
||||
db.refresh(homepage)
|
||||
logger.info('Homepage content created successfully!')
|
||||
return homepage
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f'Error seeding homepage: {str(e)}', exc_info=True)
|
||||
db.rollback()
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function to run the seeder"""
|
||||
logger.info('Starting homepage seeder...')
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
homepage = seed_homepage(db)
|
||||
logger.info(f'Homepage seeder completed successfully! ID: {homepage.id}')
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed homepage: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
172
Backend/seeders/privacy_seeder.py
Normal file
172
Backend/seeders/privacy_seeder.py
Normal file
@@ -0,0 +1,172 @@
|
||||
"""
|
||||
Privacy Policy Page Seeder
|
||||
Seeds the database with comprehensive privacy policy content
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
|
||||
# Add parent directory to path to allow importing from src
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal
|
||||
from src.shared.config.logging_config import get_logger
|
||||
from src.content.models.page_content import PageContent, PageType
|
||||
|
||||
# Import all models to ensure relationships are loaded
|
||||
from src.models import *
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_privacy_page_data():
|
||||
"""Generate comprehensive privacy policy page data"""
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
return {
|
||||
'page_type': PageType.PRIVACY,
|
||||
'title': 'Privacy Policy',
|
||||
'subtitle': 'Your Privacy Matters to Us',
|
||||
'description': 'Learn how we collect, use, and protect your personal information. We are committed to maintaining your privacy and ensuring the security of your data.',
|
||||
'content': """
|
||||
<h2>1. Introduction</h2>
|
||||
<p>At Luxury Hotel & Resort, we are committed to protecting your privacy and ensuring the security of your personal information. This Privacy Policy explains how we collect, use, disclose, and safeguard your information when you visit our website, make a reservation, or use our services.</p>
|
||||
|
||||
<h2>2. Information We Collect</h2>
|
||||
<h3>2.1 Personal Information</h3>
|
||||
<p>We may collect personal information that you provide directly to us, including:</p>
|
||||
<ul>
|
||||
<li>Name, email address, phone number, and mailing address</li>
|
||||
<li>Payment information (credit card details, billing address)</li>
|
||||
<li>Reservation details and preferences</li>
|
||||
<li>Identification documents (for check-in purposes)</li>
|
||||
<li>Special requests or dietary requirements</li>
|
||||
</ul>
|
||||
|
||||
<h3>2.2 Automatically Collected Information</h3>
|
||||
<p>When you visit our website, we may automatically collect certain information, including:</p>
|
||||
<ul>
|
||||
<li>IP address and browser type</li>
|
||||
<li>Device information and operating system</li>
|
||||
<li>Pages visited and time spent on our site</li>
|
||||
<li>Referring website addresses</li>
|
||||
<li>Cookies and similar tracking technologies</li>
|
||||
</ul>
|
||||
|
||||
<h2>3. How We Use Your Information</h2>
|
||||
<p>We use the information we collect for various purposes, including:</p>
|
||||
<ul>
|
||||
<li>Processing and managing your reservations</li>
|
||||
<li>Communicating with you about your stay</li>
|
||||
<li>Providing customer service and support</li>
|
||||
<li>Sending marketing communications (with your consent)</li>
|
||||
<li>Improving our services and website experience</li>
|
||||
<li>Complying with legal obligations</li>
|
||||
<li>Preventing fraud and ensuring security</li>
|
||||
</ul>
|
||||
|
||||
<h2>4. Information Sharing and Disclosure</h2>
|
||||
<p>We do not sell your personal information. We may share your information in the following circumstances:</p>
|
||||
<ul>
|
||||
<li><strong>Service Providers:</strong> With trusted third-party service providers who assist us in operating our business</li>
|
||||
<li><strong>Legal Requirements:</strong> When required by law or to protect our rights and safety</li>
|
||||
<li><strong>Business Transfers:</strong> In connection with a merger, acquisition, or sale of assets</li>
|
||||
<li><strong>With Your Consent:</strong> When you have given us explicit permission to share your information</li>
|
||||
</ul>
|
||||
|
||||
<h2>5. Data Security</h2>
|
||||
<p>We implement appropriate technical and organizational measures to protect your personal information against unauthorized access, alteration, disclosure, or destruction. However, no method of transmission over the Internet is 100% secure, and we cannot guarantee absolute security.</p>
|
||||
|
||||
<h2>6. Your Rights</h2>
|
||||
<p>Depending on your location, you may have certain rights regarding your personal information, including:</p>
|
||||
<ul>
|
||||
<li>The right to access your personal information</li>
|
||||
<li>The right to correct inaccurate information</li>
|
||||
<li>The right to request deletion of your information</li>
|
||||
<li>The right to object to processing of your information</li>
|
||||
<li>The right to data portability</li>
|
||||
<li>The right to withdraw consent</li>
|
||||
</ul>
|
||||
|
||||
<h2>7. Cookies and Tracking Technologies</h2>
|
||||
<p>We use cookies and similar tracking technologies to enhance your browsing experience, analyze website traffic, and personalize content. You can control cookie preferences through your browser settings.</p>
|
||||
|
||||
<h2>8. Third-Party Links</h2>
|
||||
<p>Our website may contain links to third-party websites. We are not responsible for the privacy practices of these external sites. We encourage you to review their privacy policies.</p>
|
||||
|
||||
<h2>9. Children's Privacy</h2>
|
||||
<p>Our services are not directed to individuals under the age of 18. We do not knowingly collect personal information from children. If you believe we have collected information from a child, please contact us immediately.</p>
|
||||
|
||||
<h2>10. International Data Transfers</h2>
|
||||
<p>Your information may be transferred to and processed in countries other than your country of residence. We ensure appropriate safeguards are in place to protect your information in accordance with this Privacy Policy.</p>
|
||||
|
||||
<h2>11. Changes to This Privacy Policy</h2>
|
||||
<p>We may update this Privacy Policy from time to time. We will notify you of any material changes by posting the new policy on this page and updating the "Last Updated" date.</p>
|
||||
|
||||
<h2>12. Contact Us</h2>
|
||||
<p>If you have any questions or concerns about this Privacy Policy or our data practices, please contact us at:</p>
|
||||
<p>
|
||||
<strong>Email:</strong> privacy@luxuryhotel.com<br>
|
||||
<strong>Phone:</strong> +1 (555) 123-4567<br>
|
||||
<strong>Address:</strong> 123 Luxury Avenue, Premium City, PC 12345, United States
|
||||
</p>
|
||||
|
||||
<p><em>Last Updated: {}</em></p>
|
||||
""".format(now.strftime('%B %d, %Y')),
|
||||
'meta_title': 'Privacy Policy | Luxury Hotel & Resort',
|
||||
'meta_description': 'Learn how Luxury Hotel & Resort collects, uses, and protects your personal information. Read our comprehensive privacy policy.',
|
||||
'meta_keywords': 'privacy policy, data protection, personal information, GDPR, privacy rights, hotel privacy',
|
||||
'og_title': 'Privacy Policy - Luxury Hotel & Resort',
|
||||
'og_description': 'Your privacy matters to us. Learn how we protect and use your personal information.',
|
||||
'og_image': 'https://images.unsplash.com/photo-1556761175-5973dc0f32e7?w=1200&h=630&fit=crop',
|
||||
'canonical_url': 'https://luxuryhotel.com/privacy',
|
||||
'is_active': True,
|
||||
'created_at': now,
|
||||
'updated_at': now
|
||||
}
|
||||
|
||||
|
||||
def seed_privacy_page(db: Session):
|
||||
"""Seed privacy policy page content into the database"""
|
||||
try:
|
||||
privacy_data = get_privacy_page_data()
|
||||
|
||||
# Check if privacy page content already exists
|
||||
existing_content = db.query(PageContent).filter(PageContent.page_type == PageType.PRIVACY).first()
|
||||
|
||||
if existing_content:
|
||||
logger.info('Updating existing privacy policy page content...')
|
||||
for key, value in privacy_data.items():
|
||||
if key not in ['id', 'page_type', 'created_at']:
|
||||
setattr(existing_content, key, value)
|
||||
existing_content.updated_at = datetime.now(timezone.utc)
|
||||
else:
|
||||
logger.info('Creating new privacy policy page content...')
|
||||
privacy_page = PageContent(**privacy_data)
|
||||
db.add(privacy_page)
|
||||
|
||||
db.commit()
|
||||
logger.info('Privacy policy page content seeded successfully!')
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error seeding privacy policy page: {str(e)}', exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
seed_privacy_page(db)
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed privacy policy page: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
193
Backend/seeders/refunds_seeder.py
Normal file
193
Backend/seeders/refunds_seeder.py
Normal file
@@ -0,0 +1,193 @@
|
||||
"""
|
||||
Refund Policy Page Seeder
|
||||
Seeds the database with comprehensive refund policy content
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
|
||||
# Add parent directory to path to allow importing from src
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal
|
||||
from src.shared.config.logging_config import get_logger
|
||||
from src.content.models.page_content import PageContent, PageType
|
||||
|
||||
# Import all models to ensure relationships are loaded
|
||||
from src.models import *
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_refunds_page_data():
|
||||
"""Generate comprehensive refund policy page data"""
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
return {
|
||||
'page_type': PageType.REFUNDS,
|
||||
'title': 'Refund Policy',
|
||||
'subtitle': 'Our Refund Policy and Procedures',
|
||||
'description': 'Learn about our refund policy, including eligibility, processing times, and how to request a refund for your reservation or services.',
|
||||
'content': """
|
||||
<h2>1. Overview</h2>
|
||||
<p>At Luxury Hotel & Resort, we strive to provide exceptional service and ensure your satisfaction. This Refund Policy outlines the terms and conditions under which refunds may be issued for reservations, services, and other transactions.</p>
|
||||
|
||||
<h2>2. Reservation Refunds</h2>
|
||||
<h3>2.1 Cancellation Refunds</h3>
|
||||
<p>Refunds for cancelled reservations are subject to the cancellation policy associated with your booking:</p>
|
||||
<ul>
|
||||
<li><strong>Flexible Rate:</strong> Full refund if cancelled 24-48 hours before check-in (depending on rate terms)</li>
|
||||
<li><strong>Non-Refundable Rate:</strong> No refund for cancellations, but may be eligible for credit or rescheduling (subject to terms)</li>
|
||||
<li><strong>Special Packages:</strong> Refund terms vary by package - please refer to your booking confirmation</li>
|
||||
</ul>
|
||||
|
||||
<h3>2.2 Early Departure</h3>
|
||||
<p>If you check out earlier than your scheduled departure date, you may be eligible for a partial refund for unused nights, subject to the terms of your reservation and availability. Early departure refunds are not guaranteed and are evaluated on a case-by-case basis.</p>
|
||||
|
||||
<h3>2.3 No-Show</h3>
|
||||
<p>If you do not arrive on your scheduled check-in date and have not cancelled your reservation, you will be charged for the first night. No refunds are provided for no-show reservations.</p>
|
||||
|
||||
<h2>3. Service Refunds</h2>
|
||||
<h3>3.1 Spa Services</h3>
|
||||
<p>Spa service refunds or rescheduling:</p>
|
||||
<ul>
|
||||
<li>Cancellations made 24 hours in advance: Full refund or rescheduling</li>
|
||||
<li>Cancellations made less than 24 hours in advance: 50% refund or rescheduling</li>
|
||||
<li>No-show: No refund</li>
|
||||
</ul>
|
||||
|
||||
<h3>3.2 Dining Reservations</h3>
|
||||
<p>Dining reservation refunds:</p>
|
||||
<ul>
|
||||
<li>Cancellations made 4 hours in advance: Full refund</li>
|
||||
<li>Cancellations made less than 4 hours in advance: No refund, but may be rescheduled</li>
|
||||
<li>Special event dining: Subject to specific event terms</li>
|
||||
</ul>
|
||||
|
||||
<h3>3.3 Event & Meeting Bookings</h3>
|
||||
<p>Refund policies for events and meetings vary based on the size and type of event. Please refer to your event contract for specific refund terms.</p>
|
||||
|
||||
<h2>4. Processing Refunds</h2>
|
||||
<h3>4.1 Refund Processing Time</h3>
|
||||
<p>Once approved, refunds are typically processed within 5-10 business days. The time it takes for the refund to appear in your account depends on your financial institution:</p>
|
||||
<ul>
|
||||
<li>Credit card refunds: 5-10 business days</li>
|
||||
<li>Debit card refunds: 5-10 business days</li>
|
||||
<li>Bank transfer refunds: 7-14 business days</li>
|
||||
</ul>
|
||||
|
||||
<h3>4.2 Refund Method</h3>
|
||||
<p>Refunds will be issued to the original payment method used for the transaction. If the original payment method is no longer valid, please contact us to arrange an alternative refund method.</p>
|
||||
|
||||
<h2>5. Requesting a Refund</h2>
|
||||
<h3>5.1 How to Request</h3>
|
||||
<p>To request a refund, please contact us:</p>
|
||||
<ul>
|
||||
<li><strong>Phone:</strong> +1 (555) 123-4567</li>
|
||||
<li><strong>Email:</strong> refunds@luxuryhotel.com</li>
|
||||
<li><strong>Online:</strong> Through your booking confirmation or account</li>
|
||||
</ul>
|
||||
|
||||
<h3>5.2 Required Information</h3>
|
||||
<p>When requesting a refund, please provide:</p>
|
||||
<ul>
|
||||
<li>Reservation or booking confirmation number</li>
|
||||
<li>Guest name and contact information</li>
|
||||
<li>Reason for refund request</li>
|
||||
<li>Original payment method details</li>
|
||||
</ul>
|
||||
|
||||
<h2>6. Non-Refundable Items</h2>
|
||||
<p>The following items and services are generally non-refundable:</p>
|
||||
<ul>
|
||||
<li>Non-refundable rate bookings (unless otherwise specified)</li>
|
||||
<li>Gift cards and vouchers (subject to terms and conditions)</li>
|
||||
<li>Third-party bookings (subject to third-party policies)</li>
|
||||
<li>Consumed services (meals, spa treatments already received)</li>
|
||||
<li>No-show charges</li>
|
||||
</ul>
|
||||
|
||||
<h2>7. Special Circumstances</h2>
|
||||
<h3>7.1 Force Majeure</h3>
|
||||
<p>In cases of force majeure events (natural disasters, pandemics, government restrictions, etc.), we will work with you to provide refunds, credits, or rescheduling options. Each situation is evaluated individually.</p>
|
||||
|
||||
<h3>7.2 Service Issues</h3>
|
||||
<p>If you experience service issues during your stay, please bring them to our attention immediately so we can address them. We may offer partial refunds or credits for significant service failures, evaluated on a case-by-case basis.</p>
|
||||
|
||||
<h2>8. Disputes & Appeals</h2>
|
||||
<p>If you are not satisfied with a refund decision, you may appeal by contacting our guest relations team. We will review your case and provide a response within 5-7 business days.</p>
|
||||
|
||||
<h2>9. Third-Party Bookings</h2>
|
||||
<p>If you made your reservation through a third-party booking site (such as Expedia, Booking.com, etc.), refund requests must be processed through that third party according to their policies. We cannot directly process refunds for third-party bookings.</p>
|
||||
|
||||
<h2>10. Contact Information</h2>
|
||||
<p>For refund inquiries or assistance, please contact us:</p>
|
||||
<ul>
|
||||
<li><strong>Refunds Department:</strong> refunds@luxuryhotel.com</li>
|
||||
<li><strong>Phone:</strong> +1 (555) 123-4567</li>
|
||||
<li><strong>Hours:</strong> Monday-Friday, 9:00 AM - 6:00 PM EST</li>
|
||||
<li><strong>Address:</strong> 123 Luxury Avenue, Premium City, PC 12345, United States</li>
|
||||
</ul>
|
||||
|
||||
<h2>11. Policy Updates</h2>
|
||||
<p>We reserve the right to update this Refund Policy at any time. Changes will be posted on this page with an updated "Last Updated" date. Your continued use of our services after changes are posted constitutes acceptance of the updated policy.</p>
|
||||
|
||||
<p><em>Last Updated: {}</em></p>
|
||||
""".format(now.strftime('%B %d, %Y')),
|
||||
'meta_title': 'Refund Policy | Luxury Hotel & Resort',
|
||||
'meta_description': 'Learn about our refund policy, including eligibility, processing times, and how to request refunds for reservations and services.',
|
||||
'meta_keywords': 'refund policy, cancellation refund, hotel refund, booking refund, refund request',
|
||||
'og_title': 'Refund Policy - Luxury Hotel & Resort',
|
||||
'og_description': 'Our refund policy and procedures. Learn how to request refunds for reservations and services.',
|
||||
'og_image': 'https://images.unsplash.com/photo-1556761175-5973dc0f32e7?w=1200&h=630&fit=crop',
|
||||
'canonical_url': 'https://luxuryhotel.com/refunds',
|
||||
'is_active': True,
|
||||
'created_at': now,
|
||||
'updated_at': now
|
||||
}
|
||||
|
||||
|
||||
def seed_refunds_page(db: Session):
|
||||
"""Seed refunds policy page content into the database"""
|
||||
try:
|
||||
refunds_data = get_refunds_page_data()
|
||||
|
||||
# Check if refunds page content already exists
|
||||
existing_content = db.query(PageContent).filter(PageContent.page_type == PageType.REFUNDS).first()
|
||||
|
||||
if existing_content:
|
||||
logger.info('Updating existing refunds policy page content...')
|
||||
for key, value in refunds_data.items():
|
||||
if key not in ['id', 'page_type', 'created_at']:
|
||||
setattr(existing_content, key, value)
|
||||
existing_content.updated_at = datetime.now(timezone.utc)
|
||||
else:
|
||||
logger.info('Creating new refunds policy page content...')
|
||||
refunds_page = PageContent(**refunds_data)
|
||||
db.add(refunds_page)
|
||||
|
||||
db.commit()
|
||||
logger.info('Refunds policy page content seeded successfully!')
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error seeding refunds policy page: {str(e)}', exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
seed_refunds_page(db)
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed refunds policy page: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
473
Backend/seeders/room_seeder.py
Normal file
473
Backend/seeders/room_seeder.py
Normal file
@@ -0,0 +1,473 @@
|
||||
"""
|
||||
Room Seeder
|
||||
Seeds the database with room types and rooms
|
||||
All images are from Unsplash (free stock photos)
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
from decimal import Decimal
|
||||
|
||||
# Add parent directory to path to import modules
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal
|
||||
from src.shared.config.logging_config import get_logger
|
||||
from src.rooms.models.room import Room, RoomStatus
|
||||
from src.rooms.models.room_type import RoomType
|
||||
|
||||
# Import all models to ensure relationships are loaded correctly
|
||||
from src.models import *
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_room_types_data():
|
||||
"""Generate room types data"""
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
return [
|
||||
{
|
||||
'name': 'Standard Room',
|
||||
'description': 'Comfortable and well-appointed standard rooms perfect for business travelers and couples. Features modern amenities and elegant decor.',
|
||||
'base_price': Decimal('150.00'),
|
||||
'capacity': 2,
|
||||
'amenities': json.dumps([
|
||||
'Free WiFi',
|
||||
'Flat-screen TV',
|
||||
'Air Conditioning',
|
||||
'Mini Bar',
|
||||
'Work Desk',
|
||||
'In-room Safe',
|
||||
'Coffee Maker',
|
||||
'Hair Dryer'
|
||||
])
|
||||
},
|
||||
{
|
||||
'name': 'Deluxe Room',
|
||||
'description': 'Spacious deluxe rooms with enhanced amenities and premium furnishings. Ideal for guests seeking extra comfort and space.',
|
||||
'base_price': Decimal('220.00'),
|
||||
'capacity': 2,
|
||||
'amenities': json.dumps([
|
||||
'Free WiFi',
|
||||
'Smart TV',
|
||||
'Air Conditioning',
|
||||
'Premium Mini Bar',
|
||||
'Work Desk',
|
||||
'In-room Safe',
|
||||
'Nespresso Machine',
|
||||
'Hair Dryer',
|
||||
'Bathrobe & Slippers',
|
||||
'City View'
|
||||
])
|
||||
},
|
||||
{
|
||||
'name': 'Executive Suite',
|
||||
'description': 'Luxurious suites with separate living areas, perfect for extended stays or guests who prefer extra space and privacy.',
|
||||
'base_price': Decimal('350.00'),
|
||||
'capacity': 3,
|
||||
'amenities': json.dumps([
|
||||
'Free WiFi',
|
||||
'Smart TV (Multiple)',
|
||||
'Air Conditioning',
|
||||
'Premium Mini Bar',
|
||||
'Separate Living Area',
|
||||
'In-room Safe',
|
||||
'Nespresso Machine',
|
||||
'Hair Dryer',
|
||||
'Bathrobe & Slippers',
|
||||
'Panoramic View',
|
||||
'Premium Toiletries',
|
||||
'Welcome Amenities'
|
||||
])
|
||||
},
|
||||
{
|
||||
'name': 'Presidential Suite',
|
||||
'description': 'The ultimate in luxury accommodation. Spacious multi-room suite with premium amenities, private terrace, and personalized butler service.',
|
||||
'base_price': Decimal('800.00'),
|
||||
'capacity': 4,
|
||||
'amenities': json.dumps([
|
||||
'Free WiFi',
|
||||
'Smart TV (Multiple)',
|
||||
'Air Conditioning',
|
||||
'Premium Mini Bar',
|
||||
'Separate Living & Dining Areas',
|
||||
'In-room Safe',
|
||||
'Nespresso Machine',
|
||||
'Hair Dryer',
|
||||
'Bathrobe & Slippers',
|
||||
'Panoramic View',
|
||||
'Premium Toiletries',
|
||||
'Welcome Amenities',
|
||||
'Private Terrace',
|
||||
'Butler Service',
|
||||
'Private Bar',
|
||||
'Jacuzzi'
|
||||
])
|
||||
},
|
||||
{
|
||||
'name': 'Ocean View Room',
|
||||
'description': 'Stunning ocean view rooms with floor-to-ceiling windows and private balconies. Perfect for romantic getaways and relaxation.',
|
||||
'base_price': Decimal('280.00'),
|
||||
'capacity': 2,
|
||||
'amenities': json.dumps([
|
||||
'Free WiFi',
|
||||
'Smart TV',
|
||||
'Air Conditioning',
|
||||
'Premium Mini Bar',
|
||||
'Work Desk',
|
||||
'In-room Safe',
|
||||
'Nespresso Machine',
|
||||
'Hair Dryer',
|
||||
'Bathrobe & Slippers',
|
||||
'Ocean View',
|
||||
'Private Balcony',
|
||||
'Premium Toiletries'
|
||||
])
|
||||
},
|
||||
{
|
||||
'name': 'Family Room',
|
||||
'description': 'Spacious family-friendly rooms designed to accommodate families with children. Features extra beds and family amenities.',
|
||||
'base_price': Decimal('300.00'),
|
||||
'capacity': 4,
|
||||
'amenities': json.dumps([
|
||||
'Free WiFi',
|
||||
'Smart TV (Multiple)',
|
||||
'Air Conditioning',
|
||||
'Mini Bar',
|
||||
'Extra Beds',
|
||||
'In-room Safe',
|
||||
'Coffee Maker',
|
||||
'Hair Dryer',
|
||||
'Family Amenities',
|
||||
'Game Console',
|
||||
'Child Safety Features'
|
||||
])
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
def get_rooms_data(room_type_map):
|
||||
"""Generate rooms data based on room types"""
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
rooms = []
|
||||
|
||||
# Standard Rooms (Floors 1-3, Rooms 101-130)
|
||||
standard_type = room_type_map.get('Standard Room')
|
||||
if standard_type:
|
||||
for floor in range(1, 4):
|
||||
for room_num in range(1, 11):
|
||||
room_number = f"{floor}{room_num:02d}"
|
||||
rooms.append({
|
||||
'room_type_id': standard_type.id,
|
||||
'room_number': room_number,
|
||||
'floor': floor,
|
||||
'status': RoomStatus.available,
|
||||
'price': Decimal('150.00'),
|
||||
'featured': room_num <= 2, # First 2 rooms per floor are featured
|
||||
'capacity': 2,
|
||||
'room_size': '25 sqm',
|
||||
'view': 'City View',
|
||||
'images': json.dumps([
|
||||
'https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1596394516093-501ba68a0ba6?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop'
|
||||
]),
|
||||
'amenities': json.dumps([
|
||||
'Free WiFi',
|
||||
'Flat-screen TV',
|
||||
'Air Conditioning',
|
||||
'Mini Bar',
|
||||
'Work Desk',
|
||||
'In-room Safe'
|
||||
]),
|
||||
'description': f'Comfortable standard room on floor {floor} with modern amenities and city view. Perfect for business travelers and couples.'
|
||||
})
|
||||
|
||||
# Deluxe Rooms (Floors 4-6, Rooms 401-430)
|
||||
deluxe_type = room_type_map.get('Deluxe Room')
|
||||
if deluxe_type:
|
||||
for floor in range(4, 7):
|
||||
for room_num in range(1, 11):
|
||||
room_number = f"{floor}{room_num:02d}"
|
||||
rooms.append({
|
||||
'room_type_id': deluxe_type.id,
|
||||
'room_number': room_number,
|
||||
'floor': floor,
|
||||
'status': RoomStatus.available,
|
||||
'price': Decimal('220.00'),
|
||||
'featured': room_num <= 2,
|
||||
'capacity': 2,
|
||||
'room_size': '35 sqm',
|
||||
'view': 'City View',
|
||||
'images': json.dumps([
|
||||
'https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop'
|
||||
]),
|
||||
'amenities': json.dumps([
|
||||
'Free WiFi',
|
||||
'Smart TV',
|
||||
'Air Conditioning',
|
||||
'Premium Mini Bar',
|
||||
'Work Desk',
|
||||
'Nespresso Machine',
|
||||
'Bathrobe & Slippers'
|
||||
]),
|
||||
'description': f'Spacious deluxe room on floor {floor} with premium amenities and enhanced comfort. Ideal for guests seeking extra space.'
|
||||
})
|
||||
|
||||
# Executive Suites (Floors 7-8, Rooms 701-720)
|
||||
executive_type = room_type_map.get('Executive Suite')
|
||||
if executive_type:
|
||||
for floor in range(7, 9):
|
||||
for room_num in range(1, 11):
|
||||
room_number = f"{floor}{room_num:02d}"
|
||||
rooms.append({
|
||||
'room_type_id': executive_type.id,
|
||||
'room_number': room_number,
|
||||
'floor': floor,
|
||||
'status': RoomStatus.available,
|
||||
'price': Decimal('350.00'),
|
||||
'featured': room_num <= 3,
|
||||
'capacity': 3,
|
||||
'room_size': '55 sqm',
|
||||
'view': 'Panoramic View',
|
||||
'images': json.dumps([
|
||||
'https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1596394516093-501ba68a0ba6?w=1200&h=800&fit=crop'
|
||||
]),
|
||||
'amenities': json.dumps([
|
||||
'Free WiFi',
|
||||
'Smart TV (Multiple)',
|
||||
'Separate Living Area',
|
||||
'Premium Mini Bar',
|
||||
'Nespresso Machine',
|
||||
'Bathrobe & Slippers',
|
||||
'Premium Toiletries',
|
||||
'Welcome Amenities'
|
||||
]),
|
||||
'description': f'Luxurious executive suite on floor {floor} with separate living area and panoramic views. Perfect for extended stays.'
|
||||
})
|
||||
|
||||
# Presidential Suites (Floor 9, Rooms 901-905)
|
||||
presidential_type = room_type_map.get('Presidential Suite')
|
||||
if presidential_type:
|
||||
for room_num in range(1, 6):
|
||||
room_number = f"9{room_num:02d}"
|
||||
rooms.append({
|
||||
'room_type_id': presidential_type.id,
|
||||
'room_number': room_number,
|
||||
'floor': 9,
|
||||
'status': RoomStatus.available,
|
||||
'price': Decimal('800.00'),
|
||||
'featured': True, # All presidential suites are featured
|
||||
'capacity': 4,
|
||||
'room_size': '120 sqm',
|
||||
'view': 'Panoramic View',
|
||||
'images': json.dumps([
|
||||
'https://images.unsplash.com/photo-1596394516093-501ba68a0ba6?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1200&h=800&fit=crop'
|
||||
]),
|
||||
'amenities': json.dumps([
|
||||
'Free WiFi',
|
||||
'Smart TV (Multiple)',
|
||||
'Separate Living & Dining Areas',
|
||||
'Private Terrace',
|
||||
'Butler Service',
|
||||
'Premium Mini Bar',
|
||||
'Private Bar',
|
||||
'Jacuzzi',
|
||||
'Premium Toiletries',
|
||||
'Welcome Amenities'
|
||||
]),
|
||||
'description': f'Ultimate luxury in our exclusive presidential suite. Features grand living room, formal dining, private terrace, and personal butler service. Suite {room_num}.'
|
||||
})
|
||||
|
||||
# Ocean View Rooms (Floor 10, Rooms 1001-1020)
|
||||
ocean_type = room_type_map.get('Ocean View Room')
|
||||
if ocean_type:
|
||||
for room_num in range(1, 21):
|
||||
room_number = f"10{room_num:02d}"
|
||||
rooms.append({
|
||||
'room_type_id': ocean_type.id,
|
||||
'room_number': room_number,
|
||||
'floor': 10,
|
||||
'status': RoomStatus.available,
|
||||
'price': Decimal('280.00'),
|
||||
'featured': room_num <= 5,
|
||||
'capacity': 2,
|
||||
'room_size': '30 sqm',
|
||||
'view': 'Ocean View',
|
||||
'images': json.dumps([
|
||||
'https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1587925358603-dc217c8a64f8?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1200&h=800&fit=crop'
|
||||
]),
|
||||
'amenities': json.dumps([
|
||||
'Free WiFi',
|
||||
'Smart TV',
|
||||
'Air Conditioning',
|
||||
'Premium Mini Bar',
|
||||
'Private Balcony',
|
||||
'Nespresso Machine',
|
||||
'Bathrobe & Slippers',
|
||||
'Ocean View'
|
||||
]),
|
||||
'description': f'Stunning ocean view room with floor-to-ceiling windows and private balcony. Perfect for romantic getaways and relaxation.'
|
||||
})
|
||||
|
||||
# Family Rooms (Floor 1, Rooms 111-120)
|
||||
family_type = room_type_map.get('Family Room')
|
||||
if family_type:
|
||||
for room_num in range(11, 21):
|
||||
room_number = f"1{room_num:02d}"
|
||||
rooms.append({
|
||||
'room_type_id': family_type.id,
|
||||
'room_number': room_number,
|
||||
'floor': 1,
|
||||
'status': RoomStatus.available,
|
||||
'price': Decimal('300.00'),
|
||||
'featured': room_num <= 13,
|
||||
'capacity': 4,
|
||||
'room_size': '45 sqm',
|
||||
'view': 'City View',
|
||||
'images': json.dumps([
|
||||
'https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop',
|
||||
'https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop'
|
||||
]),
|
||||
'amenities': json.dumps([
|
||||
'Free WiFi',
|
||||
'Smart TV (Multiple)',
|
||||
'Air Conditioning',
|
||||
'Mini Bar',
|
||||
'Extra Beds',
|
||||
'Game Console',
|
||||
'Child Safety Features',
|
||||
'Family Amenities'
|
||||
]),
|
||||
'description': f'Spacious family-friendly room on floor 1 designed to accommodate families with children. Features extra beds and family amenities.'
|
||||
})
|
||||
|
||||
return rooms
|
||||
|
||||
|
||||
def seed_room_types(db: Session):
|
||||
"""Seed room types into the database"""
|
||||
try:
|
||||
room_types_data = get_room_types_data()
|
||||
room_type_map = {}
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
for room_type_data in room_types_data:
|
||||
existing = db.query(RoomType).filter(RoomType.name == room_type_data['name']).first()
|
||||
|
||||
if existing:
|
||||
logger.info(f"Room type '{room_type_data['name']}' already exists. Updating...")
|
||||
for key, value in room_type_data.items():
|
||||
setattr(existing, key, value)
|
||||
existing.updated_at = now
|
||||
room_type_map[existing.name] = existing
|
||||
else:
|
||||
logger.info(f"Creating room type: {room_type_data['name']}")
|
||||
room_type = RoomType(
|
||||
**room_type_data,
|
||||
created_at=now,
|
||||
updated_at=now
|
||||
)
|
||||
db.add(room_type)
|
||||
db.flush() # Flush to get the ID
|
||||
room_type_map[room_type.name] = room_type
|
||||
|
||||
db.commit()
|
||||
logger.info(f'Successfully seeded {len(room_type_map)} room types!')
|
||||
return room_type_map
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error seeding room types: {str(e)}', exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def seed_rooms(db: Session, room_type_map: dict, clear_existing: bool = False):
|
||||
"""Seed rooms into the database"""
|
||||
try:
|
||||
if clear_existing:
|
||||
logger.info('Clearing existing rooms...')
|
||||
db.query(Room).delete()
|
||||
db.commit()
|
||||
logger.info('Existing rooms cleared.')
|
||||
|
||||
rooms_data = get_rooms_data(room_type_map)
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
created_count = 0
|
||||
updated_count = 0
|
||||
|
||||
for room_data in rooms_data:
|
||||
existing = db.query(Room).filter(Room.room_number == room_data['room_number']).first()
|
||||
|
||||
if existing:
|
||||
logger.debug(f"Room '{room_data['room_number']}' already exists. Updating...")
|
||||
for key, value in room_data.items():
|
||||
setattr(existing, key, value)
|
||||
existing.updated_at = now
|
||||
updated_count += 1
|
||||
else:
|
||||
logger.debug(f"Creating room: {room_data['room_number']}")
|
||||
room = Room(
|
||||
**room_data,
|
||||
created_at=now,
|
||||
updated_at=now
|
||||
)
|
||||
db.add(room)
|
||||
created_count += 1
|
||||
|
||||
db.commit()
|
||||
logger.info(f'Successfully seeded rooms! Created: {created_count}, Updated: {updated_count}, Total: {len(rooms_data)}')
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error seeding rooms: {str(e)}', exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def seed_rooms_and_types(db: Session, clear_existing: bool = False):
|
||||
"""Seed both room types and rooms"""
|
||||
room_type_map = seed_room_types(db)
|
||||
seed_rooms(db, room_type_map, clear_existing=clear_existing)
|
||||
return room_type_map
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Seed room types and rooms')
|
||||
parser.add_argument(
|
||||
'--clear-rooms',
|
||||
action='store_true',
|
||||
help='Clear existing rooms before seeding (room types are updated, not cleared)'
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
seed_rooms_and_types(db, clear_existing=args.clear_rooms)
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed rooms: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
184
Backend/seeders/run_seeder.py
Executable file
184
Backend/seeders/run_seeder.py
Executable file
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Seeder Runner
|
||||
Run all seeders or specific seeders
|
||||
"""
|
||||
import sys
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from homepage_seeder import seed_homepage
|
||||
from about_seeder import seed_about_page
|
||||
from contact_seeder import seed_contact_page
|
||||
from privacy_seeder import seed_privacy_page
|
||||
from faq_seeder import seed_faq_page
|
||||
from accessibility_seeder import seed_accessibility_page
|
||||
from refunds_seeder import seed_refunds_page
|
||||
from terms_seeder import seed_terms_page
|
||||
from cancellation_seeder import seed_cancellation_page
|
||||
from footer_seeder import seed_footer_page
|
||||
from banner_seeder import seed_banners
|
||||
from user_seeder import seed_users_and_roles
|
||||
from room_seeder import seed_rooms_and_types
|
||||
from service_seeder import seed_services
|
||||
from blog_seeder import seed_blog_posts
|
||||
from settings_seeder import seed_settings
|
||||
from src.shared.config.database import SessionLocal
|
||||
from src.shared.config.logging_config import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Run database seeders')
|
||||
parser.add_argument(
|
||||
'--seeder',
|
||||
choices=['homepage', 'about', 'contact', 'privacy', 'faq', 'accessibility', 'refunds', 'terms', 'cancellation', 'footer', 'banners', 'users', 'rooms', 'services', 'blog', 'settings', 'all'],
|
||||
default='all',
|
||||
help='Which seeder to run (default: all)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--clear-banners',
|
||||
action='store_true',
|
||||
help='Clear existing banners before seeding (only applies to banners seeder)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--clear-rooms',
|
||||
action='store_true',
|
||||
help='Clear existing rooms before seeding (only applies to rooms seeder)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--clear-services',
|
||||
action='store_true',
|
||||
help='Clear existing services before seeding (only applies to services seeder)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--clear-blog',
|
||||
action='store_true',
|
||||
help='Clear existing blog posts before seeding (only applies to blog seeder)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--clear-settings',
|
||||
action='store_true',
|
||||
help='Clear existing settings before seeding (only applies to settings seeder)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--admin-email',
|
||||
default='admin@hotel.com',
|
||||
help='Admin user email (default: admin@hotel.com)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--admin-password',
|
||||
default='admin123',
|
||||
help='Admin user password (default: admin123)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--admin-name',
|
||||
default='Admin User',
|
||||
help='Admin user full name (default: Admin User)'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
# Always seed users/roles first if running all or users seeder
|
||||
if args.seeder == 'users' or args.seeder == 'all':
|
||||
logger.info('Running user and role seeder...')
|
||||
seed_users_and_roles(
|
||||
db,
|
||||
admin_email=args.admin_email,
|
||||
admin_password=args.admin_password,
|
||||
admin_name=args.admin_name
|
||||
)
|
||||
logger.info('User and role seeder completed!')
|
||||
|
||||
if args.seeder == 'homepage' or args.seeder == 'all':
|
||||
logger.info('Running homepage seeder...')
|
||||
seed_homepage(db)
|
||||
logger.info('Homepage seeder completed!')
|
||||
|
||||
if args.seeder == 'about' or args.seeder == 'all':
|
||||
logger.info('Running about page seeder...')
|
||||
seed_about_page(db)
|
||||
logger.info('About page seeder completed!')
|
||||
|
||||
if args.seeder == 'contact' or args.seeder == 'all':
|
||||
logger.info('Running contact page seeder...')
|
||||
seed_contact_page(db)
|
||||
logger.info('Contact page seeder completed!')
|
||||
|
||||
if args.seeder == 'privacy' or args.seeder == 'all':
|
||||
logger.info('Running privacy policy page seeder...')
|
||||
seed_privacy_page(db)
|
||||
logger.info('Privacy policy page seeder completed!')
|
||||
|
||||
if args.seeder == 'faq' or args.seeder == 'all':
|
||||
logger.info('Running FAQ page seeder...')
|
||||
seed_faq_page(db)
|
||||
logger.info('FAQ page seeder completed!')
|
||||
|
||||
if args.seeder == 'accessibility' or args.seeder == 'all':
|
||||
logger.info('Running accessibility page seeder...')
|
||||
seed_accessibility_page(db)
|
||||
logger.info('Accessibility page seeder completed!')
|
||||
|
||||
if args.seeder == 'refunds' or args.seeder == 'all':
|
||||
logger.info('Running refunds policy page seeder...')
|
||||
seed_refunds_page(db)
|
||||
logger.info('Refunds policy page seeder completed!')
|
||||
|
||||
if args.seeder == 'terms' or args.seeder == 'all':
|
||||
logger.info('Running terms of use page seeder...')
|
||||
seed_terms_page(db)
|
||||
logger.info('Terms of use page seeder completed!')
|
||||
|
||||
if args.seeder == 'cancellation' or args.seeder == 'all':
|
||||
logger.info('Running cancellation policy page seeder...')
|
||||
seed_cancellation_page(db)
|
||||
logger.info('Cancellation policy page seeder completed!')
|
||||
|
||||
if args.seeder == 'footer' or args.seeder == 'all':
|
||||
logger.info('Running footer page seeder...')
|
||||
seed_footer_page(db)
|
||||
logger.info('Footer page seeder completed!')
|
||||
|
||||
if args.seeder == 'banners' or args.seeder == 'all':
|
||||
logger.info('Running banner seeder...')
|
||||
seed_banners(db, clear_existing=args.clear_banners)
|
||||
logger.info('Banner seeder completed!')
|
||||
|
||||
if args.seeder == 'rooms' or args.seeder == 'all':
|
||||
logger.info('Running room seeder...')
|
||||
seed_rooms_and_types(db, clear_existing=args.clear_rooms)
|
||||
logger.info('Room seeder completed!')
|
||||
|
||||
if args.seeder == 'services' or args.seeder == 'all':
|
||||
logger.info('Running service seeder...')
|
||||
seed_services(db, clear_existing=args.clear_services)
|
||||
logger.info('Service seeder completed!')
|
||||
|
||||
if args.seeder == 'blog' or args.seeder == 'all':
|
||||
logger.info('Running blog seeder...')
|
||||
seed_blog_posts(db, clear_existing=args.clear_blog)
|
||||
logger.info('Blog seeder completed!')
|
||||
|
||||
if args.seeder == 'settings' or args.seeder == 'all':
|
||||
logger.info('Running settings seeder...')
|
||||
seed_settings(db, clear_existing=args.clear_settings)
|
||||
logger.info('Settings seeder completed!')
|
||||
|
||||
logger.info('All seeders completed successfully!')
|
||||
except Exception as e:
|
||||
logger.error(f'Seeder failed: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
413
Backend/seeders/service_seeder.py
Normal file
413
Backend/seeders/service_seeder.py
Normal file
@@ -0,0 +1,413 @@
|
||||
"""
|
||||
Service Seeder
|
||||
Seeds the database with hotel services
|
||||
All images are from Unsplash (free stock photos)
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
from decimal import Decimal
|
||||
import re
|
||||
|
||||
# Add parent directory to path to import modules
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal
|
||||
from src.shared.config.logging_config import get_logger
|
||||
from src.hotel_services.models.service import Service
|
||||
|
||||
# Import all models to ensure relationships are loaded correctly
|
||||
from src.models import *
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def slugify(text):
|
||||
"""Convert text to URL-friendly slug"""
|
||||
text = text.lower()
|
||||
text = re.sub(r'[^\w\s-]', '', text)
|
||||
text = re.sub(r'[-\s]+', '-', text)
|
||||
return text.strip('-')
|
||||
|
||||
|
||||
def get_services_data():
|
||||
"""Generate comprehensive services data with Unsplash images"""
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
services = [
|
||||
# Spa & Wellness Services
|
||||
{
|
||||
'name': 'Luxury Spa Treatment',
|
||||
'description': 'Indulge in our signature spa treatments designed to rejuvenate your mind, body, and soul. Experience ultimate relaxation with our expert therapists.',
|
||||
'price': Decimal('150.00'),
|
||||
'category': 'Spa & Wellness',
|
||||
'slug': 'luxury-spa-treatment',
|
||||
'image': 'https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Our luxury spa treatments combine traditional techniques with modern wellness practices. Choose from a variety of massages, facials, and body treatments tailored to your needs.</p>',
|
||||
'sections': json.dumps([
|
||||
{
|
||||
'type': 'features',
|
||||
'title': 'Treatment Options',
|
||||
'content': 'Swedish Massage, Deep Tissue, Hot Stone, Aromatherapy, Facial Treatments',
|
||||
'alignment': 'left',
|
||||
'is_visible': True
|
||||
}
|
||||
]),
|
||||
'meta_title': 'Luxury Spa Treatment | Hotel Spa Services',
|
||||
'meta_description': 'Experience ultimate relaxation with our luxury spa treatments. Expert therapists, premium products, and serene environment.',
|
||||
'meta_keywords': 'spa, massage, wellness, relaxation, hotel spa, luxury treatment',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'name': 'Couples Massage',
|
||||
'description': 'Share a relaxing experience with your partner in our private couples massage room. Perfect for romantic getaways and special occasions.',
|
||||
'price': Decimal('280.00'),
|
||||
'category': 'Spa & Wellness',
|
||||
'slug': 'couples-massage',
|
||||
'image': 'https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Enjoy a synchronized massage experience with your loved one in our beautifully appointed couples suite. Includes champagne and chocolate-covered strawberries.</p>',
|
||||
'sections': None,
|
||||
'meta_title': 'Couples Massage | Romantic Spa Experience',
|
||||
'meta_description': 'Share a romantic spa experience with couples massage. Private suite, synchronized treatments, and special amenities included.',
|
||||
'meta_keywords': 'couples massage, romantic spa, couples treatment, hotel spa',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'name': 'Facial Treatment',
|
||||
'description': 'Rejuvenate your skin with our professional facial treatments using premium skincare products. Customized for your skin type.',
|
||||
'price': Decimal('120.00'),
|
||||
'category': 'Spa & Wellness',
|
||||
'slug': 'facial-treatment',
|
||||
'image': 'https://images.unsplash.com/photo-1570172619644-dfd03ed5d881?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Our expert estheticians provide personalized facial treatments to address your specific skin concerns. Includes deep cleansing, exfoliation, and hydration.</p>',
|
||||
'sections': None,
|
||||
'meta_title': 'Facial Treatment | Professional Skincare Services',
|
||||
'meta_description': 'Professional facial treatments with premium products. Customized for your skin type by expert estheticians.',
|
||||
'meta_keywords': 'facial, skincare, spa facial, beauty treatment',
|
||||
'is_active': True
|
||||
},
|
||||
|
||||
# Dining Services
|
||||
{
|
||||
'name': 'Fine Dining Experience',
|
||||
'description': 'Savor exquisite cuisine at our award-winning restaurant. Chef-prepared meals with the finest ingredients and impeccable service.',
|
||||
'price': Decimal('200.00'),
|
||||
'category': 'Dining',
|
||||
'slug': 'fine-dining-experience',
|
||||
'image': 'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Experience culinary excellence at our Michelin-starred restaurant. Our talented chefs create innovative dishes using locally sourced, seasonal ingredients.</p>',
|
||||
'sections': json.dumps([
|
||||
{
|
||||
'type': 'menu',
|
||||
'title': 'Signature Dishes',
|
||||
'content': 'Truffle Risotto, Wagyu Beef, Lobster Thermidor, Seasonal Tasting Menu',
|
||||
'alignment': 'center',
|
||||
'is_visible': True
|
||||
}
|
||||
]),
|
||||
'meta_title': 'Fine Dining Restaurant | Award-Winning Cuisine',
|
||||
'meta_description': 'Experience award-winning fine dining with chef-prepared meals, premium ingredients, and exceptional service.',
|
||||
'meta_keywords': 'fine dining, restaurant, gourmet, Michelin, hotel restaurant',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'name': 'Room Service',
|
||||
'description': 'Enjoy delicious meals in the comfort of your room. Available 24/7 with an extensive menu of international and local cuisine.',
|
||||
'price': Decimal('50.00'),
|
||||
'category': 'Dining',
|
||||
'slug': 'room-service',
|
||||
'image': 'https://images.unsplash.com/photo-1551632811-5617803d319f?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Our room service menu features breakfast, lunch, dinner, and late-night options. All dishes are prepared fresh and delivered to your room with professional service.</p>',
|
||||
'sections': None,
|
||||
'meta_title': '24/7 Room Service | In-Room Dining',
|
||||
'meta_description': 'Enjoy delicious meals in your room with our 24/7 room service. Extensive menu, fresh preparation, and professional delivery.',
|
||||
'meta_keywords': 'room service, in-room dining, hotel food delivery',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'name': 'Private Chef Service',
|
||||
'description': 'Experience gourmet dining in the privacy of your suite with a personal chef. Customized menus and intimate dining experience.',
|
||||
'price': Decimal('500.00'),
|
||||
'category': 'Dining',
|
||||
'slug': 'private-chef-service',
|
||||
'image': 'https://images.unsplash.com/photo-1577219491135-ce391730fd43?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Our private chef service brings fine dining directly to your suite. Work with our chef to create a customized menu for your special occasion.</p>',
|
||||
'sections': None,
|
||||
'meta_title': 'Private Chef Service | In-Suite Dining',
|
||||
'meta_description': 'Enjoy a private chef experience in your suite. Customized menus, intimate dining, and exceptional culinary expertise.',
|
||||
'meta_keywords': 'private chef, in-suite dining, personal chef, luxury dining',
|
||||
'is_active': True
|
||||
},
|
||||
|
||||
# Concierge Services
|
||||
{
|
||||
'name': '24/7 Concierge Service',
|
||||
'description': 'Our dedicated concierge team is available around the clock to assist with restaurant reservations, event tickets, transportation, and more.',
|
||||
'price': Decimal('0.00'),
|
||||
'category': 'Concierge',
|
||||
'slug': 'concierge-service',
|
||||
'image': 'https://images.unsplash.com/photo-1556761175-5973dc0f32e7?w=1200&h=800&fit=crop',
|
||||
'content': '<p>From restaurant reservations to exclusive experiences, our concierge team ensures your stay is seamless and memorable. Available 24/7 for all your needs.</p>',
|
||||
'sections': json.dumps([
|
||||
{
|
||||
'type': 'services',
|
||||
'title': 'Concierge Services',
|
||||
'content': 'Restaurant Reservations, Event Tickets, Transportation, City Tours, Special Occasions',
|
||||
'alignment': 'left',
|
||||
'is_visible': True
|
||||
}
|
||||
]),
|
||||
'meta_title': '24/7 Concierge Service | Personal Assistance',
|
||||
'meta_description': 'Round-the-clock concierge service for restaurant reservations, tickets, transportation, and personalized assistance.',
|
||||
'meta_keywords': 'concierge, personal assistant, hotel concierge, guest services',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'name': 'Airport Transfer',
|
||||
'description': 'Enjoy seamless airport transfers in our luxury vehicles. Professional drivers and comfortable transportation to and from the airport.',
|
||||
'price': Decimal('80.00'),
|
||||
'category': 'Transportation',
|
||||
'slug': 'airport-transfer',
|
||||
'image': 'https://images.unsplash.com/photo-1583485088076-494435075764?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Start and end your journey in comfort with our premium airport transfer service. Available for all major airports with luxury vehicles and professional drivers.</p>',
|
||||
'sections': None,
|
||||
'meta_title': 'Airport Transfer Service | Luxury Transportation',
|
||||
'meta_description': 'Premium airport transfer service with luxury vehicles and professional drivers. Seamless transportation to and from the airport.',
|
||||
'meta_keywords': 'airport transfer, transportation, airport shuttle, luxury car service',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'name': 'City Tour Service',
|
||||
'description': 'Discover the city with our guided tour service. Customized itineraries and expert local guides to show you the best attractions.',
|
||||
'price': Decimal('150.00'),
|
||||
'category': 'Concierge',
|
||||
'slug': 'city-tour-service',
|
||||
'image': 'https://images.unsplash.com/photo-1488646953014-85cb44e25828?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Explore the city with our professional tour guides. Choose from standard tours or customize your itinerary to visit your preferred attractions.</p>',
|
||||
'sections': None,
|
||||
'meta_title': 'City Tour Service | Guided Tours',
|
||||
'meta_description': 'Discover the city with our guided tour service. Expert guides, customized itineraries, and memorable experiences.',
|
||||
'meta_keywords': 'city tour, guided tour, sightseeing, local attractions',
|
||||
'is_active': True
|
||||
},
|
||||
|
||||
# Business Services
|
||||
{
|
||||
'name': 'Business Center Access',
|
||||
'description': 'Access our fully equipped business center with computers, printers, meeting rooms, and high-speed internet. Perfect for business travelers.',
|
||||
'price': Decimal('25.00'),
|
||||
'category': 'Business',
|
||||
'slug': 'business-center-access',
|
||||
'image': 'https://images.unsplash.com/photo-1497366216548-37526070297c?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Our business center provides all the facilities you need for productive work. Includes private workstations, printing services, and meeting spaces.</p>',
|
||||
'sections': None,
|
||||
'meta_title': 'Business Center | Professional Workspace',
|
||||
'meta_description': 'Fully equipped business center with computers, printers, meeting rooms, and high-speed internet for business travelers.',
|
||||
'meta_keywords': 'business center, workspace, meeting room, business facilities',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'name': 'Meeting Room Rental',
|
||||
'description': 'Host your business meetings in our state-of-the-art meeting rooms. Equipped with modern technology and professional amenities.',
|
||||
'price': Decimal('300.00'),
|
||||
'category': 'Business',
|
||||
'slug': 'meeting-room-rental',
|
||||
'image': 'https://images.unsplash.com/photo-1497366216548-37526070297c?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Our meeting rooms accommodate various group sizes and are equipped with AV equipment, high-speed internet, and catering options.</p>',
|
||||
'sections': None,
|
||||
'meta_title': 'Meeting Room Rental | Business Facilities',
|
||||
'meta_description': 'State-of-the-art meeting rooms with modern technology, AV equipment, and professional amenities for your business needs.',
|
||||
'meta_keywords': 'meeting room, conference room, business meeting, event space',
|
||||
'is_active': True
|
||||
},
|
||||
|
||||
# Additional Services
|
||||
{
|
||||
'name': 'Laundry & Dry Cleaning',
|
||||
'description': 'Professional laundry and dry cleaning services. Same-day service available for your convenience.',
|
||||
'price': Decimal('30.00'),
|
||||
'category': 'Housekeeping',
|
||||
'slug': 'laundry-dry-cleaning',
|
||||
'image': 'https://images.unsplash.com/photo-1582735689369-4fe89db7114c?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Keep your wardrobe fresh with our professional laundry and dry cleaning services. Same-day service available for urgent needs.</p>',
|
||||
'sections': None,
|
||||
'meta_title': 'Laundry & Dry Cleaning Service',
|
||||
'meta_description': 'Professional laundry and dry cleaning services with same-day service available. Keep your wardrobe fresh during your stay.',
|
||||
'meta_keywords': 'laundry, dry cleaning, clothing service, hotel laundry',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'name': 'Fitness Center Access',
|
||||
'description': 'Access our state-of-the-art fitness center with modern equipment, personal trainers, and group fitness classes.',
|
||||
'price': Decimal('0.00'),
|
||||
'category': 'Fitness',
|
||||
'slug': 'fitness-center-access',
|
||||
'image': 'https://images.unsplash.com/photo-1534438747741-0bf23ca35f0d?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Maintain your fitness routine in our fully equipped gym. Features cardio equipment, weight training, and personal training sessions available.</p>',
|
||||
'sections': None,
|
||||
'meta_title': 'Fitness Center | Hotel Gym Access',
|
||||
'meta_description': 'State-of-the-art fitness center with modern equipment, personal trainers, and group fitness classes. Stay fit during your stay.',
|
||||
'meta_keywords': 'fitness center, gym, workout, exercise, hotel gym',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'name': 'Personal Shopper',
|
||||
'description': 'Discover the city\'s best boutiques and shopping destinations with our expert personal shopper. Tailored shopping experiences.',
|
||||
'price': Decimal('200.00'),
|
||||
'category': 'Concierge',
|
||||
'slug': 'personal-shopper',
|
||||
'image': 'https://images.unsplash.com/photo-1528716321680-815a8cdb8bc7?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Let our personal shopper guide you to the best shopping destinations. From luxury boutiques to local markets, we\'ll help you find exactly what you\'re looking for.</p>',
|
||||
'sections': None,
|
||||
'meta_title': 'Personal Shopper Service | Shopping Assistance',
|
||||
'meta_description': 'Expert personal shopper service to guide you to the best boutiques and shopping destinations. Tailored shopping experiences.',
|
||||
'meta_keywords': 'personal shopper, shopping service, boutique shopping, shopping guide',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'name': 'Valet Parking',
|
||||
'description': 'Complimentary valet parking service for all hotel guests. Secure parking with professional valet attendants.',
|
||||
'price': Decimal('0.00'),
|
||||
'category': 'Transportation',
|
||||
'slug': 'valet-parking',
|
||||
'image': 'https://images.unsplash.com/photo-1502877338535-766e1452684a?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Enjoy the convenience of valet parking. Our professional attendants will safely park and retrieve your vehicle whenever needed.</p>',
|
||||
'sections': None,
|
||||
'meta_title': 'Valet Parking Service | Complimentary Parking',
|
||||
'meta_description': 'Complimentary valet parking service with professional attendants. Secure and convenient parking for all hotel guests.',
|
||||
'meta_keywords': 'valet parking, parking service, hotel parking',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'name': 'Butler Service',
|
||||
'description': 'Experience personalized butler service for suite guests. Available 24/7 to attend to your every need and ensure a flawless stay.',
|
||||
'price': Decimal('0.00'),
|
||||
'category': 'Concierge',
|
||||
'slug': 'butler-service',
|
||||
'image': 'https://images.unsplash.com/photo-1556761175-5973dc0f32e7?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Our dedicated butlers provide personalized service to suite guests. From unpacking to arranging special requests, we ensure every detail is perfect.</p>',
|
||||
'sections': None,
|
||||
'meta_title': 'Butler Service | Personalized Assistance',
|
||||
'meta_description': 'Personalized butler service for suite guests. Available 24/7 to attend to your every need and ensure a flawless stay.',
|
||||
'meta_keywords': 'butler service, personal butler, suite service, luxury service',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'name': 'Event Planning',
|
||||
'description': 'Let our expert event planners organize your special occasion. From intimate dinners to grand celebrations, we handle every detail.',
|
||||
'price': Decimal('500.00'),
|
||||
'category': 'Events',
|
||||
'slug': 'event-planning',
|
||||
'image': 'https://images.unsplash.com/photo-1519167758481-83f29da1c4fe?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Our event planning team will work with you to create unforgettable celebrations. From venue selection to catering and entertainment, we manage it all.</p>',
|
||||
'sections': None,
|
||||
'meta_title': 'Event Planning Service | Special Occasions',
|
||||
'meta_description': 'Expert event planning service for special occasions. From intimate dinners to grand celebrations, we handle every detail.',
|
||||
'meta_keywords': 'event planning, party planning, special events, celebration planning',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'name': 'Photography Service',
|
||||
'description': 'Capture your special moments with our professional photography service. Available for events, portraits, and special occasions.',
|
||||
'price': Decimal('300.00'),
|
||||
'category': 'Events',
|
||||
'slug': 'photography-service',
|
||||
'image': 'https://images.unsplash.com/photo-1516035069371-29a1b244cc32?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Our professional photographers will capture your special moments with artistic flair. Perfect for weddings, anniversaries, and other celebrations.</p>',
|
||||
'sections': None,
|
||||
'meta_title': 'Professional Photography Service',
|
||||
'meta_description': 'Professional photography service for events, portraits, and special occasions. Capture your special moments with artistic flair.',
|
||||
'meta_keywords': 'photography, photographer, event photography, portrait photography',
|
||||
'is_active': True
|
||||
},
|
||||
{
|
||||
'name': 'Babysitting Service',
|
||||
'description': 'Professional babysitting service for families. Certified caregivers available to watch your children while you enjoy your stay.',
|
||||
'price': Decimal('50.00'),
|
||||
'category': 'Family',
|
||||
'slug': 'babysitting-service',
|
||||
'image': 'https://images.unsplash.com/photo-1503454537195-1dcabb73ffb9?w=1200&h=800&fit=crop',
|
||||
'content': '<p>Enjoy peace of mind with our professional babysitting service. All caregivers are certified and experienced in childcare.</p>',
|
||||
'sections': None,
|
||||
'meta_title': 'Babysitting Service | Childcare',
|
||||
'meta_description': 'Professional babysitting service with certified caregivers. Enjoy your stay while your children are safely cared for.',
|
||||
'meta_keywords': 'babysitting, childcare, kids service, family service',
|
||||
'is_active': True
|
||||
}
|
||||
]
|
||||
|
||||
return services
|
||||
|
||||
|
||||
def seed_services(db: Session, clear_existing: bool = False):
|
||||
"""Seed services into the database"""
|
||||
try:
|
||||
if clear_existing:
|
||||
logger.info('Clearing existing services...')
|
||||
db.query(Service).delete()
|
||||
db.commit()
|
||||
logger.info('Existing services cleared.')
|
||||
|
||||
services_data = get_services_data()
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
created_count = 0
|
||||
updated_count = 0
|
||||
|
||||
for service_data in services_data:
|
||||
# Generate slug if not provided
|
||||
if not service_data.get('slug'):
|
||||
service_data['slug'] = slugify(service_data['name'])
|
||||
|
||||
existing = db.query(Service).filter(Service.slug == service_data['slug']).first()
|
||||
|
||||
if existing:
|
||||
logger.debug(f"Service '{service_data['name']}' already exists. Updating...")
|
||||
for key, value in service_data.items():
|
||||
setattr(existing, key, value)
|
||||
existing.updated_at = now
|
||||
updated_count += 1
|
||||
else:
|
||||
logger.debug(f"Creating service: {service_data['name']}")
|
||||
service = Service(
|
||||
**service_data,
|
||||
created_at=now,
|
||||
updated_at=now
|
||||
)
|
||||
db.add(service)
|
||||
created_count += 1
|
||||
|
||||
db.commit()
|
||||
logger.info(f'Successfully seeded services! Created: {created_count}, Updated: {updated_count}, Total: {len(services_data)}')
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error seeding services: {str(e)}', exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Seed hotel services')
|
||||
parser.add_argument(
|
||||
'--clear',
|
||||
action='store_true',
|
||||
help='Clear existing services before seeding'
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
seed_services(db, clear_existing=args.clear)
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed services: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
339
Backend/seeders/settings_seeder.py
Normal file
339
Backend/seeders/settings_seeder.py
Normal file
@@ -0,0 +1,339 @@
|
||||
"""
|
||||
Settings Seeder
|
||||
Seeds the database with system settings
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
|
||||
# Add parent directory to path to import modules
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal
|
||||
from src.shared.config.logging_config import get_logger
|
||||
from src.system.models.system_settings import SystemSettings
|
||||
from src.auth.models.user import User
|
||||
|
||||
# Import all models to ensure relationships are loaded correctly
|
||||
from src.models import *
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_settings_data():
|
||||
"""Generate comprehensive system settings data"""
|
||||
|
||||
return [
|
||||
# Company Settings
|
||||
{
|
||||
'key': 'company_name',
|
||||
'value': 'Luxury Hotel & Resort',
|
||||
'description': 'The official name of the hotel/company'
|
||||
},
|
||||
{
|
||||
'key': 'company_tagline',
|
||||
'value': 'Experience Unparalleled Elegance and Comfort',
|
||||
'description': 'Company tagline or slogan'
|
||||
},
|
||||
{
|
||||
'key': 'company_logo_url',
|
||||
'value': 'https://ui-avatars.com/api/?name=Luxury+Hotel&background=d4af37&color=fff&size=400&bold=true&font-size=0.5',
|
||||
'description': 'URL to the company logo image'
|
||||
},
|
||||
{
|
||||
'key': 'company_favicon_url',
|
||||
'value': 'https://ui-avatars.com/api/?name=LH&background=d4af37&color=fff&size=64&bold=true',
|
||||
'description': 'URL to the company favicon image'
|
||||
},
|
||||
{
|
||||
'key': 'company_phone',
|
||||
'value': '+1 (555) 123-4567',
|
||||
'description': 'Primary company phone number'
|
||||
},
|
||||
{
|
||||
'key': 'company_email',
|
||||
'value': 'info@luxuryhotel.com',
|
||||
'description': 'Primary company email address'
|
||||
},
|
||||
{
|
||||
'key': 'company_address',
|
||||
'value': '123 Luxury Avenue, Premium City, PC 12345, United States',
|
||||
'description': 'Company physical address'
|
||||
},
|
||||
{
|
||||
'key': 'tax_rate',
|
||||
'value': '10.0',
|
||||
'description': 'Default tax rate percentage (e.g., 10.0 for 10%)'
|
||||
},
|
||||
{
|
||||
'key': 'chat_working_hours_start',
|
||||
'value': '9',
|
||||
'description': 'Chat support working hours start (24-hour format, e.g., 9 for 9 AM)'
|
||||
},
|
||||
{
|
||||
'key': 'chat_working_hours_end',
|
||||
'value': '18',
|
||||
'description': 'Chat support working hours end (24-hour format, e.g., 18 for 6 PM)'
|
||||
},
|
||||
|
||||
# Platform Settings
|
||||
{
|
||||
'key': 'platform_currency',
|
||||
'value': 'USD',
|
||||
'description': 'Default platform currency code (ISO 4217 format, e.g., USD, EUR, GBP)'
|
||||
},
|
||||
|
||||
# Payment Gateway Settings (Placeholder values - should be configured in production)
|
||||
{
|
||||
'key': 'stripe_secret_key',
|
||||
'value': '',
|
||||
'description': 'Stripe secret API key (configure in production)'
|
||||
},
|
||||
{
|
||||
'key': 'stripe_publishable_key',
|
||||
'value': '',
|
||||
'description': 'Stripe publishable API key (configure in production)'
|
||||
},
|
||||
{
|
||||
'key': 'stripe_webhook_secret',
|
||||
'value': '',
|
||||
'description': 'Stripe webhook secret for verifying webhook events (configure in production)'
|
||||
},
|
||||
{
|
||||
'key': 'paypal_client_id',
|
||||
'value': '',
|
||||
'description': 'PayPal client ID (configure in production)'
|
||||
},
|
||||
{
|
||||
'key': 'paypal_client_secret',
|
||||
'value': '',
|
||||
'description': 'PayPal client secret (configure in production)'
|
||||
},
|
||||
{
|
||||
'key': 'paypal_mode',
|
||||
'value': 'sandbox',
|
||||
'description': 'PayPal mode: "sandbox" for testing, "live" for production'
|
||||
},
|
||||
{
|
||||
'key': 'borica_terminal_id',
|
||||
'value': '',
|
||||
'description': 'Borica terminal ID (configure if using Borica payment gateway)'
|
||||
},
|
||||
{
|
||||
'key': 'borica_merchant_id',
|
||||
'value': '',
|
||||
'description': 'Borica merchant ID (configure if using Borica payment gateway)'
|
||||
},
|
||||
{
|
||||
'key': 'borica_private_key_path',
|
||||
'value': '',
|
||||
'description': 'Path to Borica private key file (configure if using Borica)'
|
||||
},
|
||||
{
|
||||
'key': 'borica_certificate_path',
|
||||
'value': '',
|
||||
'description': 'Path to Borica certificate file (configure if using Borica)'
|
||||
},
|
||||
{
|
||||
'key': 'borica_gateway_url',
|
||||
'value': '',
|
||||
'description': 'Borica gateway URL (configure if using Borica payment gateway)'
|
||||
},
|
||||
{
|
||||
'key': 'borica_mode',
|
||||
'value': 'test',
|
||||
'description': 'Borica mode: "test" for testing, "production" for live transactions'
|
||||
},
|
||||
|
||||
# SMTP Settings (Placeholder values - should be configured in production)
|
||||
{
|
||||
'key': 'smtp_host',
|
||||
'value': '',
|
||||
'description': 'SMTP server hostname (e.g., smtp.gmail.com, smtp.sendgrid.net)'
|
||||
},
|
||||
{
|
||||
'key': 'smtp_port',
|
||||
'value': '587',
|
||||
'description': 'SMTP server port (587 for STARTTLS, 465 for SSL)'
|
||||
},
|
||||
{
|
||||
'key': 'smtp_user',
|
||||
'value': '',
|
||||
'description': 'SMTP authentication username/email'
|
||||
},
|
||||
{
|
||||
'key': 'smtp_password',
|
||||
'value': '',
|
||||
'description': 'SMTP authentication password (stored securely)'
|
||||
},
|
||||
{
|
||||
'key': 'smtp_from_email',
|
||||
'value': 'noreply@luxuryhotel.com',
|
||||
'description': 'Default "From" email address for outgoing emails'
|
||||
},
|
||||
{
|
||||
'key': 'smtp_from_name',
|
||||
'value': 'Luxury Hotel & Resort',
|
||||
'description': 'Default "From" name for outgoing emails'
|
||||
},
|
||||
{
|
||||
'key': 'smtp_use_tls',
|
||||
'value': 'true',
|
||||
'description': 'Use TLS/SSL for SMTP connection (true for port 465, false for port 587 with STARTTLS)'
|
||||
},
|
||||
|
||||
# Security Settings
|
||||
{
|
||||
'key': 'recaptcha_site_key',
|
||||
'value': '',
|
||||
'description': 'Google reCAPTCHA site key (configure if using reCAPTCHA)'
|
||||
},
|
||||
{
|
||||
'key': 'recaptcha_secret_key',
|
||||
'value': '',
|
||||
'description': 'Google reCAPTCHA secret key (configure if using reCAPTCHA)'
|
||||
},
|
||||
{
|
||||
'key': 'recaptcha_enabled',
|
||||
'value': 'false',
|
||||
'description': 'Enable/disable reCAPTCHA verification (true/false)'
|
||||
},
|
||||
|
||||
# Additional Settings
|
||||
{
|
||||
'key': 'booking_confirmation_email_enabled',
|
||||
'value': 'true',
|
||||
'description': 'Enable automatic booking confirmation emails (true/false)'
|
||||
},
|
||||
{
|
||||
'key': 'booking_cancellation_email_enabled',
|
||||
'value': 'true',
|
||||
'description': 'Enable automatic booking cancellation emails (true/false)'
|
||||
},
|
||||
{
|
||||
'key': 'newsletter_enabled',
|
||||
'value': 'true',
|
||||
'description': 'Enable newsletter subscription feature (true/false)'
|
||||
},
|
||||
{
|
||||
'key': 'maintenance_mode',
|
||||
'value': 'false',
|
||||
'description': 'Enable maintenance mode (true/false)'
|
||||
},
|
||||
{
|
||||
'key': 'maintenance_message',
|
||||
'value': 'We are currently performing scheduled maintenance. Please check back soon.',
|
||||
'description': 'Message to display when maintenance mode is enabled'
|
||||
},
|
||||
{
|
||||
'key': 'default_checkin_time',
|
||||
'value': '15:00',
|
||||
'description': 'Default check-in time (24-hour format, e.g., 15:00 for 3 PM)'
|
||||
},
|
||||
{
|
||||
'key': 'default_checkout_time',
|
||||
'value': '11:00',
|
||||
'description': 'Default check-out time (24-hour format, e.g., 11:00 for 11 AM)'
|
||||
},
|
||||
{
|
||||
'key': 'cancellation_hours',
|
||||
'value': '24',
|
||||
'description': 'Number of hours before check-in that cancellation is allowed without penalty'
|
||||
},
|
||||
{
|
||||
'key': 'max_guests_per_room',
|
||||
'value': '4',
|
||||
'description': 'Maximum number of guests allowed per room'
|
||||
},
|
||||
{
|
||||
'key': 'min_booking_advance_days',
|
||||
'value': '0',
|
||||
'description': 'Minimum number of days in advance required for booking (0 = same day allowed)'
|
||||
},
|
||||
{
|
||||
'key': 'max_booking_advance_days',
|
||||
'value': '365',
|
||||
'description': 'Maximum number of days in advance bookings can be made'
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
def seed_settings(db: Session, clear_existing: bool = False, admin_user_id: int = None):
|
||||
"""Seed system settings into the database"""
|
||||
try:
|
||||
if clear_existing:
|
||||
logger.info('Clearing existing system settings...')
|
||||
db.query(SystemSettings).delete()
|
||||
db.commit()
|
||||
logger.info('Existing system settings cleared.')
|
||||
|
||||
# Get admin user if not provided
|
||||
if admin_user_id is None:
|
||||
admin_user = db.query(User).filter(User.email == 'admin@hotel.com').first()
|
||||
if admin_user:
|
||||
admin_user_id = admin_user.id
|
||||
else:
|
||||
logger.warning('Admin user not found. Settings will be created without updated_by_id.')
|
||||
|
||||
settings_data = get_settings_data()
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
created_count = 0
|
||||
updated_count = 0
|
||||
|
||||
for setting_data in settings_data:
|
||||
existing = db.query(SystemSettings).filter(SystemSettings.key == setting_data['key']).first()
|
||||
|
||||
if existing:
|
||||
logger.debug(f"Setting '{setting_data['key']}' already exists. Updating...")
|
||||
existing.value = setting_data['value']
|
||||
existing.description = setting_data['description']
|
||||
if admin_user_id:
|
||||
existing.updated_by_id = admin_user_id
|
||||
existing.updated_at = now
|
||||
updated_count += 1
|
||||
else:
|
||||
logger.debug(f"Creating setting: {setting_data['key']}")
|
||||
setting = SystemSettings(
|
||||
key=setting_data['key'],
|
||||
value=setting_data['value'],
|
||||
description=setting_data['description'],
|
||||
updated_by_id=admin_user_id,
|
||||
updated_at=now
|
||||
)
|
||||
db.add(setting)
|
||||
created_count += 1
|
||||
|
||||
db.commit()
|
||||
logger.info(f'Successfully seeded system settings! Created: {created_count}, Updated: {updated_count}, Total: {len(settings_data)}')
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error seeding system settings: {str(e)}', exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Seed system settings')
|
||||
parser.add_argument(
|
||||
'--clear',
|
||||
action='store_true',
|
||||
help='Clear existing settings before seeding'
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
seed_settings(db, clear_existing=args.clear)
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed system settings: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
178
Backend/seeders/terms_seeder.py
Normal file
178
Backend/seeders/terms_seeder.py
Normal file
@@ -0,0 +1,178 @@
|
||||
"""
|
||||
Terms of Use Page Seeder
|
||||
Seeds the database with comprehensive terms of use content
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
|
||||
# Add parent directory to path to allow importing from src
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal
|
||||
from src.shared.config.logging_config import get_logger
|
||||
from src.content.models.page_content import PageContent, PageType
|
||||
|
||||
# Import all models to ensure relationships are loaded
|
||||
from src.models import *
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_terms_page_data():
|
||||
"""Generate comprehensive terms of use page data"""
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
return {
|
||||
'page_type': PageType.TERMS,
|
||||
'title': 'Terms of Use',
|
||||
'subtitle': 'Terms and Conditions for Using Our Services',
|
||||
'description': 'Please read these terms and conditions carefully before using our website or services. By using our services, you agree to be bound by these terms.',
|
||||
'content': """
|
||||
<h2>1. Acceptance of Terms</h2>
|
||||
<p>By accessing and using the Luxury Hotel & Resort website and services, you accept and agree to be bound by the terms and provision of this agreement. If you do not agree to these terms, please do not use our services.</p>
|
||||
|
||||
<h2>2. Use of Website</h2>
|
||||
<h3>2.1 Eligibility</h3>
|
||||
<p>You must be at least 18 years old to make a reservation or use our services. By using our website, you represent and warrant that you are at least 18 years of age and have the legal capacity to enter into this agreement.</p>
|
||||
|
||||
<h3>2.2 User Account</h3>
|
||||
<p>If you create an account with us, you are responsible for maintaining the confidentiality of your account and password. You agree to accept responsibility for all activities that occur under your account.</p>
|
||||
|
||||
<h3>2.3 Prohibited Uses</h3>
|
||||
<p>You agree not to use our website or services:</p>
|
||||
<ul>
|
||||
<li>For any unlawful purpose or to solicit others to perform unlawful acts</li>
|
||||
<li>To violate any international, federal, provincial, or state regulations, rules, laws, or local ordinances</li>
|
||||
<li>To infringe upon or violate our intellectual property rights or the intellectual property rights of others</li>
|
||||
<li>To harass, abuse, insult, harm, defame, slander, disparage, intimidate, or discriminate</li>
|
||||
<li>To submit false or misleading information</li>
|
||||
<li>To upload or transmit viruses or any other type of malicious code</li>
|
||||
<li>To collect or track the personal information of others</li>
|
||||
<li>To spam, phish, pharm, pretext, spider, crawl, or scrape</li>
|
||||
<li>For any obscene or immoral purpose</li>
|
||||
<li>To interfere with or circumvent the security features of our website</li>
|
||||
</ul>
|
||||
|
||||
<h2>3. Reservations and Bookings</h2>
|
||||
<h3>3.1 Reservation Terms</h3>
|
||||
<p>When you make a reservation through our website or by phone, you agree to:</p>
|
||||
<ul>
|
||||
<li>Provide accurate and complete information</li>
|
||||
<li>Use a valid payment method</li>
|
||||
<li>Pay all charges incurred by your account</li>
|
||||
<li>Comply with our cancellation and refund policies</li>
|
||||
</ul>
|
||||
|
||||
<h3>3.2 Pricing</h3>
|
||||
<p>All prices are displayed in the currency specified and are subject to change without notice. We reserve the right to correct any pricing errors. Taxes and fees may apply and will be disclosed at the time of booking.</p>
|
||||
|
||||
<h3>3.3 Payment</h3>
|
||||
<p>Payment is required at the time of booking or as specified in your reservation confirmation. We accept major credit cards and other payment methods as indicated on our website.</p>
|
||||
|
||||
<h2>4. Cancellation and Refund Policy</h2>
|
||||
<p>Cancellation and refund terms vary by rate type and are specified at the time of booking. Please refer to your booking confirmation and our Refund Policy for detailed information.</p>
|
||||
|
||||
<h2>5. Intellectual Property</h2>
|
||||
<p>The content on our website, including text, graphics, logos, images, and software, is the property of Luxury Hotel & Resort or its content suppliers and is protected by copyright and other intellectual property laws. You may not reproduce, distribute, modify, or create derivative works from any content without our express written permission.</p>
|
||||
|
||||
<h2>6. User Content</h2>
|
||||
<p>If you submit content to our website (such as reviews, comments, or photos), you grant us a non-exclusive, royalty-free, perpetual, and worldwide license to use, reproduce, modify, and distribute such content for any purpose.</p>
|
||||
|
||||
<h2>7. Limitation of Liability</h2>
|
||||
<p>To the fullest extent permitted by law, Luxury Hotel & Resort shall not be liable for any indirect, incidental, special, consequential, or punitive damages, or any loss of profits or revenues, whether incurred directly or indirectly, or any loss of data, use, goodwill, or other intangible losses resulting from your use of our services.</p>
|
||||
|
||||
<h2>8. Indemnification</h2>
|
||||
<p>You agree to indemnify, defend, and hold harmless Luxury Hotel & Resort and its officers, directors, employees, and agents from any claims, damages, losses, liabilities, and expenses (including legal fees) arising out of or relating to your use of our services or violation of these terms.</p>
|
||||
|
||||
<h2>9. Disclaimer of Warranties</h2>
|
||||
<p>Our services are provided "as is" and "as available" without warranties of any kind, either express or implied. We do not warrant that our services will be uninterrupted, secure, or error-free.</p>
|
||||
|
||||
<h2>10. Third-Party Links</h2>
|
||||
<p>Our website may contain links to third-party websites. We are not responsible for the content, privacy policies, or practices of third-party websites. Your use of third-party websites is at your own risk.</p>
|
||||
|
||||
<h2>11. Force Majeure</h2>
|
||||
<p>We shall not be liable for any failure or delay in performance under these terms which is due to circumstances beyond our reasonable control, including but not limited to natural disasters, war, terrorism, pandemics, government actions, or other force majeure events.</p>
|
||||
|
||||
<h2>12. Governing Law</h2>
|
||||
<p>These terms shall be governed by and construed in accordance with the laws of the jurisdiction in which our hotel is located, without regard to its conflict of law provisions.</p>
|
||||
|
||||
<h2>13. Dispute Resolution</h2>
|
||||
<p>Any disputes arising out of or relating to these terms or our services shall be resolved through binding arbitration in accordance with the rules of the applicable arbitration association, except where prohibited by law.</p>
|
||||
|
||||
<h2>14. Changes to Terms</h2>
|
||||
<p>We reserve the right to modify these terms at any time. Changes will be effective immediately upon posting on our website. Your continued use of our services after changes are posted constitutes acceptance of the modified terms.</p>
|
||||
|
||||
<h2>15. Severability</h2>
|
||||
<p>If any provision of these terms is found to be unenforceable or invalid, that provision shall be limited or eliminated to the minimum extent necessary, and the remaining provisions shall remain in full force and effect.</p>
|
||||
|
||||
<h2>16. Entire Agreement</h2>
|
||||
<p>These terms constitute the entire agreement between you and Luxury Hotel & Resort regarding the use of our services and supersede all prior agreements and understandings.</p>
|
||||
|
||||
<h2>17. Contact Information</h2>
|
||||
<p>If you have any questions about these Terms of Use, please contact us:</p>
|
||||
<ul>
|
||||
<li><strong>Email:</strong> legal@luxuryhotel.com</li>
|
||||
<li><strong>Phone:</strong> +1 (555) 123-4567</li>
|
||||
<li><strong>Address:</strong> 123 Luxury Avenue, Premium City, PC 12345, United States</li>
|
||||
</ul>
|
||||
|
||||
<p><em>Last Updated: {}</em></p>
|
||||
""".format(now.strftime('%B %d, %Y')),
|
||||
'meta_title': 'Terms of Use | Luxury Hotel & Resort - Terms and Conditions',
|
||||
'meta_description': 'Read our terms and conditions for using our website and services. By using our services, you agree to these terms.',
|
||||
'meta_keywords': 'terms of use, terms and conditions, user agreement, legal terms, hotel terms',
|
||||
'og_title': 'Terms of Use - Luxury Hotel & Resort',
|
||||
'og_description': 'Terms and conditions for using our website and services. Please read carefully before using our services.',
|
||||
'og_image': 'https://images.unsplash.com/photo-1556761175-5973dc0f32e7?w=1200&h=630&fit=crop',
|
||||
'canonical_url': 'https://luxuryhotel.com/terms',
|
||||
'is_active': True,
|
||||
'created_at': now,
|
||||
'updated_at': now
|
||||
}
|
||||
|
||||
|
||||
def seed_terms_page(db: Session):
|
||||
"""Seed terms of use page content into the database"""
|
||||
try:
|
||||
terms_data = get_terms_page_data()
|
||||
|
||||
# Check if terms page content already exists
|
||||
existing_content = db.query(PageContent).filter(PageContent.page_type == PageType.TERMS).first()
|
||||
|
||||
if existing_content:
|
||||
logger.info('Updating existing terms of use page content...')
|
||||
for key, value in terms_data.items():
|
||||
if key not in ['id', 'page_type', 'created_at']:
|
||||
setattr(existing_content, key, value)
|
||||
existing_content.updated_at = datetime.now(timezone.utc)
|
||||
else:
|
||||
logger.info('Creating new terms of use page content...')
|
||||
terms_page = PageContent(**terms_data)
|
||||
db.add(terms_page)
|
||||
|
||||
db.commit()
|
||||
logger.info('Terms of use page content seeded successfully!')
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f'Error seeding terms of use page: {str(e)}', exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
seed_terms_page(db)
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed terms of use page: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
198
Backend/seeders/user_seeder.py
Normal file
198
Backend/seeders/user_seeder.py
Normal file
@@ -0,0 +1,198 @@
|
||||
"""
|
||||
User and Role Seeder
|
||||
Creates default roles and an admin user
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
import bcrypt
|
||||
|
||||
# Add parent directory to path to import modules
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from src.shared.config.database import SessionLocal
|
||||
# Import all models to ensure relationships are properly initialized
|
||||
from src.models import *
|
||||
from src.auth.models.role import Role
|
||||
from src.auth.models.user import User
|
||||
from src.shared.config.logging_config import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def get_roles_data():
|
||||
"""Generate default roles data"""
|
||||
return [
|
||||
{
|
||||
'name': 'admin',
|
||||
'description': 'Full system access with all administrative privileges'
|
||||
},
|
||||
{
|
||||
'name': 'staff',
|
||||
'description': 'Hotel staff with operational access'
|
||||
},
|
||||
{
|
||||
'name': 'customer',
|
||||
'description': 'Regular customer/guest user'
|
||||
},
|
||||
{
|
||||
'name': 'accountant',
|
||||
'description': 'Financial management and accounting access'
|
||||
},
|
||||
|
||||
{
|
||||
'name': 'housekeeping',
|
||||
'description': 'Housekeeping and room management access'
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
def seed_roles(db: Session):
|
||||
"""Seed roles into the database"""
|
||||
try:
|
||||
roles_data = get_roles_data()
|
||||
created_count = 0
|
||||
updated_count = 0
|
||||
role_map = {}
|
||||
|
||||
for role_data in roles_data:
|
||||
existing = db.query(Role).filter(Role.name == role_data['name']).first()
|
||||
|
||||
if existing:
|
||||
logger.info(f'Role already exists: {role_data["name"]}')
|
||||
role_map[role_data['name']] = existing
|
||||
else:
|
||||
logger.info(f'Creating role: {role_data["name"]}')
|
||||
role = Role(**role_data)
|
||||
db.add(role)
|
||||
db.flush() # Flush to get the ID
|
||||
role_map[role_data['name']] = role
|
||||
created_count += 1
|
||||
|
||||
db.commit()
|
||||
logger.info(f'Role seeding completed! Created: {created_count}, Existing: {len(roles_data) - created_count}')
|
||||
return role_map
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f'Error seeding roles: {str(e)}', exc_info=True)
|
||||
db.rollback()
|
||||
raise
|
||||
|
||||
|
||||
def seed_admin_user(db: Session, admin_role: Role, email: str = 'admin@hotel.com', password: str = 'admin123', full_name: str = 'Admin User'):
|
||||
"""Seed admin user into the database"""
|
||||
try:
|
||||
# Check if admin user already exists
|
||||
existing = db.query(User).filter(User.email == email).first()
|
||||
|
||||
if existing:
|
||||
logger.info(f'Admin user already exists: {email}')
|
||||
# Update role if needed
|
||||
if existing.role_id != admin_role.id:
|
||||
existing.role_id = admin_role.id
|
||||
existing.updated_at = datetime.now(timezone.utc)
|
||||
db.commit()
|
||||
logger.info(f'Updated admin user role: {email}')
|
||||
return existing
|
||||
|
||||
# Create new admin user
|
||||
logger.info(f'Creating admin user: {email}')
|
||||
password_bytes = password.encode('utf-8')
|
||||
salt = bcrypt.gensalt()
|
||||
hashed_password = bcrypt.hashpw(password_bytes, salt).decode('utf-8')
|
||||
|
||||
admin_user = User(
|
||||
email=email,
|
||||
password=hashed_password,
|
||||
full_name=full_name,
|
||||
role_id=admin_role.id,
|
||||
is_active=True,
|
||||
phone=None,
|
||||
address=None
|
||||
)
|
||||
|
||||
db.add(admin_user)
|
||||
db.commit()
|
||||
db.refresh(admin_user)
|
||||
logger.info(f'Admin user created successfully: {email}')
|
||||
return admin_user
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f'Error seeding admin user: {str(e)}', exc_info=True)
|
||||
db.rollback()
|
||||
raise
|
||||
|
||||
|
||||
def seed_users_and_roles(db: Session, admin_email: str = 'admin@hotel.com', admin_password: str = 'admin123', admin_name: str = 'Admin User'):
|
||||
"""Seed roles and admin user"""
|
||||
try:
|
||||
# First, seed roles
|
||||
role_map = seed_roles(db)
|
||||
|
||||
# Get admin role
|
||||
admin_role = role_map.get('admin')
|
||||
if not admin_role:
|
||||
raise ValueError('Admin role not found after seeding')
|
||||
|
||||
# Seed admin user
|
||||
admin_user = seed_admin_user(db, admin_role, admin_email, admin_password, admin_name)
|
||||
|
||||
return role_map, admin_user
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f'Error seeding users and roles: {str(e)}', exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function to run the seeder"""
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Seed roles and admin user')
|
||||
parser.add_argument(
|
||||
'--email',
|
||||
default='admin@hotel.com',
|
||||
help='Admin user email (default: admin@hotel.com)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--password',
|
||||
default='admin123',
|
||||
help='Admin user password (default: admin123)'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--name',
|
||||
default='Admin User',
|
||||
help='Admin user full name (default: Admin User)'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
logger.info('Starting user and role seeder...')
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
role_map, admin_user = seed_users_and_roles(
|
||||
db,
|
||||
admin_email=args.email,
|
||||
admin_password=args.password,
|
||||
admin_name=args.name
|
||||
)
|
||||
logger.info(f'User and role seeder completed successfully!')
|
||||
logger.info(f'Admin user: {admin_user.email} (ID: {admin_user.id})')
|
||||
logger.info(f'Roles created: {len(role_map)}')
|
||||
print(f'\n✓ Admin user created successfully!')
|
||||
print(f' Email: {admin_user.email}')
|
||||
print(f' Password: {args.password}')
|
||||
print(f' Role: admin')
|
||||
print(f'\n⚠️ IMPORTANT: Change the default password after first login!')
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to seed users and roles: {str(e)}', exc_info=True)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user