зеркало из https://github.com/mozilla/kitsune.git
Massage customercare models to make tweet replies more traversible.
Tweet now uses tweet_id as its pkey. The surrogate key wasn't really useful, and this makes it simple to turn reply_to into a Django ForeignKey so we can traverse it for the Answered and Unanswered filters. Cascading deletes are okay for replies; it doesn't make sense (UI or otherwise) to hang onto replies to tweets we no longer have.
This commit is contained in:
Родитель
02b6b20d20
Коммит
602144100c
|
@ -1,120 +1,109 @@
|
|||
[
|
||||
{
|
||||
"pk": 30,
|
||||
"pk": 25308717656,
|
||||
"model": "customercare.tweet",
|
||||
"fields": {
|
||||
"locale": "en",
|
||||
"tweet_id": 25308717656,
|
||||
"raw_json": "{\"iso_language_code\": \"en\", \"text\": \"Kudos to Brizzly - the application is much less buggy lately. No more double tweet boxes. No more extra UI garbage on my Firefox window.\", \"created_at\": \"Thu, 23 Sep 2010 13:52:40 +0000\", \"profile_image_url\": \"http://a1.twimg.com/profile_images/876200349/tool-belt_Logo_normal.jpg\", \"source\": \"<a href="http://www.brizzly.com" rel="nofollow">Brizzly</a>\", \"from_user\": \"rossgk\", \"from_user_id\": 150857, \"to_user_id\": null, \"geo\": null, \"id\": 25308717656, \"metadata\": {\"result_type\": \"recent\"}}",
|
||||
"reply_to": null,
|
||||
"created": "2010-09-23 13:52:40"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 23,
|
||||
"pk": 25308845620,
|
||||
"model": "customercare.tweet",
|
||||
"fields": {
|
||||
"locale": "en",
|
||||
"tweet_id": 25308845620,
|
||||
"raw_json": "{\"iso_language_code\": \"en\", \"text\": \"Firefox\\u3000chrome\\u306b\\u4e57\\u308a\\u63db\\u3048\\u308b\\u304b\\u601d\\u6848\\u4e2d #firefox\", \"created_at\": \"Thu, 23 Sep 2010 13:54:12 +0000\", \"profile_image_url\": \"http://a1.twimg.com/profile_images/1041604705/188292_8256_normal.jpg\", \"source\": \"<a href="http://www.echofon.com/" rel="nofollow">Echofon</a>\", \"from_user\": \"ikd_fine\", \"from_user_id\": 129866568, \"to_user_id\": null, \"geo\": null, \"id\": 25308845620, \"metadata\": {\"result_type\": \"recent\"}}",
|
||||
"reply_to": null,
|
||||
"created": "2010-09-23 13:54:12"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 21,
|
||||
"pk": 25308851981,
|
||||
"model": "customercare.tweet",
|
||||
"fields": {
|
||||
"locale": "en",
|
||||
"tweet_id": 25308851981,
|
||||
"raw_json": "{\"iso_language_code\": \"en\", \"text\": \"We're noticing a lot of #Flash Errors in #Firefox in the last few days. Including the AS3 Scroll Bars on my site. Too many updates FTL.\", \"created_at\": \"Thu, 23 Sep 2010 13:54:17 +0000\", \"profile_image_url\": \"http://a3.twimg.com/profile_images/1037516415/IA_100x100_avtr_normal.png\", \"source\": \"<a href="http://twitter.com/">web</a>\", \"from_user\": \"runtime_iA\", \"from_user_id\": 130011759, \"to_user_id\": null, \"geo\": null, \"id\": 25308851981, \"metadata\": {\"result_type\": \"recent\"}}",
|
||||
"reply_to": null,
|
||||
"created": "2010-09-23 13:54:17"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 19,
|
||||
"pk": 25308865789,
|
||||
"model": "customercare.tweet",
|
||||
"fields": {
|
||||
"locale": "en",
|
||||
"tweet_id": 25308865789,
|
||||
"raw_json": "{\"iso_language_code\": \"en\", \"text\": \"Ok so it looks good in chrome, firefox and safari. \\nIt even seems to look ok in IE. (163 visitors to MDN using IE last month)\", \"created_at\": \"Thu, 23 Sep 2010 13:54:27 +0000\", \"profile_image_url\": \"http://a0.twimg.com/profile_images/533310872/twitterscotty_normal.jpg\", \"source\": \"<a href="http://kiwi-app.net" rel="nofollow">kiwi</a>\", \"from_user\": \"macdevnet\", \"from_user_id\": 28772, \"to_user_id\": null, \"geo\": null, \"id\": 25308865789, \"metadata\": {\"result_type\": \"recent\"}}",
|
||||
"reply_to": null,
|
||||
"created": "2010-09-23 13:54:27"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 15,
|
||||
"pk": 25308906635,
|
||||
"model": "customercare.tweet",
|
||||
"fields": {
|
||||
"locale": "en",
|
||||
"tweet_id": 25308906635,
|
||||
"raw_json": "{\"iso_language_code\": \"en\", \"text\": \"I'm still partial to Firefox, but IE9 Beta is FAST!\", \"created_at\": \"Thu, 23 Sep 2010 13:54:56 +0000\", \"profile_image_url\": \"http://a2.twimg.com/profile_images/1120347326/cole_normal.jpg\", \"source\": \"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>\", \"from_user\": \"Kid_Zer0\", \"from_user_id\": 130442244, \"to_user_id\": null, \"geo\": null, \"id\": 25308906635, \"metadata\": {\"result_type\": \"recent\"}}",
|
||||
"reply_to": null,
|
||||
"created": "2010-09-23 13:54:56"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 14,
|
||||
"pk": 25308913992,
|
||||
"model": "customercare.tweet",
|
||||
"fields": {
|
||||
"locale": "en",
|
||||
"tweet_id": 25308913992,
|
||||
"raw_json": "{\"iso_language_code\": \"en\", \"text\": \"Hey guys...am thinking of switching from IE to Firefox. yay or nay?\", \"created_at\": \"Thu, 23 Sep 2010 13:55:02 +0000\", \"profile_image_url\": \"http://a2.twimg.com/profile_images/151180126/Lucid_normal.jpg\", \"source\": \"<a href="http://twitter.com/">web</a>\", \"from_user\": \"LucidLilith\", \"from_user_id\": 1884444, \"to_user_id\": null, \"geo\": null, \"id\": 25308913992, \"metadata\": {\"result_type\": \"recent\"}}",
|
||||
"reply_to": null,
|
||||
"created": "2010-09-23 13:55:02"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 11,
|
||||
"pk": 25309157145,
|
||||
"model": "customercare.tweet",
|
||||
"fields": {
|
||||
"locale": "en",
|
||||
"tweet_id": 25309157145,
|
||||
"raw_json": "{\"iso_language_code\": \"en\", \"text\": \"Just changed my firefox theme for the first time in months and months. I like my new one :)\", \"created_at\": \"Thu, 23 Sep 2010 13:57:58 +0000\", \"profile_image_url\": \"http://a3.twimg.com/profile_images/1093204039/Me_and_claw_normal.jpg\", \"source\": \"<a href="http://twitter.com/">web</a>\", \"from_user\": \"jamesgrant17\", \"from_user_id\": 4403196, \"to_user_id\": null, \"geo\": null, \"id\": 25309157145, \"metadata\": {\"result_type\": \"recent\"}}",
|
||||
"reply_to": null,
|
||||
"created": "2010-09-23 13:57:58"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 101,
|
||||
"pk": 25309168529,
|
||||
"model": "customercare.tweet",
|
||||
"fields": {
|
||||
"locale": "ro",
|
||||
"tweet_id": 25309168529,
|
||||
"raw_json": "{\"iso_language_code\": \"en\", \"text\": \"Un tweet n romana #Firefox\", \"created_at\": \"Thu, 23 Sep 2010 13:58:06 +0000\", \"profile_image_url\": \"http://a1.twimg.com/profile_images/1117809237/cool_cat_normal.jpg\", \"source\": \"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>\", \"from_user\": \"__jimcasey__\", \"from_user_id\": 142651388, \"to_user_id\": null, \"geo\": null, \"id\": 25309168521, \"metadata\": {\"result_type\": \"recent\"}}",
|
||||
"reply_to": null,
|
||||
"created": "2010-09-23 13:58:06"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 102,
|
||||
"pk": 25309168528,
|
||||
"model": "customercare.tweet",
|
||||
"fields": {
|
||||
"locale": "ro",
|
||||
"tweet_id": 25309168528,
|
||||
"raw_json": "{\"iso_language_code\": \"en\", \"text\": \"Inca un tweet in Romana pentru Firefox!\", \"created_at\": \"Thu, 23 Sep 2010 13:54:56 +0000\", \"profile_image_url\": \"http://a2.twimg.com/profile_images/1120347326/cole_normal.jpg\", \"source\": \"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>\", \"from_user\": \"Kid_Zer0\", \"from_user_id\": 130442244, \"to_user_id\": null, \"geo\": null, \"id\": 25308906635, \"metadata\": {\"result_type\": \"recent\"}}",
|
||||
"reply_to": null,
|
||||
"created": "2010-09-24 14:58:06"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 10,
|
||||
"pk": 25309168521,
|
||||
"model": "customercare.tweet",
|
||||
"fields": {
|
||||
"locale": "en",
|
||||
"tweet_id": 25309168521,
|
||||
"raw_json": "{\"iso_language_code\": \"en\", \"text\": \"Looks like with #Firefox "Tabs on top" & "Hide Menubar" add-ons you can get same amount of browser space that you have in Chrome. Yay!\", \"created_at\": \"Thu, 23 Sep 2010 13:58:06 +0000\", \"profile_image_url\": \"http://a1.twimg.com/profile_images/1117809237/cool_cat_normal.jpg\", \"source\": \"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>\", \"from_user\": \"__jimcasey__\", \"from_user_id\": 142651388, \"to_user_id\": null, \"geo\": null, \"id\": 25309168521, \"metadata\": {\"result_type\": \"recent\"}}",
|
||||
"reply_to": null,
|
||||
"created": "2010-09-23 13:58:06"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 4,
|
||||
"pk": 25309381333,
|
||||
"model": "customercare.tweet",
|
||||
"fields": {
|
||||
"locale": "en",
|
||||
"tweet_id": 25309381333,
|
||||
"raw_json": "{\"iso_language_code\": \"en\", \"text\": \"On this day in 2002, first public version of Mozilla Firefox ('Phoenix 0.1') is released. Jose Canseco becomes first member of 40-40 club.\", \"created_at\": \"Thu, 23 Sep 2010 14:00:35 +0000\", \"profile_image_url\": \"http://a3.twimg.com/profile_images/407391555/643797910_fgRus-S_normal.jpg\", \"source\": \"<a href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a>\", \"from_user\": \"jasonboche\", \"from_user_id\": 1644275, \"to_user_id\": null, \"geo\": null, \"id\": 25309381333, \"metadata\": {\"result_type\": \"recent\"}}",
|
||||
"reply_to": null,
|
||||
"created": "2010-09-23 14:00:35"
|
||||
|
|
|
@ -8,13 +8,12 @@ from sumo.models import ModelBase, LocaleField
|
|||
|
||||
class Tweet(ModelBase):
|
||||
"""An entry on twitter."""
|
||||
tweet_id = models.BigIntegerField(unique=True)
|
||||
tweet_id = models.BigIntegerField(primary_key=True)
|
||||
raw_json = models.TextField()
|
||||
# This is different from our usual locale, so not using LocaleField.
|
||||
locale = models.CharField(max_length=20, db_index=True)
|
||||
created = models.DateTimeField(default=datetime.now, db_index=True)
|
||||
reply_to = models.BigIntegerField(blank=True, null=True, default=None,
|
||||
db_index=True)
|
||||
reply_to = models.ForeignKey('self', null=True, related_name='replies')
|
||||
hidden = models.BooleanField(default=False, db_index=True)
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -69,9 +69,9 @@ class GetOldestTweetTestCase(TestCase):
|
|||
fixtures = ['tweets.json']
|
||||
|
||||
def test_get_oldest_tweet_exists(self):
|
||||
eq_(11, _get_oldest_tweet('en', 2).pk)
|
||||
eq_(4, _get_oldest_tweet('en', 0).pk)
|
||||
eq_(21, _get_oldest_tweet('en', 6).pk)
|
||||
eq_(25309157145, _get_oldest_tweet('en', 2).pk)
|
||||
eq_(25309381333, _get_oldest_tweet('en', 0).pk)
|
||||
eq_(25308851981, _get_oldest_tweet('en', 6).pk)
|
||||
|
||||
def test_get_oldest_tweet_offset_too_big(self):
|
||||
eq_(None, _get_oldest_tweet('en', 100))
|
||||
|
|
|
@ -55,7 +55,7 @@ class TweetListTestCase(TestCase):
|
|||
def test_hide_tweets_with_replies(self):
|
||||
"""Hiding tweets with replies is not allowed."""
|
||||
tw = Tweet.objects.filter(reply_to=None)[0]
|
||||
tw.reply_to = 123
|
||||
tw.reply_to_id = 25309168529
|
||||
tw.save()
|
||||
|
||||
r = self.client.post(
|
||||
|
|
|
@ -37,18 +37,19 @@ def _tweet_for_template(tweet):
|
|||
|
||||
# Recursively fetch replies.
|
||||
if settings.CC_SHOW_REPLIES:
|
||||
replies = _get_tweets(limit=0, reply_to=tweet.tweet_id)
|
||||
# If ever slow, optimize to do fewer queries.
|
||||
replies = _get_tweets(limit=0, reply_to=tweet)
|
||||
else:
|
||||
replies = None
|
||||
|
||||
return {'profile_img': bleach.clean(data['profile_image_url']),
|
||||
'user': bleach.clean(data['from_user']),
|
||||
'text': bleach.clean(data['text']),
|
||||
'id': int(tweet.tweet_id),
|
||||
'id': tweet.pk,
|
||||
'date': date,
|
||||
'reply_count': len(replies) if replies else 0,
|
||||
'replies': replies,
|
||||
'reply_to': tweet.reply_to}
|
||||
'reply_to': tweet.reply_to and tweet.reply_to.pk}
|
||||
|
||||
|
||||
def _get_tweets(locale=settings.LANGUAGE_CODE,
|
||||
|
@ -138,7 +139,7 @@ def twitter_post(request):
|
|||
"""Post a tweet, and return a rendering of it (and any replies)."""
|
||||
|
||||
try:
|
||||
reply_to = int(request.POST.get('reply_to', ''))
|
||||
reply_to_id = int(request.POST.get('reply_to', ''))
|
||||
except ValueError:
|
||||
# L10n: the tweet needs to be a reply to another tweet.
|
||||
return HttpResponseBadRequest(_('Reply-to is empty'))
|
||||
|
@ -152,7 +153,7 @@ def twitter_post(request):
|
|||
return HttpResponseBadRequest(_('Message is too long'))
|
||||
|
||||
try:
|
||||
result = request.twitter.api.update_status(content, reply_to)
|
||||
result = request.twitter.api.update_status(content, reply_to_id)
|
||||
except tweepy.TweepError, e:
|
||||
# L10n: {message} is an error coming from our twitter api library
|
||||
return HttpResponseBadRequest(
|
||||
|
@ -176,16 +177,16 @@ def twitter_post(request):
|
|||
'from_user': author['screen_name'],
|
||||
'profile_image_url': author['profile_image_url'],
|
||||
}
|
||||
# Tweet metadata
|
||||
tweet_model_data = {
|
||||
'tweet_id': status['id'],
|
||||
'raw_json': json.dumps(raw_tweet_data),
|
||||
'locale': author['lang'],
|
||||
'created': status['created_at'],
|
||||
'reply_to': reply_to,
|
||||
}
|
||||
tweet = Tweet(**tweet_model_data)
|
||||
tweet.save()
|
||||
|
||||
# The tweet with id `reply_to_id` will not be missing from the DB unless
|
||||
# the purge cron job has run since the user loaded the form and we are
|
||||
# replying to a deleted tweet. TODO: Catch integrity error and log or
|
||||
# something.
|
||||
tweet = Tweet.objects.create(pk=status['id'],
|
||||
raw_json=json.dumps(raw_tweet_data),
|
||||
locale=author['lang'],
|
||||
created=status['created_at'],
|
||||
reply_to_id=reply_to_id)
|
||||
|
||||
# We could optimize by not encoding and then decoding JSON.
|
||||
return jingo.render(request, 'customercare/tweets.html',
|
||||
|
@ -210,11 +211,12 @@ def hide_tweet(request):
|
|||
return HttpResponseBadRequest(_('Invalid ID.'))
|
||||
|
||||
try:
|
||||
tweet = Tweet.objects.get(tweet_id=id)
|
||||
tweet = Tweet.objects.get(pk=id)
|
||||
except Tweet.DoesNotExist:
|
||||
return HttpResponseNotFound(_('Invalid ID.'))
|
||||
|
||||
if tweet.reply_to or Tweet.objects.filter(reply_to=id).count():
|
||||
if (tweet.reply_to is not None or
|
||||
Tweet.objects.filter(reply_to=tweet).exists()):
|
||||
return HttpResponseBadRequest(_('Tweets that are replies or have '
|
||||
'replies must not be hidden.'))
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче