views.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. import datetime
  2. import openpyxl
  3. from rest_framework import status
  4. from rest_framework.views import APIView
  5. from django.views.generic import TemplateView
  6. from rest_framework.response import Response
  7. from gauth.models import Location, LocationManager
  8. from django.http import Http404
  9. from django.shortcuts import render, redirect
  10. from django.views.generic import View
  11. from django.contrib import messages
  12. from user.forms import StaffRegistrationForm, StaffSheetDateForm, GoogleReviewsFilter, FacebookReviewsFilter
  13. from review.models import Review
  14. from yelp.models import YelpReview
  15. from facebook_app.models import FacebookReview
  16. from name_extractor.models import Staff
  17. from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
  18. from django.shortcuts import get_object_or_404
  19. from .analytics import weekly_positive_review_count, get_weeks, weekly_negative_review_count
  20. from name_extractor.utils import extract_names_from_reviews, make_all_staffs_point_zero
  21. from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
  22. from user.utils import (
  23. get_google_review_report,
  24. get_facebook_report,
  25. get_yelp_review_report,
  26. date_str2datetime
  27. )
  28. from .forms import ImportStaffSpreadSheet
  29. LOC_SYN = {
  30. 'cypress-1960': 'cypress',
  31. 'collegestation': 'college station'
  32. }
  33. class LocationListView(View, PermissionRequiredMixin):
  34. permission_required = 'is_staff'
  35. def post(self, request, *args, **kwargs):
  36. form = ImportStaffSpreadSheet(request.POST, request.FILES)
  37. if form.is_valid():
  38. staff_file = form.cleaned_data.get('staff_file')
  39. wb = openpyxl.load_workbook(staff_file)
  40. worksheet = wb.worksheets[0]
  41. rows = worksheet.values
  42. col_names = next(rows)
  43. try:
  44. name_idx, loc_idx, dept_idx = col_names.index('Name'), col_names.index('Location'), col_names.index('Job Title')
  45. except ValueError:
  46. messages.warning(request, "Columns in missing. Check columns ['Name', 'Location', 'Job Title'] again.")
  47. return redirect('location-list')
  48. # Clear all previously registered staffs
  49. staffs = Staff.objects.all()
  50. staffs.delete()
  51. for row in rows:
  52. try:
  53. name, loc, dept = row[name_idx], row[loc_idx], row[dept_idx]
  54. except IndexError:
  55. pass
  56. if loc.lower() in ['alllocations', '#n/a']:
  57. continue
  58. if loc.lower() in LOC_SYN.keys():
  59. loc = LOC_SYN[loc.lower()]
  60. location = Location.objects.filter(care_name__icontains=loc).first()
  61. if location:
  62. Staff.objects.create(
  63. name=name,
  64. location=location,
  65. department=dept
  66. )
  67. messages.success(request, 'Staff file upload successfully.')
  68. return redirect('location-list')
  69. def get(self, request, *args, **kwargs):
  70. locations = Location.objects.all()
  71. form = ImportStaffSpreadSheet()
  72. context = {
  73. 'all_locations': locations,
  74. 'file_upload_form': form
  75. }
  76. return render(request, 'locations.html', context=context)
  77. class LocationAnalytics(LoginRequiredMixin, View):
  78. def get(self, request, location_id, *args, **kwargs):
  79. location = Location.objects.get(pk=location_id)
  80. google_report = get_google_review_report(location_id)
  81. facebook_report = get_facebook_report(location_id)
  82. yelp_report = get_yelp_review_report(location_id)
  83. context = {
  84. 'location': location,
  85. 'google_this_month_pos': google_report.get('this_month_pos'),
  86. 'google_last_month_pos': google_report.get('last_month_pos'),
  87. 'facebook_this_month_pos': facebook_report.get('this_month_pos'),
  88. 'facebook_last_month_pos': facebook_report.get('last_month_pos'),
  89. 'google_this_month_neg': google_report.get('this_month_neg'),
  90. 'google_last_month_neg': google_report.get('last_month_neg'),
  91. 'facebook_this_month_neg': facebook_report.get('this_month_neg'),
  92. 'facebook_last_month_neg': facebook_report.get('last_month_neg'),
  93. 'yelp': yelp_report
  94. }
  95. return render(request, 'manager-dashboard.html', context=context)
  96. class ReviewListLocationWise(View):
  97. def get(self, request, platform, location_id, *args, **kwargs):
  98. location = Location.objects.get(pk=location_id)
  99. if platform == 'google':
  100. form = GoogleReviewsFilter()
  101. reviews = Review.objects.filter(location_id=location_id).order_by('-update_time')
  102. elif platform == 'facebook':
  103. form = FacebookReviewsFilter()
  104. reviews = FacebookReview.objects.filter(page__location_id=location_id).order_by('-create_time')
  105. elif platform == 'yelp':
  106. form = GoogleReviewsFilter()
  107. reviews = YelpReview.objects.filter(location__location_id=location_id).order_by('-date_posted')
  108. else:
  109. raise Http404()
  110. page = request.GET.get('page', 1)
  111. paginator = Paginator(reviews, 50)
  112. try:
  113. reviews = paginator.page(page)
  114. except PageNotAnInteger:
  115. reviews = paginator.page(1)
  116. except EmptyPage:
  117. reviews = paginator.page(paginator.num_pages)
  118. context = {'reviews': reviews, 'platform': platform, 'location': location, 'form': form}
  119. return render(request, 'review-list-man.html', context=context)
  120. def post(self, request, platform, location_id, *args, **kwargs):
  121. location = Location.objects.get(pk=location_id)
  122. if platform == 'google':
  123. form = GoogleReviewsFilter(data=request.POST)
  124. start_date = date_str2datetime(request.POST.get('start_date'))
  125. end_date = date_str2datetime(request.POST.get('end_date'))
  126. if end_date < start_date:
  127. start_date, end_date = end_date, start_date
  128. star_rating = int(request.POST.get('star_ratings'))
  129. reviews = Review.objects.filter(location_id=location_id).order_by('-update_time')
  130. if start_date and end_date:
  131. if star_rating > 5:
  132. reviews = reviews.filter(create_time__range=(start_date, end_date))
  133. else:
  134. reviews = reviews.filter(create_time__range=(start_date, end_date), star_rating=star_rating)
  135. elif platform == 'yelp':
  136. form = GoogleReviewsFilter(data=request.POST)
  137. start_date = date_str2datetime(request.POST.get('start_date'))
  138. end_date = date_str2datetime(request.POST.get('end_date'))
  139. if end_date < start_date:
  140. start_date, end_date = end_date, start_date
  141. star_rating = int(request.POST.get('star_ratings'))
  142. reviews = YelpReview.objects.filter(location__location_id=location_id).order_by('-date_posted')
  143. if start_date and end_date:
  144. if star_rating > 5:
  145. reviews = reviews.filter(date_posted__range=(start_date, end_date))
  146. else:
  147. reviews = reviews.filter(date_posted__range=(start_date, end_date), rating=star_rating)
  148. elif platform == 'facebook':
  149. form = FacebookReviewsFilter(request.POST)
  150. start_date = date_str2datetime(request.POST.get('start_date'))
  151. end_date = date_str2datetime(request.POST.get('end_date'))
  152. star_rating = int(request.POST.get('star_ratings'))
  153. reviews = FacebookReview.objects.filter(page__location_id=location_id).order_by('-create_time')
  154. if start_date and end_date:
  155. if star_rating > 5:
  156. reviews = reviews.filter(create_time__range=(start_date, end_date))
  157. else:
  158. reviews = reviews.filter(create_time__range=(start_date, end_date), recommendation_type=bool(star_rating))
  159. else:
  160. raise Http404()
  161. page = request.GET.get('page', 1)
  162. paginator = Paginator(reviews, 50)
  163. try:
  164. reviews = paginator.page(page)
  165. except PageNotAnInteger:
  166. reviews = paginator.page(1)
  167. except EmptyPage:
  168. reviews = paginator.page(paginator.num_pages)
  169. context = {'reviews': reviews, 'platform': platform, 'location': location, 'form': form}
  170. return render(request, 'review-list-man.html', context=context)
  171. class ReviewAnalyticsGraph(View):
  172. def get(self, request, location_id, *args, **kwargs):
  173. location = Location.objects.get(pk=location_id)
  174. return render(request, 'location-wise-reviews-man.html', context={'location': location})
  175. class StaffLeaderBoard(View):
  176. def get(self, request, location_id, *args, **kwargs):
  177. location = Location.objects.get(pk=location_id)
  178. staffs = Staff.objects.filter(location=location).order_by('-total_units')
  179. form = StaffRegistrationForm()
  180. date_form = StaffSheetDateForm()
  181. context = {
  182. 'location': location,
  183. 'staffs': staffs,
  184. 'date_form': date_form,
  185. 'form': form
  186. }
  187. return render(request, 'staff_list_man.html', context)
  188. def post(self, request, location_id, *args, **kwargs):
  189. form = StaffRegistrationForm(request.POST)
  190. if form.is_valid():
  191. name = form.cleaned_data.get('name')
  192. department = form.cleaned_data.get('department')
  193. nick_names = form.cleaned_data.get('nick_names')
  194. staff = Staff.objects.create(
  195. name=name,
  196. location_id=location_id,
  197. department=department,
  198. nick_names=nick_names
  199. )
  200. messages.success(request, f'A new staff {staff} has been created!')
  201. return redirect('staff-leaderboard-man', location_id=location_id)
  202. class SyncStaffLeaderBoard(View):
  203. def post(self, request, location_id, *args, **kwargs):
  204. start_date = date_str2datetime(request.POST.get('start_date'))
  205. end_date = date_str2datetime(request.POST.get('end_date'))
  206. extract_names_from_reviews(
  207. start_date=start_date,
  208. end_date=end_date,
  209. location_id=location_id
  210. )
  211. return redirect('staff-leaderboard-man', location_id=location_id)
  212. class StaffDelete(View):
  213. def get(self, request, staff_id, *args, **kwargs):
  214. staff = get_object_or_404(Staff, id=staff_id)
  215. staff.delete()
  216. return redirect('staff-leaderboard-man', location_id=staff.location_id)
  217. class AllLocationSummary(APIView):
  218. def get(self, request, *args, **kwargs):
  219. days = request.GET['days']
  220. if not days:
  221. return Response({'error': 'No location Found'}, status=status.HTTP_400_BAD_REQUEST)
  222. locations = Location.objects.all()
  223. review_counts = []
  224. for location in locations:
  225. loc_json = {
  226. 'name': location.care_name,
  227. 'positive': [
  228. location.last_week_pos_google_review_count,
  229. location.last_week_pos_facebook_review_count,
  230. location.last_week_pos_yelp_review_count
  231. ],
  232. 'negative': [
  233. location.last_week_neg_google_review_count,
  234. location.last_week_neg_facebook_review_count,
  235. location.last_week_neg_yelp_review_count
  236. ]
  237. }
  238. review_counts.append(loc_json)
  239. response = {
  240. 'labels': ['Google', 'Facebook', 'Yelp'],
  241. 'review_counts': review_counts,
  242. }
  243. return Response(response)
  244. class ReviewAnalysis(APIView):
  245. def get(self, request, *args, **kwargs):
  246. now = datetime.datetime.now()
  247. pos_ratings, labels = weekly_positive_review_count()
  248. neg_ratings = weekly_negative_review_count()
  249. weeks = get_weeks(now.year, now.isocalendar()[1])
  250. weeks = [datetime.date.fromisocalendar(w[1], w[0], 7) for w in weeks]
  251. response = {
  252. "weeks": weeks,
  253. "pos_data": pos_ratings,
  254. "neg_data": neg_ratings,
  255. "labels": labels
  256. }
  257. return Response(response)
  258. class ReviewAnalysisAllPlatformView(LoginRequiredMixin, TemplateView):
  259. template_name = 'review-analysis.html'