123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- import json
- from requests import get, put
- from gauth.auth_utils import get_gmb_id, get_auth_header
- from gauth.location_utils import get_all_location_ids
- # from django.db.models import Max
- from .models import Review, Reply
- from gauth.models import Location
- from django.utils import timezone
- STAR_REVIEW_NUM = {'STAR_RATING_UNSPECIFIED': 0, 'ONE': 1, 'TWO': 2, 'THREE': 3, 'FOUR': 4, 'FIVE': 5}
- def get_review_list_url(location_id, next_page_token=''):
- # An helper function that make a url that need to consume GMB review api
- _, account_id = get_gmb_id()
- return f'https://mybusiness.googleapis.com/v4/accounts/{account_id}/locations/{location_id}/reviews?pageToken='+next_page_token
- def get_reply_url(location_id, review_id):
- _, account_id = get_gmb_id()
- return f'https://mybusiness.googleapis.com/v4/accounts/{account_id}/locations/{location_id}/reviews/{review_id}/reply'
- def reply_review(review, replied_text):
- '''
- reply a review with a put request.
- :param review: review object -> a review which you want to reply.
- :param replied_text: string -> The actual reply that you want to post.
- :return:
- '''
- url = get_reply_url(review.location_id, review.review_id)
- headers = get_auth_header()
- payload = json.dumps({'comment': replied_text})
- response = put(url, headers=headers, data=payload)
- return response
- # def get_max_date(loc_id):
- # '''
- # find the maximum date of any particular location. the latest date
- # :param loc_id: Integer -> Globally unique ID for google my business locations.
- # :return: DateTime Obj -> The latest reviews date of that location.
- # '''
- # # Function that takes a location id and return the latest updated review.
- # largest = Review.objects.filter(location_id=loc_id).aggregate(Max('create_time'))['create_time__max']
- # max_date = largest if largest else '1970-01-11 17:41:17.532740'
- # return max_date
- # def filter_unrecorded_review_by_date(reviews, max_date):
- # # A function that return only those reviews whose has larger value than
- # # the max create_time value in review database.
- # filtered_reviews = []
- # for rev in reviews:
- # if rev['createTime'] >= str(max_date):
- # filtered_reviews.append(rev)
- # return filtered_reviews
- # def insert_review_into_database(reviews, loc):
- # '''
- # Insert reviews to database.
- # :param unrecorded_reviews: all reviews for location.
- # :param loc: location that unrecorded_reviews belongs to.
- # :return: It insert all reviews if it is not exits in database and return nothing.
- # '''
- # for review in reviews:
- # review_id = review.get('reviewId')
- # # Check the review already exists in database then We don't need to store again.
- # rev = Review.objects.filter(pk=review_id).first()
- # if rev:
- # continue
- # comment = review.get('comment')
- # create_time = review.get('createTime')
- # update_time = review.get('updateTime')
- # star_rating = STAR_REVIEW_NUM[review.get('starRating')]
- # reviewer = review.get('reviewer')
- # reviewer_name = reviewer.get('displayName')
- # reviewer_photo = reviewer.get('profilePhotoUrl')
- # review_reply = review.get('reviewReply')
- # # Check if it is already replied.
- # if review_reply:
- # replied_text = review_reply.get('comment')
- # create_time = review_reply.get('updateTime')
- # reply = Reply.objects.create(replied_text=replied_text, create_time=create_time)
- # else:
- # reply = None
- # review = Review(
- # review_id=review_id,
- # comment=comment,
- # create_time=create_time,
- # update_time=update_time,
- # star_rating=star_rating,
- # reviewer_name=reviewer_name,
- # reviewer_photo=reviewer_photo,
- # location=loc,
- # reply=reply
- # )
- # review.save()
- def insert_review_into_database(reviews, loc_id):
- '''
- Insert reviews to database.
- :param unrecorded_reviews: all reviews for location.
- :param loc: location that unrecorded_reviews belongs to.
- :return: It insert all reviews if it is not exits in database and return nothing.
- '''
- for rev in reviews:
- review_id = rev.get('reviewId')
- try:
- review = Review.objects.get(pk=review_id)
- except Review.DoesNotExist:
- review = Review(review_id=review_id)
- review.comment = rev.get('comment')
- review.create_time = rev.get('createTime')
- review.update_time = rev.get('updateTime')
- review.star_rating = STAR_REVIEW_NUM[rev.get('starRating')]
- reviewer = rev.get('reviewer')
- review.reviewer_name = reviewer.get('displayName')
- review.reviewer_photo = reviewer.get('profilePhotoUrl')
- review.location_id = loc_id
- review_reply = rev.get('reviewReply')
- # Check if it is already replied.
- if review_reply:
- replied_text = review_reply.get('comment')
- create_time = review_reply.get('updateTime')
- review.reply = Reply.objects.create(
- replied_text=replied_text,
- create_time=create_time
- )
- else:
- review.reply = None
- review.save()
- def sync_all_review(loc_id):
- '''
- Sync a location if any bad thing occur i.e. any network break.
- :param: loc_id -> Location id of a particular location
- :return: None -> It just update all reviews of this location and return nothing.
- '''
- loc = Location.objects.get(pk=loc_id)
- next_page_token = ''
- headers = get_auth_header()
- while True:
- url = get_review_list_url(loc_id, next_page_token)
- res = get(url, headers=headers)
- if res.status_code == 401:
- headers = get_auth_header()
- continue
- data = res.json()
- reviews = data['reviews']
- if len(reviews) != 0:
- insert_review_into_database(reviews, loc)
- next_page_token = data.get('nextPageToken')
- if next_page_token is None:
- break
- average_rating = data.get('averageRating')
- total_reviews = data.get('totalReviewCount')
- total_reviews_db = Review.objects.filter(location_id=loc_id).count()
- update_location_data(loc_id, average_rating, total_reviews, total_reviews_db)
- def update_location_data(loc_id, average_rating, total_reviews, total_reviews_db):
- loc = Location.objects.get(pk=loc_id)
- loc.average_rating = average_rating
- loc.total_review = total_reviews
- loc.total_review_DB = total_reviews_db
- loc.save()
- # def fetch_all_review(loc_id):
- # loc = Location.objects.get(pk=loc_id)
- # max_date = get_max_date(loc_id)
- # headers = get_auth_header()
- # url = get_review_list_url(loc_id)
- # res = get(url, headers=headers)
- # if res.status_code == 401:
- # return
- # data = res.json()
- # reviews = data['reviews']
- # average_rating = data.get('averageRating')
- # total_reviews = data.get('totalReviewCount')
- # unrecorded_reviews = filter_unrecorded_review_by_date(reviews, max_date)
- # if len(unrecorded_reviews) != 0:
- # insert_review_into_database(unrecorded_reviews, loc)
- # total_reviews_db = Review.objects.filter(location_id=loc_id).count()
- # update_location_data(loc, average_rating, total_reviews, total_reviews_db)
- def fetch_last_20_reviews(loc_id):
- headers = get_auth_header()
- url = get_review_list_url(loc_id)+'&pageSize=100'
- res = get(url, headers=headers)
- data = res.json()
- reviews = data['reviews']
- average_rating = data.get('averageRating')
- total_reviews = data.get('totalReviewCount')
- if len(reviews) > 0:
- insert_review_into_database(reviews, loc_id)
- total_reviews_db = Review.objects.filter(location_id=loc_id).count()
- update_location_data(loc_id, average_rating, total_reviews, total_reviews_db)
- def populate_reviews():
- start = timezone.now()
- locations = get_all_location_ids()
- for loc_id in locations:
- fetch_last_20_reviews(loc_id)
- end = timezone.now()
- elapsed = end - start
- print(f'Elapsed time: {elapsed.seconds//60} minutes and {elapsed.seconds % 60} secs.')
- def get_bad_reviews(location_id, **kwargs):
- '''
- a utility function that return all reviews has less or equal three.
- :param location_id: str -> id of the location where reviews are belongs to
- :param kwargs: i.e (days=__, hours=__, minutes=__)
- :return: QuerySet -> all low rating reviews in last * days/hours/minutes
- Example --------------
- >>> get_bad_reviews(location_id='123456', days=5, hours=2, minute=1)
- >>> get_bad_reviews(location_id='123456', days=5)
- >>> get_bad_reviews(location_id='123456', hours=5)
- '''
- now = timezone.now()
- date = now - timezone.timedelta(**kwargs)
- reviews = Review.objects.filter(location_id=location_id, update_time__gte=date, star_rating__lte=3)
- return reviews
|