Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add replication for new inquiries and listings #235

Merged
merged 1 commit into from
Apr 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion caravel/model/inquiry.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,38 @@
from caravel.model.principal import PrincipalMixin
from caravel.model.side_effects import SideEffectsMixin
from caravel.model.rate_limits import RateLimitMixin
from caravel.model.replication import ReplicationMixin


from flask import render_template


class _Inquiry(TimeOrderMixin, PrincipalMixin, ModeratedMixin,
ndb.Model):
ReplicationMixin, ndb.Model):

REPLICATION_URL = "https://go-marketplace.appspot.com/inquiries"

message = ndb.StringProperty()
listing = ndb.KeyProperty(kind=listing.Listing)

def encode_for_replication(self):
"""Flattens this Listing into a JSON dict."""

data = self.to_dict()
data["listing"] = self.listing.id()
data["sender"] = {
"email": self.principal.email,
"validated": (self.principal.auth_method == "GOOGLE_APPS")
}
data["moderated"] = (bool(self.principal.validated_by) or
(self.principal.auth_method == "GOOGLE_APPS"))
del data["principal"]
del data["posted_at"]
if "run_trigger" in data:
del data["run_trigger"]

return data


class Inquiry(SideEffectsMixin, _Inquiry):

Expand Down
30 changes: 29 additions & 1 deletion caravel/model/listing.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from caravel.model.full_text import FullTextMixin
from caravel.model.rate_limits import RateLimitMixin
from caravel.model.sellable import SellableMixin
from caravel.model.replication import ReplicationMixin

from caravel import utils

Expand All @@ -21,10 +22,11 @@

class _Listing(CategoriesMixin, PhotosMixin, PrincipalMixin, TimeOrderMixin,
SchemaMixin, PriceMixin, RateLimitMixin, ModeratedMixin,
SellableMixin, FullTextMixin, ndb.Model):
SellableMixin, FullTextMixin, ReplicationMixin, ndb.Model):

SCHEMA_VERSION = 12
MARK_AS_OLD_AFTER = datetime.timedelta(days=30)
REPLICATION_URL = "https://go-marketplace.appspot.com/listings"

title = ndb.StringProperty()
body = ndb.TextProperty()
Expand All @@ -33,6 +35,32 @@ class _Listing(CategoriesMixin, PhotosMixin, PrincipalMixin, TimeOrderMixin,
def can_bump(self):
return self.age >= datetime.timedelta(days=7)

def encode_for_replication(self):
"""Flattens this Listing into a JSON dict."""

data = self.to_dict()
data["posted_at"] = data["posted_at"].isoformat()
data["photos"] = [{"small": photo.public_url("small"),
"large": photo.public_url("large")}
for photo in data["photos"]]
data["price"] = float(data["price"])
if "run_trigger" in data:
del data["run_trigger"]
del data["version"]
del data["burst_count"]
del data["daily_count"]
del data["keywords"]
del data["principal"]

data["seller"] = {
"email": self.principal.email,
"validated": (self.principal.auth_method == "GOOGLE_APPS")
}
data["moderated"] = (bool(self.principal.validated_by) or
(self.principal.auth_method == "GOOGLE_APPS"))

return data


class Listing(SideEffectsMixin, _Listing):

Expand Down
31 changes: 31 additions & 0 deletions caravel/model/replication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from google.appengine.ext import ndb, db
import urllib2
import json
from caravel.storage import config


class ReplicationMixin(ndb.Model):

"""
The ReplicatedMixin triggers a background urlfetch call to update this
listing.
"""

REPLICATION_URL = None

def encode_for_replication(self):
return self.to_dict()

def _post_put_hook(self, future):
"""
Write this entity to the third-party site URL.
"""

if self.REPLICATION_URL:
data = self.encode_for_replication()
data["key"] = self.key.id()
data["replication_key"] = config.replication_key

urllib2.urlopen(self.REPLICATION_URL, json.dumps(data))

return super(ReplicationMixin, self)._post_put_hook(future)
1 change: 1 addition & 0 deletions caravel/storage/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ def get_tor_addresses():
"recaptcha_private_key",
"6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe")
app.config["RECAPTCHA_DATA_ATTRS"] = {"size": "compact"}
replication_key = lookup("replication_key", "~key~")

