@@ -9,7 +9,6 @@ namespace Microsoft.SCIM.WebHostSample.Provider
99 using System . Threading . Tasks ;
1010 using System . Web . Http ;
1111 using Microsoft . SCIM ;
12- using Microsoft . SCIM . WebHostSample . Resources ;
1312
1413 public class InMemoryUserProvider : ProviderBase
1514 {
@@ -44,6 +43,11 @@ public override Task<Resource> CreateAsync(Resource resource, string correlation
4443 throw new HttpResponseException ( HttpStatusCode . Conflict ) ;
4544 }
4645
46+ // Update metadata
47+ DateTime created = DateTime . UtcNow ;
48+ user . Metadata . Created = created ;
49+ user . Metadata . LastModified = created ;
50+
4751 string resourceIdentifier = Guid . NewGuid ( ) . ToString ( ) ;
4852 resource . Identifier = resourceIdentifier ;
4953 this . storage . Users . Add ( resourceIdentifier , user ) ;
@@ -82,71 +86,153 @@ public override Task<Resource[]> QueryAsync(IQueryParameters parameters, string
8286
8387 if ( null == parameters . AlternateFilters )
8488 {
85- throw new ArgumentException ( SampleServiceResources . ExceptionInvalidParameters ) ;
89+ throw new ArgumentException ( SystemForCrossDomainIdentityManagementServiceResources . ExceptionInvalidParameters ) ;
8690 }
8791
8892 if ( string . IsNullOrWhiteSpace ( parameters . SchemaIdentifier ) )
8993 {
90- throw new ArgumentException ( SampleServiceResources . ExceptionInvalidParameters ) ;
94+ throw new ArgumentException ( SystemForCrossDomainIdentityManagementServiceResources . ExceptionInvalidParameters ) ;
9195 }
9296
93- Resource [ ] results ;
94- IFilter queryFilter = parameters . AlternateFilters . SingleOrDefault ( ) ;
95- if ( queryFilter == null )
96- {
97- IEnumerable < Core2EnterpriseUser > allUsers = this . storage . Users . Values ;
98- results =
99- allUsers . Select ( ( Core2EnterpriseUser user ) => user as Resource ) . ToArray ( ) ;
100-
101- return Task . FromResult ( results ) ;
102- }
103-
104- if ( string . IsNullOrWhiteSpace ( queryFilter . AttributePath ) )
105- {
106- throw new ArgumentException ( SampleServiceResources . ExceptionInvalidParameters ) ;
107- }
97+ IEnumerable < Resource > results = new List < Core2EnterpriseUser > ( ) ;
10898
109- if ( string . IsNullOrWhiteSpace ( queryFilter . ComparisonValue ) )
99+ if ( parameters . AlternateFilters . Count <= 0 )
110100 {
111- throw new ArgumentException ( SampleServiceResources . ExceptionInvalidParameters ) ;
101+ results = this . storage . Users . Values . Select (
102+ ( Core2EnterpriseUser user ) => user as Resource ) ;
112103 }
113-
114- if ( queryFilter . FilterOperator != ComparisonOperator . Equals )
104+ else
115105 {
116- throw new NotSupportedException ( SampleServiceResources . UnsupportedComparisonOperator ) ;
117- }
106+ results = new List < Core2EnterpriseUser > ( ) ;
118107
119- if ( queryFilter . AttributePath . Equals ( AttributeNames . UserName ) )
120- {
121- IEnumerable < Core2EnterpriseUser > allUsers = this . storage . Users . Values ;
122- results =
123- allUsers . Where (
124- ( Core2EnterpriseUser item ) =>
125- string . Equals (
126- item . UserName ,
127- parameters . AlternateFilters . Single ( ) . ComparisonValue ,
128- StringComparison . OrdinalIgnoreCase ) )
129- . Select ( ( Core2EnterpriseUser user ) => user as Resource ) . ToArray ( ) ;
130-
131- return Task . FromResult ( results ) ;
108+ foreach ( IFilter queryFilter in parameters . AlternateFilters )
109+ {
110+ IEnumerable < Core2EnterpriseUser > users = this . storage . Users . Values ;
111+
112+ IFilter andFilter = queryFilter ;
113+ IFilter currentFilter = andFilter ;
114+ do
115+ {
116+ if ( string . IsNullOrWhiteSpace ( andFilter . AttributePath ) )
117+ {
118+ throw new ArgumentException ( SystemForCrossDomainIdentityManagementServiceResources . ExceptionInvalidParameters ) ;
119+ }
120+
121+ else if ( string . IsNullOrWhiteSpace ( andFilter . ComparisonValue ) )
122+ {
123+ throw new ArgumentException ( SystemForCrossDomainIdentityManagementServiceResources . ExceptionInvalidParameters ) ;
124+ }
125+
126+ // UserName filter
127+ else if ( andFilter . AttributePath . Equals ( AttributeNames . UserName , StringComparison . OrdinalIgnoreCase ) )
128+ {
129+ if ( andFilter . FilterOperator != ComparisonOperator . Equals )
130+ {
131+ throw new NotSupportedException (
132+ string . Format ( SystemForCrossDomainIdentityManagementServiceResources . ExceptionFilterOperatorNotSupportedTemplate , andFilter . FilterOperator ) ) ;
133+ }
134+
135+ users =
136+ users . Where (
137+ item =>
138+ string . Equals (
139+ item . UserName ,
140+ andFilter . ComparisonValue ,
141+ StringComparison . OrdinalIgnoreCase ) ) ;
142+ }
143+
144+ // ExternalId filter
145+ else if ( andFilter . AttributePath . Equals ( AttributeNames . ExternalIdentifier , StringComparison . OrdinalIgnoreCase ) )
146+ {
147+ if ( andFilter . FilterOperator != ComparisonOperator . Equals )
148+ {
149+ throw new NotSupportedException (
150+ string . Format ( SystemForCrossDomainIdentityManagementServiceResources . ExceptionFilterOperatorNotSupportedTemplate , andFilter . FilterOperator ) ) ;
151+ }
152+
153+ users =
154+ users . Where (
155+ item =>
156+ string . Equals (
157+ item . ExternalIdentifier ,
158+ andFilter . ComparisonValue ,
159+ StringComparison . OrdinalIgnoreCase ) ) . ToList ( ) ;
160+ }
161+
162+ // Id filter
163+ else if ( andFilter . AttributePath . Equals ( AttributeNames . Identifier , StringComparison . OrdinalIgnoreCase ) )
164+ {
165+ if ( andFilter . FilterOperator != ComparisonOperator . Equals )
166+ {
167+ throw new NotSupportedException (
168+ string . Format ( SystemForCrossDomainIdentityManagementServiceResources . ExceptionFilterOperatorNotSupportedTemplate , andFilter . FilterOperator ) ) ;
169+ }
170+
171+ users =
172+ users . Where (
173+ item =>
174+ string . Equals (
175+ item . Identifier ,
176+ andFilter . ComparisonValue ,
177+ StringComparison . OrdinalIgnoreCase ) ) . ToList ( ) ;
178+ }
179+
180+ // Active filter
181+ else if ( andFilter . AttributePath . Equals ( AttributeNames . Active , StringComparison . OrdinalIgnoreCase ) )
182+ {
183+ if ( andFilter . FilterOperator != ComparisonOperator . Equals )
184+ {
185+ throw new NotSupportedException (
186+ string . Format ( SystemForCrossDomainIdentityManagementServiceResources . ExceptionFilterOperatorNotSupportedTemplate , andFilter . FilterOperator ) ) ;
187+ }
188+
189+ users =
190+ users . Where (
191+ item =>
192+ item . Active == bool . Parse ( andFilter . ComparisonValue ) ) . ToList ( ) ;
193+ }
194+
195+ // LastModified filter
196+ else if ( andFilter . AttributePath . Equals ( $ "{ AttributeNames . Metadata } .{ AttributeNames . LastModified } ", StringComparison . OrdinalIgnoreCase ) )
197+ {
198+ if ( andFilter . FilterOperator == ComparisonOperator . EqualOrGreaterThan )
199+ {
200+ users =
201+ users . Where (
202+ item =>
203+ item . Metadata . LastModified >= DateTime . Parse ( andFilter . ComparisonValue ) . ToUniversalTime ( ) ) . ToList ( ) ;
204+ }
205+ else if ( andFilter . FilterOperator == ComparisonOperator . EqualOrLessThan )
206+ {
207+ users =
208+ users . Where (
209+ item =>
210+ item . Metadata . LastModified <= DateTime . Parse ( andFilter . ComparisonValue ) . ToUniversalTime ( ) ) . ToList ( ) ;
211+ }
212+ else
213+ throw new NotSupportedException (
214+ string . Format ( SystemForCrossDomainIdentityManagementServiceResources . ExceptionFilterOperatorNotSupportedTemplate , andFilter . FilterOperator ) ) ;
215+ }
216+ else
217+ throw new NotSupportedException (
218+ string . Format ( SystemForCrossDomainIdentityManagementServiceResources . ExceptionFilterAttributePathNotSupportedTemplate , andFilter . AttributePath ) ) ;
219+
220+ currentFilter = andFilter ;
221+ andFilter = andFilter . AdditionalFilter ;
222+
223+ } while ( currentFilter . AdditionalFilter != null ) ;
224+
225+ results = results . Union ( users . Select ( ( Core2EnterpriseUser user ) => user as Resource ) . ToList ( ) ) ;
226+ }
132227 }
133228
134- if ( queryFilter . AttributePath . Equals ( AttributeNames . ExternalIdentifier ) )
229+ if ( parameters . PaginationParameters != null )
135230 {
136- IEnumerable < Core2EnterpriseUser > allUsers = this . storage . Users . Values ;
137- results =
138- allUsers . Where (
139- ( Core2EnterpriseUser item ) =>
140- string . Equals (
141- item . ExternalIdentifier ,
142- parameters . AlternateFilters . Single ( ) . ComparisonValue ,
143- StringComparison . OrdinalIgnoreCase ) )
144- . Select ( ( Core2EnterpriseUser user ) => user as Resource ) . ToArray ( ) ;
145-
146- return Task . FromResult ( results ) ;
231+ int count = parameters . PaginationParameters . Count . HasValue ? parameters . PaginationParameters . Count . Value : 0 ;
232+ return Task . FromResult ( results . Take ( count ) . ToArray ( ) ) ;
147233 }
148-
149- throw new NotSupportedException ( SampleServiceResources . UnsupportedFilterAttributeUser ) ;
234+ else
235+ return Task . FromResult ( results . ToArray ( ) ) ;
150236 }
151237
152238 public override Task < Resource > ReplaceAsync ( Resource resource , string correlationIdentifier )
@@ -163,10 +249,9 @@ public override Task<Resource> ReplaceAsync(Resource resource, string correlatio
163249 throw new HttpResponseException ( HttpStatusCode . BadRequest ) ;
164250 }
165251
166- IEnumerable < Core2EnterpriseUser > exisitingUsers = this . storage . Users . Values ;
167252 if
168253 (
169- exisitingUsers . Any (
254+ this . storage . Users . Values . Any (
170255 ( Core2EnterpriseUser exisitingUser ) =>
171256 string . Equals ( exisitingUser . UserName , user . UserName , StringComparison . Ordinal ) &&
172257 ! string . Equals ( exisitingUser . Identifier , user . Identifier , StringComparison . OrdinalIgnoreCase ) )
@@ -175,11 +260,20 @@ public override Task<Resource> ReplaceAsync(Resource resource, string correlatio
175260 throw new HttpResponseException ( HttpStatusCode . Conflict ) ;
176261 }
177262
178- if ( ! this . storage . Users . TryGetValue ( user . Identifier , out Core2EnterpriseUser _ ) )
263+ Core2EnterpriseUser exisitingUser = this . storage . Users . Values
264+ . FirstOrDefault (
265+ ( Core2EnterpriseUser exisitingUser ) =>
266+ string . Equals ( exisitingUser . Identifier , user . Identifier , StringComparison . OrdinalIgnoreCase )
267+ ) ;
268+ if ( exisitingUser == null )
179269 {
180270 throw new HttpResponseException ( HttpStatusCode . NotFound ) ;
181271 }
182272
273+ // Update metadata
274+ user . Metadata . Created = exisitingUser . Metadata . Created ;
275+ user . Metadata . LastModified = DateTime . UtcNow ;
276+
183277 this . storage . Users [ user . Identifier ] = user ;
184278 Resource result = user as Resource ;
185279 return Task . FromResult ( result ) ;
@@ -226,17 +320,17 @@ public override Task UpdateAsync(IPatch patch, string correlationIdentifier)
226320
227321 if ( null == patch . ResourceIdentifier )
228322 {
229- throw new ArgumentException ( SampleServiceResources . ExceptionInvalidPatch ) ;
323+ throw new ArgumentException ( string . Format ( SystemForCrossDomainIdentityManagementServiceResources . ExceptionInvalidOperation ) ) ;
230324 }
231325
232326 if ( string . IsNullOrWhiteSpace ( patch . ResourceIdentifier . Identifier ) )
233327 {
234- throw new ArgumentException ( SampleServiceResources . ExceptionInvalidPatch ) ;
328+ throw new ArgumentException ( SystemForCrossDomainIdentityManagementServiceResources . ExceptionInvalidOperation ) ;
235329 }
236330
237331 if ( null == patch . PatchRequest )
238332 {
239- throw new ArgumentException ( SampleServiceResources . ExceptionInvalidPatch ) ;
333+ throw new ArgumentException ( SystemForCrossDomainIdentityManagementServiceResources . ExceptionInvalidOperation ) ;
240334 }
241335
242336 PatchRequest2 patchRequest =
@@ -251,6 +345,9 @@ public override Task UpdateAsync(IPatch patch, string correlationIdentifier)
251345 if ( this . storage . Users . TryGetValue ( patch . ResourceIdentifier . Identifier , out Core2EnterpriseUser user ) )
252346 {
253347 user . Apply ( patchRequest ) ;
348+
349+ // Update metadata
350+ user . Metadata . LastModified = DateTime . UtcNow ;
254351 }
255352 else
256353 {
0 commit comments