Skip to content

Commit

Permalink
Expire listings after 30 days.
Browse files Browse the repository at this point in the history
  • Loading branch information
fatlotus committed Jan 25, 2016
1 parent c2ff247 commit 612bb0e
Show file tree
Hide file tree
Showing 17 changed files with 192 additions and 32 deletions.
30 changes: 14 additions & 16 deletions caravel/controllers/listings.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ def show_listing(listing):
if is_from_tor():
abort(403)

if listing.sold or listing.old:
abort(403)

inquiry = model.UnapprovedInquiry(listing=listing.key)
form.populate_obj(inquiry)
inquiry.put()
Expand Down Expand Up @@ -192,24 +195,16 @@ def publish_listing(listing):
if not requester.can_act_as(listing.principal):
abort(403)

fields = listing.to_dict()

new_listing = model.UnapprovedListing(id=listing.key.id())
for key, value in listing.to_dict().items():
try:
setattr(new_listing, key, value)
except ndb.ComputedPropertyError:
pass

new_listing.sold = (request.form.get("sold") == "true")
new_listing.take_values_from(listing)
new_listing.principal = requester

new_listing.sold = (request.form.get("sold") == "true")
new_listing.put()

if not isinstance(new_listing, model.Listing):
flash("Your edit is awaiting moderation. "
"We'll email you when it is approved.")
return redirect(url_for("show_listing", listing=listing))
return redirect(url_for("show_listing", listing=new_listing))


@app.route("/<listing:listing>/edit", methods=["GET", "POST"])
Expand All @@ -233,13 +228,15 @@ def edit_listing(listing):
form.principal.validators[-1].principal = listing.principal

if form.validate_on_submit():
listing = model.UnapprovedListing(id=listing.key.id(), version=11)
form.populate_obj(listing)
listing.put()
if not isinstance(listing, model.Listing):
new_listing = model.UnapprovedListing(id=listing.key.id(), version=11)
new_listing.take_values_from(listing)
form.populate_obj(new_listing)
new_listing.put()

if not isinstance(new_listing, model.Listing):
flash("Your edit is awaiting moderation. "
"We'll email you when it is approved.")
return redirect(url_for("show_listing", listing=listing))
return redirect(url_for("show_listing", listing=new_listing))

return render_template("listing_form.html", form=form)

Expand All @@ -258,6 +255,7 @@ def new_listing():
if form.validate_on_submit():
listing = model.UnapprovedListing(id=str(uuid.uuid4()), version=11)
form.populate_obj(listing)
listing.posted_at = datetime.datetime.now()
listing.put()

if isinstance(listing, model.Listing):
Expand Down
1 change: 1 addition & 0 deletions caravel/daemons/delete_old_photos.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from caravel import app, model


@app.route('/_internal/collect_garbage')
def collect_garbage():
model.Photo.remove_old_photos()
Expand Down
7 changes: 6 additions & 1 deletion caravel/daemons/migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from google.appengine.ext import ndb
from caravel import app, model
import itertools
import datetime


def grouper(iterable, n, fillvalue=None):
Expand All @@ -16,8 +17,12 @@ def grouper(iterable, n, fillvalue=None):

@app.route("/_internal/migrate_schema")
def migrate_schema():
horizon = datetime.datetime.now() - model.Listing.MARK_AS_OLD_AFTER

q = model.Listing.query(
model.Listing.version < model.Listing.SCHEMA_VERSION)
(model.Listing.version < model.Listing.SCHEMA_VERSION) or
(model.Listing.posted_at <= horizon and
model.Listing.keywords >= ""))

for entities in grouper(itertools.islice(q, 0, 1000), 100):
ndb.put_multi([entity for entity in entities if entity])
Expand Down
2 changes: 1 addition & 1 deletion caravel/model/full_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def grouper(iterable, n, fillvalue=None):

