How to set relation foreign key to be required - loopbackjs

I have two models. Company and Booking.
In the relation part of model Company
"bookings": {
"type": "hasMany",
"model": "Booking",
"foreignKey": "companyId"
}
The issue is, it is possible to post a Booking without companyId which is not ok.
From the explorer.
Booking {
bookingId (string, optional),
name (string),
location (string),
companyId (string, optional)
}

You actually can't enforce this particular validation out-of-the-box. Instead you have a couple different options:
a) You can enforce the creation of Booking through company through the endpoint, POST /api/Company/{id}/Bookings by disabling Booking.disableRemoteMethod('create', ...) along with any other methods that have the ability to create records from the Booking model.
b) You can add a remote hook to check whether or not the company record exists and throw an error accordingly.
Booking.beforeRemote('create', function(ctx, booking, next) {
var Company = Booking.app.models.Company;
var companyId = ctx.req.body.companyId;
if (companyId) {
errorMsg = 'Company with id=' + companyId + ' does not exist.';
var noCompany = new Error(errorMsg);
Company.findById(companyId, function(err, company) {
if (err) next(err);
if (!company) {
ctx.res.statusCode = 400;
next(noCompany);
} else {
next();
}
});
} else {
next();
}
});
You will also have to do the same thing for any other endpoints that allow record create such as PUT /api/Bookings.
Hope that helps!

You can add the companyId property explicitly in the booking.json file, and add the required:true property. It would look like
{
"properties": {
"companyId": {
"type": "number",
"required": true
},
... //other properties
}
}

In richardpringle's answer part b booking was an empty object for me.
I was able to get this answer to work by adding app to the booking.js file like below:
'use strict';
var app = require('../../server/server');
module.exports = function(Booking) {
Booking.beforeRemote('create', function(ctx, booking, next) {
var Company = app.models.Company;
var companyId = ctx.req.body.companyId;
if (companyId) {
errorMsg = 'Company with id=' + companyId + ' does not exist.';
var noCompany = new Error(errorMsg);
Company.findById(companyId, function(err, company) {
if (err) next(err);
if (!company) {
ctx.res.statusCode = 400;
next(noCompany);
} else {
next();
}
});
} else {
next();
}
});
};
line 2 is new
line 6 is modified from richardpringle's answer
From: var Company = Booking.app.models.Company;
To: var Company = app.models.Company;

Related

Flutter aws amplify not returning data when calling graphql api

On button click I have programmed to call a graphql api which is connected to a Lambda function and the function is pulling data from a dynamodb table. The query does not produce any error, but it doesn't give me any results as well. I have also checked the cloudwatch logs and I dont see any traces of the function being called. Not sure on the careless mistake I am making here.
Here is my api
void findUser() async {
try {
String graphQLDocument = '''query getUserById(\$userId: ID!) {
getUserById(userId: \$id) {
id
name
}
}''';
var operation = Amplify.API.query(
request: GraphQLRequest<String>(
document: graphQLDocument,
variables: {'id': 'USER-14160000000'}));
var response = await operation.response;
var data = response.data;
print('Query result: ' + data);
} on ApiException catch (e) {
print('Query failed: $e');
}
}
Here is my lambda function -
const getUserById = require('./user-queries/getUserById');
exports.handler = async (event) => {
var userId = event.arguments.userId;
var name = event.arguments.name;
var avatarUrl = event.arguments.avatarUrl;
//console.log('Received Event - ', JSON.stringify(event,3));
console.log(userId);
switch(event.info.fieldName) {
case "getUserById":
return getUserById(userId);
}
};
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient({region: 'ca-central-1'});
async function getUserById(userId) {
const params = {
TableName:"Bol-Table",
KeyConditionExpression: 'pk = :hashKey and sk = :sortKey',
ExpressionAttributeValues: {
':hashKey': userId,
':sortKey': 'USER'
}
};
try {
const Item = await docClient.query(params).promise();
console.log(Item);
return {
id: Item.Items[0].pk,
name: Item.Items[0].details.displayName,
avatarUrl: Item.Items[0].details.avatarUrl,
createdAt: Item.Items[0].details.createdAt,
updatedAt: Item.Items[0].details.updatedAt
};
} catch(err) {
console.log("BOL Error: ", err);
}
}
module.exports = getUserById;
Upon button click I get this
Moving my comment to an answer:
Can you try changing your graphQLDocumnet to
String graphQLDocument = '''query getUserById(\$id: ID!) {
getUserById(userId: \$id) {
id
name
}
}''';
Your variable is $userId and then $id. Try calling it $id in both places like in your variables object.
Your flutter code is working fine but in lambda from the aws is returning blank string "" to not to print anything

