I make an API for modifying profiles (pseudo and another for the avatar, an image) and back run!
My problem is in the Front. I don't find how to create a function to modify the avatar (with upload an image) as I do for my function modification (for the pseudo).
When the user modifies her avatar, the upload of the image runs, but the user is redirected directly to the API request address. So, I want to make a function to make the response in a variable and to have the choice to redirection. I don't know what to put in the headers.
You can see the code-
<template>
<h1> Modifier mon profil</h1>
<div v-if="MyTokenStore.role == 'ADMIN' || MyTokenStore.role == 'USER'">
//MODIFY USER S PSEUDO WITH A FONCTION
<form #submit.prevent="modify(user)"><br>
<input v-model.trim='user.new_pseudo' maxlength="50" type="text" class="largeur"
:placeholder="[[ MyTokenStore.pseudo ]]" />
<button type="submit" class="largeur">Modifier le pseudo</button><br><br>
</form>
//MODIFY IMAGE FOR AVATAR HERE HOW I WANT TO MAKE LIKE PSEUDO MODIFY
<form :action="`http://localhost:100/myupload/${MyTokenStore.myid}`"
method="POST" enctype="multipart/form-data">
<input type="file" name="image"/>
<button type="submit">Valider mon avatar</button>
</form>
</div>
<div v-else>{{router.push("/book")}}</div>
</template>
<script setup lang="ts">
import { useRouter } from "vue-router";
import { TokenStore } from "../stores/token";
const MyTokenStore = TokenStore();
const router = useRouter();
var user = {
new_pseudo: "",
};
async function modify() {
if ( !(user.new_pseudo) || !(typeof user.new_pseudo === "string") || (user.new_pseudo.length > 25)){
alert ("pseudo invalide : mauvais format, trop long ou non renseigné.")
return
} ;
let response = await fetch(`http://localhost:100/modifyUser`, {
method: "PUT",
headers: {
"Authorization": MyTokenStore.token,
"Content-Type": "application/json",
},
body: JSON.stringify(user)
})
.then((response) => response.json())
.catch((error) => {
console.log("Failed", error)
});
if(response.error){
alert(response.message);
return
}
MyTokenStore.pseudo = user.new_pseudo;
router.push("/book");
}
</script>
Thanks for the help.
Related
Any help appreciated. I've got an app that pulls data from google books api. From each book page, the user is able to leave a review. The path to the review is /review/${isbn Number}. Each page has a path based on the isbn. The review routes work and I'm able to make the post request through insomnia/postman with no issues, I'm just having trouble with the front-end js in pulling the data from the input boxes to make the post request. I'm not sure if the issue is because the isbn being in the path. Below is my front-end javascript that I am unable to fix.
const newFormHandler = async (event) => {
event.preventDefault();
console.log("testing")
const description = document.querySelector('#description').value;
const reviewTitle = document.querySelector('#reviewTitle').value;
const isbn = window.location.search
if (description) {
const response = await fetch(`api/review/${isbn}`, {
method: 'POST',
body: JSON.stringify({ description, reviewTitle }),
headers: {
'Content-Type': 'application/json',
},
});
if (response.ok) {
document.location.reload();
} else {
alert('Failed to create review');
}
}
};
document
.querySelector('.form-group')
.addEventListener('submit', newFormHandler);
My form is below:
<div class="col form-group">
<div class ="card reviewCard" style = "background-color:#fcf8f3; color: #65625e;">
<form id="blog-form">
<div>
<label for="reviewTitle">Review Title</label>
<input
value="{{title}}"
id="reviewTitle"
name="reviewtitle"
placeholder="Enter Review Title"
type="text"
required="required"
class="form-control"
data-bv-notempty="true"
data-bv-notempty-message="The title cannot be empty"
/>
</div>
<div>
<label for="review">Review</label>
<textarea
id="description"
name="review"
cols="40"
rows="10"
required="required"
class="form-control"
>{{description}}</textarea>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</div>
</div>
And here is my route that works fine with insomnia, no issues.
router.get('/review/:id', async (req, res) => {
try {
const isbn13 = req.params['id'];
const reviewData = await Review.findAll({ where: {
isbn:isbn13
},
include: [
{
model: User,
attributes: ['name'],
}
]
})
const reviews = reviewData.map((review) => review.get({ plain:true}));
// console.log(isbn13);
res.render('review', {
isbn: isbn13, reviews:reviews
});
} catch (err) {
console.log(err)
}
});
Any help appreciated. I tried to pull in the isbn number from the path, but with no success. I think I have it formatted wrong somehow.
First console log your req
You should see the body containing some data.
In a get request the they are arguments in the URL.
In a Psot request they are in the body of the request.
I have created a Twitter clone using Ruby in the backend and React in the front end. I have managed to fetch all tweets and I am trying to post a tweet. It is connected but it is posting nothing. Literally an empty tweet.
Below is the React code.
const TweetsFeed = () => {
const [tweet, setTweet] = useState("");
const tweetChangeHandler = (event) => {
event.preventDefault();
setTweet(event.target.value);
};
const postTweet = async () => {
const postRequest = {
method: "POST",
params: tweet,
};
fetch("http://127.0.0.1:9292/tweets", postRequest).then((response) =>
response.json().then((data) => {
console.log(data);
})
);
fetchTweets();
};
Below is the Ruby route and create method code
post '/tweets' do
Tweet.create(tweet: params[:tweet])
end
def self.create(tweet:)
result = DatabaseConnection.query("INSERT INTO tweets (tweet) VALUES ('#{tweet}') RETURNING id, tweet;")
Tweet.new(
id: result[0][0],
tweet: result[0][1]
)
end
Below is the form
<form className="new-tweet-form" action="/tweets" method="post">
<div className="pp-input">
<img src="./images/pp1.jpg" alt="" />
<input
type="text"
name="tweet"
placeholder="What's happening?"
onChange={tweetChangeHandler}
/>
</div>
<div className="extras-button">
<Extras />
<Button type="button" onClick={postTweet}>
Tweet
</Button>
</div>
</form>
It does post to the database, but an empty tweet everytime.
I am new to working with databases. I've been trying to create a login/register webpage using only HTML, Js and MongoDB in my codes in order to practice. I have successfully made a function for login, yet I've been struggling to create a function for registering using the Fetch API.
I am aware that my register code is used rather for a login function, but I used it as a template for the sign up one.
I'd appreciate it if anyone can help me fix the register function using Fetch() in order to not give me 401 and to be able to add the new user's email and password to my database. Thank you.
const btnAccount = document.querySelector('.account .submit')
btnAccount.addEventListener('click', event => {
event.preventDefault()
const email = emailAccount.value
const pass = passAccount.value
const pass2 = pass2Account.value
if (email && pass && pass2) {
if (pass === pass2) {
// The data i wish to add to my mongoDB users database:
const account = {
strategy: "local",
email : emailAccount.value,
password: passAccount.value
}
fetch('http://localhost:3030/authentication', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(account)
}).then(response => {
return response.json()
}).then(result => {
console.log(result)
document.forms[1].reset();
})
.catch(err => {
// If I got some errors regardings the DB or in the code itself:
console.log('eroare:', err)
alert(`Something's wrong. I can feel it!`)
})
}
else {
// Passwords not the same:
alert('Parolele nu coincid!')
}
}
else {
// Not all fields written:
alert('Completeaza bah campurile...')
}
})
<main>
<form class="account">
<div>
<label for="email">Email:</label>
<input required type="email">
</div>
<div>
<label for="password">Password:</label>
<input required type="password" class="password">
</div>
<div>
<label for="password2">Verify Password:</label>
<input type="password" class="password2">
</div>
<div>
<button class="submit">Create new account</button>
</div>
<div>
I already have an account
</div>
</form>
<button class="fetchItems">Load ITEMS</button>
<div class="output"></div>
</main>
Description
I have a table, where i collect values from checkboxes with JavaScript. This values should be send to a protected API route in a Laravel backend.
I use the standard Laravel auth setup (out of the box).
Question
What do I have to send with the JavaScript post request for authentication and how do i do that? Can i add a auth token or something like that to the headers?
At the moment i get the reponse:
"This action is unauthorized".
exception: "Symfony\\Component\\HttpKernel\\Exception\\AccessDeniedHttpException"
Edit
At the current point of my research the api token seems to be a simple solution for my case. But i can't figure out how to attach the api token to the JavaScript post request.
Thats the JavaScript function for collecting the values storing them in objects.
import SaveData from "../api/SaveData";
export default async function SaveMultipleReports() {
const table = document.getElementById("reports-dashboard");
const rows = table.querySelectorAll("div[class=report-tr]");
let reports = [];
for (const row of rows) {
const checkbox_visible = row.querySelector("input[name=visible]")
.checked;
const checkbox_slider = document.querySelector(
"input[name=show_in_slider]"
).checked;
const report = {
id: row.id,
visible: checkbox_visible,
show_in_slider: checkbox_slider
};
reports.push(report);
}
console.log(reports);
const response = await SaveData("/api/reports/update", reports);
console.log(response);
}
And that is the SavaData function:
export default async function SaveData(api, data) {
const token = document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content");
const url = window.location.origin + api;
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRF-TOKEN": token,
Accept: "application/json"
},
body: JSON.stringify(data)
});
const result = await response.json();
return result;
}
And thats the line in the api.php:
Route::middleware("can:administration")->post("reports/update", "ReportsController#UpdateAll");
The whole repo is here.
Thanks for your time in advance :)
Edit 2
For now i managed it without JavaScript. Put all the values, i want to update in form and load a hidden input for the ID of every object (the ID is needed for the controller afterwards).
Thanks to this post.
{!! Form::open(["route" => ["admin.reports.multiupdate"], "method" => "PUT", "class" => "report-table"]) !!}
... // some HTML
#foreach ($reports as $report)
<div class="report-tr">
<input type="hidden" name="reports[{{$loop->index}}][id]" value="{{$report->id}}">
<div class="td-name">
<p class="td-text">{{$report->name}}</p>
</div>
<div class="td-flex">{{$report->body}}</div>
<div class="tr-wrapper">
<div class="checkbox-visible">
<div class="checkbox-container">
<input class="checkbox" type="checkbox" name="reports[{{$loop->index}}][visible]" value="1" checked>
<span class="checkmark"></span>
</div>
<label class="table-label" for="visible">Sichtbar</label>
</div>
<div class="checkbox-slider">
<div class="checkbox-container">
<input class="checkbox" type="checkbox" name="reports[{{$loop->index}}][show_in_slider]" value="1"
{{($report->show_in_slider == 1 ? "checked" : "")}}>
<span class="checkmark"></span>
</div>
<label class="table-label" for="show_in_slider">Im Slider</label>
</div>
<div class="td-buttons">
...
#endforeach
<button class="floating-save">
#svg("saveAll", "saveAll")
</button>
{!! Form::close() !!}
And a snippet from the Controller:
public function MultipleUpate(ReportUpdate $request)
{
$reports = $request->input("reports");
foreach ($reports as $row) {
$report = Report::find($row["id"]);
// giving the checkbox 0, if it isn't checked
$isVisible = isset($row["visible"]) ? 1 : 0;
$inSlider = isset($row["show_in_slider"]) ? 1 : 0;
$report->visible = $isVisible;
$report->show_in_slider = $inSlider;
$report->new = false;
if ($report->save()) {
$saved = true;
}
}
if ($saved == true) {
$request->session()->flash("success", "Änderungen gespeichert!");
} else {
$request->session()->flash("error", "Das hat nicht geklappt!");
}
return back();
The ReportUdpate function contains only that:
public function authorize()
{
return true;
}
public function rules()
{
return [
"visible" => "nullable",
"show_in_slider" => "nullable"
];
}
You are talking about authentication but using an authorization middleware. There is a difference between the two.
Read about it here: https://medium.com/datadriveninvestor/authentication-vs-authorization-716fea914d55
With that being said, what you are looking for is an authentication middleware that protects your routes from unauthenticated users. Laravel provides a middleware called Authenticate out of the box for this specific purpose.
Change your route to be like so:
Route::middleware("auth")->post("reports/update", "ReportsController#UpdateAll");
I am trying to retrieve data from a Bootstrap form element, and save it to a PostgresSQL database using Express and Knex. There are no errors when I run the route; however, the data from the form is saved as null. Here is my form element (I'm using React):
render() {
return (
<form>
<div className ="form-group">
<label>Add a Note:</label>
<textarea className="form-control" name="note" rows="5">
</textarea>
</div>
<button onClick={this.handleClick} className="btn btn-primary"
type="submit">Submit</button>
</form>
)
}
Here is my fetch to the POST route:
handleClick(e) {
e.preventDefault()
fetch('/create-note', {
method: 'POST'
})
}
Here is my Express POST route (app.use(bodyParser.json()) is included in this file):
app.post('/create-note', (req, res) => {
postNote(req.body.note)
.then(() => {
res.sendStatus(201)
})
})
Here is the Knex postNote function:
export function postNote(newNote) {
const query = knex
.insert({ note_content: newNote })
.into('notes')
return query
}
Any help would be appreciated!
With POST requests you may have to wait for data body to be ready. Try this
app.post('/create-note', (req, res) => {
var body = '';
request.on('data',function(data) { body += data; });
request.on('end', function(data) {
postNote(body)
.then(() => {
res.sendStatus(201)
})
});
})
try the following in your markup, and forgo using fetch
...
<form method="POST" action="/create-note" enctype='application/json'>
...
</form>
...
or since the default encoding for a form is application/x-www-form-encoded (doc), add the following middleware to your express app..
...
app.use(bodyParser.urlencoded({ extended: true }));
...
also you could try...
...
<button ref="form" onClick={this.handleClick} className="btn btn-primary"
type="submit">Submit</button>
...
along with
handleClick(e) {
e.preventDefault();
const data = new FormData(this.refs.form);
fetch('/create-note', {
method: 'POST',
body: data
})
}
I found a solution and want to post it incase anyone else runs into a similar issue. The problem was I wasn't querying textarea's value correctly, so I was passing an undefined variable to the database to save.
Here's the solution I came up with:
handleSubmit(e) {
const data = new FormData(e.target)
const text = {note: data.get('note')}
fetch('/create-note', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(text)
})
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className ="form-group">
<label>Add a Note:</label>
<textarea className="form-control" name="note" rows="5">
</textarea>
<button ref="textarea" className="btn btn-primary"
type="submit">Submit</button>
</div>
</form>
)
}
I put a onSubmit event listener on the form, and created a new FormData instance with the form. Then I created an object containing the value of the textarea to pass into the fetch call.