class FullTextMixin(ndb.Model):
keywords = ndb.ComputedProperty(
lambda self: [""] + list(set(self._keywords())), repeated=True)
lambda self: list(set(self._keywords())), repeated=True)

@classmethod
def matching(klass, query, offset=0, limit=None):
Expand Down
3 changes: 2 additions & 1 deletion caravel/model/listing.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class _Listing(CategoriesMixin, PhotosMixin, PrincipalMixin, TimeOrderMixin,
SellableMixin, FullTextMixin, ndb.Model):

SCHEMA_VERSION = 12
MARK_AS_OLD_AFTER = datetime.timedelta(days=30)

title = ndb.StringProperty()
body = ndb.TextProperty()
Expand All @@ -46,7 +47,7 @@ def side_effects(self):
def _keywords(self):
"""Generates keywords for this listing."""

if self.sold:
if self.sold or self.old:
return []

keywords = (
Expand Down
22 changes: 19 additions & 3 deletions caravel/model/moderation.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
from google.appengine.ext import ndb
from caravel.model import principal


class ModeratedMixin(ndb.Model):

"""
A ModeratedMixin allows an entity to change type once the approval property
is true. If no approved() method is specified, the class defaults to using
the .principal property.
>>> from google.appengine.ext import ndb
>>> class Parent(ndb.Model): pass
>>> class A(Parent): pass
>>> class B(ModeratedMixin, Parent):
Expand Down Expand Up @@ -69,4 +71,18 @@ def approve(self, reason):
"""

self.principal.validate(reason)
assert self.approved()
assert self.approved()

def take_values_from(self, existing_entity):
"""
Reads property values from the existing_entity. Primarily, this is
useful for modifying existing entities.
"""

for key, value in existing_entity.to_dict().items():
if not value:
continue
try:
setattr(self, key, value)
except ndb.ComputedPropertyError:
pass
10 changes: 9 additions & 1 deletion caravel/model/temporal.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
from google.appengine.ext import ndb
import datetime


class TimeOrderMixin(ndb.Model):

"""
The TimeOrderMixin defines entities that have a creation time.
"""

posted_at = ndb.DateTimeProperty(auto_now_add=True)
posted_at = ndb.DateTimeProperty()

@property
def old(self):
horizon = datetime.datetime.now() - self.MARK_AS_OLD_AFTER
return (self.posted_at <= horizon)
12 changes: 9 additions & 3 deletions caravel/templates/listings/fullpage.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,14 @@ <h2>{{ listing.title }}</h2>
</p>
{% if listing.sold %}
<p class="alert alert-warning">
This listing was sold, preventing it from showing up in searches
and blocking future inquiries.
"<strong>{{ listing.title }}</strong>" has been sold,
preventing it from showing up in searches and blocking future inquiries.
</p>
{% elif listing.old %}
<p class="alert alert-warning">
"<strong>{{ listing.title }}</strong>" was posted more than 30 days ago,
so it does not show up in searches, and will not receive inquiries.
It has likely already been sold.
</p>
{% endif %}
{% if is_admin %}
Expand Down Expand Up @@ -106,7 +112,7 @@ <h3 class="panel-title">
</div>

{% endif %}
{% if not listing.sold %}
{% if not listing.sold and not listing.old %}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Contact Seller</h3>
Expand Down
22 changes: 22 additions & 0 deletions caravel/tests/test_listings.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,26 @@
import StringIO
import time
import re
import datetime


class TestListings(helper.CaravelTestCase):

def test_indexing(self):
# Test normal indexing.
self.assertFalse(self.listing_a.old)
self.assertLongString("\n".join(sorted(self.listing_a.keywords)))

# Test that old listings are de-indexed.
self.listing_a.posted_at = datetime.datetime(2003, 2, 3)

self.assertTrue(self.listing_a.old)
self.assertEquals(self.listing_a.keywords, [])

# Test that sold listings are de-indexed.
self.listing_b.sold = True
self.assertEquals(self.listing_a.keywords, [])

def test_search(self):
# View all listings, in order.
self.assertLongString(self.get("/").data)
Expand Down Expand Up @@ -308,3 +324,9 @@ def test_publish_listing_with_cnetid(self):

# Listing is visible again in searches.
self.assertLongString(self.get("/").data)

def test_old_listing(self):
self.listing_a.posted_at -= datetime.timedelta(days=60)
self.listing_a.put()

self.assertLongString(self.get("/listing_a").data)
2 changes: 1 addition & 1 deletion caravel/tests/test_listings_edit_listing_expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ My Listings
Logout
Title☆A
cars
Posted now .
Posted 5h ago .
Price: $2.34
Validated by GOOGLE_APPS. Originally posted by
None with
Expand Down
13 changes: 13 additions & 0 deletions caravel/tests/test_listings_indexing_expect.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
body
body:body
body:of
body:☆a
cars
category:cars
listing
of
seller-a@uchicago.edu
seller:seller-a@uchicago.edu
title:listing
title:☆a
☆a
12 changes: 12 additions & 0 deletions caravel/tests/test_listings_old_listing_expect.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
New Listing
Listing ☆A
cars
Posted 9w ago .
Price: $3.10
" Listing ☆A " was posted more than 30 days ago,
so it does not show up in searches, and will not receive inquiries.
It has likely already been sold.
Body of ☆A
Manage Listing
Sign in with CNetID
to edit.
Empty file.
8 changes: 4 additions & 4 deletions caravel/tests/test_listings_publish_listing_expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ Listing ☆B
apartments
Posted 2d ago .
Price: $71.10
This listing was sold, preventing it from showing up in searches
and blocking future inquiries.
" Listing ☆B " has been sold,
preventing it from showing up in searches and blocking future inquiries.
Body of ☆B
Suggest Changes
Edit
Expand All @@ -43,8 +43,8 @@ Listing ☆B
apartments
Posted 2d ago .
Price: $71.10
This listing was sold, preventing it from showing up in searches
and blocking future inquiries.
" Listing ☆B " has been sold,
preventing it from showing up in searches and blocking future inquiries.
Body of ☆B
Suggest Changes
Edit
Expand Down
77 changes: 77 additions & 0 deletions caravel/tests/test_listings_publish_listing_with_cnetid_expect.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
New Listing
Logged in as
seller-b@uchicago.edu
My Listings
Logout
Listing ☆A
cars
Posted 5h ago .
Price: $3.10
Validated by GOOGLE_APPS. Originally posted by
1.2.3.4 with
mozilla.
Body of ☆A
Contact Seller
From
seller-b@uchicago.edu ( Logout )
Message
---
New Listing
Logged in as
seller-b@uchicago.edu
My Listings
Logout
Listing ☆A
$3.10
cars
5h ago
Listing ☆B
$71.10
apartments
2d ago
---
New Listing
Logged in as
seller-b@uchicago.edu
My Listings
Logout
Listing ☆A
$3.10
cars
5h ago
Listing ☆B
$71.10
apartments
2d ago
---
New Listing
Logged in as
seller-b@uchicago.edu
My Listings
Logout
Listing ☆A
cars
Posted 5h ago .
Price: $3.10
Validated by GOOGLE_APPS. Originally posted by
1.2.3.4 with
mozilla.
Body of ☆A
Contact Seller
From
seller-b@uchicago.edu ( Logout )
Message
---
New Listing
Logged in as
seller-b@uchicago.edu
My Listings
Logout
Listing ☆A
$3.10
cars
5h ago
Listing ☆B
$71.10
apartments
2d ago
3 changes: 2 additions & 1 deletion caravel/tests/test_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from caravel import model

import datetime
from google.appengine.ext import db
import time
from google.appengine.ext import db, ndb


class Listing(db.Expando):
Expand Down
Empty file.

0 comments on commit 612bb0e

Please sign in to comment.