Ejemplo n.º 1
0
def edit_listing(permalink):
    """Allow a seller to update or unpublish a listing."""

    # Retrieve the listing by key.
    listing = helpers.lookup_listing(permalink)
    if not listing:
        abort(404)

    form = forms.EditListingForm()

    # Prevent non-creators from editing a listing.
    if session.get("email") != listing.seller or not session["email"]:
        abort(403)

    # Allow the author of a listing to unpublish it.
    if request.form.get("unpublish"):
        listing.posting_time = 0.0
        listing.put()
        helpers.invalidate_listing(listing)

        return redirect("/")

    # Upload photos after validate_on_submit(), even if other fields in the form
    # are invalid.
    is_valid = form.validate_on_submit()
    if request.method == "POST":
        photos = []
        for photo in form.photos:
            if not photo.data:
                continue
            image = photo.data["image"]
            if not image or (hasattr(image, "filename") and not image.filename):
                continue
            photos.append(image)
        listing.photos = photos

    # Allow authors to edit listings.
    if is_valid:
        listing.title = form.title.data
        listing.body = form.description.data
        listing.categories = form.categories.data
        listing.price = int(form.price.data * 100)
        listing.put()

        helpers.invalidate_listing(listing)

        return redirect(url_for("show_listing", permalink=listing.permalink))

    # Display an edit form.
    form.title.data = listing.title
    form.description.data = listing.body
    form.categories.data = listing.categories
    form.price.data = listing.price / 100.0
    for index, entry in enumerate(form.photos.entries):
        if index < len(listing.photos):
            entry["image"].data = listing.photos[index]
        else:
            entry["image"].data = None

    return render_template("listing_form.html", type="Edit", form=form)
Ejemplo n.º 2
0
def migrate_schema():
    q = entities.Listing.all()
    q = q.filter("version <", entities.Listing.SCHEMA_VERSION)

    for listing in q.fetch(100):
        db.run_in_transaction(lambda: (listing.migrate(), listing.put()))
        helpers.invalidate_listing(listing)

    return "ok"
Ejemplo n.º 3
0
def migrate_schema():
    q = entities.Listing.all()
    q = q.filter("version <", entities.Listing.SCHEMA_VERSION)

    for listing in q.fetch(100):
        db.run_in_transaction(lambda: (listing.migrate(), listing.put()))
        helpers.invalidate_listing(listing)

    return "ok"
Ejemplo n.º 4
0
def show_listing(permalink):
    """View a particular listing and provide links to place an inquiry."""

    # Retrieve the listing by key.
    listing = helpers.lookup_listing(permalink)
    if not listing:
        abort(404)

    # If the listing isn't yet published, check the URL key and update session.
    if request.args.get("key") == listing.admin_key and listing.admin_key:
        session["email"] = listing.seller
        if not listing.posting_time:
            listing.posting_time = time.time()
            listing.put()
            helpers.invalidate_listing(listing)

            flash("Your listing has been published.")
            return redirect(
                url_for("show_listing",
                        permalink=permalink,
                        q=request.args.get("q")))

    # Otherwise, hide the listing.
    elif not listing.posting_time:
        abort(404)

    # Display a form for buyers to place an offer.
    buyer_form = forms.BuyerForm()

    buyer = buyer_form.buyer.data
    message = buyer_form.message.data
    seller = listing.seller

    # Validate emails with the submission of the form.
    buyer_form.post_validate = (
        lambda: policy.place_inquiry(listing, buyer, message))

    # Handle submissions on the form.
    if buyer_form.validate_on_submit():

        # Track what requests are sent to which people.
        helpers.add_inqury(listing, buyer, message)

        # Provide a flash message.
        flash("Your inquiry has been sent.")

        return redirect(url_for("show_listing", permalink=permalink))

    # Have the form email default to the value from the session.
    if not buyer_form.buyer.data:
        buyer_form.buyer.data = session.get("email")

    # Display the resulting template.
    return render_template("listing_show.html",
                           listing=listing,
                           buyer_form=buyer_form)
