- بکاند: ستون role برای admin_users (admin/creator) + author_id برای مقالهها - نقشگارد روی کل روتر مدیریتی: creator فقط لیست/ساخت/خواندن/ویرایش پیشنویسهای «خودش» را میبیند؛ بقیهٔ مسیرهای مدیریتی ۴۰۳ - ساخت توسط creator همیشه پیشنویس است و ویرایشش هرگز منتشر نمیشود (حتی تلاش برای publish در payload نادیده گرفته میشود) - حذف/ترتیببندی/پیامها/خبرنامه/سایر بخشها برای creator ممنوع - لاگین نقش را برمیگرداند؛ پنل: AdminBar نویسنده فقط «نوشتن مقاله» + زبان ویرایش + رمز + خروج دارد؛ دکمههای انتشار/حذف مقاله فقط برای admin - ورود creator مستقیم به صفحهٔ نوشتن مقاله هدایت میشود
506 lines
24 KiB
Python
506 lines
24 KiB
Python
from datetime import datetime, timezone
|
|
from typing import Optional
|
|
|
|
from sqlalchemy import JSON, Boolean, DateTime, Integer, String, Text
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from .database import Base
|
|
|
|
|
|
def utcnow() -> datetime:
|
|
return datetime.now(timezone.utc)
|
|
|
|
|
|
# ستونهای *_en معادل انگلیسی فیلدهای متنیِ قابل نمایش هستند؛
|
|
# مقدار خالی یعنی «ترجمهای ثبت نشده» و فرانتاند به نسخه فارسی برمیگردد.
|
|
|
|
|
|
class AdminUser(Base):
|
|
__tablename__ = "admin_users"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
username: Mapped[str] = mapped_column(String(64), unique=True, index=True)
|
|
password_hash: Mapped[str] = mapped_column(String(255))
|
|
# 'admin' همهکاره — 'creator' فقط نویسندهٔ محتوا (پیشنویس مقالههای خودش)
|
|
role: Mapped[str] = mapped_column(String(16), default='admin')
|
|
|
|
|
|
class Brand(Base):
|
|
__tablename__ = "brand"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(128), default="")
|
|
name_en: Mapped[str] = mapped_column(String(128), default="")
|
|
logo: Mapped[str] = mapped_column(Text, default="")
|
|
hero: Mapped[str] = mapped_column(Text, default="")
|
|
contact_bg: Mapped[str] = mapped_column(Text, default="")
|
|
phone: Mapped[str] = mapped_column(String(64), default="")
|
|
phone_href: Mapped[str] = mapped_column(String(128), default="")
|
|
email: Mapped[str] = mapped_column(String(128), default="")
|
|
address: Mapped[str] = mapped_column(Text, default="")
|
|
address_en: Mapped[str] = mapped_column(Text, default="")
|
|
|
|
|
|
class Service(Base):
|
|
__tablename__ = "services"
|
|
|
|
position: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
title: Mapped[str] = mapped_column(String(256))
|
|
title_en: Mapped[str] = mapped_column(String(256), default="")
|
|
desc: Mapped[str] = mapped_column(Text, default="")
|
|
desc_en: Mapped[str] = mapped_column(Text, default="")
|
|
icon: Mapped[str] = mapped_column(String(32), default="draft")
|
|
|
|
|
|
class Project(Base):
|
|
__tablename__ = "projects"
|
|
|
|
position: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
slug: Mapped[str] = mapped_column(String(128), unique=True, index=True)
|
|
title: Mapped[str] = mapped_column(String(256))
|
|
title_en: Mapped[str] = mapped_column(String(256), default="")
|
|
location: Mapped[str] = mapped_column(String(128), default="")
|
|
location_en: Mapped[str] = mapped_column(String(128), default="")
|
|
year: Mapped[str] = mapped_column(String(64), default="")
|
|
year_en: Mapped[str] = mapped_column(String(64), default="")
|
|
status: Mapped[str] = mapped_column(String(16), default="done") # done | progress
|
|
image: Mapped[str] = mapped_column(Text, default="")
|
|
gallery: Mapped[list] = mapped_column(JSON, default=list)
|
|
area: Mapped[str] = mapped_column(String(64), default="")
|
|
area_en: Mapped[str] = mapped_column(String(64), default="")
|
|
floors: Mapped[str] = mapped_column(String(64), default="")
|
|
floors_en: Mapped[str] = mapped_column(String(64), default="")
|
|
land_area: Mapped[str] = mapped_column(String(64), default="")
|
|
pilot_floors: Mapped[str] = mapped_column(String(32), default="")
|
|
units_residential: Mapped[str] = mapped_column(String(32), default="")
|
|
units_commercial: Mapped[str] = mapped_column(String(32), default="")
|
|
units_office: Mapped[str] = mapped_column(String(32), default="")
|
|
client: Mapped[str] = mapped_column(String(128), default="")
|
|
client_en: Mapped[str] = mapped_column(String(128), default="")
|
|
# مشخصات تکمیلی پروژه — به درخواست تیم: نوع پروژه و کاربری
|
|
project_type: Mapped[str] = mapped_column(String(128), default="")
|
|
project_type_en: Mapped[str] = mapped_column(String(128), default="")
|
|
usage: Mapped[str] = mapped_column(String(128), default="")
|
|
usage_en: Mapped[str] = mapped_column(String(128), default="")
|
|
summary: Mapped[str] = mapped_column(Text, default="")
|
|
summary_en: Mapped[str] = mapped_column(Text, default="")
|
|
body: Mapped[list] = mapped_column(JSON, default=list)
|
|
body_en: Mapped[list] = mapped_column(JSON, default=list)
|
|
|
|
|
|
class Article(Base):
|
|
__tablename__ = "articles"
|
|
|
|
position: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
slug: Mapped[str] = mapped_column(String(128), unique=True, index=True)
|
|
title: Mapped[str] = mapped_column(String(256))
|
|
title_en: Mapped[str] = mapped_column(String(256), default="")
|
|
date: Mapped[str] = mapped_column(String(64), default="")
|
|
date_en: Mapped[str] = mapped_column(String(64), default="")
|
|
category: Mapped[str] = mapped_column(String(64), default="")
|
|
category_en: Mapped[str] = mapped_column(String(64), default="")
|
|
image: Mapped[str] = mapped_column(Text, default="")
|
|
# متن جایگزین و عنوان تصویر شاخص — سئو و دسترسپذیری
|
|
image_alt: Mapped[str] = mapped_column(String(256), default="")
|
|
image_title: Mapped[str] = mapped_column(String(256), default="")
|
|
read: Mapped[str] = mapped_column(String(32), default="")
|
|
read_en: Mapped[str] = mapped_column(String(32), default="")
|
|
excerpt: Mapped[str] = mapped_column(Text, default="")
|
|
excerpt_en: Mapped[str] = mapped_column(Text, default="")
|
|
body: Mapped[list] = mapped_column(JSON, default=list) # سند TipTap (تاریخی: لیست پاراگراف)
|
|
body_en: Mapped[dict] = mapped_column(JSON, default=dict) # سند TipTap انگلیسی
|
|
# پرسش و پاسخهای پایان مقاله — [{question, answer}]؛ برای نتایج غنی سئو (FAQPage)
|
|
faqs: Mapped[list] = mapped_column(JSON, default=list)
|
|
faqs_en: Mapped[Optional[list]] = mapped_column(JSON) # NULL یعنی بدون ترجمه — برگشت به فارسی
|
|
author_id: Mapped[int | None] = mapped_column(Integer, nullable=True) # نویسندهٔ creator — برای مقالههای ادمین NULL
|
|
# draft | published — پیشنویس فقط برای ادمین دیده میشود
|
|
status: Mapped[str] = mapped_column(String(16), default="published")
|
|
# کلمه کلیدی هدف چکلیست سئو — راهنمای نوشتن، در سایت نمایش داده نمیشود
|
|
seo_keyphrase: Mapped[str] = mapped_column(String(128), default="")
|
|
|
|
|
|
class Testimonial(Base):
|
|
__tablename__ = "testimonials"
|
|
|
|
position: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(128))
|
|
name_en: Mapped[str] = mapped_column(String(128), default="")
|
|
role: Mapped[str] = mapped_column(String(128), default="")
|
|
role_en: Mapped[str] = mapped_column(String(128), default="")
|
|
quote: Mapped[str] = mapped_column(Text, default="")
|
|
quote_en: Mapped[str] = mapped_column(Text, default="")
|
|
|
|
|
|
class Faq(Base):
|
|
__tablename__ = "faqs"
|
|
|
|
position: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
question: Mapped[str] = mapped_column(Text)
|
|
question_en: Mapped[str] = mapped_column(Text, default="")
|
|
answer: Mapped[str] = mapped_column(Text, default="")
|
|
answer_en: Mapped[str] = mapped_column(Text, default="")
|
|
|
|
|
|
class TeamMember(Base):
|
|
__tablename__ = "team"
|
|
|
|
position: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(128))
|
|
name_en: Mapped[str] = mapped_column(String(128), default="")
|
|
role: Mapped[str] = mapped_column(String(128), default="")
|
|
role_en: Mapped[str] = mapped_column(String(128), default="")
|
|
bio: Mapped[str] = mapped_column(Text, default="")
|
|
bio_en: Mapped[str] = mapped_column(Text, default="")
|
|
|
|
|
|
class TimelineItem(Base):
|
|
__tablename__ = "timeline"
|
|
|
|
position: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
year: Mapped[str] = mapped_column(String(32))
|
|
year_en: Mapped[str] = mapped_column(String(32), default="")
|
|
title: Mapped[str] = mapped_column(String(256))
|
|
title_en: Mapped[str] = mapped_column(String(256), default="")
|
|
desc: Mapped[str] = mapped_column(Text, default="")
|
|
desc_en: Mapped[str] = mapped_column(Text, default="")
|
|
image: Mapped[str] = mapped_column(Text, default="")
|
|
|
|
|
|
class Stat(Base):
|
|
__tablename__ = "stats"
|
|
|
|
position: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
value: Mapped[int] = mapped_column(Integer)
|
|
suffix: Mapped[str] = mapped_column(String(16), default="")
|
|
suffix_en: Mapped[str] = mapped_column(String(16), default="")
|
|
label: Mapped[str] = mapped_column(String(128))
|
|
label_en: Mapped[str] = mapped_column(String(128), default="")
|
|
|
|
|
|
class WhyUsItem(Base):
|
|
__tablename__ = "why_us"
|
|
|
|
position: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
title: Mapped[str] = mapped_column(String(256))
|
|
title_en: Mapped[str] = mapped_column(String(256), default="")
|
|
desc: Mapped[str] = mapped_column(Text, default="")
|
|
desc_en: Mapped[str] = mapped_column(Text, default="")
|
|
|
|
|
|
class BeforeAfter(Base):
|
|
__tablename__ = "before_after"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
title: Mapped[str] = mapped_column(String(256), default="")
|
|
title_en: Mapped[str] = mapped_column(String(256), default="")
|
|
lead: Mapped[str] = mapped_column(Text, default="")
|
|
lead_en: Mapped[str] = mapped_column(Text, default="")
|
|
before: Mapped[str] = mapped_column(Text, default="")
|
|
after: Mapped[str] = mapped_column(Text, default="")
|
|
before_label: Mapped[str] = mapped_column(String(128), default="")
|
|
before_label_en: Mapped[str] = mapped_column(String(128), default="")
|
|
after_label: Mapped[str] = mapped_column(String(128), default="")
|
|
after_label_en: Mapped[str] = mapped_column(String(128), default="")
|
|
|
|
|
|
class NavItem(Base):
|
|
__tablename__ = "nav_items"
|
|
|
|
position: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
label: Mapped[str] = mapped_column(String(64))
|
|
label_en: Mapped[str] = mapped_column(String(64), default="")
|
|
href: Mapped[str] = mapped_column(String(128))
|
|
|
|
|
|
class Hero(Base):
|
|
"""محتوای هیرو صفحه اصلی — رکورد یگانه."""
|
|
|
|
__tablename__ = "hero"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
kicker: Mapped[str] = mapped_column(Text, default="")
|
|
kicker_en: Mapped[str] = mapped_column(Text, default="")
|
|
title: Mapped[str] = mapped_column(Text, default="")
|
|
title_en: Mapped[str] = mapped_column(Text, default="")
|
|
title_highlight: Mapped[str] = mapped_column(String(128), default="")
|
|
title_highlight_en: Mapped[str] = mapped_column(String(128), default="")
|
|
subtitle: Mapped[str] = mapped_column(Text, default="")
|
|
subtitle_en: Mapped[str] = mapped_column(Text, default="")
|
|
badge_value: Mapped[str] = mapped_column(String(32), default="")
|
|
badge_value_en: Mapped[str] = mapped_column(String(32), default="")
|
|
badge_label: Mapped[str] = mapped_column(Text, default="")
|
|
badge_label_en: Mapped[str] = mapped_column(Text, default="")
|
|
cta_primary_label: Mapped[str] = mapped_column(String(128), default="")
|
|
cta_primary_label_en: Mapped[str] = mapped_column(String(128), default="")
|
|
cta_primary_href: Mapped[str] = mapped_column(String(128), default="")
|
|
cta_secondary_label: Mapped[str] = mapped_column(String(128), default="")
|
|
cta_secondary_label_en: Mapped[str] = mapped_column(String(128), default="")
|
|
cta_secondary_href: Mapped[str] = mapped_column(String(128), default="")
|
|
scroll_label: Mapped[str] = mapped_column(String(64), default="")
|
|
scroll_label_en: Mapped[str] = mapped_column(String(64), default="")
|
|
|
|
|
|
class StorySection(Base):
|
|
"""بخش «درباره ما» در خانه و صفحه درباره — رکورد یگانه."""
|
|
|
|
__tablename__ = "story"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
title: Mapped[str] = mapped_column(String(256), default="")
|
|
title_en: Mapped[str] = mapped_column(String(256), default="")
|
|
paragraphs: Mapped[list] = mapped_column(JSON, default=list)
|
|
paragraphs_en: Mapped[list] = mapped_column(JSON, default=list)
|
|
quote: Mapped[str] = mapped_column(Text, default="")
|
|
quote_en: Mapped[str] = mapped_column(Text, default="")
|
|
quote_author: Mapped[str] = mapped_column(Text, default="")
|
|
quote_author_en: Mapped[str] = mapped_column(Text, default="")
|
|
stat1_value: Mapped[str] = mapped_column(String(32), default="")
|
|
stat1_value_en: Mapped[str] = mapped_column(String(32), default="")
|
|
stat1_label: Mapped[str] = mapped_column(String(128), default="")
|
|
stat1_label_en: Mapped[str] = mapped_column(String(128), default="")
|
|
stat2_value: Mapped[str] = mapped_column(String(32), default="")
|
|
stat2_value_en: Mapped[str] = mapped_column(String(32), default="")
|
|
stat2_label: Mapped[str] = mapped_column(String(128), default="")
|
|
stat2_label_en: Mapped[str] = mapped_column(String(128), default="")
|
|
link_label: Mapped[str] = mapped_column(String(128), default="")
|
|
link_label_en: Mapped[str] = mapped_column(String(128), default="")
|
|
link_href: Mapped[str] = mapped_column(String(128), default="")
|
|
bento: Mapped[list] = mapped_column(JSON, default=list) # [{src, alt}]
|
|
bento_en: Mapped[list] = mapped_column(JSON, default=list) # [{src, alt}] انگلیسی
|
|
|
|
|
|
class SectionHeadingContent(Base):
|
|
"""تیتر و توضیح بخشها — فرانتاند بر اساس key آن را پیدا میکند."""
|
|
|
|
__tablename__ = "section_headings"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
key: Mapped[str] = mapped_column(String(64), unique=True, index=True)
|
|
label: Mapped[str] = mapped_column(String(64), default="")
|
|
label_en: Mapped[str] = mapped_column(String(64), default="")
|
|
title: Mapped[str] = mapped_column(String(256), default="")
|
|
title_en: Mapped[str] = mapped_column(String(256), default="")
|
|
lead: Mapped[str] = mapped_column(Text, default="")
|
|
lead_en: Mapped[str] = mapped_column(Text, default="")
|
|
image: Mapped[str] = mapped_column(Text, default="")
|
|
cta_label: Mapped[str] = mapped_column(String(128), default="")
|
|
cta_label_en: Mapped[str] = mapped_column(String(128), default="")
|
|
cta_href: Mapped[str] = mapped_column(String(128), default="")
|
|
|
|
|
|
class PageHeroContent(Base):
|
|
"""هیرو بالای هر صفحه — key: about | services | projects | investment | blog | faq | contact."""
|
|
|
|
__tablename__ = "page_heroes"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
key: Mapped[str] = mapped_column(String(32), unique=True, index=True)
|
|
title: Mapped[str] = mapped_column(String(256), default="")
|
|
title_en: Mapped[str] = mapped_column(String(256), default="")
|
|
lead: Mapped[str] = mapped_column(Text, default="")
|
|
lead_en: Mapped[str] = mapped_column(Text, default="")
|
|
image: Mapped[str] = mapped_column(Text, default="")
|
|
|
|
|
|
class InvestmentModel(Base):
|
|
__tablename__ = "investment_models"
|
|
|
|
position: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
title: Mapped[str] = mapped_column(String(256))
|
|
title_en: Mapped[str] = mapped_column(String(256), default="")
|
|
desc: Mapped[str] = mapped_column(Text, default="")
|
|
desc_en: Mapped[str] = mapped_column(Text, default="")
|
|
points: Mapped[list] = mapped_column(JSON, default=list)
|
|
points_en: Mapped[list] = mapped_column(JSON, default=list)
|
|
|
|
|
|
class ProcessStep(Base):
|
|
__tablename__ = "process_steps"
|
|
|
|
position: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
step: Mapped[str] = mapped_column(String(16), default="")
|
|
step_en: Mapped[str] = mapped_column(String(16), default="")
|
|
title: Mapped[str] = mapped_column(String(256))
|
|
title_en: Mapped[str] = mapped_column(String(256), default="")
|
|
desc: Mapped[str] = mapped_column(Text, default="")
|
|
desc_en: Mapped[str] = mapped_column(Text, default="")
|
|
|
|
|
|
class Office(Base):
|
|
__tablename__ = "offices"
|
|
|
|
position: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
city: Mapped[str] = mapped_column(String(64))
|
|
city_en: Mapped[str] = mapped_column(String(64), default="")
|
|
address: Mapped[str] = mapped_column(Text, default="")
|
|
address_en: Mapped[str] = mapped_column(Text, default="")
|
|
hours: Mapped[str] = mapped_column(String(128), default="")
|
|
hours_en: Mapped[str] = mapped_column(String(128), default="")
|
|
|
|
|
|
class GalleryImage(Base):
|
|
__tablename__ = "gallery_images"
|
|
|
|
position: Mapped[int] = mapped_column(Integer, default=0)
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
src: Mapped[str] = mapped_column(Text, default="")
|
|
alt: Mapped[str] = mapped_column(Text, default="")
|
|
alt_en: Mapped[str] = mapped_column(Text, default="")
|
|
|
|
|
|
class StatusLabel(Base):
|
|
"""برچسب فارسی وضعیت پروژه — key: done | progress."""
|
|
|
|
__tablename__ = "status_labels"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
key: Mapped[str] = mapped_column(String(16), unique=True, index=True)
|
|
label: Mapped[str] = mapped_column(String(64))
|
|
label_en: Mapped[str] = mapped_column(String(64), default="")
|
|
|
|
|
|
class ContactSectionContent(Base):
|
|
"""بخش فرم تماس — رکورد یگانه."""
|
|
|
|
__tablename__ = "contact_section"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
label: Mapped[str] = mapped_column(String(64), default="")
|
|
label_en: Mapped[str] = mapped_column(String(64), default="")
|
|
title: Mapped[str] = mapped_column(String(256), default="")
|
|
title_en: Mapped[str] = mapped_column(String(256), default="")
|
|
lead: Mapped[str] = mapped_column(Text, default="")
|
|
lead_en: Mapped[str] = mapped_column(Text, default="")
|
|
address_label: Mapped[str] = mapped_column(String(64), default="")
|
|
address_label_en: Mapped[str] = mapped_column(String(64), default="")
|
|
phone_label: Mapped[str] = mapped_column(String(64), default="")
|
|
phone_label_en: Mapped[str] = mapped_column(String(64), default="")
|
|
email_label: Mapped[str] = mapped_column(String(64), default="")
|
|
email_label_en: Mapped[str] = mapped_column(String(64), default="")
|
|
name_label: Mapped[str] = mapped_column(String(64), default="")
|
|
name_label_en: Mapped[str] = mapped_column(String(64), default="")
|
|
name_placeholder: Mapped[str] = mapped_column(String(128), default="")
|
|
name_placeholder_en: Mapped[str] = mapped_column(String(128), default="")
|
|
phone_field_label: Mapped[str] = mapped_column(String(64), default="")
|
|
phone_field_label_en: Mapped[str] = mapped_column(String(64), default="")
|
|
phone_placeholder: Mapped[str] = mapped_column(String(64), default="")
|
|
phone_placeholder_en: Mapped[str] = mapped_column(String(64), default="")
|
|
note_label: Mapped[str] = mapped_column(String(64), default="")
|
|
note_label_en: Mapped[str] = mapped_column(String(64), default="")
|
|
note_optional_label: Mapped[str] = mapped_column(String(64), default="")
|
|
note_optional_label_en: Mapped[str] = mapped_column(String(64), default="")
|
|
note_placeholder: Mapped[str] = mapped_column(String(256), default="")
|
|
note_placeholder_en: Mapped[str] = mapped_column(String(256), default="")
|
|
submit_label: Mapped[str] = mapped_column(String(128), default="")
|
|
submit_label_en: Mapped[str] = mapped_column(String(128), default="")
|
|
sending_label: Mapped[str] = mapped_column(String(64), default="")
|
|
sending_label_en: Mapped[str] = mapped_column(String(64), default="")
|
|
success_title: Mapped[str] = mapped_column(String(256), default="")
|
|
success_title_en: Mapped[str] = mapped_column(String(256), default="")
|
|
success_text: Mapped[str] = mapped_column(Text, default="")
|
|
success_text_en: Mapped[str] = mapped_column(Text, default="")
|
|
success_button_label: Mapped[str] = mapped_column(String(128), default="")
|
|
success_button_label_en: Mapped[str] = mapped_column(String(128), default="")
|
|
|
|
|
|
class NewsletterSectionContent(Base):
|
|
"""بخش خبرنامه — رکورد یگانه."""
|
|
|
|
__tablename__ = "newsletter"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
title: Mapped[str] = mapped_column(String(256), default="")
|
|
title_en: Mapped[str] = mapped_column(String(256), default="")
|
|
lead: Mapped[str] = mapped_column(Text, default="")
|
|
lead_en: Mapped[str] = mapped_column(Text, default="")
|
|
placeholder: Mapped[str] = mapped_column(String(128), default="")
|
|
placeholder_en: Mapped[str] = mapped_column(String(128), default="")
|
|
button_label: Mapped[str] = mapped_column(String(64), default="")
|
|
button_label_en: Mapped[str] = mapped_column(String(64), default="")
|
|
sending_label: Mapped[str] = mapped_column(String(64), default="")
|
|
sending_label_en: Mapped[str] = mapped_column(String(64), default="")
|
|
success_text: Mapped[str] = mapped_column(String(256), default="")
|
|
success_text_en: Mapped[str] = mapped_column(String(256), default="")
|
|
|
|
|
|
class FooterContent(Base):
|
|
"""متنهای فوتر — رکورد یگانه."""
|
|
|
|
__tablename__ = "footer"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
about_text: Mapped[str] = mapped_column(Text, default="")
|
|
about_text_en: Mapped[str] = mapped_column(Text, default="")
|
|
pages_heading: Mapped[str] = mapped_column(String(64), default="")
|
|
pages_heading_en: Mapped[str] = mapped_column(String(64), default="")
|
|
services_heading: Mapped[str] = mapped_column(String(64), default="")
|
|
services_heading_en: Mapped[str] = mapped_column(String(64), default="")
|
|
contact_heading: Mapped[str] = mapped_column(String(64), default="")
|
|
contact_heading_en: Mapped[str] = mapped_column(String(64), default="")
|
|
copyright: Mapped[str] = mapped_column(String(256), default="")
|
|
copyright_en: Mapped[str] = mapped_column(String(256), default="")
|
|
tagline: Mapped[str] = mapped_column(String(256), default="")
|
|
tagline_en: Mapped[str] = mapped_column(String(256), default="")
|
|
socials: Mapped[list] = mapped_column(JSON, default=list) # [{label, href, icon}]
|
|
socials_en: Mapped[list] = mapped_column(JSON, default=list) # [{label, href, icon}] انگلیسی
|
|
|
|
|
|
class SeoMeta(Base):
|
|
"""عنوان و توضیح سئوی هر صفحه — page_key: home / about / services / ..."""
|
|
|
|
__tablename__ = "seo_meta"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
page_key: Mapped[str] = mapped_column(String(32), unique=True, index=True)
|
|
title: Mapped[str] = mapped_column(String(256), default="")
|
|
title_en: Mapped[str] = mapped_column(String(256), default="")
|
|
description: Mapped[str] = mapped_column(Text, default="")
|
|
description_en: Mapped[str] = mapped_column(Text, default="")
|
|
|
|
|
|
class ContactMessage(Base):
|
|
__tablename__ = "contact_messages"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(128))
|
|
phone: Mapped[str] = mapped_column(String(32))
|
|
note: Mapped[str] = mapped_column(Text, default="")
|
|
is_read: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
|
|
|
|
|
|
class Subscriber(Base):
|
|
__tablename__ = "subscribers"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
email: Mapped[str] = mapped_column(String(256), unique=True, index=True)
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)
|