flatisfy/flatisfy/models/flat.py

214 lines
5.8 KiB
Python
Raw Normal View History

2017-04-03 17:29:29 +02:00
# coding: utf-8
"""
This modules defines an SQLAlchemy ORM model for a flat.
"""
# pylint: disable=locally-disabled,invalid-name,too-few-public-methods
2017-04-03 17:29:29 +02:00
from __future__ import absolute_import, print_function, unicode_literals
import logging
import enum
import arrow
2017-04-03 17:29:29 +02:00
from sqlalchemy import (
2021-01-26 14:39:52 +01:00
Boolean,
Column,
DateTime,
Enum,
Float,
SmallInteger,
String,
Text,
inspect,
)
2017-12-05 12:20:40 +01:00
from sqlalchemy.orm import validates
2017-04-03 17:29:29 +02:00
from flatisfy.database.base import BASE
from flatisfy.database.types import MagicJSON
LOGGER = logging.getLogger(__name__)
class FlatUtilities(enum.Enum):
"""
An enum of the possible utilities status for a flat entry.
"""
2021-01-26 14:39:52 +01:00
included = 10
unknown = 0
excluded = -10
2017-04-03 17:29:29 +02:00
class FlatStatus(enum.Enum):
"""
An enum of the possible status for a flat entry.
"""
2021-01-26 14:39:52 +01:00
user_deleted = -100
duplicate = -20
ignored = -10
2017-04-03 17:29:29 +02:00
new = 0
followed = 10
contacted = 20
answer_no = 30
answer_yes = 31
2017-04-03 17:29:29 +02:00
# List of statuses that are automatically handled, and which the user cannot
# manually set through the UI.
2021-01-26 14:39:52 +01:00
AUTOMATED_STATUSES = [FlatStatus.new, FlatStatus.duplicate, FlatStatus.ignored]
2017-04-03 17:29:29 +02:00
class Flat(BASE):
"""
SQLAlchemy ORM model to store a flat.
"""
2021-01-26 14:39:52 +01:00
2017-04-03 17:29:29 +02:00
__tablename__ = "flats"
2021-01-26 14:39:52 +01:00
__searchable__ = ["title", "text", "station", "location", "details", "notes"]
2017-04-03 17:29:29 +02:00
# Weboob data
id = Column(String, primary_key=True)
area = Column(Float)
bedrooms = Column(Float)
cost = Column(Float)
currency = Column(String)
utilities = Column(Enum(FlatUtilities), default=FlatUtilities.unknown)
2017-04-03 17:29:29 +02:00
date = Column(DateTime)
details = Column(MagicJSON)
location = Column(String)
phone = Column(String)
photos = Column(MagicJSON)
rooms = Column(Float)
station = Column(String)
text = Column(Text)
title = Column(String)
urls = Column(MagicJSON)
merged_ids = Column(MagicJSON)
notes = Column(Text)
notation = Column(SmallInteger, default=0)
is_expired = Column(Boolean, default=False)
2017-04-03 17:29:29 +02:00
# Flatisfy data
# TODO: Should be in another table with relationships
flatisfy_stations = Column(MagicJSON)
flatisfy_postal_code = Column(String)
flatisfy_time_to = Column(MagicJSON)
flatisfy_constraint = Column(String)
2021-01-16 17:11:34 +01:00
flatisfy_position = Column(MagicJSON)
2017-04-03 17:29:29 +02:00
# Status
status = Column(Enum(FlatStatus), default=FlatStatus.new)
# Date for visit
visit_date = Column(DateTime)
2021-01-26 14:39:52 +01:00
@validates("utilities")
2017-12-05 12:20:40 +01:00
def validate_utilities(self, _, utilities):
"""
Utilities validation method
"""
if isinstance(utilities, FlatUtilities):
return utilities
if utilities == "C.C.":
return FlatUtilities.included
elif utilities == "H.C.":
return FlatUtilities.excluded
2017-12-05 15:17:03 +01:00
return FlatUtilities.unknown
2017-12-05 12:20:40 +01:00
@validates("status")
def validate_status(self, _, status):
"""
Status validation method
"""
if isinstance(status, FlatStatus):
return status
try:
return getattr(FlatStatus, status)
except (AttributeError, TypeError):
2021-01-26 14:39:52 +01:00
LOGGER.warn("Unkown flat status %s, ignoring it.", status)
2017-12-05 12:20:40 +01:00
return self.status.default.arg
@validates("notation")
2017-12-05 15:17:03 +01:00
def validate_notation(self, _, notation):
2017-12-05 12:20:40 +01:00
"""
Notation validation method
"""
try:
notation = int(notation)
assert notation >= 0 and notation <= 5
except (ValueError, AssertionError):
2021-01-26 14:39:52 +01:00
raise ValueError("notation should be an integer between 0 and 5")
2017-12-05 12:20:40 +01:00
return notation
@validates("date")
def validate_date(self, _, date):
"""
Date validation method
"""
2021-03-14 18:00:36 +01:00
if date:
return arrow.get(date).naive
return None
2017-12-05 12:20:40 +01:00
@validates("visit_date")
def validate_visit_date(self, _, visit_date):
"""
Visit date validation method
"""
2021-03-14 18:00:36 +01:00
if visit_date:
return arrow.get(visit_date).naive
return None
2017-12-05 12:20:40 +01:00
@validates("photos")
def validate_photos(self, _, photos):
"""
Photos validation method
"""
if not photos:
photos = []
for photo in photos:
try:
# Remove computed hash to avoid storing it in db
del photo["hash"]
except KeyError:
pass
return photos
2017-04-03 17:29:29 +02:00
@staticmethod
def from_dict(flat_dict):
"""
Create a Flat object from a flat dict as manipulated by the filtering
pass.
"""
# Handle flatisfy metadata
flat_dict = flat_dict.copy()
if "flatisfy" in flat_dict:
flat_dict["flatisfy_stations"] = flat_dict["flatisfy"].get("matched_stations", [])
flat_dict["flatisfy_postal_code"] = flat_dict["flatisfy"].get("postal_code", None)
2021-01-26 14:39:52 +01:00
flat_dict["flatisfy_position"] = flat_dict["flatisfy"].get("position", None)
flat_dict["flatisfy_time_to"] = flat_dict["flatisfy"].get("time_to", {})
flat_dict["flatisfy_constraint"] = flat_dict["flatisfy"].get("constraint", "default")
del flat_dict["flatisfy"]
2017-04-03 17:29:29 +02:00
flat_dict = {k: v for k, v in flat_dict.items() if k in inspect(Flat).columns.keys()}
2017-12-06 19:03:25 +01:00
return Flat(**flat_dict)
2017-04-03 17:29:29 +02:00
def __repr__(self):
return "<Flat(id=%s, urls=%s)>" % (self.id, self.urls)
2017-04-03 17:29:29 +02:00
def json_api_repr(self):
"""
Return a dict representation of this flat object that is JSON
serializable.
"""
2021-01-26 14:39:52 +01:00
flat_repr = {k: v for k, v in self.__dict__.items() if not k.startswith("_")}
if isinstance(flat_repr["status"], FlatStatus):
flat_repr["status"] = flat_repr["status"].name
if isinstance(flat_repr["utilities"], FlatUtilities):
flat_repr["utilities"] = flat_repr["utilities"].name
2017-04-03 17:29:29 +02:00
return flat_repr