SoftLayer API : getNasNetworkStorage return null - api

I am checking to get NAS storage list.
I tested 2 ways, one ways is using BAP id, another way is direct account id
first
Using BAP id, get account list.
Using account id, get NAS Storage list.
==> I didn't NAS Storage list
second
Using direct account id, get NAS Storage list
===> successly, get NAS Storage list
I don't Understand difference between ways.
i attached first test code,
"getNasNetworkStorageCount" method returned NAS stroage count, but "getNasNetworkStorage" return "null".
public void test() {
String userId = "IBMxxxxx";
String apiKey = "xxxxx";
client = new RestApiClient().withCredentials(userId, apiKey).withLoggingEnabled();
Account.Service accountService = Account.service(client);
List<Brand> brandList = accountService.getOwnedBrands();
for (Brand brand : brandList) {
Brand.Service brandService = brand.asService(client);
Account.Mask mask = new Account.Mask();
mask.id();
mask.companyName();
mask.accountStatusId();
mask.email();
mask.hardwareCount();
mask.hardware();
mask.virtualGuestCount();
mask.virtualGuests();
mask.nasNetworkStorage();
mask.nasNetworkStorageCount();
brandService.clearMask();
brandService.setMask(mask);
List<Account> accountList = accountList = brandService.getOwnedAccounts();
for (Account account : accountList) {
if(account.getNasNetworkStorageCount() != 0){
System.out.print(account.getNasNetworkStorageCount() + " == ");
System.out.println(account.getNasNetworkStorage().size());
}
}
System.out.println(accountList.size());
}
}

Your results might be those because when you run the SoftLayer_Brand::getOwnedAccounts method it only returns the account for the current user (i.e. the user that’s calling the API)
You can run this Java example and see that effectively the brand retrieves the right account for the user caller, and then all NAS Network Storages that belong to it.
package SoftLayer_Java_Scripts.Examples;
import com.google.gson.Gson;
import com.softlayer.api.*;
import com.softlayer.api.service.Account;
import com.softlayer.api.service.Brand;
import com.softlayer.api.service.network.Storage;
import java.util.List;
public class GetNasNetworkStorage
{
public static void main( String[] args )
{
String user = "set me";
String apiKey = "set me";
long brandId = 2L;
ApiClient client = new RestApiClient().withCredentials(user, apiKey);
Brand.Service brandService = Brand.service(client, brandId);
try
{
List<Account> accountsList = brandService.getOwnedAccounts();
Gson gson = new Gson();
for (Account account : accountsList) {
Account.Service accountService = account.asService(client);
List<Storage> nasStorageList = accountService.getNasNetworkStorage();
for (Storage storage : nasStorageList) {
System.out.println(gson.toJson(storage));
}
}
}
catch(Exception e)
{
System.out.println("Script failed, review the next message for further details: " + e.getMessage());
}
}
}

The difference is that the Brand service is to manage brand accounts whilts using directly the account service is to manage all the information about a particular account.
Currently it may be an issue with the object mask that you are using, however the problem of use the Brand service is that this service was designed only to display the basic information of the all accounts which belong to the brand it was not designed to display all the information of the related accounts (even if you use object masks). I am going to report the issue of the object mask to softlayer, I mean the one related that the nasNetworkStorage returns null, but I already reported similar issues and they were not fix it, because as I told you that is not the propuse of the service.
You also can try setting the object mask as a string maybe that works e.g.
brandService.setMask("mask[id,companyName,accountStatusId,email,hardwareCount,hardware,virtualGuestCount,VirtualGuest,nasNetworkStorage,nasNetworkStorageCount]");
Anyway the most reliable way to get that information of your accounts associated to the brand is using the master user of each accout, I mean using the account service; even the softlayer agent portal uses the master account to get more information of a particular account in your brand.
Let me know if you have more questions
Regards

Related

Symfony 6 Api Platform Extension

