I know how to access attributes from the client side but I want to access attributes of a device from the thingsboard server side. So when developing a new widget I can display a list of all attributes and change them if necessary. How can I do that?
We have to be very clear about server-side and client-side.
In fact a Thingsboard widget runs on the client-side in the browser.
As far as I understand we have two options for attribute access in a widget.
define attribute access in the widget's datasource or
access attributes by using the HTTP-Api
Thingsboard provides a handy "service" for using the HTTP-Api that we can use like this:
var entityId, attributeKey, myAttribute, attributeService;
entityId = ... // entity id from the widgets datasource.
attributeKey = 'MyAttribute';
myAttribute = {
key: attributeKey,
value: 'MyAttributeValue';
};
attributeService = self.ctx.$scope.$injector.get('attributeService');
// Access attributes.
attributeService.getEntityAttributesValues('DEVICE', entityId, 'SERVER_SCOPE', attributeKey)
.then(function success(attributes) {
// Use the attribute value.
});
// Write attributes.
attributeService.saveEntityAttributes(
'DEVICE', entityId, 'SERVER_SCOPE', [myAttribute]);
There are more options with the Http-Api and even the service provides some more handy functions. Check out the sources of the service at
thingsboard/ui/src/app/api/attribute.service.js
NOTE: This refers to the ui modules for Thingsboard Version lower then 3.
Related
we have the following scenario with REST custom connectors.
I have followed the lb4 guidelines to create REST based custom connectors, let's say i have two connectors i.e secrets and hello-world.
I also have the loopback application which has data sources, models, repositories and services for 2 integrations.
But I want to maintain a single controller which has service injection in constructor like below
#inject(ConnectorServiceBindings.CONNECTOR_SERVICE) public externalDataService: ConnectorRepositoryService,
here ConnectorRepositoryService is an interface which has contract for method called getSomething(), so i have 2 services which implements interface for calling respective connector.
So in my application.ts i have this.bind(ConnectorServiceBindings.CONNECTOR_SERVICE).toClass( SecretsService, ); this to bind the injection with respective service.
But i needed to have a condition here to select the binding like below
if (type === "secrets") { // how to pass this type during runtime
this.bind(ConnectorServiceBindings.CONNECTOR_SERVICE).toClass(
SecretsManagerServiceService,
);
} else {
this.bind(ConnectorServiceBindings.CONNECTOR_SERVICE).toClass(
HelloWorldService,
);
}
is there a way we can do this binding whenever we get new API request?????
FYI : controller has single POST end point which internally calls interface method using this.externalDataService.getData?.()!;
Question 1 : Why do you want to bind at application.ts?
Ans : In future we want to add more connectors, so doesn't want to touch the controller code every time.
Background:
I have a set of models, including a User and various other models, some of which contain references to a User. I am exposing these models for querying via a GraphQL API generated by Graffiti, backed by a Mongo database using the graffiti-mongoose adaptor. My current REST API (which I am migrating to GraphQL) uses JSON Web Tokens to authenticate users, and has some custom permission logic on the server side to handle access control.
Problem:
I'd like to restrict access to objects in GraphQL based upon the current logged-in user. Some models should be accessible for reads by unauthenticated calls. Most other models should be only accessible to the User who created them. What's the best way to manage access control to objects via the Graffiti-generated API?
In general, are there good patterns of access control for GraphQL? And in particular, are there any good examples or libraries for doing it with Graffiti?
Notes:
I understand that pre- and post- hooks have been implemented for graffiti-mongoose, and that they can be used to do basic binary checks for authentication. I'd like to see how a more detailed access-control logic could be worked into a GraphQL API. In the future, we'll want to support things like Administrators who have access to model instances created by a certain group of Users (e.g. Users whose Affiliations include that of the Administrator).
Typically GraphQL does not handle access control directly, instead delegating that responsibility to whatever data system it interfaces with. In your case that sounds like Mongoose.
Since access control logic is often arbitrary logic (for example, has this user been banned from some content? did the publisher of that content restrict it with custom privacy settings? etc.), and it sounds like in your case this access control logic is in fact custom, it should live in the "resolve" function which produces a value for a GraphQL field.
For example:
var UserType = new GraphQLObjectType({
name: 'User',
fields: {
name: { type: GraphQLString },
birthday: {
type: GraphQLString,
resolve(user, context) {
var auth = context.myLoggedInAuth;
if (myCanAuthSeeBirthday(auth, user)) {
return user.birthday;
}
}
}
}
});
I create a rule base access control to be used with GraphQL.
https://github.com/joonhocho/graphql-rule
It is simple and unopionated that it can be used with or without GraphQL.
You can use it with a plain javascript objects.
Hope it helps GraphQLers!
Using the first example in the ServiceStack Auto Query documentation in a project structured similar to the EmailContacts sample project (i.e. separate projects for the ServiceModel and ServiceInterface), how would one register the custom route "/movies" defined by the Route attribute?
[Route("/movies")]
public class FindMovies : QueryBase<Movie>
{
public string[] Ratings { get; set; }
}
Normally, custom routes such as these can be register by passing the ServiceInterface assembly when instantiating AppHostBase:
public AppHost() : base("Email Contact Services", typeof(ContactsServices).Assembly) {}
However, the FindMovies request DTO does not have an associated service and therefore won't be included. No routes are registered.
If I pass typeof(FindMovies).Assembly instead of or in addition to typeof(ContactsServices).Assembly, then the pre-defined route will be registered (i.e. shows up in the metadata, postman, etc.) but the custom route is still not registered (i.e. does not show up in the metadata, postman, etc.).
What is the best way to register the custom route using attributes when there is no service and the ServiceModel and ServiceInterface are in separate projects?
These issues should be resolved in v4.0.24+ that's now available on MyGet.
There's a new AutoQueryFeature.LoadFromAssemblies property to specify an additional list of assemblies to scan for IQuery Request DTO's. This automatically looks in the assemblies where your other Request DTO's are defined so in most cases nothing needs to be done as it will automatically be able to find your query services.
The routes for Query DTO's should now appear on the metadata pages as well as Swagger and Postman metadata API's.
I'm new to angular and developing my first 'real' application. I'm trying to build a calendar/scheduling app ( source code can all be seen on github ) and I want to be able to change the content if there is a user logged in (i.e. display details relevant to them) but here's the catch:
I don't want the app to be dependent on having a logged in user ( needs to be something that can be configured to work publicly, privately or both)
I don't want to implement the user/login within this app if it can be avoided ( I want to eventually include my app in another app where this might be implemented but isn't necessarily implemented using any particular security frameworks or limited to any)
I had an idea of creating some global variable user that could be referenced through out my application, or if I had to implement a system to do it all in this app that I could do so in in some abstract way so that different options could be injected in.
some of my ideas or understanding of what I should be doing may be completely wrong and ignorant of fundamentals but I genuinely do not know what approach I should take to do this.
In case it is relevant I currently don't have any back-end but eventually hope use MongoDB for storage and nodejs for services but I also want to try keep it open-ended to allow others to use different storage/backends such as sql and php
is there away to have a global uservariable/service that I could inject/populate from another (parent?) app?
If so what would be the best approach to do so?
If Not, why and what approach should I take and why?
Update
I Believe from comments online and some suggestion made to me that a service would be the best option BUT How would I go about injecting from a parent application into this applications service?
If your (single) page is rendered dynamically by the server and the server knows if you are logged-in or not, then you could do the following:
Dynamically render a script tag that produces:
<script>
window.user = { id: 1234, name: 'User A', isLoggedIn: true };
</script>
For non logged-in users:
<script>
window.user = { isLoggedIn: false };
</script>
For convinience, copy user to a value inside angular's IOC:
angular.module('myApp').value('user', window.user);
Then, you can use it in DI:
angular.module('myApp').factory('myService', function(user) {
return {
doSomething: function() {
if (user.isLoggedIn) {
...
} else {
...
}
}
};
});
Something tricky (which you should thing twice before doing [SEE COMMENTS]) is extending the $scope:
angular.module('myApp').config(function($provide) {
$provide.decorator('$controller', function($delegate, user) {
return function(constructor, locals) {
locals.$scope._user = user;
return $delegate(constructor, locals);
};
});
});
This piece of code decorates the $controller service (responsible for contructing controllers) and basically says that $scope objects prior to being passed to controllers, will be enhanced with the _user property.
Having it automatically $scoped means that you can directly use it any view, anywhere:
<div ng-if="_user.isLoggedIn">Content only for logged-in users</div>
This is something risky since you may end up running into naming conflicts with the original $scope API or properties that you add in your controllers.
It goes without saying that these stuff run solely in the client and they can be easily tampered. Your server-side code should always check the user and return the correct data subset or accept the right actions.
Yes you can do it in $rootScope. However, I believe it's better practice to put it inside a service. Services are singletons meaning they maintain the same state throughout the application and as such are prefect for storing things like a user object. Using a "user" service instead of $rootScope is just better organization in my opinion. Although technically you can achieve the same results, generally speaking you don't want to over-populate your $rootScope with functionality.
You can have a global user object inside the $rootScope and have it injected in all your controllers by simply putting it into the arguments of the controller, just as you do with $scope. Then you can implement functionalities in a simple check: if($rootScope.user). This allows you to model the user object in any way you want and where you want, acting as a global variable, inside of Angular's domain and good practices with DI.
Just to add on my comment and your edit. Here is what the code would look like if you wanted to be able to re-use your user service and insert it into other apps.
angular.module('user', []).service('userService', [function(){
//declare your user properties and methods
}])
angular.module('myApp', ['user'])
.controller('myCtrl', ['userService', '$scope', function(userService, scope){
// you can access userService from here
}])
Not sure if that's what you wanted but likewise you could have your "user" module have a dependency to another "parent" module and access that module's data the same way.
I am using Mvvmcross crosscore in my project
I am trying to bind my loginviewmodel to the loginviewcontroller
I bound a command for the login button. the app waits until it gets a login response, which is stored in the loginViewModel itself..
How can I communicate this to the loginviewcontroller --- regarding the login status and login error message if any
Can I access the viewmodel datacontext inside my loginviewcontroller ??? and how ?
What is the best approach to communication any items in the viewmodel back ( I basically mean all the NON-UI binding items)
I am using Mvvmcross crosscore in my project
I'm assuming from this that you followed the CrossLight sample N=39.
Can I access the viewmodel datacontext inside my loginviewcontroller ??? and how ?
If you followed N=39. then you can access the DataContext using the property called DataContext - see https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/blob/master/N-39-CrossLight-Touch/CrossLightTouch/MyViewController.cs#L33
public object DataContext
{
get { return BindingContext.DataContext; }
set { BindingContext.DataContext = value; }
}
Beyond this, there are many other examples in the N+1 videos which demonstrate how to communicate between ViewModels and Views including error messages and loading dialogs - e.g. N=34 shows one implementation of progress dialogs - https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/tree/master/N-34-Progress
A complete index of N+1 videos is available on http://mvvmcross.wordpress.com
Obviously not all of these are appropriate for your CrossLight approach to development, but this is where you can allow your custom mvvm approach to fill the gap - it's code for you to write in your custom framework.
One of the best methods solving viewmodel interdependencies is using a loosely coupled approch using the MessageBus/Event Aggregator pattern. There's a plugin for MvvmCross. Or you could use the excellent TinyMessenger.
In principle when using this approach, you no longer establish hard references between the publisher and consumers of arbitrary notifications. Instead notifications get published on a message bus and every one is free to listen and subscribe.