Podio .NET View.Items always returns zero - podio

Using the Podio.NET library (Podio.Async), I am trying to get a Podio View object using the ViewService.GetView() method. The Podio View object represents a predefined view, or set of filters, within a Podio Application.
One of the properties of the Podio View object (PodioAPI.Models.View) is the Items property, as in var noOfItems = myView.Items. However, this field always seems to return zero for me.
I guess that I can make a call to ItemService.FilterItemsByView() using the view-id, which in turn returns a PodioCollection<Item> object that has a FilteredItems property that can be used to get the number of items, but this would mean an additional call.
Does anyone have any thoughts or information that may help me?
Thanks for taking the time to read my question, and I hope that you can help, or others find this helpful.
Kaine
Example code
class Program
{
const string CLIENT_ID = "[Your Client Id]";
const string CLIENT_SECRET = "[Your Client Secret]";
const int APP_ID = [Your App Id];
const string APP_TOKEN = "[Your App Token]";
const string VIEW_NAME = "[Your View Id]";
static void Main(string[] args)
{
Task.Run(async () => { await Go(); }).GetAwaiter().GetResult();
Console.ReadKey();
}
static async Task Go()
{
var client = await GetClient();
var views = await GetViews(client);
var view = await GetView(client);
var viewItems = await GetViewItems(client, view);
}
static async Task<View> GetView(Podio client)
{
var view = await client.ViewService.GetView(APP_ID, VIEW_NAME);
Console.WriteLine("View Name: {0}, Id: {1}, Items: {2}",view.Name, view.ViewId, view.Items);
return view;
}
static async Task<List<View>> GetViews(Podio client)
{
var views = await client.ViewService.GetViews(APP_ID);
Console.WriteLine("Views: " + views.Count);
foreach (var view in views)
{
Console.WriteLine(" - ({0}) {1}", view.ViewId, view.Name);
}
return views;
}
static async Task<List<Item>> GetViewItems(Podio client, View view)
{
Console.WriteLine("View Items: " + view.Items); // This always return 0
var itemList = new List<Item>();
var itemsRemaining = true;
var offset = 0;
while (itemsRemaining)
{
var colItems = await client.ItemService.FilterItemsByView(appId: APP_ID, viewId: Int32.Parse(view.ViewId), offset: offset);
Console.WriteLine(" Downloaded: {0} to {1}", offset, offset + colItems.Items.Count());
itemList.AddRange(colItems.Items);
offset += colItems.Items.Count();
if (offset >= colItems.Filtered)
{
itemsRemaining = false;
break;
}
}
Console.WriteLine("Total View Items Downloaded: " + itemList.Count);
return itemList;
}
static async Task<Podio> GetClient()
{
var client = new Podio(CLIENT_ID, CLIENT_SECRET);
var auth = await client.AuthenticateWithApp(APP_ID, APP_TOKEN);
Console.WriteLine("Auth expires in: " + auth.ExpiresIn);
return client;
}
}

