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