I get this error while using webapp2 user authentication. No 'Access-Control-Allow-Origin' header is present on the requested resource.
How do I add access header before redirect ?
redirect code :
self.redirect(users.create_login_url(self.request.uri))
CODE:
class Authenticate(webapp2.RequestHandler):
def get(self):
user = users.get_current_user()
cookie_value = self.request.cookies.get('user')
if user==cookie_value and user!=None:
self.response.headers['Content-Type'] = 'text/plain'
self.response.write('Success')
else:
self.request.headers['Access-Control-Allow-Origin'] = '*'
self.redirect(users.create_login_url(self.request.uri))
def redirect(self, uri, permanent=False, abort=False, code=None,body=None)
and
def redirect(uri, permanent=False, abort=False, code=None,
body=None,request=None, response=None)
So, I think you should call the second one as (if you want to pass the response object):
return webapp2.redirect(users.create_login_url(self.request.uri),True,False,None
,None,None,self.response)
Refer Webapp2 Source Code
Before the self.redirect call, do
self.response.headers['Access-Control-Allow-Origin'] = '*'
or whatever value you wish to have for that header -- self.redirect by default makes a new response object, but you can change that with
return self.redirect(users.create_login_url(self.request.uri,
response=self.response)
Related
I have an aiohttp app that has some endpoints created using nested apps.
My use case is once the request is processed, I want to return not in web.response format but whatever format is requested by the client in their request's header (could be csv, json, html etc).
So I was using a decorator and from that decorator wrapper, getting the current request to know the header format and process the response to that type.
My question is how can I get current request's context. I know there isn't anything like current_app like in flask, so what's the best of doing what I want to do.
Below I am posting some code that explains above content:
#subapp_routes.get('')
#subapp_routes.get('/{c_id}')
#format_output
async def index(request):
print(request)
c_id = request.match_info.get('c_id', None)
return await get_index(c_id)
def format_data_object(data):
status = 200
mime = _most_acceptable_format(request, data) # HOW TO PASS THIS CURRENT request AS CURRENTLY THIS ISN'T GETTING RECOGNIZED. I TRIED aiohttp.request and aiohttp.web.request but get not recognized, so not sure now
if mime == MIME_DATAFRAME:
return _render_dataframe(data, status)
elif mime == MIME_CSV:
return _render_csv(data, status)
elif mime == MIME_JSON:
return _render_json(data, status)
elif mime == MIME_HTML:
return _render_html(data, status)
raise InvalidRequest('unrecognized format: "%s"' % mime)
def format_output(function):
"""
Output format decorator.
"""
#wraps(function)
def wrapper(*args, **kwargs):
try:
data = function(*args, **kwargs)
return format_data_object(data)
except Exception as ex:
return handle_error(ex)
return wrapper
flask way spoils people.
If you need an entire request, DB connection or other resource -- explicitly pass it into called function.
Very obvious and elegant way which doesn't require any implicit context namespace magic.
Please left things like threadlocal variables to system tools, user code should not use them for sake of simplicity and readability.
I'm intern and work on a project where I develop DRF API that need to interact with mobile app written by my colleague with Ionic framework.
We are creating new user. My view method is following:
class NewUser(generics.CreateAPIView):
model = User
permission_classes = [permissions.AllowAny]
serializer_class = NewUserSerializer
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
token, created = Token.objects.get_or_create(user=serializer.instance)
return Response({'token': token.key}, status=status.HTTP_201_CREATED, headers=headers)
When someone wants to create new user via POST request if user name has't been taken yet, then API return 201 status code and token in JSON, if user name already taken it returns 400 status and error message in JSON. MY colleague request me to change status message to 200 when he tries to create username with name that already exist. He says that he can't consume the ERROR response.
His code looks like:
$http.post(url,{
username:$scope.tel,
password:$scope.passwd
}).success(function(data){
alert(data);
$ionicLoading.hide();
console.log(data);
})
Question:
1) Should I tweak my API to send 200 status instead of more logical 400 for 'user already register' error?
I tried to change my code, But i couldn't find the method to override in CreateAPIView/ModelSerializer of DRF. I ended up rewriting my view class to method:
#api_view(['POST'])
def newUser(request):
"""
Saves a new user on the database
"""
if request.method == 'POST':
serializer = NewUserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
token, created = Token.objects.get_or_create(user=serializer.instance)
return Response({'token': token.key}, status=status.HTTP_201_CREATED, headers=serializer.data)
else:
return Response(serializer.errors, status=status.HTTP_200_OK)
Question:
2) If I want to change behaviorof API and responce, which method should I override
3) I'm new to Django and still don't qiute know where we should use generic views VS. #.... methods
200 vs 400 in this case is mostly preference. 400 means "Bad Request". This is generally more correct for a incorrectly formatted request, rather than one that doesn't meet some condition.
200 is just as appropriate it conveys the correct information:
Your request was valid, but I didn't create a new record.
As to how to do the override. The shortest path is to override the CreateAPIView.create and change the response code used. You should also avoid repeating the default behavior of CreateAPIView by calling super.
class CreateUserView(generics.CreateAPIView):
model = User
permission_classes = [permissions.AllowAny]
serializer_class = NewUserSerializer
def create(self, request, *args, **kwargs):
response = super(CreateUserView, self).create(request, *args, **kwargs)
token, created = Token.objects.get_or_create(user=serializer.instance)
response.status = status.HTTP_200_OK
response.data = {'token': token.key}
return response
Personally, I would have also crafted my NewUserSerializer to have a token field and handle the token so I didn't have to do that work in the View. It doesn't belong in a View.
Save and deletion hooks:
The following methods are provided by the mixin classes, and provide easy overriding of the object save or deletion behavior.
perform_create(self, serializer) - Called by CreateModelMixin when
saving a new object instance. perform_update(self, serializer) -
Called by UpdateModelMixin when saving an existing object instance.
perform_destroy(self, instance) - Called by DestroyModelMixin when
deleting an object instance.
These hooks are particularly useful for setting attributes that are implicit in the request, but are not part of the request data. For instance, you might set an attribute on the object based on the request user, or based on a URL keyword argument.
https://www.django-rest-framework.org/api-guide/generic-views/#methods
class CourseOrder(generics.CreateAPIView):
serializer_class = serializers.OrderCoursesSerializer
permission_classes = [permissions.AllowAny]
# hook before creating
def perform_create(self, serializer):
# print(serializer['name'].value)
# save post data
serializer.save()
try:
subject, from_email, to = 'New order', 'zelenchyks#gmail.com', 'zelenchyks#gmail.com'
text_content = 'New order'
html_content = '''
<p>client name: %s </p>
<p>client phone: %s </p>
'''
% (serializer['name'].value, serializer['mobile'].value)
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, "text/html")
msg.send()
except Warning:
print('Huston we have a problems with smtp')
I'm using this code to send Http request inside my app and then show the result:
def get(self):
url = "http://www.google.com/"
try:
result = urllib2.urlopen(url)
self.response.out.write(result)
except urllib2.URLError, e:
I expect to get the html code of google.com page, but I get this sign ">", what the wrong with that ?
Try using the urlfetch service instead of urllib2:
Import urlfetch:
from google.appengine.api import urlfetch
And this in your request handler:
def get(self):
try:
url = "http://www.google.com/"
result = urlfetch.fetch(url)
if result.status_code == 200:
self.response.out.write(result.content)
else:
self.response.out.write("Error: " + str(result.status_code))
except urlfetch.InvalidURLError:
self.response.out.write("URL is an empty string or obviously invalid")
except urlfetch.DownloadError:
self.response.out.write("Server cannot be contacted")
See this document for more detail.
You need to call the read() method to read the response. Also good practice to check the HTTP status, and close when your done.
Example:
url = "http://www.google.com/"
try:
response = urllib2.urlopen(url)
if response.code == 200:
html = response.read()
self.response.out.write(html)
else:
# handle
response.close()
except urllib2.URLError, e:
pass
Hopefully someone can help. I am building an app on Google app engine and trying to pass the credentials of an authenticated user to the push task Handler. I am using the OAuth2DecoratorFromClientSecrets library to create the decorator which seems to store the credentials for the user in the datastore. It stores it with a key name of something like "110111913122157971566". My problem is that I cant seem to find a way to figure out what that key name is so that I can retrieve it using the StorageByKeyName method from within my worker handler. The documentation I have read uses the user_id as the key name but this doesnt work for me as the credentials are not stored with the user_id as the key name, however if I hard code the key name then the code does work. I am aware that I could run the copy code from within the Submit handler but need to run it as a separate task. Below is a sample of my code, thanks for any help you can provide:
JINJA_ENVIRONMENT = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
extensions=['jinja2.ext.autoescape'],
autoescape=True)
SCOPES =['https://www.googleapis.com/auth/drive']
decorator = OAuth2DecoratorFromClientSecrets(
os.path.join(os.path.dirname(__file__),
'client_secrets.json'),
' '.join(SCOPES)
)
class MainPage(webapp2.RequestHandler):
def get(self):
if users.get_current_user():
url = users.create_logout_url(self.request.uri)
url_linktext = 'Logout'
template_values = {'url': url,
'url_linktext': url_linktext,
}
template = JINJA_ENVIRONMENT.get_template('index.html')
self.response.write(template.render(template_values))
else:
self.redirect(users.create_login_url(self.request.uri))
class Submit(webapp2.RequestHandler):
#decorator.oauth_required
def post(self):
taskqueue.add(url='/worker', params={'user_id' : users.get_current_user().user_id()})
self.response.write('<html><body>You wrote:<pre>')
self.response.write(users.get_current_user().user_id())
self.response.write('</pre></body></html>')
class Worker(webapp2.RequestHandler):
def post(self):
user_id = self.request.get('user_id')
credentials = StorageByKeyName(CredentialsModel, user_id , 'credentials').get()
http = httplib2.Http()
http = credentials.authorize(http)
service = build('drive', 'v2',http=http)
fileId = 'actual file_id of drive file here'
copied_file = {'title': 'My New Test Doc2'}
new_file = service.files().copy(fileId=fileId,body=copied_file).execute(http=http)
application = webapp2.WSGIApplication([
('/', MainPage),
('/submit', Submit),
('/worker', Worker),
(decorator.callback_path, decorator.callback_handler()),
], debug=True)
First, remove the http=decorator.http at the top level - it doesn't appear to be used and should only be used from inside the decorated method.
I'm not certain, but looking at the decorator code I think it is is keying based on the user_id(). Your code is displaying that, but the parameter you are passing to the task isn't. Try {'user_id' : users.get_current_user().user_id()}.
Using Google App Engines webapp framework, is there any way to pass data to a base template?
To be specific, I just want a logout button to be visible if the user is logged on (using googles own authentication system).
I'm still learning so I'm not sure what parts are GAE specific and what parts are django specific; having to send the logged in user from every single request handler seems very un-DRY.
Arguments to base templates are passed the same way as any other template arguments, by being passed to template.render. I usually solve this by having a convenience method on my base handler that inserts common template arguments, like this:
class BaseHandler(webapp.RequestHandler):
def render_template(self, filename, template_args):
path = os.path.join(os.path.dirname(__file__), 'templates', filename)
template_args.update({
'user': users.get_current_user(),
# ...
})
class MyHandler(BaseHandler):
def get(self):
self.render_template('my.html', {'foo': 'bar'})
I think you are looking for something like login_required decorator in django. You can either try to use a complete django framework in GAE (I never tried) or it can be customized easily with decoration and add your own behavior. In your case, it will be a good idea to pass user's login status to template engine.
#the decorator
def login_checked(f):
def wrap(request, *args, **kwargs):
# get current user
user = get_current_user()
template_path, vars = f(request, *args, **kwargs)
vars['user']= user
template.render(template_path, vars)
return wrap
# usage
class MyPage(webapp.RequestHandler):
#login_checked # add a decoration
def get(self):
# your page
return "the_template_page_you_want", {"the value you want to pass to template": "xxx"}
Take a look at this example:
from google.appengine.api import users
class MyHandler(webapp.RequestHandler):
def get(self):
user = users.get_current_user()
if user:
greeting = ("Welcome, %s! (sign out)" %
(user.nickname(), users.create_logout_url("/")))
else:
greeting = ("Sign in or register." %
users.create_login_url("/"))
self.response.out.write("<html><body>%s</body></html>" % greeting)
Source: http://code.google.com/appengine/docs/python/users/loginurls.html