Skip to content

Commit

Permalink
Add limit and max_age params to RSS feeds
Browse files Browse the repository at this point in the history
  • Loading branch information
alexbecker committed Dec 18, 2019
1 parent c332062 commit edac6c3
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 6 deletions.
115 changes: 115 additions & 0 deletions tests/unit/rss/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
import datetime

import pretend
import pytest
from pyramid.httpexceptions import HTTPBadRequest

from warehouse.rss import views as rss
from warehouse.utils import now

from ...common.db.packaging import ProjectFactory, ReleaseFactory

Expand Down Expand Up @@ -44,6 +47,72 @@ def test_rss_updates(db_request):
assert db_request.response.content_type == "text/xml"


def test_rss_updates_limit(db_request):
db_request.params = {"limit": 2}

db_request.find_service = pretend.call_recorder(
lambda *args, **kwargs: pretend.stub(
enabled=False, csp_policy=pretend.stub(), merge=lambda _: None
)
)

db_request.session = pretend.stub()

project1 = ProjectFactory.create()
project2 = ProjectFactory.create()

release1 = ReleaseFactory.create(project=project1)
release1.created = datetime.date(2011, 1, 1)
release2 = ReleaseFactory.create(project=project2)
release2.created = datetime.date(2012, 1, 1)
release3 = ReleaseFactory.create(project=project1)
release3.created = datetime.date(2013, 1, 1)

assert rss.rss_updates(db_request) == {"latest_releases": [release3, release2]}
assert db_request.response.content_type == "text/xml"


def test_rss_updates_max_age(db_request):
db_request.params = {"max_age": 150}

db_request.find_service = pretend.call_recorder(
lambda *args, **kwargs: pretend.stub(
enabled=False, csp_policy=pretend.stub(), merge=lambda _: None
)
)

db_request.session = pretend.stub()

project1 = ProjectFactory.create()

release1 = ReleaseFactory.create(project=project1)
release1.created = now() - datetime.timedelta(seconds=100)
release2 = ReleaseFactory.create(project=project1)
release2.created = now() - datetime.timedelta(seconds=200)

assert rss.rss_updates(db_request) == {"latest_releases": [release1]}
assert db_request.response.content_type == "text/xml"


def test_rss_updates_max_age_invalid(db_request):
db_request.params = {"max_age": "foo"}

db_request.find_service = pretend.call_recorder(
lambda *args, **kwargs: pretend.stub(
enabled=False, csp_policy=pretend.stub(), merge=lambda _: None
)
)

db_request.session = pretend.stub()

with pytest.raises(HTTPBadRequest) as excinfo:
rss.rss_updates(db_request)

resp = excinfo.value

assert resp.status_code == 400


def test_rss_packages(db_request):
db_request.find_service = pretend.call_recorder(
lambda *args, **kwargs: pretend.stub(
Expand All @@ -66,3 +135,49 @@ def test_rss_packages(db_request):

assert rss.rss_packages(db_request) == {"newest_projects": [project3, project1]}
assert db_request.response.content_type == "text/xml"


def test_rss_packages_limit(db_request):
db_request.params = {"limit": 1}

db_request.find_service = pretend.call_recorder(
lambda *args, **kwargs: pretend.stub(
enabled=False, csp_policy=pretend.stub(), merge=lambda _: None
)
)

db_request.session = pretend.stub()

project1 = ProjectFactory.create()
project1.created = datetime.date(2011, 1, 1)
ReleaseFactory.create(project=project1)

project2 = ProjectFactory.create()
project2.created = datetime.date(2012, 1, 1)
ReleaseFactory.create(project=project2)

assert rss.rss_packages(db_request) == {"newest_projects": [project2]}
assert db_request.response.content_type == "text/xml"


def test_rss_packages_max_age(db_request):
db_request.params = {"max_age": 150}

db_request.find_service = pretend.call_recorder(
lambda *args, **kwargs: pretend.stub(
enabled=False, csp_policy=pretend.stub(), merge=lambda _: None
)
)

db_request.session = pretend.stub()

project1 = ProjectFactory.create()
project1.created = now() - datetime.timedelta(seconds=100)
ReleaseFactory.create(project=project1)

project2 = ProjectFactory.create()
project2.created = now() - datetime.timedelta(seconds=200)
ReleaseFactory.create(project=project2)

assert rss.rss_packages(db_request) == {"newest_projects": [project1]}
assert db_request.response.content_type == "text/xml"
42 changes: 36 additions & 6 deletions warehouse/rss/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,31 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from datetime import timedelta

from pyramid.httpexceptions import HTTPBadRequest
from pyramid.view import view_config
from sqlalchemy.orm import joinedload

from warehouse.cache.origin import origin_cache
from warehouse.packaging.models import Project, Release
from warehouse.utils import now
from warehouse.xml import XML_CSP

DEFAULT_RESULTS = 40
MAX_RESULTS = 200


def _get_int_query_param(request, param, default=None):
value = request.params.get(param)
if not value:
# Return default if 'param' is absent or has an empty value.
return default
try:
return int(value)
except ValueError:
raise HTTPBadRequest(f"'{param}' must be an integer.") from None


@view_config(
route_name="rss.updates",
Expand All @@ -39,11 +57,17 @@ def rss_updates(request):
request.db.query(Release)
.options(joinedload(Release.project))
.order_by(Release.created.desc())
.limit(40)
.all()
)

return {"latest_releases": latest_releases}
max_age = _get_int_query_param(request, "max_age")
if max_age is not None:
created_since = now() - timedelta(seconds=max_age)
latest_releases = latest_releases.filter(Release.created > created_since)

limit = min(_get_int_query_param(request, "limit", DEFAULT_RESULTS), MAX_RESULTS)
latest_releases = latest_releases.limit(limit)

return {"latest_releases": latest_releases.all()}


@view_config(
Expand All @@ -67,8 +91,14 @@ def rss_packages(request):
request.db.query(Project)
.options(joinedload(Project.releases, innerjoin=True))
.order_by(Project.created.desc())
.limit(40)
.all()
)

return {"newest_projects": newest_projects}
max_age = _get_int_query_param(request, "max_age")
if max_age is not None:
created_since = now() - timedelta(seconds=max_age)
newest_projects = newest_projects.filter(Project.created > created_since)

limit = min(_get_int_query_param(request, "limit", DEFAULT_RESULTS), MAX_RESULTS)
newest_projects = newest_projects.limit(limit)

return {"newest_projects": newest_projects.all()}

0 comments on commit edac6c3

Please sign in to comment.