Display messages/notifications in NetBox - django

I would like some help with messages in NetBox, please. I'm writing a custom validator and I need to display a warning message if for example a device name doesn't fit the company's policy. I can't use the standard fail method in the CustomValidator class - the edit request should be fulfilled, it's just supposed to warn the user as well. I would like to use a box message like this one, just with the warning level.
I tried something like this:
from extras.validators import CustomValidator
from django.contrib import messages
class device_validator(CustomValidator):
def validate(self, instance):
if instance.name is not instance.name.upper():
messages.info(request, "Names of devices should be in all-caps.")
return
But clearly, my syntax is wrong. I get the "Server Error" window and following message:
<class 'NameError'>
name 'request' is not defined
How do I define the request? Could someone please give me an example how to display a message in this context?
Thank you.

request probably needs to be self.request
messages.info(self.request, "Names of devices should be in all-caps.")

Related

Store messages after showing in the template

I would like to store the last messages to get a chance for the user to check it again.
How can I save it, after show? before show? Do I need to implement a db model?
you can use redis,
Redis might come in handy.
I found a nice solution, without using external library. Just with my lovely python!
First I create a function to store the messages into a database:
def save_messages(message):
db.objects.add(ManyToMany.object.create(message))
return redirect('message_saved')
and then I put the function to run anytime a message is being sent into contrib messages itself
MYPROJECT\venv\Lib\site-packages\django\contrib\messages\api.py
def add_message(request, level, message, extra_tags='', fail_silently=False):
"""
Attempt to add a message to the request using the 'messages' app.
"""
try:
messages = request._messages
except AttributeError:
if not hasattr(request, 'META'):
raise TypeError(
"add_message() argument must be an HttpRequest object, not "
"'%s'." % request.__class__.__name__
)
if not fail_silently:
raise MessageFailure(
'You cannot add messages without installing '
'django.contrib.messages.middleware.MessageMiddleware'
)
else:
from WALLAWALLA import save_messages
save_messages(message)
return messages.add(level, message, extra_tags)
and this really works great

Django How to add user info to Sentry's report when an error happened?

I use the django-restful framework and I want to add user info to Sentry's report when an error happened in the ModelViewSet.
I find this doc of Sentry:
https://docs.sentry.io/enriching-error-data/context/?_ga=1.219964441.1220115692.1472094716%3F_ga&platform=python#capturing-the-user
It gives some code as follows:
from sentry_sdk import configure_scope
with configure_scope() as scope:
scope.user = {"email": "john.doe#example.com"}
But I can not figure out how to properly use it. I think there exists a better way than the following:
#list_route()
def fun_xxx(self, request, *args, **kwargs):
user = request.user
with configure_scope() as scope:
scope.user = {"id": user.id,......}
...some code may cause an error...
return Response({...})
Can anyone give me some suggestions? :)
As mentioned in the comments, the Django integration will attach this particular data automatically.
As for the question on how to generally add data in a Django app, you are basically looking for something to run before each view. A Django middleware suits this:
def sentry_middleware(get_response):
def middleware(request):
with configure_scope() as scope:
...
response = get_response(request)
return response
return middleware
https://docs.djangoproject.com/en/2.2/topics/http/middleware/
As mentioned here: https://docs.sentry.io/platforms/python/guides/django/#configure
Set:
# If you wish to associate users to errors (assuming you are using
# django.contrib.auth) you may enable sending PII data.
send_default_pii=True,
while configuring the sentry in Django.
PII: Personal Identifiable Information
P.S. Don't forget to include django.contrib.auth in your installed_apps.

Passing a cause description to a 403 handler view

