Search Active Directory (AD LDS) by DateTime custom attribute - c#

I have added custom attribute lastLogonTime syntax: UTC Coded Time. I extended UserPrincipal class to GET/SET that custom attribute.
...
[DirectoryProperty("lastLogonTime")]
public DateTime? LastLogonTime
{
get
{
object[] result = this.ExtensionGet("lastLogonTime");
if (result != null && result.Count() > 0) return (DateTime?)result[0];
return null;
}
set
{
this.ExtensionSet("lastLogonTime", value);
}
}
...
I have also extended AdvancedFilters to be able to search by this custom attribute.
MyUserPrincipalSearch searchFilter;
new public MyUserPrincipalSearch AdvancedSearchFilter
{
get
{
if (null == searchFilter)
searchFilter = new MyUserPrincipalSearch(this);
return searchFilter;
}
}
public class MyUserPrincipalSearch: AdvancedFilters
{
public MyUserPrincipalSearch(Principal p) : base(p) { }
public void LastLogonTime (DateTime? lastLogonTime, MatchType mt)
{
this.AdvancedFilterSet("lastLogonTime", lastLogonTime.Value, typeof(DateTime?), mt);
}
}
Now, I would like to search through all users who has lastLogonTime less than a day.
using (PrincipalContext ctx = ADLDSUtility.Users)
{
MyUserPrincipal filter = new MyUserPrincipal(ctx);
filter.AdvancedSearchFilter.LastLogonTime((DateTime.Now - new TimeSpan(1,0,0,0,0)), MatchType.LessThan);
PrincipalSearcher ps = new PrincipalSearcher(filter);
foreach (MyUserPrincipal p in ps.FindAll())
{
//my custom code
}
}
The above search is not returning me any results. I have test users who have not logged in in the last couple days.
I have tried MatchType.GreaterThan, MatchType.Equals. None of them are returning any results, yet there're users who match those criteria.
The only filter that does work is
filter.AdvancedSearchFilter.LastLogonTime(DateTime.Now , MatchType.NotEquals);
But this is basically returning all users. Any ideas why my search result is not returning any results?
My goal is to search for all users who's last logon time is less than X days.
I'm open to other solutions as long as I get those users.
P.S. I do know a way around this. Loop through all users, get their lastLogonTime and then do a comparison, but that's just an overkill for what I'm doing.

After spending sometimes on this issue, I found the problem.
As I mentioned on my post the custom attribute lastLogonTime has syntax: UTC Coded Time. However, the date and time is not getting stored as DateTime. It's actually getting stored as string in this format:
yyyyMMddHHmmss.0Z
How I ended up solving this issue is by modifying my AdvancedSearchFilter.LastLogonTime to search using formatted string.
public void LastLogonTime (DateTime? lastLogonTime, MatchType mt)
{
const string lastLogonTimeFormat = "yyyyMMddHHmmss.0Z";
this.AdvancedFilterSet("lastLogonTime", lastLogonTime.Value.ToUniversalTime().ToString(lastLogonTimeFormat), typeof(string), mt);
}
Hope this helps someone.

Related

how can I use "distinct" with all my property

