Преглед изворни кода

Merge branch 'ercare-v1' into 'master'

Ercare v1

See merge request ByteTrek-Projects/review-automation-backend!1
Mohidul Islam пре 5 година
родитељ
комит
56ef6c058d

+ 9 - 3
gauth/admin.py

@@ -1,9 +1,15 @@
 from django.contrib import admin
-from .models import UserModel
+from .models import UserModel, Location
 
 
 class UserModelAdmin(admin.ModelAdmin):
-    list_display = ['user', 'refresh_token']
+    list_display = ['user', 'refresh_token', 'gmb_account_id']
 
 
-admin.site.register(UserModel, UserModelAdmin)
+class LocationsAdmin(admin.ModelAdmin):
+    list_display = ['location_id', 'location_name', 'website_url', 'display_name']
+
+
+admin.site.register(Location, LocationsAdmin)
+
+admin.site.register(UserModel, UserModelAdmin)

+ 32 - 8
gauth/utils.py → gauth/auth_utils.py

@@ -1,7 +1,9 @@
+from django.contrib.auth.models import User
 from django.utils import timezone
 from requests import post
 from django.conf import settings
 from .models import UserModel
+from requests import get
 
 
 def has_expired(credentials):
@@ -11,7 +13,24 @@ def has_expired(credentials):
 
 
 def get_access_token(request):
-    uid = request.user.id
+    if 'credentials' in request.session and not has_expired(request.session['credentials']):
+        cred = request.session['credentials']
+        return cred['access_token']
+
+    access_token, expires_in = refresh_access_token()
+    expired_at = timezone.datetime.now() + timezone.timedelta(seconds=expires_in)
+    expiry = str(expired_at)
+    credentials = {
+        'access_token': access_token,
+        'expiry': expiry
+    }
+    request.session['credentials'] = credentials
+    return credentials['access_token']
+
+
+def refresh_access_token():
+    user = User.objects.filter(username='admin@ercare').first()
+    uid = user.id
     user = UserModel.objects.filter(pk=uid).first()
     if user:
         refresh_token = user.refresh_token
@@ -31,11 +50,16 @@ def get_access_token(request):
     response = post(token_uri, data=params).json()
     access_token = response['access_token']
     expires_in = response['expires_in']
-    expired_at = timezone.datetime.now() + timezone.timedelta(seconds=expires_in)
-    expiry = str(expired_at)
-    credentials = {
-        'access_token': access_token,
-        'expiry': expiry
+    return access_token, expires_in
+
+
+def get_google_account_id(access_token):
+    uri = 'https://mybusiness.googleapis.com/v4/accounts'
+    headers = {
+        'authorization': 'Bearer '+access_token,
+        'content-type': 'application/json'
     }
-    request.session['credentials'] = credentials
-    return response['access_token']
+    res = get(uri, headers=headers).json()
+    accounts_name = res['accounts'][0]['name']
+    id = accounts_name.split('/')[-1]
+    return id

+ 39 - 0
gauth/location_utils.py

@@ -0,0 +1,39 @@
+from django.contrib.auth.models import User
+from requests import get
+from .auth_utils import refresh_access_token
+from .models import UserModel, Location
+
+
+def get_all_location_ids():
+    locations = Location.objects.only('location_id')
+    ids = [loc.location_id for loc in locations]
+    '''
+    There is a location which we don't need to add into database.
+    It is a Medical Billing Service, That's why it is nothing to do with review. 
+    '''
+    ids.remove('5397588228065547694')
+    return ids
+
+
+def populate_locations():
+    access_token, _ = refresh_access_token()
+    user = User.objects.get(username='admin@ercare')
+    gmb_id = UserModel.objects.get(user=user).gmb_account_id
+    url = 'https://mybusiness.googleapis.com/v4/accounts/' + gmb_id + '/locations'
+    headers = {
+        'authorization': 'Bearer ' + access_token,
+        'content-type': 'application/json'
+    }
+    res = get(url, headers=headers).json()
+    locations = res['locations']
+    for loc in locations:
+        # loc['name'] = 'accounts/103266181421855655295/locations/8916258876770296726'
+        loc_id = loc['name'].split('/')[-1]
+        location_ids = get_all_location_ids()
+        if loc_id in location_ids:
+            continue
+        loc_name = loc['locationName']
+        loc_website = loc['websiteUrl']
+        loc_display = loc['primaryCategory']['displayName']
+        location = Location.objects.create(location_id=loc_id, location_name=loc_name, website_url=loc_website, display_name=loc_display, owner=user)
+        location.save()

+ 2 - 1
gauth/migrations/0001_initial.py

@@ -1,4 +1,4 @@
-# Generated by Django 3.0 on 2019-12-12 09:13
+# Generated by Django 3.0 on 2019-12-26 13:17
 
 from django.conf import settings
 from django.db import migrations, models
@@ -19,6 +19,7 @@ class Migration(migrations.Migration):
             fields=[
                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                 ('refresh_token', models.CharField(max_length=30)),
+                ('gmb_account_id', models.CharField(max_length=30)),
                 ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='token_of', to=settings.AUTH_USER_MODEL)),
             ],
         ),