Ejemplo n.º 5
0
def test_lookups():
    a = entities.Listing(title="lista", body="ba", key_name="foo")
    a.put()
    assert helpers.lookup_listing("foo").title == "lista"

    a.title = "listb"
    a.put()
    assert helpers.lookup_listing("foo").title == "lista"

    helpers.invalidate_listing(a)
    assert helpers.lookup_listing("foo").title == "listb"
Ejemplo n.º 6
0
def test_lookups():
    a = entities.Listing(title="lista", body="ba", key_name="foo")
    a.put()
    assert helpers.lookup_listing("foo").title == "lista"

    a.title = "listb"
    a.put()
    assert helpers.lookup_listing("foo").title == "lista"

    helpers.invalidate_listing(a)
    assert helpers.lookup_listing("foo").title == "listb"
Ejemplo n.º 7
0
def show_listing(permalink):
    """View a particular listing and provide links to place an inquiry."""

    # Retrieve the listing by key.
    listing = helpers.lookup_listing(permalink)
    if not listing:
        abort(404)

    # If the listing isn't yet published, check the URL key and update session.
    if request.args.get("key") == listing.admin_key and listing.admin_key:
        session["email"] = listing.seller
        if not listing.posting_time:
            listing.posting_time = time.time()
            listing.put()
            helpers.invalidate_listing(listing)

            flash("Your listing has been published.")
            return redirect(url_for("show_listing", permalink=permalink,
                                                    q=request.args.get("q")))

    # Otherwise, hide the listing.
    elif not listing.posting_time:
        abort(404)

    # Display a form for buyers to place an offer. 
    buyer_form = forms.BuyerForm()

    buyer = buyer_form.buyer.data
    message = buyer_form.message.data
    seller = listing.seller

    # Validate emails with the submission of the form.
    buyer_form.post_validate = (
        lambda: policy.place_inquiry(listing, buyer, message))

    # Handle submissions on the form.
    if buyer_form.validate_on_submit():

        # Track what requests are sent to which people.
        helpers.add_inqury(listing, buyer, message)

        # Provide a flash message.
        flash("Your inquiry has been sent.")

        return redirect(url_for("show_listing", permalink=permalink))

    # Have the form email default to the value from the session.
    if not buyer_form.buyer.data:
        buyer_form.buyer.data = session.get("email")

    # Display the resulting template.
    return render_template("listing_show.html", listing=listing,
                           buyer_form=buyer_form)
Ejemplo n.º 8
0
def test_search():
    entities.Listing(title="title for test",
                     posting_time=1.0e5, key_name="search_test").put()

    assert tuple(helpers.fetch_shard("title")) == ("search_test",)
    assert (tuple(x.permalink for x in helpers.run_query("title for test")) ==
            ("search_test",))

    ent = entities.Listing(title="new title",
                           posting_time=1.0e5, key_name="search_test")
    ent.put()
    helpers.invalidate_listing(ent)

    assert not helpers.run_query("title for test")
Ejemplo n.º 9
0
def test_search():
    entities.Listing(title="title for test",
                     posting_time=1.0e5,
                     key_name="search_test").put()

    assert tuple(helpers.fetch_shard("title")) == ("search_test", )
    assert (tuple(
        x.permalink
        for x in helpers.run_query("title for test")) == ("search_test", ))

    ent = entities.Listing(title="new title",
                           posting_time=1.0e5,
                           key_name="search_test")
    ent.put()
    helpers.invalidate_listing(ent)

    assert not helpers.run_query("title for test")
