Wagtail formbuilder submissions are not sending emails - wagtail

Contact form data (using Wagtail's formbuilder) is not sending to email what is the issue?
I added email host also but not sending data to email
The form response (contact data) is being saved in wagtail admin but data not sending to email.
Console Output
DEBUG CONSOLE
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: contact form submission
From: archanapco8#gmail.com
To: ranjuranjitha. 1997#gmail.com
Date: Mon, 08 Nov 2021 08:13:45 -0000
Message-ID: <163635922547.9304.15785246130187863651#DESKTOP-NC1TOGR>
Auto-submitted: auto-generated
Your Name: ranjitha
Your company: mdrift
Your email address: rmanju#dgmail.com
When do you want to start?: 20-09-2021
What is your budget: 1000
Describe your needs, the more we know, the better: hi
[08/Nov/2021 13:43:45] "POST /contact-us/ HTTP/1.1" 200 9590
[08/Nov/2021 13:43:45] "GET /static/img/Thank-you.png HTTP/1.1" 200 15470
O
contact/models.py
from wagtail.contrib.forms.models import AbstractEmailForm, AbstractFormField
class FormField(AbstractFormField):
page = ParentalKey('Form Page', related_name='custom_form_fields')
class Form Page(AbstractEmailForm):
thank_you_text = RichTextField(blank=True)
content_panels = AbstractEmailForm.content_panels + [
InlinePanel('custom_form_fields', label="Form fields"),
FieldPanel('thank_you_text', classname="full"),
MultiFieldPanel([
FieldRowPanel([
FieldPanel('from_address', classname="col6"),
FieldPanel('to_address', classname="col6"),
]),
FieldPanel('subject'),
], "Email Notification Config"),
]
def get_form_fields(self):
return self.custom_form_fields.all()
form_page.html
{% load static wagtailcore_tags widget_tweaks %}
{% block content %}
<h1>Contact</h1>
<br>
<form action="{% pageurl page %}" method="POST">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% endif %}
{% for field in form.visible_fields %}
<div class="form-group">
{{ field.label_tag }}
{% render_field field class+="form-control" %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary" >Submit</button>
</form>
{% endblock %}
settings/base.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'ranjuranjitha.1997#gmail.com'
EMAIL_HOST_PASSWORD = 'Password$'
EMAIL_USE_TLS = True
EMAIL_USE_SSL = True
DEFAULT_FROM_EMAIL ='ranjuranjitha.1997#gmail.com'
EMAIL_TO = 'ap8366106#gmail.com'
This is dev.py file. I given email backend also but not sending the mail.
settings/dev.py
from .base import *
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-iu22rfee4za6ro+mez!4*#_trpy7!ebpbtu8iw$95v(rh_5fib'
# SECURITY WARNING: define the correct hosts in production!
ALLOWED_HOSTS = ['*']
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
try:
from .local import *
except ImportError:
pass

A few potential solutions below.
1. dev mode settings
Based on your log output and your settings/dev.py file, it appears that the email is working but is just logging the email.
In the dev settings you have EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend', this is a normal dev setup and leverages the Email Console backend which will never actually send an email but just log the email output to the console (terminal).
This means, while in development mode you can easily check the email content without actually sending a real email.
To temporarily override this you can create a file settings/local.py and put a different email backend in that file.
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
Then restart your dev server and it should use the override in the local.py file.
This works because of the settings/dev.py code you already have
try:
from .local import *
except ImportError:
pass
Note: Ensure that your settings/local.py is not committed to your code (git) as this may contain private secrets/passwords etc and usually is just a quick way to test something different.
Refer to this answer about managing Django settings for more insights. It would be good to read the full documentation page end to end that explains how sending email works in Django also.
2. Gmail settings
Check you have ensured that your Gmail will allow SMTP sending? You need to ensure less secure apps are enabled - support.google.com/accounts/answer/6010255?hl=en
See also How to send Django emails with SMTP for more details.
However, using Gmail for this purpose is quite risky and likely to be blocked by Gmail and have spam issues. It is recommended you use a third party service, see some recommendations for third party email services.

Related

My urls no longer point to my pages Wagtail

On a wagtail site I have lost links to my blog pages (possibly as a result of moving to a newer version)
My blog listing page is still accessible with the url "http://localhost:8080/blog/"
I have the following models
class BlogListingPage(Page):
template = "home/blog_listing_page.html"
subpage_types = ['home.BlogDetailPage']
blog_listing_title = models.CharField(
max_length=100,
blank=False,
null=False,
help_text="Heading for the blog listing page",
)
content_panels = Page.content_panels + [
FieldPanel("blog_listing_title"),
]
class BlogDetailPage(Page):
"""Blog detail page."""
template = "home/blog_detail_page.html"
parent_page_types = ['home.BlogListingPage']
blog_title = models.CharField(
max_length=100,
blank=False,
null=True,
help_text="Blog title (100 chars max)",
)
content_panels = Page.content_panels + [
FieldPanel("blog_title"),
]
I can list the blog pages in my blog listing page:
{{ blog_listing.get_children.specific}}
{% for blog in blog_listing.get_children.live %}
<h5>{{ blog.specific.blog_title}}</h5>
<h5>{{ blog.slug }}</h5>
{% endfor %}
The slug displays correctly (e.g. /blog/xxx/) but the pageurl blog is None and if I click on it I get a 404 error (Request URL: http://localhost:8080/blog/xxx/)
Finally, even if I put http://localhost:8080/blog/xxx/ in the browser I get a 404 error
The line
{{ blog_listing.get_children.specific}}
displays the page queryset with the list of wagtail.core.models.Pages as I would expect
If I enter the following code into views
views.py
pqs = BlogListingPage.objects.all()
children = pqs.live()[0].get_children()
for child in children:
print('s', child.slug, '|', child.url_path)
I get the output
s xxx | /blog/xxx/
Which is what I expect.
Why are the pages/links no longer in sync?
I cannot post an MRE because, ironically, when I try to construct one, it works as expected. I cannot see what the difference is with my live site, but if someone could point to where I might look it would help.

How to create an invisible dummy page in Wagtail?

How can I create an invisible dummy page in Wagtail?
I need a "virtual" page object within Wagtail to build a menu for non Wagtail based pages and also external resources. (See my entry post here)
class MenuDummyPage(Page):
menu_description = models.CharField(max_length=255, blank=True)
menu_icon = models.CharField(max_length=255, blank=True)
menu_link = models.CharField(max_length=255, blank=True)
settings_panels = [
FieldPanel('menu_description'),
FieldPanel('menu_icon'),
FieldPanel('menu_link'),
]
def get_sitemap_urls(self):
return []
def serve(self, request):
pass
If I create the above page object then it is not listed within the generated wagtail sitemap.
But if I navigate on my own to that page manually the object is called. How can I stop this?
Example:
If I create a MenuDummyPage with the title "This is a test" then the system will automatically generate a slug => "this-is-a-test".
If I call "/this-is-a-test"/ in my browser wagtail is answering because the slug exists. How can I remove this behavior for my "MenuDummyPage" objects?
If what you mean by a dummy page is a page under which other pages are kept in the page tree, then you could do the following:
from django.http import HttpResponseRedirect
class Node(Page):
subpage_types = [your subpage types]
parent_page_types = [your parent page types]
link = models.CharField(max_length=255, default='', blank='True')
content_panels = Page.content_panels + [
FieldPanel('link')
]
def serve(self, request):
if self.link is not None:
return HttpResponseRedirect(self.link)
# To handle the situation where someone inadvertantly lands on a parent page, do a redirect
first_descendant = self.get_descendants().first()
if first_descendant:
return HttpResponseRedirect(first_descendant.url)
else:
return HttpResponseRedirect(request.site.root_page.url)
The optional link field allows you to define a link if you wish for this position in the page tree structure. The above, again, assumes that you are using this Page-based item as a placeholder in the Page tree so that you can have other Pages under it. As long as you don't render the url of this page in your template, then users should never know how to get to the url for the Node, but if someone does get to the url for a Node-type page, then the first_descendant logic handles this situation by sending them to either the first descendant of the Node or to the home page if no descendants of Node exist.
In your template (note the use of specific_class):
{% for item in menu_items %}
<li>
<a href="{% if item.specific.link and item.specific.link != '' %}{{ item.specific.link }}{% elif item.specific_class == 'Node'%}#{% else %}{% pageurl item %}{% endif %}">{{ item.title }
</a>
</li>
{% endfor %}

delete function need write user into useredit

every one I got
models.py
....
class ProductsTbl(models.Model):
.....
slug = models.SlugField(unique=True)
user = models.ForeignKey(User, blank=True, null=True)
useredit = models.CharField(max_length=32, blank=True, null=True)
image = models.ImageField(upload_to=get_imagep_Product, blank=True)
def __unicode__(self):
return self.name
def save(self, *args, **kwargs):
''' On save, update timestamps '''
if not self.id:
self.created = timezone.now()
return super(ProductsTbl, self).save(*args, **kwargs)
def get_image_path(instance, filename):
return '/'.join(['thing_images', instance.thing.slug, filename])
class Upload(models.Model):
thing = models.ForeignKey(ProductsTbl, related_name="uploads")
image = models.ImageField(upload_to=get_image_path) #delete or upload image for this one
def save(self, *args, **kwargs):
super(Upload, self).save(*args, **kwargs)
if self.image:
image = Image.open(self.image)
i_width, i_height = image.size
max_size = (640,480)
if i_width > 1000:
image.thumbnail(max_size, Image.ANTIALIAS)
image.save(self.image.path)
and I got the views.py function it is for delete the image in class Upload(models.Model) of models.py,
views.py
.....
#login_required
def delete_upload(request, id):
# grab the image
upload = Upload.objects.get(id=id)
upload.thing.useredit = request.user.username
upload.save()
# security check
# if upload.thing.user != request.user:
# raise Http404
# delete the image
upload.delete()
# refresh the edit page
return redirect('edit_thing_uploads', slug=upload.thing.slug)
what I have to do is when I delete the image I have to write the "user" into the
"useredit".
however,,when never I delete the image the "user" won't write into "useredit"
,,in contrast,here is my
edit_thing_uploads.html
{% extends 'base.html' %}
{% block title %}
Edit {{ thing.name }}'s Images - {{ block.super }} {% endblock %}
{% block content %}
<h1>Edit {{ thing.name }}'s Images</h1>
<h2>Uploaded images</h2>
{% for upload in uploads %}
<img src="{{ upload.image.url }}" alt="" />
Delete
{% endfor %}
<h2>Upload a new image</h2>
<form role="form" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
when I upload an image it will write "user" into "useredit" successfully ,,the function for upload image in
views.py
#login_required
def edit_thing_uploads(request, slug):
# grab the object...
thing = ProductsTbl.objects.get(slug=slug)
# double checking just for security
# if thing.user != request.user:
# raise Http404
form_class = ProductsTblUploadForm
# if we're coming to this view from a submitted form,
if request.method == 'POST':
# grab the data from the submitted form, # note the new "files" part
form = form_class(data=request.POST,files=request.FILES, instance=thing)
if form.is_valid():
thing = form.save(commit=False)
thing.useredit = request.user.username
thing.save()
# create a new object from the submitted form
Upload.objects.create(
image=form.cleaned_data['image'],
thing=thing,
)
return redirect('edit_thing_uploads', slug=thing.slug)
# otherwise just create the form
else:
form = form_class(instance=thing)
# grab all the object's images
uploads = thing.uploads.all()
# and render the template
return render(request, 'things/edit_thing_uploads.html', {
'thing': thing,
'form': form,
'uploads': uploads,
})
however,,I have to let the "user" into "useredit" when I delete also,,,how can I do it? thank you!
I solve the problem
views.py
#login_required
def delete_upload(request, id):
# grab the image
upload = Upload.objects.get(id=id)
upload.thing.useredit = request.user.username
upload.thing.save()
# security check
# if upload.thing.user != request.user:
# raise Http404
# delete the image
upload.delete()
# refresh the edit page
return redirect('edit_thing_uploads', slug=upload.thing.slug)

Why is current_user None?

I have a horrible bug that I put a bounty on and now I'm reducing to the simplest case of reproduction. At least a can reproduce it :D Some info: The entity FUser does not populate an entity, the javascript button switches between login / logout apprioriately and from the log you might be able to tell me what's wrong with the flow.
2011-10-04 17:34:14.398 /example 200 10ms 0cpu_ms 0kb Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20100101 Firefox/4.0
213.89.134.0 - - [04/Oct/2011:13:34:14 -0700] "GET /example HTTP/1.1" 200 694 - "Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20100101 Firefox/4.0" "www.koolbusiness.com" ms=11 cpu_ms=0 api_cpu_ms=0 cpm_usd=0.000157 instance=00c61b117c837db085d58acd70ffae167a06
D 2011-10-04 17:34:14.395
logging current_userNone
.py
"""A barebones AppEngine application that uses Facebook for login."""
FACEBOOK_APP_ID = "164355773607006"
FACEBOOK_APP_SECRET = "642f15e4324b45661e1049d5b139cb0"
import facebook
import os.path
import wsgiref.handlers
import logging
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import template
class FUser(db.Model):
id = db.StringProperty(required=True)
created = db.DateTimeProperty(auto_now_add=True)
updated = db.DateTimeProperty(auto_now=True)
name = db.StringProperty(required=True)
profile_url = db.StringProperty(required=True)
access_token = db.StringProperty(required=True)
class BaseHandler(webapp.RequestHandler):
"""Provides access to the active Facebook user in self.current_user
The property is lazy-loaded on first access, using the cookie saved
by the Facebook JavaScript SDK to determine the user ID of the active
user. See http://developers.facebook.com/docs/authentication/ for
more information.
"""
#property
def current_user(self):
if not hasattr(self, "_current_user"):
self._current_user = None
cookie = facebook.get_user_from_cookie(
self.request.cookies, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET)
logging.debug("logging cookie"+str(cookie))
if cookie:
# Store a local instance of the user data so we don't need
# a round-trip to Facebook on every request
user = FUser.get_by_key_name(cookie["uid"])
logging.debug("user "+str(user))
if not user:
graph = facebook.GraphAPI(cookie["access_token"])
profile = graph.get_object("me")
user = FUser(key_name=str(profile["id"]),
id=str(profile["id"]),
name=profile["name"],
profile_url=profile["link"],
access_token=cookie["access_token"])
user.put()
elif user.access_token != cookie["access_token"]:
user.access_token = cookie["access_token"]
user.put()
self._current_user = user
return self._current_user
class HomeHandler(BaseHandler):
def get(self):
path = os.path.join(os.path.dirname(__file__), "example.html")
logging.debug("logging current_user"+str(self.current_user))
args = dict(current_user=self.current_user,
facebook_app_id=FACEBOOK_APP_ID)
self.response.out.write(template.render(path, args))
def main():
util.run_wsgi_app(webapp.WSGIApplication([(r"/example", HomeHandler)]))
if __name__ == "__main__":
main()
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Facebook Example</title>
</head>
<body>
<fb:login-button autologoutlink="true"></fb:login-button>
{% if current_user %}
<p><img src="http://graph.facebook.com/{{ current_user.id }}/picture?type=square"/></p>
<p>Hello, {{ current_user.name|escape }}</p>
{% endif %}
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function() {
FB.init({appId: '{{ facebook_app_id }}', status: true, cookie: true,
xfbml: true});
FB.Event.subscribe('{% if current_user %}auth.logout{% else %}auth.login{% endif %}', function(response) {
window.location.reload();
});
};
(function() {
var e = document.createElement('script');
e.type = 'text/javascript';
e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
e.async = true;
document.getElementById('fb-root').appendChild(e);
}());
</script>
</body>
</html>
Update
I still don't get the user object and changed the HomeHandler to this
class HomeHandler(BaseHandler):
def get(self):
path = os.path.join(os.path.dirname(__file__), "example.html")
logging.debug("logging current_user"+str(self.current_user))
args = dict(current_user=self.current_user,
facebook_app_id=FACEBOOK_APP_ID)
user = facebook.get_user_from_cookie(self.request.cookies, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET)
if not user:
logging.debug("no user")
if user:
graph = facebook.GraphAPI(user["access_token"])
profile = graph.get_object("me")
friends = graph.get_connections("me", "friends")
logging.debug("logging profile"+str(profile))
self.response.out.write(template.render(path, args))
Relating to #Shay Erlichmen's observation, the above code shouldn't work due to facebook's changes of a few days ago. As I pointed out on your original question, there is a version of the facebook python SDK which has been modified to support the new authentication mechanism - see
https://gist.github.com/1190267
The specific place where this differs from the old version is in the get_user_from_cookie() method. If you're still using the old version of the facebook python SDK, this should look for an fbs_APPID cookie, not find it and return None - hence cookie is never assigned a value _current_user retains the None state assigned at the start of the method.
One check you can do is to have a look at the cookies in your browser - you should see the new fbsr_APPID cookies which are not handled by the old library.
Facebook switched to OAuth2.0 on October 1,2011, this code is old and should work anymore.

Configuring MIME type

Hi I want to configure my mime type:
The MIME type for KML files is
* application/vnd.google-earth.kml+xml
How can I do this with google app engine? I generate KML on a template that looks like this:
<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
<Document>{% for article in articles %}{% if article.geopt %}
<Placemark><name></name>
<description>
<![CDATA[{% if article.kmluri2view %}<img src="http://{{host}}/images/{{ article.kmluri2view.key.id }}.jpg">{% endif %} {{ article.title }} <br/>{{article.text}}]]></description><Point><coordinates>{{article.geopt.lon|floatformat:2}},{{article.geopt.lat|floatformat:2}}</coordinates></Point>
</Placemark>{% endif %}{% endfor %}
</Document>
</kml>
Updated the code I try set the MIME type like below. How can I verify it works?
class KMLHandler(webapp.RequestHandler):
def get(self):
start=datetime.datetime.now()-timedelta(days=10)#vary
host = os.environ.get("HTTP_HOST", os.environ["SERVER_NAME"])
logging.debug('host '+host)
count = int(self.request.get('count')) if not self.request.get('count')=='' else 1000
from google.appengine.api import memcache
memcache.flush_all()
memcache_key = "ads"
data = memcache.get(memcache_key)
if data is None:
a= Ad.all().filter("modified >", start).filter("url IN", ['www.koolbusiness.com']).filter("published =", True).order("-modified").fetch(count)
memcache.set("ads", a)
else:
a = data
dispatch='templates/kml.html'
template_values = {'a': a , 'request':self.request, 'host':host}
path = os.path.join(os.path.dirname(__file__), dispatch)
self.response.headers['Content-Type'] = 'application/vnd.google-earth.kml+xml'
self.response.out.write(template.render(path, template_values))
Simply set the Content-Type header in the response to the mimetype you want. If you're using webapp, for instance, you do it like this:
self.response.headers['Content-Type'] = 'application/vnd.google-earth.kml+xml'

Resources