How to delete duplicates of a List<MyDataModel> (Dart/Flutter)

I have a futurebuilder that builds the UI based on a List, it does the job, however I get duplicates due to the UI being built again and again whenever I navigate. My question is, is there a innate method in Dart that can remove duplicates from a list? I've tried this StackOverflow question however it doesn't work.
Here is my custom model:
class HomeList {
Widget navigateScreen;
String imagePath;
PatientInfo patientInfo;
HomeList({
this.navigateScreen,
this.imagePath = '',
this.patientInfo,
});
static List<HomeList> homeList = [];
}
Here is my function for the futureBuilder i'm getting the data from my cloud_firestore:
_getPatients() async {
if (didLoadpatients == 0) {
print('this is didloadpatients at start of func $didLoadpatients');
var document = await db
.collection('users')
.document(mUser.uid)
.collection('patients');
document.getDocuments().then((QuerySnapshot query) async {
query.documents.forEach((f) {
uids.add(f.data['uID']);
});
didLoadpatients++;
print('this is didloadpatients at end of func $didLoadpatients');
for (var i = 0; i < uids.length; i++) {
var userDocuments = await db.collection('users').document(uids[i]);
userDocuments.get().then((DocumentSnapshot doc) {
print(doc.data);
homeList.add(HomeList(
imagePath: 'assets/fitness_app/fitness_app.png',
patientInfo: new PatientInfo.fromFbase(doc.data)));
});
print(homeList);
}
});
} else
print('I am leaving the get patient function');
}
Future<bool> getData() async {
_getCurrentUser();
await Future.delayed(const Duration(milliseconds: 1500), () async {
_getPatients();
});
return true;
}
Any help would be appreciated thank you!
To remove duplicates you can use Set Data Structure instead of List.
Just use Set instead of List to get unique values only.
Before Adding you can Remove Element from model this will Work
dummymodel.removeWhere((m) => m.id == id);
dummymodel.add(dummymodel.fromJson(data));
To Remove Duplicates from Data Model simply use Set (Data structure),
Original List with Duplicate Entries:
List<MyDataModel> mList = [MyDataModel(1), MyDataModel(2), MyDataModel(1), MyDataModel(3)];
New List that removes duplicate Entries from your List<MyDataModel>:
List<MyDataModel> mNewList = list.toSet().toList();
Output:
The result will be like
MyDataModel(1), MyDataModel(2), MyDataModel(3)
To remove the duplicate elements from custom object list, you need to override == and hashcode methods in your POJO class and then add the items in Set and again convert set to list to remove duplicate objects. Below is the working code:-
class TrackPointList {
double latitude;
double longitude;
String eventName;
Time timeZone;
TrackPointList({
this.latitude,
this.longitude,
this.eventName,
this.timeZone,
});
#override
bool operator==(other) {
// Dart ensures that operator== isn't called with null
// if(other == null) {
// return false;
// }
if(other is! TrackPointList) {
return false;
}
// ignore: test_types_in_equals
return eventName == (other as TrackPointList).eventName;
}
int _hashCode;
#override
int get hashCode {
if(_hashCode == null) {
_hashCode = eventName.hashCode;
}
return _hashCode;
}
factory TrackPointList.fromJson(Map<String, dynamic> json) => TrackPointList(
latitude: json["latitude"].toDouble(),
longitude: json["longitude"].toDouble(),
eventName: json["eventName"],
timeZone: timeValues.map[json["timeZone"]],
);
Map<String, dynamic> toJson() => {
"latitude": latitude,
"longitude": longitude,
"eventName": eventName,
"timeZone": timeValues.reverse[timeZone],
};
}
Above is the POJO class. Now below is the method which helps you to filter the objects according to the eventName data member.
List<TrackPointList> getFilteredList(List<TrackPointList> list){
final existing = Set<TrackPointList>();
final unique = list
.where((trackingPoint) => existing.add(trackingPoint))
.toList();
return unique;
}
This will work definitely.
Please +1 if it helps you.
I've come up with quite a brute force solution. Instead of
_getPatients() async {
if (didLoadpatients == 0) {
print('this is didloadpatients at start of func $didLoadpatients');
var document = await db
.collection('users')
.document(mUser.uid)
.collection('patients');
document.getDocuments().then((QuerySnapshot query) async {
query.documents.forEach((f) {
uids.add(f.data['uID']);
});
didLoadpatients++;
print('this is didloadpatients at end of func $didLoadpatients');
for (var i = 0; i < uids.length; i++) {
var userDocuments = await db.collection('users').document(uids[i]);
userDocuments.get().then((DocumentSnapshot doc) {
print(doc.data);
homeList.add(HomeList(
imagePath: 'assets/fitness_app/fitness_app.png',
patientInfo: new PatientInfo.fromFbase(doc.data)));
});
print(homeList);
}
});
} else
print('I am leaving the get patient function');
}
I've done what #Jay Mungara says and clear my Set everytime my UI rebuilds:
_getPatients() async {
homeList.clear();
if (didLoadpatients == 0) {
print('this is didloadpatients at start of func $didLoadpatients');
var document = await db
.collection('users')
.document(mUser.uid)
.collection('patients');
document.getDocuments().then((QuerySnapshot query) async {
query.documents.forEach((f) {
uids.add(f.data['uID']);
});
didLoadpatients++;
print('this is didloadpatients at end of func $didLoadpatients');
for (var i = 0; i < uids.length; i++) {
var userDocuments = await db.collection('users').document(uids[i]);
userDocuments.get().then((DocumentSnapshot doc) {
print(doc.data);
homeList.add(HomeList(
imagePath: 'assets/fitness_app/fitness_app.png',
patientInfo: new PatientInfo.fromFbase(doc.data)));
});
print(homeList);
}
});
} else
print('I am leaving the get patient function');
}
Thank you for all your answers!
this is a small examples to remove duplicate element
removeDuplicate() {
List<dynamic> demoList = [
{"userId": 1, "id": 1, "name": "thappu1"},
{"userId": 2, "id": 2, "name": "appu"},
{"userId": 1, "id": 1, "name": "thappu1"},
{"userId": 2, "id": 2, "name": "appu"},
{"userId": 2, "id": 2, "name": "appu"},
{"userId": 2, "id": 2, "name": "appu"},
{"userId": 2, "id": 2, "name": "appu"},
];
var toRemove = {};
demoList.forEach((e) {
toRemove.putIfAbsent("$e", () => e);
});
print(toRemove.keys.toList());
}
output is
[{userId: 1, id: 1, name: thappu1}, {userId: 2, id: 2, name: appu}]

