def test_add_topic(self): import transaction from fanboi2.models import Topic request = {'remote_addr': '127.0.0.1'} with transaction.manager: board = self._makeBoard(title='Foobar', slug='foobar') board_id = board.id # board is not bound outside transaction! result = self._makeOne(request, board_id, 'Foobar', 'Hello, world!') topic = DBSession.query(Topic).first() self.assertTrue(result.successful()) self.assertEqual(DBSession.query(Topic).count(), 1) self.assertEqual(DBSession.query(Topic).get(result.get()[1]), topic) self.assertEqual(topic.title, 'Foobar') self.assertEqual(topic.posts[0].body, 'Hello, world!') self.assertEqual(result.result, ('topic', topic.id))
def _creator(): page = DBSession.query(Page).filter_by( namespace='internal', slug=slug).\ first() if page: return page.body
def test_add_post(self): import transaction from fanboi2.models import Post request = {'remote_addr': '127.0.0.1'} with transaction.manager: board = self._makeBoard(title='Foobar', slug='foobar') topic = self._makeTopic(board=board, title='Hello, world!') topic_id = topic.id # topic is not bound outside transaction! result = self._makeOne(request, topic_id, 'Hi!', True) post = DBSession.query(Post).first() self.assertTrue(result.successful()) self.assertEqual(DBSession.query(Post).count(), 1) self.assertEqual(DBSession.query(Post).get(result.get()[1]), post) self.assertEqual(post.body, 'Hi!') self.assertEqual(post.bumped, True) self.assertEqual(result.result, ('post', post.id))
def main(global_config, **settings): # pragma: no cover """This function returns a Pyramid WSGI application. :param global_config: A :type:`dict` containing global config. :param settings: A :type:`dict` containing values from INI. :type global_config: dict :type settings: dict :rtype: pyramid.router.Router """ config = Configurator(settings=normalize_settings(settings)) config.include('pyramid_mako') config.include('pyramid_beaker') engine = engine_from_config(config.registry.settings, 'sqlalchemy.') DBSession.configure(bind=engine) Base.metadata.bind = engine cache_region.configure_from_config(config.registry.settings, 'dogpile.') redis_conn.from_url(config.registry.settings['redis.url']) celery.config_from_object(configure_celery(config.registry.settings)) identity.configure_tz(config.registry.settings['app.timezone']) akismet.configure_key(config.registry.settings['app.akismet_key']) dnsbl.configure_providers(config.registry.settings['app.dnsbl_providers']) geoip.configure_geoip2(config.registry.settings['app.geoip2_database']) checklist.configure_checklist(config.registry.settings['app.checklist']) proxy_detector.configure_from_config( config.registry.settings, 'app.proxy_detect.') config.set_request_property(remote_addr) config.set_request_property(route_name) config.add_request_method(tagged_static_path) config.add_route('robots', '/robots.txt') config.include('fanboi2.serializers') config.include('fanboi2.views.pages', route_prefix='/pages') config.include('fanboi2.views.api', route_prefix='/api') config.include('fanboi2.views.boards', route_prefix='/') config.add_static_view('static', 'static', cache_max_age=3600) config.scan() return config.make_wsgi_app()
def test_add_post_overridden_other_scoped(self): import transaction from fanboi2.models import Post request = {'remote_addr': '10.0.1.1'} with transaction.manager: self._makeRuleOverride(ip_address='10.0.1.0/24', scope='board:other', override={'status': 'open'}) board = self._makeBoard(title='Foobar', slug='foobar', status='locked') topic = self._makeTopic(board=board, title='Hello, world!') topic_id = topic.id # topic is not bound outside transaction! result = self._makeOne(request, topic_id, 'Hi!', True) post = DBSession.query(Post).first() self.assertTrue(result.successful()) self.assertEqual(DBSession.query(Post).count(), 0) self.assertEqual(result.result, ('failure', 'status_rejected', 'locked'))
def add_topic(request, board_id, title, body): """Insert a topic to the database. :param request: A serialized request :type:`dict` returned from :meth:`fanboi2.utils.serialize_request`. :param board_id: An :type:`int` referencing board ID. :param title: A :type:`str` topic title. :param body: A :type:`str` topic body. :type request: dict :type board_id: int :type title: str :type body: str :rtype: tuple """ ip_address = request['remote_addr'] country_code = geoip.country_code(ip_address) country_scope = 'country:%s' % (str(country_code).lower()) with transaction.manager: board = DBSession.query(Board).get(board_id) board_scope = 'board:%s' % (board.slug, ) if DBSession.query(RuleBan).\ filter(RuleBan.listed(ip_address, scopes=(board_scope,))).\ count() > 0: return 'failure', 'ban_rejected' override = {} rule_override = DBSession.query(RuleOverride).filter( RuleOverride.listed(ip_address, scopes=(board_scope,))).\ first() if rule_override is not None: override = rule_override.override board_status = override.get('status', board.status) if board_status != 'open': return 'failure', 'status_rejected', board_status if checklist.enabled(country_scope, 'akismet') and \ akismet.spam(request, body): return 'failure', 'spam_rejected' if checklist.enabled(country_scope, 'dnsbl') and \ dnsbl.listed(ip_address): return 'failure', 'dnsbl_rejected' if checklist.enabled(country_scope, 'proxy_detect') and \ proxy_detector.detect(ip_address): return 'failure', 'proxy_rejected' post = Post(body=body, ip_address=ip_address) post.topic = Topic(board=board, title=title) DBSession.add(post) DBSession.flush() return 'topic', post.topic_id
def boards_get(request): """Retrieve a list of all boards. :param request: A :class:`pyramid.request.Request` object. :type request: pyramid.request.Request :rtype: sqlalchemy.orm.Query """ return DBSession.query(Board).\ order_by(Board.title).\ filter(Board.status != 'archived')
def topic_get(request): """Retrieve a full post info for an individual topic. :param request: A :class:`pyramid.request.Request` object. :type request: pyramid.request.Request :rtype: sqlalchemy.orm.Query """ return DBSession.query(Topic).\ filter_by(id=request.matchdict['topic']).\ one()
def board_get(request): """Retrieve a full info of a single board. :param request: A :class:`pyramid.request.Request` object. :type request: pyramid.request.Request :rtype: sqlalchemy.orm.Query """ return DBSession.query(Board).\ filter_by(slug=request.matchdict['board']).\ one()
def test_add_topic_ban_scoped(self): from fanboi2.models import Topic request = {'remote_addr': '10.0.1.1'} with transaction.manager: self._makeRuleBan(ip_address='10.0.1.0/24', scope='board:foobar') board = self._makeBoard(title='Foobar', slug='foobar') board_id = board.id # board is not bound outside transaction! result = self._makeOne(request, board_id, 'Foobar', 'Hello, world!') self.assertTrue(result.successful()) self.assertEqual(DBSession.query(Topic).count(), 0) self.assertEqual(result.result, ('failure', 'ban_rejected'))
def test_add_topic_overridden(self): import transaction from fanboi2.models import Topic request = {'remote_addr': '10.0.1.1'} with transaction.manager: self._makeRuleOverride(ip_address='10.0.1.0/24', override={'status': 'open'}) board = self._makeBoard(title='Foobar', slug='foobar', status='restricted') board_id = board.id # board is not bound outside transaction! result = self._makeOne(request, board_id, 'Foobar', 'Hello, world!') topic = DBSession.query(Topic).first() print(result.result) self.assertTrue(result.successful()) self.assertEqual(DBSession.query(Topic).count(), 1) self.assertEqual(DBSession.query(Topic).get(result.get()[1]), topic) self.assertEqual(topic.title, 'Foobar') self.assertEqual(topic.posts[0].body, 'Hello, world!') self.assertEqual(result.result, ('topic', topic.id))
def main(argv=sys.argv): if not len(argv) >= 2: sys.stderr.write("Usage: %s config\n" % os.path.basename(argv[0])) sys.stderr.write("Configuration file not present.\n") sys.exit(1) bootstrap(argv[1]) query = TopicMeta.__table__.update().\ values(bumped_at=sa.select([Post.created_at]).\ where(Post.topic_id == TopicMeta.topic_id).\ where(Post.bumped).\ order_by(sa.desc(Post.created_at)).\ limit(1)) with transaction.manager: session = DBSession() results = session.execute(query) mark_changed(session) print("Successfully synced topic.")
def test_add_topic_proxy(self, proxy): from fanboi2.models import Topic proxy.return_value = True request = {'remote_addr': '127.0.0.1'} with transaction.manager: board = self._makeBoard(title='Foobar', slug='foobar') board_id = board.id # board is not bound outside transaction! result = self._makeOne(request, board_id, 'Foobar', 'Hello, world!') self.assertTrue(result.successful()) self.assertEqual(DBSession.query(Topic).count(), 0) self.assertEqual(result.result, ('failure', 'proxy_rejected'))
def main(global_config, **settings): # pragma: no cover """This function returns a Pyramid WSGI application. :param global_config: A :type:`dict` containing global config. :param settings: A :type:`dict` containing values from INI. :type global_config: dict :type settings: dict :rtype: pyramid.router.Router """ config = Configurator(settings=normalize_settings(settings)) config.include('pyramid_mako') config.include('pyramid_beaker') engine = engine_from_config(config.registry.settings, 'sqlalchemy.') DBSession.configure(bind=engine) Base.metadata.bind = engine cache_region.configure_from_config(config.registry.settings, 'dogpile.') redis_conn.from_url(config.registry.settings['redis.url']) celery.config_from_object(configure_celery(config.registry.settings)) identity.configure_tz(config.registry.settings['app.timezone']) akismet.configure_key(config.registry.settings['app.akismet_key']) dnsbl.configure_providers(config.registry.settings['app.dnsbl_providers']) proxy_detector.configure_from_config( config.registry.settings, 'app.proxy_detect.') config.set_request_property(remote_addr) config.set_request_property(route_name) config.add_request_method(tagged_static_path) config.add_route('robots', '/robots.txt') config.include('fanboi2.serializers') config.include('fanboi2.views.pages', route_prefix='/pages') config.include('fanboi2.views.api', route_prefix='/api') config.include('fanboi2.views.boards', route_prefix='/') config.add_static_view('static', 'static', cache_max_age=3600) config.scan() return config.make_wsgi_app()
def test_add_post_ban(self): import transaction from fanboi2.models import Post request = {'remote_addr': '10.0.1.1'} with transaction.manager: self._makeRuleBan(ip_address='10.0.1.0/24') board = self._makeBoard(title='Foobar', slug='foobar') topic = self._makeTopic(board=board, title='Hello, world!') topic_id = topic.id # topic is not bound outside transaction! result = self._makeOne(request, topic_id, 'Hi!', True) self.assertTrue(result.successful()) self.assertEqual(DBSession.query(Post).count(), 0) self.assertEqual(result.result, ('failure', 'ban_rejected'))
def pages_get(request, namespace=None): """Retrieve a list of all pages. :param request: A :class:`pyramid.request.Request` object. :type request: pyramid.request.Request :rtype: sqlalchemy.orm.Query """ if namespace is None: namespace = 'public' return DBSession.query(Page).\ order_by(Page.title).\ filter_by(namespace=namespace)
def test_add_post_proxy(self, proxy): import transaction from fanboi2.models import Post proxy.return_value = True request = {'remote_addr': '8.8.8.8'} with transaction.manager: board = self._makeBoard(title='Foobar', slug='foobar') topic = self._makeTopic(board=board, title='Hello, world!') topic_id = topic.id # topic is not bound outside transaction! result = self._makeOne(request, topic_id, 'Hi!', True) self.assertTrue(result.successful()) self.assertEqual(DBSession.query(Post).count(), 0) self.assertEqual(result.result, ('failure', 'proxy_rejected'))
def test_add_topic_overridden(self): import transaction from fanboi2.models import Topic request = {'remote_addr': '10.0.1.1'} with transaction.manager: self._makeRuleOverride( ip_address='10.0.1.0/24', override={'status': 'open'}) board = self._makeBoard( title='Foobar', slug='foobar', status='restricted') board_id = board.id # board is not bound outside transaction! result = self._makeOne(request, board_id, 'Foobar', 'Hello, world!') topic = DBSession.query(Topic).first() print(result.result) self.assertTrue(result.successful()) self.assertEqual(DBSession.query(Topic).count(), 1) self.assertEqual(DBSession.query(Topic).get(result.get()[1]), topic) self.assertEqual(topic.title, 'Foobar') self.assertEqual(topic.posts[0].body, 'Hello, world!') self.assertEqual(result.result, ('topic', topic.id))
def test_query(self): from fanboi2.models import DBSession from fanboi2.models import Board board1 = self._makeBoard(title='Foobar', slug='bar') board2 = self._makeBoard(title='Foobaz', slug='baz') request = self._makeRequest() config = self._makeConfig(request, self._makeRegistry()) config.add_route('api_board', '/board/{board}/') response = self._makeOne( DBSession.query(Board).order_by(Board.title), request=request) self.assertIsInstance(response, list) self.assertEqual(response[0]['title'], board1.title) self.assertEqual(response[1]['title'], board2.title)
def test_add_post_overridden_other_scoped(self): import transaction from fanboi2.models import Post request = {'remote_addr': '10.0.1.1'} with transaction.manager: self._makeRuleOverride( ip_address='10.0.1.0/24', scope='board:other', override={'status': 'open'}) board = self._makeBoard( title='Foobar', slug='foobar', status='locked') topic = self._makeTopic(board=board, title='Hello, world!') topic_id = topic.id # topic is not bound outside transaction! result = self._makeOne(request, topic_id, 'Hi!', True) post = DBSession.query(Post).first() self.assertTrue(result.successful()) self.assertEqual(DBSession.query(Post).count(), 0) self.assertEqual(result.result, ( 'failure', 'status_rejected', 'locked'))
def add_topic(request, board_id, title, body): """Insert a topic to the database. :param request: A serialized request :type:`dict` returned from :meth:`fanboi2.utils.serialize_request`. :param board_id: An :type:`int` referencing board ID. :param title: A :type:`str` topic title. :param body: A :type:`str` topic body. :type request: dict :type board_id: int :type title: str :type body: str :rtype: tuple """ with transaction.manager: board = DBSession.query(Board).get(board_id) scope = 'board:%s' % (board.slug,) if DBSession.query(RuleBan).\ filter(RuleBan.listed(request['remote_addr'], scopes=(scope,))).\ count() > 0: return 'failure', 'ban_rejected' override = {} rule_override = DBSession.query(RuleOverride).filter( RuleOverride.listed(request['remote_addr'], scopes=(scope,))).\ first() if rule_override is not None: override = rule_override.override board_status = override.get('status', board.status) if board_status != 'open': return 'failure', 'status_rejected', board_status if akismet.spam(request, body): return 'failure', 'spam_rejected' if dnsbl.listed(request['remote_addr']): return 'failure', 'dnsbl_rejected' if proxy_detector.detect(request['remote_addr']): return 'failure', 'proxy_rejected' post = Post(body=body, ip_address=request['remote_addr']) post.topic = Topic(board=board, title=title) DBSession.add(post) DBSession.flush() return 'topic', post.topic_id
def object(self): """Serializing the result into Python object. :rtype: object """ if self._object is None: obj, id_, *args = self._result.get() if obj == 'failure': self._object = serialize_error(id_, *args) else: class_ = serialize_model(obj) if class_ is not None: self._object = DBSession.query(class_).\ filter_by(id=id_).\ one() return self._object
def test_add_topic_proxy_disabled(self, checklist, proxy): import transaction from fanboi2.models import Topic def disable_proxy_detect(scope, target): return target != 'proxy_detect' checklist.side_effect = disable_proxy_detect proxy.return_value = True request = {'remote_addr': '127.0.0.1'} with transaction.manager: board = self._makeBoard(title='Foobar', slug='foobar') board_id = board.id # board is not bound outside transaction! result = self._makeOne(request, board_id, 'Foobar', 'Hello, world!') self.assertTrue(result.successful()) self.assertEqual(DBSession.query(Topic).count(), 1) proxy.assert_not_called()
def test_add_post_dnsbl_disabled(self, checklist, dnsbl): import transaction from fanboi2.models import Post def disable_dnsbl(scope, target): return target != 'dnsbl' checklist.side_effect = disable_dnsbl dnsbl.return_value = True request = {'remote_addr': '127.0.0.1'} with transaction.manager: board = self._makeBoard(title='Foobar', slug='foobar') topic = self._makeTopic(board=board, title='Hello, world!') topic_id = topic.id # topic is not bound outside transaction! result = self._makeOne(request, topic_id, 'Hi!', True) self.assertTrue(result.successful()) self.assertEqual(DBSession.query(Post).count(), 1) dnsbl.assert_not_called()
def page_get(request, page=None, namespace=None): """Retrieve a page. :param request: A :class:`pyramid.request.Request` object. :param page: Page name to retrieve. :param namespace: Page namespace to retrieve from. :type request: pyramid.request.Request :type page: str :type namespace: str :rtype: sqlalchemy.orm.Query """ if namespace is None: namespace = 'public' if page is None: page = request.matchdict['page'] return DBSession.query(Page).\ filter_by(namespace=namespace, slug=page).\ one()
def _get_override(request, board=None): """Returns a :type:`dict` of an override rule for the given IP address presented in request. If no override present for a user, an empty dict is returned. :param request: A :class:`pyramid.request.Request` object. :param board: A :class:`fanboi2.models.Board` object to scope. :type request: pyramid.request.Request :type board: fanboi2.models.Board :rtype: dict """ scopes = None if board is not None: scopes = ('board:%s' % (board.slug, ), ) rule_override = DBSession.query(RuleOverride).filter( RuleOverride.listed(request.remote_addr, scopes=scopes)).\ first() if rule_override is not None: return rule_override.override return {}
def _get_override(request, board=None): """Returns a :type:`dict` of an override rule for the given IP address presented in request. If no override present for a user, an empty dict is returned. :param request: A :class:`pyramid.request.Request` object. :param board: A :class:`fanboi2.models.Board` object to scope. :type request: pyramid.request.Request :type board: fanboi2.models.Board :rtype: dict """ scopes = None if board is not None: scopes = ('board:%s' % (board.slug,),) rule_override = DBSession.query(RuleOverride).filter( RuleOverride.listed(request.remote_addr, scopes=scopes)).\ first() if rule_override is not None: return rule_override.override return {}
def _makeRule(self, **kwargs): rule = self._newRule(**kwargs) DBSession.add(rule) DBSession.flush() return rule
def add_post(self, request, topic_id, body, bumped): """Insert a post to a topic. :param self: A :class:`celery.Task` object. :param request: A serialized request :type:`dict` returned from :meth:`fanboi2.utils.serialize_request`. :param topic_id: An :type:`int` referencing topic ID. :param body: A :type:`str` post body. :param bumped: A :type:`bool` specifying bump status. :type self: celery.Task :type request: dict :type topic_id: int :type body: str :type bumped: bool :rtype: tuple """ ip_address = request['remote_addr'] country_code = geoip.country_code(ip_address) country_scope = 'country:%s' % (str(country_code).lower()) with transaction.manager: topic = DBSession.query(Topic).get(topic_id) board = topic.board board_scope = 'board:%s' % (board.slug, ) if DBSession.query(RuleBan).\ filter(RuleBan.listed(ip_address, scopes=(board_scope,))).\ count() > 0: return 'failure', 'ban_rejected' if topic.status != 'open': return 'failure', 'status_rejected', topic.status override = {} rule_override = DBSession.query(RuleOverride).filter( RuleOverride.listed(ip_address, scopes=(board_scope,))).\ first() if rule_override is not None: override = rule_override.override board_status = override.get('status', board.status) if not board_status in ('open', 'restricted'): return 'failure', 'status_rejected', board_status if checklist.enabled(country_scope, 'akismet') and \ akismet.spam(request, body): return 'failure', 'spam_rejected' if checklist.enabled(country_scope, 'dnsbl') and \ dnsbl.listed(ip_address): return 'failure', 'dnsbl_rejected' if checklist.enabled(country_scope, 'proxy_detect') and \ proxy_detector.detect(ip_address): return 'failure', 'proxy_rejected' post = Post(topic=topic, body=body, bumped=bumped, ip_address=ip_address) try: DBSession.add(post) DBSession.flush() except IntegrityError as e: raise self.retry(exc=e) return 'post', post.id
def _makeBoard(self, **kwargs): board = self._newBoard(**kwargs) DBSession.add(board) DBSession.flush() return board
def _makeTopic(self, **kwargs): topic = self._newTopic(**kwargs) DBSession.add(topic) DBSession.flush() return topic
def setUpClass(cls): super(ModelMixin, cls).setUpClass() engine = create_engine(DATABASE_URI) DBSession.configure(bind=engine) Base.metadata.bind = engine
def _makeRuleBan(self, **kwargs): rule_ban = self._newRuleBan(**kwargs) DBSession.add(rule_ban) DBSession.flush() return rule_ban
def _makeRuleOverride(self, **kwargs): rule_override = self._newRuleOverride(**kwargs) DBSession.add(rule_override) DBSession.flush() return rule_override
def tearDownClass(cls): super(ModelMixin, cls).tearDownClass() Base.metadata.bind = None DBSession.remove()
def _makePage(self, **kwargs): page = self._newPage(**kwargs) DBSession.add(page) DBSession.flush() return page
def add_post(self, request, topic_id, body, bumped): """Insert a post to a topic. :param self: A :class:`celery.Task` object. :param request: A serialized request :type:`dict` returned from :meth:`fanboi2.utils.serialize_request`. :param topic_id: An :type:`int` referencing topic ID. :param body: A :type:`str` post body. :param bumped: A :type:`bool` specifying bump status. :type self: celery.Task :type request: dict :type topic_id: int :type body: str :type bumped: bool :rtype: tuple """ with transaction.manager: topic = DBSession.query(Topic).get(topic_id) board = topic.board scope = 'board:%s' % (board.slug,) if DBSession.query(RuleBan).\ filter(RuleBan.listed(request['remote_addr'], scopes=(scope,))).\ count() > 0: return 'failure', 'ban_rejected' if topic.status != 'open': return 'failure', 'status_rejected', topic.status override = {} rule_override = DBSession.query(RuleOverride).filter( RuleOverride.listed(request['remote_addr'], scopes=(scope,))).\ first() if rule_override is not None: override = rule_override.override board_status = override.get('status', board.status) if not board_status in ('open', 'restricted'): return 'failure', 'status_rejected', board_status if akismet.spam(request, body): return 'failure', 'spam_rejected' if dnsbl.listed(request['remote_addr']): return 'failure', 'dnsbl_rejected' if proxy_detector.detect(request['remote_addr']): return 'failure', 'proxy_rejected' post = Post( topic=topic, body=body, bumped=bumped, ip_address=request['remote_addr']) try: DBSession.add(post) DBSession.flush() except IntegrityError as e: raise self.retry(exc=e) return 'post', post.id
def _makePost(self, **kwargs): post = self._newPost(**kwargs) DBSession.add(post) DBSession.flush() return post
def _makeTopicMeta(self, **kwargs): topic_meta = self._newTopicMeta(**kwargs) DBSession.add(topic_meta) DBSession.flush() return topic_meta