# Path: suma/core/services/link.py
# class LinkService(object):
# 
#     def __init__(self, dbsession, hashid):
#         self.dbsession = dbsession
#         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)
#         args.append(Link.hashid == str(id_or_hashid))
#         try:
#             return self.dbsession.query(Link).filter(
#                 or_(*args)
#             ).one()
#         except NoResultFound:
#             return None
# 
#     def get_link_by_url(self, url, user_id=None):
#         l_query = self.dbsession.query(Link)
#         return l_query.filter(Link.url == url, Link.user_id == user_id).first()
# 
#     def get_link_by_id(self, id):
#         return self.dbsession.query(Link).filter(Link.id == id).first()
# 
#     def get_link_by_hashid(self, hashid):
#         return self.dbsession.query(Link).filter(Link.hashid == hashid).first()
# 
#     def ban_url(self, url, mode='url'):
#         assert mode in ('url', 'netloc', 'path'),\
#             'Bad mode is not "url", "netloc" or "path"'
#         hash_url, hash_netloc, hash_path = create_url_hashes(url)
#         hdict = dict(zip(('url', 'netloc', 'path'), (hash_url, hash_netloc, hash_path)))
#         btype = BlockingType.from_string(mode)
#         bl = BlockedLink(
#             hash=hdict[mode],
#             url=url,
#             type=btype
#         )
#         self.dbsession.begin_nested()
#         try:
#             self.dbsession.add(bl)
#             self.dbsession.commit()
#         except IntegrityError:
#             # already blocked so we me ignore
#             self.dbsession.rollback()
# 
# Path: suma/core/services/hashid.py
# class HashIdService(object):
#     def __init__(self, secret):
#         self.hashids = hashids.Hashids(secret, min_length=6)
# 
#     def encode(self, primary_id, secondary_id=None):
#         args = []
#         if secondary_id is not None:
#             # Using the primary_id as 1st argument create better entropy
#             # The same user with different link will get very different ids
#             args.append(secondary_id)
#         args.append(primary_id)
#         return self.hashids.encode(*args)
# 
#     def decode(self, short_id):
#         # we are reversing the order to respect primary first in the return
#         return self.hashids.decode(short_id)[::-1] # we use the step to ensure a tuple
# 
# Path: suma/core/services/stat.py
# class StatService(object):
# 
#     def __init__(self, dbsession):
#         self.dbsession = dbsession
# 
#     def add_click(self, link_id, ip=None, referer=None):
#         """
#         The code may look more complex than it should but it was made to handle
#         the edge case of concurrent transaction. Counter doesn't exist yet when
#         we fetch but it exist when we try to write it to the DB.
#         """
#         assert type(link_id) in [IntType, LongType], "link_id is not an integer: %r" % link_id
# 
#         lcounter = self.get_counter_by_link_id(link_id)
#         if lcounter:
#             lcounter.counter = lcounter.counter + 1
#             self.dbsession.add(lcounter)
#         if not lcounter:
#             lcounter = ClickCounter(
#                 id=link_id,
#                 counter=1
#             )
#             self.dbsession.begin_nested()
#             try:
#                 self.dbsession.add(lcounter)
#                 self.dbsession.commit()
#             except IntegrityError:
#                 self.dbsession.rollback()
#                 lcounter = self.get_counter_by_link_id(link_id)
#                 lcounter.counter = lcounter.counter + 1
#                 self.dbsession.add(lcounter)
# 
#         stat = Stat(
#             link_id=link_id,
#             ip=ip,
#             referer=referer
#         )
#         self.dbsession.add(stat)
#         return lcounter, stat
# 
#     def get_counter_by_link_id(self, link_id):
#         return self.dbsession.query(ClickCounter).get(link_id)


from suma.core.services import LinkService, HashIdService, StatService
from hashlib import sha1
from sqlalchemy.exc import IntegrityError
import pytest


@pytest.fixture
def link_svc(db_session, hashid_svc):
    return LinkService(db_session, hashid_svc)



