Related: StrongLoop: hiding method updateAttributes(), but the accepted answer does not solve my problem.
I have followed the Get Started guide in order to get a basic app setup. In this app, my only model is called Pharmacy, and I would like to hide all mutating functions (i.e. delete, update,create...) from its REST API.
I am following the instructions in the documentation (http://docs.strongloop.com/display/public/LB/Exposing+models+over+REST#ExposingmodelsoverREST-HidingmethodsandRESTendpoints). While I can hide the static functions just fine, the updateAttributes method is still being exposed no matter what I do.
I have placed my hiding logic in common/models/pharmacy.js. Placing it in server/pharmacy.js as indicated by the docs does nothing, as the file is not even loaded.
The content of common/models/pharmacy.js is:
module.exports = function(Pharmacy) {
Pharmacy.sharedClass.find('deleteById', true).shared = false;
Pharmacy.sharedClass.find('updateAttributes', false).shared = false;
Pharmacy.sharedClass.find('upsert', true).shared = false;
Pharmacy.sharedClass.find('create', true).shared = false;
};
What am I doing wrong? Thanks in advance!
Managed to solve this after a very helpful email from the devs. The file should look like this:
module.exports = function(Pharmacy) {
Pharmacy.disableRemoteMethod('deleteById', true);
Pharmacy.disableRemoteMethod('updateAttributes', false);
Pharmacy.disableRemoteMethod('updateAll', true);
Pharmacy.disableRemoteMethod('upsert', true);
Pharmacy.disableRemoteMethod('create', true);
};
Related
I'm trying to convert an existing Alexa app to Google Actions wherein I need to implement session and persistent data values. My understanding from https://developers.google.com/assistant/conversational/df-asdk/save-data is that conv.data and conv.user.storage are intended for this purpose. However, making any attempt to assign values to either results in the error "Error: Unauthorized, Your client does not have permission to the requested URL", and also a reference to the offending key which points to this in the firebase console log: https://us-central1-hello-world-e37ec.cloudfunctions.net/cf-p7ROQlBMjQId9Cws6XdJBA-name. Similar issues here in stackoverflow seem to indicate that I need to grant the appropriate function to all users, but I don't know which function is being called. I'm new to Google Actions, so apologies if I'm overlooking something obvious. Code is very similar to the example offered on google's doc.
const {conversation} = require('#assistant/conversation');
const functions = require('firebase-functions');
const app = conversation();
...
app.handle('status', async conv => {
conv.overwrite = false;
if (conv.user.verificationStatus === 'VERIFIED') {
conv.user.storage = {};
conv.user.storage.sum = 69;
conv.add(`Alright, I'll store that for next time. See you then.`);
} else {
conv.add(`I can't save that right now, but we can add ` +
`new numbers next time!`);
}
});
I found the answer for this issue. Appears that I was not in the correct area of documentation for the "conversation" object/app. Correct method is described here: https://developers.google.com/assistant/conversational/webhooks#read_and_write_storage.
Using my example
app.handle('status', async conv => {
conv.overwrite = false;
if (conv.user.verificationStatus === 'VERIFIED') {
conv.session.params.sum = 69; //within session
conv.user.params.sum = 100; //across sessions
conv.add(`Alright, I'll store that for next time. See you then.`);
} else {
conv.add(`I can't save that right now, but we can add ` +
`new numbers next time!`);
}
});
As the question states, is there any downside in referencing the service directly in the template as such :
[disabled]="stateService.selectedClient == null || stateService.currentStep == 1"
In my opinion this doesn't seem like good practice and I'd much rather keep a "selectedClient" object in whatever component needs to use it. How can I get the state and store it into local variables, while observing the changes:
example: I want to move from step1 to step2 by changing "currentStep" in the "stateService", however I want the component that keeps "currentStep" ALSO as a local variable to reflect the change in the state?
Is it good practice to reference services in html templates in Angular
2?
I'd generally avoid it. It seems to bring more chaos than good.
Cons:
Coming from OOP background, this approach looks like it breaks the Law of Demeter, but more importantly,
It's no longer MVC, where your controller (Angular2's Component) acts like a mediator between the view and the services.
Like Ced said, what if a call to a service's member is costly and we need to refer to it multiple times in the view?
At the moment my editor of choice (VS Code) does not fully support Angular2 templates; referencing too many things outside of its own Component's scope in a template makes refactoring not fun anymore.
Pros:
Sometimes it looks more elegant (because it saves you 2 lines of code), but trust me, it's not.
How can I get the state and store it into local variables, while
observing the changes
Madhu Ranjan has a good answer to this. I'll just try to make it more complete here for your particular example:
In your StateService, define:
currentStep : Subject<number> = new Subject<number>();
selectedClient: Subject<Client> = new Subject<Client>();
changeStep(nextStep: number){
this.currentStep.next(nextStep);
}
selectClient(client: Client) {
this.selectedClient.next(client);
}
In your Component:
currentStep: number;
constructor(stateService : StateService){
stateService.currentStep.combineLatest(
stateService.selectedClient,
(currStep, client) => {
if (client == null) {
// I'm assuming you are not showing any step here, replace it with your logic
return -1;
}
return currStep;
})
.subscribe(val => {
this.currentStep = val;
});
}
You may try below,
stateService
currentStep : Subject<number> = new Subject<number>();
somestepChangeMethod(){
this.currentStep.next(<set step here to depending on your logic>);
}
component
// use this in template
currentStep: number;
constructor(stateService : stateServiceClass){
stateService.currentStep.subscribe(val => {
this.currentStep = val;
});
}
Hope this helps!!
It is probably not a good idea to expose your subject inside of your state service. Something like this would be better.
StateService
private currentStep: Subject<number> = new Subject<number>();
changeStep(value: number) {
this.currentStep.next(value);
}
get theCurrentStep(): Observable<number> {
this.currentStep.asObservable();
}
Component
currentStep: number;
constructor(private stateService: StateService) {
this.currentStep = this.stateService.theCurrentStep;
}
Template
[disabled]="(currentStep | async) == 1" // Not sure if this part would work
In Loopback it is easy to include relational objects when querying for data. For example, one can include all the comments that belong to a blog post in a single call using the include filter.
But in my case I want to get data that doesn't have a relation.
I have a User Detail page. On that page a user can choose a username and there's also a dropdown list where a user can choose from what country he is.
So from the client side I do something like:
Country.find().$promise.then(function(countryData) {
$scope.countries = countryData;
});
Player.find().$promise.then(function(playerData) {
$scope.player = playerData;
}
But what if I get more lists that I want to fill? Like, city, state, colors etc.
Then I'd have to make a lot of separate calls.
Is there a way to include all this data in one call, eventhough they have no relation? Something like this:
Player.find({ filter: { include: ["countries", "colors"] } }).$promise.then(function(data) {
// some stuff
}
You may want to try using the Where filter as documented here
An example of this for querying two specific things would be:
Post.find({where: {and: [{title: 'My Post'}, {content: 'Hello'}]}},
function (err, posts) {
...
});
You could create a remote method on one of your models that makes the calls internally and packages them back up for you.
Use some promise library if not using ES6 to wait for all and then return
Model.getAll = function(next) {
var promises = [];
promises.push(Model.app.models.Country.find());
promises.push(Model.app.models.Player.find());
promises.push(Model.app.models.Color.find());
Promise.all(promises)
.then(function(results) {
next(results);
});
}
/**
Register your remote method here
*/
You could create a remote method on one of your models that makes the calls internally and packages them back up for you.
Use some promise library if not using ES6 to wait for all and then return
Model.getAll = function(next) {
var promises = [];
promises.push(Model.app.models.Country.find());
promises.push(Model.app.models.Player.find());
promises.push(Model.app.models.Color.find());
Promise.all(promises)
.then(function(results) {
next(results);
});
}
/**
Register your remote method here
*/
I have problem and try with this solution but i get error "Failed with multiple errors, see details for more information.". It seems like there is bug on Loopback while using promise.all
Im building a prestashop catalog, but it needs to be visible to logged in customers only. Is this possible. It would be nice if the built in prestashop login is used for this.. any help is appreciated.
I have a suggestion. You can use the Customer Groups feature in PrestaShop 1.5 and only allow logged in customers to see the prices. For every Customer that is grouped in Visitor, they would see your website in Catalog Mode.
Prestashop 1.5 solution:
Simply upload the original file:
classes\controller\FrontController.php
into:
override/classes/controller/FrontController.php
Next, rename the class. Final code should look like this:
class FrontController extends FrontControllerCore
{
public function init()
{
parent::init();
if (!$this->context->customer->isLogged() && $this->php_self != 'authentication' && $this->php_self != 'password')
{
Tools::redirect('index.php?controller=authentication?back=my-account');
}
}
}
The last step is to manually delete the following file so prestashop is aware of the overriden class (It will be re-generated automatically):
cache/class_index.php
And voilà, functionality achieved without overwriting core files.
It'll be easy.
Use this code:
if(!self::$cookie->isLogged(true) AND in_array($this->step, array(1, 2, 3)))
Tools::redirect('authentication.php');
In the preprocess of your indexController
Here’s my solution, it works like a charm and is a very easy fix!
In classes\Configuration.php (around line 114) it looks like this
static public function get($key, $id_lang = NULL)
{
if ($id_lang AND isset(self::$_CONF_LANG[(int)$id_lang][$key]))
return self::$_CONF_LANG[(int)$id_lang][$key];
elseif (is_array(self::$_CONF) AND key_exists($key, self::$_CONF))
return self::$_CONF[$key];
return false;
}
change it to this:
static public function get($key, $id_lang = NULL)
{
//Grab access to the $cookie which is already loaded in the FrontController as global $cookie;
global $cookie;
if ($id_lang AND isset(self::$_CONF_LANG[(int)$id_lang][$key]))
return self::$_CONF_LANG[(int)$id_lang][$key];
elseif (is_array(self::$_CONF) AND key_exists($key, self::$_CONF))
//If the system is trying to find out if Catalog Mode is ON, then return the configuration setting,
//but override it with the user logon status
if($key == 'PS_CATALOG_MODE')
{
return !$cookie->logged || self::$_CONF[$key];
}
else
{
return self::$_CONF[$key];
}
return false;
}
Essentially, I wanted to force the system to display the “Catalog Mode” when the user is not logged in, and to turn this off when he is logged in.
I can guarantee this works for v1.4.3.0 and the code for the current version 1.4.8.2 (at the time of this post) has not changed, so it should work there.
Does anyone have an idea why this doesn't work or a workaround?
I'm trying to use the ValueChanging event from inside an EditorProvider
I have defined an EditProvider
<ig:TextEditorProvider ID="tepPercent">
<EditorControl HorizontalAlign="Right" ClientEvents-ValueChanging="validatePercent4Decimals"></EditorControl>
</ig:TextEditorProvider>
And a javascript handler
function validatePercent4Decimals(sender, args) {
var oldfieldvalue = args.get_oldValue();
var newfieldvalue = args.get_value();
if (isNaN(newfieldvalue)) {
args.set_value(oldfieldvalue);
args.set_cancel(true);
}
}
I've debugged it and can see it is running, and if I enter 34r, the inNan tests true and the set_value and set_cancel are called. But the value on the grid does not change from the 34r...
What's going on?
From this post on the Infragistics forums I believe that you have a numeric column. If this is the case then you should use a NumbericEditorProvider instead. There are more details on the available editor provides in the Infragistics help:
http://help.infragistics.com/NetAdvantage/ASPNET/2011.1?page=WebDataGrid_Editor_Providers.html