Infinite loop with a graphql and mongoose backend - express

I have a backend made in express and mongoose:
all my mutations and queries work perfectly except one mutation sends me an infinite loader
updateVehicleVerification: async (_, { id, updateVehicleVerification }) => {
const vehicleVeri = await VehicleVerification.findById(id);
if (!vehicleVeri) {
throw new Error(ErrorMessage + ' : Verification de Vehicule');
}
await VehicleVerification.findByIdAndUpdate(
id,
updateVehicleVerification
);
const veri = await VehicleVerification.findById(id);
return veri;
},
and the query I use here:
export const UPDATE_CONTROL_VEHICLE = gqlmutation updateVehicleVerification( $id: String! $updateVehicleVerification: VerificationVehicleInput ) { updateVehicleVerification( id: $id updateVehicleVerification: $updateVehicleVerification ) { honk { state image comment } mileage dateVerification stateVehicle { damaged good missing } } };
enter code here

I I solved the problem !
I did not manage the case where the data reached me by the request which keyed an infinite loop.

Related

Shopify Storage Redis Issue with Node React App

I have added session storage in serve.js as follows :-
import SessionHandler from "./SessionHandler";
const sessionStorage = new SessionHandler();
Shopify.Context.initialize({
API_KEY: process.env.SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
SCOPES: process.env.SCOPES.split(","),
HOST_NAME: process.env.HOST.replace(/https:\/\//, ""),
API_VERSION: ApiVersion.October21,
IS_EMBEDDED_APP: false,
// This should be replaced with your preferred storage strategy
//SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
SESSION_STORAGE: new Shopify.Session.CustomSessionStorage(
sessionStorage.storeCallback,
sessionStorage.loadCallback,
sessionStorage.deleteCallback
),
});
My router get function is
router.get("(.*)", async (ctx) => {
const shop = ctx.query.shop;
let documentQuery = { shop: shop };
let data = await SessionStorage.findOne(documentQuery); //this finds the store in the session table
if (ACTIVE_SHOPIFY_SHOPS[shop] === undefined) {
if (data == null) {
ctx.redirect(`/auth?shop=${shop}`);
} else {
await handleRequest(ctx);
}
} else {
await handleRequest(ctx);
}
});
and than in the SessionHandler file added code as attached in file ,
but when I run install the app it goes to the storeCallback , loadcallback and deletecallback function multiple times
StoreCallback Function Code
Load and delete callback function code
sorry I have edited my answer as I think its incorrect . all I can say for now is to look at this example:https://github.com/Shopify/shopify-api-node/blob/main/docs/usage/customsessions.md
if you havent already..

Apollo/graphql request result buffered in vuejs

In a Vue component controlling users subsciption to newsletters, I have the fellowing code:
async newSubscriber(event) {
// Validate email
//---------------
if (!this.isEmailValid(this.subscriber_email))
this.subscribeResult = "Email not valid";
else {
// If valid, check if email is not already recorded
//-------------------------------------------------
let alreadyRecorded = false;
let recordedEmails = await this.$apollo.query({ query: gql`query { newslettersEmails { email } }` });
console.log('length ' + recordedEmails.data.newslettersEmails.length);
console.log(recordedEmails.data.newslettersEmails);
for (let i = 0; !alreadyRecorded && i < recordedEmails.data.newslettersEmails.length; i++)
alreadyRecorded = this.subscriber_email === recordedEmails.data.newslettersEmails[i].email;
if (alreadyRecorded)
this.subscribeResult = "Email already recorded";
else {
// If not, record it and warn the user
//------------------------------------
this.$apollo.mutate({
mutation: gql`mutation ($subscriber_email: String!){
createNewslettersEmail(input: { data: { email: $subscriber_email } }) {
newslettersEmail {
email
}
}
}`,
variables: {
subscriber_email: this.subscriber_email,
}
})
.then((data) => { this.subscribeResult = "Email recorded"; })
.catch((error) => { this.subscribeResult = "Error recording the email: " + error.graphQLErrors[0].message; });
}
}
}
At the very first email subscription test, $apollo.query returns me the correct number of emails already recorded (let's say, 10) and record the new subscriber email. But if I try to record a second email without hard refreshing (F5) the browser, $apollo.query returns me the exact same result than the first time (10), EVEN IF the first test email has been correctly recorded by strapi (graphql palyground showns me the added email with the very same query!). Even if I add ten emails, apollo will always return me what it got during its first call (10 recorded emails), as if it uses a buffered result. Of course, that allows Vue to record several times the same email, which I obviously want to avoid!
Does it speaks to anyone ?
After a lot of Google digging (giving the desired results by simply changing in my requests, at the end, "buffering" by "caching" !), I understood that Apollo cache its queries by default (at least, in the configuration of the Vue project I received). To solve the problem I just added "fetchPolicy: 'network-only'" to the query I make:
let recordedEmails = await this.$apollo.query({
query: gql`query { newslettersEmails { email } }`,
});
became
let recordedEmails = await this.$apollo.query({
query: gql`query { newslettersEmails { email } }`,
fetchPolicy: 'network-only'
});
And problem solved ^^

fetch pictures with mongoose with a certain parameter

Hi and thanks for all the people willing and ready to help me out !
I have a mongoose Model like so :
const pictureSchema = mongoose.Schema ({
pictureName : String,
creator : String,
description : String,
img : String,
createdAt : {
type : Date,
default : new Date(),
},
themeLinked : String
})
Now what i am trying to do, is to fetch all the documents that have a certain specific value for "themeLinked". it's like sorting all the entries in my documents that have the same "themeLinked".
so what i did, from my front-end react App, i sent the value of theme linked as a req.param. so it is sent to my back end with the GET request.
and in my back end, in the controller i wrote this code :
const fetchPictures = async (req,res) => {
const {themeId} = req.params;
try {
const pictures = await pictureModel.findOne({themeLinked : themeId});
res.status(200).json(pictures)
} catch (err) {
res.status(404).json({ message : err})
}
}
and in the network Tab in my chrome browser, i get 'null' as a value for Response.
so beeing a begginer i am struggling to find the right way to fetch all the pictures that have the same 'themeLinked' value....this must be pretty simple but i'm struggling
thanks !!
ok i got, it, all i needed to do was :
const fetchPictures = async (req,res) => {
const {themeId} = req.params;
try {
const pictures = await pictureModel.find({themeLinked : themeId});
res.status(200).json(pictures)
} catch (err) {
res.status(404).json({ message : err})
}
}
for Obvious lexical reasons, findOne only returns one entry, as find returns all entries that have the same matching 'themeLinked' value....:)

CKEditor 5 Image Upload Issues

I'm using ckeditor5 into my project. I have to support image upload so I have search and followed this stackoverflow article.
I have created an uploadAdapter which is:
class UploadAdapter {
constructor( loader, url, t ) {
this.loader = loader;
this.url = url;
this.t = t;
}
upload() {
return new Promise( ( resolve, reject ) => {
this._initRequest();
this._initListeners( resolve, reject );
this._sendRequest();
} );
}
abort() {
if ( this.xhr ) {
this.xhr.abort();
}
}
_initRequest() {
const xhr = this.xhr = new XMLHttpRequest();
xhr.open( 'POST', this.url, true );
xhr.responseType = 'json';
}
_initListeners( resolve, reject ) {
const xhr = this.xhr;
const loader = this.loader;
const t = this.t;
const genericError = t( 'Cannot upload file:' ) + ` ${ loader.file.name }.`;
xhr.addEventListener( 'error', () => reject( genericError ) );
xhr.addEventListener( 'abort', () => reject() );
xhr.addEventListener( 'load', () => {
const response = xhr.response;
if ( !response || !response.uploaded ) {
return reject( response && response.error && response.error.message ? response.error.message : genericError );
}
resolve( {
default: response.url
} );
} );
if ( xhr.upload ) {
xhr.upload.addEventListener( 'progress', evt => {
if ( evt.lengthComputable ) {
loader.uploadTotal = evt.total;
loader.uploaded = evt.loaded;
}
} );
}
}
_sendRequest() {
const data = new FormData();
data.append( 'upload', this.loader.file );
this.xhr.send( data );
}
}
import Plugin from '#ckeditor/ckeditor5-core/src/plugin';
import FileRepository from '#ckeditor/ckeditor5-upload/src/filerepository';
export default class GappUploadAdapter extends Plugin {
static get requires() {
return [ FileRepository ];
}
static get pluginName() {
return 'GappUploadAdapter';
}
init() {
const url = this.editor.config.get( 'gapp.uploadUrl' );
if ( !url ) {
return;
}
this.editor.plugins.get( FileRepository ).createUploadAdapter = loader => new UploadAdapter( loader, url, this.editor.t );
}
}
Now this is explained. I have 2 issues.
Once uploaded ( my upload on server is working fine and returning a valid url in format {default: url}, why is my image content inserted as data-uri and not in url as for easy image demo here. I want my image to be url like.
I would like to listen for a kind of success upload image ( with image id retrieved from upload server call ) to insert some content in my page. How to proceed ?
Thanks for help.
PS: I'm building ckeditor with command 'npm run build' from git repo cloned from https://github.com/ckeditor/ckeditor5-build-classic
EDIT:
Thanks to accepted response, I saw that I was wrong in returned data. I was not returning any URL in my uploader front end which was causing editor image to stay in img-data way. Once valid URL was returned, it was parsed automatically and my editor image was containing a valid url.
If the data-uri is still used after successful upload I would assume that server response was not processed correctly and the received url could not be retrieved. I have tested adapter code you provided and it works fine (with CKFinder on server side). I would check how the upload server response looks and if it can be correctly parsed.
When using CKFinder you will see:
and a parsed JSON response:
You could check if response is processed correctly in your adapter in:
xhr.addEventListener( 'load', () => {
const response = xhr.response;
...
}
Listening to successful image upload may be tricky as there is no event directly related to it. Depending on what exactly you are trying to achieve you may try to extend you custom loader so when successful response is received (and resolve() called) you may execute some code. However, in this state the image element is still not updated (in model, view and DOM) with new URL and UploadAdapter lacks a direct access to editor instance so it may be hard to do anything complex.
Better way may be to listen to model changes, the similar way it is done in ImageUploadEditing plugin (see code here) checking the image uploadStatus attribute change:
editor.model.document.on( 'change', () => {
const changes = doc.differ.getChanges();
for ( const entry of changes ) {
const uploaded = entry.type === 'attribute' && entry.attributeNewValue === 'complete' && entry.attributeOldValue === 'uploading';
console.log( entry );
}
} );
If it changes from uploading to complete it means the images was successfully uploaded:
You may also take a look at another answer, which shows how to hook into FileRepository API to track entire upload process - https://github.com/ckeditor/ckeditor5-image/issues/243#issuecomment-442393578.

Crash with simple history push

just trying come silly stuff and playing around with Cycle.js. and running into problem. Basically I just have a button. When you click it it's suppose to navigate the location to a random hash and display it. Almost like a stupid router w/o predefined routes. Ie. routes are dynamic. Again this isn't anything practical I am just messing with some stuff and trying to learn Cycle.js. But the code below crashes after I click "Add" button. However the location is updated. If I actually just navigate to "#/asdf" it displays the correct content with "Hash: #/asdf". Not sure why the flow is crashing with error:
render-dom.js:242 TypeError: Cannot read property 'subscribe' of undefined(…)
import Rx from 'rx';
import Cycle from '#cycle/core';
import { div, p, button, makeDOMDriver } from '#cycle/dom';
import { createHashHistory } from 'history';
import ranomdstring from 'randomstring';
const history = createHashHistory({ queryKey: false });
function CreateButton({ DOM }) {
const create$ = DOM.select('.create-button').events('click')
.map(() => {
return ranomdstring.generate(10);
}).startWith(null);
const vtree$ = create$.map(rs => rs ?
history.push(`/${rs}`) :
button('.create-button .btn .btn-default', 'Add')
);
return { DOM: vtree$ };
}
function main(sources) {
const hash = location.hash;
const DOM = sources.DOM;
const vtree$ = hash ?
Rx.Observable.of(
div([
p(`Hash: ${hash}`)
])
) :
CreateButton({ DOM }).DOM;
return {
DOM: vtree$
};
}
Cycle.run(main, {
DOM: makeDOMDriver('#main-container')
});
Thank you for the help
I would further suggest using #cycle/history to do your route changing
(Only showing relevant parts)
import {makeHistoryDriver} from '#cycle/history'
import {createHashHistory} from 'history'
function main(sources) {
...
return {history: Rx.Observable.just('/some/route') } // a stream of urls
}
const history = createHashHistory({ queryKey: false })
Cycle.run(main, {
DOM: makeDOMDriver('#main-container'),
history: makeHistoryDriver(history),
})
On your function CreateButton you are mapping your clicks to history.push() instead of mapping it to a vtree which causes the error:
function CreateButton({ DOM }) {
...
const vtree$ = create$.map(rs => rs
? history.push(`/${rs}`) // <-- not a vtree
: button('.create-button .btn .btn-default', 'Add')
);
...
}
Instead you could use the do operator to perform the hashchange:
function CreateButton({ DOM }) {
const create$ =
...
.do(history.push(`/${rs}`)); // <-- here
const vtree$ = Observable.of(
button('.create-button .btn .btn-default', 'Add')
);
...
}
However in functional programming you should not perform side effects on you app logic, every function must remain pure. Instead, all side effects should be handled by drivers. To learn more take a look at the drivers section on Cycle's documentation
To see a working driver jump at the end of the message.
Moreover on your main function you were not using streams to render your vtree. It would have not been reactive to locationHash changes because vtree$ = hash ? ... : ... is only evaluated once on app bootstrapping (when the main function is evaluated and "wires" every streams together).
An improvement will be to declare your main's vtree$ as following while keeping the same logic:
const vtree$ = hash$.map((hash) => hash ? ... : ...)
Here is a complete solution with a small locationHash driver:
import Rx from 'rx';
import Cycle from '#cycle/core';
import { div, p, button, makeDOMDriver } from '#cycle/dom';
import { createHashHistory } from 'history';
import randomstring from 'randomstring';
function makeLocationHashDriver (params) {
const history = createHashHistory(params);
return (routeChange$) => {
routeChange$
.filter(hash => {
const currentHash = location.hash.replace(/^#?\//g, '')
return hash && hash !== currentHash
})
.subscribe(hash => history.push(`/${hash}`));
return Rx.Observable.fromEvent(window, 'hashchange')
.startWith({})
.map(_ => location.hash);
}
}
function CreateButton({ DOM }) {
const create$ = DOM.select('.create-button').events('click')
.map(() => randomstring.generate(10))
.startWith(null);
const vtree$ = Rx.Observable.of(
button('.create-button .btn .btn-default', 'Add')
);
return { DOM: vtree$, routeChange$: create$ };
}
function main({ DOM, hash }) {
const button = CreateButton({ DOM })
const vtree$ = hash.map(hash => hash
? Rx.Observable.of(
div([
p(`Hash: ${hash}`)
])
)
: button.DOM
)
return {
DOM: vtree$,
hash: button.routeChange$
};
}
Cycle.run(main, {
DOM: makeDOMDriver('#main-container'),
hash: makeLocationHashDriver({ queryKey: false })
});
PS: there is a typo in your randomstring function name, I fixed it in my example.