I have a site with Drupal 8. I have created a custom module. Here is its code :
https://github.com/S1BIOSE/generator_website
generator-website-page.html.twig :
<div class="card mb-5 overflow-hidden shadow rounded bg-white">
<div class="card-body">
<form>
<legend>Générateur de site web</legend>
<div class="mb-3">
<label for="TokenUrl" class="form-label">L'URL de votre site web</label>
<input type="text" class="form-control is-invalid" id="TokenUrl" required>
<div class="invalid-feedback">
Ce champ est requis.
</div>
<small id="helpUrl" class="form-text">Entrez l'URL complète de votre site web.</small>
</div>
<div class="mb-3">
<label for="TokenTitle" class="form-label">Nom de l'entreprise</label>
<input type="text" class="form-control is-invalid" id="TokenTitle" required>
<div class="invalid-feedback">
Ce champ est requis.
</div>
<small id="helpTitle" class="form-text">Entrez le nom de votre entreprise.</small>
</div>
<div class="mb-3">
<label for="TokenDescription" class="form-label">Présentation de l'entreprise</label>
<textarea class="form-control is-invalid" id="TokenDescription" rows="5" required></textarea>
<div class="invalid-feedback">
Ce champ est requis.
</div>
<small id="helpDescription" class="form-text">Entrez une description de votre entreprise.</small>
</div>
<div class="mb-3">
<label for="TokenFeed" class="form-label">Fil d'actualité</label>
<input type="text" class="form-control" id="TokenFeed">
<small id="helpFeed" class="form-text">Entrez l'url de votre Flux RSS sur la plateforme S1BIOSE.</small>
</div>
<button type="submit" class="btn btn-primary">Générer</button>
</form>
</div>
</div>
What should I put in my module to generate the 3 files above and replace the words starting with Token ?
In this custom module, I created a form with IDs (I'm not sure if this is the right way to go). For example, the data entered in the TokenTitle field must replace TokenTitle wherever it appears in the files.
When a user submits the form, it must download the 3 files with the correct data (the one entered in the form). If possible in a ZIP archive.
It is unnecessary to keep the information submitted in the form in the database.
manifest.json
{
"orientation":"portrait",
"short_name": "TokenTitle",
"name": "TokenTitle",
"display": "standalone",
"background_color": "#000000",
"theme_color": "#000000",
"description": "TokenDescription",
"lang": "fr",
"icons": [{
"src": "icon-144.png",
"sizes": "144x144",
"type": "image/png",
"purpose": "any maskable"
}, {
"src": "icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
}, {
"src": "icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}],
"start_url": "/?source=pwa",
"scope": "/"
}
sitemap.xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>TokenUrl/index.html</loc>
<lastmod>TokenDate</lastmod>
</url>
</urlset>
sw.js
const staticCacheName = 'TokenTimestamp';
const filesToCache = [
'/',
'/index.html',
'/CHANGELOG.md',
'/bootstrap.min.css',
'/style.css',
'/bootstrap.bundle.min.js',
'/popover.js',
'/clipboard.min.js',
'/btn-clipboard.js',
'/pwa.js',
'/feed.js',
'/toasts.js',
'/icon-32.png',
'/icon-144.png',
'/icon-192.png',
'/icon-512.png',
'/iphone5_splash.png',
'/iphone6_splash.png',
'/iphoneplus_splash.png',
'/iphonex_splash.png',
'/iphonexr_splash.png',
'/iphonexsmax_splash.png',
'/ipad_splash.png',
'/ipadpro1_splash.png',
'/ipadpro3_splash.png',
'/ipadpro2_splash.png'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(staticCacheName).then(cache => {
return cache.addAll(filesToCache);
})
);
});
self.addEventListener('activate', event => {
event.waitUntil(caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.filter(function(staticCacheName) {
}).map(function(staticCacheName) {
return caches.delete(staticCacheName);
})
);
}));
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(cachedResponse => {
if (cachedResponse) {
return cachedResponse;
}
return fetch(event.request);
})
);
});
self.addEventListener('message', event => {
if (event.data.action === 'skipWaiting') {
self.skipWaiting();
}
});
Don't use standard PHP to make the file, as then you'll need to handle housekeeping/ removing it/ managing it as well. Drupal has BinaryFileResponse for sending files to users and \Drupal\Core\File\FileSystemInterface for creation/ management of files. If it is temporary, then simply set it as this.
Hello ok there are the things you will need to know how todo do:
Learn how to make files with php: https://www.w3schools.com/php/php_file_create.asp
learn how Drupal routing and controllers work:
https://www.drupal.org/docs/drupal-apis/routing-system/introductory-drupal-8-routes-and-controllers-example
learn how Drupal handles forms https://www.drupal.org/docs/drupal-apis/form-api/introduction-to-form-api
once you know these things then you can use on form submit
some php to generate your files and then probably group them for download ...or what ever your doing with them.
Related
I'm using Laravel Inertia on a project and I'm currently working on the form "Create.vue" to create a new role, I want to show the list of permissions (that is stored in a table) with checkboxes so the user can select them and send the "id" to the controller. The problem is when i bind the input checkbox to a reactive variable using the v-model all the checkboxes behave the same way, when i select one the others also get selected.
Here is my code
<template>
<div>
<Head title="Crear Roles" />
<h1 class="mb-5 text-2xl font-bold text-cyan-900">Crear Rol</h1>
<div class="max-w-3xl bg-white rounded-md shadow overflow-hidden">
<form #submit.prevent="roles.post(route('roles.store'))">
<div class="flex flex-wrap -mb-8 -mr-6 p-8">
<text-input v-model="roles.name" type="text" label="Nombre del Rol"
class="pb-7 pr-6 w-full lg:w-1/2" :id="name" name="name" />
</div>
<div class="flex-wrap -mb-8 -mr-6 p-8">
<div class="block">Permisos para este Rol</div>
<!-- ===========HERE IS THE PROBLEM -->
<div v-for="permission in permissions" :key="permission.id">
<label for="">
<input type="checkbox" name="permissions[]" value="{{ permission.id }}" id="" >
{{ permission.name }}
</label>
</div>
<!-- =====================================================-->
</div>
<div class="flex items-center justify-end px-8 py-4 bg-gray-50 border-t border-gray-100">
<Link type="button" :href="route('roles.index')" class="btn-cancelar">
<span class="text-white font-bold">Cancelar</span>
</Link>
<button class="btn-indigo mx-1" type="submit">
Crear Rol
</button>
</div>
</form>
</div>
</div>
</template>
<script>
import Layout from "../../Shared/Layout.vue";
import TextInput from "../../Shared/TextInput.vue";
import SelectInput from "../../Shared/SelectInput.vue";
import { Head, Link } from "#inertiajs/inertia-vue3";
import { reactive, ref } from "vue";
import { useForm } from "#inertiajs/inertia-vue3";
export default {
components: {
Head,
Link,
TextInput,
SelectInput,
},
layout: Layout,
props: {
permissions: Object
},
setup() {
const name = ref("");
const premissions = ref([]);
const roles = useForm({
name: "",
permissions: [],
});
/* const guardar = async () => {
console.log(roles);
roles.post(route("roles.store"), roles);
}; */
return {
roles
};
},
};
</script>
//================================the controller===========
public function create()
{
$permissions = Permission::all();
return Inertia::render('Roles/Nuevo', [
'permissions' => $permissions
]);
}
public function store(Request $request)
{
$role = Role::create($request->all());
//si los permisos no están nulos se lo asignamos al rol creado
if (!empty($request->permissions)) {
$role->givePermissionTo($request->permissions);
}
return Redirect::route('roles.index')->with('success', 'Rol Creado');
}
Help me please!
You can use v-model in your input field & bind value.
Like:
<input type="checkbox" v-model="permissions" :value="permission.id" />
Your problem here is the <label> you need to ensure that the checkbox has a unique id that can be identify by the label so that if you click the checkbox it will mark only those that identify by it.
<div v-for="permission in permissions" :key="permission.id">
<div class="flex items-center gap-1">
<input type="checkbox" :id="permission.name">
<label :for="permission.name">{{ permission.name }}</label>
</div>
</div>
During registration, I am validating the user input; however, I don't know how to check if the user email exist already in the database.
What I want to do is the following: if the users email already exist then it will show a toast which says "email already exist" and if the user clicks register then it will not register and display the toast.
Here is the code:
Vue.js
data() {
return {
validate: false,
loading: false,
cpass: null,
dialog: {
success: false
},
rules: {
password: [v => v === this.form.pass || 'Passwords do not match.',
v => !!v || 'This field cannot be blank.'
]
},
form: {}
}
},
methods: {
submitRegistration() {
if (this.$refs.registration.validate()) {
let formData = new FormData()
formData.set('type', 'customer')
formData.set('email', this.form.email);
formData.set('pass', this.form.pass);
formData.set('fname', this.form.fname);
formData.set('lname', this.form.lname);
formData.set('address', this.form.address);
formData.set('city', this.form.city);
formData.set('province', this.form.province);
formData.set('contact', this.form.contact);
axios.post('./sql/registration.php', formData)
.then(() => {
this.dialog.success = true
}).catch((error) => {
console.error(error)
})
}
},
},
template: `<v-container>
<v-card elevation="0">
<v-card-title class="display-1 font-weight-light">Customer Registration</v-card-title>
<v-divider class="mx-4"/>
<v-card-text>
<v-row>
<v-col cols="12" sm="6" md="8">
<v-form ref="registration" v-model="validate">
<v-row>
<v-col cols="12" md="4"><v-text-field :rules="$rules.required" type="email" v-model="form.email" rounded filled placeholder="Email Address"/></v-col>
<v-col cols="12" md="4"><v-text-field :rules="$rules.required" v-model="form.pass" type="password" rounded filled placeholder="Password"/></v-col>
<v-col cols="12" md="4"><v-text-field :rules="rules.password" v-model="cpass" type="password" rounded filled placeholder="Confirm Password"/></v-col>
<v-col cols="12" md="6"><v-text-field :rules="$rules.required" v-model="form.fname" rounded filled placeholder="First Name"/></v-col>
<v-col cols="12" md="6"><v-text-field :rules="$rules.required" v-model="form.lname" rounded filled placeholder="Last Name"/></v-col>
<v-col cols="12"><v-text-field :rules="$rules.required" v-model="form.address" rounded filled placeholder="Home Address"/></v-col>
<v-col cols="12" md="4"><v-text-field :rules="$rules.required" v-model="form.city" rounded filled placeholder="City"/></v-col>
<v-col cols="12" md="4"><v-select :rules="$rules.required" :items="$provinces" v-model="form.province" rounded filled placeholder="Province"/></v-col>
<v-col cols="12" md="4"><v-text-field v-model="form.contact" maxlength="11" rounded filled placeholder="Contact No." hint="e.g. 09021231234"/></v-col>
<v-col cols="12" align="end"><v-btn :loading="loading" #click="submitRegistration" large depressed rounded color="primary">Sign Up Now</v-btn></v-col>
</v-row>
</v-form>
</v-col>
<v-col cols="12" sm="6" md="4">
<transition appear name="slide-fade">
<v-img height="100%" src="assets/img/customer-reg.jpg" style="border-radius: 25px;"/>
</transition>
</v-col>
</v-row>
</v-card-text>
</v-card>
<v-dialog v-model="dialog.success" max-width="480">
<v-card>
<v-card-title>Registration Complete!</v-card-title>
<v-card-text>Welcome! Thank you for registering an account at our shop. You can now order apparel from any of our sellers.</v-card-text>
<v-card-actions>
<v-btn x-large tile depressed block color="primary" to="/sign-in">Get Started</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-container>`
})
php:
$type = $_POST['type'];
$password = password_hash($_POST['pass'], PASSWORD_DEFAULT);
$form = array($type, $_POST['fname'], $_POST['lname'], $_POST['address'], $_POST['city'], $_POST['province'], $_POST['contact'], $_POST['email'], $password);
$sql = $handler->prepare('INSERT INTO accounts(type, fname,lname,address,city,province,contact,email,password) VALUES(?,?,?,?,?,?,?,?,?)');
$sql->execute($form);
break;
Thank you.
Best practice is to validate the email while filling the form itself by using #keyup, #blur or #change event as per the requirement. For Demo, I am using #keyup event to validate the email address.
Demo :
new Vue({
el: '#app',
data: {
form: {
email: null
},
emailMessage: ''
},
methods: {
validateEmailAddress() {
if (!this.form.email) {
this.emailMessage = ''
return;
}
// API call will be happen here to validate the entered email address.
// For now i am just using mock response (assume you are getting this list from API or you can also get the boolean value) for the demo.
const response = ['abc#gmail.com', 'def#gmail.com', 'alpha#gmail.com', 'beta#gmail.com'];
this.emailMessage = (response.includes(this.form.email)) ? 'Email already exist' : 'Hurray! Good to Go';
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="email" v-model="form.email" placeholder="Email Address" #keyup="validateEmailAddress"/>
<p>{{ emailMessage }}</p>
</div>
You can do it in multiple ways. One way is to call a function on email input event, so that each time the user enters a character an endpoint is called to check if the email is already available.
<v-text-field type="email" v-model="form.email" placeholder="Email Address" #input="debouceCheckEmail" />
PS. You can use lodash to debounce endpoint calls to database.
import { debounce } from 'lodash';
export default {
methods: {
debouceCheckEmail() {
debounce(function () {
//check entry in database
}, 500);
}
}
}
I have a problem I tried many things but is doesn't fixed so please I need your help
this is my Vue Temp:
<form #submit.prevent="createCat" enctype="multipart/form-data" method="POST">
<div class="mt-1 relative rounded-md shadow-sm mb-3">
<input id="cat_name" type="text" v-model="categories.cat_name" />
</div>
<div class="mt-1 relative rounded-md shadow-sm mb-3 w-50">
<input name="img_url" id="img_url" accept="image/*" type="file">
</div>
<button type="submit">Add</button>
</form>
data(){
return{
categories:{
cat_name: '',
img_url: null,
},
}
},
methods:{
createCat(){
let data = new FormData();
data.append('cat_name', this.categories.cat_name);
data.append('url', this.categories.img_url);
this.$inertia.post('/categories', this.categories)
.then(()=>{
//
})
},
}
and in the Controller I tried debug the requests but it always return NULL
public function store(Request $request)
{
dump($request->file('img_url'));
dump($request->cat_name);
dump($request->all());
}
The Result
null
"name"
array:2 [▼
"cat_name" => "name"
"img_url" => null
]
As per official documentation
<template>
<form #submit.prevent="submit">
<input type="text" v-model="form.name" />
<input type="file" #input="form.avatar = $event.target.files[0]" />
<progress v-if="form.progress" :value="form.progress.percentage" max="100">
{{ form.progress.percentage }}%
</progress>
<button type="submit">Submit</button>
</form>
</template>
<script>
import { useForm } from '#inertiajs/inertia-vue3'
export default {
setup () {
const form = useForm({
name: null,
avatar: null,
})
function submit() {
form.post('/users')
}
return { form, submit }
},
}
</script>
Ref:https://inertiajs.com/file-uploads#form-data-conversion
i found the solution for this problem:
the input field must be like that:
<input name="img_url" id="img_url" type="file" #input="categories.img_url = $event.target.files[0]" />
Update
and I figure out that I have to change the variable name because I used the same variable for the props and the data variable that I want to store it and send it to backend, so I make the props from backend categories and the data that I want to store it category.
I'm currently working on an E-learning platform, where we sell courses to users that registers and make payments for that courses.
I have a HTML form and it's integrated with PayPal Checkout (sandbox) and actually the behavior I expect is that when the payment is accepted (onApprove function) the form is submited with the data I need to process on the server.
But, I was trying to imitate malicious behavior and I entered the command: document.forms[0].submit() and the form is submited without the paypal payment in between. So anybody can have the course for free.
I want to fix this issue, and I have no very much knowledge in web security. My questions:
How can I only submit the form when the Paypal payment is successful?
(Optional) Where can I learn more about this and other security issues?
payment.blade.php
<div class="container">
<form action="{{action("RegistersController#inscribir",["curso" => $curso->id])}}" method="POST">
<div class="row">
<div class="col-12 col-md-8">
<h1>Llena el formulario</h1>
#csrf
<div class="form-group">
<label for="Nombre">Ingresa tu nombre</label>
<input class="form-control" name="name" id="name" type="text" value="{{Auth::user()->name}}"/>
</div>
<div class="form-group">
<label for="email">Ingresa tu correo</label>
<input class="form-control" name="email" id="email" type="text" value="{{Auth::user()->email}}"/>
</div>
<div class="form-group">
<label for="phone">Ingresa tu número de teléfono</label>
<input class="form-control" name="phone" placeholder="+01 234 567 8910" id="phone" type="text" value=""/>
</div>
</div>
<div class="col-12 col-md-4">
<h4 class="my-3">Pagar Curso</h4>
<img src="/storage/img/cursos/{{$curso->image_square}}" alt="{{$curso->title}}" width="200px">
<h5 class="p-0 m-0">{{$curso->title}}</h5>
<small>{{substr($curso->description,0,150)}}</small>
<br>
<p>Precio: <b> <span id="price">{{number_format($curso->price,2,".","")}}</span> USD</b></p>
<br>
<input type="submit" class="btn btn-apple" style="display: none">
#if ($curso->price > 0)
<div id="paypal-button-container"></div>
#endif
</div>
</div>
</form>
</div>
<script src="https://www.paypal.com/sdk/js?client-id=<MY_CLIENT_ID>"> // Replace YOUR_SB_CLIENT_ID with your sandbox client ID
</script>
<script>
var price = document.getElementById("price").innerText;
var paypal_button = document.getElementById("paypal-button-container");
paypal.Buttons({
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
value: {{$curso->price}}
}
}]
});
},
style: {
color: 'blue',
size: 'responsive'
},
onApprove: function(data, actions) {
return actions.order.capture().then(function(details) {
// Submit the form
console.log(details);
document.forms[0].submit();
});
},
onError: function(err){
alert("Error completando la transacción");
console.error(err);
window.location.href = "/";
}
}).render('#paypal-button-container');
</script>
Marking something as paid and receiving associated form information are two separate things. One part will always need to be completed before the next can proceed. If you require the PayPal payment to be completed before the form is submitted, this will lead to issues if the process is interrupted after payment, which you must design for. Vice-versa also leads to a potential disconnect (receiving form information without a payment), which must be designed for.
The issue in your question is how to verify that a PayPal payment has taken place. This must be done on your server. The most robust way to do it is to capture the payment from your server using a server-side integration.
You'll need two server-side routes, one for 'Create an Order' and one for 'Capture Order', documented here.
The best approval front-end to pair your two routes with is: https://developer.paypal.com/demo/checkout/#/pattern/server
Recently I have been working to insert data into a database with laravel. Everything went fine. But know I am stuck with the error: "Use of undefined constant contacts - assumed 'contacts'". I do not know how to fix this.
I have already on the Laracast website to see if I could find an explanation on how to solve this, but I couldn't since the answers were not the once I was looking for. I have also looked in StackOverflow. But there were (again) no answers that could help me fix this the problem. I also have asked a classmate of mine but he also couldn't fix it.
My controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\contacts;
class ContactsController extends Controller
{
/*Haal alle data op uit de contact tabel return een view file*/
public function index($contact = contacts){
$Contact = contacts::all();
return view('contact',compact('contacts'));
}
/*Return een view file*/
public function create(){
return view('contacts');
}
public function storeContact(){
/*Maakt nieuwe variabele, wanneer er op de knop wordt geklikt worden er 2 waardes opgehaald.*/
$contacts = new contacts();
$contacts->name = request('voornaam');
$contacts->description = request('bericht');
$contacts->save();
return redirect('/contacts');
}
}
My view:
#extends ('Layout')
#section('title')
Contact
#endsection
#section('content')
<br>
<h2>Contact</h2>
<p>Voor verdere informatie (die u niet op onze website kunt vinden) kunt u ons bereiken op onze email of telefoonnummer:</p>
<p>Email: Cronensteynfake#gmail.com</p>
<p>telefoonnummer: 06-11122234</p>
<br>
U kunt ook ons contactformulier invullen.
<br><br>
<h2>Cronenstyn Contactformulier</h2>
<form action="" method="post">
#csrf
<div class="form-group">
<label for="exampleInputPassword1">Voornaam</label>
<input type="text" class="form-control" id="Vnaam" placeholder="Voornaam">
</div>
<div class="form-group">
<label for="exampleInputPassword1">Achternaam</label>
<input type="text" class="form-control" id="Anaam" placeholder="Achternaam">
</div>
<div class="form-group">
<label for="exampleInputEmail1">Email</label>
<input type="email" class="form-control" id="Email" aria-describedby="emailHelp" placeholder="Uw email">
<small id="emailHelp" class="form-text text-muted">Wij delen uw email met niemand</small>
</div>
<label for="exampleInputEmail1">Bericht</label>
<div class="form-group shadow-textarea">
<textarea class="form-control z-depth-1" id="bericht" rows="3" placeholder="Uw bericht"></textarea>
</div>
<button onclick="Message()" type="submit" class="btn btn-primary">Verzenden</button>
<script>
function Message() {
alert("Uw bericht is met succes verstuurd.");
}
</script>
</form>
#endsection
My route:
<?php
Route::get('/', function () {
return view('welcome');
});
Route::GET('/home',('CronensteynController#home'));
Route::GET('/nieuws',('CronensteynController#nieuws'));
Route::GET('/galerij',('CronensteynController#gallerij'));
Route::GET('/activiteit',('CronensteynController#activiteit'));
Route::GET('/contact',('CronensteynController#contact'));
Route::GET('/about',('CronensteynController#about'));
Route::get('/beheer', 'PageController#beheer');
Route::get('/create_beheer', 'PageController#Create_beheer');
Route::get('/update_beheer', 'PageController#Update_beheer');
Route::get('/delete_beheer', 'PageController#delete_beheer');
Route::post('/create_beheer', 'CreateBeheerController#store');
Route::post('/contact', 'contactsController#index');
Hopefully I have given you enough info and code about the problem.
Greetings,
Parsa_237
Follow a convention to avoid errors regarding cases.
Generally models start with a capital letter.
Always make your model name singular. For model Contact laravel will look the table contacts.
For more information on naming convention you can follow this link
Here you are passing $contact to index method you don't have to do that.
public function index(){
$Contacts = contacts::all();
return view('contact',compact('Contacts'));
}