+ 23 - 0
gauth/migrations/0002_auto_20191229_0659.py

@@ -0,0 +1,23 @@
+# Generated by Django 3.0 on 2019-12-29 06:59
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('gauth', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='usermodel',
+            name='gmb_account_id',
+            field=models.CharField(blank=True, max_length=30, null=True),
+        ),
+        migrations.AlterField(
+            model_name='usermodel',
+            name='refresh_token',
+            field=models.CharField(blank=True, max_length=30, null=True),
+        ),
+    ]

+ 27 - 0
gauth/migrations/0003_location.py

@@ -0,0 +1,27 @@
+# Generated by Django 3.0 on 2019-12-29 09:56
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('gauth', '0002_auto_20191229_0659'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Location',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('location_id', models.CharField(max_length=50)),
+                ('location_name', models.CharField(max_length=50)),
+                ('website_url', models.URLField()),
+                ('display_name', models.CharField(max_length=50)),
+                ('owner', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+            ],
+        ),
+    ]

+ 18 - 0
gauth/migrations/0004_auto_20191229_1033.py

@@ -0,0 +1,18 @@
+# Generated by Django 3.0 on 2019-12-29 10:33
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('gauth', '0003_location'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='location',
+            name='location_id',
+            field=models.CharField(max_length=50, unique=True),
+        ),
+    ]

+ 14 - 1
gauth/models.py

@@ -4,7 +4,20 @@ from django.contrib.auth.models import User
 
 class UserModel(models.Model):
     user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='token_of')
-    refresh_token = models.CharField(max_length=30)
+    refresh_token = models.CharField(max_length=30, null=True, blank=True)
+    gmb_account_id = models.CharField(max_length=30, null=True, blank=True)
 
     def __str__(self):
         return self.user.username
+
+
+class Location(models.Model):
+    location_id = models.CharField(max_length=50, unique=True)
+    location_name = models.CharField(max_length=50)
+    website_url = models.URLField()
+    display_name = models.CharField(max_length=50)
+    owner = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
+
+    def __str__(self):
+        return self.display_name
+

+ 3 - 2
gauth/urls.py

@@ -1,8 +1,9 @@
 from django.urls import path
-from .views import index, authorize, oauth2callback
+from .views import google_auth, authorize, oauth2callback, index
 
 urlpatterns = [
     path('', index, name='home'),
-    path('authorize/', authorize, name='authorize'),
+    path('gmb-authenticate/', google_auth, name='gmb-auth'),
+    path('authorize', authorize, name='authorize'),
     path('oauth2callback', oauth2callback, name='oauth2callback'),
 ]

+ 22 - 17
gauth/views.py

@@ -3,25 +3,13 @@ from django.shortcuts import redirect
 from django.urls import reverse
 import google_auth_oauthlib.flow
 from django.contrib.auth.decorators import login_required
+from django.contrib.auth.models import User
 
-from .utils import get_access_token, has_expired
+from .auth_utils import get_access_token, get_google_account_id
 
 from .models import UserModel
 
 
-@login_required
-def index(request):
-    uid = request.user.id
-    user = UserModel.objects.filter(pk=uid).first()
-    if not user:
-        return redirect(reverse('authorize'))
-    if 'credentials' not in request.session or has_expired(request.session['credentials']):
-        get_access_token(request)
-    cred = request.session['credentials']
-
-    return HttpResponse(cred['access_token'])
-
-
 CLIENT_SECRETS_FILE = "client_secrets.json"
 SCOPES = ['https://www.googleapis.com/auth/business.manage']
 flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
@@ -30,6 +18,20 @@ flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
         redirect_uri="http://127.0.0.1:8000/oauth2callback")
 
 
+def index(request):
+    get_access_token(request)
+    cred = request.session['credentials']
+    return HttpResponse(cred['access_token'])
+
+
+@login_required
+def google_auth(request):
+    user = User.objects.filter(username='admin@ercare').first()
+    if not user:
+        return HttpResponse('<h1>You have to have a user account with username "admin@ercare". Please create a superuser using manage.py createsuperuser</h2>')
+    return redirect(reverse('authorize'))
+
+
 def authorize(request):
     authorization_url, state = flow.authorization_url(access_type='offline')
 