Ejemplo n.º 10
0
                            minutes=float(
                                json_data["renewed_at"][-2:]))).timetuple())

    # Remove HTML tags from body.
    cleaned_body = re.sub(r'<[^>]+>', '', json_data["details"])

    # Prepare a listing to update.
    listing = entities.Listing(key_name=json_data["permalink"],
                               seller=json_data["seller"]["email"],
                               posting_time=posting_time,
                               title=json_data["description"],
                               body=cleaned_body,
                               price=(int(float(json_data["price"]) * 100)))

    # Download all original photos for this listing.
    html = _urlopen(url).read()
    images = re.finditer(r"<a class='fancybox-image' href='([^']*)'", html)
    prefix = "http://marketplace.uchicago.edu"

    listing.photos = [_urlopen(prefix + m.group(1)) for m in images]

    # Extract the current category from the production site.
    category = re.search(r'<a href=".*categories.*">([^<]*)</a>', html)
    listing.categories = [category.group(1).lower()]

    # (Idempotently) save this entity into the datastore.
    listing.put()

    # Invalidate the cache.
    helpers.invalidate_listing(listing)
Ejemplo n.º 11
0
def show_listing(permalink):
    """View a particular listing and provide links to place an inquiry."""

    # Retrieve the listing by key.
    listing = helpers.lookup_listing(permalink)
    if not listing:
        abort(404)

    # If the listing isn't yet published, check the URL key and update session.
    if request.args.get("key") == listing.admin_key and listing.admin_key:
        session["email"] = listing.seller
        if not listing.posting_time:
            listing.posting_time = time.time()
            listing.put()
            helpers.invalidate_listing(listing)

            flash("Your listing has been published.")
            return redirect(url_for("show_listing", permalink=permalink,
                                    q=request.args.get("q")))

    # Otherwise, hide the listing.
    elif not listing.posting_time:
        abort(404)

    # Display a form for buyers to place an offer.
    buyer_form = forms.BuyerForm()

    # Handle submissions on the form.
    if buyer_form.validate_on_submit():
        buyer = buyer_form.buyer.data
        message = buyer_form.message.data
        seller = listing.seller

        # Track what requests are sent to which people.
        helpers.add_inqury(listing, buyer, message)

        # Block spam inquiries.
        if (buyer.strip() == "*****@*****.**" or
                buyer.strip() == "*****@*****.**" or
                dos.rate_limit(buyer.strip(), 4, 60) or
                dos.rate_limit(request.remote_addr, 4, 60) or
                dos.rate_limit(listing.seller, 20, 3600 * 24)):

            message = "MESSAGE BLOCKED!\n\n" + str(message)
            seller = "*****@*****.**"

        # Send a listing to the person.
        email.send_mail(
            to=seller,
            reply_to=buyer,
            subject="Re: Marketplace Listing \"{}\"".format(listing.title),
            html=render_template("email/inquiry.html", **locals()),
            text=render_template("email/inquiry.txt", **locals()),
        )

        return redirect(url_for("show_listing", permalink=permalink))

    # Have the form email default to the value from the session.
    if not buyer_form.buyer.data:
        buyer_form.buyer.data = session.get("email")

    # Display the resulting template.
    return render_template("listing_show.html", listing=listing,
                           buyer_form=buyer_form)
