mirror of https://github.com/Squidex/squidex.git
19 changed files with 338 additions and 103 deletions
@ -0,0 +1,26 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.ComponentModel.DataAnnotations; |
|||
|
|||
namespace Squidex.Areas.Api.Controllers.News.Models |
|||
{ |
|||
public sealed class FeatureDto |
|||
{ |
|||
/// <summary>
|
|||
/// The name of the feature.
|
|||
/// </summary>
|
|||
[Required] |
|||
public string Name { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// The description text.
|
|||
/// </summary>
|
|||
[Required] |
|||
public string Description { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
|
|||
namespace Squidex.Areas.Api.Controllers.News.Models |
|||
{ |
|||
public class FeaturesDto |
|||
{ |
|||
/// <summary>
|
|||
/// The latest features.
|
|||
/// </summary>
|
|||
[Required] |
|||
public List<FeatureDto> Features { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// The recent version.
|
|||
/// </summary>
|
|||
public int Version { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Squidex.Areas.Api.Controllers.News.Models; |
|||
using Squidex.Areas.Api.Controllers.News.Service; |
|||
using Squidex.Infrastructure.Commands; |
|||
using Squidex.Pipeline; |
|||
|
|||
namespace Squidex.Areas.Api.Controllers.News |
|||
{ |
|||
/// <summary>
|
|||
/// Readonly API for news items.
|
|||
/// </summary>
|
|||
[ApiExplorerSettings(GroupName = nameof(Languages))] |
|||
public sealed class NewsController : ApiController |
|||
{ |
|||
private readonly FeaturesService featuresService = new FeaturesService(); |
|||
|
|||
public NewsController(ICommandBus commandBus) |
|||
: base(commandBus) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Get all features since latest version.
|
|||
/// </summary>
|
|||
/// <param name="version">The latest received version.</param>
|
|||
/// <returns>
|
|||
/// 200 => Latest features returned.
|
|||
/// </returns>
|
|||
[HttpGet] |
|||
[Route("news/features/")] |
|||
[ProducesResponseType(typeof(FeaturesDto), 200)] |
|||
[ApiPermission] |
|||
public async Task<IActionResult> GetLanguages([FromQuery] int version = 0) |
|||
{ |
|||
var features = await featuresService.GetFeaturesAsync(version); |
|||
|
|||
return Ok(features); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Squidex.Areas.Api.Controllers.News.Models; |
|||
using Squidex.ClientLibrary; |
|||
|
|||
namespace Squidex.Areas.Api.Controllers.News.Service |
|||
{ |
|||
public sealed class FeaturesService |
|||
{ |
|||
private const string AppName = "squidex-website"; |
|||
private const string ClientId = "squidex-website:default"; |
|||
private const string ClientSecret = "QGgqxd7bDHBTEkpC6fj8sbdPWgZrPrPfr3xzb3LKoec="; |
|||
private const int FeatureVersion = 1; |
|||
private static readonly QueryContext Flatten = QueryContext.Default.Flatten(); |
|||
private readonly SquidexClient<NewsEntity, FeatureDto> client; |
|||
|
|||
public sealed class NewsEntity : SquidexEntityBase<FeatureDto> |
|||
{ |
|||
} |
|||
|
|||
public FeaturesService() |
|||
{ |
|||
var clientManager = new SquidexClientManager("https://cloud.squidex.io", AppName, ClientId, ClientSecret); |
|||
|
|||
client = clientManager.GetClient<NewsEntity, FeatureDto>("feature-news"); |
|||
} |
|||
|
|||
public async Task<FeaturesDto> GetFeaturesAsync(int version = 0) |
|||
{ |
|||
var result = new FeaturesDto { Features = new List<FeatureDto>(), Version = FeatureVersion }; |
|||
|
|||
if (version < FeatureVersion) |
|||
{ |
|||
var entities = await client.GetAsync(filter: $"data/version/iv ge ${version}", context: Flatten); |
|||
|
|||
result.Features.AddRange(entities.Items.Select(x => x.Data)); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; |
|||
import { inject, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { |
|||
ApiUrlConfig, |
|||
FeatureDto, |
|||
FeaturesDto, |
|||
NewsService |
|||
} from './../'; |
|||
|
|||
describe('NewsService', () => { |
|||
beforeEach(() => { |
|||
TestBed.configureTestingModule({ |
|||
imports: [ |
|||
HttpClientTestingModule |
|||
], |
|||
providers: [ |
|||
NewsService, |
|||
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') } |
|||
] |
|||
}); |
|||
}); |
|||
|
|||
afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => { |
|||
httpMock.verify(); |
|||
})); |
|||
|
|||
it('should make get request to get features', |
|||
inject([NewsService, HttpTestingController], (newsService: NewsService, httpMock: HttpTestingController) => { |
|||
|
|||
let features: FeaturesDto; |
|||
|
|||
newsService.getFeatures().subscribe(result => { |
|||
features = result; |
|||
}); |
|||
|
|||
const req = httpMock.expectOne('http://service/p/api/news/features'); |
|||
|
|||
expect(req.request.method).toEqual('GET'); |
|||
expect(req.request.headers.get('If-Match')).toBeNull(); |
|||
|
|||
req.flush({ |
|||
version: 13, |
|||
features: [{ |
|||
name: 'Feature1', |
|||
text: 'Feature Text1' |
|||
}, { |
|||
name: 'Feature2', |
|||
text: 'Feature Text2' |
|||
}] |
|||
}); |
|||
|
|||
expect(features!).toEqual( |
|||
new FeaturesDto([ |
|||
new FeatureDto('Feature1', 'Feature Text1'), |
|||
new FeatureDto('Feature2', 'Feature Text2') |
|||
], 13)); |
|||
})); |
|||
}); |
|||
@ -0,0 +1,64 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { HttpClient } from '@angular/common/http'; |
|||
import { Injectable } from '@angular/core'; |
|||
import { Observable } from 'rxjs'; |
|||
import { map } from 'rxjs/operators'; |
|||
|
|||
import { |
|||
ApiUrlConfig, |
|||
HTTP, |
|||
pretifyError |
|||
} from '@app/framework'; |
|||
|
|||
export class FeatureDto { |
|||
constructor( |
|||
public readonly name: string, |
|||
public readonly text: string |
|||
) { |
|||
} |
|||
} |
|||
|
|||
export class FeaturesDto { |
|||
constructor( |
|||
public readonly features: FeatureDto[], |
|||
public readonly version: number |
|||
) { |
|||
} |
|||
} |
|||
|
|||
@Injectable() |
|||
export class NewsService { |
|||
constructor( |
|||
private readonly http: HttpClient, |
|||
private readonly apiUrl: ApiUrlConfig |
|||
) { |
|||
} |
|||
|
|||
public getFeatures(): Observable<FeaturesDto> { |
|||
const url = this.apiUrl.buildUrl('api/news/features'); |
|||
|
|||
return HTTP.getVersioned<any>(this.http, url).pipe( |
|||
map(response => { |
|||
const body = response.payload.body; |
|||
|
|||
const items: any[] = body.features; |
|||
|
|||
return new FeaturesDto( |
|||
items.map(item => { |
|||
return new FeatureDto( |
|||
item.name, |
|||
item.text |
|||
); |
|||
}), |
|||
body.version |
|||
); |
|||
}), |
|||
pretifyError('Failed to load features. Please reload.')); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue