I have a signal in my MessageFolder model which works fine, however in some special ocassions I don't want the post_save signal action to occur. How can I deactivate it in this case?
I have tried the following but it's not workign.
Views.py
signals.post_save.disconnect(receiver=MessageFolder,sender=Message)
email_message = EmailMessage(
subject,
message,
my_username,
[recipent,],
[], # ['bcc#example.com'],
headers = {'Reply-To': 'gusreyes01#example.com'}
)
signals.post_save.connect(MessageFolder,MessageFolder.assign_message_folder)
# Save it
my_mailbox.record_outgoing_message(
email_message.message()
)
Models.py
class MessageFolder(models.Model):
folder = models.ForeignKey(Folder, null = True, blank = True)
message = models.ForeignKey(Message, null = True, blank = True)
#receiver((post_save), sender=Message, dispatch_uid="assign_message_folder")
def assign_message_folder(sender, instance, created, **kwargs):
if not created:
return
else:
# generate MessageFolder && UserFolder
if(instance.outgoing):
message_folder = MessageFolder(None, 2, instance.pk)
else:
message_folder = MessageFolder(None, 1, instance.pk)
message_folder.save()
return
I've used the following and it works for me
Disconnect:
signals.post_save.disconnect(assign_message_folder, sender=MessageFolder)
Connect:
signals.post_save.connect(assign_message_folder, sender=MessageFolder)
Related
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
Here is my django model
class Data(models.Model):
created = models.DateTimeField(null=True, blank=True, editable=False)
modified = models.DateTimeField(null=True, blank=True)
raw = models.TextField(null=True, blank=True)
uuid = models.CharField(blank=True, null=True, max_length=48,unique=True)
used = models.BooleanField(default=False,null=True)
name = models.CharField(blank=True, null=True, max_length=200)
geohash = models.CharField(blank=True, null=True, max_length=200)
def __str__(self):
return str(self.created) + ":" + str(self.raw)
def __unicode__(self):
return str(self.created) + ":" + str(self.raw)
def save(self, *args, **kwargs):
""" On save, update timestamps """
if not self.uuid :
self.uuid = str(uuid.uuid4().hex) +str(random.randint(1000,9999) )
if not self.id:
self.created = timezone.now()
self.modified = timezone.now()
# if not self.geoHash and (self.gpsLat and self.gpsLong):
# Geohash.encode(self.gpsLat, self.gpsLong)
return super(DataLbc, self).save(*args, **kwargs)
def toJson(self):
ret = {}
ret["Created"] = str(self.created)
ret["Modified"] = str(self.modified)
ret["Used"] = self.used
ret["Raw"] = self.raw
return ret
Here is the way that i send it to my golang server :
from RawOffer.models import Data
while True:
try :
for data in Data.objects.all()[:10]:
requests.post("http://127.0.0.1:8087/convert/",json=data.toJson())
except Exception as e:
print(e)
time.sleep(5)
Now my golang server :
package main
import (
"database/sql"
"encoding/json"
"fmt"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"github.com/jmoiron/sqlx"
"github.com/lib/pq"
"strings"
"gopkg.in/guregu/null.v3"
)
type RawOffer struct {
RawOfferData string `json:"Raw"`
Modified null.Time `json:"Modified"`
Created null.Time `json:"Created"`
}
func convertLbc(c *gin.Context) {
var rawOffer RawOffer
c.BindJSON(&rawOffer)
fmt.Println(rawOffer.Created)
var err error
s := strings.Split(rawOffer.RawOfferData, `"ads": `)
s2 := `{ "ads": ` + s[1]
result := strings.Replace(s2, `, "status": "ready"}]`, ``, -1)
//fmt.Println(result)
var rawOfferLbc RawOfferLbc
if err = json.Unmarshal([]byte(result), &rawOfferLbc); err != nil {
fmt.Println(result)
panic(err)
}
}
var db *sqlx.DB
func main() {
var err error
fmt.Println("begin")
r := gin.Default()
r.Use(cors.Default())
r.POST("/convert/",convert)
r.Run((":8087"))
}
but for Created and modified when i try to receive it i have {0001-01-01 00:00:00 +0000 UTC false}
How to serialize a django datetime to send it in json and how to get it in golang?
My main goal so is to send an object with the date from the django app to a microservice in golang. So I need to serialize the django date and I need to write a lot of text because stackoverflow won't let me post my program if i don't write enough text ...
Regards
Here is a working example related to the question that could be helpful to someone in the future.
server.go
package main
import (
"fmt"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"github.com/jmoiron/sqlx"
"gopkg.in/guregu/null.v3"
"strconv"
)
type RawOffer struct {
Used_f bool `json:"Used_f"`
Used_t bool `json:"Used_t"`
RawOfferData string `json:"Raw"`
Modified null.Time `json:"Modified"`
Created null.Time `json:"Created"`
}
func convert(c *gin.Context) {
var rawOffer RawOffer
c.BindJSON(&rawOffer)
fmt.Println(`Used_f = ` + strconv.FormatBool(rawOffer.Used_f))
fmt.Println(`Used_t = ` + strconv.FormatBool(rawOffer.Used_t))
fmt.Println(`RawOfferData = `, rawOffer.RawOfferData)
fmt.Println(`Modified = `, rawOffer.Modified)
fmt.Println(`Created = `, rawOffer.Created)
}
var db *sqlx.DB
func main() {
fmt.Println("begin")
r := gin.Default()
r.Use(cors.Default())
r.POST("/convert/", convert)
r.Run((":8087"))
}
test.py
import requests
import json
import datetime
def default(o):
if isinstance(o, (datetime.date, datetime.datetime)):
return o.isoformat() + 'Z'
try :
data = dict(
Created = datetime.datetime.utcnow(),
Modified = datetime.datetime.utcnow(),
Used_f = False,
Used_t = True,
Raw = 'some raw data here',
)
datastr = json.dumps(data, default=default)
print(datastr)
requests.post("http://127.0.0.1:8087/convert/", datastr)
except Exception as e:
print(e)
Log on test.py:
$ python test.py
{"Created": "2019-06-09T15:48:38.978230Z", "Modified": "2019-06-09T15:48:38.978689Z", "Used_f": false, "Used_t": true, "Raw": "some raw data here"}
Log on Server:
begin
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] POST /convert/ --> main.convert (4 handlers)
[GIN-debug] Listening and serving HTTP on :8087
Used_f = false
Used_t = true
RawOfferData = some raw data here
Modified = {2019-06-09 15:48:38.978689 +0000 UTC true}
Created = {2019-06-09 15:48:38.97823 +0000 UTC true}
[GIN] 2019/06/09 - 11:48:39 |[97;42m 200 [0m| 16.979399ms | 127.0.0.1 |[97;46m POST [0m /convert/
by default django datetime field had timezone support. you need think other way . or you can use django-extentions . this third party package comes with a created and modified datetime field which is don't record timezone, use those two field you will get output like {0001-01-01 00:00:00 }
I've used a dirty trick to serialize the date :
def toJson(self):
ret = {}
date_handler = lambda obj: (
obj.isoformat()
if isinstance(obj, (datetime.datetime, datetime.date))
else None
)
ret["Created"] = str(json.dumps(self.created, default=date_handler)).replace("\"","")
ret["Modified"] = str(json.dumps(self.modified, default=date_handler)).replace("\"","")
ret["Used"] = self.used
ret["Raw"] = self.raw
return ret
I hope someone will find a better solution
i had a problem when i was try to make the auto logout in odoo 10. I was created change password page, after change password, i want end session and back to login page again. But the result never land me to teh login page. Here my code :
#api.model
def create(self, vals):
res = super(MyPass, self).create(vals)
get_new_passwd = vals['new_password']
get_conf_passwd = vals['confirm_pwd']
if get_conf_passwd != get_new_passwd:
raise ValidationError ("Pass")
hashing_pass = CryptContext(['pbkdf2_sha512']).encrypt(get_new_passwd)
data_users = self.env['res.users'].browse(self.env.uid)
data_users.write({'password_crypt': hashing_pass})
request.session.logout(keep_db=True
I found the solution.
def check(self, **kw):
get_re_users = request.env.user
error = {}
if get_re_users.passwd_changed:
return werkzeug.utils.redirect('/web')
else:
if request.httprequest.method == 'POST':
get_new_passwd = http.request.params['new_password']
get_conf_passwd = http.request.params['confirm_pwd']
session = http.request.session
hashing_pass = CryptContext(['pbkdf2_sha512']).encrypt(get_new_passwd)
data_users = http.request.env['res.users'].sudo().browse(http.request.env.uid)
data_users.write({'password_crypt': hashing_pass, "passwd_changed":True, "name":get_username_odoo, "login":get_name_login})
if session.db and session.uid:
session.logout(keep_db=True)
# return {
# 'type' : 'ir.actions.act_url',
# 'url': '/web',
# 'target': 'self',
# }
return werkzeug.utils.redirect('/web/login')
return http.request.render('name_model.id_view')
I started this thread and managed to figure out the issue yesterday.
However, another related issue has occurred.
When I have a 2nd select list in the model, and I select '8888' or '9999' to remove / reset the values when the form is submitted, how can I set the value of the 2nd select list to the default value?
Here is an example of the models.py code I have:
.....
DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITH_PROMPT = 8888
DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITHOUT_PROMPT = 9999
.....
AWARD_GRANT_TYPES = (
(SELECT_AWARD_AND_GRANT_TYPE, _('Select Type')),
....
(OTHER_GRANT, _('Other Grant')),
(WRITE_MY_OWN_AWARD_AND_GRANT_TYPE_DESCRIPTION, _('Write my own Type description')), #7777
(DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITH_PROMPT, _('Display only Description with prompt')), #8888
(DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITHOUT_PROMPT, _('Display only Description without prompt')) #9999
)
....
AWARD_GRANT_DISPLAY_COMMENCEMENT_DATE_AND_COMPLETION_DATE_AS_DATE_PROMPTS = 1
....
AWARD_GRANT_DETAILS_DATE_DISPLAY_TYPES = (
(AWARD_GRANT_DISPLAY_COMMENCEMENT_DATE_AND_COMPLETION_DATE_AS_DATE_PROMPTS, _('Display Commencement and Completion as date prompts')),
....
)
user = models.ForeignKey(User)
language_version = models.ForeignKey('LanguageVersion')
award_grant_type = models.PositiveIntegerField(choices=AWARD_GRANT_TYPES, default=SELECT_AWARD_AND_GRANT_TYPE, validators=[MinValueValidator(1)])
award_grant_type_description = models.CharField(null=True, blank=True, max_length=250)
award_grant_date = models.DateField(null=True, blank=True)
award_grant_date_display_type = models.PositiveIntegerField(choices=AWARD_GRANT_DETAILS_DATE_DISPLAY_TYPES, default=AWARD_GRANT_DISPLAY_COMMENCEMENT_DATE_AND_COMPLETION_DATE_AS_DATE_PROMPTS)
award_grant_description = models.TextField(null=False, blank=False, max_length=5000)
Here is my forms.py clean code that should reset the award_grant_date_display_type to 1 when the user has selected 8888 or 9999 from the select list award_grant_type before being committed to the db:
def clean(self):
cd_agdf = super(AwardGrantDetailsForm, self).clean()
if 'award_grant_type' in cd_agdf:
if cd_agdf['award_grant_type'] == '':
self._errors['award_grant_type'] = self.error_class([_("You must select a Type.")])
elif cd_agdf['award_grant_type'] == '8888' or cd_agdf['award_grant_type'] == '9999':
# remove / reset the entered values when the award grant type only requires minimum data.
self.cleaned_data.pop('award_grant_type_description', None)
self.cleaned_data.pop('award_grant_date', None)
self.cleaned_data['award_grant_date_display_type'] = 1
else:
....
return cd_agdf
It appears that the line of code self.cleaned_data['award_grant_date_display_type'] = 1 is ignored and the original value retained.
I have tried placing the value in quotation marks, searched SO, Google and django docs, but I cannot figure this out.
EDIT
Here is my forms.py code as requested:
class AwardGrantDetailsForm(forms.ModelForm):
def __init__(self, available_languages, language_preference, *args, **kwargs):
"""
available_languages should be a valid choices list
"""
super(AwardGrantDetailsForm, self).__init__(*args, **kwargs)
self.fields['language_code'] = forms.ChoiceField(choices=available_languages, initial=language_preference, label=_('Language'),)
self.fields['award_grant_date'].input_formats = (settings.DATE_INPUT_FORMATS)
class Meta:
model = AwardGrantDetails
fields = (
'award_grant_type',
'award_grant_type_description',
'award_grant_date',
'award_grant_date_display_type',
'award_grant_description',
)
labels = {
'award_grant_type': _('Type'),
'award_grant_type_description': _('Type Description'),
'award_grant_date': _('Date'),
'award_grant_date_display_type': _('Date Prompts'),
'award_grant_description': _('Description'),
}
help_texts = {
'award_grant_description': _('5,000 character limit'),
}
input_formats = {
'award_grant_date': settings.DATE_INPUT_FORMATS,
}
widgets = {
#'award_grant_description': CKEditorWidget(),
'award_grant_date': forms.DateInput(attrs={'id': 'id_award_grant_date'}, format='%m/%Y'),
#'award_grant_date': forms.DateInput(attrs={'id': 'id_award_grant_date'}, format=settings.DATE_INPUT_FORMATS),
}
error_messages = {
'award_grant_type': {'validate_min': _('This field is required.')}, # validate_min used on award_grant_type in lieu of required field.
}
EDIT
Here is my views.py code as requested:
#login_required
#resume_menu_required(entry_number=settings.MENU_DETAIL_VALUE_AWARD_GRANT_DETAILS)
#complete_profile_required
def award_grant_details_edit(request, award_grant_details_id):
try:
award_grant_details = AwardGrantDetails.objects.get(pk=award_grant_details_id, user=request.user)
except AwardGrantDetails.DoesNotExist:
return redirect(settings.MENU_DETAIL_LINK_AWARD_GRANT_DETAILS)
language_versions = LanguageVersion.objects.filter(user=request.user).select_related('language_version')
available_languages = get_available_language_details(language_versions, request.user.userprofile.language_preference)
award_grant_details_num = request.user.awardgrantdetails_set.count()
language_code = award_grant_details.language_version.language_code
language_code_disabled = award_grant_details.language_version.language_code_disabled
preview_labels = get_award_grant_types(available_languages)
selected_resume_menu_entries = (request.user.userprofile.selected_resume_menu_entries)
if language_code_disabled:
return redirect(settings.MENU_DETAIL_LINK_AWARD_GRANT_DETAILS)
if request.method == 'GET':
language_code = award_grant_details.language_version.language_code
form = AwardGrantDetailsForm(
available_languages=available_languages,
language_preference=request.user.userprofile.language_preference,
initial=dict(model_to_dict(award_grant_details), language_code=language_code))
elif request.method == 'POST':
form = AwardGrantDetailsForm(
available_languages=available_languages,
language_preference=request.user.userprofile.language_preference,
data=request.POST)
if form.is_valid():
award_grant_details.fill(form.cleaned_data)
award_grant_details.save()
messages.success(request, _('successfully updated.'))
return redirect(settings.MENU_DETAIL_LINK_AWARD_GRANT_DETAILS)
return render(request,'resume_details/award_grant_details_edit.html',{
'address_details_count': get_address_details_count(request.user),
'award_grant_details': award_grant_details,
'award_grant_details_num': award_grant_details_num,
'contact_details_count': get_contact_details_count(request.user),
'display_default_language': display_default_language(request.user),
'form': form,
'language_versions': get_language_versions(user=request.user),
'language_versions_num': len(language_versions), # the count of all users Language Versions (enabled & disabled).
'languages': LANGUAGES,
'max_award_grant_details': settings.MAX_AWARD_GRANT_DETAILS,
'max_details_count': settings.MAX_AWARD_GRANT_DETAILS,
'name_details_count': get_name_details_count(request.user),
'preview_labels': preview_labels,
'resume_details_menu_link': settings.MENU_DETAIL_LINK_AWARD_GRANT_DETAILS,
'resume_details_menu_num': settings.MENU_DETAIL_VALUE_AWARD_GRANT_DETAILS,
'selected_resume_menu_entries': selected_resume_menu_entries,
})
I never discovered the answer to this issue.
However, a workaround is that on form submit when 8888 or 9999 is selected and there are no errors, I manually set the value to 1 using jquery:
$('#id_of_element_type').val('1');
I hope that this will assist someone.
I have a little problem with web.py. Exacly I have problem with sessions.
Link to my app:
http://len.iem.pw.edu.pl/~witkowr1/apps/demo/
Login/password: wtq/wtq
Code:
# -*- coding: utf-8 -*-
import web
import json
from web.contrib.template import render_jinja
import datetime
prefix = '/~witkowr1/apps/demo'
urls = (
prefix + '/login','Login',
prefix + '/logout','Logout',
prefix + '/', 'Index',
)
app = web.application(urls, globals())
wsgi = app.wsgifunc()
session = web.session.Session(app, web.session.DiskStore('sessions'),initializer={'time':datetime.datetime.now()})
render = render_jinja('static', encoding = 'utf-8')
render._lookup.globals.update(assets=prefix+'/static')
class Login:
def GET(self):
web.seeother(prefix+'/')
def POST(self):
login = web.input().login
password = web.input().passwd
if login == 'wtq' and password == 'wtq':
session.logged_in = True
session.time = datetime.datetime.now()
last_login = web.cookies().get('time')
if last_login == None:
last_login_data = u'Zalogowałeś się pierwszy raz.'
else:
last_login_data = last_login
return render.logged(name=login, date_last_login=last_login_data)
else:
session.logged_in = False
error=u'Niepoprawne dane. SprĂłbuj jeszcze raz.'
return render.login(error_msg=error)
class Logout:
def GET(self):
web.seeother(prefix+'/')
def POST(self):
session.logged_in = False
web.setcookie('time',session.time)
message = u'Zostałeś poprawnie wylogowany.'
session.kill()
return render.login(error_msg=message)
class Index:
def GET(self):
return render.login()
if __name__ == "__main__":
app.run()
I would like to verify session and if I login early, I see site with latest login date.
Now, when I refresh the site, I must login again.
I think, that I check session, when I rendering HTML site, but I don't know, what I do it.
Please help!
The problem here is that you are not checking whether they are logged in if they access the page with GET method.
You would need to make a change like:
def GET(self):
if session.logged_in:
last_login = web.cookies().get('time')
if last_login == None:
last_login_data = u'Zalogowałeś się pierwszy raz.'
else:
last_login_data = last_login
return render.logged(name=login, date_last_login=last_login_data)
else:
web.seeother(prefix+'/')
But you should rewrite this, a lot, so that you are taken to another page once you are logged in, and that page is responsible for rendering this information. There is a lot of room for improvement in the structure of your application.
That said, the simple answer is - even though you store the session, the "GET" method of login is entirely unaware of sessions, and will always return the login prompt.
Not sure if you solved your problem already but since it looks like there are often some problems with sessions in web.py I pushed a small and crude demo of it to bitbucket. Works fine for me so hope this works for you.
You can get it via:
git clone https://victorkohler#bitbucket.org/victorkohler/webpy-login.git
I solved my problem.
Very stupid mistakes :)
Code:
# -*- coding: utf-8 -*-
import web
from web.contrib.template import render_jinja
import datetime
prefix = ''
urls = (
prefix + '/', 'Index',
prefix + '/login','Login',
prefix + '/logout','Logout',
)
app = web.application(urls, globals())
wsgi = app.wsgifunc()
web.config.debug = False
session = web.session.Session(app, web.session.DiskStore('sessions'),initializer={'time':datetime.datetime.now()})
render = render_jinja('static', encoding = 'utf-8')
render._lookup.globals.update(assets=prefix+'/static')
allowed = (
('user','user'),
)
class Login:
def GET(self):
web.seeother(prefix+'/')
def POST(self):
login = web.input().login
passwd = web.input().passwd
if(login,passwd) in allowed:
session.logged_in = True
session.login = login
session.time = datetime.datetime.now()
last_login = web.cookies().get('time')
if last_login == None:
last_login_data = u'Zalogowałeś się pierwszy raz.'
else:
last_login_data = last_login
return render.logged(name=login, date_last_login = last_login_data)
else:
session.logged_in = False
error=u'Niepoprawne dane. Spróbuj jeszcze raz.'
return render.login(error_msg=error)
class Logout:
def GET(self):
web.seeother(prefix+'/')
def POST(self):
session.logged_in = False
web.setcookie('time',session.time)
message = u'Zostałeś poprawnie wylogowany.'
session.kill()
return render.login(error_msg=message)
class Index:
def GET(self):
if session.get ('logged_in') == True:
last_login = web.cookies().get('time')
if last_login == None:
last_login_data = u'Zalogowałeś się pierwszy raz.'
else:
last_login_data = last_login
return render.logged(name=session.get ('login'), date_last_login = last_login_data)
else:
return render.login()
if __name__ == "__main__":
app.run()
This is not an answer to your question but an extension of the question. I have a similar solution to the login from the webpy cookbook (http://webpy.org/cookbook/userauthbasic) but would like to load the variable allowed from a database.
allowed = (
('user','user'),
)
When I tried a read to assign the value to the variable it comes out as "None" when executed in the login class.
def readUsersDb():
def POST(self):
# load user data into allowed variable
usersDbFilePath = 'userdata/irf/default/'
usersDbFile = 'usersDb.db'
usersDbFilePath = usersDbFilePath + usersDbFile
conn = sqlite3.connect(usersDbFilePath)
c = conn.cursor()
c.execute('SELECT * FROM users')
output = c.fetchall()
conn.close()
global allowed
allowed = output
readUsersDb()
The login functions when the variable allowed is hard coded. I used the format from the database read and it still functions as expected so it is not a format issue.
#response: [(u'user1', 'user1'), (u'user2', 'user2'), (u'user3', 'user3')]
Hopefully someone has tried to do this previously. If it is a faux pas to add a question as an answer I apologize ahead of time.