I want to do user finder using python django - python

class ForgotidAPI(generics.GenericAPIView):
serializer_class = ForgotidSerualizer
def post(self, request, *args, **kwargs):
Email = request.data.getlist('email')
First_name = request.data.getlist('first_name')
test = User.objects.get(email=Email)
print('e-mail : ', Email);
print('your name' : , First_name);
print('test : ', test)
return Response(
{
"email": "test",
"first_name": "test",
}
)
I would like to compare the saved emails to the emails I sent and print the user accordingly.
Only the statement'test = User.objects.get (email = Email)' is not executed. How do you run it?

Okay, the problem is strange and it was solved by using filter() in place of get(). So:
test = User.objects.filter(email=Email)
#handsomecode Don't use capitalize letter as variable as you did for Email = request.data.getlist('email') it's a bad practice, define variables with lowercase letters.

Related

Django: AuthStateMissing at /oauth/complete/google-oauth2/

I am using social-auth-app-django for GoogleOauth2 authentication. It works fine for all users but in case of django admin it gives me following error:
AuthStateMissing at /oauth/complete/google-oauth2/
Session value state missing.
I have tried all answers posted on stackoverflow but the error still persists. This is the result it returns.
The state value seems to be present there but either it gets null or overridden somehow.
This is my GoogleOAuth2 class, created by overriding social-auth-app-django's GoogleOAuth2 class. Though there is not much difference except for pipeline from base class. It works fine for non-admin user login.
class GoogleOAuth2(GoogleOAuth2):
"""Google OAuth2 authentication backend"""
name = 'google-oauth2'
REDIRECT_STATE = False
AUTHORIZATION_URL = 'https://accounts.google.com/o/oauth2/auth'
ACCESS_TOKEN_URL = 'https://accounts.google.com/o/oauth2/token'
ACCESS_TOKEN_METHOD = 'POST'
REVOKE_TOKEN_URL = 'https://accounts.google.com/o/oauth2/revoke'
REVOKE_TOKEN_METHOD = 'GET'
# The order of the default scope is important
DEFAULT_SCOPE = ['openid', 'email', 'profile']
EXTRA_DATA = [
('refresh_token', 'refresh_token', True),
('expires_in', 'expires'),
('token_type', 'token_type', True)
]
def pipeline(self, pipeline, pipeline_index=0, *args, **kwargs):
out = self.run_pipeline(pipeline, pipeline_index, *args, **kwargs)
user_ip = get_request_ip_address(self.strategy.request)
if not isinstance(out, dict):
return out
user = out.get('user')
if user:
user.social_user = out.get('social')
user.is_new = out.get('is_new')
if user.is_new:
logger.info(f'Register attempt', extra={"email": user.email, "remote_ip": user_ip, "status": "success", "user_id": user.pk, "oauth_backend": "google"})
else:
logger.info(f'Login attempt', extra={"email": user.email, "remote_ip": user_ip, "status": "success", "user_id": user.pk, "oauth_backend": "google"})
return user
I have tried following solutions, setting these values in settings.py file:
SOCIAL_AUTH_REDIRECT_IS_HTTPS = True
SESSION_COOKIE_SAMESITE = None
SESSION_COOKIE_HTTPONLY = False

How to pass arguments to HTML form using flask in case of redirection

