diff --git a/backend/zetikettes/manage.py b/backend/zetikettes/manage.py index e3c2db6..dbc7276 100755 --- a/backend/zetikettes/manage.py +++ b/backend/zetikettes/manage.py @@ -6,7 +6,7 @@ import sys def main(): """Run administrative tasks.""" - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'zetikettes.settings') + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "zetikettes.settings") try: from django.core.management import execute_from_command_line except ImportError as exc: @@ -18,5 +18,5 @@ def main(): execute_from_command_line(sys.argv) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/backend/zetikettes/tikette/apps.py b/backend/zetikettes/tikette/apps.py index 6676943..84db62d 100644 --- a/backend/zetikettes/tikette/apps.py +++ b/backend/zetikettes/tikette/apps.py @@ -2,5 +2,5 @@ from django.apps import AppConfig class TiketteConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'tikette' + default_auto_field = "django.db.models.BigAutoField" + name = "tikette" diff --git a/backend/zetikettes/tikette/middleware.py b/backend/zetikettes/tikette/middleware.py index fd0a7e0..2e081a7 100644 --- a/backend/zetikettes/tikette/middleware.py +++ b/backend/zetikettes/tikette/middleware.py @@ -1,9 +1,10 @@ +from django.core.exceptions import PermissionDenied from django.http import HttpResponse def cors_everywhere(get_response): def middleware(request): - if request.method == 'OPTIONS': + if request.method == "OPTIONS": response = HttpResponse() else: response = get_response(request) diff --git a/backend/zetikettes/tikette/migrations/0001_initial.py b/backend/zetikettes/tikette/migrations/0001_initial.py index e3c7914..38e16c5 100644 --- a/backend/zetikettes/tikette/migrations/0001_initial.py +++ b/backend/zetikettes/tikette/migrations/0001_initial.py @@ -8,64 +8,120 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='Tikategory', + name="Tikategory", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=50)), - ('landscape', models.BooleanField()), - ('prototempalte', models.FileField(upload_to='')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=50)), + ("landscape", models.BooleanField()), + ("prototempalte", models.FileField(upload_to="")), ], options={ - 'verbose_name_plural': 'tikategoriez', + "verbose_name_plural": "tikategoriez", }, ), migrations.CreateModel( - name='Tisub', + name="Tisub", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=50)), - ('descritpion', models.TextField()), - ('default', models.TextField()), - ('type', models.CharField(choices=[('ST', 'Short Text'), ('LT', 'Long Text'), ('C', 'Color'), ('YM', 'Year Month'), ('B', 'Boolean')], default='ST', max_length=2)), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=50)), + ("descritpion", models.TextField()), + ("default", models.TextField()), + ( + "type", + models.CharField( + choices=[ + ("ST", "Short Text"), + ("LT", "Long Text"), + ("C", "Color"), + ("YM", "Year Month"), + ("B", "Boolean"), + ], + default="ST", + max_length=2, + ), + ), ], options={ - 'verbose_name_plural': 'tisubz', + "verbose_name_plural": "tisubz", }, ), migrations.CreateModel( - name='Tizer', + name="Tizer", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('email', models.CharField()), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("email", models.CharField()), ], options={ - 'verbose_name_plural': 'tizerz', + "verbose_name_plural": "tizerz", }, ), migrations.CreateModel( - name='Tikette', + name="Tikette", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(max_length=100)), - ('designation', models.CharField(max_length=100)), - ('ingredients', models.TextField()), - ('description', models.TextField()), - ('color', models.CharField(max_length=6)), - ('ab', models.CharField(choices=[('inline', 'Visible'), ('none', 'Invisible')], max_length=7)), - ('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tikette.tikategory')), + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("title", models.CharField(max_length=100)), + ("designation", models.CharField(max_length=100)), + ("ingredients", models.TextField()), + ("description", models.TextField()), + ("color", models.CharField(max_length=6)), + ( + "ab", + models.CharField( + choices=[("inline", "Visible"), ("none", "Invisible")], + max_length=7, + ), + ), + ( + "category", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="tikette.tikategory", + ), + ), ], options={ - 'verbose_name_plural': 'tikettz', + "verbose_name_plural": "tikettz", }, ), migrations.AddField( - model_name='tikategory', - name='subs', - field=models.ManyToManyField(to='tikette.tisub'), + model_name="tikategory", + name="subs", + field=models.ManyToManyField(to="tikette.tisub"), ), ] diff --git a/backend/zetikettes/tikette/models.py b/backend/zetikettes/tikette/models.py index 32a29f3..a969b95 100644 --- a/backend/zetikettes/tikette/models.py +++ b/backend/zetikettes/tikette/models.py @@ -1,5 +1,6 @@ from django.db import models + class Tisub(models.Model): class Type(models.TextChoices): SHORT_TEXT = "ST" @@ -27,7 +28,7 @@ class Tikategory(models.Model): subs = models.ManyToManyField(Tisub) # For now we'll hardcode the following:xi # [designation, ingredients, description, color, AB, designation_fontsize] - #protosubs = models.ManyToManyField(Tisub, related_name="protosubs") + # protosubs = models.ManyToManyField(Tisub, related_name="protosubs") prototempalte = models.FileField() def __str__(self): diff --git a/backend/zetikettes/tikette/planche/generate.py b/backend/zetikettes/tikette/planche/generate.py index 164eb22..588a342 100644 --- a/backend/zetikettes/tikette/planche/generate.py +++ b/backend/zetikettes/tikette/planche/generate.py @@ -11,13 +11,18 @@ DESIGNATION_FONTSIZE = 42.6667 def inkscapize(svg_in, pdf_out): - png_out = tempfile.mktemp(suffix='.png') + png_out = tempfile.mktemp(suffix=".png") try: - cmd = ['inkscape', '--export-type=png', f'--export-filename={png_out}', - f'--export-dpi={DEFAULT_DPI}', svg_in] + cmd = [ + "inkscape", + "--export-type=png", + f"--export-filename={png_out}", + f"--export-dpi={DEFAULT_DPI}", + svg_in, + ] subprocess.check_call(cmd) - cmd = ['convert', png_out, pdf_out] + cmd = ["convert", png_out, pdf_out] subprocess.check_call(cmd) finally: if os.path.exists(png_out): @@ -25,7 +30,7 @@ def inkscapize(svg_in, pdf_out): def generate(template, subs, out_dir, landscape=False): - """ Generate a sticker sheet. + """Generate a sticker sheet. template: file name for the sticker template subs: dict-like with key-value template subtitution fields @@ -34,24 +39,25 @@ def generate(template, subs, out_dir, landscape=False): """ # default designation font size - subs['designation_fontsize'] = subs.get('designation_fontsize', - DESIGNATION_FONTSIZE) + subs["designation_fontsize"] = subs.get( + "designation_fontsize", DESIGNATION_FONTSIZE + ) # fill in sticker details - sticker_out = tempfile.mktemp(suffix='.svg') + sticker_out = tempfile.mktemp(suffix=".svg") try: - with open(sticker_out, 'w') as stickout: + with open(sticker_out, "w") as stickout: makesticker(os.path.join(out_dir, template), stickout, subs) # make sticker sheet - planche_out = tempfile.mktemp(suffix='.svg') - with open(sticker_out, 'r') as stickin: - with open(planche_out, 'w') as planchout: + planche_out = tempfile.mktemp(suffix=".svg") + with open(sticker_out, "r") as stickin: + with open(planche_out, "w") as planchout: makeplanche(stickin, planchout, landscape=landscape) # process to printable pdf - pdf_out = tempfile.mktemp(dir=out_dir, suffix='.pdf') + pdf_out = tempfile.mktemp(dir=out_dir, suffix=".pdf") inkscapize(planche_out, pdf_out) return os.path.basename(pdf_out) @@ -59,5 +65,5 @@ def generate(template, subs, out_dir, landscape=False): finally: if os.path.exists(sticker_out): os.unlink(sticker_out) - if 'planche_out' in locals() and os.path.exists(planche_out): + if "planche_out" in locals() and os.path.exists(planche_out): os.unlink(planche_out) diff --git a/backend/zetikettes/tikette/planche/makeplanche.py b/backend/zetikettes/tikette/planche/makeplanche.py index 93df040..1b62166 100755 --- a/backend/zetikettes/tikette/planche/makeplanche.py +++ b/backend/zetikettes/tikette/planche/makeplanche.py @@ -5,47 +5,54 @@ from pathlib import Path from string import Template import sys -DEFAULT_SHEET_TEMPLATE = Path(__file__).parent / 'planche.svg.in' +DEFAULT_SHEET_TEMPLATE = Path(__file__).parent / "planche.svg.in" def parse_args(): - parser = argparse.ArgumentParser( - description='Make a sheet with 12 stickers') - parser.add_argument('--template', - '-t', - default=DEFAULT_SHEET_TEMPLATE, - help='path to the sheet template') - parser.add_argument('--out', - '-o', - default=sys.stdout, - type=argparse.FileType('w'), - help='output path (default: stdout)') - parser.add_argument('--landscape', - action='store_true', - help='input sticker is in landscape orientation') - parser.add_argument('sticker', - type=argparse.FileType('r'), - default=sys.stdin, - nargs='?', - help='path to the sticker SVG (default: stdin)') + parser = argparse.ArgumentParser(description="Make a sheet with 12 stickers") + parser.add_argument( + "--template", + "-t", + default=DEFAULT_SHEET_TEMPLATE, + help="path to the sheet template", + ) + parser.add_argument( + "--out", + "-o", + default=sys.stdout, + type=argparse.FileType("w"), + help="output path (default: stdout)", + ) + parser.add_argument( + "--landscape", + action="store_true", + help="input sticker is in landscape orientation", + ) + parser.add_argument( + "sticker", + type=argparse.FileType("r"), + default=sys.stdin, + nargs="?", + help="path to the sticker SVG (default: stdin)", + ) return parser.parse_args() -def makeplanche(sticker, out, template=DEFAULT_SHEET_TEMPLATE ,landscape=False): +def makeplanche(sticker, out, template=DEFAULT_SHEET_TEMPLATE, landscape=False): with open(template) as tpl: tpl_data = tpl.read() lines = sticker.readlines() - if lines[0].startswith('{ing[1:]}') else: out.append(ing) @@ -51,40 +56,48 @@ def quirk_bold_allergens(ingredients): def handler403(request, exception): - return JsonResponse({'status': 'notok', 'message': 'permission denied'}, status=403) + return JsonResponse({"status": "notok", "message": "permission denied"}, status=403) def handler404(request, exception): - return JsonResponse({'status': 'notok', 'message': 'endpoint not found'}, status=404) + return JsonResponse( + {"status": "notok", "message": "endpoint not found"}, status=404 + ) @auth_only @ensure_csrf_cookie def get_list(request): - tikettes = [{ - 'id': x.id, - 'title': x.title, - 'category': x.category.name, - 'category_id': x.category.id, - 'prototempalte': x.category.prototempalte.name, - 'landscape': x.category.landscape, - 'designation': x.designation, - 'ingredients': x.ingredients, - 'description': x.description, - 'ab': x.ab, - 'color': x.color, - 'subs': {x.name: x.default for x in x.category.subs.all()}, - } for x in Tikette.objects.all()] - return ok({'tikettes': tikettes}) + tikettes = [ + { + "id": x.id, + "title": x.title, + "category": x.category.name, + "category_id": x.category.id, + "prototempalte": x.category.prototempalte.name, + "landscape": x.category.landscape, + "designation": x.designation, + "ingredients": x.ingredients, + "description": x.description, + "ab": x.ab, + "color": x.color, + "subs": {x.name: x.default for x in x.category.subs.all()}, + } + for x in Tikette.objects.all() + ] + return ok({"tikettes": tikettes}) @auth_only def get_categories(request): - tikats = [{ - 'id': x.id, - 'name': x.name, - } for x in Tikategory.objects.all()] - return ok({'tikats': tikats}) + tikats = [ + { + "id": x.id, + "name": x.name, + } + for x in Tikategory.objects.all() + ] + return ok({"tikats": tikats}) @auth_only @@ -92,17 +105,20 @@ def get_categories(request): def generate(request): payload = json.loads(request.body) - subs = dict(payload['subs']) - for key in ('designation', 'ingredients', 'description', 'color', 'AB'): + subs = dict(payload["subs"]) + for key in ("designation", "ingredients", "description", "color", "AB"): subs[key] = payload[key] - subs['ingredients'] = quirk_bold_allergens(subs['ingredients']) + subs["ingredients"] = quirk_bold_allergens(subs["ingredients"]) - pdfpath = stickersheet.generate(template=payload['template'], subs=subs, - out_dir=settings.TIKETTE_OUT_DIR, - landscape=payload['landscape']) + pdfpath = stickersheet.generate( + template=payload["template"], + subs=subs, + out_dir=settings.TIKETTE_OUT_DIR, + landscape=payload["landscape"], + ) - return ok({'file': pdfpath}) + return ok({"file": pdfpath}) @auth_only @@ -128,7 +144,7 @@ def deletetikette(request): @post_please def signin(request): payload = json.loads(request.body) - token = payload['token'] + token = payload["token"] try: user_data = id_token.verify_oauth2_token( @@ -136,13 +152,13 @@ def signin(request): ) except ValueError: raise - return JsonResponse({'status': 'notok'}, status=403) + return JsonResponse({"status": "notok"}, status=403) - request.session['user_data'] = user_data + request.session["user_data"] = user_data return ok(user_data) def signout(request): - del request.session['user_data'] + del request.session["user_data"] return ok() diff --git a/backend/zetikettes/zetikettes/asgi.py b/backend/zetikettes/zetikettes/asgi.py index 0c404ce..d376f5a 100644 --- a/backend/zetikettes/zetikettes/asgi.py +++ b/backend/zetikettes/zetikettes/asgi.py @@ -11,6 +11,6 @@ import os from django.core.asgi import get_asgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'zetikettes.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "zetikettes.settings") application = get_asgi_application() diff --git a/backend/zetikettes/zetikettes/settings.py b/backend/zetikettes/zetikettes/settings.py index 9733ab7..5712701 100644 --- a/backend/zetikettes/zetikettes/settings.py +++ b/backend/zetikettes/zetikettes/settings.py @@ -15,75 +15,75 @@ from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent -#TIKETTE_OUT_DIR = BASE_DIR / 'data' -TIKETTE_OUT_DIR = Path('/data') +# TIKETTE_OUT_DIR = BASE_DIR / 'data' +TIKETTE_OUT_DIR = Path("/data") MEDIA_ROOT = TIKETTE_OUT_DIR -MEDIA_URL = '/data/' +MEDIA_URL = "/data/" # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-64qxpe55#9wy=5@#dl0)3w7ywxh48m!f&!slp9e7v4lh@hjdct' +SECRET_KEY = "django-insecure-64qxpe55#9wy=5@#dl0)3w7ywxh48m!f&!slp9e7v4lh@hjdct" # SECURITY WARNING: don't run with debug turned on in production! DEBUG = False -ALLOWED_HOSTS = ['*'] -CSRF_TRUSTED_ORIGINS = ['https://*.ponteilla.net'] +ALLOWED_HOSTS = ["*"] +CSRF_TRUSTED_ORIGINS = ["https://*.ponteilla.net"] # Application definition INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'tikette', + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "tikette", ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'tikette.middleware.cors_everywhere', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "tikette.middleware.cors_everywhere", ] -ROOT_URLCONF = 'zetikettes.urls' +ROOT_URLCONF = "zetikettes.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ], }, }, ] -WSGI_APPLICATION = 'zetikettes.wsgi.application' +WSGI_APPLICATION = "zetikettes.wsgi.application" # Database # https://docs.djangoproject.com/en/4.2/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': TIKETTE_OUT_DIR / 'db.sqlite3', + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": TIKETTE_OUT_DIR / "db.sqlite3", } } @@ -93,16 +93,16 @@ DATABASES = { AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] @@ -110,9 +110,9 @@ AUTH_PASSWORD_VALIDATORS = [ # Internationalization # https://docs.djangoproject.com/en/4.2/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True @@ -122,14 +122,16 @@ USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/4.2/howto/static-files/ -STATIC_URL = '/zetikettes/srv/static/' +STATIC_URL = "/zetikettes/srv/static/" -STATIC_ROOT = 'www_static' +STATIC_ROOT = "www_static" # Default primary key field type # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" # not a secret -GOOGLE_OAUTH_CLIENT_ID = '634510965520-c5l7f15fn4koraqhpqfe01ssn8v0q2qk.apps.googleusercontent.com' +GOOGLE_OAUTH_CLIENT_ID = ( + "634510965520-c5l7f15fn4koraqhpqfe01ssn8v0q2qk.apps.googleusercontent.com" +) diff --git a/backend/zetikettes/zetikettes/urls.py b/backend/zetikettes/zetikettes/urls.py index 28eb906..5d4d89a 100644 --- a/backend/zetikettes/zetikettes/urls.py +++ b/backend/zetikettes/zetikettes/urls.py @@ -14,6 +14,7 @@ Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ + from django.conf import settings from django.conf.urls.static import static from django.contrib import admin @@ -23,16 +24,16 @@ from django.views.generic.base import TemplateView import tikette.views urlpatterns = [ - path('admin/', admin.site.urls), - path('list', tikette.views.get_list), - path('categories', tikette.views.get_categories), - path('generate', tikette.views.generate), - path('newtikette', tikette.views.newtikette), - path('deletetikette', tikette.views.deletetikette), - path('updatetikette', tikette.views.newtikette), # yes, we use newtikette - path('signin', tikette.views.signin), - path('signout', tikette.views.signout), + path("admin/", admin.site.urls), + path("list", tikette.views.get_list), + path("categories", tikette.views.get_categories), + path("generate", tikette.views.generate), + path("newtikette", tikette.views.newtikette), + path("deletetikette", tikette.views.deletetikette), + path("updatetikette", tikette.views.newtikette), # yes, we use newtikette + path("signin", tikette.views.signin), + path("signout", tikette.views.signout), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) -handler403 = 'tikette.views.handler403' -handler404 = 'tikette.views.handler404' +handler403 = "tikette.views.handler403" +handler404 = "tikette.views.handler404" diff --git a/backend/zetikettes/zetikettes/wsgi.py b/backend/zetikettes/zetikettes/wsgi.py index afb0b88..21a279b 100644 --- a/backend/zetikettes/zetikettes/wsgi.py +++ b/backend/zetikettes/zetikettes/wsgi.py @@ -11,6 +11,6 @@ import os from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'zetikettes.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "zetikettes.settings") application = get_wsgi_application() diff --git a/frontend/config.js b/frontend/config.js index 1cbf26f..a7b2231 100644 --- a/frontend/config.js +++ b/frontend/config.js @@ -1,2 +1,2 @@ -const backend_api = '/zetikettes/srv/' +const backend_api = "/zetikettes/srv/" const google_oauth_client_id = '634510965520-c5l7f15fn4koraqhpqfe01ssn8v0q2qk.apps.googleusercontent.com';