Code Monkey home page Code Monkey logo

sample-django-app's Introduction

Sample Django App

A demo app created using Django and ShopifyAPI v8.4+.

Quick start

To run this app locally, you can clone the repository and do the following.

  1. Create a .env file to specify this app's API key and API secret key app credentials that can be found in the Shopify Partners dashboard.
SHOPIFY_API_KEY=<The API key app credential specified in the Shopify Partners dashboard>
SHOPIFY_API_SECRET=<The API secret key app credential specified in the Shopify Partners dashboard>
APP_URL=<The public app URL specified in the Shopify Partners dashboard>
SCOPES=<Scopes needed for the app>

Note: It's recommended to follow along the tutorial Build a Shopify App with Node and React to understand how to retrieve the API key and API secret key app credentials.

  1. Run the following to install the required dependencies:
$ pip install -r requirements.txt
  1. Change directories to the main sample_django_app app and run all pending migrations:
$ cd sample_django_app
$ python manage.py migrate
  1. Ensure ngrok is running on port 8000:
$ ngrok http 8000
  1. In a new terminal, run the server:
$ python manage.py runserver
  1. Create an APP_URL environment variable based on the URL ngrok gives you. This is used in the CSRF_TRUSTED_ORIGINS and ALLOWED_HOSTS section of settings.py. Do not include a schema (http:// or https://) in this variable.
export APP_URL=<ngrok-url.ngrok.io>
  1. From the Partner dashboard, update the "App URL" and "Allowed redirection URL(s)" to include the callback URL:
<https://ngrok-url.ngrok.io>/auth/shopify/callback
  1. In your browser, open the https ngrok url to install and open this app on a shop. Requests to authenticated resources like the products view in the api app should now be secured with an Authorization: Bearer <session token> header.

sample-django-app's People

Contributors

nabeelahsen avatar rezaansyed avatar stevemar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sample-django-app's Issues

Iframe issue on Chrome

Showing "This content is blocked. Contact the site owner to fix the issue." on the Shopify iframe

tried everything from my end.

Setting.py variables:-

'''ALLOWED_HOSTS = [
os.getenv('APP_URL'),
'*'
]

CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True

CSRF_TRUSTED_ORIGINS = [
"https://" + os.getenv('APP_URL'),
"http://127.0.0.1:8000/",
"http://localhost:*"
]

CSP_FRAME_SRC = ("'self'", "http://127.0.0.1:8000")

CSP_FRAME_ANCESTORS = ("'self'", 'https://*.myshopify.com')

CSP_DEFAULT_SRC = ("'self'", "'unsafe-inline'", "'unsafe-eval'", "https://fonts.gstatic.com", "http://127.0.0.1:8000")

CSP_STYLE_SRC = ("'self'", "'unsafe-inline'", "https://fonts.googleapis.com")

CSP_SCRIPT_SRC = ("'self'", "'unsafe-inline'", "'unsafe-eval'")

CSP_IMG_SRC = ("'self'",
"https://*.s3.amazonaws.com", "data:", "https://cdn.shopify.com")'''

AttributeError at /api/products/, 'NoneType' object has no attribute 'startswith'

I can set up and open the app but it's giving me attribute error when I tried to open the endpoints /api/products/ & /api/orders/

It indicates that in shopify_app/decorators.py, line 16
authorization_header is None when it's passed to call startswith in session_token.py, line 44

Did I miss anything in the setup?

Also, please specify the supported Python versions in the docs
I was trying to get it up with python 3.8 but decorators.py is using removeprefix, which is only available in python 3.9.
I replace it with [0:8] and it's ok.

How to migrate to the new auth?

Hi,

I tried to run this repo and it was working quite well. But I am struggling with migration issues and whether to continue with the embedded app or standalone app.

I have an existing Shopify app codebase of Django 2.2 (Python 3.7.9) with OAuth (no app bridge). My questions are:

  1. How can I reuse the new session token auth? Copy shopify_app to my project and reuse it?
  2. By default, Django stores session id in a cookie. My sessions are database-backed sessions and I was using a lot of request.session['key'] in my code. If 3rd-party cookies are going to be banned by Chrome, the sessions will fail in embedded apps. How do you handle it here?

Discussion - Is this repo going to be the new Shopify-Django template?

Good to see the python world getting some attention from Shopify!

I'm not sure if either of the two maintainers of this simple app are interested, but there used to be three apps that could be combined to make an amazing django project and possibly save you some work. They are:

Auth - https://github.com/discolabs/django-shopify-auth
Webhook - which handles inbound webooks https://github.com/discolabs/django-shopify-webhook
and the most useful: shopify django sync that defines models and sets up two way operation between shopify and django:
original: https://github.com/discolabs/django-shopify-sync
A more recent fork: https://gitlab.com/thelabnyc/django-shopify-sync
and finally, my personal and even more recently updated fork:
https://github.com/samLozier/django-shopify-sync

With a little bit of attention, the three could be modernized to facilitate a turn-key fully built out backend for someone trying to build a shopify app.

I'm happy to contribute to this if you're welcoming PR's, but I'd like to know how basic you intend to keep it before I spend the time.

feedback from trying it out

I was surprised to see this repo still works, I did have to make a few changes which should be documented.

  1. App an APP_URL env. variable based on the URL ngrok gives you. This is used in the ALLOWED_HOSTS section of settings.py
export APP_URL=<ngrok-url.ngrok.io>
  1. Again in settings.py I had to add a few CSRF/CORS settings.
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
CSRF_TRUSTED_ORIGINS = ['https://ngrok-url.ngrok.io']
  1. It's worth mentioning to update the App URLs in the partner dashboard to include the callback URL
<ngrok-url.ngrok.io>/auth/shopify/callback

Iframe Issues in safari Browser

Does this work as an Iframe in Safari browser? We have a Shopify Django app which works fine as an iframe in Chrome and Mozilla. But its not storing cookies in Safari, so all the post requests are getting forbidden due to no csrf tokens found. This is our settings.py, can anyone mention what we can do to overcome this issue, or is there any other way of manually passing csrf token, not from the cookies.

`
import os
from shopify_app import *
from decouple import config

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(file)))

SECRET_KEY = config('DJANGO_SECRET')

DEBUG = int(config('DEBUG'))

SHOPIFY_API_KEY = config('SHOPIFY_API_KEY')
SHOPIFY_API_SECRET = config('SHOPIFY_API_SECRET')
SHOPIFY_APP_NAME = config('SHOPIFY_APP_NAME')
SHOPIFY_API_VERSION = 'unstable'
SHOPIFY_TEST = config('SHOPIFY_TEST') # For the purpose of Shopify Payments

INTERNAL_IPS = ('127.0.0.1',)

ALLOWED_HOSTS = config('DJANGO_ALLOWED_HOSTS').split(" ")

CSP_FRAME_ANCESTORS = ("'self'", 'https://*.myshopify.com')

CSP_DEFAULT_SRC = ("'self'", "'unsafe-inline'", "'unsafe-eval'", "https://fonts.gstatic.com")

CSP_STYLE_SRC = ("'self'", "'unsafe-inline'", "https://fonts.googleapis.com")

CSP_SCRIPT_SRC = ("'self'", "'unsafe-inline'", "'unsafe-eval'")

CSP_IMG_SRC = ("'self'",
"https://*.s3.amazonaws.com", "data:", "https://cdn.shopify.com")

SESSION_COOKIE_SAMESITE = 'None'
SESSION_COOKIE_SECURE = True
XS_SHARING_ALLOWED_METHODS = ['POST', 'GET', 'PUT']

CSRF_COOKIE_SAMESITE = 'None'
CSRF_COOKIE_SECURE = True

STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

CSRF_TRUSTED_ORIGINS = [config('CSRF_TRUSTED_ORIGINS')]

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',

'shopify_app.apps.ShopifyAppConfig',
'home.apps.HomeConfig',
'notification',
'api',
'payment',
'debug_toolbar',


'django_extensions',
'rest_framework',
'rest_framework.authtoken',
'django_celery_beat',
'storages',

]

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',
'csp.middleware.CSPMiddleware',
'shopify_app.middleware.LoginProtection',
'debug_toolbar.middleware.DebugToolbarMiddleware',

]

ROOT_URLCONF = 'shopify_django_app.urls'

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
"APP_DIRS": True,
'DIRS': [],
'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',
'shopify_app.context_processors.current_shop',
],
},
},
]

WSGI_APPLICATION = 'shopify_django_app.wsgi.application'

DATABASES = {
'default': {
'ENGINE': config('SQL_ENGINE'),
'NAME': config('SQL_DATABASE'),
'USER': config('SQL_USER'),
"PASSWORD": config('SQL_PASSWORD'),
"HOST": config('SQL_HOST'),
"PORT": config('SQL_PORT'),
}
}

AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]

DATA_UPLOAD_MAX_MEMORY_SIZE = None
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
AWS_ACCESS_KEY_ID = config('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = config('AWS_SECRET_ACCESS_KEY')
DEFAULT_FILE_STORAGE = config('DEFAULT_FILE_STORAGE')
AWS_STORAGE_BUCKET_NAME = config('AWS_STORAGE_BUCKET_NAME')

if DEBUG:
AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
AWS_QUERYSTRING_AUTH = False
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

else:
CLOUDFRONT_DOMAIN = config('AWS_CLOUDFRONT_DOMAIN')
CLOUDFRONT_DOMAIN_ID = config('AWS_CLOUDFRONT_ID')
AWS_S3_CUSTOM_DOMAIN = CLOUDFRONT_DOMAIN
AWS_DEFAULT_ACL = None
AWS_S3_OBJECT_PARAMETERS = {'CacheControl': 'max-age=86400'}
MEDIAFILES_LOCATION = 'media'
MEDIA_URL = f'{AWS_S3_CUSTOM_DOMAIN}/{MEDIAFILES_LOCATION}/'
STATICFILES_LOCATION = 'static'
STATIC_URL = '/static/'

STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)

REDIS_HOST = config('REDIS_HOST')
REDIS_PORT = config('REDIS_PORT')

SNS_ACCESS_KEY_ID = config('SNS_ACCESS_KEY_ID')
SNS_SECRET_ACCESS_KEY = config('SNS_SECRET_ACCESS_KEY')
SNS_REGION_NAME = config('SNS_REGION_NAME')
ANDROID_PLATFORM_APP_ARN = config('ANDROID_PLATFORM_APP_ARN')
IOS_PLATFORM_APP_ARN = config('IOS_PLATFORM_APP_ARN')

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'Asia/Kolkata'

USE_I18N = True

USE_L10N = True

USE_TZ = True

AUTH_USER_MODEL = 'shopify_app.User'

CELERY_BROKER_URL = config('CELERY_BROKER_URL')
CELERY_RESULT_BACKEND = config('CELERY_RESULT_BACKEND')
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Asia/Kolkata'

CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'

REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
),
}

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = config('EMAIL_HOST')
EMAIL_USE_TLS = True
EMAIL_PORT = config('EMAIL_PORT')
EMAIL_HOST_USER = config('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD')
`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.