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