# Path: suma/core/services/interfaces/link.py
# class ILinkService(Interface):
# 
#     def create_link(self, url, user_id=None):
#         pass
# 
#     def get_link_by_id_or_hashid(self, id_or_hashid):
#         pass
# 
#     def get_link_by_url(self, url, user_id=None):
#         pass
# 
#     def get_link_by_id(self, id):
#         pass
# 
#     def get_link_by_hashid(self, hashid):
#         pass
# 
#     def ban_url(self, url, mode='url'):
#         pass
# 
# Path: suma/core/models/link.py
# class Link(Base, TimestampColumns):
#     hashid = Column(String, index=True, unique=True, nullable=False)
#     _url = Column('url', Unicode, index=True, nullable=False)
#     user_id = Column(BigInteger)
#     _hash = Column('hash', String, index=True, nullable=False)
#     _hash_netloc = Column('hash_netloc', String, nullable=False)
#     _hash_path = Column('hash_path', String, nullable=False)
#     meta = Column(MutableDict.as_mutable(JSONB), default={})
#     __table_args__ = (
#         Index('unique_url_and_user_id', _url, user_id, unique=True,
#               postgresql_where=(user_id != None)),
#         Index('unique_url_and_user_id_is_null', 'url', unique=True,
#               postgresql_where=(user_id == None))
#     )
# 
#     is_banned = column_property(
#         exists().where(
#             or_(
#                 BlockedLink.hash.in_([_hash, _hash_netloc, _hash_path])
#             )
#         )
#     )
# 
#     @property
#     def clicks(self):
#         if self._clicks:
#             return self._clicks.counter
#         return 0
#     
#     @hybrid_property
#     def url(self):
#         return self._url
# 
#     @url.setter
#     def url(self, value):
#         self._url = value
#         self._hash, self._hash_netloc, self._hash_path = create_url_hashes(value)
# 
# class BlockingType(DeclEnum):
#     url = "url", "Url"
#     netloc = "netloc", "Netloc"
#     path = "path", "Path"
# 
# class BlockedLink (Base):
#     url = Column('url', Unicode, nullable=False)  # this is there more for readability
#     hash = Column(String, index=True, unique=True, nullable=False)
#     type = Column(BlockingType.db_type(), nullable=False)
# 
# Path: suma/core/models/link.py
# def create_url_hashes(url):
#     parsed = urlparse(url)
#     return (
#         sha1(url).hexdigest(),
#         sha1(parsed.netloc).hexdigest(),
#         sha1(parsed.netloc + parsed.path).hexdigest()
#     )


from suma.core.services.interfaces import ILinkService
from zope.interface import implementer
from suma.core.models import Link, BlockingType, BlockedLink
from suma.core.models.link import create_url_hashes
from structlog import get_logger
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy import or_
from sqlalchemy.schema import Sequence
from sqlalchemy.exc import IntegrityError
        self.hashid = hashid

    def create_link(self, url, user_id=None):
        created = False
        link = self.get_link_by_url(url, user_id)
        if link:
            return link, created

        nextid = self.dbsession.execute(Sequence("link_id_seq"))
        hashid = self.hashid.encode(nextid)
        link = Link(
            id=nextid,
            user_id=user_id,
            url=url,
            hashid=hashid
        )
        self.dbsession.begin_nested()
        try:
            self.dbsession.add(link)
            self.dbsession.commit()
            created = True
        except IntegrityError:
            self.dbsession.rollback()
            link = self.get_link_by_url(url, user_id)

        return link, created

    def get_link_by_id_or_hashid(self, id_or_hashid):
        args = []
        if str(id_or_hashid).isdigit():

# Path: suma/core/services/interfaces/link.py
# class ILinkService(Interface):
# 
#     def create_link(self, url, user_id=None):
#         pass
# 
#     def get_link_by_id_or_hashid(self, id_or_hashid):
#         pass
# 
#     def get_link_by_url(self, url, user_id=None):
#         pass
# 
#     def get_link_by_id(self, id):
#         pass
# 
#     def get_link_by_hashid(self, hashid):
#         pass
# 
#     def ban_url(self, url, mode='url'):
#         pass
# 
# Path: suma/core/models/link.py
# class Link(Base, TimestampColumns):
#     hashid = Column(String, index=True, unique=True, nullable=False)
#     _url = Column('url', Unicode, index=True, nullable=False)
#     user_id = Column(BigInteger)
#     _hash = Column('hash', String, index=True, nullable=False)
#     _hash_netloc = Column('hash_netloc', String, nullable=False)
#     _hash_path = Column('hash_path', String, nullable=False)
#     meta = Column(MutableDict.as_mutable(JSONB), default={})
#     __table_args__ = (
#         Index('unique_url_and_user_id', _url, user_id, unique=True,
#               postgresql_where=(user_id != None)),
#         Index('unique_url_and_user_id_is_null', 'url', unique=True,
#               postgresql_where=(user_id == None))
#     )
# 
#     is_banned = column_property(
#         exists().where(
#             or_(
#                 BlockedLink.hash.in_([_hash, _hash_netloc, _hash_path])
#             )
#         )
#     )
# 
#     @property
#     def clicks(self):
#         if self._clicks:
#             return self._clicks.counter
#         return 0
#     
#     @hybrid_property
#     def url(self):
#         return self._url
# 
#     @url.setter
#     def url(self, value):
#         self._url = value
#         self._hash, self._hash_netloc, self._hash_path = create_url_hashes(value)
# 
# class BlockingType(DeclEnum):
#     url = "url", "Url"
#     netloc = "netloc", "Netloc"
#     path = "path", "Path"
# 
# class BlockedLink (Base):
#     url = Column('url', Unicode, nullable=False)  # this is there more for readability
#     hash = Column(String, index=True, unique=True, nullable=False)
#     type = Column(BlockingType.db_type(), nullable=False)
# 
# Path: suma/core/models/link.py
# def create_url_hashes(url):
#     parsed = urlparse(url)
#     return (
#         sha1(url).hexdigest(),
#         sha1(parsed.netloc).hexdigest(),
#         sha1(parsed.netloc + parsed.path).hexdigest()
#     )


# Path: suma/core/services/link.py
from suma.core.services.interfaces import ILinkService
from zope.interface import implementer
from suma.core.models import Link, BlockingType, BlockedLink
from suma.core.models.link import create_url_hashes
from structlog import get_logger
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy import or_
from sqlalchemy.schema import Sequence
from sqlalchemy.exc import IntegrityError

        self.hashid = hashid

    def create_link(self, url, user_id=None):
        created = False
        link = self.get_link_by_url(url, user_id)
        if link:
            return link, created

        nextid = self.dbsession.execute(Sequence("link_id_seq"))
        hashid = self.hashid.encode(nextid)
        link = Link(
            id=nextid,
            user_id=user_id,
            url=url,
            hashid=hashid
        )
        self.dbsession.begin_nested()
        try:
            self.dbsession.add(link)
            self.dbsession.commit()
            created = True
        except IntegrityError:
            self.dbsession.rollback()
            link = self.get_link_by_url(url, user_id)

        return link, created

    def get_link_by_id_or_hashid(self, id_or_hashid):
        args = []
        if str(id_or_hashid).isdigit():

            args.append(Link.id == id_or_hashid)