Apollo client mutation with writeQuery not triggering UI update

I have a mutation to create a new card object, and I expect it should be added to the user interface after update. Cache, Apollo Chrome tool, and console logging reflect the changes, but the UI does not without a manual reload.
const [createCard, { loading, error }] = useMutation(CREATE_CARD, {
update(cache, { data: { createCard } }) {
let localData = cache.readQuery({
query: CARDS_QUERY,
variables: { id: deckId }
});
localData.deck.cards = [...localData.deck.cards, createCard];
;
client.writeQuery({
query: CARDS_QUERY,
variables: { id: parseInt(localData.deck.id, 10) },
data: { ...localData }
});
I have changed cache.writeQuery to client.writeQuery, but that didn't solve the problem.
For reference, here is the Query I am running...
const CARDS_QUERY = gql`
query CardsQuery($id: ID!) {
deck(id: $id) {
id
deckName
user {
id
}
cards {
id
front
back
pictureName
pictureUrl
createdAt
}
}
toggleDeleteSuccess #client
}
`;
I managed the same result without the cloneDeep method. Just using the spread operator solved my problem.
const update = (cache, {data}) => {
const queryData = cache.readQuery({query: USER_QUERY})
const cartItemId = data.cartItem.id
queryData.me.cart = queryData.me.cart.filter(v => v.id !== cartItemId)
cache.writeQuery({query: USER_QUERY, data: {...queryData}})
}
Hope this helps someone else.
Ok, finally ran into a long Github thread discussing their solutions for the same issue. The solution that ultimately worked for me was deep cloning the data object (I personally used Lodash cloneDeep), which after passing in the mutated data object to cache.writeQuery, it was finally updating the UI. Ultimately, it still seems like there ought to be a way to trigger the UI update, considering the cache reflects the changes.
Here's the after, view my original question for the before...
const [createCard, { loading, error }] = useMutation(CREATE_CARD, {
update(cache, { data: { createCard } }) {
const localData = cloneDeep( // Lodash cloneDeep to make a fresh object
cache.readQuery({
query: CARDS_QUERY,
variables: { id: deckId }
})
);
localData.deck.cards = [...localData.deck.cards, createCard]; //Push the mutation to the object
cache.writeQuery({
query: CARDS_QUERY,
variables: { id: localData.deck.id },
data: { ...localData } // Cloning ultimately triggers the UI update since writeQuery now sees a new object.
});
},
});

How to access data of another persisted model of loopback from remote method of one persisted model?

'use strict';
module.exports = function (City) {
City.GetCurrentPopulation = function (req) {
var population;
City.app.models.Pupulation.find({where{id:req.id}}, //This line //gives me an error that cannot read property 'find' of undefined
function(req.res){
population=res.population;
});
response='Population for ' +req.cname ' is' +population;
req(null, response);
};
City.remoteMethod(
'GetCurrentPopulation', {
http: {
path: '/GetCurrentPopulation',
verb: 'GetCurrentPopulation'
},
returns: {
arg: 'startdate',
type: 'string'
}
}
);
There is a model city and i want to access another model like "population.find(some filters)" How to do this?
I have a remote method written in city model. Where i am trying to access population record as
var countryp=population.find(where{id:4});
var currentpopulation=countryp.Totalpopulation;
It gives an error population.find is not a function.
Please suggest way to do this.
City.app.models.Population can only work if you defined some relation between City & Population models. Otherwise it wont work that way. If there is no relation to the other model. You need to get a reference to the app object using
Try like this:
var app = require('../../server/server');
module.exports = function (City) {
var Population = app.models.Population;
City.GetCurrentPopulation = function(req) {
Population.find({where{id:req.id}}, function (err) {
if (err) {
return console.log(err);
} else {
// do something here
});
}
You can refer to the documentation here https://loopback.io/doc/en/lb3/Working-with-LoopBack-objects.html#using-model-objects

Duplicate existing contacts alert

In Vtiger 6.5.0 open source, I wants to create a alert function to warn users that the conact's mobile is existing? could you please help me. I'm fresher.
Thanks,
Loi
You can refer the function wich exist in Account module for checking Duplicate Account Name.
Please follow this files you will get an idea.
This is the code flow how its done In Account Module
Registring Pre Save Event
http://code.vtiger.com/vtiger/vtigercrm/blob/master/layouts/vlayout/modules/Accounts/resources/Edit.js#L250
This teh Fucntion to check Duplicate in cache, If not calls the Helper function
http://code.vtiger.com/vtiger/vtigercrm/blob/master/layouts/vlayout/modules/Accounts/resources/Edit.js#L83
This the Helper function which makes the call to server
http://code.vtiger.com/vtiger/vtigercrm/blob/master/resources/helper.js#L166
This is the action function which is responsible for Serving the request which came from Helper Function
http://code.vtiger.com/vtiger/vtigercrm/blob/master/modules/Accounts/actions/CheckDuplicate.php#L30
And this is the function which checks for Duplicate
http://code.vtiger.com/vtiger/vtigercrm/blob/master/modules/Accounts/models/Record.php#L57
Hope this helps.
Hi Victor please follow this steps
modules\Leads\actions\Checkprimaryemail.php
<?php
class Leads_Checkprimaryemail_Action extends Vtiger_BasicAjax_Action {
public function checkPermission(Vtiger_Request $request) {
return;
}
public function process(Vtiger_Request $request) {
global $adb;
$moduleName = $request->get('module');
$recordId = $request->get('recordId');
$primary_email = $request->get('primary_email');
/*Lead Details*/
$lead_query = "select * from vtiger_leaddetails
inner join vtiger_crmentity on vtiger_crmentity.crmid=vtiger_leaddetails.leadid
where vtiger_crmentity.deleted = 0 and vtiger_leaddetails.email='".$primary_email."'";
$lead_result = $adb->query($lead_query);
$lead_email = $adb->query_result($lead_result,0,'email');
$lead_numrows = $adb->num_rows($lead_result);
/*Contact Details*/
$cont_query = "select * from vtiger_contactdetails
inner join vtiger_crmentity on vtiger_crmentity.crmid=vtiger_contactdetails.contactid
where vtiger_crmentity.deleted = 0 and vtiger_contactdetails.email='".$primary_email."'";
$cont_result = $adb->query($cont_query);
$cont_email = $adb->query_result($cont_result,0,'email');
$cont_numrows = $adb->num_rows($cont_result);
if($recordId != '' ){
if($primary_email == $lead_email && $lead_numrows == 1 ){
$emailtrue = 0;
} elseif($primary_email == $cont_email && $cont_numrows >= 1 ) {
$emailtrue = 1;
}
} else {
if(($lead_numrows >=1 || $cont_numrows >=1 ) || ($lead_numrows >=1 && $cont_numrows >= 1) ){
$emailtrue = 1;
} else {
$emailtrue = 0;
}
}
$emailData = array($emailtrue);
$response = new Vtiger_Response();
$response->setResult($emailData);
$response->emit();
}
}
?>
After Create One other file
layouts\vlayout\modules\Leads\resources\Edit.js
Vtiger_Edit_Js("Leads_Edit_Js", {
}, {
changeEvent: function (container) {
jQuery('input[name="email"]').on('focusout', function (e) {
var email = jQuery('input[name="email"]').val();
var recordId = jQuery('input[name="record"]').val();
var email_length = email.length;
if (email != '') {
if (email_length > 100) {
var errorMessage = app.vtranslate('JS_EMAIL_LENGTH_VALIDATION');
params = {
text: errorMessage,
'type': 'error',
};
Vtiger_Helper_Js.showMessage(params);
}
var progressIndicatorElement = jQuery.progressIndicator({
'position': 'html',
'blockInfo': {
'enabled': true
}
});
var postData = {
"module": 'Leads',
"action": "Checkprimaryemail",
"primary_email": email,
"recordId": recordId
}
AppConnector.request(postData).then(
function (data) {
progressIndicatorElement.progressIndicator({'mode': 'hide'});
if (data['result'] == 1) {
jQuery('#emailalready_exists').val(1);
var errorMessage = app.vtranslate('JS_EMAIL_EXIST');
params = {
text: errorMessage,
'type': 'error',
};
Vtiger_Helper_Js.showMessage(params);
} else {
jQuery('#emailalready_exists').val(0);
}
},
function (error, err) {}
);
e.preventDefault();
}
});
},
registerBasicEvents: function (container) {
this._super(container);
this.changeEvent(container);
}
});
To check duplicate records in vTiger follow below steps:
Register checkDuplicate function in registerBasicEvents
1: \layouts\vlayout\modules\Contacts\resources\Edit.js
getmobile : function(container){
return jQuery('input[name="mobile"]',container).val();
},
getRecordId : function(container){
return jQuery('input[name="record"]',container).val();
},
DuplicateCheck : function(form) {
var thisInstance = this;
if(typeof form == 'undefined') {
form = this.getForm();
}
jQuery( "#mobileFieldId" ).change(function() {
var mobile = thisInstance.getmobile(form);
var recordId = thisInstance.getRecordId(form);
var params = {
'module' : "Contacts",
'action' : "CheckDuplicate",
'mobile' : mobile,
'record' : recordId
}
AppConnector.request(params).then(
function(data) {
var response = data['result'];
var result = response['success'];
if(result == true) {
var message_params = {
title : app.vtranslate('JS_MESSAGE'),
text: response['message'],
animation: 'show',
type: 'error'
};
Vtiger_Helper_Js.showPnotify(message_params);
jQuery(".btn-success").attr('disabled',true);
return false;
} else {
jQuery(".btn-success").attr('disabled',false);
}
}
);
});
},
2: Create new file in** \modules\Contacts\actions\CheckDuplicate.php
Follow the same process / code as given in \modules\Accounts\actions\CheckDuplicate.php
3: Add new function checkDuplicate() in \modules\Contacts\models\Record.php
And follow same process as given in \modules\Accounts\models\Record.php having function checkDuplicate()
Note: Don't forget to change the db table name, class name module wise.
Hope this will help you. Thank you.