Ejemplo n.º 12
0
def new_listing():
    """Creates or removes this listing."""

    # Populate a form to create a listing.
    form = forms.NewListingForm()

    # Create a temporary listing so that photos can be uploaded.
    listing = entities.Listing(
        key_name=str(uuid.uuid4()),  # FIXME: add proper permalink generator.
        title=form.title.data,
        price=int(form.price.data * 100) if form.price.data else 0,
        body=form.description.data,
        categories=form.categories.data or [],
        seller=form.seller.data,
        posting_time=(time.time() if session.get("email") else 0.0),
        admin_key=str(uuid.uuid4())
    )

    # Allow uploading and saving the given request.
    is_valid = form.validate_on_submit()
    if request.method == "POST":
        photos = []
        for photo in form.photos:
            if not photo.data:
                continue
            image = photo.data["image"]
            if not image or(
                    hasattr(image, "filename") and not image.filename):
                continue
            photos.append(image)

        listing.photos = photos

    # Allow anyone to create listings.
    if is_valid:
        listing.title = form.title.data
        listing.body = form.description.data
        listing.categories = form.categories.data
        listing.price = int(form.price.data * 100)
        listing.put()

        helpers.invalidate_listing(listing)

        # Send the user an email to let them edit the listing.
        email.send_mail(
            to=listing.seller,
            subject="Marketplace Listing \"{}\"".format(listing.title),
            html=render_template("email/welcome.html", listing=listing),
            text=render_template("email/welcome.txt", listing=listing)
        )

        # If running locally, print a link to this listing.
        print url_for("show_listing", permalink=listing.key().name(),
                      key=listing.admin_key, _external=True)

        # Only allow the user to see the listing if they are signed in.
        if session.get("email") == listing.seller:
            flash("Your listing has been published.")
            return redirect(url_for("show_listing",
                                    permalink=listing.permalink))
        else:
            flash("Your listing has been created. "
                  "Click the link in your email to publish it.")
            return redirect(url_for("search_listings"))

    # Have the form email default to the value from the session.
    if not form.seller.data:
        form.seller.data = session.get("email")

    # Display the photo URL of any uploaded photos.
    for index, entry in enumerate(form.photos.entries):
        if index < len(listing.photos):
            entry["image"].data = listing.photos[index]
        else:
            entry["image"].data = None

    return render_template("listing_form.html", type="New", form=form)
Ejemplo n.º 13
0
def new_listing():
    """Creates or removes this listing."""

    # Populate a form to create a listing.
    form = forms.NewListingForm()

    # Create a temporary listing so that photos can be uploaded.
    listing = entities.Listing(
        key_name=str(uuid.uuid4()),  # FIXME: add proper permalink generator.
        title=form.title.data,
        price=int(form.price.data * 100) if form.price.data else 0,
        body=form.description.data,
        categories=form.categories.data or [],
        seller=form.seller.data,
        posting_time=(time.time() if session.get("email") else 0.0),
        admin_key=str(uuid.uuid4()))

    # Ensure that validations check with policy.
    form.post_validate = lambda: policy.claim_listing(listing)

    # Allow uploading and saving the given request.
    is_valid = form.validate_on_submit()
    if request.method == "POST":
        photos = []
        for photo in form.photos:
            if not photo.data:
                continue
            image = photo.data["image"]
            if not image or (hasattr(image, "filename")
                             and not image.filename):
                continue
            photos.append(image)

        listing.photos = photos

    # Allow anyone to create listings.
    if is_valid:

        # Update the listing on the server.
        listing.put()
        helpers.invalidate_listing(listing)

        # Only allow the user to see the listing if they are signed in.
        if session.get("email") == listing.seller:
            flash("Your listing has been published.")
            return redirect(
                url_for("show_listing", permalink=listing.permalink))
        else:
            flash("Your listing has been created. "
                  "Click the link in your email to publish it.")
            return redirect(url_for("search_listings"))

    # Have the form email default to the value from the session.
    if not form.seller.data:
        form.seller.data = session.get("email")

    # Display the photo URL of any uploaded photos.
    for index, entry in enumerate(form.photos.entries):
        if index < len(listing.photos):
            entry["image"].data = listing.photos[index]
        else:
            entry["image"].data = None

    return render_template("listing_form.html", type="New", form=form)