There are 2 similar methods:
Get Views: https://developers.podio.com/doc/views/get-views-27460
This method is returning items for each view returned
"items": The number of items matching the view
Get View: https://developers.podio.com/doc/views/get-view-27450
This method is not returning items parameter, but you can still get that from groupings param (if there is any grouping). Otherwise - number of items in view is not returned.
"groupings": individual groups data, if grouping is present, otherwise {}
{
"total": total count of items in all groups,
"groups": [{
"count": items count of the single group,
In case if there are no groupings you'll have to call https://developers.podio.com/doc/items/filter-items-by-view-4540284. And then use filtered response value.
"filtered": Total number of items matching the filter,
If you only need number of filtered items - please add limit=1 parameter to your request.

Related

Serenity Form Default Values

How can I get Max value from table Id field based on a lookup filter in grid?
I have a grid which shows records from a table customer and a lookup filter with different locations. I want to set the Id field in the new form with the Max value from Customers in the Location lookup filter.
I can set the Id field to a static value like 99. But how can I set it to the max value of the customer table? My code below:
#Serenity.Decorators.registerClass()
export class UtentesGrid extends Serenity.EntityGrid<UtentesRow, any> {
protected getColumnsKey() { return 'IpssDB.Utentes'; }
protected getDialogType() { return UtentesDialog; }
protected getIdProperty() { return UtentesRow.idProperty; }
protected getInsertPermission() { return UtentesRow.insertPermission; }
protected getLocalTextPrefix() { return UtentesRow.localTextPrefix; }
protected getService() { return UtentesService.baseUrl; }
constructor(container: JQuery) {
super(container);
}
protected addButtonClick() {
this.editItem(<IpssDB.UtentesRow>{
Codigo: 99
});
}
}
Also is there an event, on the server side (endpoint maybe), that gets called when the add button is clicked and which can allow me to execute c# code? This would give more "freedom" to scan database as I please.
PS:
I managed to solve the problem like this:
Built a Helper:
public static GetUtenteNextNumberResponse GetUtenteNextNumber(IDbConnection connection, GetUtenteNextNumberRequest request)
{
var min = connection.Query<string>(new SqlQuery()
.From("Locais")
.Select("UtenteCodMin")
.Where("Codigo = " + request.Local))
.FirstOrDefault();
var minN = (string.IsNullOrEmpty(min) ? 0 : int.Parse(min));
var minCod = connection.Query<string>(new SqlQuery()
.From("Utentes")
.Select("Codigo")
.Where("Codigo >= " + minN ))
.FirstOrDefault();
var response = new GetUtenteNextNumberResponse();
var n = 0;
response.Number = minCod == null ||
!int.TryParse(minCod, out n) ? minN + 1 : n + 1;
return response;
}
And in the Grid.ts:
protected addButtonClick() {
var eq = this.view.params.EqualityFilter;
var local = 0
local = eq ? eq.Local : 0;
var ultCod = 0;
IPSS.IpssDB.UtentesService.GetUtenteNextNumber({
Local: local,
User: ''
}, response => {
this.editItem(<IpssDB.UtentesRow>{
Codigo: response.Number,
Local: eq ? eq.Local : null
});
});
}
Now the problem is the new form assumes that I am editing a record and not creating a new one and the button "Save" appears as "Update". I suppose it is because I am changing the key field.
Is there a way to overcome this? Or is there another way to go?
If there was an event or endpoint called when the Add new button in grid is clicked, which allowed to return the entity with default values, that would be perfect.
Problem solved!
I was trying to intercept the wrong event. The event i should be intercepting, but didn't know about, was loadEntity and not afterLoadEntity.
So i kept the helper with no change and just replaced the 'UtentesDialog.ts' code like this:
"UtentesDialog.ts"
protected loadEntity(data) {
super.loadEntity(data);
var local = 0;
local = data.Local;
if (this.isNew())
this.getNextNumber(local);
}
private getNextNumber(local) {
IPSS.IpssDB.UtentesService.GetUtenteNextNumber({
Local: local,
User: ''
}, response => {
this.form.Codigo.value = response.Number;
});
};
I also had to keep the addButtonClick in the 'UtentesGrid.ts' in order to obtain the Local value so i could get it in the Dialog form. Otherwise i wouldn't be able to get the value of Local filter (maybe there is another way, i don't know).
"UtentesGrid.ts"
protected addButtonClick() {
var eq = this.view.params.EqualityFilter;
var local = 0
local = eq ? eq.Local : 0;
this.editItem(<IpssDB.UtentesRow>{
//Codigo: ultCod,
Local: eq ? eq.Local : null
});
}

How to sync in memory data with disk in ASP NET

In a ASP NET Controller i have a service that returns a list of items.This service serves from the RAM the list to requesters.
The list can also be altered by a special group of users , so everytime it is altered i write the changes to disk and update my RAM from disk. (Reading my own writes this way)
From a JS client when i alter this list , the changes are written correctly on the disk , but when i forward a second request to get my list , i am served a stale list.I need to hit F5 for the client to get the right data.
I do not understand how does the RAM cache lags behind.
You can see in my service below that i have guarded the altering method with a lock.I have also tried without it to no avail.
Service
public class FileService : IADReadWrite {
private const int SIZE = 5;
private const string COMPUTER_FILE = #"computers.txt";
private List<Computer> computers = new List<Computer>();
private readonly object #filelock = new object();
private readonly Computer[] DEFAULT_COMPUTERS_LIST = new Computer[] {
new Computer(id:"W-CZC81371RS",Username:"A"),
new Computer(id:"W-CZC81371RQ",Username:"B"),
};
async Task<Computers> GetComputersAsymc() {
if (this.computers.Count == 0) {
var query = await Fetch();
this.computers = query.ToList();
}
var result = new Computers(this.computers);
return result;
}
public async Task<bool> AddComputerAsync(Computer computer) {
lock (filelock) {
if (this.computers.Any(x => x == computer)) {
return false;
}
this.computers.Add(computer);
File.WriteAllText(COMPUTER_FILE, JsonConvert.SerializeObject(this.computers, Formatting.Indented));
this.computers = JsonConvert.DeserializeObject<List<Computer>>(File.ReadAllText(COMPUTER_FILE));
}
return true;
}
---------------------Helpers --------------------------
private async Task<IEnumerable<Computer>> Fetch() {
if (!File.Exists(COMPUTER_FILE)) {
WriteComputersToDisk();
}
using (FileStream stream = new FileStream(COMPUTER_FILE, FileMode.Open, FileAccess.Read)) {
var raw = await File.ReadAllTextAsync(COMPUTER_FILE);
var comp = JsonConvert.DeserializeObject<List<Computer>>(raw);
return comp;
}
}
private void WriteComputersToDisk() {
var comps = DEFAULT_COMPUTERS_LIST;
var data = JsonConvert.SerializeObject(comps, Formatting.Indented);
File.WriteAllText(COMPUTER_FILE, data);
}
}
Controller
public class MyController:Controller
{
MyController(IADReadWrite service)
{
this.service=service;
}
IADReadWrite service;
[HttpGet]
public async Task<List<Computer>> GetAll()
{
return await service.GetComputersAsync();
}
[HttpPost]
public async Task AddComputer(Computer computer)
{
await service.AddComputerAsync(computer);
}
}
Scenario
Initial list : [0,1]
Client hits controller calling `AddComputer` {2}
I check the file , list is now: [0,1,2]
Client hits controller calling `GetComputers` -> it returns [0,1]
I hit F5 on the browser -> GetComputers gets hit again -> it returns [0,1,2]
P.S
I have not posted the Computer class since it does not matter in this scenario ( It implements IEquateable in case you are wondering if it is failing when i use the == operator.
The last 2 methods deal with the initialization of the Disk file.

MS Dynamics CRM. Get users who current record shared with

I have a entity record which is shared with or more users. I would like to unshare this record when Deactivate it. I want to do that in Plugin. But I can't understand how to get all users from sharing list who have access to this record. How to do that?
Here is my code snippet:
protected void ExecutePostPersonSetStateDynamicEntity(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
var context = localContext.PluginExecutionContext;
var targetEntity = (Entity)context.InputParameters["EntityMoniker"];
var state = (OptionSetValue)context.InputParameters["State"];
var columns = new ColumnSet(new[] { "statecode" });
var retrivedEntity = localContext.OrganizationService.Retrieve(targetEntity.LogicalName, targetEntity.Id, columns);
if (state.Value == 1)
{
RevokeAccessRequest revokeRequest = new RevokeAccessRequest()
{
Target = new EntityReference(personEntity.LogicalName, personEntity.Id),
Revokee = new EntityReference(neededEntity.LogicalName, needed.Id)
};
// Execute the request.
}
}
As you can see, I need an entity "neededEntity", I don't know how to get it from "targetEntity" or "retrievedEntity".
You need to use a RetrieveSharedPrincipalsAndAccessRequest
http://msdn.microsoft.com/en-us/library/microsoft.crm.sdk.messages.retrievesharedprincipalsandaccessrequest.aspx
You can start from the included example, basically inside the foreach you call your RevokeAcessRequest

send parameter to windows azure mobile server script in c# for Windows 8 Store app

I modified the "Read" operation on my Windows Azure Mobile Services Preview table (named "Item") as follows:
Javascript:
function read(query, user, request)
{
var howRead;
if(howRead == "unique")
{
var sqlUnique = "SELECT DISTINCT ? FROM Item WHERE qProjectCode = ?";
mssql.query(sqlUnique)
request.execute();
}
else if (howRead == "column")
{
var sqlColumn = "SELECT ? FROM Item WHERE qProjectCode = ?";
mssql.query(sqlColumn)
request.execute();
}
else if (howRead == "all")
{
var sqlAll = "SELECT * FROM Item WHERE qProjectCode = ?";
mssql.query(sqlAll)
request.execute();
}
}
This simply species when I want a unique list of a single column's values returned, all items in a single column, or all columns, respectively, all while limiting the read to those records with a given project code.
Right now, this works in C#, but scans the entire table (with other project codes) and always returns all columns. This is inherently inefficient.
c#
var client = new MobileServiceClient("[https path", "[key]");
var table = client.GetTable<Item>();
var query1 = table.Where(w => w.QProjectCode == qgv.projCode && w.QRecord == (int)lbRecord.Items[uStartRecordIndex]);
var query1Enum = await query1.ToEnumerableAsync();
foreach (var i in query1Enum)
{
// process data
}
How do I alter the c# code to deal with the Javascript code? Feel free to critique the overall approach, since I am not a great programmer and can always use advice!
Thanks
A few things:
In your server code, the mssql calls are not doing anything (useful). If you want to get their results, you need to pass a callback (the call is asynchronous) to it.
Most of your scenarios can be accomplished at the client side. The only for which you'll need server code is the one with the DISTINCT modifier.
For that scenario, you'll need to pass a custom parameter to the server script. You can use the WithParameters method in the MobileServiceTableQuery<T> object to define parameters to pass to the service.
Assuming this data class:
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Other { get; set; }
public string ProjectCode { get; set; }
}
The code below can be used to accomplish the scenarios 2 and 3 at the client side only (no script needed at the server side). The other one will need some script, which I'll cover later.
Task<IEnumerable<string>> ReadingByColumn(IMobileServiceTable<Item> table, string projectCode)
{
return table
.Where(i => i.ProjectCode == projectCode)
.Select(i => i.Name)
.ToEnumerableAsync();
}
Task<IEnumerable<Item>> ReadingAll(IMobileServiceTable<Item> table, string projectCode)
{
return table.Where(i => i.ProjectCode == projectCode).ToEnumerableAsync();
}
Task<IEnumerable<string>> ReadingByColumnUnique(IMobileServiceTable<Item> table, string projectCode)
{
var dict = new Dictionary<string, string>
{
{ "howRead", "unique" },
{ "projectCode", projectCode },
{ "column", "Name" },
};
return table
.Select(i => i.Name)
.WithParameters(dict)
.ToEnumerableAsync();
}
Now, to support the last method (which takes the parameters, we'll need to do this on the server script:
function read(query, user, request)
{
var howRead = request.parameters.howRead;
if (howRead) {
if (howRead === 'unique') {
var column = request.parameters.column; // WARNING: CHECK FOR SQL INJECTION HERE!!! DO NOT USE THIS IN PRODUCTION!!!
var sqlUnique = 'SELECT DISTINCT ' + column + ' FROM Item WHERE ProjectCode = ?';
mssql.query(sqlUnique, [request.parameters.projectCode], {
success: function(distinctColumns) {
var results = distinctColumns.map(function(item) {
var result = [];
result[column] = item; // mapping to the object shape
return result;
});
request.respond(statusCodes.OK, results);
}
});
} else {
request.respond(statusCodes.BAD_REQUEST, {error: 'Script does not support option ' + howRead});
}
} else {
// no server-side action needed
request.execute();
}
}

Calling 2 httpwebrequests in parallel using Reactive Extensions

i m trying to call 2 httpwebrequest in parallel and make them call the same callback when they are done using Rx extensions.
But i don0t know how i can achive this..here's my code:
private static IObservable<Stream> GetImage(string path)
{
var uri = new Uri(path);
var thumburi = new Uri(path + "_thumb.jpg");
return Observable.Create<Stream>(o =>
{
var request = (HttpWebRequest) HttpWebRequest.Create(uri);
var readComplete =
Observable.FromAsyncPattern<WebResponse>(
request.BeginGetResponse,
request.EndGetResponse)();
var subscription = readComplete
.Select(e => e.GetResponseStream())
.Subscribe(o);
return subscription;
});
}
With the latest bits and .Net 4.5, you could do something like this:
private static IObservable<byte[]> GetImages(string path)
{
var sources = new Uri[]
{
var uri = new Uri(path),
var thumburi = new Uri(path + "_thumb.jpg")
};
var obs = from uri in sources.ToObservable()
from data in Observable.Using(
() => new WebClient(),
client => client.DownloadDataTaskAsync(uri).ToObservable())
select data;
return obs;
}
I do wonder if you really want to just return steams of data and not care which stream corresponds to the base and which is the thumbnail. Once you make the request in parallel, you no longer control the order that they come back in. You could project a type that includes the uri and data stream to disambiguate them if you want.
I'm guessing you would pull out the asynchronous calls to two separate streams then concatenate them, no? Like this: http://leecampbell.blogspot.com/2010/06/rx-part-5-combining-multiple.html
I'd suggest this kind of solution.
Make GetImage more general purpose:
private static IObservable<Stream> GetImage(Uri uri)
{
return Observable.Create<Stream>(o =>
{
var request = (HttpWebRequest)HttpWebRequest.Create(uri);
var readComplete =
Observable.FromAsyncPattern<WebResponse>(
request.BeginGetResponse,
request.EndGetResponse)();
var subscription =
readComplete
.Select(e => e.GetResponseStream())
.Subscribe(o);
return subscription;
});
}
Then add a specific GetImages method that does the querying for the image and its thumb:
private static IObservable<Tuple<Uri, Stream>> GetImages(string path)
{
var uris = new []
{
new Uri(path + ".jpg"),
new Uri(path + "_thumb.jpg"),
}.ToObservable();
return
from uri in uris
from stream in GetImage(uri)
select Tuple.Create(uri, stream);
}
I've assumed that your path variable cannot contain the ".jpg" extension otherwise you'd have had to done some string manipulation.
Now GetImages returns a IObservable<Tuple<Uri, Stream>> because the SelectMany doesn't guarantee the return order of the streams so we need to use the Uri to disambiguate the streams.
Let me know if this works for you.
Why not just use Zip?
GetStream("foo.jpg").Zip(GetStream("bar.jpg"), (foo, bar) => new { foo, bar })
.Subscribe(fooAndBar => ...);