forked from fulfilio/flask-shopify
-
Notifications
You must be signed in to change notification settings - Fork 0
/
flask_shopify.py
177 lines (147 loc) · 5.41 KB
/
flask_shopify.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# -*- coding: utf-8 -*-
"""
flask.ext.shopify
~~~~~~~~~~~~~~~~~
:copyright: (c) 2017 by Fulfil.IO Inc.
:license: BSD, see LICENSE for more details.
"""
from functools import wraps
from flask import (
request, redirect, url_for, _request_ctx_stack, session,
current_app, abort
)
import shopify
def assert_shop(func):
"""
Ensure that the shop in the session is the same as the shop in a landing
page where something like an admin link is used.
"""
@wraps(func)
def wrapper(*args, **kwargs):
if request.shopify_session.url == request.args.get('shop'):
return func(*args, **kwargs)
else:
current_app.shopify.logout()
if current_app.shopify.login_view:
return redirect(
url_for(
current_app.shopify.login_view,
shop=request.args.get('shop')
)
)
else:
abort(403)
return wrapper
def shopify_login_required(func):
"""
Ensure that there is a login token in the session.
"""
@wraps(func)
def decorated_view(*args, **kwargs):
shop_n_token = current_app.shopify.tokengetter_func()
if not shop_n_token:
return redirect(url_for(
current_app.shopify.login_view,
shop=request.args.get('shop'),
next=request.url
))
with shopify.Session.temp(*shop_n_token):
return func(*args, **kwargs)
return decorated_view
class Shopify(object):
"""
Shopify flask extension
Required Flask settings::
SHOPIFY_SHARED_SECRET
SHOPIFY_API_KEY
Configuring::
```
from flask_shopify import Shopify
app = Flask(__name__)
shopify = Shopify(app)
# Set the login view if you plan on using shopify_login_required
# decorator
shopify.login_view = 'auth.login'
"""
def __init__(self, app=None):
if app is not None:
self.init_app(self.app)
self.tokengetter_func = self._session_token_getter
self.tokensetter_func = self._session_token_setter
self.login_view = None
self.shopify_api = shopify
self.version='2019-04'
def init_app(self, app, connection=None):
app.shopify = self
if connection:
self.shopify_api.base.ShopifyConnection = connection
self.shopify_api.Session.setup(
api_key=app.config['SHOPIFY_API_KEY'],
secret=app.config['SHOPIFY_SHARED_SECRET']
)
self.scopes = app.config.get('SHOPIFY_SCOPES', [])
app.before_request(self.before_request)
def before_request(self):
"""
Add the shopify_session to the request if possible.
If there is no token, shopify_session is set to None.
"""
shop_token = self.tokengetter_func()
ctx = _request_ctx_stack.top
if shop_token is not None:
# should be a valid token
shop_session = shopify.Session(*shop_token)
self.shopify_api.ShopifyResource.activate_session(shop_session)
ctx.request.shopify_session = shop_session
else:
# not logged in, no session created
ctx.request.shopify_session = None
def install(self, shop_subdomain, scopes=None, redirect_uri=None):
"""Returns a redirect response to the "permission" URL with
the given shop. This will then prompt the user to install the app
which will then send them to the welcome view.
:param url: myshopify.com subdomain.
:type url: str.
"""
if scopes is None:
scopes = self.scopes
shop_session = self.shopify_api.Session("%s.myshopify.com" % shop_subdomain, version=self.version)
permission_url = shop_session.create_permission_url(
scopes, redirect_uri
)
return redirect(permission_url)
def authenticate(self):
shop_session = self.shopify_api.Session(request.args['shop'], version=self.version)
token = shop_session.request_token(request.args)
self.shopify_api.ShopifyResource.activate_session(shop_session)
self.tokensetter_func(request.args['shop'], self.version, token)
return shop_session
def token_getter(self, f):
"""Registers a function as tokengetter. The tokengetter has to return
a tuple of ``(url, token)`` with the user's token and secret.
If the data is unavailable, the function must return `None`.
"""
self.tokengetter_func = f
return f
def token_setter(self, f):
"""Registers a function as tokensetter. The tokensetter will be sent
the shop and the token.
"""
self.tokensetter_func = f
return f
@classmethod
def _session_token_getter(cls):
try:
return session['SHOPIFY_SHOP'], session['SHOPIFY_VERSION'], session['SHOPIFY_TOKEN']
except KeyError:
return None
@classmethod
def _session_token_setter(cls, shop, version, token):
session['SHOPIFY_SHOP'] = shop
session['SHOPIFY_VERSION'] = version
session['SHOPIFY_TOKEN'] = token
def logout(self):
session.pop('SHOPIFY_SHOP', None)
session.pop('SHOPIFY_VERSION', None)
session.pop('SHOPIFY_TOKEN', None)
self.shopify_api.ShopifyResource.clear_session()