Laravel: Uncaught (in promise) Error: Request failed with status code 422 - javascript

Hi, currently I facing this issue. I can fix it. I have no idea why the error occurs.
Basically, I trying to save the data into DB. I used the Axios method to fetch and save data. Before this, the function was working perfectly but suddenly its causing problems. Please, anyone help me with this.
Vue.js
<script>
import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'
import MarkdownIt from 'markdown-it'
import ClassicEditor from '#ckeditor/ckeditor5-build-classic';
var msg_editor;
Vue.use(VueAxios, axios);
const md = new MarkdownIt({
linkify: true
})
// Vue.directive('select2', {
// inserted(el) {
// $(el).on('select2:select', () => {
// const event = new Event('change', { bubbles: true, cancelable: true });
// el.dispatchEvent(event);
// });
// },
// });
// $('#condition').select2();
export default {
props: ['email_creation_link', 'email_index_route', 'email_edit_route','conditions','modules','mailtemplates'],
components: {
},
data() {
return {
template:
{
subject: '',
message: '' ,
days: '',
condition_id: 1,
},
options:[
{
display:'Client Name',
actual:'Client name'
},
{
display:'Joined Date',
actual:'Joined date'
},
{
display:'Module Name',
actual:'Module name'
},
{
display:'Last Seen',
actual:'Last seen'
},
],
showName: false,
}
},
mounted(){
var self = this;
ClassicEditor
.create(document.querySelector( "#msg"),
{
})
.then(editor => {
msg_editor = editor;
editor.model.document.on( 'change:data', () => {
self.template.message = msg_editor.getData();
});
})
.catch(error => {
console.error(error);
})
if (this.mailtemplates) {
this.template=this.mailtemplates;
}
},
methods: {
//Drag items
dragstart: function(item, e){
this.draggingItem = item;
e.dataTransfer.setData('text/plain', item.actual);
},
dragend: function(item,e) {
e.target.style.opacity = 1;
},
dragenter: function(item, e) {
this.draggingItem = item;
},
//content
replaceVariables(input)
{
let updated = input
return updated
},
//hidecontent
showHide: function(e)
{
console.log("Show "+e.target.value+ " fields")
this.showName = e.target.value == '3'
},
fetch()
{
//request data
axios.get(this.email_creation_link,this.template)
.then((res) => {
this.template = res.data.template;
})
},
save()
{
//save data to db
axios.post(this.email_creation_link, this.template)
.then((res) => {
alert('Mail sent successfull!')
})
},
addToMail: function(type, text)
{
if (type == 'message') {
this.template.message += text;
msg_editor.setData(this.template.message);
}
},
//user name replace
replaceVariables() {
return this.replaceVariables(this.options || '')
},
},
}
</script>
route.php
Route::post('api/email/create', ['as' => 'email.create', 'uses' => 'Havence\AutoMailController#create']);
Route::get('automail/mail',['as'=>'email.mail','uses' => 'Havence\AutoMailController#mail']);
Route::get('automail/index',['as'=>'email.index','uses' => 'Havence\AutoMailController#index']);
Route::get('automail/edit/{id}',['as'=>'email.edit','uses' => 'Havence\AutoMailController#edit']);
Route::get('automail/delete',['as'=>'email.delete','uses' => 'Havence\AutoMailController#destroy']);

Related

Rxdb infinitely pulling in replicateRxCollection

