Browse Source

Merge branch 'feature/info_endpoint' into next

pull/381/head
Sebastian Stehle 7 years ago
parent
commit
2cfa4be788
  1. 3
      Dockerfile
  2. 15
      src/Squidex.Web/ExposedConfiguration.cs
  3. 56
      src/Squidex.Web/ExposedValues.cs
  4. 19
      src/Squidex/Areas/Api/Controllers/Ping/PingController.cs
  5. 4
      src/Squidex/Areas/Api/Controllers/UI/MyUIOptions.cs
  6. 9
      src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs
  7. 4
      src/Squidex/Config/Web/WebServices.cs
  8. 2
      src/Squidex/WebStartup.cs
  9. 2
      src/Squidex/app/features/apps/pages/apps-page.component.html
  10. 7
      src/Squidex/app/features/apps/pages/apps-page.component.scss
  11. 5
      src/Squidex/app/features/apps/pages/apps-page.component.ts
  12. 13
      src/Squidex/appsettings.json
  13. 77
      tests/Squidex.Web.Tests/ExposedValuesTests.cs

3
Dockerfile

@ -55,6 +55,9 @@ RUN apk update \
# Copy from build stage
COPY --from=builder /out/alpine .
ARG SQUIDEX__VERSION
ENV SQUIDEX__VERSION ${SQUIDEX__VERSION:-dev}
EXPOSE 80
EXPOSE 11111

15
src/Squidex.Web/ExposedConfiguration.cs

@ -0,0 +1,15 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
namespace Squidex.Web
{
public sealed class ExposedConfiguration : Dictionary<string, string>
{
}
}

56
src/Squidex.Web/ExposedValues.cs

@ -0,0 +1,56 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
using System.Text;
using Microsoft.Extensions.Configuration;
using Squidex.Infrastructure;
namespace Squidex.Web
{
public sealed class ExposedValues : Dictionary<string, string>
{
public ExposedValues()
{
}
public ExposedValues(ExposedConfiguration configured, IConfiguration configuration)
{
Guard.NotNull(configured, nameof(configured));
Guard.NotNull(configuration, nameof(configuration));
foreach (var kvp in configured)
{
var value = configuration.GetValue<string>(kvp.Value);
if (!string.IsNullOrWhiteSpace(value))
{
this[kvp.Key] = value;
}
}
}
public override string ToString()
{
var sb = new StringBuilder();
foreach (var kvp in this)
{
if (sb.Length > 0)
{
sb.Append(", ");
}
sb.Append(kvp.Key);
sb.Append(": ");
sb.Append(kvp.Value);
}
return sb.ToString();
}
}
}

19
src/Squidex/Areas/Api/Controllers/Ping/PingController.cs