@@ -47,10 +49,13 @@ def oauth2callback(request):
     flow.fetch_token(code=code)
 
     credentials = flow.credentials
-    request.session['credentials'] = credentials_to_dict(credentials)
-    refresh_token = credentials.refresh_token
-    user_model = UserModel.objects.create(user=request.user, refresh_token=refresh_token)
+    account_id = get_google_account_id(credentials.token)
+    user = User.objects.filter(username='admin@ercare').first()
+    user_model, created = UserModel.objects.get_or_create(user=user)
+    user_model.refresh_token = credentials.refresh_token
+    user_model.gmb_account_id = account_id
     user_model.save()
+    request.session['credentials'] = credentials_to_dict(credentials)
     return redirect(reverse('home'))
 
 

+ 0 - 0
review/__init__.py


+ 3 - 0
review/admin.py

@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.

+ 5 - 0
review/apps.py

@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class ReviewConfig(AppConfig):
+    name = 'review'

+ 48 - 0
review/migrations/0001_initial.py

@@ -0,0 +1,48 @@
+# Generated by Django 3.0 on 2019-12-26 13:12
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Location',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('location_id', models.CharField(max_length=50)),
+                ('location_name', models.CharField(max_length=50)),
+                ('website_url', models.URLField()),
+                ('display_name', models.CharField(max_length=50)),
+            ],
+        ),
+        migrations.CreateModel(
+            name='Reply',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('replied_text', models.CharField(max_length=500)),
+                ('create_time', models.DateTimeField()),
+            ],
+        ),
+        migrations.CreateModel(
+            name='Review',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('review_id', models.CharField(max_length=50)),
+                ('comment', models.CharField(max_length=1000)),
+                ('create_time', models.DateTimeField()),
+                ('update_time', models.DateTimeField()),
+                ('star_rating', models.IntegerField()),
+                ('reviewer_name', models.CharField(max_length=50)),
+                ('reviewer_photo', models.URLField()),
+                ('location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='review.Location')),
+                ('reply', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='review.Reply')),
+            ],
+        ),
+    ]

+ 26 - 0
review/migrations/0002_auto_20191229_0603.py

@@ -0,0 +1,26 @@
+# Generated by Django 3.0 on 2019-12-29 06:03
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('review', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='location',
+            name='owner',
+            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
+        ),
+        migrations.AlterField(
+            model_name='review',
+            name='location',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='review.Location'),
+        ),
+    ]

+ 23 - 0
review/migrations/0003_auto_20191229_0956.py

@@ -0,0 +1,23 @@
+# Generated by Django 3.0 on 2019-12-29 09:56
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('gauth', '0003_location'),
+        ('review', '0002_auto_20191229_0603'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='review',
+            name='location',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='gauth.Location'),
+        ),
+        migrations.DeleteModel(
+            name='Location',
+        ),
+    ]

+ 0 - 0
review/migrations/__init__.py


+ 26 - 0
review/models.py

@@ -0,0 +1,26 @@
+from django.db import models
+from django.contrib.auth.models import User
+from gauth.models import Location
+
+
+class Reply(models.Model):
+    replied_text = models.CharField(max_length=500)
+    create_time = models.DateTimeField()
+
+    def __str__(self):
+        return self.replied_text
+
+
+class Review(models.Model):
+    review_id = models.CharField(max_length=50)
+    comment = models.CharField(max_length=1000)
+    create_time = models.DateTimeField()
+    update_time = models.DateTimeField()
+    star_rating = models.IntegerField()
+    reviewer_name = models.CharField(max_length=50)
+    reviewer_photo = models.URLField()
+    location = models.ForeignKey(Location, on_delete=models.DO_NOTHING)
+    reply = models.OneToOneField(Reply, on_delete=models.CASCADE)
+
+    def __str__(self):
+        return f'{self.reviewer_name} - {self.comment}'

+ 3 - 0
review/tests.py

@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.

+ 3 - 0
review/views.py

@@ -0,0 +1,3 @@
+from django.shortcuts import render
+
+# Create your views here.

+ 1 - 0
review_automation/settings.py

@@ -24,6 +24,7 @@ INSTALLED_APPS = [
     'django.contrib.staticfiles',
 
     'gauth.apps.GauthConfig',
+    'review.apps.ReviewConfig',
 ]
 
 MIDDLEWARE = [