mirror of https://github.com/Squidex/squidex.git
61 changed files with 1421 additions and 62 deletions
@ -0,0 +1,22 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AppClientKeyCreated.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Events; |
||||
|
|
||||
|
namespace Squidex.Events.Apps |
||||
|
{ |
||||
|
[TypeName("AppClientKeyCreated")] |
||||
|
public sealed class AppClientKeyCreated : IEvent |
||||
|
{ |
||||
|
public string ClientKey { get; set; } |
||||
|
|
||||
|
public DateTime ExpiresUtc { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AppClientKeyRevoked.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Events; |
||||
|
|
||||
|
namespace Squidex.Events.Apps |
||||
|
{ |
||||
|
[TypeName("AppClientKeyRevoked")] |
||||
|
public sealed class AppClientKeyRevoked : IEvent |
||||
|
{ |
||||
|
public string ClientKey { get; set; } |
||||
|
|
||||
|
public DateTime ExpiresUtc { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AppLanguagesConfigured.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Events; |
||||
|
|
||||
|
namespace Squidex.Events.Apps |
||||
|
{ |
||||
|
[TypeName("AppLanguagesConfigured")] |
||||
|
public sealed class AppLanguagesConfigured : IEvent |
||||
|
{ |
||||
|
public List<Language> Languages { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
// ==========================================================================
|
||||
|
// EnrichWithTimestampHandler.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.CQRS.Commands |
||||
|
{ |
||||
|
public sealed class EnrichWithTimestampHandler : ICommandHandler |
||||
|
{ |
||||
|
private readonly Func<DateTime> timestamp; |
||||
|
|
||||
|
public EnrichWithTimestampHandler() |
||||
|
: this(() => DateTime.UtcNow) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public EnrichWithTimestampHandler(Func<DateTime> timestamp) |
||||
|
{ |
||||
|
Guard.NotNull(timestamp, nameof(timestamp)); |
||||
|
|
||||
|
this.timestamp = timestamp; |
||||
|
} |
||||
|
|
||||
|
public Task<bool> HandleAsync(CommandContext context) |
||||
|
{ |
||||
|
var timestampCommand = context.Command as ITimestampCommand; |
||||
|
|
||||
|
if (timestampCommand != null) |
||||
|
{ |
||||
|
timestampCommand.Timestamp = timestamp(); |
||||
|
} |
||||
|
|
||||
|
return Task.FromResult(false); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ITimestampCommand.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.CQRS.Commands |
||||
|
{ |
||||
|
public interface ITimestampCommand : ICommand |
||||
|
{ |
||||
|
DateTime Timestamp { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
// =========================================================================
|
||||
|
// LanguageConverter.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Json |
||||
|
{ |
||||
|
public sealed class LanguageConverter : JsonConverter |
||||
|
{ |
||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) |
||||
|
{ |
||||
|
var language = value as Language; |
||||
|
|
||||
|
if (language != null) |
||||
|
{ |
||||
|
writer.WriteValue(language.Iso2Code); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
writer.WriteNull(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) |
||||
|
{ |
||||
|
return reader.TokenType == JsonToken.Null ? null : Language.GetLanguage((string) reader.Value); |
||||
|
} |
||||
|
|
||||
|
public override bool CanConvert(Type objectType) |
||||
|
{ |
||||
|
return objectType == typeof(Language); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
// ==========================================================================
|
||||
|
// IAppClientKeyEntity.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
|
||||
|
namespace Squidex.Read.Apps |
||||
|
{ |
||||
|
public interface IAppClientKeyEntity |
||||
|
{ |
||||
|
string ClientKey { get; } |
||||
|
|
||||
|
DateTime ExpiresUtc { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
// ==========================================================================
|
||||
|
// MongoAppClientKeyEntity.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using MongoDB.Bson.Serialization.Attributes; |
||||
|
using Squidex.Read.Apps; |
||||
|
|
||||
|
namespace Squidex.Store.MongoDb.Apps |
||||
|
{ |
||||
|
public class MongoAppClientKeyEntity : IAppClientKeyEntity |
||||
|
{ |
||||
|
[BsonRequired] |
||||
|
[BsonElement] |
||||
|
public string ClientKey { get; set; } |
||||
|
|
||||
|
[BsonRequired] |
||||
|
[BsonElement] |
||||
|
public DateTime ExpiresUtc { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
// =========================================================================
|
||||
|
// ClientKeyGenerator.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Security.Cryptography; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace Squidex.Write.Apps |
||||
|
{ |
||||
|
public class ClientKeyGenerator |
||||
|
{ |
||||
|
public virtual string GenerateKey() |
||||
|
{ |
||||
|
return Sha256(Guid.NewGuid().ToString()); |
||||
|
} |
||||
|
|
||||
|
private static string Sha256(string input) |
||||
|
{ |
||||
|
using (var sha = SHA256.Create()) |
||||
|
{ |
||||
|
var bytes = Encoding.UTF8.GetBytes(input); |
||||
|
var hash = sha.ComputeHash(bytes); |
||||
|
|
||||
|
return Convert.ToBase64String(hash); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ConfigureLanguages.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Write.Apps.Commands |
||||
|
{ |
||||
|
public sealed class ConfigureLanguages : AppAggregateCommand, IValidatable |
||||
|
{ |
||||
|
public List<Language> Languages { get; set; } |
||||
|
|
||||
|
public void Validate(IList<ValidationError> errors) |
||||
|
{ |
||||
|
if (Languages == null || Languages.Count == 0) |
||||
|
{ |
||||
|
errors.Add(new ValidationError("Languages need at least one element.", nameof(Languages))); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
// ==========================================================================
|
||||
|
// CreateClientKey.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Commands; |
||||
|
|
||||
|
namespace Squidex.Write.Apps.Commands |
||||
|
{ |
||||
|
public sealed class CreateClientKey : AppAggregateCommand, ITimestampCommand, IValidatable |
||||
|
{ |
||||
|
public string ClientKey { get; set; } |
||||
|
|
||||
|
public DateTime Timestamp { get; set; } |
||||
|
|
||||
|
public void Validate(IList<ValidationError> errors) |
||||
|
{ |
||||
|
if (string.IsNullOrWhiteSpace(ClientKey)) |
||||
|
{ |
||||
|
errors.Add(new ValidationError("Client key is not assigned", nameof(ClientKey))); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
// ==========================================================================
|
||||
|
// RevokeClientKey.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Write.Apps.Commands |
||||
|
{ |
||||
|
public class RevokeClientKey : AppAggregateCommand, IValidatable |
||||
|
{ |
||||
|
public string ClientKey { get; set; } |
||||
|
|
||||
|
public void Validate(IList<ValidationError> errors) |
||||
|
{ |
||||
|
if (string.IsNullOrWhiteSpace(ClientKey)) |
||||
|
{ |
||||
|
errors.Add(new ValidationError("Client key is not assigned", nameof(ClientKey))); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AppClientKeysController.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Squidex.Infrastructure.CQRS.Commands; |
||||
|
using Squidex.Infrastructure.Reflection; |
||||
|
using Squidex.Modules.Api.Apps.Models; |
||||
|
using Squidex.Pipeline; |
||||
|
using Squidex.Read.Apps.Services; |
||||
|
using Squidex.Write.Apps; |
||||
|
using Squidex.Write.Apps.Commands; |
||||
|
|
||||
|
namespace Squidex.Modules.Api.Apps |
||||
|
{ |
||||
|
[Authorize(Roles = "app-owner")] |
||||
|
[ApiExceptionFilter] |
||||
|
[ServiceFilter(typeof(AppFilterAttribute))] |
||||
|
public class AppClientKeysController : ControllerBase |
||||
|
{ |
||||
|
private readonly IAppProvider appProvider; |
||||
|
private readonly ClientKeyGenerator keyGenerator; |
||||
|
|
||||
|
public AppClientKeysController(ICommandBus commandBus, IAppProvider appProvider, ClientKeyGenerator keyGenerator) |
||||
|
: base(commandBus) |
||||
|
{ |
||||
|
this.appProvider = appProvider; |
||||
|
this.keyGenerator = keyGenerator; |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("apps/{app}/client-keys/")] |
||||
|
public async Task<IActionResult> GetContributors(string app) |
||||
|
{ |
||||
|
var entity = await appProvider.FindAppByNameAsync(app); |
||||
|
|
||||
|
if (entity == null) |
||||
|
{ |
||||
|
return NotFound(); |
||||
|
} |
||||
|
|
||||
|
var model = entity.ClientKeys.Select(x => SimpleMapper.Map(x, new ClientKeyDto())).ToList(); |
||||
|
|
||||
|
return Ok(model); |
||||
|
} |
||||
|
|
||||
|
[HttpPost] |
||||
|
[Route("apps/{app}/client-keys/")] |
||||
|
public async Task<IActionResult> PostClientKey() |
||||
|
{ |
||||
|
var clientKey = keyGenerator.GenerateKey(); |
||||
|
|
||||
|
await CommandBus.PublishAsync(new CreateClientKey { ClientKey = clientKey }); |
||||
|
|
||||
|
return Ok(new ClientKeyCreatedDto { ClientKey = clientKey }); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,60 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AppLanguagesController.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Squidex.Infrastructure.CQRS.Commands; |
||||
|
using Squidex.Infrastructure.Reflection; |
||||
|
using Squidex.Modules.Api.Apps.Models; |
||||
|
using Squidex.Pipeline; |
||||
|
using Squidex.Read.Apps.Services; |
||||
|
using Squidex.Write.Apps.Commands; |
||||
|
|
||||
|
namespace Squidex.Modules.Api.Apps |
||||
|
{ |
||||
|
[Authorize(Roles = "app-owner")] |
||||
|
[ApiExceptionFilter] |
||||
|
[ServiceFilter(typeof(AppFilterAttribute))] |
||||
|
public class AppLanguagesController : ControllerBase |
||||
|
{ |
||||
|
private readonly IAppProvider appProvider; |
||||
|
|
||||
|
public AppLanguagesController(ICommandBus commandBus, IAppProvider appProvider) |
||||
|
: base(commandBus) |
||||
|
{ |
||||
|
this.appProvider = appProvider; |
||||
|
} |
||||
|
|
||||
|
[HttpGet] |
||||
|
[Route("apps/{app}/languages/")] |
||||
|
public async Task<IActionResult> GetContributors(string app) |
||||
|
{ |
||||
|
var entity = await appProvider.FindAppByNameAsync(app); |
||||
|
|
||||
|
if (entity == null) |
||||
|
{ |
||||
|
return NotFound(); |
||||
|
} |
||||
|
|
||||
|
var model = entity.Languages.Select(x => SimpleMapper.Map(x, new LanguageDto())).ToList(); |
||||
|
|
||||
|
return Ok(model); |
||||
|
} |
||||
|
|
||||
|
[HttpPost] |
||||
|
[Route("apps/{app}/languages/")] |
||||
|
public async Task<IActionResult> PostLanguages([FromBody] ConfigureLanguagesDto model) |
||||
|
{ |
||||
|
await CommandBus.PublishAsync(SimpleMapper.Map(model, new ConfigureLanguages())); |
||||
|
|
||||
|
return Ok(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ClientKeyCreatedDto.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
namespace Squidex.Modules.Api.Apps.Models |
||||
|
{ |
||||
|
public sealed class ClientKeyCreatedDto |
||||
|
{ |
||||
|
public string ClientKey { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ClientKeyDto.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
|
||||
|
namespace Squidex.Modules.Api.Apps.Models |
||||
|
{ |
||||
|
public sealed class ClientKeyDto |
||||
|
{ |
||||
|
public string ClientKey { get; set; } |
||||
|
|
||||
|
public DateTime ExpiresUtc { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ConfigureLanguagesDto.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Modules.Api.Apps.Models |
||||
|
{ |
||||
|
public class ConfigureLanguagesDto |
||||
|
{ |
||||
|
public List<Language> Languages { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
// ==========================================================================
|
||||
|
// LanguageDto.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
namespace Squidex.Modules.Api |
||||
|
{ |
||||
|
public class LanguageDto |
||||
|
{ |
||||
|
public string Iso2Code { get; set; } |
||||
|
|
||||
|
public string EnglishName { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,52 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
import * as Ng2 from '@angular/core'; |
||||
|
import * as Ng2Http from '@angular/http'; |
||||
|
|
||||
|
import { Observable } from 'rxjs'; |
||||
|
|
||||
|
import { ApiUrlConfig, DateTime } from 'framework'; |
||||
|
import { AuthService } from './auth.service'; |
||||
|
|
||||
|
export class AppClientKeyDto { |
||||
|
constructor( |
||||
|
public readonly clientKey: string, |
||||
|
public readonly expiresUtc: DateTime |
||||
|
) { |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Ng2.Injectable() |
||||
|
export class AppClientKeysService { |
||||
|
constructor( |
||||
|
private readonly authService: AuthService, |
||||
|
private readonly apiUrl: ApiUrlConfig, |
||||
|
private readonly http: Ng2Http.Http |
||||
|
) { |
||||
|
} |
||||
|
|
||||
|
public getClientKeys(appName: string): Observable<AppClientKeyDto[]> { |
||||
|
return this.authService.authGet(this.apiUrl.buildUrl(`api/apps/${appName}/client-keys`)) |
||||
|
.map(response => { |
||||
|
const body: any[] = response.json(); |
||||
|
|
||||
|
return body.map(item => { |
||||
|
return new AppClientKeyDto(item.clientKey, DateTime.parseISO_UTC(item.expiresUtc)); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public postClientKey(appName: string): Observable<AppClientKeyDto> { |
||||
|
return this.authService.authPost(this.apiUrl.buildUrl(`api/apps/${appName}/client-keys`), {}) |
||||
|
.map(response => { |
||||
|
const body = response.json(); |
||||
|
|
||||
|
return new AppClientKeyDto(body.clientKey, DateTime.now().addYears(1)); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,76 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
import * as TypeMoq from 'typemoq'; |
||||
|
import * as Ng2Http from '@angular/http'; |
||||
|
|
||||
|
import { Observable } from 'rxjs'; |
||||
|
|
||||
|
import { |
||||
|
ApiUrlConfig, |
||||
|
AppLanguagesService, |
||||
|
AuthService, |
||||
|
LanguageDto, |
||||
|
} from './../'; |
||||
|
|
||||
|
describe('AppLanguagesService', () => { |
||||
|
let authService: TypeMoq.Mock<AuthService>; |
||||
|
let appLanguagesService: AppLanguagesService; |
||||
|
|
||||
|
beforeEach(() => { |
||||
|
authService = TypeMoq.Mock.ofType(AuthService); |
||||
|
appLanguagesService = new AppLanguagesService(authService.object, new ApiUrlConfig('http://service/p/')); |
||||
|
}); |
||||
|
|
||||
|
it('should make get request with auth service to get app languages', () => { |
||||
|
authService.setup(x => x.authGet('http://service/p/api/apps/my-app/languages')) |
||||
|
.returns(() => Observable.of( |
||||
|
new Ng2Http.Response( |
||||
|
new Ng2Http.ResponseOptions({ |
||||
|
body: [{ |
||||
|
iso2Code: 'de', |
||||
|
englishName: 'German' |
||||
|
}, { |
||||
|
iso2Code: 'en', |
||||
|
englishName: 'English' |
||||
|
}] |
||||
|
}) |
||||
|
) |
||||
|
)) |
||||
|
.verifiable(TypeMoq.Times.once()); |
||||
|
|
||||
|
let languages: LanguageDto[] = null; |
||||
|
|
||||
|
appLanguagesService.getLanguages('my-app').subscribe(result => { |
||||
|
languages = result; |
||||
|
}).unsubscribe(); |
||||
|
|
||||
|
expect(languages).toEqual( |
||||
|
[ |
||||
|
new LanguageDto('de', 'German'), |
||||
|
new LanguageDto('en', 'English'), |
||||
|
]); |
||||
|
|
||||
|
authService.verifyAll(); |
||||
|
}); |
||||
|
|
||||
|
it('should make post request to configure languages', () => { |
||||
|
const languages = ['de', 'en']; |
||||
|
|
||||
|
authService.setup(x => x.authPost('http://service/p/api/apps/my-app/languages', TypeMoq.It.is(y => y['languages'] === languages))) |
||||
|
.returns(() => Observable.of( |
||||
|
new Ng2Http.Response( |
||||
|
new Ng2Http.ResponseOptions() |
||||
|
) |
||||
|
)) |
||||
|
.verifiable(TypeMoq.Times.once()); |
||||
|
|
||||
|
appLanguagesService.postLanguages('my-app', languages); |
||||
|
|
||||
|
authService.verifyAll(); |
||||
|
}); |
||||
|
}); |
||||
@ -0,0 +1,40 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Sebastian Stehle. All rights reserved |
||||
|
*/ |
||||
|
|
||||
|
import * as Ng2 from '@angular/core'; |
||||
|
|
||||
|
import { Observable } from 'rxjs'; |
||||
|
|
||||
|
import { ApiUrlConfig } from 'framework'; |
||||
|
import { AuthService } from './auth.service'; |
||||
|
import { LanguageDto } from './languages.service'; |
||||
|
|
||||
|
@Ng2.Injectable() |
||||
|
export class AppLanguagesService { |
||||
|
constructor( |
||||
|
private readonly authService: AuthService, |
||||
|
private readonly apiUrl: ApiUrlConfig |
||||
|
) { |
||||
|
} |
||||
|
|
||||
|
public getLanguages(appName: string): Observable<LanguageDto[]> { |
||||
|
return this.authService.authGet(this.apiUrl.buildUrl(`api/apps/${appName}/languages`)) |
||||
|
.map(response => { |
||||
|
const body: any[] = response.json(); |
||||
|
|
||||
|
return body.map(item => { |
||||
|
return new LanguageDto( |
||||
|
item.iso2Code, |
||||
|
item.englishName); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public postLanguages(appName: string, languageCodes: string[]): Observable<any> { |
||||
|
return this.authService.authPost(this.apiUrl.buildUrl(`api/apps/${appName}/languages`), { languages: languageCodes }); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
@import '_mixins'; |
||||
|
@import '_vars'; |
||||
|
|
||||
|
$color-drag-border: #000; |
||||
|
|
||||
|
.dnd { |
||||
|
&-drag { |
||||
|
&-start, |
||||
|
&-enter { |
||||
|
@include opacity(.6); |
||||
|
} |
||||
|
|
||||
|
&-start, |
||||
|
&-over, |
||||
|
&-enter { |
||||
|
border: 2px dashed $color-drag-border; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&-sortable-drag { |
||||
|
@include opacity(.6); |
||||
|
border: 2px dashed $color-drag-border; |
||||
|
} |
||||
|
} |
||||
@ -1,3 +1,4 @@ |
|||||
@import '_bootstrap.scss'; |
@import '_bootstrap.scss'; |
||||
@import '_layout.scss'; |
@import '_layout.scss'; |
||||
@import '_completer.scss'; |
@import '_lib-completer.scss'; |
||||
|
@import '_lib-dnd.scss'; |
||||
@ -0,0 +1,51 @@ |
|||||
|
// ==========================================================================
|
||||
|
// EnrichWithTimestampHandlerTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.CQRS.Commands |
||||
|
{ |
||||
|
public sealed class EnrichWithTimestampHandlerTests |
||||
|
{ |
||||
|
private sealed class NormalCommand : AggregateCommand |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
private sealed class TimestampCommand : AggregateCommand, ITimestampCommand |
||||
|
{ |
||||
|
public DateTime Timestamp { get; set; } |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_set_timestamp_when_is_timestamp_command() |
||||
|
{ |
||||
|
var utc = DateTime.Today; |
||||
|
var sut = new EnrichWithTimestampHandler(() => utc); |
||||
|
|
||||
|
var command = new TimestampCommand(); |
||||
|
|
||||
|
var result = await sut.HandleAsync(new CommandContext(command)); |
||||
|
|
||||
|
Assert.False(result); |
||||
|
Assert.Equal(utc, command.Timestamp); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_do_nothing_for_normal_command() |
||||
|
{ |
||||
|
var utc = DateTime.Today; |
||||
|
var sut = new EnrichWithTimestampHandler(() => utc); |
||||
|
|
||||
|
var result = await sut.HandleAsync(new CommandContext(new NormalCommand())); |
||||
|
|
||||
|
Assert.False(result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
// =========================================================================
|
||||
|
// ClientKeyGeneratorTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Write.Apps; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Write.Tests.Apps |
||||
|
{ |
||||
|
public class ClientKeyGeneratorTests |
||||
|
{ |
||||
|
private readonly ClientKeyGenerator sut = new ClientKeyGenerator(); |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_very_long_client_key() |
||||
|
{ |
||||
|
var key = sut.GenerateKey(); |
||||
|
|
||||
|
Assert.Equal(44, key.Length); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue