review_utils.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import json
  2. from requests import get, put
  3. from gauth.auth_utils import get_gmb_id, get_auth_header
  4. from .models import Review, Reply
  5. from gauth.models import Location
  6. from django.utils import timezone
  7. STAR_REVIEW_NUM = {'STAR_RATING_UNSPECIFIED': 0, 'ONE': 1, 'TWO': 2, 'THREE': 3, 'FOUR': 4, 'FIVE': 5}
  8. def get_review_list_url(location_id, next_page_token=''):
  9. # An helper function that make a url that need to consume GMB review api
  10. _, account_id = get_gmb_id()
  11. return f'https://mybusiness.googleapis.com/v4/accounts/{account_id}/locations/{location_id}/reviews?pageToken='+next_page_token
  12. def get_reply_url(location_id, review_id):
  13. _, account_id = get_gmb_id()
  14. return f'https://mybusiness.googleapis.com/v4/accounts/{account_id}/locations/{location_id}/reviews/{review_id}/reply'
  15. def reply_review(review, replied_text):
  16. '''
  17. reply a review with a put request.
  18. :param review: review object -> a review which you want to reply.
  19. :param replied_text: string -> The actual reply that you want to post.
  20. :return:
  21. '''
  22. url = get_reply_url(review.location_id, review.review_id)
  23. headers = get_auth_header()
  24. payload = json.dumps({'comment': replied_text})
  25. response = put(url, headers=headers, data=payload)
  26. return response
  27. def insert_review_into_database(reviews, loc_id):
  28. '''
  29. Insert reviews to database.
  30. :param unrecorded_reviews: all reviews for location.
  31. :param loc: location that unrecorded_reviews belongs to.
  32. :return: It insert all reviews if it is not exits in database and return nothing.
  33. '''
  34. for rev in reviews:
  35. review_id = rev.get('reviewId')
  36. try:
  37. review = Review.objects.get(pk=review_id)
  38. except Review.DoesNotExist:
  39. review = Review(review_id=review_id)
  40. review.comment = rev.get('comment')
  41. review.create_time = rev.get('createTime')
  42. review.update_time = rev.get('updateTime')
  43. review.star_rating = STAR_REVIEW_NUM[rev.get('starRating')]
  44. reviewer = rev.get('reviewer')
  45. review.reviewer_name = reviewer.get('displayName')
  46. review.reviewer_photo = reviewer.get('profilePhotoUrl')
  47. review.location_id = loc_id
  48. review_reply = rev.get('reviewReply')
  49. # Check if it is already replied.
  50. if review_reply:
  51. replied_text = review_reply.get('comment')
  52. create_time = review_reply.get('updateTime')
  53. review.reply = Reply.objects.create(
  54. replied_text=replied_text,
  55. create_time=create_time
  56. )
  57. else:
  58. review.reply = None
  59. review.save()
  60. def sync_all_review(loc_id):
  61. '''
  62. Sync a location if any bad thing occur i.e. any network break.
  63. :param: loc_id -> Location id of a particular location
  64. :return: None -> It just update all reviews of this location and return nothing.
  65. '''
  66. next_page_token = ''
  67. headers = get_auth_header()
  68. while True:
  69. url = get_review_list_url(loc_id, next_page_token)
  70. res = get(url, headers=headers)
  71. if res.status_code == 401:
  72. headers = get_auth_header()
  73. continue
  74. data = res.json()
  75. reviews = data['reviews']
  76. if len(reviews) != 0:
  77. insert_review_into_database(reviews, loc_id)
  78. next_page_token = data.get('nextPageToken')
  79. if next_page_token is None:
  80. break
  81. average_rating = data.get('averageRating')
  82. total_reviews = data.get('totalReviewCount')
  83. total_reviews_db = Review.objects.filter(location_id=loc_id).count()
  84. update_location_data(loc_id, average_rating, total_reviews, total_reviews_db)
  85. def update_location_data(loc_id, average_rating, total_reviews, total_reviews_db):
  86. loc = Location.objects.get(pk=loc_id)
  87. loc.average_rating = average_rating
  88. loc.total_review = total_reviews
  89. loc.total_review_DB = total_reviews_db
  90. loc.save()
  91. def fetch_last_20_reviews(loc_id, page_size=20):
  92. headers = get_auth_header()
  93. url = get_review_list_url(loc_id)+'&pageSize='+str(page_size)
  94. res = get(url, headers=headers)
  95. data = res.json()
  96. reviews = data.get('reviews')
  97. average_rating = data.get('averageRating')
  98. total_reviews = data.get('totalReviewCount')
  99. if len(reviews) > 0:
  100. insert_review_into_database(reviews, loc_id)
  101. total_reviews_db = Review.objects.filter(location_id=loc_id).count()
  102. update_location_data(loc_id, average_rating, total_reviews, total_reviews_db)
  103. def populate_reviews():
  104. start = timezone.now()
  105. locations = Location.objects.all().values('location_id')
  106. for loc in locations:
  107. loc_id = loc.get('location_id')
  108. fetch_last_20_reviews(loc_id)
  109. end = timezone.now()
  110. elapsed = end - start
  111. print(f'Elapsed time: {elapsed.seconds//60} minutes and {elapsed.seconds % 60} secs.')
  112. def get_bad_reviews(location_id, **kwargs):
  113. '''
  114. a utility function that return all reviews has less or equal three.
  115. :param location_id: str -> id of the location where reviews are belongs to
  116. :param kwargs: i.e (days=__, hours=__, minutes=__)
  117. :return: QuerySet -> all low rating reviews in last * days/hours/minutes
  118. Example --------------
  119. >>> get_bad_reviews(location_id='123456', days=5, hours=2, minute=1)
  120. >>> get_bad_reviews(location_id='123456', days=5)
  121. >>> get_bad_reviews(location_id='123456', hours=5)
  122. '''
  123. now = timezone.now()
  124. date = now - timezone.timedelta(**kwargs)
  125. reviews = Review.objects.filter(location_id=location_id, update_time__gte=date, star_rating__lte=3)
  126. return reviews