I want to pass some arguments to my HTML form from flask when using redirect(url_for('Some End-Point')) instead of render_template(). I have already visited both of these questions
redirect while passing arguments
How can I pass arguments into redirect(url_for()) of Flask?
but neither of them had the answer I am looking for. After some surfing I do find out that I have to use session for this but the problem is I don't know actually how to use that either. When I use this:
return redirect(url_for('register', neg_resp="Username Already Taken"))
the problem was, my output message do generate but came with URL instead and thus my jinja template doesn't receive it. Link from 120.0.0.1:5000/register/ changed to 120.0.0.1:5000/register/?=Username Already Taken
And when I do this:
return redirect(url_for('register'), neg_resp="Username Already Taken")
An error gets generated, TypeError: redirect() got an unexpected keyword argument 'neg_resp'
Here's my Python Code
# Setting Up Route for Register Page
#app.route('/register/', methods=['GET', 'POST'])
def register():
# Fetching Form Data
user = {
"name": request.form.get('name'),
"email": request.form.get('email'),
"username": request.form.get('username'),
"password": request.form.get('password'),
"tasks":[]
}
# Inserting data to Database and Redirecting to Login Page after Successful Registration
if user['name'] != None:
user['password'] = pbkdf2_sha256.encrypt(user['password'])
if mongo.db.appname.find_one({"username": user["username"]}):
return redirect(url_for('register'), neg_resp="Username Already Taken")
else:
mongo.db.appname.insert(user)
return redirect(url_for('login', pos_resp="Registered Successfully"))
return render_template('register.html')
Error
TypeError: redirect() got an unexpected keyword argument 'neg_resp'
This won't work:
return redirect(url_for('register'), neg_resp="Username Already Taken")
because it passes neg_resp as a parameter of redirect instead of url_for.
Here's a basic example of how to pass parameters between routes and to a template:
#app.route('/first/')
def first():
return redirect(url_for('second', passed_value='string value'))
#app.route('/second/')
def second():
passed_value = request.args.get('passed_value')
return render_template('index.html', val_name=passed_value)
So here's what I tried, I made a global dictionary and keep updating it wherever needed, now whenever I want to access some values I directly access it from my dictionary and render it using jinja templating. Apart from this method there are other ways as well like storing data in flask.session also one can use flask.flash() to render messages and access them using messages.get() function in their jinja template, but the problem with it is, it only provides a limited amount of size, if you pass an object or string of beyond that size, the browser simply ignores it and your messages will not be displayed because the message passed is in the form of browser-cookies. So, storing them in my global dictionary works for me:
Here's a small snippet of my final code which similarizes the code I have posted as question:
# Globals
info = {
'logged_in' : False,
'user' : {},
'tasks' : [],
'status' : {
'value' : '',
'positive' : True
}
}
def reset():
'''
function to reset the values of info object
'''
global info
info['logged_in'] = False
info['user'] = {}
info['tasks'] = []
info['status'] = {
'value' : '',
'positive' : True
}
# Setting Up Route for Register Page
#app.route('/register/', methods=['GET', 'POST'])
def register():
'''
function to register an account into the server and database
'''
global info
# Fetching Form Data
user = {
"name": request.form.get('name'),
"email": request.form.get('email'),
"username": request.form.get('username'),
"password": request.form.get('password'),
"tasks":[]
}
# Inserting data to Database and Redirecting to Login Page after Successful Registration
if user['name'] != None:
user['password'] = pbkdf2_sha256.encrypt(user['password'])
if mongo.db.appname.find_one({"username": user["username"]}):
info['status']['value'] = 'Username Already Taken'
info['status']['positive'] = False
return redirect(url_for('register'))
else:
mongo.db.appname.insert(user)
info['status']['value'] = 'Registered Successfully'
info['status']['positive'] = True
return redirect(url_for('login'))
status_val = info['status']['value']
positive_status = info['status']['positive']
reset()
return render_template('register.html', value = status_val, positive = positive_status)

How to use postman to upload DBRef data in json?

I'm trying to post data to mongodb using postman but I don't know the proper convention for uploading the reference to a image file in the fs.files bucket. Basically, the file is already in the database, I'm just trying to post a new user with the reference to the image.
Here is my model:
class Users(db.Document):
_id = db.StringField()
name = db.StringField()
picture = db.FileField()
email = db.StringField()
password = db.StringField()
meta = {'collection': 'Users'}
In postman, I try to post data like so:
{
"_id" : "1",
"name" : "John Doe",
"picture": [{"$id": "5e6a...f9q102"}], #This is the reference id for the image already in the database, in fs.files
"password" : "<hashed pw>",
"email" : "example#example.com"
}
I'm using flask restful api so in the python script, the post function is defined like so:
def post(self):
body = request.get_json()
print (body)
user = Users()
user = Users(**body).save()
return 'Successful Upload', 200
I get the error when I try with the above convention:
mongoengine.errors.ValidationError: ValidationError (Users:None) ('list' object has no attribute
'grid_id': ['picture'])
How do I post a new user in postman? Your help is appreciated
You need to change a bit your code
Add these imports:
from mongoengine.fields import ImageGridFsProxy
from mongoengine import ReferenceField, DynamicDocument
from bson.dbref import DBRef
from bson import ObjectId
Modify your class picture field definition + add extra class fs
class Fs(DynamicDocument):
#Add 'db_alias':'default' to meta
meta = {'collection': 'fs.files'}
class Users(Document):
...
picture = ReferenceField('Fs', dbref=True)
...
Now, you need to create new instance for DBRef this way:
def post(self):
body = request.get_json()
body["picture"] = DBRef('fs.files', ObjectId(body["picture"]))
#mongoengine assumes `ObjectId('xxx')` already exists in `fs.files`.
#If you want to check, run below code:
#if Fs.objects(_id=body["picture"].id).first() is None:
# return 'Picture ' + str(body["picture"].id) + ' not found', 400
user = Users(**body).save()
return 'Successful Upload', 200
At the end, if you need to read picture content:
image = ImageGridFsProxy(grid_id=ObjectId('xxx'))
f = open("image.png", "wb")
f.write(image.read())
f.close()
It was a Validation error. The database was accepting JSON in a particular format than what I was posting. And the way I was processing the post request was also incorrect. This is the format it expected:
{
...,
"picture" = {"$ref": "fs.files",
"$id": ObjectId("5e6a...f9q102")},
...
}
Postman cannot accept the above format, instead, it accepted this:
{
"_id" : "1",
"name" : "John Doe",
"picture": {"$ref": "fs.files", "$id": {"$oid": "5e6a...f9q102"}},
"password" : "<hashed pw>",
"email" : "example#example.com"
}
To make this work I changed the model to look this so in my flask app:
class Users(db.Document):
_id = db.StringField()
name = db.StringField()
picture = db.ReferenceField('fs.files') #I changed this to a reference field because it holds the reference for the file and not the actual file in the database
upload_picture = db.FileField() #I added this field so I can still upload pics via flask and via this document
email = db.StringField()
password = db.StringField()
meta = {'collection': 'Users'}
Then I had to add this import and change the code so that it would read the input as JSON and transfer the reference value of picture to ObjectId(id) so that it matches the format the database was expecting.
from bson.json_util import loads
def post(self):
body = str(request.get_json())
x = body.replace("'", '"') #replace single quotes as double quotes to match JSON format
data = loads(x)
officer = Officers(**data).save()
return 'Successful Upload', 200
Then voila, it works!

odoo-12 : How to solve the write() method problem

In my case i inherited the crm form and add one mamy2many field this name [Estimation Assign to] when i select the users from this field and save the record that time selected users are added in Add Followers and also send the mail. Now problem is that when i change the kanban card from one stage to another stage that time if in form estimation field assigned some users the mail are also send those users.
but i want to send mail only when i'm open the record and select the users from estimation field and then click on save button only that i want to sand mail. not when i change the kanban card from one stage to another stage.                                                         
if you know it please let me know.
#api.model
def create(self, vals):
lead_res = super(CrmLead, self).create(vals)
for rec in lead_res:
if rec.estimation_id:
partner_ids = []
for est_rec in rec.estimation_id:
if est_rec.partner_id and est_rec.partner_id.email:
user_name = self.env.user.name_get()[0][1]
partner_ids.append(est_rec.partner_id.id)
template_obj = self.env['mail.mail']
template_data = {
'subject': 'New Estimation Asign : ',
'body_html': "Hello,</br><h5>" + user_name + " invited you to follow Lead/Opportunity document : " + rec.name + "</h5>",
'email_from': self.env['mail.message']._get_default_from(),
'email_to': est_rec.partner_id.email
}
template_id = template_obj.create(template_data)
template_obj.send(template_id)
if partner_ids:
rec.message_subscribe(partner_ids, None)
return lead_res
#api.multi
def write(self, vals):
res = super(CrmLead, self).write(vals)
for rec in self:
if rec.estimation_id:
partner_ids = []
for est_rec in rec.estimation_id:
if est_rec.partner_id and est_rec.partner_id.email:
user_name = self.env.user.name_get()[0][1]
partner_ids.append(est_rec.partner_id.id)
template_obj = self.env['mail.mail']
template_data = {
'subject': 'New Estimation Asign : ',
'body_html': "Hello,</br><h5>" + user_name + " invited you to follow Lead/Opportunity document : " + rec.name + "</h5>",
'email_from': self.env['mail.message']._get_default_from(),
'email_to': est_rec.partner_id.email
}
template_id = template_obj.create(template_data)
print('===================To sent ==================', est_rec.partner_id.email)
template_obj.send(template_id)
rec.message_subscribe(partner_ids, None)
#message_unsubscribe
message_partner_ids = rec.message_partner_ids.ids
est_ids = [est_rec.partner_id.id for est_rec in rec.estimation_id] + [self.env.ref('base.partner_root').id]
unsub_partners = set(message_partner_ids) - set(est_ids)
if list(unsub_partners):
rec.message_unsubscribe(list(unsub_partners))
else:
print("+++++============= Else Part =============+++++")
return res
Try to add another condition to send mails when estimation_id has changed.
if u'estimation_id' in vals and rec.estimation_id:
EDIT
The following code will compute the new added users:
user_ids = {rec.id: [user_id.id for user_id in rec.estimation_id] for rec in self}
res = super(CrmLead, self).write(vals)
for rec in self:
new_user_ids = [user.id for user in rec.estimation_id if user.id not in user_ids[rec.id]]