Bootstrap(app)
5 changes: 5 additions & 0 deletions caravel/templates/listings/map.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="col-xs-12 col-sm-6 float-to-inline-block listing thumbnail-width">
<div class="thumbnail">
<iframe style="width:100%;height:350px" frameborder="0" style="border:0" src="https://www.google.com/maps/embed/v1/view?zoom=14&center=41.7943%2C-87.5907&key=AIzaSyDzo7LIWcwdUI1_cUBML8HSphyuFBDTs6M" allowfullscreen></iframe>
</div>
</div>
11 changes: 6 additions & 5 deletions caravel/tests/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import uuid
import time
import sys
import urllib2
import os
from contextlib import contextmanager

Expand Down Expand Up @@ -94,10 +95,10 @@ def setUp(self):
sendgrid = config.send_grid_client
self._send, sendgrid.send = sendgrid.send, self.emails.append

# Capture outgoing Slack messages.
# self.chats = []
# self._send_chat = slack.send_chat
# slack.send_chat = lambda **kw: self.chats.append(kw)
# Capture outgoing webhooks.
self.webhooks = []
self._urlopen = urllib2.urlopen
urllib2.urlopen = lambda url, body: self.webhooks.append((url, body))

# Ensure that UUIDs are deterministic.
self._uuid4 = uuid.uuid4
Expand Down Expand Up @@ -156,7 +157,7 @@ def tearDown(self):
# Un-stub mocks.
uuid.uuid4 = self._uuid4
config.send_grid_client.send = self._send
# slack.send_chat = self._send_chat
urllib2.urlopen = self._urlopen

super(CaravelTestCase, self).tearDown()

Expand Down
67 changes: 67 additions & 0 deletions caravel/tests/test_replication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from caravel.tests import helper
from caravel import model
import json


class TestListings(helper.CaravelTestCase):

def test_creation(self):
# Submit an inquiry.
with self.google_apps_user("visitor@uchicago.edu"):
self.post("/listing_b", data={
"principal": "buyer@foo.com",
"message": u"message\u2606 goes here",
"csrf_token": self.csrf_token("/listing_b"),
})

self.assertEquals(
[(u, json.loads(d)) for u, d in self.webhooks],
[
("https://go-marketplace.appspot.com/listings",
{u"replication_key": u"~key~",
u"key": u"listing_a",
u"title": u"Listing \u2606A",
u"sold": False,
u"body": u"Body of \u2606A",
u"categories": [u"cars"],
u"photos": [
{u"large": u"/_ah/gcs/test.appspot.com/listing-a-large",
u"small": u"/_ah/gcs/test.appspot.com/listing-a-small"},
{u"large": u"/_ah/gcs/test.appspot.com/listing-a2-large",
u"small": u"/_ah/gcs/test.appspot.com/listing-a2-small"}
],
u"posted_at": self.listing_a.posted_at.isoformat(),
u"price": 3.1,
u"seller": {
u"email": u"seller-a@uchicago.edu",
u"validated": True},
u"moderated": True}),
("https://go-marketplace.appspot.com/listings",
{u"replication_key": u"~key~",
u"key": u"listing_b",
u"title": u"Listing \u2606B",
u"sold": False,
u"body": u"Body of \u2606B",
u"categories": [u"apartments"],
u"photos": [
{u"large": u"/_ah/gcs/test.appspot.com/listing-b-large",
u"small": u"/_ah/gcs/test.appspot.com/listing-b-small"},
{u"large": u"/_ah/gcs/test.appspot.com/listing-b2-large",
u"small": u"/_ah/gcs/test.appspot.com/listing-b2-small"}
],
u"posted_at": self.listing_b.posted_at.isoformat(),
u"price": 71.1,
u"seller": {
u"email": u"seller-b@uchicago.edu",
u"validated": False},
u"moderated": True}),
("https://go-marketplace.appspot.com/inquiries",
{u"key": 11,
u"listing": "listing_b",
u"message": u"message\u2606 goes here",
u"moderated": True,
u"replication_key": u"~key~",
u"sender": {
u"email": u"visitor@uchicago.edu", u"validated": True}
})
])
Empty file.
Empty file.