I want to show an informative error message to a user hitting a page that results in a 403 Forbidden. I'm using Django 1.8.
My idea of passing an error message is this:
# in a view
if not ...:
raise PermissionDenied('You have no power here')
Then somewhere in the handler403 view, I'd like to retrieve the message (or maybe even a structured object) and render an informative page based on it.
Though the handler seems to only receive the request object and the template name.
Is there a way to pass a custom message to the handler? (Of course I could assign a custom attribute to the request object before raising the exception, and hope that the same object will be passed to the handler, but this feels like a hack.)
Update: Indeed there is a middleware for that already: contrib/messages is capable of piggybacking messages on the request object, and more.
Looks like you would have to implement this using a middleware:
class ExceptionMiddleware:
def process_exception(self, request, exception):
if exception.args:
request.message = exception.args[0]
Then in your handler403 you could access request.message.
Obviously you could flesh-out this middleware to allow passing more than just a message to the view.

How to display a template/redirect to a template after processing a django signal?

I'm trying to integrate django-paypal, and I need to process a successful or failed signal.
I've got all my code done, but I now need to display a template telling the user their payment has succeeded or failed.
If I return HttpResponseRedirect... nothing happens, and I can't render_to_response because I don't have access to the context (and I'm using sekazai or something).
How can I do this?
## Called when django-paypal fails to validate PDT data
def pdt_failed_transaction(sender, **kwargs):
return HttpResponseRedirect(reverse('payment-error'))
Short answer: you can't. This isn't what signals are designed for. You'll need to work the validation code into your form and handle the responses in your view. That's the process.
Came across this question through a Google search and found the response pretty useless/unhelpful. I think this is a valid curiosity, and while Chris Pratt is correct that you cannot modify the request or response in signals, it does seem reasonable to want to run some code based on a user having just logged in.
To run some code only when someone logs in that contains a redirect, you can use an intermediary view and the LOGIN_REDIRECT_URL setting in your settings.py https://docs.djangoproject.com/en/dev/ref/settings/#login-redirect-url
in settings.py:
LOGIN_REDIRECT_URL = reverse_lazy('app.views.after_login')
in app/views.py:
#login_required
def after_login(request):
if conditions met:
return HttpResponseRedirect(reverse('home_alt'))
else:
return HttpResponseRedirect(reverse('home'))

Control a function (E.g send mail) from a users profile page

I have a profile page like so: http://i.stack.imgur.com/Rx4kg.png . In management I would like a option "Notify by mail" that would control my send_email functions in every application I want. As example I'm using django-messages and it sends private messages aswell as emails when you send a message. I would like for the user to be able to specify if he wants emails aswell when he gets a message.
messages/utils.py
def new_message_email(sender, instance, signal,
subject_prefix=_(u'New Message: %(subject)s'),
template_name="messages/new_message.html",
default_protocol=None,
*args, **kwargs):
"""
This function sends an email and is called via Django's signal framework.
Optional arguments:
``template_name``: the template to use
``subject_prefix``: prefix for the email subject.
``default_protocol``: default protocol in site URL passed to template
"""
if default_protocol is None:
default_protocol = getattr(settings, 'DEFAULT_HTTP_PROTOCOL', 'http')
if 'created' in kwargs and kwargs['created']:
try:
current_domain = Site.objects.get_current().domain
subject = subject_prefix % {'subject': instance.subject}
message = render_to_string(template_name, {
'site_url': '%s://%s' % (default_protocol, current_domain),
'message': instance,
})
if instance.recipient.email != "":
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL,
[instance.recipient.email,])
except Exception, e:
#print e
pass #fail silently
Apparently instance.recipient.email is the email for the recipient user. So my questions are: How do I go about creating an option in my profile management that can be used in my new_message_email to check if the user wants emails or not? My own thoughts are that I need to save a value in the database for the user and then check for that value in new_message_email function. How I do that isn't clear though. Do I create a new function in my userprofile/views.py and class in userprofile/forms.py? And have my userprofile/overview.html template change them? Some specifics and thoughts if this is the right approach would help alot!
You probably want to start off by creating a user profile so that you have a good way to store weather or not the user wants these emails sent to them. This is done using the AUTH_PROFILE_MODULE setting in your settings.py.
Once you have the data stored, you should be able to access it from instance.recipient (assuming that instance.recipient is a User object). So you could change your code to:
if instance.recipient.get_profile().wants_emails and instance.recipient.email != "":
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL,
[instance.recipient.email,])
Done and done.