actually I want: if a user is authenticated: then create/get the Cart with user,
else: create/get the Cart with session key. But at first problem happened with authentication.
At first I tried to register the user and saved the key(got from drf) in local storage.
in Reactjs:
signupHandler=()=>{
fetch('http://127.0.0.1:8000/api/rest-auth/registration/', {
method: 'POST',
headers:{
'content-type':'application/json',
},
body:JSON.stringify({
'username':this.state.username,
'email': this.state.email,
'password1': this.state.pass1,
'password2': this.state.pass2
})
})
.then((response)=>{
response.json().then((result)=>{
if (result.key !== undefined){
localStorage.setItem('login', JSON.stringify({login: true,token:result.key}))
this.setState({registered: true})
}
})
})
}
I think no problem here. if I console.log() the key , it prints the key successfully.
now look at my views.py . I think the problem is here.
#api_view(['GET'])
##permission_classes((IsAuthenticated,))<<< if i comment out this line, and try to call this function, it shows >>>Forbidden: /addToCart/21/
def addToCart(request, pk):
print(request.user)#>>>AnonymousUser
product = get_object_or_404(Product, pk=pk)
if request.user.is_authenticated:
print('authenticated')#>>> nothing prints
mycart, __ = Cart.objects.get_or_create(user=request.user)
mycart.product.add(product)
else:
print('session')#>>>session
if not request.session.exists(request.session.session_key):
request.session.create()
mycart, __ = Cart.objects.get_or_create(session_key=request.session.session_key)
mycart.product.add(product)
return Response({'response':'ok'})
now i made a button and if i click, this function call
reactjs:
addToCart=()=>{
var id = this.props.id
let store = JSON.parse(localStorage.getItem('login'))
console.log(store.token);//successfully print the key
var url = 'http://127.0.0.1:8000/addToCart/'+id+'/'
fetch(url,{
method:'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token '+store.token
}
}).then(res=>res.json().then(result=>{
if(result.response === 'ok'){
this.props.dispatch({
type: 'itemInCart',
})
this.setState({addedToCart: true})
}
}))
}
So my question is:
*why it shows Forbidden if I comment out the line #permission_classes((IsAuthenticated,)) though i don't want this line. because I also want, user can add item with session.
*(in views.py) when i print request.user it shows >>>AnonymousUser. how to print the real user?
Finally, How can I add an item to the Cart with an Authenticated user?
You need to add either DEFAULT_AUTHENTICATION_CLASSES in settings.py or add a decorator #authentication_classes([TokenAuthentication]) to the api_view if not done already.
Since you need the API to also be accessible to unauthenticated users, #permission_classes is not required.
Related
A HTTP call is made when I click on the "place order" button in my big-commerce store. The "payment name" is whatever we selected from the radio buttons on the checkout page. As you can see in the image, I selected "instore" option from the dropdown & HTTP request is made with that selected payload.
SCREENSHOT
I want to change this payload to my own custom text. How can I achieve this?
The reason for this is because I am making custom payment method & I want to use company name in the "payment name".
use a library like axios to post your request.
axios.post('/user/12345', {
cardid: 'xxxxx',
payment: {
name: "abc",
}
})
also you can pass an object in axios
let paylod ={
cardId:"",
paymentMessage:"",
paymentName:"insotre"
}
let auth_token = "your token"
const { data }= await axios({
methode:post,
url:"your_link"
data:paylod
//if you passing token for authorisation
headers: { Authorization: `Bearer ${auth_token}` },
})
In a React project, I have pay() method. A wallet balance is shown with certain coins. When pay() is clicked data is updated in purchase data. Coins data is stored in sessionStorage, but, after refresh of page data is missing.
Payment method
const onPayment = async (coins, _id) => {
try {
await fetch(`${config.baseUrl}customers/purchaseproduct?content_id=${_id}&coins=${coins}&v=1.0`, {
method:'POST',
headers: {
'Content-Type': 'application/json',
'ApiKey': config.apiKey,
'Authorization':sessionStorage.getItem('tokenNew'),
'platform':'web'
},
}).then((data) => data.json()).then((data2) => {
const balanceUpdated = data2.data.purchase.coins_after_txn
console.log('new balance', balanceUpdated) //new balance: 49990
{/* Here coins data is updated only on click of pay() method later on page refresh sessionStorage
value is empty */}
sessionStorage.setItem('walletData', balanceUpdated)
})
}
catch({error}) {
toast.error(error)
}
}
As you can see 'coins' are the price of product whereas '_id' is the id of specific product in onPayment method. walletData is updated only on payment and when refreshed the page, data is empty.
Take an example, A product price is $90 when clicked on pay() method $90 is cut from wallet 'balanceUpdated' and then passed on to sessionStorage in 'walletData' which is shown at that instance i.e 4900 but when page is refreshed 'walletData' is empty.
How to store the new updated value in sessionStorage and will remain it even after refresh?
LoginNow file
const onSubmit = async (data) => {
try {
let newData = await fetch('customers/auth/login', {
method:'POST',
headers: {
'Content-Type': 'application/json',
'ApiKey': config.apiKey,
'Platform': 'web',
},
body: JSON.stringify(data)
});
newData = await newData.json();
if(newData.error == true) {
toast.error(newData.error_messages[0])
} else {
const tokenData = newData.data.token
const walletData = newData.data.coinsxp.coins
sessionStorage.setItem('tokenNew', tokenData);
sessionStorage.setItem('walletData', walletData);
}
}
catch({error}) {
toast.error(error)
}
}
The data is probably there in the sessionStorage, you just have to retrieve it and write it in memory, on startup.
Probably you want something like this (or the other way around, depending on which value you want to have precedence):
const walletData = newData.data.coinsxp.coins || sessionStorage.getItem('walletData');
Putting data in sessionstorage is not equivalent to making it persistent. Putting data in sessionStorage means that it will just stay in session storage, it doesn't mean that your app data will be updated automatically based on it. This is why every time you call setItem, you should also call getItem - otherwise you are just stashing stuff somewhere, without accessing it.
i have a problem integrating paypals payment gateway. I am using javascript for the client, python for the backend and the checkouts v2 api.
Creating a order on the backend works without trouble, but while waiting for my servers response the createOrder function raises a error:
unhandled_error
Object { err: "Expected an order id to be passed\nLe/</<#https://www.sandbox.paypal.com/smart/buttons?style.layout=vertical&style.color=blue&style.shape=rect&style.tagline=false&components.0=buttons&locale.country=NO&locale.lang=no&sdkMeta=eyJ1cmwiOiJodHRwczovL3d3dy5wYXlwYWwuY29tL3Nkay9qcz9jbGllbnQtaWQ9QWJmSjNNSG5oMkFIU1ZwdXl4eW5lLXBCbHdJZkNsLXpyVXc1dzFiX29TVUloZU01LXNMaDNfSWhuTnZkNUhYSW5wcXVFdm5MZG1LN0xOZ1gmZGlzYWJsZS1mdW5kaW5nPWNyZWRpdCxjYXJkIiwiYXR0cnMiOnt9fQ&clientID=AbfJ3MHnh2AHSVpuyxyne-pBlwIfCl-zrUw5w1b_oSUIheM5-sLh3_IhnNvd5HXInpquEvnLdmK7LNgX&sessionID=e2ea737589_mtc6mtu6mdi&buttonSessionID=de4bfb3626_mtc6mjm6mtk&env=sandbox&fundingEligibility=eyJwYXlwYWwiOnsiZWxpZ2libGUiOnRydWV9LCJjYXJkIjp7ImVsaWdpYmxlIjpmYWxzZSwiYnJhbmRlZCI6dHJ1ZSwidmVuZG9ycyI6eyJ2aXNhIjp7ImVsaWdpYmxlIjp0cnVlfSwibWFzdGVyY2FyZCI6eyJlbGlnaWJsZSI6dHJ1ZX0sImFtZXgiOnsiZWxpZ2libGUiOnRydWV9LCJkaXNjb3ZlciI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJoaXBlciI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJlbG8iOnsiZWxpZ2libGUiOmZhbHNlfSwiamNiIjp7ImVsaWdpYmxlIjpmYWxzZX19…", timestamp: "1593537805136", referer: "www.sandbox.paypal.com", sessionID: "e2ea737589_mtc6mtu6mdi", env: "sandbox", buttonSessionID: "de4bfb3626_mtc6mjm6mtk" }
Error: Expected an order id to be passed
Error: Expected an order id to be passed
12V21085461823829 // ticks in a few seconds later
Console screenshot
The problem seems to be that createOrder does not wait for the promise before raising the error, or that the promise is not given in the correct way. Something like that. Anyways here is the client side code:
paypal.Buttons({
// button styling removed for clarity
createOrder: function() {
// purchase information
var data = {
'track_id': vm.selectedTrack.id,
'lease_id': vm.selectedLease.id,
}
// post req to api with lease and track ids
// create payment on server side
fetch('http://localhost:5000/api/paypal/create-purchase', {
method: 'post',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(data),
}).then(function(res) {
return res.json();
}).then(function(data) {
console.log(data.order_id)
return data.order_id
})
}
// conatiner element to render buttons in
}).render('#paypal-button');
And the server side:
#app.route('/api/paypal/create-purchase', methods=['POST'])
def paypal_create_purchase():
# cart validation removed for clarity
# create paypal purchase
environment = SandboxEnvironment(client_id=app.config['PAYPAL_PUBLIC'], client_secret=app.config['PAYPAL_PRIVATE'])
client = PayPalHttpClient(environment)
paypal_request = OrdersCreateRequest()
paypal_request.prefer('return=representation')
paypal_request.request_body (
{
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": lease.price
}
}
]
}
)
try:
# Call API with your client and get a response for your call
response = client.execute(paypal_request)
order = response.result
print(order.id)
except IOError as ioe:
print (ioe)
if isinstance(ioe, HttpError):
# Something went wrong server-side
print(ioe.status_code)
# note that it is the same key as on the client
return jsonify(success=True,order_id=order.id)
I found this similar thread, but i dont consider the origin of the error to be the same as in that thread (incorrect json key on client)
Also see this relevant page in the docs which supplies this code:
createOrder: function() {
return fetch('/my-server/create-paypal-transaction', {
method: 'post',
headers: {
'content-type': 'application/json'
}
}).then(function(res) {
return res.json();
}).then(function(data) {
return data.orderID; // Use the same key name for order ID on the client and server
});
}
Damn, just as i was typing out the last part of the post i noticed the error. A missing return before my fetch call. Will leave this up for other people with the same mistake.
In the course you are supposed to make a form that creates 'todos' and then have a parent list as well. Everything worked fine until we were instructed to add a foreign key 'list_id' to the child so that it associates with the parent list. After that when I attempt to create a todo I get the integrity error saying that the list_id is null and goes against the constraint since it is set to nullable=false. How do I get the todos(child) table to associate to the parent(list) table so that is automatically matches the list_id to the parent's id? They are already set up to have a relationship but it is still not associating them. Below is the back end code to model the tables.
'''
'''
Back end to create the todo
'''
#app.route('/todos/create', methods=['POST'])
def create_todo():
error = False
body = {}
try:
description = request.get_json()['description']
todo = Todo(description=description)
db.session.add(todo)
db.session.commit()
body['description'] = todo.description
except:
db.session.rollback()
print(sys.exc_info())
finally:
db.session.close()
print("i am in todo")
if error:
abort(400)
else:
return jsonify(body)
'''
This is the front side javascript for the create form
'''
document.getElementById('form').onsubmit = function(e) {
e.preventDefault();
const desc = descInput.value;
//descInput.value = '';
console.log(desc);
fetch('/todos/create', {
method: 'POST',
body: JSON.stringify({
'description': desc,
}),
headers: {
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(jsonResponse => {
console.log('response', jsonResponse);
li = document.createElement('li');
li.innerText = desc;
document.getElementById('todos').appendChild(li);
document.getElementById('error').className = 'hidden';
})
.catch(function() {
document.getElementById('error').className = '';
})
}
'''
In your server code you have to explicitly set todo list to your newly created todo object before you save it (e.g. todo = Todo(description=description, list_id=some_todolist.id)), otherwise the nullable=False constraint will trigger. How you get the needed todolist object there depends on how you provide the "this todo should under this list" idea, e.g. provide the list id through request params, if the frontend knows about that.
I'm trying the Wikipedia client login flow depicted in the API:Login docs, but something wrong happens:
1) I correctly get a token raised with the HTTP GET https://en.wikipedia.org/w/api.php?action=query&meta=tokens&type=login&format=json
and I get a valid logintoken string.
2.1) I then try the clientlogin like:
HTTP POST /w/api.php?action=clientlogin&format=json&lgname=xxxx&lgtoken=xxxx%2B%5C
and the POST BODY was
{
"lgpassword" : "xxxxx",
"lgtoken" : "xxxxx"
}
But I get an error:
{
"error": {
"code": "notoken",
"info": "The \"token\" parameter must be set."
},
"servedby": "mw1228"
}
If I try to change lgtoken to token I get the same result.
2.2) I have then tried the old method i.e. action=login and passing the body, but it does not work, since it gives me back another login token: HTTP POST https://en.wikipedia.org/w/api.php?action=login&format=json&lgname=xxxx
and the same POST BODY
I then get
{
"warnings": {}
},
"login": {
"result": "NeedToken",
"token": "xxxxx+\\"
}
where the docs here states that
NeedToken if the lgtoken parameter was not provided or no session was active (e.g. your cookie handling is broken).
but I have passed the lgtoken in the json body as showed.
I'm using Node.js and the built-in http module, that is supposed to pass and keep session Cookies in the right way (with other api it works ok).
I have found a similar issue on a the LrMediaWiki client here.
[UPDATE]
This is my current implementation:
Wikipedia.prototype.loginUser = function (username, password) {
var self = this;
return new Promise((resolve, reject) => {
var cookies = self.cookies({});
var headers = {
'Cookie': cookies.join(';'),
'Accept': '*/*',
'User-Agent': self.browser.userAgent()
};
// fetch login token
self.api.RequestGetP('/w/api.php', headers, {
action: 'query',
meta: 'tokens',
type: 'login',
format: 'json'
})
.then(response => { // success
if (response.query && response.query.tokens && response.query.tokens['logintoken']) {
self.login.logintoken = response.query.tokens['logintoken'];
self.logger.info("Wikipedia.login token:%s", self.login);
return self.api.RequestPostP('/w/api.php', headers, {
action: 'login',
format: 'json',
lgname: username
},
{
lgpassword: password,
lgtoken: self.login.logintoken
});
} else {
var error = new Error('no logintoken');
return reject(error);
}
})
.then(response => { // success
return resolve(response);
})
.catch(error => { // error
self.logger.error("Wikipedia.login error%s\n%#", error.message, error.stack);
return reject(error);
});
});
}//loginUser
where this.api is a simple wrapper of the Node.js http, the source code is available here and the api signatures are like:
Promise:API.RequestGetP(url,headers,querystring)
Promise:API.RequestPostP(url,headers,querystring,body)
If the currently accepted answer isn't working for someone, the following method will definitely work. I've used the axios library to send requests. Any library can be used but the key lies in formatting the body and headers correctly.
let url = "https://test.wikipedia.org/w/api.php";
let params = {
action: "query",
meta: "tokens",
type: "login",
format: "json"
};
axios.get(url, { params: params }).then(resp => {
let loginToken = resp.data.query.tokens.logintoken
let cookie = resp.headers["set-cookie"].join(';');
let body = {
action: 'login',
lgname: 'user_name',
lgpassword: 'password',
lgtoken: loginToken,
format: 'json'
}
let bodyData = new URLSearchParams(body).toString();
axios.post(url, bodyData, {
headers: {
Cookie: cookie,
}
}).then(resp => {
// You're now logged in!
// You'll have to add the following cookie in the headers again for any further requests that you might make
let cookie = resp.headers["set-cookie"].join(';')
console.log(resp.data)
})
})
And you should be seeing a response like
{
login: { result: 'Success', lguserid: 0000000, lgusername: 'Username' }
}
The second post request was where I got stuck for several hours, trying to figure out what was wrong. You need to send the data in an encoded form by using an API like URLSearchParams, or by just typing up the body as a string manually yourself.
I think from what you are saying you have lgtoken and lgname in the URL you are using, and then lgpassword and lgtoken (again!) in a JSON-encoded POST body.
This is not how the Mediawiki API works.
You submit it all as POST parameters. JSON is never involved, except when you ask for the result to come back in that format. I can't help you fix your code as you don't provide it, but that's what you need to do. (If you edit your question with your code, I'll do my best to help you.)
After seeing your code, I'll presume (without knowing the detail of your code) that you want something like this:
return self.api.RequestPostP('/w/api.php', headers, {
action: 'login',
format: 'json',
lgname: username,
lgpassword: password,
lgtoken: self.login.logintoken
});