@ -18,9 +18,26 @@ namespace Squidex.Areas.Api.Controllers.Ping
[ApiExplorerSettings(GroupName = nameof(Ping))]
public sealed class PingController : ApiController
{
public PingController(ICommandBus commandBus)
private readonly ExposedValues exposedValues;
public PingController(ICommandBus commandBus, ExposedValues exposedValues)
: base(commandBus)
{
this.exposedValues = exposedValues;
}
/// <summary>
/// Get general info status of the API.
/// </summary>
/// <returns>
/// 200 => Infos returned.
/// </returns>
[HttpGet]
[ProducesResponseType(typeof(ExposedValues), 200)]
[Route("info/")]
public IActionResult Info()
{
return Ok(exposedValues);
}
/// <summary>

4
src/Squidex/Areas/Api/Controllers/UI/MyUIOptions.cs

@ -13,8 +13,12 @@ namespace Squidex.Areas.Api.Controllers.UI
{
public Dictionary<string, string> RegexSuggestions { get; set; }
public Dictionary<string, string> More { get; set; } = new Dictionary<string, string>();
public MapOptions Map { get; set; }
public bool ShowInfo { get; set; }
public bool HideNews { get; set; }
public bool HideOnboarding { get; set; }

9
src/Squidex/Areas/Frontend/Middlewares/IndexExtensions.cs

@ -9,9 +9,9 @@ using System;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Squidex.Areas.Api.Controllers.UI;
using Squidex.Infrastructure.Json;
using Squidex.Web;
namespace Squidex.Areas.Frontend.Middlewares
{
@ -45,6 +45,13 @@ namespace Squidex.Areas.Frontend.Middlewares
if (uiOptions != null)
{
var values = httpContext.RequestServices.GetService<ExposedValues>();
if (values != null)
{
uiOptions.More["info"] = values.ToString();
}
var jsonSerializer = httpContext.RequestServices.GetRequiredService<IJsonSerializer>();
var jsonOptions = jsonSerializer.Serialize(uiOptions, false);

4
src/Squidex/Config/Web/WebServices.cs

@ -8,6 +8,7 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Squidex.Config.Domain;
using Squidex.Domain.Apps.Entities;
using Squidex.Pipeline.Plugins;
@ -21,6 +22,9 @@ namespace Squidex.Config.Web
{
public static void AddMyMvcWithPlugins(this IServiceCollection services, IConfiguration config)
{
services.AddSingletonAs(c => new ExposedValues(c.GetRequiredService<IOptions<ExposedConfiguration>>().Value, config))
.AsSelf();
services.AddSingletonAs<FileCallbackResultExecutor>()
.AsSelf();

2
src/Squidex/WebStartup.cs

@ -95,6 +95,8 @@ namespace Squidex
config.GetSection("usage"));
services.Configure<RebuildOptions>(
config.GetSection("rebuild"));
services.Configure<ExposedConfiguration>(
config.GetSection("exposedConfiguration"));
services.Configure<MyContentsControllerOptions>(
config.GetSection("contentsController"));

2
src/Squidex/app/features/apps/pages/apps-page.component.html

@ -100,6 +100,8 @@
</div>
</div>
<div *ngIf="info" class="info">{{info}}</div>
<ng-container *sqxModalView="addAppDialog;onRoot:true">
<sqx-app-form [template]="addAppTemplate"
(complete)="addAppDialog.hide()">

7
src/Squidex/app/features/apps/pages/apps-page.component.scss

@ -90,3 +90,10 @@
display: none;
}
}
.info {
color: $color-border-dark;
padding: 2rem;
padding-left: $size-sidebar-width + .25rem;
font-size: .8rem;
}

5
src/Squidex/app/features/apps/pages/apps-page.component.ts

@ -35,6 +35,8 @@ export class AppsPageComponent implements OnInit {
public newsFeatures: FeatureDto[];
public newsDialog = new DialogModel();
public info: string;
constructor(
public readonly appsState: AppsState,
public readonly authState: AuthService,
@ -44,6 +46,9 @@ export class AppsPageComponent implements OnInit {
private readonly onboardingService: OnboardingService,
private readonly uiOptions: UIOptions
) {
if (uiOptions.get('showInfo')) {
this.info = uiOptions.get('more.info');
}
}
public ngOnInit() {

13
src/Squidex/appsettings.json

@ -78,7 +78,11 @@
/*
* Hide all onboarding tooltips and dialogs.
*/
"hideOnboarding": false
"hideOnboarding": false,
/*
* Show the exposed values as information on the apps overview page.
*/
"showInfo": false
},
"email": {
@ -483,5 +487,12 @@
* Set to true to rebuild indexes.
*/
"indexes": false
},
/*"
* A list of configuration valeus that should be exposed from the info endpoint and in the UI.
*/
"exposedConfiguration": {
"version": "squidex:version"
}
}

77
tests/Squidex.Web.Tests/ExposedValuesTests.cs

@ -0,0 +1,77 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using FakeItEasy;
using Microsoft.Extensions.Configuration;
using Xunit;
namespace Squidex.Web
{
public class ExposedValuesTests
{
[Fact]
public void Should_create_from_configuration()
{
var source = new ExposedConfiguration
{
["name1"] = "config1",
["name2"] = "config2",
["name3"] = "config3",
};
var configuration = A.Fake<IConfiguration>();
SetupConfiguration(configuration, "config1", "value1");
SetupConfiguration(configuration, "config2", "value2");
var values = new ExposedValues(source, configuration);
Assert.Equal(2, values.Count);
Assert.Equal("value1", values["name1"]);
Assert.Equal("value2", values["name2"]);
}
[Fact]
public void Should_format_empty_values()
{
var values = new ExposedValues();
Assert.Empty(values.ToString());
}
[Fact]
public void Should_format_from_single_value()
{
var values = new ExposedValues
{
["name1"] = "value1"
};
Assert.Equal("name1: value1", values.ToString());
}
[Fact]
public void Should_format_from_multiple_values()
{
var values = new ExposedValues
{
["name1"] = "value1",
["name2"] = "value2"
};
Assert.Equal("name1: value1, name2: value2", values.ToString());
}
private static void SetupConfiguration(IConfiguration configuration, string key, string value)
{
var configSection = A.Fake<IConfigurationSection>();
A.CallTo(() => configSection.Value).Returns(value);
A.CallTo(() => configuration.GetSection(key)).Returns(configSection);
}
}
}
Loading…
Cancel
Save