I have a method that allows me to create an agent list.
This list of agents contains "Nom", "Prenom", "Matricule", "Mail".
I use.distinct() to sort them, but this only takes into account "Nom", "Prenom", "Matricule". This does not check if the emails are different. How do I proceed?
The creation of my agent list:
private ObservableCollection<AgentMailModel> _Agents;
public ObservableCollection<AgentMailModel> Agents
{
get
{
return _Agents;
}
set
{
if (value != _Agents)
{
_Agents = value;
RaisePropertyChanged("Agents");
}
}
}
foreach (Destinataire dst in (await _dataService.GetDestinatairesAsync()))
_TmpAgents.Add(new AgentMailModel() { Matricule = dst.Matricule, Nom = dst.Nom, Prenom = dst.Prenom, Mail = dst.Mail });
foreach (AgentModel ag in (await _dataService.GetAgentsContratsAsync()))
_TmpAgents.Add(new AgentMailModel() { Matricule = ag.Matricule, Nom = ag.Nom, Prenom = ag.Prenom, Mail = ag.Mail });
Agents = new ObservableCollection<AgentMailModel(_TmpAgents.Distinct());
My list in WPF :
My database :
As you can see :
It displays "carré" (cause "Nom" is different, It also works with a different "Prenom" or "Matricule) and only one "carre" (without "é").
Distinct() doesn't work with my Mails. Any tips ?
You have two possibilities.
First one is to create a class of IEqualityComparer and implement a full comparison.
you can find an example here.
The second one is to convert the objects to JSON, and made of comparison of strings instead of objects.

Filtering walls by Base Constraint: The filter value is not valid for the field and filter type

I'm having difficulty trying to filter out walls by the WALL_BASE_CONSTRAINT. This is the code I currently have. The Build is successful but when I execute the plugin. I come up with the exception: The filter value is not valid for the field and filter type.
Parameter name: filter
I have successfully tried this code on other BuiltInParameters like Material_Name, ALL_MODEL_DESCRIPTION.
private static void AddFilterToSchedule(Document doc, ViewSchedule
schedule)
{
string value = "Foundation";
using (Transaction transaction = new Transaction(schedule.Document, "Filter Material TakeOff"))
{
transaction.Start();
ScheduleDefinition definition = schedule.Definition;
ScheduleField scheduleField = FindField(schedule, BuiltInParameter.WALL_BASE_CONSTRAINT);
ScheduleFilter filter = new ScheduleFilter(scheduleField.FieldId, ScheduleFilterType.NotEqual, value);
definition.AddFilter(filter);
transaction.Commit();
}
}
public static ScheduleField FindField(ViewSchedule schedule,
BuiltInParameter paramEnum)
{
ScheduleDefinition definition = schedule.Definition;
ScheduleField foundField = null;
ElementId paramId = new ElementId(paramEnum);
foreach (ScheduleFieldId fieldId in definition.GetFieldOrder())
{
foundField = definition.GetField(fieldId);
if (foundField.ParameterId == paramId)
{
return foundField;
}
}
return foundField;
}
Where does FindField come from and what does it do?
Have you looked at the ScheduleCreation Revit SDK sample?
Be sure to make sure that "Include Elements in Links" is set to False, or otherwise not checked in your created schedule.
This results in not being able to filter by Base Constraint.

What is the recommended way to respond to bad user input with a REST API?

Let's assume the following:
I have a rest API that will return me names of fruits, and there are only 5 fruits.
To get the fruit name, I have to request an ID.
Consider the following code:
public class Fruit {
public int FruitID { get; set; }
public string FruitName { get; set; }
public Fruit(string json){
JObject o = JObject.Parse(json);
FruitID = Int32.Parse((string) o["id"]);
FruitName = (string) o["name");
}
}
public static Fruit getFruit(int id){
Task<Fruit> task = "http://fruit.com/get_fruit"
.SetQueryParams(new { fruit_id = id })
.GetStringAsync();
return new Fruit(task.Result);
}
(If anything looks wrong at this point please correct me, I am new to C# Tasks)
Let's say when that Task returns, the json could look like the following if it received a valid ID...
{
"status":1,
"id": 3,
"name": "apple"
}
Or this if it received an invalid ID.
{
"status":0
}
If the user is supposed to enter which ID is searched for, then there is a chance they could enter an ID which does not exist, since there are only 5, (0 through 4). Based on the code I entered above, I can see the application crashing if a "status":0 is returned, as it would not have the two fields the class constructor is looking for.
My question is: What is the best way to handle possible invalid inputs (such as the user entering ID of 20)?
The recommended way for a RESTful API is to use HTTP Error codes, in your case it would be 404 (Not found), since the fruit requested does not exist.
You should handle the error codes before trying to create the object. So check whether the request has been successfully executed (200 OK), and then process the payload.
Here's a reference of status codes:
http://www.restapitutorial.com/httpstatuscodes.html
input validation is one of the important tasks in web service development. i personally have two phase. at first i check the object for null values. i wrote this method in order to do it:
private bool HasNull(object webServiceInput, string[] optionalParameters = null)
{
if (ReferenceEquals(null, webServiceInput))
return false;
if (optionalParameters == null)
optionalParameters = new string[0];
var binding = BindingFlags.Instance | BindingFlags.Public;
var properties = webServiceInput.GetType().GetProperties(binding);
foreach (var property in properties)
{
if (!property.CanRead)
continue;
if (property.PropertyType.IsValueType)
continue;
if (optionalParameters.Contains(property.Name))
continue;
var value = property.GetValue(webServiceInput);
if (ReferenceEquals(null, value))
return false;
}
return true;
}
then if some of the inputs should have specified validation i check it individually. for example i check the ID be between 0 and 5;
i hope it could help you.

How to filter on multiple SubItems in ObjectListView

So, I am trying to programmatically add in a ModelFilter to my ObjectListView that will look at two (or more) columns and filters on each separately. Currently, I think that ObjectListView only supports one filter, but I may be missing something in the code/documentation.
As an example, one of my intended filters is to look at column "Active" and that has values of "A" or "T". Another column is a Supervisor Name. So, I want to find all entries where Supervisor name = "Smith" and Active = "A".
I can get the filter to work for either of these options separately using TextMatchFilter, but cannot figure out how to get both to work at the same time.
The minor problem I see is that if the Supervisor Name contains an "A", then using the standard Filter will return the whole row. I have been able to get around that by programmatically setting the Searchable property for columns to false if I don't want to look at them, and then turn them back on once the list is filtered. However, I have a feeling that if I turn Searchable on for the Supervisor column, I will get the unwanted results.
Does anyone know of a way to get the filter to work on multiple columns, using only the indicated columns for each filter?
(I have no sample code to show that helps in solving this. However, if you really want to see what I have for my filtering code, I will be happy to add that; it is in VB however).
Current Code - This looks at a value chosen by the user (searchMeth) and enables searching on that column. It then does the search for what was entered in the txtSearch box. However, in addition to this, I want to add in an additional filter for Supervisor. (See the AndAlso comment
olvEmps.UseFiltering = True
OlvColumn1.Searchable = False
OlvColumn2.Searchable = False
OlvColumn4.Searchable = False
OlvColumn3.Searchable = False
OlvColumn5.Searchable = False
Select Case searchMeth
Case "Name"
OlvColumn1.Searchable = True
Case "Employee Number"
OlvColumn2.Searchable = True
Case "Department"
OlvColumn3.Searchable = True
End Select
olvEmps.OwnerDraw = True
Dim tFilter As BrightIdeasSoftware.TextMatchFilter = BrightIdeasSoftware.TextMatchFilter.Contains(olvEmps, txtSearch.Text)
'andalso olvColumn5 = supeName?
olvEmps.ModelFilter = tFilter
olvEmps.DefaultRenderer = New BrightIdeasSoftware.HighlightTextRenderer(tFilter)
OlvColumn1.Searchable = True
OlvColumn2.Searchable = True
OlvColumn3.Searchable = True
OlvColumn4.Searchable = True
OlvColumn5.Searchable = True
I'm sure the PredicateBuilder solution will work, but ObjectListView comes with a simpler solution already.
TextMatchFilter can be limited to which columns it searches via the Columns property. Set this to an array of columns that you want to consider.
TextMatchFilter filter1 = TextMatchFilter.Contains(olvEmps, txtSearch.Text)
filter1.Columns = new [] { this.olvColumn1, this.olvColumn2 };
You can combine two filters using the CompositeAllFilter to match two or more other filters.
this.olvEmps.ModelFilter = new CompositeAllFilter(new List<IModelFilter> { filter1, filter2 });
Though I don't yet fully understand your deal, I'll give it a shot with the PredicateBuilder that is part of the LINQKit assembly which you can download here.
As such, filtering on multiple columns shall get easy. Perhaps shall you consider to reset the binding of your ObjectListView control once your source collection has been filtered.
Grossly, I would do about the following:
Load your datum;
Display them through data binding;
Once a column is clicked for filter, make a call to your "Filter" method which will apply your predicates;
Rebind your control with the new filtered collection.
Please refer to the PredicateBuilder documentation at the link provided previously. Another example to building dynamic filters is illustrated here: "How would this query translate into a dynamic Linq expression?" for a search engine I implemented.
In my case, the filters were applied directly against the database results. Aside, it can even be used in your situation with in-memory datum since it is Linq based.
I'm sure I'll be able to provide further assitance when you post your code sample for filtering the information.
EDIT #1
After I have read the code sample provided, here's what I believe would do the trick. As for the Searchable property, I am no familiar of this approach, so maybe I can miss something important out of your code and if it is so, feel free to point me what I could have missed. =)
Note that I assume that all of your datum are string, since I am verifying whether your datum is null or white space. Furthermore, the way I see it, to filter a result set is to bring visible only records which meet certain criterion. You don't want to see what doesn't meet the criterion. It's the same as a WHERE clause in SQL.
public class FilterCriterion {
public bool HasEmployeeName { get { return !string.IsNullOrWhiteSpace(EmployeeName); } }
public bool HasEmployeeNumber { get { return !string.IsNullOrWhiteSpace(EmployeeNumber); } }
public bool HasDepartment { get { return !string.IsNullOrWhiteSpace(Department); } }
public string EmployeeName { get; set; }
public string EmployeeNumber { get; set; }
public string Department { get; set; }
}
The FilterCriterion class shall be used to apply any filter that you want against your data source, collection or whatsoever.
var employees = LoadEmployeesFromUnderlyingDataStore();
var criterion = new FilterCriterion();
switch(searchMeth) {
case "Name": filter.EmployeeName = "the name to filter by"; break;
case "EmployeeNumber": filter.EmployeeNumber = "the number to filter by"; break;
case "Department": filter.Department = "the department to filter by"; break;
}
var filter = PredicateBuilder.True<Employee>(); // assuming you have an employee class.
if (criterion.HasEmployeeName)
filter.And(e => e.Name.ContainsLike(criterion.EmployeeName));
if (criterion.HasEmployeeNumber)
filter.And(e => e.EmployeeNumber.ContainsLike(criterion.EmployeeNumber));
if (criterion.HasDepartment)
filter.And(e => e.Department.ContainsLike(criterion.Department));
var filteredEmployees = employees.Where(filter);
// Supply your ObjectListView the way you're used to and this shall function.
Aside, you could also, if you have to deal with such string variables write a ContainsLike extension method to the string class.
namespace System {
public static class StringExtensions {
public static bool ContainsLike(this string input, string value) {
if (string.IsNullOrWhiteSpace(input) || string.IsNullOrWhiteSpace(value)) return false;
input = input.ToLower().RemoveDiacritics();
value = value.ToLower().RemoveDiacritics();
if (string.IsNullOrWhiteSpace(input) || string.IsNullOrWhiteSpace(value)) return false;
return input.Contains(value);
}
public static string RemoveDiacritics(this string input) {
return input == null ? null :
Encoding.ASCII.GetString(Encoding.GetEncoding(1251).GetBytes(input));
}
}
}
I do hope this helps, otherwise inform me of what I misunderstood from your question and we'll try to figure this out together.
Should you need the VB version of this code, I'll try to translate to the best of my VB knowledge.
This code is provided as is and has not been tested, except for both the string extension methods.

Querying Distinct Events from Google Calendar

Right now I have a very simple query that pulls up entries that have a string and a specific date range.
EventQuery eQuery = new EventQuery(calendarInfo.Uri.ToString());
eQuery.Query = "Tennis";
eQuery.StartDate = startDate;
eQuery.EndDate = endDate;
EventFeed myResultsFeed = _service.Query(eQuery);
After querying, myResultsFeed will contain an atomEntryCollection. Each atomEntry has a Title. The way I have it set up, there could be multiple entries with the same title.
I would like my Query to be able to select UNIQUE titles. Is this possible?
Link to the API Docs
I hypothesized that I could use a WHERE object
Where x = new Where();
x.yadayada();
but it can't be passed to _service.Query()
I'm also exploring the .extraparameters object. is it possible to do something like this?
eQuery.ExtraParameters = "distinct";
Looking into the "Partial Response" feature..
http://code.google.com/apis/gdata/docs/2.0/reference.html#PartialResponse
it looks pretty promising..
I don't think what you're trying to do is possible using the Google Data API.
However, extenting upon #Fueled answer, you could do something like this if you need a collection of AtomEntry's.
// Custom comparer for the AtomEntry class
class AtomEntryComparer : IEqualityComparer<AtomEntry>
{
// EventEntry are equal if their titles are equal.
public bool Equals(AtomEntry x, AtomEntry y)
{
// adjust as needed
return x.Title.Text.Equals(y.Title.Text);
}
public int GetHashCode(AtomEntry entry)
{
// adjust as needed
return entry.Title.Text.GetHashCode();
}
}
EventFeed eventFeed = service.Query(query)
var entries = eventFeed.Entries.Distinct(new AtomEntryComparer());
It's probably not the solution you were looking for, but since you have in hand an AtomEntryCollection (which down the line implements IEnumerable<T>), you could use LINQ to retrieve the distinct titles, like so:
EventFeed feed = service.Query(query);
var uniqueEntries =
(from e in feed.Entries
select e.Title.Text).Distinct();
And then loop over them with a simple foreach:
foreach (var item in uniqueEntries)
{
Console.WriteLine(item);
}
But then you have only a collection of string representing the Event titles, and not a collection of AtomEntry. I guess you could link them together in a Dictionary.
Not optimal, but should work.

Categories

Resources