I'm working with rxdb and I have pull and push handlers for the backend I have used supabase
I have setup the code for replication as follows:
replication.ts
import { RxDatabase } from "rxdb";
import { RxReplicationPullStreamItem } from "rxdb/dist/types/types";
import { replicateRxCollection } from "rxdb/plugins/replication";
import { Subject } from "rxjs";
import { supabaseClient, SUPABASE_URL } from "src/config/supabase";
import { DbTables } from "src/constants/db";
import {
blockPullHandler,
blockPushHandler,
} from "./repilicationhandlers/block";
import { CheckpointType, RxBlockDocument, RxBlocksCollections } from "./types";
export async function startReplication(
database: RxDatabase<RxBlocksCollections>
) {
const pullStream$ = new Subject<
RxReplicationPullStreamItem<RxBlockDocument, CheckpointType>
>();
supabaseClient
.from(DbTables.Block)
.on("*", (payload) => {
console.log("Change received!", payload);
const doc = payload.new;
pullStream$.next({
checkpoint: {
id: doc.id,
updated: doc.updated,
},
documents: [doc] as any,
});
})
.subscribe((status: string) => {
console.log("STATUS changed");
console.dir(status);
if (status === "SUBSCRIBED") {
pullStream$.next("RESYNC");
}
});
const replicationState = await replicateRxCollection({
collection: database.blocks,
replicationIdentifier: "supabase-replication-to-" + SUPABASE_URL,
deletedField: "archived",
pull: {
handler: blockPullHandler as any,
stream$: pullStream$.asObservable(),
batchSize: 10,
},
push: {
batchSize: 1,
handler: blockPushHandler as any,
},
});
replicationState.error$.subscribe((err) => {
console.error("## replicationState.error$:");
console.log(err);
});
return replicationState;
}
blockPullHandler:
export const blockPullHandler = async (
lastCheckpoint: any,
batchSize: number
) => {
const minTimestamp = lastCheckpoint ? lastCheckpoint.updated : 0;
console.log("Pulling data", batchSize, lastCheckpoint);
const { data, error } = await supabaseClient
.from(DbTables.Block)
.select()
.gt("updated", minTimestamp)
.order("updated", { ascending: true })
.limit(batchSize);
if (error) {
console.log(error);
throw error;
}
const docs: Array<Block> = data;
return {
documents: docs,
hasMoreDocuments: false,
checkpoint:
docs.length === 0
? lastCheckpoint
: {
id: lastOfArray(docs).id,
updated: lastOfArray(docs).updated,
},
};
};
blockPushHandler:
export const blockPushHandler = async (
rows: RxReplicationWriteToMasterRow<RxBlockDocumentType>[]
) => {
if (rows.length !== 1) {
throw new Error("# pushHandler(): too many push documents");
}
const row = rows[0];
const oldDoc: any = row.assumedMasterState;
const doc: Block = row.newDocumentState;
console.log(row, oldDoc, doc);
// insert
if (!row.assumedMasterState) {
const { error } = await supabaseClient.from(DbTables.Block).insert([doc]);
console.log("Error 1", error);
if (error) {
// we have an insert conflict
const conflictDocRes: any = await supabaseClient
.from(DbTables.Block)
.select()
.eq("id", doc.id)
.limit(1);
return [conflictDocRes.data[0]];
} else {
return [];
}
}
// update
console.log("pushHandler(): is update");
const { data, error } = await supabaseClient
.from(DbTables.Block)
.update(doc)
.match({
id: doc.id,
replicationRevision: oldDoc.replicationRevision,
});
console.log("Error 2", error);
if (error) {
console.log("pushHandler(): error:");
console.log(error);
console.log(data);
throw error;
}
console.log("update response:");
console.log(data);
if (data.length === 0) {
// we have an updated conflict
const conflictDocRes: any = await supabaseClient
.from(DbTables.Block)
.select()
.eq("id", doc.id)
.limit(1);
return [conflictDocRes.data[0]];
}
return [];
};
But the issue is when I start the application and the pull handler is called correctly but it doesn't stop calling the pull handler and it sends continuous request one after another even after it has fetched the documents even when I set hasMoreDocuments to false It keeps sending requests and running the replicator. Is there something wrong with my configuration?
database.ts:
export const createDatabase = async () => {
const database = await createRxDatabase({
name: "sundaedb",
storage: getRxStorageDexie(),
});
await database.addCollections({
blocks: {
schema: blockSchema as any,
conflictHandler: conflictHandler as any,
},
documents: {
schema: documentSchema as any,
conflictHandler: conflictHandler as any,
},
});
database.blocks.preInsert((docData) => {
docData.replicationRevision = createRevision(
database.hashFunction,
docData as any
);
return docData;
}, false);
database.blocks.preRemove((docData) => {
console.log(" PRE REMOVE !!");
console.log(JSON.stringify(docData, null, 4));
const oldRevHeight = parseRevision(docData.replicationRevision).height;
docData.replicationRevision =
oldRevHeight + 1 + "-" + database.hashFunction(JSON.stringify(docData));
console.log(JSON.stringify(docData, null, 4));
return docData;
}, false);
database.blocks.preSave((docData) => {
const oldRevHeight = parseRevision(docData.replicationRevision).height;
docData.replicationRevision =
oldRevHeight + 1 + "-" + database.hashFunction(JSON.stringify(docData));
return docData;
}, false);
return database;
};

Get source in constructor

I'm trying to make a search with autocomplete, tell me how I can get in the constructor an array of label and results with axios get
new Autocomplete(input, {
source: (response) => {
axios.get('{{ route('api.autocomplete) }}', {
params: {
term: input.value
}
})
.then(response => {
return {
label: response.data.name,
results: response.data.children,
}
})
},
select: ({element}) => {
alert(element);
}
});
class Autocomplete {
constructor(element, {
source = () => {},
select = () => {},
}) {
console.log(source);
}
}
Instead of an array, it gives out a piece of axios request code

Vuex: Wait for websocket response before dispatching action

So this is the scenario / premises:
In order to populate a chat queue in real time I need to open a connection to a websocket, send a message and then set the data to a websocket store. This store will basically manage all the websocket state.
Before populating the chat queue there's two parameters I need: a shiftId coming from one http API request and a connectionId coming from the websocket. Using those two parameters I finally can subscribe to a third http API and start receiving messages to populate the chat queue.
The problem is that due to the async behaviour of the websocket (or that's what I think, please feel to correct me if I'm wrong) I always get an empty "connectionId" when trying to make the put to that "subscription" API. I have tried with async/await and promises but nothing seems to work. I'm pretty new to async/await and websockets with Vuex so pretty sure I'm doing something wrong.
This is the user vuex module where I do all the login/token operations and dispatch a "updateEventsSubscription" action from the shift vuex module. In order for the "updateEventsSubscription" action to work I need to get the response from the "processWebsocket" action (to get the connectionId parameter) and from the "startShift" action (to get the shiftId parameter) coming from the shifts vuex module:
import UserService from '#/services/UserService.js'
import TokenService from '#/services/TokenService.js'
import router from '#/router'
export const namespaced = true
export const state = {
accessToken: '',
errorMessage: '',
errorState: false,
userEmail: localStorage.getItem('userEmail'),
userPassword: localStorage.getItem('userPassword'),
}
export const mutations = {
SET_TOKEN(state, accessToken) {
state.accessToken = accessToken
TokenService.saveToken(accessToken)
},
SET_USER(state, authUserJson) {
state.userEmail = authUserJson.email
state.userPassword = authUserJson.password
localStorage.setItem('userPassword', authUserJson.password)
localStorage.setItem('userEmail', authUserJson.email)
},
SET_ERROR(state, error) {
state.errorState = true
state.errorMessage = error.data.error_description
},
CLOSE_NOTIFICATION(state, newErrorState) {
state.errorState = newErrorState
},
}
export const actions = {
signIn({ commit, dispatch, rootState }, authUserJson) {
return UserService.authUser(authUserJson)
.then((result) => {
commit('SET_USER', authUserJson)
commit('SET_TOKEN', result.data.access_token)
dispatch('token/decodeToken', result.data.access_token, {
root: true,
})
dispatch(
'shifts/updateEventsSubscription',
rootState.token.agentId,
{
root: true,
}
)
router.push('/support')
})
.catch((error) => {
console.log(error)
if (error.response.status === 400) {
commit('SET_TOKEN', null)
commit('SET_USER', {})
commit('SET_ERROR', error.response)
} else {
console.log(error.response)
}
})
},
signOut({ commit }) {
commit('SET_TOKEN', null)
commit('SET_USER', {})
localStorage.removeItem('userPassword')
localStorage.removeItem('userEmail')
TokenService.removeToken()
router.push('/')
},
closeNotification({ commit }, newErrorState) {
commit('CLOSE_NOTIFICATION', newErrorState)
},
}
export const getters = {
getToken: (state) => {
return state.accessToken
},
errorState: (state) => {
return state.errorState
},
errorMessage: (state) => {
return state.errorMessage
},
isAuthenticated: (state) => {
return state.accessToken
},
userEmail: (state) => {
return state.userEmail
},
userPassword: (state) => {
return state.userPassword
},
}
This is websocket store: I pass the connectionId to the state in order to be able to use it in another vuex action to subscribe for new chats:
export const namespaced = true
export const state = {
connected: false,
error: null,
connectionId: '',
statusCode: '',
incomingChatInfo: [],
remoteMessage: [],
messageType: '',
ws: null,
}
export const actions = {
processWebsocket({ commit }) {
const v = this
this.ws = new WebSocket('mywebsocket')
this.ws.onopen = function (event) {
commit('SET_CONNECTION', event.type)
v.ws.send('message')
}
this.ws.onmessage = function (event) {
commit('SET_REMOTE_DATA', event)
}
this.ws.onerror = function (event) {
console.log('webSocket: on error: ', event)
}
this.ws.onclose = function (event) {
console.log('webSocket: on close: ', event)
commit('SET_CONNECTION')
ws = null
setTimeout(startWebsocket, 5000)
}
},
}
export const mutations = {
SET_REMOTE_DATA(state, remoteData) {
const wsData = JSON.parse(remoteData.data)
if (wsData.connectionId) {
state.connectionId = wsData.connectionId
console.log(`Retrieving Connection ID ${state.connectionId}`)
} else {
console.log(`We got chats !!`)
state.messageType = wsData.type
state.incomingChatInfo = wsData.documents
}
},
SET_CONNECTION(state, message) {
if (message == 'open') {
state.connected = true
} else state.connected = false
},
SET_ERROR(state, error) {
state.error = error
},
}
And finally this is the shift store (where the problem is), as you can see I have a startShift action (everything works fine with it) and then the "updateEventsSubscription" where I'm trying to wait for the response from the "startShift" action and the "processWebsocket" action. Debugging the app I realize that everything works fine with the startShift action but the websocket action sends the response after the "updateEventsSubscription" needs it causing an error when I try to make a put to that API (because it needs the connectionId parameter coming from the state of the websocket).
import ShiftService from '#/services/ShiftService.js'
export const namespaced = true
export const state = {
connectionId: '',
shiftId: '',
agentShiftInfo: '{}',
}
export const actions = {
startShift({ commit }, agentId) {
return ShiftService.startShift(agentId)
.then((response) => {
if (response.status === 200) {
commit('START_SHIFT', response.data.aggregateId)
}
})
.catch((error) => {
console.log(error)
if (error.response.status === 401) {
console.log('Error in Response')
}
})
},
async updateEventsSubscription({ dispatch, commit, rootState }, agentId) {
await dispatch('startShift', agentId)
const shiftId = state.shiftId
await dispatch('websocket/processWebsocket', null, { root: true })
let agentShiftInfo = {
aggregateId: state.shiftId,
connectionId: rootState.websocket.connectionId,
}
console.log(agentShiftInfo)
return ShiftService.updateEventsSubscription(shiftId, agentShiftInfo)
.then((response) => {
commit('UPDATE_EVENTS_SUBSCRIPTION', response.data)
})
.catch((error) => {
if (error.response.status === 401) {
console.log('Error in Response')
}
})
},
}
export const mutations = {
START_SHIFT(state, shiftId) {
state.shiftId = shiftId
console.log(`Retrieving Shift ID: ${state.shiftId}`)
},
UPDATE_EVENTS_SUBSCRIPTION(state, agentShiftInfo) {
state.agentShiftInfo = agentShiftInfo
},
}
You should convert your WebSocket action into a promise that resolves when WebSocket is connected.:
export const actions = {
processWebsocket({ commit }) {
return new Promise(resolve=> {
const v = this
this.ws = new WebSocket('mywebsocket')
this.ws.onopen = function (event) {
commit('SET_CONNECTION', event.type)
v.ws.send('message')
resolve();
}
this.ws.onmessage = function (event) {
commit('SET_REMOTE_DATA', event)
}
this.ws.onerror = function (event) {
console.log('webSocket: on error: ', event)
}
this.ws.onclose = function (event) {
console.log('webSocket: on close: ', event)
commit('SET_CONNECTION')
ws = null
setTimeout(startWebsocket, 5000)
}
});
},
}
So I realized that I have to resolve the promise on the this.ws.message instead. By doing that all my data is populated accordingly, there's still sync issues (I can't feed the websocket state at the moment because due to its async behaviour the state is not there yet when other components try to use it via: rootGetters.websocket.incomingChats for example) but I guess that's part of another question. Here's the final version of the module action:
export const actions = {
processWebsocket({ commit }) {
return new Promise((resolve) => {
const v = this
this.ws = new WebSocket('wss://ws.rubiko.io')
this.ws.onopen = function (event) {
commit('SET_CONNECTION', event.type)
v.ws.send('message')
}
this.ws.onmessage = function (event) {
commit('SET_REMOTE_DATA', event)
resolve(event)
}
this.ws.onerror = function (event) {
console.log('webSocket: on error: ', event)
}
this.ws.onclose = function (event) {
console.log('webSocket: on close: ', event)
commit('SET_CONNECTION')
ws = null
setTimeout(startWebsocket, 5000)
}
})
},
}
Anyways, thanks #Eldar you were in the right path.

