I am trying to send email that has to contain static image. The problem involves the way how to pass src for image. I mean for now I have to provide full path with origin like http://localhost:3000/logo.png and it works. But is this possible to provide only relative path for instance src=logo.png and it would work the same way?
Here is my hbs file:
<h2 class="header">Welcome {{ name }},</h2>
<p>Please the link click below to confirm your email address</p>
<p>
Confirm your email
</p>
<p>If you did not request this email you can safely ignore it.</p>
<br>
<footer >
<p>Best regards, <br><br> Bookify team</p>
<div class="image-container">
<img src="http://localhost:3000/logo.png" alt="Bookify logo">
</div>
</footer>
main.ts:
app.useStaticAssets(join(__dirname, '..', 'public'));
app.setBaseViewsDir(join(__dirname, '..', 'views'));
app.setViewEngine('hbs');`
app.module.ts:
ServeStaticModule.forRoot({
rootPath: join(__dirname, '..', 'public'),
}),
nest-cli.json:
"compilerOptions": {
"assets": [
{
"include": "../views/**/*.hbs",
"outDir": "dist/views"
},
{
"include": "../public/**/*.{png, jpg}",
"outDir": "dist/public"
}
],
"watchAssets": true
}
Configuration for mailermodule:
export const mailerConfig: MailerAsyncOptions = {
useFactory: () =>
({
transport: {
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
secure: false,
auth: {
user: process.env.SMTP_AUTH_USER,
pass: process.env.SMTP_AUTH_PASSWORD,
},
},
defaults: {
from: process.env.WEBSITE_EMAIL,
},
template: {
dir: join(__dirname, '../../views'),
adapter: new HandlebarsAdapter(),
options: {
strict: true,
},
},
} as MailerOptions),
};
Related
I'm building a login page and to pass the token from the backend I modify my nuxt config file with this strategy:
auth: {
strategies: {
local: {
endpoints: {
login: { url: '/auth/login', method: 'post', propertyName: 'meta.token' },
logout: { url: '/auth/logout', method: 'post' },
}
}
}
},
my login page:
<div>
<div>
<form action="#" #submit.prevent="login">
<b-form-input
v-model="form.name"
id="input-default"
placeholder="Enter Username"
type="text"
></b-form-input>
<b-form-input
v-model="form.password"
placeholder="Enter Password"
type="password"
></b-form-input>
<b-button type="submit" variant="success">Login</b-button>
</form>
</div>
</div>
</template>
<script>
export default {
data() {
return {
form: {
name: "",
password: "",
},
};
},
methods: {
async login() {
try {
await this.$auth.loginWith('local', {
data: this.form,
});
this.$router.push({path : "index"});
} catch (error) {
this.messageError = error
}
},
},
};
</script>
Server-side I've added a custom response that returns login data in this way
{
"success": true,
"message": "",
"code": 200,
"data": {
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwMDAvYXBpL2F1dGgvbG9naW4iLCJpYXQiOjE2NzExMzA2NDUsImV4cCI6MTY3MTEzNDI0NSwibmJmIjoxNjcxMTMwNjQ1LCJqdGkiOiJQcXc1bHNmY1JWN2dLdVZUIiwic3ViIjoiMyIsInBydiI6IjIzYmQ1Yzg5NDlmNjAwYWRiMzllNzAxYzQwMDg3MmRiN2E1OTc2ZjcifQ.0IB-Efk3RaZY4NzHRIQS0CmH95KKa4-vF3dNJG2fNBg"
}
}
I receive the error
TypeError: Cannot use 'in' operator to search for 'meta.token'
OP solved that one by fixing a proxy issue. Was probably a typo or something similar.
I am writing a SPA application (laravel + vue). There was a question how to hide routes in vue-router before authorization of a user with a certain role.
Now there is such a router.js fight with routes.
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../components/Calendar.vue'
import PermissionList from '../components/PermissionList.vue'
import BoardsList from '../components/BoardsList.vue'
import UsersList from '../components/UsersList.vue'
import Login from '../components/Login.vue'
const routes = [{
path: '/',
name: 'Home',
component: Home
},
{
path: '/permission-list',
name: 'PermissionList',
component: PermissionList
},
{
path: '/boards-list',
name: 'BoardsList',
component: BoardsList
},
{
path: '/users-list',
name: 'UsersList',
component: UsersList
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/dsad',
name: 'asd',
component: Login
},
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
linkActiveClass: "active",
})
router.beforeEach((to, from, next) => {
const token = localStorage.getItem('token');
if (!token) {
if (to.name == 'Login') {
next();
} else {
next({
name: 'Login'
});
}
} else {
if (to.name == 'Login') {
next({
name: 'Home'
});
} else {
next();
}
}
})
export default router
User data including his role and jwt token come after authorization and are stored in localstorage.
<template>
<main class="form-signin text-center">
<div>
<h1 class="h3 mb-3 fw-normal">Form</h1>
<div class="form-floating">
<input
type="text"
class="form-control"
placeholder="Login"
v-model="login"
/>
<label for="floatingInput">Login</label>
</div>
<div class="form-floating my-2">
<input
type="password"
class="form-control"
placeholder="Pass"
v-model="password"
/>
<label for="floatingPassword">Pass</label>
</div>
<a class="w-100 btn btn-lg btn-primary" #click="logIn()">
Login
</a>
</div>
</main>
</template>
<script>
export default {
name:'Login',
data() {
return {
login:"",
password:"",
};
},
methods: {
logIn() {
this.HTTP.get('/sanctum/csrf-cookie').then(response => {
this.HTTP.post("/login",{
email:this.login,
password:this.password,
})
.then((response) => {
localStorage.setItem('token',response.config.headers['X-XSRF-TOKEN']);
localStorage.setItem('user',JSON.stringify(response.data.user));
this.$emit('loginUpdate');
this.$router.push('/');
})
.catch((error) => {
console.log(error);
});
});
},
},
};
</script>
<style>
.form-signin {
width: 100%;
max-width: 330px;
padding: 15px;
margin: auto;
}
.form-signin .checkbox {
font-weight: 400;
}
</style>
if you go to the vue developer panel, all routes will be visible even before the user is authorized, how can I hide them so that unauthorized users do not see the site structure.
did you solve this problem?
Just use separated js file using your mixin laravel config. One login.js, another app.js and then use each of them in separated view-laravel
i use izitoast,
i need use $route in button function in vue-izitoast but it doesn't work
or
i don't know how return value of this function to use in vue
buttons: [
[
"<button><b>yes</b></button>",
function() {
axios
.post(`/student/rooms`, {
room_id: room.id
})
.then(res => {
this.$router.push(`/student/rooms/${room.id}`);
});
},
true
],
You must use an Arrow Function to get local scope. Try this:
<template>
<div id="app">
<div>
<button #click="test">TEST</button>
</div>
<router-view />
</div>
</template>
<script>
export default {
name: 'App',
methods: {
test() {
this.$toast.show('Welcome!', 'Hey', {
position: 'topCenter',
buttons: [
[
'<button>Change Router</button>',
(instance, toast) => {
this.$router.push({ name: 'About' });
},
true,
],
],
});
},
},
};
</script>
I have installed and configured Laravel 7.3 Passport, then I made a fresh install of Nuxt.js and configure it as explained here (works perfect with Laravel 5.8.34). But when logging in, I get a CORS error message in the javascript console:
Access to XMLHttpRequest at 'http://my-laravel.test/oauth/token' from
origin 'http://localhost:3000' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
Below is how I configured Nuxt.js:
pages/index.vue
<template>
<section class="container">
<div>
<strong>Home Page</strong>
<pre>Both guests and logged in users can access!</pre>
<nuxt-link to="/login">Login</nuxt-link>
</div>
</section>
</template>
pages/login.vue
<template>
<div class="container">
<div class="row justify-content-center mt-5">
<div class="col-md-5">
<form>
<div class="form-group">
<input
v-model="user.username"
class="form-control"
placeholder="Username"
/>
</div>
<div class="form-group">
<input
v-model="user.password"
type="password"
class="form-control"
placeholder="Password"
/>
</div>
<button
#click.prevent="passwordGrantLogin"
type="submit"
class="btn btn-primary btn-block"
>
Login with Password Grant
</button>
</form>
</div>
</div>
</div>
</template>
<script>
export default {
middleware: 'guest',
data() {
return {
user: {
username: '',
password: ''
}
}
},
mounted() {},
methods: {
async passwordGrantLogin() {
await this.$auth.loginWith('password_grant', {
data: {
grant_type: 'password',
client_id: process.env.PASSPORT_PASSWORD_GRANT_ID,
client_secret: process.env.PASSPORT_PASSWORD_GRANT_SECRET,
scope: '',
username: this.user.username,
password: this.user.password
}
})
}
}
}
</script>
pages/profile.vue
<template>
<section class="container">
<div>
<strong>Strategy</strong>
<pre>{{ strategy }}</pre>
</div>
<div>
<strong>User</strong>
<pre>{{ $auth.user }}</pre>
</div>
<button #click="logout" class="btn btn-primary">
Logout
</button>
</section>
</template>
<script>
export default {
middleware: 'auth',
data() {
return {
strategy: this.$auth.$storage.getUniversal('strategy')
}
},
mounted() {},
methods: {
async logout() {
await this.$auth.logout()
}
}
}
</script>
nuxt.config.js (partly)
/*
** Nuxt.js modules
*/
modules: [
// Doc: https://axios.nuxtjs.org/usage
'#nuxtjs/axios',
'#nuxtjs/proxy',
'#nuxtjs/pwa',
'#nuxtjs/auth',
'#nuxtjs/dotenv',
'bootstrap-vue/nuxt'
],
/*
** Axios module configuration
** See https://axios.nuxtjs.org/options
*/
axios: {
baseURL: process.env.LARAVEL_ENDPOINT,
// proxy: true
},
// Proxy module configuration
proxy: {
'/api': {
target: process.env.LARAVEL_ENDPOINT,
pathRewrite: {
'^/api': '/'
}
}
},
// Auth module configuration
auth: {
// redirect: {
// login: '/login',
// logout: '/',
// callback: '/login',
// home: '/profile'
// },
// strategies: {
// 'laravel.passport': {
// url: '/',
// client_id: process.env.PASSPORT_PASSWORD_GRANT_ID,
// client_secret: process.env.PASSPORT_PASSWORD_GRANT_SECRET
// }
// }
strategies: {
local: false,
password_grant: {
_scheme: 'local',
endpoints: {
login: {
url: '/oauth/token',
method: 'post',
propertyName: 'access_token'
},
logout: false,
user: {
url: 'api/auth/me',
method: 'get',
propertyName: 'user'
}
}
}
}
},
middleware/guest.js
export default function({ store, redirect }) {
if (store.state.auth.loggedIn) {
return redirect('/')
}
}
.env
LARAVEL_ENDPOINT='http://my-laravel.test/'
PASSPORT_PASSWORD_GRANT_ID=6
PASSPORT_PASSWORD_GRANT_SECRET=p9PMlcO***********GFeNY0v7xvemkP
As you can see in the commented code source, I also tried unsuccessfully with proxy as suggested here and with auth strategy laravel.passport as suggested here.
Go to cors.php and make sure you have oauth endpoint like api/* or laravel sanctum.
You have to clear config and cache before test again
So im creating a basic tasklist where i want to set them done, when the <li>is clicked. When it's clicked i want that a class is added to the <li> thats clicked. i could not figure this out with the docs so i hope someone could help me out :D
The code i already have:
<transition-group name="list">
<li class="list-item list-group-item" v-for="(task, index) in list" :key="task.id" v-on:click="finishTask(task.id)" >
#{{ task.text }}
<button #click="removeTask(task.id)" class="btn btn-danger btn-xs pull-right">Delete</button>
</li>
</transition-group>
</ul>
</div>
// get the csrf token from the meta
var csrf_token = $('meta[name="csrf-token"]').attr('content');
export default {
data() {
return {
list: [],
taskInput: {
id: '',
text: ''
}
};
},
// So the tasks will show when the page is loaded
created() {
this.allTasks();
},
methods: {
// get all the existing tasks
allTasks() {
axios.get('tasks').then((response) => {
this.list = response.data;
});
},
// create a new task
createTask() {
axios({
method: 'post',
url: '/tasks',
data: {
_token: csrf_token,
text: this.taskInput.text,
},
}).then(response => {
this.taskInput.text = '';
this.allTasks();
});
},
// remove the tasks
removeTask(id) {
axios.get('tasks/' + id).then((response) => {
this.allTasks();
});
},
finishTask(id) {
axios({
method: 'post',
url: 'tasks/done/' + id,
data: {
_token: csrf_token,
data: this.taskInput,
},
}).then(response => {
this.allTasks();
});
}
}
}
I know how i should do this with jquery but not with vue js, i hope this aint a to stupid question :D
You can bind css classes and styles, add a Boolean done property to your note object with default value of false, when you click the note change its done property to true. here is an example
new Vue({
el:"#app",
data:{
notes: [
{ text: "First note", done:false },
{ text: "Second note", done:false },
{ text: "Third note", done:false },
{ text: "Fourth note", done:false },
{ text: "Fifth note", done:false }
]
},
methods:{
finishNote(note){
// send your api request
// then update your note
note.done = true
}
}
})
.done{
background-color:green;
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.13/dist/vue.min.js"></script>
<div id="app">
<ul>
<li v-for="note in notes" :class="{done:note.done}" #click="finishNote(note)">{{note.text}}</li>
</ul>
</div>
You can use the event argument. Which is automatically provided on your on click method.
onListClicked(event) {
event.target.className += " myClass";
}
Here I did a demo for you: https://jsfiddle.net/6wpbp70g/