mirror of https://github.com/Squidex/squidex.git
committed by
GitHub
74 changed files with 517 additions and 107 deletions
@ -0,0 +1,19 @@ |
|||||
|
// ==========================================================================
|
||||
|
// MyUIOptions.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
// ReSharper disable CollectionNeverUpdated.Global
|
||||
|
|
||||
|
namespace Squidex.Config |
||||
|
{ |
||||
|
public sealed class MyUIOptions |
||||
|
{ |
||||
|
public Dictionary<string, string> RegexSuggestions { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ScopesProcessor.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Reflection; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using NSwag; |
||||
|
using NSwag.SwaggerGeneration.Processors; |
||||
|
using NSwag.SwaggerGeneration.Processors.Contexts; |
||||
|
using Squidex.Infrastructure.Tasks; |
||||
|
|
||||
|
// ReSharper disable InvertIf
|
||||
|
|
||||
|
namespace Squidex.Config.Swagger |
||||
|
{ |
||||
|
public class ScopesProcessor : IOperationProcessor |
||||
|
{ |
||||
|
public Task<bool> ProcessAsync(OperationProcessorContext context) |
||||
|
{ |
||||
|
if (context.OperationDescription.Operation.Security == null) |
||||
|
{ |
||||
|
context.OperationDescription.Operation.Security = new List<SwaggerSecurityRequirement>(); |
||||
|
} |
||||
|
|
||||
|
var authorizeAttributes = |
||||
|
context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Union( |
||||
|
context.MethodInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(true).OfType<AuthorizeAttribute>()).ToArray(); |
||||
|
|
||||
|
if (authorizeAttributes.Any()) |
||||
|
{ |
||||
|
var scopes = authorizeAttributes.Where(a => a.Roles != null).SelectMany(a => a.Roles.Split(',')).Distinct().ToList(); |
||||
|
|
||||
|
context.OperationDescription.Operation.Security.Add(new SwaggerSecurityRequirement |
||||
|
{ |
||||
|
{ Constants.SecurityDefinition, scopes } |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
return TaskHelper.True; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
// ==========================================================================
|
||||
|
// UIRegexSuggestionDto.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace Squidex.Controllers.Api.UI.Models |
||||
|
{ |
||||
|
public sealed class UIRegexSuggestionDto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The name of the suggestion.
|
||||
|
/// </summary>
|
||||
|
[Required] |
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The regex pattern.
|
||||
|
/// </summary>
|
||||
|
[Required] |
||||
|
public string Pattern { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
// ==========================================================================
|
||||
|
// UISettingsDto.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
|
||||
|
namespace Squidex.Controllers.Api.UI.Models |
||||
|
{ |
||||
|
public sealed class UISettingsDto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The regex suggestions.
|
||||
|
/// </summary>
|
||||
|
[Required] |
||||
|
public List<UIRegexSuggestionDto> RegexSuggestions { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,57 @@ |
|||||
|
// ==========================================================================
|
||||
|
// UIController.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using NSwag.Annotations; |
||||
|
using Squidex.Config; |
||||
|
using Squidex.Controllers.Api.UI.Models; |
||||
|
using Squidex.Pipeline; |
||||
|
|
||||
|
namespace Squidex.Controllers.Api.UI |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Manages ui settings and configs.
|
||||
|
/// </summary>
|
||||
|
[ApiExceptionFilter] |
||||
|
[SwaggerTag("UI")] |
||||
|
public sealed class UIController : Controller |
||||
|
{ |
||||
|
private readonly MyUIOptions uiOptions; |
||||
|
|
||||
|
public UIController(IOptions<MyUIOptions> uiOptions) |
||||
|
{ |
||||
|
this.uiOptions = uiOptions.Value; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Get ui settings.
|
||||
|
/// </summary>
|
||||
|
[HttpGet] |
||||
|
[Route("ui/settings/")] |
||||
|
[ProducesResponseType(typeof(UISettingsDto), 200)] |
||||
|
[ApiCosts(0)] |
||||
|
public IActionResult GetSettings() |
||||
|
{ |
||||
|
var dto = new UISettingsDto |
||||
|
{ |
||||
|
RegexSuggestions = |
||||
|
uiOptions.RegexSuggestions? |
||||
|
.Where(x => |
||||
|
!string.IsNullOrWhiteSpace(x.Key) && |
||||
|
!string.IsNullOrWhiteSpace(x.Value)) |
||||
|
.Select(x => new UIRegexSuggestionDto { Name = x.Key, Pattern = x.Value }).ToList() |
||||
|
?? new List<UIRegexSuggestionDto>() |
||||
|
}; |
||||
|
|
||||
|
return Ok(dto); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,79 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; |
||||
|
import { inject, TestBed } from '@angular/core/testing'; |
||||
|
|
||||
|
import { |
||||
|
ApiUrlConfig, |
||||
|
UIService, |
||||
|
UISettingsDto |
||||
|
} from './../'; |
||||
|
|
||||
|
describe('UIService', () => { |
||||
|
beforeEach(() => { |
||||
|
TestBed.configureTestingModule({ |
||||
|
imports: [ |
||||
|
HttpClientTestingModule |
||||
|
], |
||||
|
providers: [ |
||||
|
UIService, |
||||
|
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') } |
||||
|
] |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => { |
||||
|
httpMock.verify(); |
||||
|
})); |
||||
|
|
||||
|
it('should make get request to get settings', |
||||
|
inject([UIService, HttpTestingController], (uiService: UIService, httpMock: HttpTestingController) => { |
||||
|
|
||||
|
let settings1: UISettingsDto | null = null; |
||||
|
let settings2: UISettingsDto | null = null; |
||||
|
|
||||
|
uiService.getSettings().subscribe(result => { |
||||
|
settings1 = result; |
||||
|
}); |
||||
|
|
||||
|
const response: UISettingsDto = { regexSuggestions: [] }; |
||||
|
|
||||
|
const req = httpMock.expectOne('http://service/p/api/ui/settings'); |
||||
|
|
||||
|
expect(req.request.method).toEqual('GET'); |
||||
|
expect(req.request.headers.get('If-Match')).toBeNull(); |
||||
|
|
||||
|
req.flush(response); |
||||
|
|
||||
|
uiService.getSettings().subscribe(result => { |
||||
|
settings2 = result; |
||||
|
}); |
||||
|
|
||||
|
expect(settings1).toEqual(response); |
||||
|
expect(settings2).toEqual(response); |
||||
|
})); |
||||
|
|
||||
|
it('should return default settings when error occurs', |
||||
|
inject([UIService, HttpTestingController], (uiService: UIService, httpMock: HttpTestingController) => { |
||||
|
|
||||
|
let settings: UISettingsDto | null = null; |
||||
|
|
||||
|
uiService.getSettings().subscribe(result => { |
||||
|
settings = result; |
||||
|
}); |
||||
|
|
||||
|
const req = httpMock.expectOne('http://service/p/api/ui/settings'); |
||||
|
|
||||
|
expect(req.request.method).toEqual('GET'); |
||||
|
expect(req.request.headers.get('If-Match')).toBeNull(); |
||||
|
|
||||
|
req.error(new ErrorEvent('500')); |
||||
|
|
||||
|
expect(settings.regexSuggestions).toEqual([]); |
||||
|
})); |
||||
|
}); |
||||
@ -0,0 +1,49 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
import { HttpClient } from '@angular/common/http'; |
||||
|
import { Injectable } from '@angular/core'; |
||||
|
import { Observable } from 'rxjs'; |
||||
|
|
||||
|
import 'framework/angular/http-extensions'; |
||||
|
|
||||
|
import { ApiUrlConfig } from 'framework'; |
||||
|
|
||||
|
export interface UISettingsDto { |
||||
|
regexSuggestions: UIRegexSuggestionDto[]; |
||||
|
} |
||||
|
|
||||
|
export interface UIRegexSuggestionDto { |
||||
|
name: string; pattern: string; |
||||
|
} |
||||
|
|
||||
|
@Injectable() |
||||
|
export class UIService { |
||||
|
private settings: UISettingsDto; |
||||
|
|
||||
|
constructor( |
||||
|
private readonly http: HttpClient, |
||||
|
private readonly apiUrl: ApiUrlConfig |
||||
|
) { |
||||
|
} |
||||
|
|
||||
|
public getSettings(): Observable<UISettingsDto> { |
||||
|
if (this.settings) { |
||||
|
return Observable.of(this.settings); |
||||
|
} else { |
||||
|
const url = this.apiUrl.buildUrl(`api/ui/settings`); |
||||
|
|
||||
|
return this.http.get<UISettingsDto>(url) |
||||
|
.catch(error => { |
||||
|
return Observable.of({ regexSuggestions: [] }); |
||||
|
}) |
||||
|
.do(settings => { |
||||
|
this.settings = settings; |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue