wagtail def get_context and def serve - wagtail

I can add to the context in the serve method for a page, and get the context variable in the page template. I cannot seem to add to the context in get_context; or, access it in the page template. This is stumping me.
I'd like to add a variable or two to the context using the get_context function, and access that in the page template.
# If request.user is authenticated AND is registered for this event
# set that in the context
# ###---THIS DOES SEEM TO ADD TO CONTEXT, OR
# ###---IF IT DOES, THEN CANNOT ACCESS IT IN THE TEMPLATE--###
# def get_context(self, request, *args, **kwargs):
# # pdb.set_trace()
# context = super(EventPage, self).get_context(request, *args, **kwargs)
# if request.user.is_authenticated:
# # pdb.set_trace()
# for attendee in self.event.eventattendee_set.all():
# if attendee.email == request.user.email:
# # user is an attendee for this event
# context["is_attendee"] = True
# break
# context["hello"] = "hello"
# return context

You don't show the full page model definition, so I assume it is for EventPage. Also, the code you have above is commented out. Is it commented out in your file? That would explain why you're not getting anything. Also, you don't have to do super(EventPage, self).get_context(request, *args, **kwargs). You can just do super().get_context(request, *args, **kwargs) (though what you have should work also). Everything else looks correct.

I was accessing the added context data via get_context using the page or self prefix in the template. That would not have worked--at least it seems not to have. Access the context variables directly, without the prefix, and there you have it. Sometimes, one just has to step away from the keyboard. All is good with get_context.

Related

Getting the URL of an attachment in Discord.py

I am trying to get the URL of the file that the user attaches so I can use it later on in my code however I'm not too sure on how to go about doing so.
#client.command(pass_context=True)
async def readURL(ctx, url):
# Do something
References:
discord.ext.commands
Attachment.url
If I'm understanding the question correctly, it would go like this:
#client.command() # context is automatically passed in rewrite
async def readURL(ctx):
attachment = ctx.message.attachments[0] # gets first attachment that user
# sent along with command
print(attachment.url)
References:
Attachment.url
Message.attachments

How can I manage authorization in GAE using Google Accounts?

So far I have used oauth2 to manage authentication using Google Accounts for my app, which gives me some data to complete a basic profile. The problem is that I now want to manage permissions to view and edit a lot of the content in the app, with different groups of people being able to view/edit different parts of the app.
I want some parts of my application to be accessed by users with permission for A, some for B, C, etc. The way I started doing this was using a decorator in the get and post method of each handler, like this:
class SomeHandler(Handler):
#validate_access
def get(self):
pass
#validate_access
def post(self):
pass
Where #validate_access executes the code in the function only if the user has permission for it, and returning an authorization error if not. This seemed to be a good solution a while back, but since there are many handlers I have to use that decorator everywhere, which is annoying and dangerous, since I may forget to put it in some functions.
Is there a way to put this validations in the initialization of the base handler, so that I don't have to use that decorator everywhere? I imagine something like this:
class BaseHandler(webapp2.RequestHandler):
def initialize(self, request, response):
super(Handler, self).initialize(request, response)
self.user = users.get_current_user()
employee = Employee.query(user_id=self.user.user_id).get()
if employee.auth_level > 3:
#See the content: Do whatever the "get" method of the corresponding handler does.
pass
else:
#Raise authorization error
pass
Or is there a better way to do this? (Sorry if it's a basic question, I've never done this before)
Yes, you can overwrite the webapp2 dispatch handler for this purpose. I used this method to enforce role based access control (RBAC).
Example code:
class BaseHandler(webapp2.RequestHandler):
""" webapp2 base handler """
def dispatch(self):
# UserAccess aborts if the user does not have permission to use a handler
UserAccess(self.request)
super(BaseHandler, self).dispatch()
....
class ExampleHandler(BaseHandler):
def get(self):
.....
I use a config file with the allowed roles for a handler. This file is also used to create the webapp2 routes and the dynamic user menu.

Django generic UpdateView in Djangular

The Python source code for Djangular Demos gives examples of how to process the post request from a form that creates a Django object instance. But they don't show how to process the post request from a form which updates an existing object instance.
The code for updating an object seems rather complicated: my code is missing something crucial. Using my code I always get a form validation error: Object with this Name already exists.
I am using the Django generic UpdateView class and my model has a unique field called name.
My code:
from django.views.generic.edit import UpdateView
class MyForm(NgModelFormMixin, Bootstrap3FormMixin, NgModelForm):
scope_prefix='form_data'
form_name = 'my_form'
class Meta:
model = models.MyModel
fields = ['name','person']
class MyModelUpdate(UpdateView):
model = models.MyModel
form_class = MyForm
def post(self, request, **kwargs):
if request.is_ajax():
return self.ajax(request, **kwargs)
return super(MyModelUpdate, self).post(request, **kwargs)
# from the djangular combined_validation example
def ajax(self, request, **kwargs):
# tbd: need update-specific logic here: pass in instance
# parameter (object) or set it from pk. Base class post
# methods use self.get_object()
form = self.form_class(data=json.loads(request.body))
return JsonResponse({'errors': form.errors,
'success_url': force_text(self.success_url)})
What code do I need to get Django to load the instance identified by the pk argument and attach it to the form. That would be the default behavior when the request data comes from POST rather than ajax?
After trial and error experimentation I came up with the following new implementation for the view's ajax method. It passes my tests but feels clunky.
def ajax(self, request, **kwargs):
form = self.form_class(data=json.loads(request.body),
instance=self.get_object())
try:
form.save()
except:
# error is in form.errors
pass
return JsonResponse({'errors': form.errors,
'success_url': force_text(self.success_url)})

Is there a way to handle requests with locale-dependant wsgi handlers?

Is there a way to handle requests from different geographic locations with a different WSGI handler? Specifically I want to allow all requests from one local (US) and redirect all others to a holding page i.e. something like
application_us = webapp2.WSGIApplication([
('/.*', MainHandler)
], debug=DEBUG)
application_elsewhere = webapp2.WSGIApplication([
('/.*', HoldingPageHandler)
], debug=DEBUG)
I'm aware of X-AppEngine-Country however I'm not quite sure how to put it to use in this case?
Okay, building the answer by Sebastian Kreft I figured it's probably easiest to throw this into a base handler of which every other handler is a subclass as follows.
class BaseHandler(webapp2.RequestHandler):
def __init__(self, *args, **kwargs):
super(BaseHandler, self).__init__(*args, **kwargs)
country = self.request.headers.get('X-AppEngine-Country')
if not country == "US" and not country == "" and not country == None: # The last two handle local development
self.redirect('international_holding_page')
logging.info(country)
This is more in keeping with DRY though I'm not certain it's the most efficient way of doing this.
What you need to do is to have only one app and in the handler redirect the user to a HoldingPageHandler if the country is not supported.
See Is it possible to use X-AppEngine-Country within an application. There they explain how to get the country
country = self.request.headers.get('X-AppEngine-Country')
So your handler would be something like this
class MainHandler(webapp2.RequestHandler):
def get(self):
country = self.request.headers.get('X-AppEngine-Country')
if country != "US":
self.redirect_to('hold') #assuming you have a route to hold
# your logic

How can I pass data to a GAE base template?

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

Resources