I'm a beginner on Sf6 and i'm stuck on a problem with the doctrine extension. I try to recover some datas from an API and send them to a front-end Angular 13. My personnal project is an application for manage some garden equipments and i look for to recover datas according to the role of the user.
If the current user have ['ROLE_USER'] i want to fetch his owns datas but if the user have ['ROLE_ADMIN'] i want to fetch all the datas for this entity. I'm ever able to do it with my entity Garden but not for the equipments entity.
My relationnal logical data model:
And the code for CurrentUserExtension.php :
<?php
namespace App\Doctrine;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use App\Entity\Garden;
use App\Entity\Lawnmower;
use App\Entity\Lightning;
use App\Entity\Pool;
use App\Entity\Portal;
use App\Entity\Watering;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Security\Core\Security;
/**
* This extension makes sure normal users can only access their own Datas
*/
final class CurrentUserExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
{
private $security;
public function __construct(Security $security) {
$this->security = $security;
}
public function applyToCollection(QueryBuilder $queryBuilder,
QueryNameGeneratorInterface $queryNameGenerator,
string $resourceClass,
string $operationName = null): void {
$this->addWhere($queryBuilder, $resourceClass);
}
public function applyToItem(QueryBuilder $queryBuilder,
QueryNameGeneratorInterface $queryNameGenerator,
string $resourceClass,
array $identifiers,
string $operationName = null,
array $context = []): void {
$this->addWhere($queryBuilder, $resourceClass);
}
private function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void {
if ($this->security->isGranted('ROLE_ADMIN')
|| null === $user = $this->security->getUser()) {
return;
}
$rootAlias = $queryBuilder->getRootAliases()[0];
switch ($resourceClass) {
case Garden::class:
$queryBuilder->andWhere(sprintf('%s.user = :current_user', $rootAlias))
->setParameter('current_user', $user);
break;
case Lawnmower::class:
case Lightning::class:
case Pool::class:
case Portal::class:
case Watering::class:
$gardenAlias = sprintf("%s_garden", $rootAlias);
$queryBuilder->innerJoin(sprintf('%s.garden', $rootAlias), $gardenAlias)
->andWhere(sprintf('%s.user = :current_user', $gardenAlias))
->setParameter('current_user', $user);
break;
}
}
}
It's my first post on Stackoverflow so feel free to say me if my post isn't formated as well. Some help will be appreciated.
Ps: As you could see in the final class CurrentUserExtension.php i'm using Api Platform.
According to the documentation of Api Platform (https://api-platform.com/docs/core/extensions/) i'm able to fetch gardens depending of the user role, the final class CurrentUserExtension work as expected. I'm looking for doing the same for the equipments entities (Watering, Lawnmower, Pool, Portal and Lightning). Notice the relation between my entities (one-to-many):
A User could have many gardens but a Garden could belong to a single User.
A Garden could have many waterings but a Watering could belong to a single Garden.
I just saw there is an error on my relationnal logical data model: the entities Lawnmower, Pool, Portal and Lightning doesn't have the property garden_user_id in their classe. But the entity Watering is ok, i have just a single foreign key garden_id.
I'm able to give you the SQL request for retrieve all the waterings for the user which have the id 2 (this request works fine):
SELECT w.id, w.garden_id, w.name, w.flow_sensor, w.pressure_sensor, w.status FROM watering AS w INNER JOIN garden AS g ON g.id = w.garden_id INNER JOIN user AS u ON u.id = g.user_id WHERE u.id = 2
I think i'm near to my goal but now i've the following error =>
"[Semantical Error] line 0, col 104 near 'o_garden INNER': Error: 'o_garden' is already defined."
Your problem can be solved with a "conception" change.
I would say I do not try to make a single api url with different behaviors based on the user.
To make this work, I advise you to do something like this :
Be careful; my answer is on Symfony 6.2, Php 8, and Api Platform 3
#[ApiResource(
operations: [
new GetCollection(),
new GetCollection(
uriTemplate: "/gardens/my-gardens"
security: "is_granted('ROLE_USER')"
controller: MyGardenController.php
)
],
security: "is_granted('ROLE_ADMIN')"
)]
class Garden {}
And inside
class MyGardenController extends AbstractController
{
public function __construct(
private Security $security,
private GardenRepository $gardenRepository,
)
{}
public function __invoke()
{
return $this->gardenRepository->findBy(['user' => $this->security->getUser());
}
}
So ! What does it do?
By default, the Garden entity is only accessible to ADMIN.
So by default, /api/gardens cant be accessed by a non admin user.
But, /api/gardens/my-gardens as a custom controller returns only a garden linked to the currently connected user.
Just call a different endpoint based on the user role on your front end.
But if you want to keep one endpoint, you could do this inside the custom controller :
public function __invoke()
{
if($this->isGranted('ROLE_ADMIN')){
return $this->gardenRepository->findAll();
}
return $this->gardenRepository->findBy(['user' => $this->security->getUser());
}

ASP.NET Core Authentication Id?

The tutorials on enabling authentication work all right, but what identifier should be used to store data for a user in the database? The only thing easily available is User.Name, which seems to be my email address.
I see in the database there is an AspNetUsers table with that as the UserName column, and a varchar Id column that appears to be a GUID and is the primary key. It seems like the 'Id' field is the logical value to use, but it's not readily available in my app. I found I can get to it like this:
string ID_TYPE = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier";
var id = User.Claims.Where(x => x.Type == ID_TYPE).Select(x => x.Value).FirstOrDefault();
But that seems like a weird way to go about it. Is that the proper value to use say if I want to create a 'Posts' table that has a user associated with a post?
I've looked at these pages and it seems that a lot of this might be due to Microsoft integrating the same login process with ActiveDirectory.
Is there a reason to make the id so hard to get to and the name so easy? Should I be using the name instead? Should I be careful not to let the user change their user name then?
The shortest path to UserId is:
User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
Or create extension like so if you need to access UserId a lot:
public static class ClaimsPrincipalExtensions
{
public static string GetUserId(this ClaimsPrincipal principal)
{
if (principal == null)
return null; //throw new ArgumentNullException(nameof(principal));
string ret = "";
try
{
ret = principal.FindFirst(ClaimTypes.NameIdentifier)?.Value;
}
catch (System.Exception)
{
}
return ret;
}
}
Usage:
User.GetUserId()
In your controller use dependency injection to get the user manager:
Create a class MyUser that has your extended properties
public class MyUser : IdentityUser
{
public string MyExendedInfo { get; set; }
public int MyOtherInfo {get;set;}
}
add this property to the database using migration, or manually add it.
In Startup.cs in Configure Services add:
services.AddIdentity<MyUser, IdentityRole>()
Now inject this in your controller class:
private readonly UserManager<MyUser> _userManager;
public HomeController(
UserManager<MyUser> userManager)
{
_userManager = userManager;
}
Now you can access your additional proporties and your Id (if you still need this) in your action methods like this:
var user = await _userManager.GetUserAsync(HttpContext.User);
var id = user.Id;
var myExtendedInfo = user.MyExtendedInfo;
var myOtherInfo = user.MyOtherInfo;
etc
You can also update information about your user:
user.myExtendedInfo = "some string";
user.MyOtherInfo = myDatabase.pointer;
var result = await _userManager.UpdateAsync(user);
if (!result.Succeeded)
{
//handle error
}
So as long as you want only limited additional data stored in the database, you can create a custom user class, and use the Identity system to store it for you. I would not store it myself.
If however, you need to store large information in a separate table and/or reference the user from other tables, the Id is the correct field to use and you can access it as shown above.
I don't know what the best practice is for how much information can be stored in AspNetUsers, versus in claims, versus in your own table, but since the provided table already stores things like user name, phonenumber etc, I think it is Ok to extend it like this.

Genesys Platform : Get Call Details From Sip Server

I want to get Call Details from Genesys Platform SIP Server.
And Genesys Platform has Platform SDK for .NET .
Anybod has a SIMPLE sample code which shows how to get call details using Platform SDK for .NET [ C# ] from SIP Server?
Extra Notes:
Call Details : especially i wanted to get AgentId for a given call
and
From Sip Server : I am not sure if Sip Server is the best candiate to
take call details. So open to other suggestions/ alternatives
You can build a class that monitor DN actions. Also you watch specific DN or all DN depending what you had to done. If its all about the call, this is the best way to this.
Firstly, you must define a TServerProtocol, then you must connect via host,port and client info.
var endpoint = new Endpoint(host, port, config);
//Endpoint backupEndpoint = new Endpoint("", 0, config);
protocol = new TServerProtocol(endpoint)
{
ClientName = clientName
};
//Sync. way;
protocol.Open();
//Async way;
protocol.BeginOpen();
I always use async way to do this. I got my reason thou :) You can detect when connection open with event that provided by SDK.
protocol.Opened += new EventHandler(OnProtocolOpened);
protocol.Closed += new EventHandler(OnProtocolClosed);
protocol.Received += new EventHandler(OnMessageReceived);
protocol.Error += new EventHandler(OnProtocolError);
Here there is OnMessageReceived event. This event where the magic happens. You can track all of your call events and DN actions. If you go genesys support site. You'll gonna find a SDK reference manual. On that manual quiet easy to understand there lot of information about references and usage.
So in your case, you want agentid for a call. So you need EventEstablished to do this. You can use this in your recieve event;
var message = ((MessageEventArgs)e).Message;
// your event-handling code goes here
switch (message.Id)
{
case EventEstablished.MessageId:
var eventEstablished = message as EventEstablished;
var AgentID = eventEstablished.AgentID;
break;
}
You can lot of this with this usage. Like dialing, holding on a call inbound or outbound even you can detect internal calls and reporting that genesys platform don't.
I hope this is clear enough.
If you have access to routing strategy and you can edit it. You can add some code to strategy to send the details you need to some web server (for example) or to DB. We do such kind of stuff in our strategy. After successful routing block as a post routing strategy sends values of RTargetPlaceSelected and RTargetAgentSelected.
Try this:
>
Genesyslab.Platform.Contacts.Protocols.ContactServer.Requests.JirayuGetInteractionContent
JirayuGetInteractionContent =
Genesyslab.Platform.Contacts.Protocols.ContactServer.Requests.JirayuGetInteractionContent.Create();
JirayuGetInteractionContent.InteractionId = "004N4aEB63TK000P";
Genesyslab.Platform.Commons.Protocols.IMessage respondingEventY =
contactserverProtocol.Request(JirayuGetInteractionContent);
Genesyslab.Platform.Commons.Collections.KeyValueCollection keyValueCollection =
((Genesyslab.Platform.Contacts.Protocols.ContactServer.Events.EventGetInteractionContent)respondingEventY).InteractionAttributes.AllAttributes;
We are getting AgentID and Place as follows,
Step-1:
Create a Custome Command Class and Add Chain of command In ExtensionSampleModule class as follows,
class LogOnCommand : IElementOfCommand
{
readonly IObjectContainer container;
ILogger log;
ICommandManager commandManager;
public bool Execute(IDictionary<string, object> parameters, IProgressUpdater progress)
{
if (Application.Current.Dispatcher != null && !Application.Current.Dispatcher.CheckAccess())
{
object result = Application.Current.Dispatcher.Invoke(DispatcherPriority.Send, new ExecuteDelegate(Execute), parameters, progress);
return (bool)result;
}
else
{
// Get the parameter
IAgent agent = parameters["EnterpriseAgent"] as IAgent;
IIdentity workMode = parameters["WorkMode"] as IIdentity;
IAgent agentManager = container.Resolve<IAgent>();
Genesyslab.Desktop.Modules.Core.Model.Agents.IPlace place = agentManager.Place;
if (place != null)
{
string Place = place.PlaceName;
}
else
log.Debug("Place object is null");
CfgPerson person = agentManager.ConfPerson;
if (person != null)
{
string AgentID = person.UserName;
log.DebugFormat("Place: {0} ", AgentID);
}
else
log.Debug("AgentID object is null");
}
}
}
// In ExtensionSampleModule
readonly ICommandManager commandManager;
commandManager.InsertCommandToChainOfCommandAfter("MediaVoiceLogOn", "LogOn", new
List<CommandActivator>() { new CommandActivator()
{ CommandType = typeof(LogOnCommand), Name = "OnEventLogOn" } });
enter code here
IInteractionVoice interaction = (IInteractionVoice)e.Value;
switch (interaction.EntrepriseLastInteractionEvent.Id)
{
case EventEstablished.MessageId:
var eventEstablished = interaction.EntrepriseLastInteractionEvent as EventEstablished;
var genesysCallUuid = eventEstablished.CallUuid;
var genesysAgentid = eventEstablished.AgentID;
.
.
.
.
break;
}

How To Use Groovy HTTPBuilder To Get Stories from AgileZen?

I would like to pull stories from Agile Zen using their REST API.
I read:
http://help.agilezen.com/kb/api/overview
http://help.agilezen.com/kb/api/security
Also, I got this to work: http://groovy.codehaus.org/HTTP+Builder
How would one combine the above in order to get Groovy client code to access AgileZen stories?
Here is the code sample which makes one story with id of 1 show up for a specific project whose id is 16854:
import groovyx.net.http.HTTPBuilder
import static groovyx.net.http.Method.GET
import static groovyx.net.http.ContentType.JSON
public class StoryGetter {
public static void main(String[] args) {
new StoryGetter().getStories()
}
void getStories() {
// http://agilezen.com/project/16854/story/4
// /api/v1/project/16854/story/2
def http = new HTTPBuilder( 'http://agilezen.com' )
http.request( GET, JSON ) {
uri.path = '/api/v1/project/16854/story/1'
headers.'X-Zen-ApiKey' = 'PUT YOUR OWN API KEY HERE'
response.success = { resp, json ->
println "json size is " + json.size()
println json.toString()
}
}
}
}
I had to put in a fake API key in this post since I should not share my API key.
(By the way, this is not using SSL. A follow up question in regards to doing this for a SSL enabled project may come soon.)

Unable to get presence of roster by using smack, openfire

I am new to smack API. I am trying to develop a chat application where I was trying for setting and getting the presence.
When I change the presence of a user, its working perfectly fine and it is getting reflected in the Openfire Server.
But when I tries to get the Presence of a user, I am always getting the status as 'unavailable' even if his presence in openfire is showing as 'available'.
I am using the following code to set the status.
Presence presence = new Presence(Presence.Type.available);
presence.setStatus("Online, Programmatically!");
presence.setPriority(24);
presence.setMode(Presence.Mode.available);
user.getConnection().sendPacket(presence);
I am using the Roster class to get the presence as follows.
Roster roster = avatar.getRoster();
Collection<RosterEntry> entries = roster.getEntries();
for(RosterEntry rosterEntry: entries) {
String user = rosterEntry.getUser();
Presence presence = roster.getPresence(user);
System.out.println("Presence : "+presence); // 1
System.out.println("Presence type: "+presence.getType()); // 2
System.out.println("Presence mode: "+presence.getMode()); // 3
}
Line No 1 alwasys gives 'unavailable' while line number 2 and 3 always give null
I am not able to figure out the cause of this problem. Please help me to resolve this issue.
Thanks in advance.
Using RosterListener is the proper solution to this problem. There is no reason that code should have a Thread.sleep() in order to make it work properly.
Roster roster = con.getRoster();
roster.addRosterListener(new RosterListener() {
// Ignored events public void entriesAdded(Collection<String> addresses) {}
public void entriesDeleted(Collection<String> addresses) {}
public void entriesUpdated(Collection<String> addresses) {}
public void presenceChanged(Presence presence) {
System.out.println("Presence changed: " + presence.getFrom() + " " + presence);
}
});
(source: http://www.igniterealtime.org/builds/smack/docs/latest/documentation/roster.html)
the problem is that after logging in immediately, it is gonna take some time for the presence of users to get updated.So between logging in and calling the online buddies function there should be a thread.sleep() for a few seconds.Then the online contacts will be retrieved. I did that and was able to retrieve them.
after login use
Thread.sleep(5000);
use in the beginiing of the method also
I had the same problem and searched for a while before finding what the problem was. In fact, you don't need to do a Thread.sleep(). The problem is that you don't have the "permission" to get the Presence of other users.
To solve the problem, just go in Openfire admin -> your user options -> Roster // Then just set the subscription of the buddy you wanna get the presence to "both" (both users can view each other presence).
Hope that is helps.
Edit : In fact you need to add a Thread.sleep() before getting the roster from the connection. Without the Thread.sleep(), sometimes it works, sometimes not...
I fixed it adding:
if (!roster.isLoaded())
roster.reloadAndWait();
after:
Roster roster = Roster.getInstanceFor(connection);
Ref: Smack 4.1.0 android Roster not displaying
This full code
public void getRoaster(final Callback<List<HashMap<String, String>>> callback) {
final Roster roster = Roster.getInstanceFor(connection);
boolean success = true;
if (!roster.isLoaded())
try {
roster.reloadAndWait();
} catch (SmackException.NotLoggedInException | SmackException.NotConnectedException | InterruptedException e) {
android.util.Log.e(AppConstant.PUBLIC_TAG, TAG + " " + e.getMessage());
success = false;
}
if (!success) {
if (callback != null) {
callback.onError(new Throwable());
}
}
Collection<RosterEntry> entries = roster.getEntries();
List<HashMap<String, String>> maps = new ArrayList<HashMap<String, String>>(entries.size());
for (RosterEntry entry : entries) {
HashMap<String, String> map = new HashMap<String, String>(3);
Presence presence = roster.getPresence(entry.getUser());
map.put(ROASTER_KEY, entry.getName());
map.put(ROASTER_BARE_JID, entry.getUser());
map.put(PRESENCE_TYPE, presence.isAvailable() == true ? PRESENCE_ONLINE : PRESENCE_OFFLINE);
maps.add(map);
}
if (maps != null && maps.size() > 0 && callback != null) {
callback.onSuccess(maps);
} else {
callback.onError(new Throwable());
}
}