feat(backend): add video_url and video_position to properties
- Model: video_url VARCHAR(512) nullable, video_position VARCHAR(20) default 'section' - Migration: k3l4m5n6o7p8_add_video_to_properties - Admin route: expose/accept video_url (sanitize empty->NULL) and video_position - Public schema: PropertyDetailOut exposes both fields
This commit is contained in:
parent
7a53865408
commit
d363a09f36
4 changed files with 40 additions and 1 deletions
|
|
@ -51,6 +51,8 @@ class Property(db.Model):
|
|||
index=True,
|
||||
)
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now())
|
||||
video_url = db.Column(db.String(512), nullable=True)
|
||||
video_position = db.Column(db.String(20), nullable=False, server_default='section')
|
||||
|
||||
photos = db.relationship(
|
||||
"PropertyPhoto",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import re
|
|||
import bcrypt
|
||||
from datetime import datetime, date
|
||||
from decimal import Decimal
|
||||
from typing import Optional
|
||||
from typing import Optional, Literal
|
||||
from flask import Blueprint, request, jsonify, current_app, send_from_directory
|
||||
from werkzeug.utils import secure_filename
|
||||
from pydantic import BaseModel, ValidationError
|
||||
|
|
@ -168,6 +168,8 @@ class PropertyAdminOut(BaseModel):
|
|||
is_featured: bool
|
||||
photos: list[PhotoAdminOut] = []
|
||||
amenity_ids: list[int] = []
|
||||
video_url: Optional[str] = None
|
||||
video_position: Literal['carousel', 'section'] = 'section'
|
||||
|
||||
@classmethod
|
||||
def from_prop(cls, p: Property) -> "PropertyAdminOut":
|
||||
|
|
@ -203,6 +205,8 @@ class PropertyAdminOut(BaseModel):
|
|||
for ph in p.photos
|
||||
],
|
||||
amenity_ids=[a.id for a in p.amenities],
|
||||
video_url=p.video_url,
|
||||
video_position=p.video_position,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -348,10 +352,15 @@ def admin_update_property(property_id: str):
|
|||
"area_m2",
|
||||
"city_id",
|
||||
"neighborhood_id",
|
||||
"video_position",
|
||||
)
|
||||
for field in _SCALAR_FIELDS:
|
||||
if field in body:
|
||||
setattr(prop, field, body[field])
|
||||
# video_url: sanitizar e tratar string vazia como NULL
|
||||
if 'video_url' in body:
|
||||
raw = body['video_url']
|
||||
prop.video_url = raw.strip() if raw and raw.strip() else None
|
||||
# code: tratar string vazia como NULL
|
||||
if "code" in body:
|
||||
prop.code = body["code"] if body["code"] else None
|
||||
|
|
|
|||
|
|
@ -61,3 +61,5 @@ class PropertyDetailOut(PropertyOut):
|
|||
address: str | None = None
|
||||
code: str | None = None
|
||||
description: str | None = None
|
||||
video_url: str | None = None
|
||||
video_position: Literal['carousel', 'section'] = 'section'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
"""add video to properties
|
||||
|
||||
Revision ID: k3l4m5n6o7p8
|
||||
Revises: j2k3l4m5n6o7
|
||||
Create Date: 2026-04-22
|
||||
"""
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
revision = 'k3l4m5n6o7p8'
|
||||
down_revision = 'j2k3l4m5n6o7'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column('properties',
|
||||
sa.Column('video_url', sa.String(512), nullable=True))
|
||||
op.add_column('properties',
|
||||
sa.Column('video_position', sa.String(20),
|
||||
nullable=False, server_default='section'))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column('properties', 'video_position')
|
||||
op.drop_column('properties', 'video_url')
|
||||
Loading…
Add table
Add a link
Reference in a new issue