# Path: suma/core/services/link.py
# class LinkService(object):
# 
#     def __init__(self, dbsession, hashid):
#         self.dbsession = dbsession
#         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)
#         args.append(Link.hashid == str(id_or_hashid))
#         try:
#             return self.dbsession.query(Link).filter(
#                 or_(*args)
#             ).one()
#         except NoResultFound:
#             return None
# 
#     def get_link_by_url(self, url, user_id=None):
#         l_query = self.dbsession.query(Link)
#         return l_query.filter(Link.url == url, Link.user_id == user_id).first()
# 
#     def get_link_by_id(self, id):
#         return self.dbsession.query(Link).filter(Link.id == id).first()
# 
#     def get_link_by_hashid(self, hashid):
#         return self.dbsession.query(Link).filter(Link.hashid == hashid).first()
# 
#     def ban_url(self, url, mode='url'):
#         assert mode in ('url', 'netloc', 'path'),\
#             'Bad mode is not "url", "netloc" or "path"'
#         hash_url, hash_netloc, hash_path = create_url_hashes(url)
#         hdict = dict(zip(('url', 'netloc', 'path'), (hash_url, hash_netloc, hash_path)))
#         btype = BlockingType.from_string(mode)
#         bl = BlockedLink(
#             hash=hdict[mode],
#             url=url,
#             type=btype
#         )
#         self.dbsession.begin_nested()
#         try:
#             self.dbsession.add(bl)
#             self.dbsession.commit()
#         except IntegrityError:
#             # already blocked so we me ignore
#             self.dbsession.rollback()
# 
# Path: suma/core/services/hashid.py
# class HashIdService(object):
#     def __init__(self, secret):
#         self.hashids = hashids.Hashids(secret, min_length=6)
# 
#     def encode(self, primary_id, secondary_id=None):
#         args = []
#         if secondary_id is not None:
#             # Using the primary_id as 1st argument create better entropy
#             # The same user with different link will get very different ids
#             args.append(secondary_id)
#         args.append(primary_id)
#         return self.hashids.encode(*args)
# 
#     def decode(self, short_id):
#         # we are reversing the order to respect primary first in the return
#         return self.hashids.decode(short_id)[::-1] # we use the step to ensure a tuple
# 
# Path: suma/core/services/stat.py
# class StatService(object):
# 
#     def __init__(self, dbsession):
#         self.dbsession = dbsession
# 
#     def add_click(self, link_id, ip=None, referer=None):
#         """
#         The code may look more complex than it should but it was made to handle
#         the edge case of concurrent transaction. Counter doesn't exist yet when
#         we fetch but it exist when we try to write it to the DB.
#         """
#         assert type(link_id) in [IntType, LongType], "link_id is not an integer: %r" % link_id
# 
#         lcounter = self.get_counter_by_link_id(link_id)
#         if lcounter:
#             lcounter.counter = lcounter.counter + 1
#             self.dbsession.add(lcounter)
#         if not lcounter:
#             lcounter = ClickCounter(
#                 id=link_id,
#                 counter=1
#             )
#             self.dbsession.begin_nested()
#             try:
#                 self.dbsession.add(lcounter)
#                 self.dbsession.commit()
#             except IntegrityError:
#                 self.dbsession.rollback()
#                 lcounter = self.get_counter_by_link_id(link_id)
#                 lcounter.counter = lcounter.counter + 1
#                 self.dbsession.add(lcounter)
# 
#         stat = Stat(
#             link_id=link_id,
#             ip=ip,
#             referer=referer
#         )
#         self.dbsession.add(stat)
#         return lcounter, stat
# 
#     def get_counter_by_link_id(self, link_id):
#         return self.dbsession.query(ClickCounter).get(link_id)


# Path: tests/core/services/conftest.py
from suma.core.services import LinkService, HashIdService, StatService
from hashlib import sha1
from sqlalchemy.exc import IntegrityError
import pytest



@pytest.fixture
def link_svc(db_session, hashid_svc):
    return LinkService(db_session, hashid_svc)



@pytest.fixture