DataRequired validator is broken for wtforms.BooleanField

I'm using WTForms (together with Flask, flask-wtf, sqlalchemy) to validate incoming JSON for REST APIs. I realize that WTForms is aimed more towards HTML form rendering and validation, but I chose it because it can autogenerate forms out of my sqlalchemy models (thanks to wtforms.ext.sqlalchemy).
Anyway, here is the problem. One of my models includes boolean field which translates to wtforms.BooleanField with DataRequired validator. The issue is that validation fails with 'This field is required' error message even if I pass correct data. My Form:
class MyForm(Form):
name = TextField('name', validators=[DataRequired()])
disabled = BooleanField('disabled', validators=[DataRequired()])
JSON data is like this:
'{"name": "John", "disabled": "false"}'
What I'm expecting:
{"disabled": "false"} -> validates successful, coerced Python data: {'disabled': False}
{"disabled": "true"} -> validates successful, coerced Python data: {'disabled': True}
{"disabled": ""} or '{"disabled": "foo"}' -> fails validation
Currently in first case validation is failed with {'disabled': [u'This field is required.']}
I know there is a note in docs that says DataRequired validator "require coerced data, not input data", but 1) the form is autogenerated by wtforms.ext.sqlalchemy and 2) how it is supposed to behave if I use InputRequired validator? Check (via form.validate()) that some data exists and then check that this data is "true" or "false"?
To summarize, my question is:
What is the correct way of validating wtforms.BooleanField?
Maybe there is some other framework that can validate incoming JSON against given sqlalchemy models?
Thanks.
There are a number of ways of going about this. You could write your own converter to make of use a radiofield with true/false choices, you could use a data filter, you could set a default value, but I think the behavior you want will be possible with this:
MyForm = model_form(MyModel, db_session=db, field_args = {
'disabled' : {
'false_values': ['false'],
'validators' : [InputRequired()] }
})
EDIT: If you wanted a stricter handler you could do the following:
class BooleanRequired(object):
field_flags = ('required', )
def __init__(self, message=None):
self.message = message
def __call__(self, form, field):
if field.data is None:
if self.message is None:
message = field.gettext('This field is required.')
else:
message = self.message
field.errors[:] = []
raise StopValidation(message)
class StrictBooleanField(BooleanField):
def process_formdata(self, valuelist):
self.data = None
if valuelist:
if valuelist[0] == 'false':
self.data = False
elif valuelist[0] == 'true':
self.data = True
class StrictModelConverter(ModelConverter):
#converts('Boolean')
def conv_Boolean(self, field_args, **extra):
return StrictBooleanField(**field_args)
MyForm = model_form(MyModel, db_session=db, converter=StrictModelConverter(),
field_args = { 'disabled' : { 'validators': [BooleanRequired()] }
})

Categories