How can I pull gmail data with Vue.js

I'm essentially trying to create an application for myself that I can manage my emails etc. with Vue.js
I've managed to get authorisation working using an npm package called vue-googleapis
However I am now trying to pull data from my (or the users) gmail account but running into some errors.
Here's my existing code in my component:
<div class="gmail-init">
<h1>Google APIs example - oAuth2 (vuex)</h1>
<p>isReady: {{ gauthReady }}</p>
<p>isSignedIn: {{ isSignedIn }}</p>
<p v-if="isSignedIn && user">{{ user.getBasicProfile().getName() }}</p>
<button :disabled="isSignedIn || !gauthReady" #click="signIn">Sign In</button>
<button :disabled="!isSignedIn || !gauthReady" #click="signOut">Sign Out</button>
<button :disabled="!isSignedIn || !gauthReady" #click="disconnect">Disconnect</button>
<button :disabled="!isSignedIn || !gauthReady" #click="labels">Labels</button>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
export default {
name: 'GmailInit',
computed: {
...mapGetters('gauth', {
gauthReady: 'isReady',
isSignedIn: 'isSignedIn',
user: 'getUser'
})
},
mounted () {
this.$store.dispatch('gauth/init')
},
methods: {
...mapActions('gauth', {
signIn: 'signIn',
signOut: 'signOut',
disconnect: 'disconnect'
}),
async labels () {
console.log('labels called')
const auth = this.isSignedIn
// const response = await this.$google.api.client.youtube.playlists.list({
const gmail = this.$google.gmail({ version: 'v1', auth })
const response = await gmail.users.labels.list({
// mine: true
userId: 'me'
// part: "snippet",
})
const labels = response.data.labels
if (labels.length) {
console.log(response.result.items)
labels.forEach((label) => {
console.log(`- ${label.name}`)
})
// this.playlistItems = response.result.items
} else {
console.log('error')
}
}
}
}
</script>
and here's my code for the import (vuex/store)
const STATUS_LOADING = 'loading'
const STATUS_READY = 'ready'
export default {
namespaced: true,
state: {
status: STATUS_LOADING,
signedId: null,
user: null,
error: null
},
mutations: {
setStatus (state, status) {
state.status = status
},
setSignedIn (state, signedId) {
state.signedId = signedId
},
setError (state, error) {
state.error = error
},
setUser (state, user) {
state.user = user
}
},
actions: {
init (context) {
const google = this._vm.$google
const load = setInterval(function () {
if (google.isInit) {
context.commit('setStatus', STATUS_READY)
context.commit(
'setSignedIn',
google.api.auth2.getAuthInstance().isSignedIn.get()
)
google.api.auth2.getAuthInstance().isSignedIn.listen(function (signedId) {
context.commit('setSignedIn', signedId)
})
google.api.auth2.getAuthInstance().currentUser.listen(function (user) {
context.commit('setUser', user)
})
clearInterval(load)
}
})
},
async signIn (context) {
try {
await this._vm.$google.api.auth2.getAuthInstance().signIn()
} catch (e) {
console.error(e)
context.commit('setError', e.error)
}
},
async signOut (context) {
try {
await this._vm.$google.api.auth2.getAuthInstance().signOut()
} catch (e) {
console.error(e)
context.commit('setError', e.error)
}
},
async disconnect (context) {
try {
await this._vm.$google.api.auth2.getAuthInstance().disconnect()
} catch (e) {
console.error(e)
context.commit('setError', e.error)
}
}
},
getters: {
isReady (state) {
return state.status === STATUS_READY
},
isSignedIn (state) {
return state.signedId === true
},
getUser (state) {
return state.user
}
}
}
the main function that isn't working:
async labels () {
console.log('labels called')
const auth = this.isSignedIn
// const response = await this.$google.api.client.youtube.playlists.list({
const gmail = this.$google.gmail({ version: 'v1', auth })
const response = await gmail.users.labels.list({
// mine: true
userId: 'me'
// part: "snippet",
})
const labels = response.data.labels
if (labels.length) {
console.log(response.result.items)
labels.forEach((label) => {
console.log(`- ${label.name}`)
})
// this.playlistItems = response.result.items
} else {
console.log('error')
}
}

Why is my test passing?

The SUT is just:
#Injectable()
export class GetLocationService {
getPosition(): Observable<Object> {
return Observable.create(observer => {
navigator.geolocation.getCurrentPosition((pos: Position) => {
observer.next(pos);
observer.complete();
}),
() => {
alert('Position is not available');
},
{
enableHighAccuracy: true
};
});
}
}
and my test for it is the following:
export const POSITION_INFO_FAKE_JSON = {
coords: {
latitude: 32,
longitude: 27
}
};
describe('Get location service', () => {
beforeEachProviders(() => [
GetLocationService
]);
it('should get current position', inject([GetLocationService], (getLocationService) => {
navigator.geolocation = <any>{ getCurrentPosition: function() {
return Observable.create(observer => {
observer.next({ json : function() { return POSITION_INFO_FAKE_JSON; }});
observer.complete();
});
} };
getLocationService.getPosition().subscribe(
(pos: Position) => {
expect(pos.coords.latitude).toBe(434);
expect(pos.coords.longitude).toBe(23);
});
}));
});
I have no idea why this test is always passing, since it definitaly should fail. Why so then? Anyone could point what I am doing wrong here ?

Categories