Ejemplo n.º 14
0
def edit_listing(permalink):
    """Allow a seller to update or unpublish a listing."""

    # Retrieve the listing by key.
    listing = helpers.lookup_listing(permalink)
    if not listing:
        abort(404)

    form = forms.EditListingForm()

    # Prevent non-creators from editing a listing.
    if session.get("email") != listing.seller or not session["email"]:
        abort(403)

    # Allow the author of a listing to unpublish it.
    if request.form.get("unpublish"):
        listing.posting_time = 0.0
        listing.put()
        helpers.invalidate_listing(listing)

        return redirect("/")

    # Upload photos after validate_on_submit(), even if other fields in the form
    # are invalid.
    is_valid = form.validate_on_submit()
    if request.method == "POST":
        photos = []
        for photo in form.photos:
            if not photo.data:
                continue
            image = photo.data["image"]
            if not image or (hasattr(image, "filename")
                             and not image.filename):
                continue
            photos.append(image)

        listing.photos = photos

    # Allow authors to edit listings.
    if is_valid:
        listing.title = form.title.data
        listing.body = form.description.data
        listing.categories = form.categories.data
        listing.price = int(form.price.data * 100)
        listing.put()

        helpers.invalidate_listing(listing)

        return redirect(url_for("show_listing", permalink=listing.permalink))

    # Display an edit form.
    form.title.data = listing.title
    form.description.data = listing.body
    form.categories.data = listing.categories
    form.price.data = listing.price / 100.0
    for index, entry in enumerate(form.photos.entries):
        if index < len(listing.photos):
            entry["image"].data = listing.photos[index]
        else:
            entry["image"].data = None

    return render_template("listing_form.html", type="Edit", form=form)
Ejemplo n.º 15
0
    # Remove HTML tags from body.
    cleaned_body = re.sub(r'<[^>]+>', '', json_data["details"])

    # Prepare a listing to update.
    listing = entities.Listing(
        key_name=json_data["permalink"],
        seller=json_data["seller"]["email"],
        posting_time=posting_time,
        title=json_data["description"],
        body=cleaned_body,
        price=(int(float(json_data["price"]) * 100))
    )

    # Download all original photos for this listing.
    html = _urlopen(url).read()
    images = re.finditer(r"<a class='fancybox-image' href='([^']*)'", html)
    prefix = "http://marketplace.uchicago.edu"

    listing.photos = [_urlopen(prefix + m.group(1)) for m in images]

    # Extract the current category from the production site.
    category = re.search(r'<a href=".*categories.*">([^<]*)</a>', html)
    listing.categories = [category.group(1).lower()]

    # (Idempotently) save this entity into the datastore.
    listing.put()

    # Invalidate the cache.
    helpers.invalidate_listing(listing)
Ejemplo n.º 16
0
def new_listing():
    """Creates or removes this listing."""

    # Populate a form to create a listing.
    form = forms.NewListingForm()

    # Create a temporary listing so that photos can be uploaded.
    listing = entities.Listing(
        key_name=str(uuid.uuid4()),  # FIXME: add proper permalink generator.
        title=form.title.data,
        price=int(form.price.data * 100) if form.price.data else 0,
        body=form.description.data,
        categories=form.categories.data or [],
        seller=form.seller.data,
        posting_time=(time.time() if session.get("email") else 0.0),
        admin_key=str(uuid.uuid4())
    )

    # Ensure that validations check with policy.
    form.post_validate = lambda: policy.claim_listing(listing)

    # Allow uploading and saving the given request.
    is_valid = form.validate_on_submit()
    if request.method == "POST":
        photos = []
        for photo in form.photos:
            if not photo.data:
                continue
            image = photo.data["image"]
            if not image or (hasattr(image, "filename") and not image.filename):
                continue
            photos.append(image)

        listing.photos = photos

    # Allow anyone to create listings.
    if is_valid:
        
        # Update the listing on the server.
        listing.put()
        helpers.invalidate_listing(listing)

        # Only allow the user to see the listing if they are signed in.
        if session.get("email") == listing.seller:
            flash("Your listing has been published.")
            return redirect(url_for("show_listing",
                     permalink=listing.permalink))
        else:
            flash("Your listing has been created. "
                  "Click the link in your email to publish it.")
            return redirect(url_for("search_listings"))

    # Have the form email default to the value from the session.
    if not form.seller.data:
        form.seller.data = session.get("email")

    # Display the photo URL of any uploaded photos.
    for index, entry in enumerate(form.photos.entries):
        if index < len(listing.photos):
            entry["image"].data = listing.photos[index]
        else:
            entry["image"].data = None

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