def test_slugify(db): with session_scope() as session: assert session.execute( func.slugify("this is a test")).scalar_one() == "this-is-a-test" assert session.execute( func.slugify("this is ä test")).scalar_one() == "this-is-a-test" # nothing here gets converted to ascci by unaccent, so it should be empty assert session.execute( func.slugify("Создай группу своего города")).scalar_one() == "slug" assert session.execute(func.slugify( "Detta är ett test!")).scalar_one() == "detta-ar-ett-test" assert session.execute( func.slugify("@#(*$&!@#")).scalar_one() == "slug" assert (session.execute( func.slugify( "This has a lot ‒ at least relatively speaking ‒ of punctuation! :)" )).scalar_one() == "this-has-a-lot-at-least-relatively-speaking-of-punctuation") assert (session.execute( func.slugify("Multiple - #@! - non-ascii chars")).scalar_one() == "multiple-non-ascii-chars") assert session.execute(func.slugify("123")).scalar_one() == "123" assert (session.execute( func.slugify( "A sentence that is over 64 chars long and where the last thing would be replaced by a dash" ) ).scalar_one( ) == "a-sentence-that-is-over-64-chars-long-and-where-the-last-thing")
class Discussion(Base): """ forum board """ __tablename__ = "discussions" id = Column(BigInteger, communities_seq, primary_key=True, server_default=communities_seq.next_value()) title = Column(String, nullable=False) content = Column(String, nullable=False) thread_id = Column(ForeignKey("threads.id"), nullable=False, unique=True) created = Column(DateTime(timezone=True), nullable=False, server_default=func.now()) creator_user_id = Column(ForeignKey("users.id"), nullable=False, index=True) owner_cluster_id = Column(ForeignKey("clusters.id"), nullable=False, index=True) slug = column_property(func.slugify(title)) thread = relationship("Thread", backref="discussion", uselist=False) subscribers = relationship("User", backref="discussions", secondary="discussion_subscriptions") creator_user = relationship("User", backref="created_discussions", foreign_keys="Discussion.creator_user_id") owner_cluster = relationship("Cluster", backref=backref("owned_discussions", lazy="dynamic"), uselist=False)
class PageVersion(Base): """ version of page content """ __tablename__ = "page_versions" id = Column(BigInteger, primary_key=True) page_id = Column(ForeignKey("pages.id"), nullable=False, index=True) editor_user_id = Column(ForeignKey("users.id"), nullable=False, index=True) title = Column(String, nullable=False) content = Column(String, nullable=False) # CommonMark without images photo_key = Column(ForeignKey("uploads.key"), nullable=True) # the human-readable address address = Column(String, nullable=True) geom = Column(Geometry(geometry_type="POINT", srid=4326), nullable=True) created = Column(DateTime(timezone=True), nullable=False, server_default=func.now()) slug = column_property(func.slugify(title)) page = relationship("Page", backref="versions", order_by="PageVersion.id") editor_user = relationship("User", backref="edited_pages") photo = relationship("Upload") @property def coordinates(self): # returns (lat, lng) or None if self.geom: return get_coordinates(self.geom) else: return None def __repr__(self): return f"PageVersion({self.id=}, {self.page_id=})"
class Cluster(Base): """ Cluster, administered grouping of content """ __tablename__ = "clusters" id = Column(BigInteger, communities_seq, primary_key=True, server_default=communities_seq.next_value()) parent_node_id = Column(ForeignKey("nodes.id"), nullable=False, index=True) name = Column(String, nullable=False) # short description description = Column(String, nullable=False) created = Column(DateTime(timezone=True), nullable=False, server_default=func.now()) is_official_cluster = Column(Boolean, nullable=False, default=False) slug = column_property(func.slugify(name)) official_cluster_for_node = relationship( "Node", primaryjoin= "and_(Cluster.parent_node_id == Node.id, Cluster.is_official_cluster)", backref=backref("official_cluster", uselist=False), uselist=False, ) parent_node = relationship("Node", backref="child_clusters", remote_side="Node.id", foreign_keys="Cluster.parent_node_id") nodes = relationship("Cluster", backref="clusters", secondary="node_cluster_associations") # all pages pages = relationship("Page", backref="clusters", secondary="cluster_page_associations", lazy="dynamic") events = relationship("Event", backref="clusters", secondary="cluster_event_associations") discussions = relationship("Discussion", backref="clusters", secondary="cluster_discussion_associations") # includes also admins members = relationship( "User", lazy="dynamic", backref="cluster_memberships", secondary="cluster_subscriptions", primaryjoin="Cluster.id == ClusterSubscription.cluster_id", secondaryjoin="User.id == ClusterSubscription.user_id", ) admins = relationship( "User", lazy="dynamic", backref="cluster_adminships", secondary="cluster_subscriptions", primaryjoin="Cluster.id == ClusterSubscription.cluster_id", secondaryjoin= "and_(User.id == ClusterSubscription.user_id, ClusterSubscription.role == 'admin')", ) main_page = relationship( "Page", primaryjoin= "and_(Cluster.id == Page.owner_cluster_id, Page.type == 'main_page')", viewonly=True, uselist=False, ) __table_args__ = ( # Each node can have at most one official cluster Index( "ix_clusters_owner_parent_node_id_is_official_cluster", parent_node_id, is_official_cluster, unique=True, postgresql_where=is_official_cluster, ), )